heroku-sauce/vendor/ruby/1.9.1/gems/httparty-0.9.0/lib/httparty/request.rb

240 lines
7.1 KiB
Ruby

module HTTParty
class Request #:nodoc:
SupportedHTTPMethods = [
Net::HTTP::Get,
Net::HTTP::Post,
Net::HTTP::Patch,
Net::HTTP::Put,
Net::HTTP::Delete,
Net::HTTP::Head,
Net::HTTP::Options
]
SupportedURISchemes = [URI::HTTP, URI::HTTPS]
NON_RAILS_QUERY_STRING_NORMALIZER = Proc.new do |query|
Array(query).map do |key, value|
if value.nil?
key.to_s
elsif value.is_a?(Array)
value.map {|v| "#{key}=#{URI.encode(v.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}"}
else
HashConversions.to_params(key => value)
end
end.flatten.sort.join('&')
end
attr_accessor :http_method, :path, :options, :last_response, :redirect, :last_uri
def initialize(http_method, path, o={})
self.http_method = http_method
self.path = path
self.options = {
:limit => o.delete(:no_follow) ? 1 : 5,
:default_params => {},
:follow_redirects => true,
:parser => Parser,
:connection_adapter => ConnectionAdapter
}.merge(o)
end
def path=(uri)
@path = URI.parse(uri)
end
def uri
new_uri = path.relative? ? URI.parse("#{base_uri}#{path}") : path
# avoid double query string on redirects [#12]
unless redirect
new_uri.query = query_string(new_uri)
end
unless SupportedURISchemes.include? new_uri.class
raise UnsupportedURIScheme, "'#{new_uri}' Must be HTTP or HTTPS"
end
@last_uri = new_uri
end
def base_uri
redirect ? "#{@last_uri.scheme}://#{@last_uri.host}" : options[:base_uri]
end
def format
options[:format] || (format_from_mimetype(last_response['content-type']) if last_response)
end
def parser
options[:parser]
end
def connection_adapter
options[:connection_adapter]
end
def perform(&block)
validate
setup_raw_request
chunked_body = nil
self.last_response = http.request(@raw_request) do |http_response|
if block
chunks = []
http_response.read_body do |fragment|
chunks << fragment
block.call(fragment)
end
chunked_body = chunks.join
end
end
handle_deflation
handle_response(chunked_body)
end
private
def http
connection_adapter.call(uri, options)
end
def body
options[:body].is_a?(Hash) ? normalize_query(options[:body]) : options[:body]
end
def credentials
options[:basic_auth] || options[:digest_auth]
end
def username
credentials[:username]
end
def password
credentials[:password]
end
def normalize_query(query)
if query_string_normalizer
query_string_normalizer.call(query)
else
HashConversions.to_params(query)
end
end
def query_string_normalizer
options[:query_string_normalizer]
end
def setup_raw_request
@raw_request = http_method.new(uri.request_uri)
@raw_request.body = body if body
@raw_request.initialize_http_header(options[:headers])
@raw_request.basic_auth(username, password) if options[:basic_auth]
setup_digest_auth if options[:digest_auth]
end
def setup_digest_auth
auth_request = http_method.new(uri.request_uri)
auth_request.initialize_http_header(options[:headers])
res = http.request(auth_request)
if res['www-authenticate'] != nil && res['www-authenticate'].length > 0
@raw_request.digest_auth(username, password, res)
end
end
def query_string(uri)
query_string_parts = []
query_string_parts << uri.query unless uri.query.nil?
if options[:query].is_a?(Hash)
query_string_parts << normalize_query(options[:default_params].merge(options[:query]))
else
query_string_parts << normalize_query(options[:default_params]) unless options[:default_params].empty?
query_string_parts << options[:query] unless options[:query].nil?
end
query_string_parts.size > 0 ? query_string_parts.join('&') : nil
end
def handle_response(body)
if response_redirects?
options[:limit] -= 1
self.path = last_response['location']
self.redirect = true
self.http_method = Net::HTTP::Get unless options[:maintain_method_across_redirects]
capture_cookies(last_response)
perform
else
body = body || last_response.body
Response.new(self, last_response, lambda { parse_response(body) }, :body => body)
end
end
# Inspired by Ruby 1.9
def handle_deflation
case last_response["content-encoding"]
when "gzip", "x-gzip"
body_io = StringIO.new(last_response.body)
last_response.body.replace Zlib::GzipReader.new(body_io).read
last_response.delete('content-encoding')
when "deflate"
last_response.body.replace Zlib::Inflate.inflate(last_response.body)
last_response.delete('content-encoding')
end
end
def response_redirects?
case last_response
when Net::HTTPMultipleChoice, # 300
Net::HTTPMovedPermanently, # 301
Net::HTTPFound, # 302
Net::HTTPSeeOther, # 303
Net::HTTPUseProxy, # 305
Net::HTTPTemporaryRedirect
options[:follow_redirects] && last_response.key?('location')
end
end
def parse_response(body)
parser.call(body, format)
end
def capture_cookies(response)
return unless response['Set-Cookie']
cookies_hash = HTTParty::CookieHash.new()
cookies_hash.add_cookies(options[:headers]['Cookie']) if options[:headers] && options[:headers]['Cookie']
cookies_hash.add_cookies(response['Set-Cookie'])
options[:headers] ||= {}
options[:headers]['Cookie'] = cookies_hash.to_cookie_string
end
# Uses the HTTP Content-Type header to determine the format of the
# response It compares the MIME type returned to the types stored in the
# SupportedFormats hash
def format_from_mimetype(mimetype)
if mimetype && parser.respond_to?(:format_from_mimetype)
parser.format_from_mimetype(mimetype)
end
end
def validate
raise HTTParty::RedirectionTooDeep.new(last_response), 'HTTP redirects too deep' if options[:limit].to_i <= 0
raise ArgumentError, 'only get, post, patch, put, delete, head, and options methods are supported' unless SupportedHTTPMethods.include?(http_method)
raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].is_a?(Hash)
raise ArgumentError, 'only one authentication method, :basic_auth or :digest_auth may be used at a time' if options[:basic_auth] && options[:digest_auth]
raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].is_a?(Hash)
raise ArgumentError, ':digest_auth must be a hash' if options[:digest_auth] && !options[:digest_auth].is_a?(Hash)
raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].is_a?(Hash)
end
def post?
Net::HTTP::Post == http_method
end
end
end