httparty-0.12.0/0000755000004100000410000000000012254052222013475 5ustar www-datawww-datahttparty-0.12.0/Rakefile0000644000004100000410000000052612254052222015145 0ustar www-datawww-datarequire 'spec/rake/spectask' Spec::Rake::SpecTask.new(:spec) do |spec| spec.ruby_opts << '-rubygems' spec.libs << 'lib' << 'spec' spec.spec_files = FileList['spec/**/*_spec.rb'] spec.spec_opts = ['--options', 'spec/spec.opts'] end require 'cucumber/rake/task' Cucumber::Rake::Task.new(:features) task :default => [:spec, :features] httparty-0.12.0/bin/0000755000004100000410000000000012254052222014245 5ustar www-datawww-datahttparty-0.12.0/bin/httparty0000755000004100000410000000540712254052222016060 0ustar www-datawww-data#!/usr/bin/env ruby require "optparse" require "pp" $:.unshift(File.join(File.dirname(__FILE__), "/../lib")) require "httparty" opts = { :action => :get, :headers => {}, :verbose => false } OptionParser.new do |o| o.banner = "USAGE: #{$0} [options] [url]" o.on("-f", "--format [FORMAT]", "Output format to use instead of pretty-print ruby: " + "plain, json or xml") do |f| opts[:output_format] = f.downcase.to_sym end o.on("-a", "--action [ACTION]", "HTTP action: get (default), post, put, delete, head, or options") do |a| opts[:action] = a.downcase.to_sym end o.on("-d", "--data [BODY]", "Data to put in request body (prefix with '@' for file)") do |d| if d =~ /^@/ opts[:body] = open(d[1..-1]).read else opts[:body] = d end end o.on("-H", "--header [NAME:VALUE]", "Additional HTTP headers in NAME:VALUE form") do |h| abort "Invalid header specification, should be Name:Value" unless h =~ /.+:.+/ name, value = h.split(':') opts[:headers][name.strip] = value.strip end o.on("-v", "--verbose", "If set, print verbose output") do |v| opts[:verbose] = true end o.on("-u", "--user [CREDS]", "Use basic authentication. Value should be user:password") do |u| abort "Invalid credentials format. Must be user:password" unless u =~ /.*:.+/ user, password = u.split(':') opts[:basic_auth] = { :username => user, :password => password } end o.on("-r", "--response-code", "Command fails if response code >= 400") do opts[:response_code] = true end o.on("-h", "--help", "Show help documentation") do |h| puts o exit end end.parse! if ARGV.empty? STDERR.puts "You need to provide a URL" STDERR.puts "USAGE: #{$0} [options] [url]" end def dump_headers(response) resp_type = Net::HTTPResponse::CODE_TO_OBJ[response.code.to_s] puts "#{response.code} #{resp_type.to_s.sub(/^Net::HTTP/, '')}" response.headers.each do |n,v| puts "#{n}: #{v}" end puts end if opts[:verbose] puts "#{opts[:action].to_s.upcase} #{ARGV.first}" opts[:headers].each do |n,v| puts "#{n}: #{v}" end puts end response = HTTParty.send(opts[:action], ARGV.first, opts) if opts[:output_format].nil? dump_headers(response) if opts[:verbose] pp response else print_format = opts[:output_format] dump_headers(response) if opts[:verbose] case opts[:output_format] when :json begin require 'json' puts JSON.pretty_generate(response.delegate) rescue LoadError puts YAML.dump(response.delegate) end when :xml require 'rexml/document' REXML::Document.new(response.body).write(STDOUT, 2) puts else puts response end end exit false if opts[:response_code] && response.code >= 400 httparty-0.12.0/Gemfile0000644000004100000410000000035512254052222014773 0ustar www-datawww-datasource 'https://rubygems.org' gemspec gem 'rake' gem 'cucumber', '~> 0.7' gem 'fakeweb', '~> 1.2' gem 'rspec', '~> 1.3' gem 'mongrel', '1.2.0.pre2' group :development do gem 'guard' gem 'guard-rspec' gem 'guard-bundler' end httparty-0.12.0/examples/0000755000004100000410000000000012254052222015313 5ustar www-datawww-datahttparty-0.12.0/examples/custom_parsers.rb0000644000004100000410000000201712254052222020711 0ustar www-datawww-dataclass ParseAtom include HTTParty # Support Atom along with the default parsers: xml, json, etc. class Parser::Atom < HTTParty::Parser SupportedFormats.merge!({"application/atom+xml" => :atom}) protected # perform atom parsing on body def atom body.to_atom end end parser Parser::Atom end class OnlyParseAtom include HTTParty # Only support Atom class Parser::OnlyAtom < HTTParty::Parser SupportedFormats = {"application/atom+xml" => :atom} protected # perform atom parsing on body def atom body.to_atom end end parser Parser::OnlyAtom end class SkipParsing include HTTParty # Parse the response body however you like class Parser::Simple < HTTParty::Parser def parse body end end parser Parser::Simple end class AdHocParsing include HTTParty parser( Proc.new do |body, format| case format when :json body.to_json when :xml body.to_xml else body end end ) end httparty-0.12.0/examples/tripit_sign_in.rb0000644000004100000410000000152612254052222020665 0ustar www-datawww-datadir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') class TripIt include HTTParty base_uri 'http://www.tripit.com' debug_output def initialize(email, password) @email = email response = self.class.get('/account/login') response = self.class.post( '/account/login', :body => { :login_email_address => email, :login_password => password }, :headers => {'Cookie' => response.headers['Set-Cookie']} ) @cookie = response.request.options[:headers]['Cookie'] end def account_settings self.class.get('/account/edit', :headers => {'Cookie' => @cookie}) end def logged_in? account_settings.include? "You're logged in as #{@email}" end end tripit = TripIt.new('email', 'password') puts "Logged in: #{tripit.logged_in?}" httparty-0.12.0/examples/aaws.rb0000644000004100000410000000203212254052222016570 0ustar www-datawww-datarequire 'rubygems' require 'active_support' dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') require 'pp' config = YAML::load(File.read(File.join(ENV['HOME'], '.aaws'))) module AAWS class Book include HTTParty base_uri 'http://ecs.amazonaws.com' default_params :Service => 'AWSECommerceService', :Operation => 'ItemSearch', :SearchIndex => 'Books' def initialize(key) self.class.default_params :AWSAccessKeyId => key end def search(options={}) raise ArgumentError, 'You must search for something' if options[:query].blank? # amazon uses nasty camelized query params options[:query] = options[:query].inject({}) { |h, q| h[q[0].to_s.camelize] = q[1]; h } # make a request and return the items (NOTE: this doesn't handle errors at this point) self.class.get('/onca/xml', options)['ItemSearchResponse']['Items'] end end end aaws = AAWS::Book.new(config[:access_key]) pp aaws.search(:query => {:title => 'Ruby On Rails'}) httparty-0.12.0/examples/google.rb0000644000004100000410000000057712254052222017125 0ustar www-datawww-datadir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') require 'pp' class Google include HTTParty format :html end # google.com redirects to www.google.com so this is live test for redirection pp Google.get('http://google.com') puts '', '*'*70, '' # check that ssl is requesting right pp Google.get('https://www.google.com')httparty-0.12.0/examples/crack.rb0000644000004100000410000000066412254052222016731 0ustar www-datawww-datarequire 'rubygems' require 'crack' dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') require 'pp' class Rep include HTTParty parser( Proc.new do |body, format| Crack::XML.parse(body) end ) end pp Rep.get('http://whoismyrepresentative.com/getall_mems.php?zip=46544') pp Rep.get('http://whoismyrepresentative.com/getall_mems.php', :query => {:zip => 46544}) httparty-0.12.0/examples/delicious.rb0000644000004100000410000000224012254052222017616 0ustar www-datawww-datadir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') require 'pp' config = YAML::load(File.read(File.join(ENV['HOME'], '.delicious'))) class Delicious include HTTParty base_uri 'https://api.del.icio.us/v1' def initialize(u, p) @auth = {:username => u, :password => p} end # query params that filter the posts are: # tag (optional). Filter by this tag. # dt (optional). Filter by this date (CCYY-MM-DDThh:mm:ssZ). # url (optional). Filter by this url. # ie: posts(:query => {:tag => 'ruby'}) def posts(options={}) options.merge!({:basic_auth => @auth}) self.class.get('/posts/get', options) end # query params that filter the posts are: # tag (optional). Filter by this tag. # count (optional). Number of items to retrieve (Default:15, Maximum:100). def recent(options={}) options.merge!({:basic_auth => @auth}) self.class.get('/posts/recent', options) end end delicious = Delicious.new(config['username'], config['password']) pp delicious.posts(:query => {:tag => 'ruby'}) pp delicious.recent delicious.recent['posts']['post'].each { |post| puts post['href'] } httparty-0.12.0/examples/rubyurl.rb0000644000004100000410000000054612254052222017351 0ustar www-datawww-datadir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') require 'pp' class Rubyurl include HTTParty base_uri 'rubyurl.com' def self.shorten( website_url ) post( '/api/links.json', :query => { :link => { :website_url => website_url } } ) end end pp Rubyurl.shorten( 'http://istwitterdown.com/')httparty-0.12.0/examples/twitter.rb0000644000004100000410000000174412254052222017350 0ustar www-datawww-datadir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') require 'pp' config = YAML::load(File.read(File.join(ENV['HOME'], '.twitter'))) class Twitter include HTTParty base_uri 'twitter.com' def initialize(u, p) @auth = {:username => u, :password => p} end # which can be :friends, :user or :public # options[:query] can be things like since, since_id, count, etc. def timeline(which=:friends, options={}) options.merge!({:basic_auth => @auth}) self.class.get("/statuses/#{which}_timeline.json", options) end def post(text) options = { :query => {:status => text}, :basic_auth => @auth } self.class.post('/statuses/update.json', options) end end twitter = Twitter.new(config['email'], config['password']) pp twitter.timeline # pp twitter.timeline(:friends, :query => {:since_id => 868482746}) # pp twitter.timeline(:friends, :query => 'since_id=868482746') # pp twitter.post('this is a test of 0.2.0') httparty-0.12.0/examples/nokogiri_html_parser.rb0000644000004100000410000000062012254052222022057 0ustar www-datawww-datarequire 'rubygems' require 'nokogiri' dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') require 'pp' class HtmlParserIncluded < HTTParty::Parser SupportedFormats.merge!('text/html' => :html) def html Nokogiri::HTML(body) end end class Page include HTTParty parser HtmlParserIncluded end pp Page.get('http://www.google.com') httparty-0.12.0/examples/headers_and_user_agents.rb0000644000004100000410000000050012254052222022467 0ustar www-datawww-data# To send custom user agents to identify your application to a web service (or mask as a specific browser for testing), send "User-Agent" as a hash to headers as shown below. require 'httparty' APPLICATION_NAME = "Httparty" response = HTTParty.get('http://example.com', :headers => {"User-Agent" => APPLICATION_NAME}) httparty-0.12.0/examples/basic.rb0000644000004100000410000000155012254052222016722 0ustar www-datawww-datadir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') require 'pp' # You can also use post, put, delete, head, options in the same fashion response = HTTParty.get('http://twitter.com/statuses/public_timeline.json') puts response.body, response.code, response.message, response.headers.inspect response.each do |item| puts item['user']['screen_name'] end # An example post to a minimal rails app in the development environment # Note that "skip_before_filter :verify_authenticity_token" must be set in the # "pears" controller for this example class Partay include HTTParty base_uri 'http://localhost:3000' end options = { :body => { :pear => { # your resource :foo => '123', # your columns/data :bar => 'second', :baz => 'last thing' } } } pp Partay.post('/pears.xml', options) httparty-0.12.0/examples/whoismyrep.rb0000644000004100000410000000047412254052222020053 0ustar www-datawww-datadir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') require 'pp' class Rep include HTTParty end pp Rep.get('http://whoismyrepresentative.com/getall_mems.php?zip=46544') pp Rep.get('http://whoismyrepresentative.com/getall_mems.php', :query => {:zip => 46544})httparty-0.12.0/script/0000755000004100000410000000000012254052222015001 5ustar www-datawww-datahttparty-0.12.0/script/release0000744000004100000410000000155112254052222016347 0ustar www-datawww-data#!/bin/sh #/ Usage: release #/ #/ Tag the version in the repo and push the gem. #/ set -e cd $(dirname "$0")/.. [ "$1" = "--help" -o "$1" = "-h" -o "$1" = "help" ] && { grep '^#/' <"$0"| cut -c4- exit 0 } gem_name=httparty # Build a new gem archive. rm -rf $gem_name-*.gem gem build -q $gem_name.gemspec # Make sure we're on the master branch. (git branch | grep -q '* master') || { echo "Only release from the master branch." exit 1 } # Figure out what version we're releasing. tag=v`ls $gem_name-*.gem | sed "s/^$gem_name-\(.*\)\.gem$/\1/"` echo "Releasing $tag" # Make sure we haven't released this version before. git fetch -t origin (git tag -l | grep -q "$tag") && { echo "Whoops, there's already a '${tag}' tag." exit 1 } # Tag it and bag it. gem push $gem_name-*.gem && git tag "$tag" && git push origin master && git push origin "$tag" httparty-0.12.0/features/0000755000004100000410000000000012254052222015313 5ustar www-datawww-datahttparty-0.12.0/features/supports_timeout_option.feature0000644000004100000410000000116112254052222023724 0ustar www-datawww-dataFeature: Supports the timeout option In order to handle inappropriately slow response times As a developer I want my request to raise an exception after my specified timeout as elapsed Scenario: A long running response Given a remote service that returns '

Some HTML

' And that service is accessed at the path '/long_running_service.html' And that service takes 2 seconds to generate a response When I set my HTTParty timeout option to 1 And I call HTTParty#get with '/long_running_service.html' Then it should raise a Timeout::Error exception And I wait for the server to recover httparty-0.12.0/features/handles_compressed_responses.feature0000644000004100000410000000222412254052222024633 0ustar www-datawww-dataFeature: Handles Compressed Responses In order to save bandwidth As a developer I want to uncompress compressed responses Scenario: Supports deflate encoding Given a remote deflate service And the response from the service has a body of '

Some HTML

' And that service is accessed at the path '/deflate_service.html' When I call HTTParty#get with '/deflate_service.html' Then the return value should match '

Some HTML

' Scenario: Supports gzip encoding Given a remote gzip service And the response from the service has a body of '

Some HTML

' And that service is accessed at the path '/gzip_service.html' When I call HTTParty#get with '/gzip_service.html' Then the return value should match '

Some HTML

' Scenario: Supports HEAD request with gzip encoding Given a remote gzip service And that service is accessed at the path '/gzip_head.gz.js' When I call HTTParty#head with '/gzip_head.gz.js' Then it should return a response with a 200 response code Then it should return a response with a gzip content-encoding Then it should return a response with a blank body httparty-0.12.0/features/basic_authentication.feature0000644000004100000410000000167512254052222023061 0ustar www-datawww-dataFeature: Basic Authentication As a developer I want to be able to use a service that requires Basic Authentication Because that is not an uncommon requirement Scenario: Passing no credentials to a page requiring Basic Authentication Given a restricted page at '/basic_auth.html' When I call HTTParty#get with '/basic_auth.html' Then it should return a response with a 401 response code Scenario: Passing proper credentials to a page requiring Basic Authentication Given a remote service that returns 'Authenticated Page' And that service is accessed at the path '/basic_auth.html' And that service is protected by Basic Authentication And that service requires the username 'jcash' with the password 'maninblack' When I call HTTParty#get with '/basic_auth.html' and a basic_auth hash: | username | password | | jcash | maninblack | Then the return value should match 'Authenticated Page' httparty-0.12.0/features/steps/0000755000004100000410000000000012254052222016451 5ustar www-datawww-datahttparty-0.12.0/features/steps/httparty_response_steps.rb0000644000004100000410000000312312254052222024010 0ustar www-datawww-data# Not needed anymore in ruby 2.0, but needed to resolve constants # in nested namespaces. This is taken from rails :) def constantize(camel_cased_word) names = camel_cased_word.split('::') names.shift if names.empty? || names.first.empty? constant = Object names.each do |name| constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name) end constant end Then /it should return an? (\w+)$/ do |class_string| @response_from_httparty.should be_an_instance_of(class_string.class) end Then /the return value should match '(.*)'/ do |expected_text| @response_from_httparty.should eql(expected_text) end Then /it should return a Hash equaling:/ do |hash_table| @response_from_httparty.should be_an_instance_of(Hash) @response_from_httparty.keys.length.should eql(hash_table.rows.length) hash_table.hashes.each do |pair| key, value = pair["key"], pair["value"] @response_from_httparty.keys.should include(key) @response_from_httparty[key].should eql(value) end end Then /it should return a response with a (\d+) response code/ do |code| @response_from_httparty.code.should eql(code.to_i) end Then /it should return a response with a (.*) content\-encoding$/ do |content_type| @response_from_httparty.headers['content-encoding'].should eql('gzip') end Then /it should return a response with a blank body$/ do @response_from_httparty.body.should be(nil) end Then /it should raise (?:an|a) ([\w:]+) exception/ do |exception| @exception_from_httparty.should_not be_nil @exception_from_httparty.should be_a constantize(exception) end httparty-0.12.0/features/steps/mongrel_helper.rb0000644000004100000410000000453212254052222022004 0ustar www-datawww-datarequire 'base64' class BasicMongrelHandler < Mongrel::HttpHandler attr_accessor :content_type, :custom_headers, :response_body, :response_code, :preprocessor, :username, :password def initialize @content_type = "text/html" @response_body = "" @response_code = 200 @custom_headers = {} end def process(request, response) instance_eval &preprocessor if preprocessor reply_with(response, response_code, response_body) end def reply_with(response, code, response_body) response.start(code) do |head, body| head["Content-Type"] = content_type custom_headers.each { |k,v| head[k] = v } body.write(response_body) end end end class DeflateHandler < BasicMongrelHandler def process(request, response) response.start do |head, body| head['Content-Encoding'] = 'deflate' body.write Zlib::Deflate.deflate(response_body) end end end class GzipHandler < BasicMongrelHandler def process(request, response) response.start do |head, body| head['Content-Encoding'] = 'gzip' body.write gzip(response_body) end end protected def gzip(string) sio = StringIO.new('', 'r+') gz = Zlib::GzipWriter.new sio gz.write string gz.finish sio.rewind sio.read end end module BasicAuthentication def self.extended(base) base.custom_headers["WWW-Authenticate"] = 'Basic Realm="Super Secret Page"' end def process(request, response) if authorized?(request) super else reply_with(response, 401, "Incorrect. You have 20 seconds to comply.") end end def authorized?(request) request.params["HTTP_AUTHORIZATION"] == "Basic " + Base64.encode64("#{@username}:#{@password}").strip end end module DigestAuthentication def self.extended(base) base.custom_headers["WWW-Authenticate"] = 'Digest realm="testrealm@host.com",qop="auth,auth-int",nonce="nonce",opaque="opaque"' end def process(request, response) if authorized?(request) super else reply_with(response, 401, "Incorrect. You have 20 seconds to comply.") end end def authorized?(request) request.params["HTTP_AUTHORIZATION"] =~ /Digest.*uri=/ end end def new_mongrel_redirector(target_url, relative_path = false) target_url = "http://#{@host_and_port}#{target_url}" unless relative_path Mongrel::RedirectHandler.new(target_url) end httparty-0.12.0/features/steps/remote_service_steps.rb0000644000004100000410000000420212254052222023225 0ustar www-datawww-dataGiven /a remote service that returns '(.*)'/ do |response_body| @handler = BasicMongrelHandler.new Given "the response from the service has a body of '#{response_body}'" end Given /a remote service that returns a (\d+) status code/ do |code| @handler = BasicMongrelHandler.new @handler.response_code = code end Given /that service is accessed at the path '(.*)'/ do |path| @server.register(path, @handler) end Given /^that service takes (\d+) seconds to generate a response$/ do |time| @server_response_time = time.to_i @handler.preprocessor = Proc.new { sleep time.to_i } end Given /^a remote deflate service$/ do @handler = DeflateHandler.new end Given /^a remote gzip service$/ do @handler = GzipHandler.new end Given /the response from the service has a Content-Type of '(.*)'/ do |content_type| @handler.content_type = content_type end Given /the response from the service has a body of '(.*)'/ do |response_body| @handler.response_body = response_body end Given /the url '(.*)' redirects to '(.*)'/ do |redirection_url, target_url| @server.register redirection_url, new_mongrel_redirector(target_url) end Given /that service is protected by Basic Authentication/ do @handler.extend BasicAuthentication end Given /that service is protected by Digest Authentication/ do @handler.extend DigestAuthentication end Given /that service requires the username '(.*)' with the password '(.*)'/ do |username, password| @handler.username = username @handler.password = password end Given /a restricted page at '(.*)'/ do |url| Given "a remote service that returns 'A response I will never see'" And "that service is accessed at the path '#{url}'" And "that service is protected by Basic Authentication" And "that service requires the username 'something' with the password 'secret'" end # This joins the server thread, and halts cucumber, so you can actually hit the # server with a browser. Runs until you kill it with Ctrl-c Given /I want to hit this in a browser/ do @server.acceptor.join end Then /I wait for the server to recover/ do timeout = @request_options[:timeout] || 0 sleep @server_response_time - timeout end httparty-0.12.0/features/steps/env.rb0000644000004100000410000000062212254052222017566 0ustar www-datawww-datarequire 'mongrel' require './lib/httparty' require 'spec/expectations' Before do def new_port server = TCPServer.new('0.0.0.0', nil) port = server.addr[1] ensure server.close end port = ENV["HTTPARTY_PORT"] || new_port @host_and_port = "0.0.0.0:#{port}" @server = Mongrel::HttpServer.new("0.0.0.0", port) @server.run @request_options = {} end After do @server.stop end httparty-0.12.0/features/steps/httparty_steps.rb0000644000004100000410000000224312254052222022074 0ustar www-datawww-dataWhen /^I set my HTTParty timeout option to (\d+)$/ do |timeout| @request_options[:timeout] = timeout.to_i end When /I call HTTParty#get with '(.*)'$/ do |url| begin @response_from_httparty = HTTParty.get("http://#{@host_and_port}#{url}", @request_options) rescue HTTParty::RedirectionTooDeep, Timeout::Error => e @exception_from_httparty = e end end When /^I call HTTParty#head with '(.*)'$/ do |url| begin @response_from_httparty = HTTParty.head("http://#{@host_and_port}#{url}", @request_options) rescue HTTParty::RedirectionTooDeep, Timeout::Error => e @exception_from_httparty = e end end When /I call HTTParty#get with '(.*)' and a basic_auth hash:/ do |url, auth_table| h = auth_table.hashes.first @response_from_httparty = HTTParty.get( "http://#{@host_and_port}#{url}", :basic_auth => { :username => h["username"], :password => h["password"] } ) end When /I call HTTParty#get with '(.*)' and a digest_auth hash:/ do |url, auth_table| h = auth_table.hashes.first @response_from_httparty = HTTParty.get( "http://#{@host_and_port}#{url}", :digest_auth => { :username => h["username"], :password => h["password"] } ) end httparty-0.12.0/features/command_line.feature0000644000004100000410000000036712254052222021323 0ustar www-datawww-dataFeature: Command Line As a developer I want to be able to harness the power of HTTParty from the command line Because that would make quick testing and debugging easy And 'easy' is my middle name And I'm kidding it's actually 'Danger'! httparty-0.12.0/features/supports_redirection.feature0000644000004100000410000000165412254052222023164 0ustar www-datawww-dataFeature: Supports Redirection As a developer I want to work with services that may redirect me And I want it to follow a reasonable number of redirects Because sometimes web services do that Scenario: A service that redirects once Given a remote service that returns 'Service Response' And that service is accessed at the path '/landing_service.html' And the url '/redirector.html' redirects to '/landing_service.html' When I call HTTParty#get with '/redirector.html' Then the return value should match 'Service Response' # TODO: Look in to why this actually fails... Scenario: A service that redirects to a relative URL Scenario: A service that redirects infinitely Given the url '/first.html' redirects to '/second.html' And the url '/second.html' redirects to '/first.html' When I call HTTParty#get with '/first.html' Then it should raise an HTTParty::RedirectionTooDeep exception httparty-0.12.0/features/deals_with_http_error_codes.feature0000644000004100000410000000224012254052222024436 0ustar www-datawww-dataFeature: Deals with HTTP error codes As a developer I want to be informed of non-successful responses Because sometimes thing explode And I should probably know what happened Scenario: A response of '404 - Not Found' Given a remote service that returns a 404 status code And that service is accessed at the path '/404_service.html' When I call HTTParty#get with '/404_service.html' Then it should return a response with a 404 response code Scenario: A response of '500 - Internal Server Error' Given a remote service that returns a 500 status code And that service is accessed at the path '/500_service.html' When I call HTTParty#get with '/500_service.html' Then it should return a response with a 500 response code Scenario: A non-successful response where I need the body Given a remote service that returns a 400 status code And the response from the service has a body of 'Bad response' And that service is accessed at the path '/400_service.html' When I call HTTParty#get with '/400_service.html' Then it should return a response with a 400 response code And the return value should match 'Bad response' httparty-0.12.0/features/digest_authentication.feature0000644000004100000410000000172512254052222023253 0ustar www-datawww-dataFeature: Digest Authentication As a developer I want to be able to use a service that requires Digest Authentication Because that is not an uncommon requirement Scenario: Passing no credentials to a page requiring Digest Authentication Given a restricted page at '/digest_auth.html' When I call HTTParty#get with '/digest_auth.html' Then it should return a response with a 401 response code Scenario: Passing proper credentials to a page requiring Digest Authentication Given a remote service that returns 'Digest Authenticated Page' And that service is accessed at the path '/digest_auth.html' And that service is protected by Digest Authentication And that service requires the username 'jcash' with the password 'maninblack' When I call HTTParty#get with '/digest_auth.html' and a digest_auth hash: | username | password | | jcash | maninblack | Then the return value should match 'Digest Authenticated Page' httparty-0.12.0/features/handles_multiple_formats.feature0000644000004100000410000000355312254052222023762 0ustar www-datawww-dataFeature: Handles Multiple Formats As a developer I want to be able to consume remote services of many different formats And I want those formats to be automatically detected and handled Because web services take many forms And I don't want to have to do any extra work Scenario: An HTML service Given a remote service that returns '

Some HTML

' And that service is accessed at the path '/html_service.html' And the response from the service has a Content-Type of 'text/html' When I call HTTParty#get with '/html_service.html' Then it should return a String And the return value should match '

Some HTML

' Scenario: A JSON service Given a remote service that returns '{ "jennings": "waylon", "cash": "johnny" }' And that service is accessed at the path '/service.json' And the response from the service has a Content-Type of 'application/json' When I call HTTParty#get with '/service.json' Then it should return a Hash equaling: | key | value | | jennings | waylon | | cash | johnny | Scenario: An XML Service Given a remote service that returns 'waylon jennings' And that service is accessed at the path '/service.xml' And the response from the service has a Content-Type of 'text/xml' When I call HTTParty#get with '/service.xml' Then it should return a Hash equaling: | key | value | | singer | waylon jennings | Scenario: A Javascript remote file Given a remote service that returns '$(function() { alert("hi"); });' And that service is accessed at the path '/service.js' And the response from the service has a Content-Type of 'application/javascript' When I call HTTParty#get with '/service.js' Then it should return a String And the return value should match '$(function() { alert("hi"); });' httparty-0.12.0/MIT-LICENSE0000644000004100000410000000204112254052222015126 0ustar www-datawww-dataCopyright (c) 2008 John Nunemaker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.httparty-0.12.0/spec/0000755000004100000410000000000012254052222014427 5ustar www-datawww-datahttparty-0.12.0/spec/spec.opts0000644000004100000410000000002512254052222016265 0ustar www-datawww-data--colour --backtrace httparty-0.12.0/spec/spec_helper.rb0000644000004100000410000000144312254052222017247 0ustar www-datawww-data$:.push File.expand_path("../lib", __FILE__) require "httparty" require 'spec/autorun' require 'fakeweb' def file_fixture(filename) open(File.join(File.dirname(__FILE__), 'fixtures', "#{filename.to_s}")).read end Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f} Spec::Runner.configure do |config| config.include HTTParty::StubResponse config.include HTTParty::SSLTestHelper config.before(:suite) do FakeWeb.allow_net_connect = false end config.after(:suite) do FakeWeb.allow_net_connect = true end end Spec::Matchers.define :use_ssl do match do |connection| connection.use_ssl? end end Spec::Matchers.define :use_cert_store do |cert_store| match do |connection| connection.cert_store == cert_store end end httparty-0.12.0/spec/fixtures/0000755000004100000410000000000012254052222016300 5ustar www-datawww-datahttparty-0.12.0/spec/fixtures/google.html0000644000004100000410000001335412254052222020450 0ustar www-datawww-dataGoogle
Web Images Maps News Shopping Gmail more
iGoogle | Sign in

Google

 
  Advanced Search
  Preferences
  Language Tools


Advertising Programs - Business Solutions - About Google

©2008 - Privacy

httparty-0.12.0/spec/fixtures/twitter.xml0000644000004100000410000004167412254052222020540 0ustar www-datawww-data Sun Dec 07 00:36:16 +0000 2008 1042729116 @sebbo Outlook not so good web false 1042716367 2989541 false 17656026 Magic 8 Bot magic8bot ask me a question http://s3.amazonaws.com/twitter_production/profile_images/65565851/8ball_large_normal.jpg false 90 Sun Dec 07 00:36:14 +0000 2008 1042729115 Azdel Slade :friends from midian city http://bloghud.com/id/27312 web false false 801094 BlogHUD bloghud http://s3.amazonaws.com/twitter_production/profile_images/25235272/bloghud_twitter_normal.jpg false 313 Sun Dec 07 00:36:14 +0000 2008 1042729114 Reading: "The Reckoning - Debt Watchdogs - Tamed or Caught Napping? - Series - NYTimes.com" ( http://tinyurl.com/5754s6 ) twitthat false false 3512101 bill niubi in beijing learning socialism 2 prepare 4 return 2 us beijing http://s3.amazonaws.com/twitter_production/profile_images/53292616/realtwitterers_normal.jpg false 710 Sun Dec 07 00:36:14 +0000 2008 1042729113 Fianlly done and headed home! sms false false 13186842 Okthirddayfan Okthirddayfan Oklahoma! http://s3.amazonaws.com/twitter_production/profile_images/61414367/mecropped_normal.jpg http://thirddaypix.blogspot.com/ false 68 Sun Dec 07 00:36:16 +0000 2008 1042729112 Adobe Flashplayer 10 and Debug versions: http://www.adobe.com/support/flashplayer/downloads.html toro false false 15243380 cbrueggenolte cbrueggenolte 27, Male, Mac Geek, Developer Java &amp; Flex &amp; Air Aachen http://s3.amazonaws.com/twitter_production/profile_images/55929263/214508011845f026bfd407c_normal.jpg http://my.opera.com/carstenbrueggenolte false 16 Sun Dec 07 00:36:14 +0000 2008 1042729111 Done and done. twitterrific false false 10978752 Sergey Safonov iron_Lung I have my fingers in many pies. Moscow http://s3.amazonaws.com/twitter_production/profile_images/57841057/eat38_normal.gif http://www.flickr.com/photos/iron_Lung false 11 Sun Dec 07 00:36:14 +0000 2008 1042729110 Veja a tabela de preços do Acquaplay da Tecnisa aqui:http://tinyurl.com/acquaplaypreco web false false 13735402 Tecnisa S.A Tecnisa Mais construtora por m2 Faria Lima, 3144 - SP http://s3.amazonaws.com/twitter_production/profile_images/56572222/logo_normal.jpg http://www.tecnisa.com.br false 77 Sun Dec 07 00:36:16 +0000 2008 1042729108 devin harris has the flu. always have the memory of jordan scoring 50 on the knicks at the garden with the flu web false false 17930773 24 Seconds to Shoot NBA24sts NBA handicapping insight and analysis. las vegas http://s3.amazonaws.com/twitter_production/profile_images/66593862/fresno_normal.jpg false 1 Sun Dec 07 00:36:16 +0000 2008 1042729105 At Brandon and Shannon's holiday party.. twitterberry false false 5388602 Mike J. (Telligent) mjamrst Video Game Account Manager Palo Alto, CA http://s3.amazonaws.com/twitter_production/profile_images/66375174/Thanksgiving_11272008-048_normal.jpg http://www.telligent.com false 225 Sun Dec 07 00:36:13 +0000 2008 1042729104 Xinhua: Forty percent of Australian PM office' staff quit : CANBERRA, Dec. 7 (Xinhua) -- Only.. http://tinyurl.com/5gwotd twitterfeed false false 11566502 Headline News headlinenews http://s3.amazonaws.com/twitter_production/profile_images/41784602/1890_wires_normal.jpg false 575 Sun Dec 07 00:36:13 +0000 2008 1042729101 @hilarycassman soo funnny sms false 1042725825 17644455 false 17887548 katieballss katieballss http://s3.amazonaws.com/twitter_production/profile_images/66523737/th_Photo87_normal.jpg http://www.myspace.com/xxpeachxx101 false 23 Sun Dec 07 00:36:13 +0000 2008 1042729100 d'ora in poi, oltre al ferragosto, odiera' anche il natale e tutto il mese che ci gira intorno.. =.='' mobile false false 9719482 trotto trotto sociologo di formazione... uno dei tanti attivisti! :) Fano - Italy http://s3.amazonaws.com/twitter_production/profile_images/55603933/mybob-calimetux-1526_normal.png http://trotto1308.netsons.org/wordpress/ false 98 Sun Dec 07 00:36:13 +0000 2008 1042729099 Came across an ad on another site with a redneck looking santa... said "Bust Santa's zit and win a free ipod." Umm... disturbing much? web false false 9937182 froggybluesock froggybluesock Indiana http://s3.amazonaws.com/twitter_production/profile_images/35393032/about_me_normal.jpg http://www.footprintsonthemoon.com false 82 Sun Dec 07 00:36:17 +0000 2008 1042729098 nothing web false false 17932339 treblehook treblehook http://static.twitter.com/images/default_profile_normal.png false 0 Sun Dec 07 00:36:13 +0000 2008 1042729095 Setting up my new Windows Live profile web false false 17906075 Mark_Layton Mark_Layton http://static.twitter.com/images/default_profile_normal.png false 2 Sun Dec 07 00:36:13 +0000 2008 1042729092 me voy a sobar, a ver si mañana estoy mejor, wenas noches a tod@s web false false 14062655 tmaniak tmaniak http://s3.amazonaws.com/twitter_production/profile_images/51680481/BF-109_normal.jpg http://dhost.info/tmaniak false 10 Sun Dec 07 00:36:14 +0000 2008 1042729090 バイト延長戦入りましたー 店長が遅刻ってどうなんだ。しかも何回も natsuliphone false false 15618846 kabayaki kabayaki FPS(L4D、TF2、CS:S、BF)、TPS、RCG、マンガ、アニメ、デジモノが好きなとある学生 tokyo http://s3.amazonaws.com/twitter_production/profile_images/57305902/184_normal.jpg http://kabayakiya.blog43.fc2.com/ false 20 Sun Dec 07 00:36:13 +0000 2008 1042729089 just drove to southern california and joy of children hugging grandparents made it all worthwhile. heading to imedia in la quinta tomorrow. web false false 1630261 mark silva marksilva digital media http://realbranding.com Principal, Managing Director often san francisco http://s3.amazonaws.com/twitter_production/profile_images/29807902/silvasimpson3th_normal.jpg http://marksilva.com false 497 Sun Dec 07 00:36:14 +0000 2008 1042729088 @wholefoods would love to have a juicebar in one of your cambridge or boston locations web false 1041125103 15131310 false 15856582 Maura McGovern mmcgovern photographer with a day job in venture capital; obsessed with design blogs, long walks, yoga, social networking, people watching. tea and music are essential! Boston http://s3.amazonaws.com/twitter_production/profile_images/66110383/DSCN1740_normal.JPG http://lefteyephotography.blogspot.com false 244 Sun Dec 07 00:36:15 +0000 2008 1042729087 Going over the Advent lists. web false false 17122107 gsusan gsusan US American writer/sister/daughter/aunt/woman from New England living in SoCal. San Diego, CA USA http://s3.amazonaws.com/twitter_production/profile_images/63951854/susan_ocracoke_normal.jpg false 6 httparty-0.12.0/spec/fixtures/ssl/0000755000004100000410000000000012254052222017101 5ustar www-datawww-datahttparty-0.12.0/spec/fixtures/ssl/generated/0000755000004100000410000000000012254052222021037 5ustar www-datawww-datahttparty-0.12.0/spec/fixtures/ssl/generated/bogushost.crt0000644000004100000410000000137112254052222023570 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIICBTCCAW6gAwIBAgIBATANBgkqhkiG9w0BAQUFADAuMSwwKgYDVQQDEyNJTlNF Q1VSRSBUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTAgFw0xMDEwMjAxMzQ2MjNa GA80NzQ4MDkxNTEzNDYyM1owDzENMAsGA1UEAxMEYm9nbzCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEAr6b0ZBrRrVvPmPbQv36Jnj5jv00ZkhimXrmbv9Z1AdIZ WSsBpMd8TP7exE5OR5/DaxKmiZqVskgRyRkLm52/Dkt7Ncrzr5I3unHnMqsAv/28 5fGlYoRxnkCGMse/6NOFgCemRFw/bglxPNAGrFYKStameBRbCm0dCgtlvcwzdf8C AwEAAaNQME4wDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUddLPFtGmb0aFWbTl2kAo xD+fd6kwHwYDVR0jBBgwFoAUy0Lz6RgmtpywlBOXdPABQArp358wDQYJKoZIhvcN AQEFBQADgYEAosqpPVsFu6cOIhGFT85Y1wwRUaihO0vWO7ghBU5ScuRU3tuvyJDZ Z/HoAMXV6XZjVZzRosjtPjFbyWkZYjUqJJRMyEaRiGArWe6urKLzwnD6R9O3eNa5 7bgFhzZ5WBldJmtq4A3oNqBuvgZkYM6NVKvS4UoakkTliHB21/mDOSY= -----END CERTIFICATE----- httparty-0.12.0/spec/fixtures/ssl/generated/ca.crt0000644000004100000410000000161012254052222022132 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIICbTCCAdagAwIBAgIJAIAeO9TXtJ45MA0GCSqGSIb3DQEBBQUAMC4xLDAqBgNV BAMTI0lOU0VDVVJFIFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MCAXDTEwMTAy MDEzNDYyM1oYDzQ3NDgwOTE1MTM0NjIzWjAuMSwwKgYDVQQDEyNJTlNFQ1VSRSBU ZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw gYkCgYEA3lkBcd352qiIIzqnyvvJj59cx1dnzMyjnuaK2cRH420rBfukLE2MbOVr 9nYq/7CdjqXpE8uFAF+UTSIK6MWZ/bidkr2xd/et/Ce2pVIVxH+rt3pJz3wZhC3H Yz+HU4CD2iI9wAzsb6mMV7md1fjlYfir4SBGGPTkcqUJUp2/tQMCAwEAAaOBkDCB jTAdBgNVHQ4EFgQUy0Lz6RgmtpywlBOXdPABQArp358wXgYDVR0jBFcwVYAUy0Lz 6RgmtpywlBOXdPABQArp35+hMqQwMC4xLDAqBgNVBAMTI0lOU0VDVVJFIFRlc3Qg Q2VydGlmaWNhdGUgQXV0aG9yaXR5ggkAgB471Ne0njkwDAYDVR0TBAUwAwEB/zAN BgkqhkiG9w0BAQUFAAOBgQCmi3JQm+EIWjkRlyz9sijkYS+Ps4opmd/weeaXwa4E gVBWJGyiduB+kBnfv61+/tDjlrbjBDH5dP8suczHQL8gox4zGgjw64KH4o1ujZYR cEPbhnUpwbXu7yItlajBZfpFefjF5P0Ao2iEzQldDy0D6nQ19h5QANvQxqweTPQp pw== -----END CERTIFICATE----- httparty-0.12.0/spec/fixtures/ssl/generated/1fe462c2.00000644000004100000410000000161012254052222022252 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIICbTCCAdagAwIBAgIJAIAeO9TXtJ45MA0GCSqGSIb3DQEBBQUAMC4xLDAqBgNV BAMTI0lOU0VDVVJFIFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MCAXDTEwMTAy MDEzNDYyM1oYDzQ3NDgwOTE1MTM0NjIzWjAuMSwwKgYDVQQDEyNJTlNFQ1VSRSBU ZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw gYkCgYEA3lkBcd352qiIIzqnyvvJj59cx1dnzMyjnuaK2cRH420rBfukLE2MbOVr 9nYq/7CdjqXpE8uFAF+UTSIK6MWZ/bidkr2xd/et/Ce2pVIVxH+rt3pJz3wZhC3H Yz+HU4CD2iI9wAzsb6mMV7md1fjlYfir4SBGGPTkcqUJUp2/tQMCAwEAAaOBkDCB jTAdBgNVHQ4EFgQUy0Lz6RgmtpywlBOXdPABQArp358wXgYDVR0jBFcwVYAUy0Lz 6RgmtpywlBOXdPABQArp35+hMqQwMC4xLDAqBgNVBAMTI0lOU0VDVVJFIFRlc3Qg Q2VydGlmaWNhdGUgQXV0aG9yaXR5ggkAgB471Ne0njkwDAYDVR0TBAUwAwEB/zAN BgkqhkiG9w0BAQUFAAOBgQCmi3JQm+EIWjkRlyz9sijkYS+Ps4opmd/weeaXwa4E gVBWJGyiduB+kBnfv61+/tDjlrbjBDH5dP8suczHQL8gox4zGgjw64KH4o1ujZYR cEPbhnUpwbXu7yItlajBZfpFefjF5P0Ao2iEzQldDy0D6nQ19h5QANvQxqweTPQp pw== -----END CERTIFICATE----- httparty-0.12.0/spec/fixtures/ssl/generated/ca.key0000644000004100000410000000157312254052222022142 0ustar www-datawww-data-----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQDeWQFx3fnaqIgjOqfK+8mPn1zHV2fMzKOe5orZxEfjbSsF+6Qs TYxs5Wv2dir/sJ2OpekTy4UAX5RNIgroxZn9uJ2SvbF39638J7alUhXEf6u3eknP fBmELcdjP4dTgIPaIj3ADOxvqYxXuZ3V+OVh+KvhIEYY9ORypQlSnb+1AwIDAQAB AoGBAL147VFCDlM1gGU865V+wIFCFQbNxedwjxGuda4io/v6oEoF6R3Tq5F0Y27v va6Lq4fOe/LhYGI0EKU2GEPJd3F2wA21r+81InPKAkqYI5CDQtKDDNLviur8ZVKF i3UzutjeYoCqmWeHaKPD6w5DtqeBieem7LTWRyXlFtHZV/nBAkEA8nsMOSd1+JTm ZT4HDsEFQrN8mIFUUioFSHPut2CwzvTEW+hTkLQiog3bua4n7uQOFImR63X9qMsh IjZRJQNmowJBAOq+mQdnRWYKl0SYb++Eb3uW6L4h1zsW375+caKo9omtpeqDW/y0 BWyY0q4DPkm3yU26Yr+b2JijISrml9/8PiECQQDHuXyG8y7jktn3GFE94NURbL+6 6gPnLX9ufzdoSjc4MDowrbtvHEDOlHWgioeP6L6EQhA0DtrhlnbzNCRARX3bAkEA jQOsF+dwqAjKr/lGnMKY2cxgyf64NZXbGKsKhmUrnK9E0SjR9G8MJx1yyffGzi/q bJf/xAzRw3eTcBsPtwznIQJAHq5MOK7oaUuO+6cbsZYpOYOOkKIvDLiOtdSr7LTI DziH/fpzB0VhCmFhhEQwHhlB4t3m66A9TelHmhrCDsIaLA== -----END RSA PRIVATE KEY----- httparty-0.12.0/spec/fixtures/ssl/generated/selfsigned.crt0000644000004100000410000000143212254052222023674 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIICHTCCAYagAwIBAgIJALT/G+ylQljIMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV BAMTCWxvY2FsaG9zdDAgFw0xMDEwMjAxMzQ2MjNaGA80NzQ4MDkxNTEzNDYyM1ow FDESMBAGA1UEAxMJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB gQCvpvRkGtGtW8+Y9tC/fomePmO/TRmSGKZeuZu/1nUB0hlZKwGkx3xM/t7ETk5H n8NrEqaJmpWySBHJGQubnb8OS3s1yvOvkje6cecyqwC//bzl8aVihHGeQIYyx7/o 04WAJ6ZEXD9uCXE80AasVgpK1qZ4FFsKbR0KC2W9zDN1/wIDAQABo3UwczAdBgNV HQ4EFgQUddLPFtGmb0aFWbTl2kAoxD+fd6kwRAYDVR0jBD0wO4AUddLPFtGmb0aF WbTl2kAoxD+fd6mhGKQWMBQxEjAQBgNVBAMTCWxvY2FsaG9zdIIJALT/G+ylQljI MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAlOCBO54S88mD3VYviER6 V+lkd7iWmdas2wUUDeMKA9CxnirWi7ne2U7wQH/5FJ1j3ImSfjb4h/98xiVJE84e Ld7mb61g/M4g4b62kt0HK8/cGUxfuz5zwIfi28qJq3ow6AFEq1fywbJvUAnnamwU cZF/qoVfJhus2mXjYc4hFWg= -----END CERTIFICATE----- httparty-0.12.0/spec/fixtures/ssl/generated/server.crt0000644000004100000410000000140112254052222023053 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIICCjCCAXOgAwIBAgIBATANBgkqhkiG9w0BAQUFADAuMSwwKgYDVQQDEyNJTlNF Q1VSRSBUZXN0IENlcnRpZmljYXRlIEF1dGhvcml0eTAgFw0xMDEwMjAxMzQ2MjNa GA80NzQ4MDkxNTEzNDYyM1owFDESMBAGA1UEAxMJbG9jYWxob3N0MIGfMA0GCSqG SIb3DQEBAQUAA4GNADCBiQKBgQCvpvRkGtGtW8+Y9tC/fomePmO/TRmSGKZeuZu/ 1nUB0hlZKwGkx3xM/t7ETk5Hn8NrEqaJmpWySBHJGQubnb8OS3s1yvOvkje6cecy qwC//bzl8aVihHGeQIYyx7/o04WAJ6ZEXD9uCXE80AasVgpK1qZ4FFsKbR0KC2W9 zDN1/wIDAQABo1AwTjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBR10s8W0aZvRoVZ tOXaQCjEP593qTAfBgNVHSMEGDAWgBTLQvPpGCa2nLCUE5d08AFACunfnzANBgkq hkiG9w0BAQUFAAOBgQCR4Oor0YAvK0tNFrOLtqmC6D0F5IYCyu7komk7JGn9L4nn 7VyVxd4MXdc1r1v+WP5JtnA9ZjMmEmH9gl4gwR/Cu+TMkArsq0Z8mREOLNL8pwpx Zxgk0CwacYR9RQcpuJ9nSDzVoO5ecYkb5C9q7gwgqbmCzr7oz/rwTqRwiUZCVQ== -----END CERTIFICATE----- httparty-0.12.0/spec/fixtures/ssl/generated/server.key0000644000004100000410000000156712254052222023070 0ustar www-datawww-data-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQCvpvRkGtGtW8+Y9tC/fomePmO/TRmSGKZeuZu/1nUB0hlZKwGk x3xM/t7ETk5Hn8NrEqaJmpWySBHJGQubnb8OS3s1yvOvkje6cecyqwC//bzl8aVi hHGeQIYyx7/o04WAJ6ZEXD9uCXE80AasVgpK1qZ4FFsKbR0KC2W9zDN1/wIDAQAB AoGALIdgkTgTS6VovVhklwcXEBy04LxE7Tp+gqj/COTvCKUgc/BpHELOCh7ajl1j jti7i5tQyLV9mZKXn6lPvgWBd0w+p6VhM4NFA97CoodEJm2ckFC9zUABCh9dOpbm 8KzF7hdpYWgJJchwwZ60tbcP7K1DkiNX6Kk9qKQEWvitMBECQQDpOSzzLldcEU9l ze/nG2+rf6ecaPnKeafY8R2qVils8I7ZJAW3+0bNT5gQs7rT7aWo8vMvrXq++lWb JkNV6hK9AkEAwM5wsmg7REmAaDwgUBq5mNt963/uG2ihAODFS70lYT23UYl5Y3rD s3qU4ntG4DvWIQgPdwdstzDh9fMBVXa1awJBAID1WoOE5k1ETRDP1I2HwDGmPnng Ge75YfQ1LuAXEITqZzJuFrNqv/Waw0zI9M9moqlO3WVJmYusRFWrzKPe8EkCQEwC FlN+275z63csHOD3aCtmfCGW8VtEyBP8iErvagkHt3khZQVepD/hF0ihqLNFY4jq EI6wEp+1WZ8ICYKTpbkCQQDhl5QLdy5Xo3k3agCnB9nktSzs2iqFvsGvfOAW4628 iThKTNua6bBvbdiG0Vh2Sv0XBYVJoHB3WnTVgFyPJaaF -----END RSA PRIVATE KEY----- httparty-0.12.0/spec/fixtures/ssl/openssl-exts.cnf0000644000004100000410000000033412254052222022235 0ustar www-datawww-data[ca] basicConstraints=critical,CA:true subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer:always [cert] basicConstraints=critical,CA:false subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer httparty-0.12.0/spec/fixtures/ssl/generate.sh0000755000004100000410000000241212254052222021231 0ustar www-datawww-data#!/bin/sh set -e if [ -d "generated" ] ; then echo >&2 "error: 'generated' directory already exists. Delete it first." exit 1 fi mkdir generated # Generate the CA private key and certificate openssl req -batch -subj '/CN=INSECURE Test Certificate Authority' -newkey rsa:1024 -new -x509 -days 999999 -keyout generated/ca.key -nodes -out generated/ca.crt # Create symlinks for ssl_ca_path c_rehash generated # Generate the server private key and self-signed certificate openssl req -batch -subj '/CN=localhost' -newkey rsa:1024 -new -x509 -days 999999 -keyout generated/server.key -nodes -out generated/selfsigned.crt # Generate certificate signing request with bogus hostname openssl req -batch -subj '/CN=bogo' -new -days 999999 -key generated/server.key -nodes -out generated/bogushost.csr # Sign the certificate requests openssl x509 -CA generated/ca.crt -CAkey generated/ca.key -set_serial 1 -in generated/selfsigned.crt -out generated/server.crt -clrext -extfile openssl-exts.cnf -extensions cert -days 999999 openssl x509 -req -CA generated/ca.crt -CAkey generated/ca.key -set_serial 1 -in generated/bogushost.csr -out generated/bogushost.crt -clrext -extfile openssl-exts.cnf -extensions cert -days 999999 # Remove certificate signing requests rm -f generated/*.csr httparty-0.12.0/spec/fixtures/twitter.json0000644000004100000410000003131212254052222020675 0ustar www-datawww-data[{"user":{"followers_count":1,"description":null,"url":null,"profile_image_url":"http:\/\/static.twitter.com\/images\/default_profile_normal.png","protected":false,"location":"Opera Plaza, California","screen_name":"Pyk","name":"Pyk","id":"7694602"},"text":"@lapilofu If you need a faster transfer, target disk mode should work too :)","truncated":false,"favorited":false,"in_reply_to_user_id":6128642,"created_at":"Sat Dec 06 21:29:14 +0000 2008","source":"twitterrific","in_reply_to_status_id":1042497164,"id":"1042500587"},{"user":{"followers_count":278,"description":"しがないプログラマ\/とりあえず宮子は俺の嫁\u2026いや、娘だ!\/Delphi&Pythonプログラマ修行中\/bot製作にハマりつつある。三つほど製作&構想中\/[eof]","url":"http:\/\/logiq.orz.hm\/","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/59588711\/l_ワ_l↑_normal.png","protected":false,"location":"ひだまり荘202号室","screen_name":"feiz","name":"azkn3","id":"14310520"},"text":"@y_benjo ちょー遅レスですがただのはだいろすぎる・・・ ( ll ワ ll )","truncated":false,"favorited":false,"in_reply_to_user_id":8428752,"created_at":"Sat Dec 06 21:29:14 +0000 2008","source":"twit","in_reply_to_status_id":1042479758,"id":"1042500586"},{"user":{"followers_count":1233,"description":""to understand one life you must swallow the world." I run refine+focus: a marketing agency working w\/ brands, media and VCs. http:\/\/tinyurl.com\/63mrn","url":"http:\/\/www.quiverandquill.com","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/53684650\/539059005_2a3b462d20_normal.jpg","protected":false,"location":"Cambridge, MA ","screen_name":"quiverandquill","name":"zach Braiker","id":"6845872"},"text":"@18percentgrey I didn't see Damon on Palin. i'll look on youtube. thx .Z","truncated":false,"favorited":false,"in_reply_to_user_id":10529932,"created_at":"Sat Dec 06 21:29:12 +0000 2008","source":"web","in_reply_to_status_id":1042499331,"id":"1042500584"},{"user":{"followers_count":780,"description":"Mein Blog ist unter http:\/\/blog.helmschrott.de zu finden. Unter http:\/\/blogalm.de kannst Du Deinen Blog eintragen!","url":"http:\/\/helmschrott.de\/blog","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/60997686\/avatar-250_normal.jpg","protected":false,"location":"Münchner Straße","screen_name":"helmi","name":"Frank Helmschrott","id":"867641"},"text":"@gigold auch mist oder?ich glaub ich fangs jetzt dann einfach mal an - wird schon vernünftige update-prozesse geben.","truncated":false,"favorited":false,"in_reply_to_user_id":959931,"created_at":"Sat Dec 06 21:29:11 +0000 2008","source":"twhirl","in_reply_to_status_id":1042500095,"id":"1042500583"},{"user":{"followers_count":63,"description":"Liberation from Misconceptions","url":"http:\/\/sexorcism.blogspot.com","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/63897302\/having-sex-on-bed_normal.jpg","protected":false,"location":"USA","screen_name":"Sexorcism","name":"Sexorcism","id":"16929435"},"text":"@thursdays_child someecards might.","truncated":false,"favorited":false,"in_reply_to_user_id":14484963,"created_at":"Sat Dec 06 21:29:13 +0000 2008","source":"twittergadget","in_reply_to_status_id":1042499777,"id":"1042500581"},{"user":{"followers_count":106,"description":"Researcher. Maître de Conférences - Sémiologue - Spécialiste des médias audiovisuels. Analyste des médias, de la télévision et de la presse people (gossip). ","url":"http:\/\/semioblog.over-blog.org\/","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/57988482\/Thomas_et_Vic_pour_promo_2_058_normal.JPG","protected":false,"location":"France","screen_name":"semioblog","name":"Virginie Spies","id":"10078802"},"text":"@richardvonstern on reparle de tout cela bientôt, si vous voulez vraiment m'aider","truncated":false,"favorited":false,"in_reply_to_user_id":15835317,"created_at":"Sat Dec 06 21:29:13 +0000 2008","source":"twitterrific","in_reply_to_status_id":1042357537,"id":"1042500580"},{"user":{"followers_count":26,"description":"","url":"","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/63461084\/November2ndpics_125_normal.jpg","protected":false,"location":"Louisville, Ky","screen_name":"scrapaunt","name":"scrapaunt","id":"16660671"},"text":"@NKOTB4LIFE Hope your neck feels better after your nap.","truncated":false,"favorited":false,"in_reply_to_user_id":16041403,"created_at":"Sat Dec 06 21:29:10 +0000 2008","source":"web","in_reply_to_status_id":1042450159,"id":"1042500579"},{"user":{"followers_count":245,"description":"Maui HI Real Estate Salesperson specializing in off the grid lifestyle","url":"http:\/\/www.eastmaui.com","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/59558480\/face2_normal.jpg","protected":false,"location":"north shore maui hawaii","screen_name":"mauihunter","name":"Georgina M. Hunter ","id":"16161708"},"text":"@BeeRealty http:\/\/twitpic.com\/qpog - It's a good safe place to lay - no dogs up there.","truncated":false,"favorited":false,"in_reply_to_user_id":15781063,"created_at":"Sat Dec 06 21:29:13 +0000 2008","source":"twitpic","in_reply_to_status_id":1042497815,"id":"1042500578"},{"user":{"followers_count":95,"description":"","url":"","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/66581657\/nose-pick_normal.jpg","protected":false,"location":"zoetermeer","screen_name":"GsKlukkluk","name":"Klukkluk","id":"14218588"},"text":"twit \/off zalige nacht!","truncated":false,"favorited":false,"in_reply_to_user_id":null,"created_at":"Sat Dec 06 21:29:14 +0000 2008","source":"web","in_reply_to_status_id":null,"id":"1042500577"},{"user":{"followers_count":33,"description":"Living in denial that I live in a podunk town, I spend my time in search of good music in LA. Pure city-dweller and puma. That's about it.","url":"","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/56024131\/Photo_145_normal.jpg","protected":false,"location":"Santa Barbara, CA","screen_name":"pumainthemvmt","name":"Valerie","id":"15266837"},"text":"I love my parents with all my heart, but sometimes they make me want to scratch my eyes out.","truncated":false,"favorited":false,"in_reply_to_user_id":null,"created_at":"Sat Dec 06 21:29:10 +0000 2008","source":"sms","in_reply_to_status_id":null,"id":"1042500576"},{"user":{"followers_count":99,"description":"大学生ですよ。Ad[es]er。趣味で辭書とか編輯してゐます。JavaScriptでゲーム書きたいけど時間ねえ。","url":"http:\/\/greengablez.net\/diary\/","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/60269370\/zonu_1_normal.gif","protected":false,"location":"Sapporo, Hokkaido, Japan","screen_name":"tadsan","name":"船越次男","id":"11637282"},"text":"リトル・プリンセスとだけ書かれたら小公女を連想するだろ、常識的に考へて。","truncated":false,"favorited":false,"in_reply_to_user_id":null,"created_at":"Sat Dec 06 21:29:11 +0000 2008","source":"tiitan","in_reply_to_status_id":null,"id":"1042500575"},{"user":{"followers_count":68,"description":"I love all things beer. What goes better with beer than Porn, nothig I tell ya nothing.","url":"","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/66479069\/Picture_9_normal.jpg","protected":false,"location":"Durant","screen_name":"Jeffporn","name":"Jeffporn","id":"14065262"},"text":"At Lefthand having milk stout on cask - Photo: http:\/\/bkite.com\/02PeH","truncated":false,"favorited":false,"in_reply_to_user_id":null,"created_at":"Sat Dec 06 21:29:10 +0000 2008","source":"brightkite","in_reply_to_status_id":null,"id":"1042500574"},{"user":{"followers_count":7,"description":"","url":"http:\/\/www.PeteKinser.com","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/65572489\/PeteKinser-close_normal.jpg","protected":false,"location":"Denver, CO","screen_name":"pkinser","name":"pkinser","id":"15570525"},"text":"Snooze is where it's at for brunch if you're ever in Denver. Yum.","truncated":false,"favorited":false,"in_reply_to_user_id":null,"created_at":"Sat Dec 06 21:29:11 +0000 2008","source":"fring","in_reply_to_status_id":null,"id":"1042500572"},{"user":{"followers_count":75,"description":"I am a gamer and this is my gaming account, check out my other Twitter account for non-gaming tweets.","url":"http:\/\/twitter.com\/Nailhead","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/56881055\/nailhead_184x184_normal.jpg","protected":false,"location":"Huntsville, AL","screen_name":"Nailhead_Gamer","name":"Eric Fullerton","id":"15487663"},"text":"Completed the epic quest line for the Death Knight. Now what? Outlands? I wish to skip Outlands please, thanks.","truncated":false,"favorited":false,"in_reply_to_user_id":null,"created_at":"Sat Dec 06 21:29:13 +0000 2008","source":"twitterfox","in_reply_to_status_id":null,"id":"1042500571"},{"user":{"followers_count":111,"description":"","url":"http:\/\/www.ns-tech.com\/blog\/geldred.nsf","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/63865052\/brak2_normal.JPG","protected":false,"location":"Cleveland OH","screen_name":"geldred","name":"geldred","id":"14093394"},"text":"I'm at Target Store - Avon OH (35830 Detroit Rd, Avon, OH 44011, USA) - http:\/\/bkite.com\/02PeI","truncated":false,"favorited":false,"in_reply_to_user_id":null,"created_at":"Sat Dec 06 21:29:13 +0000 2008","source":"brightkite","in_reply_to_status_id":null,"id":"1042500570"},{"user":{"followers_count":16,"description":"Soundtrack Composer\/Musician\/Producer","url":"http:\/\/www.reverbnation\/musicbystratos","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/63311865\/logo-stratos_normal.png","protected":false,"location":"Grove City, Ohio 43123","screen_name":"Stratos","name":"Bryan K Borgman","id":"756062"},"text":"is reminded how beautiful the world can be when it's blanketed by clean white snow.","truncated":false,"favorited":false,"in_reply_to_user_id":null,"created_at":"Sat Dec 06 21:29:13 +0000 2008","source":"web","in_reply_to_status_id":null,"id":"1042500569"},{"user":{"followers_count":7,"description":null,"url":null,"profile_image_url":"http:\/\/static.twitter.com\/images\/default_profile_normal.png","protected":false,"location":null,"screen_name":"garrettromine","name":"garrettromine","id":"16120885"},"text":"Go Julio","truncated":false,"favorited":false,"in_reply_to_user_id":null,"created_at":"Sat Dec 06 21:29:10 +0000 2008","source":"sms","in_reply_to_status_id":null,"id":"1042500568"},{"user":{"followers_count":111,"description":"WHAT IS HAPPNING IN THE WORLD??? SEE DIFFERENT NEWS STORIES FROM MANY SOURCES.","url":"http:\/\/henrynews.wetpaint.com","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/65118112\/2008-election-map-nytimes_normal.png","protected":false,"location":"","screen_name":"HenryNews","name":"HenryNews","id":"17398510"},"text":"Svindal completes double at Beaver Creek: Read full story for latest details. http:\/\/tinyurl.com\/6qugub","truncated":false,"favorited":false,"in_reply_to_user_id":null,"created_at":"Sat Dec 06 21:29:13 +0000 2008","source":"twitterfeed","in_reply_to_status_id":null,"id":"1042500567"},{"user":{"followers_count":34,"description":"I am a man of many bio's, scott bio's!","url":"http:\/\/flickr.com\/photos\/giantcandy","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/25680382\/Icon_for_Twitter_normal.jpg","protected":false,"location":"Loves Park, IL, USA","screen_name":"Pychobj2001","name":"William Boehm Jr","id":"809103"},"text":"I have a 3rd break light and the license plate lights are out...just replacing 1 plate light...abide by law just enough","truncated":false,"favorited":false,"in_reply_to_user_id":null,"created_at":"Sat Dec 06 21:29:10 +0000 2008","source":"twidroid","in_reply_to_status_id":null,"id":"1042500566"},{"user":{"followers_count":61,"description":"Wife. Designer. Green Enthusiast. New Homeowner. Pet Owner. Internet Addict.","url":"http:\/\/confessionsofadesignjunkie.blogspot.com\/","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/66044439\/n27310459_33432814_6743-1_normal.jpg","protected":false,"location":"Indiana","screen_name":"smquaseb","name":"Stacy","id":"15530992"},"text":"@Indygardener We still had a few people shoveling in our neighborhood - I didn't think it was enough to shovel, but keeps the kids busy.","truncated":false,"favorited":false,"in_reply_to_user_id":12811482,"created_at":"Sat Dec 06 21:29:13 +0000 2008","source":"web","in_reply_to_status_id":1042488558,"id":"1042500565"}]httparty-0.12.0/spec/fixtures/empty.xml0000644000004100000410000000000012254052222020146 0ustar www-datawww-datahttparty-0.12.0/spec/fixtures/delicious.xml0000644000004100000410000001633512254052222021012 0ustar www-datawww-data httparty-0.12.0/spec/fixtures/undefined_method_add_node_for_nil.xml0000644000004100000410000000024112254052222025645 0ustar www-datawww-data httparty-0.12.0/spec/httparty_spec.rb0000644000004100000410000005750412254052222017660 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper')) describe HTTParty do before(:each) do @klass = Class.new @klass.instance_eval { include HTTParty } end describe "AllowedFormats deprecated" do before do Kernel.stub(:warn) end it "warns with a deprecation message" do Kernel.should_receive(:warn).with("Deprecated: Use HTTParty::Parser::SupportedFormats") HTTParty::AllowedFormats end it "returns HTTPart::Parser::SupportedFormats" do HTTParty::AllowedFormats.should == HTTParty::Parser::SupportedFormats end end describe "pem" do it 'should set the pem content' do @klass.pem 'PEM-CONTENT' @klass.default_options[:pem].should == 'PEM-CONTENT' end it "should set the password to nil if it's not provided" do @klass.pem 'PEM-CONTENT' @klass.default_options[:pem_password].should be_nil end it 'should set the password' do @klass.pem 'PEM-CONTENT', 'PASSWORD' @klass.default_options[:pem_password].should == 'PASSWORD' end end describe 'ssl_version' do it 'should set the ssl_version content' do @klass.ssl_version :SSLv3 @klass.default_options[:ssl_version].should == :SSLv3 end end describe 'ciphers' do it 'should set the ciphers content' do @klass.default_options[:ciphers].should be_nil @klass.ciphers 'RC4-SHA' @klass.default_options[:ciphers].should == 'RC4-SHA' end end describe 'http_proxy' do it 'should set the address' do @klass.http_proxy 'proxy.foo.com', 80 options = @klass.default_options options[:http_proxyaddr].should == 'proxy.foo.com' options[:http_proxyport].should == 80 end it 'should set the proxy user and pass when they are provided' do @klass.http_proxy 'proxy.foo.com', 80, 'user', 'pass' options = @klass.default_options options[:http_proxyuser].should == 'user' options[:http_proxypass].should == 'pass' end end describe "base uri" do before(:each) do @klass.base_uri('api.foo.com/v1') end it "should have reader" do @klass.base_uri.should == 'http://api.foo.com/v1' end it 'should have writer' do @klass.base_uri('http://api.foobar.com') @klass.base_uri.should == 'http://api.foobar.com' end it 'should not modify the parameter during assignment' do uri = 'http://api.foobar.com' @klass.base_uri(uri) uri.should == 'http://api.foobar.com' end end describe ".disable_rails_query_string_format" do it "sets the query string normalizer to HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER" do @klass.disable_rails_query_string_format @klass.default_options[:query_string_normalizer].should == HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER end end describe ".normalize_base_uri" do it "should add http if not present for non ssl requests" do uri = HTTParty.normalize_base_uri('api.foobar.com') uri.should == 'http://api.foobar.com' end it "should add https if not present for ssl requests" do uri = HTTParty.normalize_base_uri('api.foo.com/v1:443') uri.should == 'https://api.foo.com/v1:443' end it "should not remove https for ssl requests" do uri = HTTParty.normalize_base_uri('https://api.foo.com/v1:443') uri.should == 'https://api.foo.com/v1:443' end it 'should not modify the parameter' do uri = 'http://api.foobar.com' HTTParty.normalize_base_uri(uri) uri.should == 'http://api.foobar.com' end it "should not treat uri's with a port of 4430 as ssl" do uri = HTTParty.normalize_base_uri('http://api.foo.com:4430/v1') uri.should == 'http://api.foo.com:4430/v1' end end describe "headers" do def expect_headers(header={}) HTTParty::Request.should_receive(:new) \ .with(anything, anything, hash_including({ :headers => header })) \ .and_return(mock("mock response", :perform => nil)) end it "should default to empty hash" do @klass.headers.should == {} end it "should be able to be updated" do init_headers = {:foo => 'bar', :baz => 'spax'} @klass.headers init_headers @klass.headers.should == init_headers end it "uses the class headers when sending a request" do expect_headers(:foo => 'bar') @klass.headers(:foo => 'bar') @klass.get('') end it "overwrites class headers when passing in headers" do expect_headers(:baz => 'spax') @klass.headers(:foo => 'bar') @klass.get('', :headers => {:baz => 'spax'}) end context "with cookies" do it 'utilizes the class-level cookies' do expect_headers(:foo => 'bar', 'cookie' => 'type=snickerdoodle') @klass.headers(:foo => 'bar') @klass.cookies(:type => 'snickerdoodle') @klass.get('') end it 'adds cookies to the headers' do expect_headers(:foo => 'bar', 'cookie' => 'type=snickerdoodle') @klass.headers(:foo => 'bar') @klass.get('', :cookies => {:type => 'snickerdoodle'}) end it 'adds optional cookies to the optional headers' do expect_headers(:baz => 'spax', 'cookie' => 'type=snickerdoodle') @klass.get('', :cookies => {:type => 'snickerdoodle'}, :headers => {:baz => 'spax'}) end end end describe "cookies" do def expect_cookie_header(s) HTTParty::Request.should_receive(:new) \ .with(anything, anything, hash_including({ :headers => { "cookie" => s } })) \ .and_return(mock("mock response", :perform => nil)) end it "should not be in the headers by default" do HTTParty::Request.stub!(:new).and_return(stub(nil, :perform => nil)) @klass.get("") @klass.headers.keys.should_not include("cookie") end it "should raise an ArgumentError if passed a non-Hash" do lambda do @klass.cookies("nonsense") end.should raise_error(ArgumentError) end it "should allow a cookie to be specified with a one-off request" do expect_cookie_header "type=snickerdoodle" @klass.get("", :cookies => { :type => "snickerdoodle" }) end describe "when a cookie is set at the class level" do before(:each) do @klass.cookies({ :type => "snickerdoodle" }) end it "should include that cookie in the request" do expect_cookie_header "type=snickerdoodle" @klass.get("") end it "should pass the proper cookies when requested multiple times" do 2.times do expect_cookie_header "type=snickerdoodle" @klass.get("") end end it "should allow the class defaults to be overridden" do expect_cookie_header "type=chocolate_chip" @klass.get("", :cookies => { :type => "chocolate_chip" }) end end describe "in a class with multiple methods that use different cookies" do before(:each) do @klass.instance_eval do def first_method get("first_method", :cookies => { :first_method_cookie => "foo" }) end def second_method get("second_method", :cookies => { :second_method_cookie => "foo" }) end end end it "should not allow cookies used in one method to carry over into other methods" do expect_cookie_header "first_method_cookie=foo" @klass.first_method expect_cookie_header "second_method_cookie=foo" @klass.second_method end end end describe "default params" do it "should default to empty hash" do @klass.default_params.should == {} end it "should be able to be updated" do new_defaults = {:foo => 'bar', :baz => 'spax'} @klass.default_params new_defaults @klass.default_params.should == new_defaults end end describe "default timeout" do it "should default to nil" do @klass.default_options[:timeout].should == nil end it "should support updating" do @klass.default_timeout 10 @klass.default_options[:timeout].should == 10 end it "should support floats" do @klass.default_timeout 0.5 @klass.default_options[:timeout].should == 0.5 end end describe "debug_output" do it "stores the given stream as a default_option" do @klass.debug_output $stdout @klass.default_options[:debug_output].should == $stdout end it "stores the $stderr stream by default" do @klass.debug_output @klass.default_options[:debug_output].should == $stderr end end describe "basic http authentication" do it "should work" do @klass.basic_auth 'foobar', 'secret' @klass.default_options[:basic_auth].should == {:username => 'foobar', :password => 'secret'} end end describe "digest http authentication" do it "should work" do @klass.digest_auth 'foobar', 'secret' @klass.default_options[:digest_auth].should == {:username => 'foobar', :password => 'secret'} end end describe "parser" do class CustomParser def self.parse(body) return {:sexy => true} end end let(:parser) do Proc.new{ |data, format| CustomParser.parse(data) } end it "should set parser options" do @klass.parser parser @klass.default_options[:parser].should == parser end it "should be able parse response with custom parser" do @klass.parser parser FakeWeb.register_uri(:get, 'http://twitter.com/statuses/public_timeline.xml', :body => 'tweets') custom_parsed_response = @klass.get('http://twitter.com/statuses/public_timeline.xml') custom_parsed_response[:sexy].should == true end it "raises UnsupportedFormat when the parser cannot handle the format" do @klass.format :json class MyParser < HTTParty::Parser SupportedFormats = {} end unless defined?(MyParser) expect do @klass.parser MyParser end.to raise_error(HTTParty::UnsupportedFormat) end it 'does not validate format whe custom parser is a proc' do expect do @klass.format :json @klass.parser lambda {|body, format|} end.to_not raise_error(HTTParty::UnsupportedFormat) end end describe "connection_adapter" do let(:uri) { 'http://google.com/api.json' } let(:connection_adapter) { mock('CustomConnectionAdapter') } it "should set the connection_adapter" do @klass.connection_adapter connection_adapter @klass.default_options[:connection_adapter].should be connection_adapter end it "should set the connection_adapter_options when provided" do options = {:foo => :bar} @klass.connection_adapter connection_adapter, options @klass.default_options[:connection_adapter_options].should be options end it "should not set the connection_adapter_options when not provided" do @klass.connection_adapter connection_adapter @klass.default_options[:connection_adapter_options].should be_nil end it "should process a request with a connection from the adapter" do connection_adapter_options = {:foo => :bar} connection_adapter.should_receive(:call) do |u,o| o[:connection_adapter_options].should == connection_adapter_options HTTParty::ConnectionAdapter.call(u,o) end.with(URI.parse(uri), kind_of(Hash)) FakeWeb.register_uri(:get, uri, :body => 'stuff') @klass.connection_adapter connection_adapter, connection_adapter_options @klass.get(uri).should == 'stuff' end end describe "format" do it "should allow xml" do @klass.format :xml @klass.default_options[:format].should == :xml end it "should allow json" do @klass.format :json @klass.default_options[:format].should == :json end it "should allow plain" do @klass.format :plain @klass.default_options[:format].should == :plain end it 'should not allow funky format' do lambda do @klass.format :foobar end.should raise_error(HTTParty::UnsupportedFormat) end it 'should only print each format once with an exception' do lambda do @klass.format :foobar end.should raise_error(HTTParty::UnsupportedFormat, "':foobar' Must be one of: html, json, plain, xml") end it 'sets the default parser' do @klass.default_options[:parser].should be_nil @klass.format :json @klass.default_options[:parser].should == HTTParty::Parser end it 'does not reset parser to the default parser' do my_parser = lambda {} @klass.parser my_parser @klass.format :json @klass.parser.should == my_parser end end describe "#no_follow" do it "sets no_follow to false by default" do @klass.no_follow @klass.default_options[:no_follow].should be_false end it "sets the no_follow option to true" do @klass.no_follow true @klass.default_options[:no_follow].should be_true end end describe "#maintain_method_across_redirects" do it "sets maintain_method_across_redirects to true by default" do @klass.maintain_method_across_redirects @klass.default_options[:maintain_method_across_redirects].should be_true end it "sets the maintain_method_across_redirects option to false" do @klass.maintain_method_across_redirects false @klass.default_options[:maintain_method_across_redirects].should be_false end end describe ".follow_redirects" do it "sets follow redirects to true by default" do @klass.follow_redirects @klass.default_options[:follow_redirects].should be_true end it "sets the follow_redirects option to false" do @klass.follow_redirects false @klass.default_options[:follow_redirects].should be_false end end describe ".query_string_normalizer" do it "sets the query_string_normalizer option" do normalizer = proc {} @klass.query_string_normalizer normalizer @klass.default_options[:query_string_normalizer].should == normalizer end end describe "with explicit override of automatic redirect handling" do before do @request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', :format => :xml, :no_follow => true) @redirect = stub_response 'first redirect', 302 @redirect['location'] = 'http://foo.com/bar' HTTParty::Request.stub(:new => @request) end it "should fail with redirected GET" do lambda do @error = @klass.get('/foo', :no_follow => true) end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'} end it "should fail with redirected POST" do lambda do @klass.post('/foo', :no_follow => true) end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'} end it "should fail with redirected PATCH" do lambda do @klass.patch('/foo', :no_follow => true) end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'} end it "should fail with redirected DELETE" do lambda do @klass.delete('/foo', :no_follow => true) end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'} end it "should fail with redirected MOVE" do lambda do @klass.move('/foo', :no_follow => true) end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'} end it "should fail with redirected COPY" do lambda do @klass.copy('/foo', :no_follow => true) end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'} end it "should fail with redirected PUT" do lambda do @klass.put('/foo', :no_follow => true) end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'} end it "should fail with redirected HEAD" do lambda do @klass.head('/foo', :no_follow => true) end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'} end it "should fail with redirected OPTIONS" do lambda do @klass.options('/foo', :no_follow => true) end.should raise_error(HTTParty::RedirectionTooDeep) {|e| e.response.body.should == 'first redirect'} end end describe "with multiple class definitions" do before(:each) do @klass.instance_eval do base_uri "http://first.com" default_params :one => 1 end @additional_klass = Class.new @additional_klass.instance_eval do include HTTParty base_uri "http://second.com" default_params :two => 2 end end it "should not run over each others options" do @klass.default_options.should == { :base_uri => 'http://first.com', :default_params => { :one => 1 } } @additional_klass.default_options.should == { :base_uri => 'http://second.com', :default_params => { :two => 2 } } end end describe "two child classes inheriting from one parent" do before(:each) do @parent = Class.new do include HTTParty def self.name "Parent" end end @child1 = Class.new(@parent) @child2 = Class.new(@parent) end it "does not modify each others inherited attributes" do @child1.default_params :joe => "alive" @child2.default_params :joe => "dead" @child1.default_options.should == { :default_params => {:joe => "alive"} } @child2.default_options.should == { :default_params => {:joe => "dead"} } @parent.default_options.should == { } end it "inherits default_options from the superclass" do @parent.basic_auth 'user', 'password' @child1.default_options.should == {:basic_auth => {:username => 'user', :password => 'password'}} @child1.basic_auth 'u', 'p' # modifying child1 has no effect on child2 @child2.default_options.should == {:basic_auth => {:username => 'user', :password => 'password'}} end it "doesn't modify the parent's default options" do @parent.basic_auth 'user', 'password' @child1.basic_auth 'u', 'p' @child1.default_options.should == {:basic_auth => {:username => 'u', :password => 'p'}} @child1.basic_auth 'email', 'token' @child1.default_options.should == {:basic_auth => {:username => 'email', :password => 'token'}} @parent.default_options.should == {:basic_auth => {:username => 'user', :password => 'password'}} end it "doesn't modify hashes in the parent's default options" do @parent.headers 'Accept' => 'application/json' @child1.headers 'Accept' => 'application/xml' @parent.default_options[:headers].should == {'Accept' => 'application/json'} @child1.default_options[:headers].should == {'Accept' => 'application/xml'} end it "works with lambda values" do @child1.default_options[:imaginary_option] = lambda { "This is a new lambda "} @child1.default_options[:imaginary_option].should be_a Proc end it 'should dup the proc on the child class' do imaginary_option = lambda { 2 * 3.14 } @parent.default_options[:imaginary_option] = imaginary_option @parent.default_options[:imaginary_option].call.should == imaginary_option.call @child1.default_options[:imaginary_option] @child1.default_options[:imaginary_option].call.should == imaginary_option.call @child1.default_options[:imaginary_option].should_not be_equal imaginary_option end it "inherits default_cookies from the parent class" do @parent.cookies 'type' => 'chocolate_chip' @child1.default_cookies.should == {"type" => "chocolate_chip"} @child1.cookies 'type' => 'snickerdoodle' @child1.default_cookies.should == {"type" => "snickerdoodle"} @child2.default_cookies.should == {"type" => "chocolate_chip"} end it "doesn't modify the parent's default cookies" do @parent.cookies 'type' => 'chocolate_chip' @child1.cookies 'type' => 'snickerdoodle' @child1.default_cookies.should == {"type" => "snickerdoodle"} @parent.default_cookies.should == {"type" => "chocolate_chip"} end end describe "grand parent with inherited callback" do before do @grand_parent = Class.new do def self.inherited(subclass) subclass.instance_variable_set(:@grand_parent, true) end end @parent = Class.new(@grand_parent) do include HTTParty end end it "continues running the #inherited on the parent" do child = Class.new(@parent) child.instance_variable_get(:@grand_parent).should be_true end end describe "#get" do it "should be able to get html" do stub_http_response_with('google.html') HTTParty.get('http://www.google.com').should == file_fixture('google.html') end it "should be able to get chunked html" do chunks = ["Chunk1", "Chunk2", "Chunk3", "Chunk4"] stub_chunked_http_response_with(chunks) HTTParty.get('http://www.google.com') do |fragment| chunks.should include(fragment) end.should == chunks.join end it "should be able parse response type json automatically" do stub_http_response_with('twitter.json') tweets = HTTParty.get('http://twitter.com/statuses/public_timeline.json') tweets.size.should == 20 tweets.first['user'].should == { "name" => "Pyk", "url" => nil, "id" => "7694602", "description" => nil, "protected" => false, "screen_name" => "Pyk", "followers_count" => 1, "location" => "Opera Plaza, California", "profile_image_url" => "http://static.twitter.com/images/default_profile_normal.png" } end it "should be able parse response type xml automatically" do stub_http_response_with('twitter.xml') tweets = HTTParty.get('http://twitter.com/statuses/public_timeline.xml') tweets['statuses'].size.should == 20 tweets['statuses'].first['user'].should == { "name" => "Magic 8 Bot", "url" => nil, "id" => "17656026", "description" => "ask me a question", "protected" => "false", "screen_name" => "magic8bot", "followers_count" => "90", "profile_image_url" => "http://s3.amazonaws.com/twitter_production/profile_images/65565851/8ball_large_normal.jpg", "location" => nil } end it "should not get undefined method add_node for nil class for the following xml" do stub_http_response_with('undefined_method_add_node_for_nil.xml') result = HTTParty.get('http://foobar.com') result.should == {"Entities"=>{"href"=>"https://s3-sandbox.parature.com/api/v1/5578/5633/Account", "results"=>"0", "total"=>"0", "page_size"=>"25", "page"=>"1"}} end it "should parse empty response fine" do stub_http_response_with('empty.xml') result = HTTParty.get('http://foobar.com') result.should be_nil end it "should accept http URIs" do stub_http_response_with('google.html') lambda do HTTParty.get('http://google.com') end.should_not raise_error(HTTParty::UnsupportedURIScheme) end it "should accept https URIs" do stub_http_response_with('google.html') lambda do HTTParty.get('https://google.com') end.should_not raise_error(HTTParty::UnsupportedURIScheme) end it "should accept webcal URIs" do stub_http_response_with('google.html') lambda do HTTParty.get('webcal://google.com') end.should_not raise_error(HTTParty::UnsupportedURIScheme) end it "should raise an InvalidURIError on URIs that can't be parsed at all" do lambda do HTTParty.get("It's the one that says 'Bad URI'") end.should raise_error(URI::InvalidURIError) end end end httparty-0.12.0/spec/support/0000755000004100000410000000000012254052222016143 5ustar www-datawww-datahttparty-0.12.0/spec/support/stub_response.rb0000644000004100000410000000271612254052222021371 0ustar www-datawww-datamodule HTTParty module StubResponse def stub_http_response_with(filename) format = filename.split('.').last.intern data = file_fixture(filename) response = Net::HTTPOK.new("1.1", 200, "Content for you") response.stub!(:body).and_return(data) http_request = HTTParty::Request.new(Net::HTTP::Get, 'http://localhost', :format => format) http_request.stub_chain(:http, :request).and_return(response) HTTParty::Request.should_receive(:new).and_return(http_request) end def stub_chunked_http_response_with(chunks) response = Net::HTTPResponse.new("1.1", 200, nil) response.stub(:chunked_data).and_return(chunks) def response.read_body(&block) @body || chunked_data.each(&block) end http_request = HTTParty::Request.new(Net::HTTP::Get, 'http://localhost', :format => "html") http_request.stub_chain(:http, :request).and_yield(response).and_return(response) HTTParty::Request.should_receive(:new).and_return(http_request) end def stub_response(body, code = 200) @request.options[:base_uri] ||= 'http://localhost' unless defined?(@http) && @http @http = Net::HTTP.new('localhost', 80) @request.stub!(:http).and_return(@http) end response = Net::HTTPResponse::CODE_TO_OBJ[code.to_s].new("1.1", code, body) response.stub!(:body).and_return(body) @http.stub!(:request).and_return(response) response end end end httparty-0.12.0/spec/support/ssl_test_helper.rb0000644000004100000410000000301312254052222021664 0ustar www-datawww-datarequire 'pathname' module HTTParty module SSLTestHelper def ssl_verify_test(mode, ca_basename, server_cert_filename, options = {}) options = { :format => :json, :timeout => 30, }.merge(options) if mode ca_path = File.expand_path("../../fixtures/ssl/generated/#{ca_basename}", __FILE__) raise ArgumentError.new("#{ca_path} does not exist") unless File.exist?(ca_path) options[mode] = ca_path end begin test_server = SSLTestServer.new( :rsa_key => File.read(File.expand_path("../../fixtures/ssl/generated/server.key", __FILE__)), :cert => File.read(File.expand_path("../../fixtures/ssl/generated/#{server_cert_filename}", __FILE__))) test_server.start if mode ca_path = File.expand_path("../../fixtures/ssl/generated/#{ca_basename}", __FILE__) raise ArgumentError.new("#{ca_path} does not exist") unless File.exist?(ca_path) return HTTParty.get("https://localhost:#{test_server.port}/", options) else return HTTParty.get("https://localhost:#{test_server.port}/", options) end ensure test_server.stop if test_server end test_server = SSLTestServer.new({ :rsa_key => path.join('server.key').read, :cert => path.join(server_cert_filename).read, }) test_server.start HTTParty.get("https://localhost:#{test_server.port}/", options) ensure test_server.stop if test_server end end end httparty-0.12.0/spec/support/ssl_test_server.rb0000644000004100000410000000360612254052222021723 0ustar www-datawww-datarequire 'openssl' require 'socket' require 'thread' # NOTE: This code is garbage. It probably has deadlocks, it might leak # threads, and otherwise cause problems in a real system. It's really only # intended for testing HTTParty. class SSLTestServer attr_accessor :ctx # SSLContext object attr_reader :port def initialize(options={}) @ctx = OpenSSL::SSL::SSLContext.new @ctx.cert = OpenSSL::X509::Certificate.new(options[:cert]) @ctx.key = OpenSSL::PKey::RSA.new(options[:rsa_key]) @ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE # Don't verify client certificate @port = options[:port] || 0 @thread = nil @stopping_mutex = Mutex.new @stopping = false end def start @raw_server = TCPServer.new(@port) if @port == 0 @port = Socket::getnameinfo(@raw_server.getsockname, Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV)[1].to_i end @ssl_server = OpenSSL::SSL::SSLServer.new(@raw_server, @ctx) @stopping_mutex.synchronize{ return if @stopping @thread = Thread.new{ thread_main } } nil end def stop @stopping_mutex.synchronize{ return if @stopping @stopping = true } @thread.join end private def thread_main until @stopping_mutex.synchronize{ @stopping } (rr,_,_) = select([@ssl_server.to_io], nil, nil, 0.1) next unless rr && rr.include?(@ssl_server.to_io) socket = @ssl_server.accept Thread.new{ header = [] until (line = socket.readline).rstrip.empty? header << line end response =< false).should == {'success' => true} end it "should fail when no trusted CA list is specified, with a bogus hostname, by default" do lambda do ssl_verify_test(nil, nil, "bogushost.crt") end.should raise_error OpenSSL::SSL::SSLError end it "should work when no trusted CA list is specified, even with a bogus hostname, when the verify option is set to true" do ssl_verify_test(nil, nil, "bogushost.crt", :verify => false).should == {'success' => true} end it "should work when using ssl_ca_file with a self-signed CA" do ssl_verify_test(:ssl_ca_file, "selfsigned.crt", "selfsigned.crt").should == {'success' => true} end it "should work when using ssl_ca_file with a certificate authority" do ssl_verify_test(:ssl_ca_file, "ca.crt", "server.crt").should == {'success' => true} end it "should work when using ssl_ca_path with a certificate authority" do http = Net::HTTP.new('www.google.com', 443) response = stub(Net::HTTPResponse, :[] => '', :body => '', :to_hash => {}) http.stub(:request).and_return(response) Net::HTTP.should_receive(:new).with('www.google.com', 443).and_return(http) http.should_receive(:ca_path=).with('/foo/bar') HTTParty.get('https://www.google.com', :ssl_ca_path => '/foo/bar') end it "should fail when using ssl_ca_file and the server uses an unrecognized certificate authority" do lambda do ssl_verify_test(:ssl_ca_file, "ca.crt", "selfsigned.crt") end.should raise_error(OpenSSL::SSL::SSLError) end it "should fail when using ssl_ca_path and the server uses an unrecognized certificate authority" do lambda do ssl_verify_test(:ssl_ca_path, ".", "selfsigned.crt") end.should raise_error(OpenSSL::SSL::SSLError) end it "should fail when using ssl_ca_file and the server uses a bogus hostname" do lambda do ssl_verify_test(:ssl_ca_file, "ca.crt", "bogushost.crt") end.should raise_error(OpenSSL::SSL::SSLError) end it "should fail when using ssl_ca_path and the server uses a bogus hostname" do lambda do ssl_verify_test(:ssl_ca_path, ".", "bogushost.crt") end.should raise_error(OpenSSL::SSL::SSLError) end end end httparty-0.12.0/spec/httparty/net_digest_auth_spec.rb0000644000004100000410000000624512254052222023022 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) describe Net::HTTPHeader::DigestAuthenticator do def setup_digest(response) digest = Net::HTTPHeader::DigestAuthenticator.new("Mufasa", "Circle Of Life", "GET", "/dir/index.html", response) digest.stub(:random).and_return("deadbeef") Digest::MD5.stub(:hexdigest) { |str| "md5(#{str})" } digest end def authorization_header @digest.authorization_header.join(", ") end context "with an opaque value in the response header" do before do @digest = setup_digest({ 'www-authenticate' => 'Digest realm="myhost@testrealm.com", opaque="solid"' }) end it "should set opaque" do authorization_header.should include(%Q(opaque="solid")) end end context "without an opaque valid in the response header" do before do @digest = setup_digest({ 'www-authenticate' => 'Digest realm="myhost@testrealm.com"' }) end it "should not set opaque" do authorization_header.should_not include(%Q(opaque=)) end end context "with specified quality of protection (qop)" do before do @digest = setup_digest({ 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth"', }) end it "should set prefix" do authorization_header.should =~ /^Digest / end it "should set username" do authorization_header.should include(%Q(username="Mufasa")) end it "should set digest-uri" do authorization_header.should include(%Q(uri="/dir/index.html")) end it "should set qop" do authorization_header.should include(%Q(qop="auth")) end it "should set cnonce" do authorization_header.should include(%Q(cnonce="md5(deadbeef)")) end it "should set nonce-count" do authorization_header.should include(%Q(nc=00000001)) end it "should set response" do request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:00000001:md5(deadbeef):auth:md5(GET:/dir/index.html))" authorization_header.should include(%Q(response="#{request_digest}")) end end context "with unspecified quality of protection (qop)" do before do @digest = setup_digest({ 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE"', }) end it "should set prefix" do authorization_header.should =~ /^Digest / end it "should set username" do authorization_header.should include(%Q(username="Mufasa")) end it "should set digest-uri" do authorization_header.should include(%Q(uri="/dir/index.html")) end it "should not set qop" do authorization_header.should_not include(%Q(qop=)) end it "should not set cnonce" do authorization_header.should_not include(%Q(cnonce=)) end it "should not set nonce-count" do authorization_header.should_not include(%Q(nc=)) end it "should set response" do request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:md5(GET:/dir/index.html))" authorization_header.should include(%Q(response="#{request_digest}")) end end end httparty-0.12.0/spec/httparty/parser_spec.rb0000644000004100000410000001144312254052222021144 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) describe HTTParty::Parser do describe ".SupportedFormats" do it "returns a hash" do HTTParty::Parser::SupportedFormats.should be_instance_of(Hash) end end describe ".call" do it "generates an HTTParty::Parser instance with the given body and format" do HTTParty::Parser.should_receive(:new).with('body', :plain).and_return(stub(:parse => nil)) HTTParty::Parser.call('body', :plain) end it "calls #parse on the parser" do parser = mock('Parser') parser.should_receive(:parse) HTTParty::Parser.stub(:new => parser) parser = HTTParty::Parser.call('body', :plain) end end describe ".formats" do it "returns the SupportedFormats constant" do HTTParty::Parser.formats.should == HTTParty::Parser::SupportedFormats end it "returns the SupportedFormats constant for subclasses" do class MyParser < HTTParty::Parser SupportedFormats = {"application/atom+xml" => :atom} end MyParser.formats.should == {"application/atom+xml" => :atom} end end describe ".format_from_mimetype" do it "returns a symbol representing the format mimetype" do HTTParty::Parser.format_from_mimetype("text/plain").should == :plain end it "returns nil when the mimetype is not supported" do HTTParty::Parser.format_from_mimetype("application/atom+xml").should be_nil end end describe ".supported_formats" do it "returns a unique set of supported formats represented by symbols" do HTTParty::Parser.supported_formats.should == HTTParty::Parser::SupportedFormats.values.uniq end end describe ".supports_format?" do it "returns true for a supported format" do HTTParty::Parser.stub(:supported_formats => [:json]) HTTParty::Parser.supports_format?(:json).should be_true end it "returns false for an unsupported format" do HTTParty::Parser.stub(:supported_formats => []) HTTParty::Parser.supports_format?(:json).should be_false end end describe "#parse" do before do @parser = HTTParty::Parser.new('body', :json) end it "attempts to parse supported formats" do @parser.stub(:supports_format? => true) @parser.should_receive(:parse_supported_format) @parser.parse end it "returns the unparsed body when the format is unsupported" do @parser.stub(:supports_format? => false) @parser.parse.should == @parser.body end it "returns nil for an empty body" do @parser.stub(:body => '') @parser.parse.should be_nil end it "returns nil for a nil body" do @parser.stub(:body => nil) @parser.parse.should be_nil end it "returns nil for a 'null' body" do @parser.stub(:body => "null") @parser.parse.should be_nil end it "returns nil for a body with spaces only" do @parser.stub(:body => " ") @parser.parse.should be_nil end end describe "#supports_format?" do it "utilizes the class method to determine if the format is supported" do HTTParty::Parser.should_receive(:supports_format?).with(:json) parser = HTTParty::Parser.new('body', :json) parser.send(:supports_format?) end end describe "#parse_supported_format" do it "calls the parser for the given format" do parser = HTTParty::Parser.new('body', :json) parser.should_receive(:json) parser.send(:parse_supported_format) end context "when a parsing method does not exist for the given format" do it "raises an exception" do parser = HTTParty::Parser.new('body', :atom) expect do parser.send(:parse_supported_format) end.to raise_error(NotImplementedError, "HTTParty::Parser has not implemented a parsing method for the :atom format.") end it "raises a useful exception message for subclasses" do atom_parser = Class.new(HTTParty::Parser) do def self.name; 'AtomParser'; end end parser = atom_parser.new 'body', :atom expect do parser.send(:parse_supported_format) end.to raise_error(NotImplementedError, "AtomParser has not implemented a parsing method for the :atom format.") end end end context "parsers" do subject do HTTParty::Parser.new('body', nil) end it "parses xml with MultiXml" do MultiXml.should_receive(:parse).with('body') subject.send(:xml) end it "parses json with JSON" do JSON.should_receive(:load).with('body', nil) subject.send(:json) end it "parses html by simply returning the body" do subject.send(:html).should == 'body' end it "parses plain text by simply returning the body" do subject.send(:plain).should == 'body' end end end httparty-0.12.0/spec/httparty/logger/0000755000004100000410000000000012254052222017565 5ustar www-datawww-datahttparty-0.12.0/spec/httparty/logger/curl_logger_spec.rb0000644000004100000410000000114612254052222023432 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')) describe HTTParty::Logger::CurlLogger do describe "#format" do it "formats a response in a style that resembles a -v curl" do logger_double = double logger_double.should_receive(:info).with( /\[HTTParty\] \[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\ [+-]\d{4}\] > GET http:\/\/localhost/) subject = described_class.new(logger_double, :info) stub_http_response_with("google.html") response = HTTParty::Request.new.perform subject.format(response.request, response) end end end httparty-0.12.0/spec/httparty/logger/logger_spec.rb0000644000004100000410000000125712254052222022410 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')) describe HTTParty::Logger do describe ".build" do subject { HTTParty::Logger } it "defaults level to :info" do logger_double = double() subject.build(logger_double, nil, nil).level.should == :info end it "defaults format to :apache" do logger_double = double() subject.build(logger_double, nil, nil).should be_an_instance_of(HTTParty::Logger::ApacheLogger) end it "builds :curl style logger" do logger_double = double() subject.build(logger_double, nil, :curl).should be_an_instance_of(HTTParty::Logger::CurlLogger) end end end httparty-0.12.0/spec/httparty/logger/apache_logger_spec.rb0000644000004100000410000000154112254052222023705 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')) describe HTTParty::Logger::ApacheLogger do describe "#format" do it "formats a response in a style that resembles apache's access log" do request_time = Time.new.strftime("%Y-%m-%d %H:%M:%S %z") log_message = "[HTTParty] [#{request_time}] 302 \"GET http://my.domain.com/my_path\" - " request_double = double( :http_method => Net::HTTP::Get, :path => "http://my.domain.com/my_path" ) response_double = double( :code => 302, :[] => nil ) logger_double = double logger_double.should_receive(:info).with(log_message) subject = described_class.new(logger_double, :info) subject.current_time = request_time subject.format(request_double, response_double) end end end httparty-0.12.0/spec/httparty/connection_adapter_spec.rb0000644000004100000410000002007312254052222023506 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) describe HTTParty::ConnectionAdapter do describe "initialization" do let(:uri) { URI 'http://www.google.com' } it "takes a URI as input" do HTTParty::ConnectionAdapter.new(uri) end it "raises an ArgumentError if the uri is nil" do expect { HTTParty::ConnectionAdapter.new(nil) }.to raise_error ArgumentError end it "raises an ArgumentError if the uri is a String" do expect { HTTParty::ConnectionAdapter.new('http://www.google.com') }.to raise_error ArgumentError end it "sets the uri" do adapter = HTTParty::ConnectionAdapter.new(uri) adapter.uri.should be uri end it "also accepts an optional options hash" do HTTParty::ConnectionAdapter.new(uri, {}) end it "sets the options" do options = {:foo => :bar} adapter = HTTParty::ConnectionAdapter.new(uri, options) adapter.options.should be options end end describe ".call" do it "generates an HTTParty::ConnectionAdapter instance with the given uri and options" do HTTParty::ConnectionAdapter.should_receive(:new).with(@uri, @options).and_return(stub(:connection => nil)) HTTParty::ConnectionAdapter.call(@uri, @options) end it "calls #connection on the connection adapter" do adapter = mock('Adapter') connection = mock('Connection') adapter.should_receive(:connection).and_return(connection) HTTParty::ConnectionAdapter.stub(:new => adapter) HTTParty::ConnectionAdapter.call(@uri, @options).should be connection end end describe '#connection' do let(:uri) { URI 'http://www.google.com' } let(:options) { Hash.new } let(:adapter) { HTTParty::ConnectionAdapter.new(uri, options) } describe "the resulting connection" do subject { adapter.connection } it { should be_an_instance_of Net::HTTP } context "using port 80" do let(:uri) { URI 'http://foobar.com' } it { should_not use_ssl } end context "when dealing with ssl" do let(:uri) { URI 'https://foobar.com' } context "uses the system cert_store, by default" do let(:system_cert_store) do system_cert_store = mock('default_cert_store') system_cert_store.should_receive(:set_default_paths) OpenSSL::X509::Store.should_receive(:new).and_return(system_cert_store) system_cert_store end it { should use_cert_store(system_cert_store) } end context "should use the specified cert store, when one is given" do let(:custom_cert_store) { mock('custom_cert_store') } let(:options) { {:cert_store => custom_cert_store} } it { should use_cert_store(custom_cert_store) } end context "using port 443 for ssl" do let(:uri) { URI 'https://api.foo.com/v1:443' } it { should use_ssl } end context "https scheme with default port" do it { should use_ssl } end context "https scheme with non-standard port" do let(:uri) { URI 'https://foobar.com:123456' } it { should use_ssl } end context "when ssl version is set" do let(:options) { {:ssl_version => :TLSv1} } it "sets ssl version" do subject.ssl_version.should == :TLSv1 end end if RUBY_VERSION > '1.9' end context "when dealing with IPv6" do let(:uri) { URI 'http://[fd00::1]' } it "strips brackets from the address" do subject.address.should == 'fd00::1' end end context "specifying ciphers" do let(:options) { {:ciphers => 'RC4-SHA' } } it "should set the ciphers on the connection" do subject.ciphers.should == 'RC4-SHA' end end if RUBY_VERSION > '1.9' context "when timeout is not set" do it "doesn't set the timeout" do http = mock("http", :null_object => true) http.should_not_receive(:open_timeout=) http.should_not_receive(:read_timeout=) Net::HTTP.stub(:new => http) adapter.connection end end context "when setting timeout" do context "to 5 seconds" do let(:options) { {:timeout => 5} } its(:open_timeout) { should == 5 } its(:read_timeout) { should == 5 } end context "and timeout is a string" do let(:options) { {:timeout => "five seconds"} } it "doesn't set the timeout" do http = mock("http", :null_object => true) http.should_not_receive(:open_timeout=) http.should_not_receive(:read_timeout=) Net::HTTP.stub(:new => http) adapter.connection end end end context "when debug_output" do let(:http) { Net::HTTP.new(uri) } before do Net::HTTP.stub(:new => http) end context "is set to $stderr" do let(:options) { {:debug_output => $stderr} } it "has debug output set" do http.should_receive(:set_debug_output).with($stderr) adapter.connection end end context "is not provided" do it "does not set_debug_output" do http.should_not_receive(:set_debug_output) adapter.connection end end end context 'when providing proxy address and port' do let(:options) { {:http_proxyaddr => '1.2.3.4', :http_proxyport => 8080} } it { should be_a_proxy } its(:proxy_address) { should == '1.2.3.4' } its(:proxy_port) { should == 8080 } context 'as well as proxy user and password' do let(:options) do {:http_proxyaddr => '1.2.3.4', :http_proxyport => 8080, :http_proxyuser => 'user', :http_proxypass => 'pass'} end its(:proxy_user) { should == 'user' } its(:proxy_pass) { should == 'pass' } end end context 'when not providing a proxy address' do let(:uri) { URI 'http://proxytest.com' } it "does not pass any proxy parameters to the connection" do http = Net::HTTP.new("proxytest.com") Net::HTTP.should_receive(:new).once.with("proxytest.com", 80).and_return(http) adapter.connection end end context 'when providing a local bind address and port' do let(:options) { {:local_host => "127.0.0.1", :local_port => 12345 } } its(:local_host) { should == '127.0.0.1' } its(:local_port) { should == 12345 } end if RUBY_VERSION >= '2.0' context "when providing PEM certificates" do let(:pem) { :pem_contents } let(:options) { {:pem => pem, :pem_password => "password"} } context "when scheme is https" do let(:uri) { URI 'https://google.com' } let(:cert) { mock("OpenSSL::X509::Certificate") } let(:key) { mock("OpenSSL::PKey::RSA") } before do OpenSSL::X509::Certificate.should_receive(:new).with(pem).and_return(cert) OpenSSL::PKey::RSA.should_receive(:new).with(pem, "password").and_return(key) end it "uses the provided PEM certificate " do subject.cert.should == cert subject.key.should == key end it "will verify the certificate" do subject.verify_mode.should == OpenSSL::SSL::VERIFY_PEER end end context "when scheme is not https" do let(:uri) { URI 'http://google.com' } let(:http) { Net::HTTP.new(uri) } before do Net::HTTP.stub(:new => http) OpenSSL::X509::Certificate.should_not_receive(:new).with(pem) OpenSSL::PKey::RSA.should_not_receive(:new).with(pem, "password") http.should_not_receive(:cert=) http.should_not_receive(:key=) end it "has no PEM certificate " do subject.cert.should be_nil subject.key.should be_nil end end end end end end httparty-0.12.0/spec/httparty/response_spec.rb0000644000004100000410000002155112254052222021507 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) describe HTTParty::Response do before do @last_modified = Date.new(2010, 1, 15).to_s @content_length = '1024' @request_object = HTTParty::Request.new Net::HTTP::Get, '/' @response_object = Net::HTTPOK.new('1.1', 200, 'OK') @response_object.stub(:body => "{foo:'bar'}") @response_object['last-modified'] = @last_modified @response_object['content-length'] = @content_length @parsed_response = lambda { {"foo" => "bar"} } @response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) end describe ".underscore" do it "works with one capitalized word" do HTTParty::Response.underscore("Accepted").should == "accepted" end it "works with titlecase" do HTTParty::Response.underscore("BadGateway").should == "bad_gateway" end it "works with all caps" do HTTParty::Response.underscore("OK").should == "ok" end end describe "initialization" do it "should set the Net::HTTP Response" do @response.response.should == @response_object end it "should set body" do @response.body.should == @response_object.body end it "should set code" do @response.code.should.to_s == @response_object.code end it "should set code as a Fixnum" do @response.code.should be_an_instance_of(Fixnum) end end it "returns response headers" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.headers.should == {'last-modified' => [@last_modified], 'content-length' => [@content_length]} end it "should send missing methods to delegate" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response['foo'].should == 'bar' end it "response to request" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.respond_to?(:request).should be_true end it "responds to response" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.respond_to?(:response).should be_true end it "responds to body" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.respond_to?(:body).should be_true end it "responds to headers" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.respond_to?(:headers).should be_true end it "responds to parsed_response" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.respond_to?(:parsed_response).should be_true end it "responds to anything parsed_response responds to" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.respond_to?(:[]).should be_true end it "should be able to iterate if it is array" do response = HTTParty::Response.new(@request_object, @response_object, lambda { [{'foo' => 'bar'}, {'foo' => 'baz'}] }) response.size.should == 2 expect { response.each { |item| } }.to_not raise_error end it "allows headers to be accessed by mixed-case names in hash notation" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.headers['Content-LENGTH'].should == @content_length end it "returns a comma-delimited value when multiple values exist" do @response_object.add_field 'set-cookie', 'csrf_id=12345; path=/' @response_object.add_field 'set-cookie', '_github_ses=A123CdE; path=/' response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.headers['set-cookie'].should == "csrf_id=12345; path=/, _github_ses=A123CdE; path=/" end # Backwards-compatibility - previously, #headers returned a Hash it "responds to hash methods" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) hash_methods = {}.methods - response.headers.methods hash_methods.each do |method_name| response.headers.respond_to?(method_name).should be_true end end describe "semantic methods for response codes" do def response_mock(klass) response = klass.new('', '', '') response.stub(:body) response end context "major codes" do it "is information" do net_response = response_mock(Net::HTTPInformation) response = HTTParty::Response.new(@request_object, net_response, '') response.information?.should be_true end it "is success" do net_response = response_mock(Net::HTTPSuccess) response = HTTParty::Response.new(@request_object, net_response, '') response.success?.should be_true end it "is redirection" do net_response = response_mock(Net::HTTPRedirection) response = HTTParty::Response.new(@request_object, net_response, '') response.redirection?.should be_true end it "is client error" do net_response = response_mock(Net::HTTPClientError) response = HTTParty::Response.new(@request_object, net_response, '') response.client_error?.should be_true end it "is server error" do net_response = response_mock(Net::HTTPServerError) response = HTTParty::Response.new(@request_object, net_response, '') response.server_error?.should be_true end end context "for specific codes" do SPECIFIC_CODES = { :accepted? => Net::HTTPAccepted, :bad_gateway? => Net::HTTPBadGateway, :bad_request? => Net::HTTPBadRequest, :conflict? => Net::HTTPConflict, :continue? => Net::HTTPContinue, :created? => Net::HTTPCreated, :expectation_failed? => Net::HTTPExpectationFailed, :forbidden? => Net::HTTPForbidden, :found? => Net::HTTPFound, :gateway_time_out? => Net::HTTPGatewayTimeOut, :gone? => Net::HTTPGone, :internal_server_error? => Net::HTTPInternalServerError, :length_required? => Net::HTTPLengthRequired, :method_not_allowed? => Net::HTTPMethodNotAllowed, :moved_permanently? => Net::HTTPMovedPermanently, :multiple_choice? => Net::HTTPMultipleChoice, :no_content? => Net::HTTPNoContent, :non_authoritative_information? => Net::HTTPNonAuthoritativeInformation, :not_acceptable? => Net::HTTPNotAcceptable, :not_found? => Net::HTTPNotFound, :not_implemented? => Net::HTTPNotImplemented, :not_modified? => Net::HTTPNotModified, :ok? => Net::HTTPOK, :partial_content? => Net::HTTPPartialContent, :payment_required? => Net::HTTPPaymentRequired, :precondition_failed? => Net::HTTPPreconditionFailed, :proxy_authentication_required? => Net::HTTPProxyAuthenticationRequired, :request_entity_too_large? => Net::HTTPRequestEntityTooLarge, :request_time_out? => Net::HTTPRequestTimeOut, :request_uri_too_long? => Net::HTTPRequestURITooLong, :requested_range_not_satisfiable? => Net::HTTPRequestedRangeNotSatisfiable, :reset_content? => Net::HTTPResetContent, :see_other? => Net::HTTPSeeOther, :service_unavailable? => Net::HTTPServiceUnavailable, :switch_protocol? => Net::HTTPSwitchProtocol, :temporary_redirect? => Net::HTTPTemporaryRedirect, :unauthorized? => Net::HTTPUnauthorized, :unsupported_media_type? => Net::HTTPUnsupportedMediaType, :use_proxy? => Net::HTTPUseProxy, :version_not_supported? => Net::HTTPVersionNotSupported } # Ruby 2.0, new name for this response. if RUBY_VERSION >= "2.0.0" && ::RUBY_PLATFORM != "java" SPECIFIC_CODES[:multiple_choices?] = Net::HTTPMultipleChoices end SPECIFIC_CODES.each do |method, klass| it "responds to #{method}" do net_response = response_mock(klass) response = HTTParty::Response.new(@request_object, net_response, '') response.__send__(method).should be_true end end end end describe "headers" do it "can initialize without headers" do headers = HTTParty::Response::Headers.new headers.should == {} end end end httparty-0.12.0/spec/httparty/cookie_hash_spec.rb0000644000004100000410000000513012254052222022120 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper')) describe HTTParty::CookieHash do before(:each) do @cookie_hash = HTTParty::CookieHash.new end describe "#add_cookies" do describe "with a hash" do it "should add new key/value pairs to the hash" do @cookie_hash.add_cookies(:foo => "bar") @cookie_hash.add_cookies(:rofl => "copter") @cookie_hash.length.should eql(2) end it "should overwrite any existing key" do @cookie_hash.add_cookies(:foo => "bar") @cookie_hash.add_cookies(:foo => "copter") @cookie_hash.length.should eql(1) @cookie_hash[:foo].should eql("copter") end end describe "with a string" do it "should add new key/value pairs to the hash" do @cookie_hash.add_cookies("first=one; second=two; third") @cookie_hash[:first].should == 'one' @cookie_hash[:second].should == 'two' @cookie_hash[:third].should == nil end it "should overwrite any existing key" do @cookie_hash[:foo] = 'bar' @cookie_hash.add_cookies("foo=tar") @cookie_hash.length.should eql(1) @cookie_hash[:foo].should eql("tar") end it "should handle '=' within cookie value" do @cookie_hash.add_cookies("first=one=1; second=two=2==") @cookie_hash.keys.should include(:first, :second) @cookie_hash[:first].should == 'one=1' @cookie_hash[:second].should == 'two=2==' end end describe 'with other class' do it "should error" do lambda { @cookie_hash.add_cookies(Array.new) }.should raise_error end end end # The regexen are required because Hashes aren't ordered, so a test against # a hardcoded string was randomly failing. describe "#to_cookie_string" do before(:each) do @cookie_hash.add_cookies(:foo => "bar") @cookie_hash.add_cookies(:rofl => "copter") @s = @cookie_hash.to_cookie_string end it "should format the key/value pairs, delimited by semi-colons" do @s.should match(/foo=bar/) @s.should match(/rofl=copter/) @s.should match(/^\w+=\w+; \w+=\w+$/) end it "should not include client side only cookies" do @cookie_hash.add_cookies(:path => "/") @s = @cookie_hash.to_cookie_string @s.should_not match(/path=\//) end it "should not include client side only cookies even when attributes use camal case" do @cookie_hash.add_cookies(:Path => "/") @s = @cookie_hash.to_cookie_string @s.should_not match(/Path=\//) end end end httparty-0.12.0/spec/httparty/request_spec.rb0000644000004100000410000005550312254052222021345 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) describe HTTParty::Request do before do @request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', :format => :xml) end describe "::NON_RAILS_QUERY_STRING_NORMALIZER" do let(:normalizer) { HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER } it "doesn't modify strings" do query_string = normalizer["foo=bar&foo=baz"] URI.unescape(query_string).should == "foo=bar&foo=baz" end context "when the query is an array" do it "doesn't include brackets" do query_string = normalizer[{:page => 1, :foo => %w(bar baz)}] URI.unescape(query_string).should == "foo=bar&foo=baz&page=1" end it "URI encodes array values" do query_string = normalizer[{:people => ["Bob Marley", "Tim & Jon"]}] query_string.should == "people=Bob%20Marley&people=Tim%20%26%20Jon" end end context "when the query is a hash" do it "correctly handles nil values" do query_string = normalizer[{:page => 1, :per_page => nil}] query_string.should == "page=1&per_page" end end end describe "initialization" do it "sets parser to HTTParty::Parser" do request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com') request.parser.should == HTTParty::Parser end it "sets parser to the optional parser" do my_parser = lambda {} request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com', :parser => my_parser) request.parser.should == my_parser end it "sets connection_adapter to HTTPParty::ConnectionAdapter" do request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com') request.connection_adapter.should == HTTParty::ConnectionAdapter end it "sets connection_adapter to the optional connection_adapter" do my_adapter = lambda {} request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com', :connection_adapter => my_adapter) request.connection_adapter.should == my_adapter end end describe "#format" do context "request yet to be made" do it "returns format option" do request = HTTParty::Request.new 'get', '/', :format => :xml request.format.should == :xml end it "returns nil format" do request = HTTParty::Request.new 'get', '/' request.format.should be_nil end end context "request has been made" do it "returns format option" do request = HTTParty::Request.new 'get', '/', :format => :xml request.last_response = stub request.format.should == :xml end it "returns the content-type from the last response when the option is not set" do request = HTTParty::Request.new 'get', '/' response = stub response.should_receive(:[]).with('content-type').and_return('text/json') request.last_response = response request.format.should == :json end end end context "options" do it "should use basic auth when configured" do @request.options[:basic_auth] = {:username => 'foobar', :password => 'secret'} @request.send(:setup_raw_request) @request.instance_variable_get(:@raw_request)['authorization'].should_not be_nil end it "should use digest auth when configured" do FakeWeb.register_uri(:get, "http://api.foo.com/v1", :www_authenticate => 'Digest realm="Log Viewer", qop="auth", nonce="2CA0EC6B0E126C4800E56BA0C0003D3C", opaque="5ccc069c403ebaf9f0171e9517f40e41", stale=false') @request.options[:digest_auth] = {:username => 'foobar', :password => 'secret'} @request.send(:setup_raw_request) raw_request = @request.instance_variable_get(:@raw_request) raw_request.instance_variable_get(:@header)['Authorization'].should_not be_nil end it "should use the right http method for digest authentication" do @post_request = HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :format => :xml) FakeWeb.register_uri(:post, "http://api.foo.com/v1", {}) http = @post_request.send(:http) @post_request.should_receive(:http).and_return(http) http.should_not_receive(:head).and_return({'www-authenticate' => nil}) @post_request.options[:digest_auth] = {:username => 'foobar', :password => 'secret'} @post_request.send(:setup_raw_request) end end describe "#uri" do context "query strings" do it "does not add an empty query string when default_params are blank" do @request.options[:default_params] = {} @request.uri.query.should be_nil end it "respects the query string normalization proc" do empty_proc = lambda {|qs| ""} @request.options[:query_string_normalizer] = empty_proc @request.options[:query] = {:foo => :bar} URI.unescape(@request.uri.query).should == "" end it "does not duplicate query string parameters when uri is called twice" do @request.options[:query] = {:foo => :bar} @request.uri @request.uri.query.should == "foo=bar" end context "when representing an array" do it "returns a Rails style query string" do @request.options[:query] = {:foo => %w(bar baz)} URI.unescape(@request.uri.query).should == "foo[]=bar&foo[]=baz" end end end end describe "#setup_raw_request" do context "when query_string_normalizer is set" do it "sets the body to the return value of the proc" do @request.options[:query_string_normalizer] = HTTParty::Request::NON_RAILS_QUERY_STRING_NORMALIZER @request.options[:body] = {:page => 1, :foo => %w(bar baz)} @request.send(:setup_raw_request) body = @request.instance_variable_get(:@raw_request).body URI.unescape(body).should == "foo=bar&foo=baz&page=1" end end end describe 'http' do it "should get a connection from the connection_adapter" do http = Net::HTTP.new('google.com') adapter = mock('adapter') request = HTTParty::Request.new(Net::HTTP::Get, 'https://api.foo.com/v1:443', :connection_adapter => adapter) adapter.should_receive(:call).with(request.uri, request.options).and_return(http) request.send(:http).should be http end end describe '#format_from_mimetype' do it 'should handle text/xml' do ["text/xml", "text/xml; charset=iso8859-1"].each do |ct| @request.send(:format_from_mimetype, ct).should == :xml end end it 'should handle application/xml' do ["application/xml", "application/xml; charset=iso8859-1"].each do |ct| @request.send(:format_from_mimetype, ct).should == :xml end end it 'should handle text/json' do ["text/json", "text/json; charset=iso8859-1"].each do |ct| @request.send(:format_from_mimetype, ct).should == :json end end it 'should handle application/json' do ["application/json", "application/json; charset=iso8859-1"].each do |ct| @request.send(:format_from_mimetype, ct).should == :json end end it 'should handle text/javascript' do ["text/javascript", "text/javascript; charset=iso8859-1"].each do |ct| @request.send(:format_from_mimetype, ct).should == :plain end end it 'should handle application/javascript' do ["application/javascript", "application/javascript; charset=iso8859-1"].each do |ct| @request.send(:format_from_mimetype, ct).should == :plain end end it "returns nil for an unrecognized mimetype" do @request.send(:format_from_mimetype, "application/atom+xml").should be_nil end it "returns nil when using a default parser" do @request.options[:parser] = lambda {} @request.send(:format_from_mimetype, "text/json").should be_nil end end describe 'parsing responses' do it 'should handle xml automatically' do xml = %q[1234Foo Bar!] @request.options[:format] = :xml @request.send(:parse_response, xml).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}} end it 'should handle json automatically' do json = %q[{"books": {"book": {"name": "Foo Bar!", "id": "1234"}}}] @request.options[:format] = :json @request.send(:parse_response, json).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}} end it "should include any HTTP headers in the returned response" do @request.options[:format] = :html response = stub_response "Content" response.initialize_http_header("key" => "value") @request.perform.headers.should == { "key" => ["value"] } end if "".respond_to?(:encoding) it "should process charset in content type properly" do response = stub_response "Content" response.initialize_http_header("Content-Type" => "text/plain;charset = utf-8") resp = @request.perform resp.body.encoding.should == Encoding.find("UTF-8") end it "should process charset in content type properly if it has a different case" do response = stub_response "Content" response.initialize_http_header("Content-Type" => "text/plain;CHARSET = utf-8") resp = @request.perform resp.body.encoding.should == Encoding.find("UTF-8") end it "should process quoted charset in content type properly" do response = stub_response "Content" response.initialize_http_header("Content-Type" => "text/plain;charset = \"utf-8\"") resp = @request.perform resp.body.encoding.should == Encoding.find("UTF-8") end it "should process utf-16 charset with little endian bom correctly" do @request.options[:assume_utf16_is_big_endian] = true response = stub_response "\xFF\xFEC\x00o\x00n\x00t\x00e\x00n\x00t\x00" response.initialize_http_header("Content-Type" => "text/plain;charset = utf-16") resp = @request.perform resp.body.encoding.should == Encoding.find("UTF-16LE") end it "should process utf-16 charset with big endian bom correctly" do @request.options[:assume_utf16_is_big_endian] = false response = stub_response "\xFE\xFF\x00C\x00o\x00n\x00t\x00e\x00n\x00t" response.initialize_http_header("Content-Type" => "text/plain;charset = utf-16") resp = @request.perform resp.body.encoding.should == Encoding.find("UTF-16BE") end it "should assume utf-16 little endian if options has been chosen" do @request.options[:assume_utf16_is_big_endian] = false response = stub_response "C\x00o\x00n\x00t\x00e\x00n\x00t\x00" response.initialize_http_header("Content-Type" => "text/plain;charset = utf-16") resp = @request.perform resp.body.encoding.should == Encoding.find("UTF-16LE") end it "should perform no encoding if the charset is not available" do response = stub_response "Content" response.initialize_http_header("Content-Type" => "text/plain;charset = utf-lols") resp = @request.perform resp.body.should == "Content" resp.body.encoding.should == "Content".encoding end it "should perform no encoding if the content type is specified but no charset is specified" do response = stub_response "Content" response.initialize_http_header("Content-Type" => "text/plain") resp = @request.perform resp.body.should == "Content" resp.body.encoding.should == "Content".encoding end end describe 'with non-200 responses' do context "3xx responses" do it 'returns a valid object for 304 not modified' do stub_response '', 304 resp = @request.perform resp.code.should == 304 resp.body.should == '' resp.should be_nil end it "redirects if a 300 contains a location header" do redirect = stub_response '', 300 redirect['location'] = 'http://foo.com/foo' ok = stub_response('bar', 200) @http.stub!(:request).and_return(redirect, ok) response = @request.perform response.request.base_uri.to_s.should == "http://foo.com" response.request.path.to_s.should == "http://foo.com/foo" response.request.uri.request_uri.should == "/foo" response.request.uri.to_s.should == "http://foo.com/foo" response.should == {"hash" => {"foo" => "bar"}} end it "calls block given to perform with each redirect" do @request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', :format => :xml) FakeWeb.register_uri(:get, "http://test.com/redirect", :status => [300, "REDIRECT"], :location => "http://api.foo.com/v2") FakeWeb.register_uri(:get, "http://api.foo.com/v2", :body => "bar") body = "" response = @request.perform { |chunk| body += chunk } body.length.should == 27 end it "redirects if a 300 contains a relative location header" do redirect = stub_response '', 300 redirect['location'] = '/foo/bar' ok = stub_response('bar', 200) @http.stub!(:request).and_return(redirect, ok) response = @request.perform response.request.base_uri.to_s.should == "http://api.foo.com" response.request.path.to_s.should == "/foo/bar" response.request.uri.request_uri.should == "/foo/bar" response.request.uri.to_s.should == "http://api.foo.com/foo/bar" response.should == {"hash" => {"foo" => "bar"}} end it "handles multiple redirects and relative location headers on different hosts" do @request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', :format => :xml) FakeWeb.register_uri(:get, "http://test.com/redirect", :status => [300, "REDIRECT"], :location => "http://api.foo.com/v2") FakeWeb.register_uri(:get, "http://api.foo.com/v2", :status => [300, "REDIRECT"], :location => "/v3") FakeWeb.register_uri(:get, "http://api.foo.com/v3", :body => "bar") response = @request.perform response.request.base_uri.to_s.should == "http://api.foo.com" response.request.path.to_s.should == "/v3" response.request.uri.request_uri.should == "/v3" response.request.uri.to_s.should == "http://api.foo.com/v3" response.should == {"hash" => {"foo" => "bar"}} end it "returns the HTTParty::Response when the 300 does not contain a location header" do stub_response '', 300 HTTParty::Response.should === @request.perform end end it 'should return a valid object for 4xx response' do stub_response 'yes', 401 resp = @request.perform resp.code.should == 401 resp.body.should == "yes" resp['foo']['bar'].should == "yes" end it 'should return a valid object for 5xx response' do stub_response 'error', 500 resp = @request.perform resp.code.should == 500 resp.body.should == "error" resp['foo']['bar'].should == "error" end it "parses response lazily so codes can be checked prior" do stub_response 'not xml', 500 @request.options[:format] = :xml lambda { response = @request.perform response.code.should == 500 response.body.should == 'not xml' }.should_not raise_error end end end it "should not attempt to parse empty responses" do [204, 304].each do |code| stub_response "", code @request.options[:format] = :xml @request.perform.should be_nil end end it "should not fail for missing mime type" do stub_response "Content for you" @request.options[:format] = :html @request.perform.should == 'Content for you' end describe "a request that redirects" do before(:each) do @redirect = stub_response("", 302) @redirect['location'] = '/foo' @ok = stub_response('bar', 200) end describe "once" do before(:each) do @http.stub!(:request).and_return(@redirect, @ok) end it "should be handled by GET transparently" do @request.perform.should == {"hash" => {"foo" => "bar"}} end it "should be handled by POST transparently" do @request.http_method = Net::HTTP::Post @request.perform.should == {"hash" => {"foo" => "bar"}} end it "should be handled by DELETE transparently" do @request.http_method = Net::HTTP::Delete @request.perform.should == {"hash" => {"foo" => "bar"}} end it "should be handled by MOVE transparently" do @request.http_method = Net::HTTP::Move @request.perform.should == {"hash" => {"foo" => "bar"}} end it "should be handled by COPY transparently" do @request.http_method = Net::HTTP::Copy @request.perform.should == {"hash" => {"foo" => "bar"}} end it "should be handled by PATCH transparently" do @request.http_method = Net::HTTP::Patch @request.perform.should == {"hash" => {"foo" => "bar"}} end it "should be handled by PUT transparently" do @request.http_method = Net::HTTP::Put @request.perform.should == {"hash" => {"foo" => "bar"}} end it "should be handled by HEAD transparently" do @request.http_method = Net::HTTP::Head @request.perform.should == {"hash" => {"foo" => "bar"}} end it "should be handled by OPTIONS transparently" do @request.http_method = Net::HTTP::Options @request.perform.should == {"hash" => {"foo" => "bar"}} end it "should keep track of cookies between redirects" do @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly' @request.perform @request.options[:headers]['Cookie'].should match(/foo=bar/) @request.options[:headers]['Cookie'].should match(/name=value/) end it 'should update cookies with rediects' do @request.options[:headers] = {'Cookie'=> 'foo=bar;'} @redirect['Set-Cookie'] = 'foo=tar;' @request.perform @request.options[:headers]['Cookie'].should match(/foo=tar/) end it 'should keep cookies between rediects' do @request.options[:headers] = {'Cookie'=> 'keep=me'} @redirect['Set-Cookie'] = 'foo=tar;' @request.perform @request.options[:headers]['Cookie'].should match(/keep=me/) end it "should handle multiple Set-Cookie headers between redirects" do @redirect.add_field 'set-cookie', 'foo=bar; name=value; HTTPOnly' @redirect.add_field 'set-cookie', 'one=1; two=2; HTTPOnly' @request.perform @request.options[:headers]['Cookie'].should match(/foo=bar/) @request.options[:headers]['Cookie'].should match(/name=value/) @request.options[:headers]['Cookie'].should match(/one=1/) @request.options[:headers]['Cookie'].should match(/two=2/) end it 'should make resulting request a get request if it not already' do @request.http_method = Net::HTTP::Delete @request.perform.should == {"hash" => {"foo" => "bar"}} @request.http_method.should == Net::HTTP::Get end it 'should not make resulting request a get request if options[:maintain_method_across_redirects] is true' do @request.options[:maintain_method_across_redirects] = true @request.http_method = Net::HTTP::Delete @request.perform.should == {"hash" => {"foo" => "bar"}} @request.http_method.should == Net::HTTP::Delete end it 'should log the redirection' do logger_double = double logger_double.should_receive(:info).twice @request.options[:logger] = logger_double @request.perform end end describe "infinitely" do before(:each) do @http.stub!(:request).and_return(@redirect) end it "should raise an exception" do lambda { @request.perform }.should raise_error(HTTParty::RedirectionTooDeep) end end end describe "#handle_deflation" do context "context-encoding" do before do @request.options[:format] = :html @last_response = mock() @last_response.stub!(:body).and_return('') end it "should inflate the gzipped body with content-encoding: gzip" do @last_response.stub!(:[]).with("content-encoding").and_return("gzip") @request.stub!(:last_response).and_return(@last_response) Zlib::GzipReader.should_receive(:new).and_return(StringIO.new('')) @request.last_response.should_receive(:delete).with('content-encoding') @request.send(:handle_deflation) end it "should inflate the gzipped body with content-encoding: x-gzip" do @last_response.stub!(:[]).with("content-encoding").and_return("x-gzip") @request.stub!(:last_response).and_return(@last_response) Zlib::GzipReader.should_receive(:new).and_return(StringIO.new('')) @request.last_response.should_receive(:delete).with('content-encoding') @request.send(:handle_deflation) end it "should inflate the deflated body" do @last_response.stub!(:[]).with("content-encoding").and_return("deflate") @request.stub!(:last_response).and_return(@last_response) Zlib::Inflate.should_receive(:inflate).and_return('') @request.last_response.should_receive(:delete).with('content-encoding') @request.send(:handle_deflation) end end end context "with POST http method" do it "should raise argument error if query is not a hash" do lambda { HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :format => :xml, :query => 'astring').perform }.should raise_error(ArgumentError) end end describe "argument validation" do it "should raise argument error if basic_auth and digest_auth are both present" do lambda { HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :basic_auth => {}, :digest_auth => {}).perform }.should raise_error(ArgumentError, "only one authentication method, :basic_auth or :digest_auth may be used at a time") end it "should raise argument error if basic_auth is not a hash" do lambda { HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :basic_auth => ["foo", "bar"]).perform }.should raise_error(ArgumentError, ":basic_auth must be a hash") end it "should raise argument error if digest_auth is not a hash" do lambda { HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :digest_auth => ["foo", "bar"]).perform }.should raise_error(ArgumentError, ":digest_auth must be a hash") end end end httparty-0.12.0/.travis.yml0000644000004100000410000000017412254052222015610 0ustar www-datawww-datalanguage: ruby rvm: - 1.8.7 - ree - 1.9.3 - 2.0.0 notifications: email: false bundler_args: --without development httparty-0.12.0/lib/0000755000004100000410000000000012254052222014243 5ustar www-datawww-datahttparty-0.12.0/lib/httparty.rb0000644000004100000410000004314212254052222016453 0ustar www-datawww-datarequire 'pathname' require 'net/http' require 'net/https' require 'uri' require 'zlib' require 'multi_xml' require 'json' require 'httparty/module_inheritable_attributes' require 'httparty/cookie_hash' require 'httparty/net_digest_auth' require 'httparty/version' require 'httparty/connection_adapter' require 'httparty/logger/logger' # @see HTTParty::ClassMethods module HTTParty module AllowedFormatsDeprecation def const_missing(const) if const.to_s =~ /AllowedFormats$/ Kernel.warn("Deprecated: Use HTTParty::Parser::SupportedFormats") HTTParty::Parser::SupportedFormats else super end end end extend AllowedFormatsDeprecation def self.included(base) base.extend ClassMethods base.send :include, HTTParty::ModuleInheritableAttributes base.send(:mattr_inheritable, :default_options) base.send(:mattr_inheritable, :default_cookies) base.instance_variable_set("@default_options", {}) base.instance_variable_set("@default_cookies", CookieHash.new) end # == Common Request Options # Request methods (get, post, patch, put, delete, head, options) all take a common set of options. These are: # # [:+body+:] Body of the request. If passed a Hash, will try to normalize it first, by default passing it to ActiveSupport::to_params. Any other kind of object will get used as-is. # [:+http_proxyaddr+:] Address of proxy server to use. # [:+http_proxyport+:] Port of proxy server to use. # [:+http_proxyuser+:] User for proxy server authentication. # [:+http_proxypass+:] Password for proxy server authentication. # [:+limit+:] Maximum number of redirects to follow. Takes precedences over :+no_follow+. # [:+query+:] Query string, or a Hash representing it. Normalized according to the same rules as :+body+. If you specify this on a POST, you must use a Hash. See also HTTParty::ClassMethods.default_params. # [:+timeout+:] Timeout for opening connection and reading data. # [:+local_host:] Local address to bind to before connecting. # [:+local_port:] Local port to bind to before connecting. # # There are also another set of options with names corresponding to various class methods. The methods in question are those that let you set a class-wide default, and the options override the defaults on a request-by-request basis. Those options are: # * :+base_uri+: see HTTParty::ClassMethods.base_uri. # * :+basic_auth+: see HTTParty::ClassMethods.basic_auth. Only one of :+basic_auth+ and :+digest_auth+ can be used at a time; if you try using both, you'll get an ArgumentError. # * :+debug_output+: see HTTParty::ClassMethods.debug_output. # * :+digest_auth+: see HTTParty::ClassMethods.digest_auth. Only one of :+basic_auth+ and :+digest_auth+ can be used at a time; if you try using both, you'll get an ArgumentError. # * :+format+: see HTTParty::ClassMethods.format. # * :+headers+: see HTTParty::ClassMethods.headers. Must be a Hash. # * :+maintain_method_across_redirects+: see HTTParty::ClassMethods.maintain_method_across_redirects. # * :+no_follow+: see HTTParty::ClassMethods.no_follow. # * :+parser+: see HTTParty::ClassMethods.parser. # * :+connection_adapter+: see HTTParty::ClassMethods.connection_adapter. # * :+pem+: see HTTParty::ClassMethods.pem. # * :+query_string_normalizer+: see HTTParty::ClassMethods.query_string_normalizer # * :+ssl_ca_file+: see HTTParty::ClassMethods.ssl_ca_file. # * :+ssl_ca_path+: see HTTParty::ClassMethods.ssl_ca_path. module ClassMethods extend AllowedFormatsDeprecation # Turns on logging # # class Foo # include HTTParty # logger Logger.new('http_logger'), :info, :apache # end def logger(logger, level=:info, format=:apache) default_options[:logger] = logger default_options[:log_level] = level default_options[:log_format] = format end # Allows setting http proxy information to be used # # class Foo # include HTTParty # http_proxy 'http://foo.com', 80, 'user', 'pass' # end def http_proxy(addr=nil, port=nil, user=nil, pass=nil) default_options[:http_proxyaddr] = addr default_options[:http_proxyport] = port default_options[:http_proxyuser] = user default_options[:http_proxypass] = pass end # Allows setting a base uri to be used for each request. # Will normalize uri to include http, etc. # # class Foo # include HTTParty # base_uri 'twitter.com' # end def base_uri(uri=nil) return default_options[:base_uri] unless uri default_options[:base_uri] = HTTParty.normalize_base_uri(uri) end # Allows setting basic authentication username and password. # # class Foo # include HTTParty # basic_auth 'username', 'password' # end def basic_auth(u, p) default_options[:basic_auth] = {:username => u, :password => p} end # Allows setting digest authentication username and password. # # class Foo # include HTTParty # digest_auth 'username', 'password' # end def digest_auth(u, p) default_options[:digest_auth] = {:username => u, :password => p} end # Do not send rails style query strings. # Specically, don't use bracket notation when sending an array # # For a query: # get '/', :query => {:selected_ids => [1,2,3]} # # The default query string looks like this: # /?selected_ids[]=1&selected_ids[]=2&selected_ids[]=3 # # Call `disable_rails_query_string_format` to transform the query string # into: # /?selected_ids=1&selected_ids=2&selected_ids=3 # # @example # class Foo # include HTTParty # disable_rails_query_string_format # end def disable_rails_query_string_format query_string_normalizer Request::NON_RAILS_QUERY_STRING_NORMALIZER end # Allows setting default parameters to be appended to each request. # Great for api keys and such. # # class Foo # include HTTParty # default_params :api_key => 'secret', :another => 'foo' # end def default_params(h={}) raise ArgumentError, 'Default params must be a hash' unless h.is_a?(Hash) default_options[:default_params] ||= {} default_options[:default_params].merge!(h) end # Allows setting a default timeout for all HTTP calls # Timeout is specified in seconds. # # class Foo # include HTTParty # default_timeout 10 # end def default_timeout(t) raise ArgumentError, 'Timeout must be an integer or float' unless t && (t.is_a?(Integer) || t.is_a?(Float)) default_options[:timeout] = t end # Set an output stream for debugging, defaults to $stderr. # The output stream is passed on to Net::HTTP#set_debug_output. # # class Foo # include HTTParty # debug_output $stderr # end def debug_output(stream = $stderr) default_options[:debug_output] = stream end # Allows setting HTTP headers to be used for each request. # # class Foo # include HTTParty # headers 'Accept' => 'text/html' # end def headers(h={}) raise ArgumentError, 'Headers must be a hash' unless h.is_a?(Hash) default_options[:headers] ||= {} default_options[:headers].merge!(h) end def cookies(h={}) raise ArgumentError, 'Cookies must be a hash' unless h.is_a?(Hash) default_cookies.add_cookies(h) end # Proceed to the location header when an HTTP response dictates a redirect. # Redirects are always followed by default. # # @example # class Foo # include HTTParty # base_uri 'http://google.com' # follow_redirects true # end def follow_redirects(value = true) default_options[:follow_redirects] = value end # Allows setting the format with which to parse. # Must be one of the allowed formats ie: json, xml # # class Foo # include HTTParty # format :json # end def format(f = nil) if f.nil? default_options[:format] else parser(Parser) if parser.nil? default_options[:format] = f validate_format end end # Declare whether or not to follow redirects. When true, an # {HTTParty::RedirectionTooDeep} error will raise upon encountering a # redirect. You can then gain access to the response object via # HTTParty::RedirectionTooDeep#response. # # @see HTTParty::ResponseError#response # # @example # class Foo # include HTTParty # base_uri 'http://google.com' # no_follow true # end # # begin # Foo.get('/') # rescue HTTParty::RedirectionTooDeep => e # puts e.response.body # end def no_follow(value = false) default_options[:no_follow] = value end # Declare that you wish to maintain the chosen HTTP method across redirects. # The default behavior is to follow redirects via the GET method. # If you wish to maintain the original method, you can set this option to true. # # @example # class Foo # include HTTParty # base_uri 'http://google.com' # maintain_method_across_redirects true # end def maintain_method_across_redirects(value = true) default_options[:maintain_method_across_redirects] = value end # Allows setting a PEM file to be used # # class Foo # include HTTParty # pem File.read('/home/user/my.pem'), "optional password" # end def pem(pem_contents, password=nil) default_options[:pem] = pem_contents default_options[:pem_password] = password end # Override the way query strings are normalized. # Helpful for overriding the default rails normalization of Array queries. # # For a query: # get '/', :query => {:selected_ids => [1,2,3]} # # The default query string normalizer returns: # /?selected_ids[]=1&selected_ids[]=2&selected_ids[]=3 # # Let's change it to this: # /?selected_ids=1&selected_ids=2&selected_ids=3 # # Pass a Proc to the query normalizer which accepts the yielded query. # # @example Modifying Array query strings # class ServiceWrapper # include HTTParty # # query_string_normalizer proc { |query| # query.map do |key, value| # value.map {|v| "#{key}=#{v}"} # end.join('&') # } # end # # @param [Proc] normalizer custom query string normalizer. # @yield [Hash, String] query string # @yieldreturn [Array] an array that will later be joined with '&' def query_string_normalizer(normalizer) default_options[:query_string_normalizer] = normalizer end # Allows setting of SSL version to use. This only works in Ruby 1.9+. # You can get a list of valid versions from OpenSSL::SSL::SSLContext::METHODS. # # class Foo # include HTTParty # ssl_version :SSLv3 # end def ssl_version(version) default_options[:ssl_version] = version end # Allows setting of SSL ciphers to use. This only works in Ruby 1.9+. # You can get a list of valid specific ciphers from OpenSSL::Cipher.ciphers. # You also can specify a cipher suite here, listed here at openssl.org: # http://www.openssl.org/docs/apps/ciphers.html#CIPHER_SUITE_NAMES # # class Foo # include HTTParty # ciphers "RC4-SHA" # end def ciphers(cipher_names) default_options[:ciphers] = cipher_names end # Allows setting an OpenSSL certificate authority file. The file # should contain one or more certificates in PEM format. # # Setting this option enables certificate verification. All # certificates along a chain must be available in ssl_ca_file or # ssl_ca_path for verification to succeed. # # # class Foo # include HTTParty # ssl_ca_file '/etc/ssl/certs/ca-certificates.crt' # end def ssl_ca_file(path) default_options[:ssl_ca_file] = path end # Allows setting an OpenSSL certificate authority path (directory). # # Setting this option enables certificate verification. All # certificates along a chain must be available in ssl_ca_file or # ssl_ca_path for verification to succeed. # # class Foo # include HTTParty # ssl_ca_path '/etc/ssl/certs/' # end def ssl_ca_path(path) default_options[:ssl_ca_path] = path end # Allows setting a custom parser for the response. # # class Foo # include HTTParty # parser Proc.new {|data| ...} # end def parser(custom_parser = nil) if custom_parser.nil? default_options[:parser] else default_options[:parser] = custom_parser validate_format end end # Allows setting a custom connection_adapter for the http connections # # @example # class Foo # include HTTParty # connection_adapter Proc.new {|uri, options| ... } # end # # @example provide optional configuration for your connection_adapter # class Foo # include HTTParty # connection_adapter Proc.new {|uri, options| ... }, {:foo => :bar} # end # # @see HTTParty::ConnectionAdapter def connection_adapter(custom_adapter = nil, options = nil) if custom_adapter.nil? default_options[:connection_adapter] else default_options[:connection_adapter] = custom_adapter default_options[:connection_adapter_options] = options end end # Allows making a get request to a url. # # class Foo # include HTTParty # end # # # Simple get with full url # Foo.get('http://foo.com/resource.json') # # # Simple get with full url and query parameters # # ie: http://foo.com/resource.json?limit=10 # Foo.get('http://foo.com/resource.json', :query => {:limit => 10}) def get(path, options={}, &block) perform_request Net::HTTP::Get, path, options, &block end # Allows making a post request to a url. # # class Foo # include HTTParty # end # # # Simple post with full url and setting the body # Foo.post('http://foo.com/resources', :body => {:bar => 'baz'}) # # # Simple post with full url using :query option, # # which gets set as form data on the request. # Foo.post('http://foo.com/resources', :query => {:bar => 'baz'}) def post(path, options={}, &block) perform_request Net::HTTP::Post, path, options, &block end # Perform a PATCH request to a path def patch(path, options={}, &block) perform_request Net::HTTP::Patch, path, options, &block end # Perform a PUT request to a path def put(path, options={}, &block) perform_request Net::HTTP::Put, path, options, &block end # Perform a DELETE request to a path def delete(path, options={}, &block) perform_request Net::HTTP::Delete, path, options, &block end # Perform a MOVE request to a path def move(path, options={}, &block) perform_request Net::HTTP::Move, path, options, &block end # Perform a COPY request to a path def copy(path, options={}, &block) perform_request Net::HTTP::Copy, path, options, &block end # Perform a HEAD request to a path def head(path, options={}, &block) perform_request Net::HTTP::Head, path, options, &block end # Perform an OPTIONS request to a path def options(path, options={}, &block) perform_request Net::HTTP::Options, path, options, &block end def default_options #:nodoc: @default_options end private def perform_request(http_method, path, options, &block) #:nodoc: options = default_options.dup.merge(options) process_cookies(options) Request.new(http_method, path, options).perform(&block) end def process_cookies(options) #:nodoc: return unless options[:cookies] || default_cookies.any? options[:headers] ||= headers.dup options[:headers]["cookie"] = cookies.merge(options.delete(:cookies) || {}).to_cookie_string end def validate_format if format && parser.respond_to?(:supports_format?) && !parser.supports_format?(format) raise UnsupportedFormat, "'#{format.inspect}' Must be one of: #{parser.supported_formats.map{|f| f.to_s}.sort.join(', ')}" end end end def self.normalize_base_uri(url) #:nodoc: normalized_url = url.dup use_ssl = (normalized_url =~ /^https/) || (normalized_url =~ /:443\b/) ends_with_slash = normalized_url =~ /\/$/ normalized_url.chop! if ends_with_slash normalized_url.gsub!(/^https?:\/\//i, '') "http#{'s' if use_ssl}://#{normalized_url}" end class Basement #:nodoc: include HTTParty end def self.get(*args, &block) Basement.get(*args, &block) end def self.post(*args, &block) Basement.post(*args, &block) end def self.patch(*args, &block) Basement.patch(*args, &block) end def self.put(*args, &block) Basement.put(*args, &block) end def self.delete(*args, &block) Basement.delete(*args, &block) end def self.move(*args, &block) Basement.move(*args, &block) end def self.copy(*args, &block) Basement.move(*args, &block) end def self.head(*args, &block) Basement.head(*args, &block) end def self.options(*args, &block) Basement.options(*args, &block) end end require 'httparty/core_extensions' require 'httparty/hash_conversions' require 'httparty/exceptions' require 'httparty/parser' require 'httparty/request' require 'httparty/response' httparty-0.12.0/lib/httparty/0000755000004100000410000000000012254052222016122 5ustar www-datawww-datahttparty-0.12.0/lib/httparty/net_digest_auth.rb0000644000004100000410000000401512254052222021615 0ustar www-datawww-datarequire 'digest/md5' require 'net/http' module Net module HTTPHeader def digest_auth(username, password, response) @header['Authorization'] = DigestAuthenticator.new(username, password, @method, @path, response).authorization_header end class DigestAuthenticator def initialize(username, password, method, path, response_header) @username = username @password = password @method = method @path = path @response = parse(response_header) end def authorization_header @cnonce = md5(random) header = [ %Q(Digest username="#{@username}"), %Q(realm="#{@response['realm']}"), %Q(nonce="#{@response['nonce']}"), %Q(uri="#{@path}"), %Q(response="#{request_digest}"), ] if qop_present? fields = [ %Q(cnonce="#{@cnonce}"), %Q(qop="#{@response['qop']}"), %Q(nc=00000001) ] fields.each { |field| header << field } end header << %Q(opaque="#{@response['opaque']}") if opaque_present? header end private def parse(response_header) response_header['www-authenticate'] =~ /^(\w+) (.*)/ params = {} $2.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 } params end def opaque_present? @response.has_key?('opaque') and not @response['opaque'].empty? end def qop_present? @response.has_key?('qop') and not @response['qop'].empty? end def random "%x" % (Time.now.to_i + rand(65535)) end def request_digest a = [md5(a1), @response['nonce'], md5(a2)] a.insert(2, "00000001", @cnonce, @response['qop']) if qop_present? md5(a.join(":")) end def md5(str) Digest::MD5.hexdigest(str) end def a1 [@username, @response['realm'], @password].join(":") end def a2 [@method, @path].join(":") end end end end httparty-0.12.0/lib/httparty/response.rb0000644000004100000410000000407312254052222020311 0ustar www-datawww-datamodule HTTParty class Response < HTTParty::BasicObject #:nodoc: def self.underscore(string) string.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z])([A-Z])/,'\1_\2').downcase end attr_reader :request, :response, :body, :headers def initialize(request, response, parsed_block, options={}) @request = request @response = response @body = options[:body] || response.body @parsed_block = parsed_block @headers = Headers.new(response.to_hash) if request.options[:logger] logger = ::HTTParty::Logger.build(request.options[:logger], request.options[:log_level], request.options[:log_format]) logger.format(request, self) end end def parsed_response @parsed_response ||= @parsed_block.call end def class Response end def code response.code.to_i end def inspect inspect_id = "%x" % (object_id * 2) %(#<#{self.class}:0x#{inspect_id} parsed_response=#{parsed_response.inspect}, @response=#{response.inspect}, @headers=#{headers.inspect}>) end CODES_TO_OBJ = ::Net::HTTPResponse::CODE_CLASS_TO_OBJ.merge ::Net::HTTPResponse::CODE_TO_OBJ CODES_TO_OBJ.each do |response_code, klass| name = klass.name.sub("Net::HTTP", '') define_method("#{underscore(name)}?") do klass === response end end # Support old multiple_choice? method from pre 2.0.0 era. if ::RUBY_VERSION >= "2.0.0" && ::RUBY_PLATFORM != "java" alias_method :multiple_choice?, :multiple_choices? end def respond_to?(name) return true if [:request, :response, :parsed_response, :body, :headers].include?(name) parsed_response.respond_to?(name) || response.respond_to?(name) end protected def method_missing(name, *args, &block) if parsed_response.respond_to?(name) parsed_response.send(name, *args, &block) elsif response.respond_to?(name) response.send(name, *args, &block) else super end end end end require 'httparty/response/headers' httparty-0.12.0/lib/httparty/logger/0000755000004100000410000000000012254052222017401 5ustar www-datawww-datahttparty-0.12.0/lib/httparty/logger/logger.rb0000644000004100000410000000057012254052222021207 0ustar www-datawww-datarequire 'httparty/logger/apache_logger' require 'httparty/logger/curl_logger' module HTTParty module Logger def self.build(logger, level, formatter) level ||= :info format ||= :apache case formatter when :curl Logger::CurlLogger.new(logger, level) else Logger::ApacheLogger.new(logger, level) end end end end httparty-0.12.0/lib/httparty/logger/curl_logger.rb0000644000004100000410000000267712254052222022246 0ustar www-datawww-datamodule HTTParty module Logger class CurlLogger #:nodoc: TAG_NAME = HTTParty.name OUT = ">" IN = "<" attr_accessor :level, :logger, :current_time def initialize(logger, level) @logger = logger @level = level.to_sym end def format(request, response) messages = [] time = Time.now.strftime("%Y-%m-%d %H:%M:%S %z") http_method = request.http_method.name.split("::").last.upcase path = request.path.to_s messages << print(time, OUT, "#{http_method} #{path}") if request.options[:headers] && request.options[:headers].size > 0 request.options[:headers].each do |k, v| messages << print(time, OUT, "#{k}: #{v}") end end messages << print(time, OUT, request.raw_body) messages << print(time, OUT, "") messages << print(time, IN, "HTTP/#{response.http_version} #{response.code}") headers = response.respond_to?(:headers) ? response.headers : response response.each_header do |response_header| messages << print(time, IN, "#{response_header.capitalize}: #{headers[response_header]}") end messages << print(time, IN, "\n#{response.body}") @logger.send @level, messages.join("\n") end def print(time, direction, line) "[#{TAG_NAME}] [#{time}] #{direction} #{line}" end end end end httparty-0.12.0/lib/httparty/logger/apache_logger.rb0000644000004100000410000000125412254052222022510 0ustar www-datawww-datamodule HTTParty module Logger class ApacheLogger #:nodoc: TAG_NAME = HTTParty.name attr_accessor :level, :logger, :current_time def initialize(logger, level) @logger = logger @level = level.to_sym end def format(request, response) current_time = Time.now.strftime("%Y-%m-%d %H:%M:%S %z") http_method = request.http_method.name.split("::").last.upcase path = request.path.to_s content_length = response['Content-Length'] @logger.send @level, "[#{TAG_NAME}] [#{current_time}] #{response.code} \"#{http_method} #{path}\" #{content_length || "-"} " end end end end httparty-0.12.0/lib/httparty/parser.rb0000644000004100000410000000652412254052222017752 0ustar www-datawww-datamodule HTTParty # The default parser used by HTTParty, supports xml, json, html, and # plain text. # # == Custom Parsers # # If you'd like to do your own custom parsing, subclassing HTTParty::Parser # will make that process much easier. There are a few different ways you can # utilize HTTParty::Parser as a superclass. # # @example Intercept the parsing for all formats # class SimpleParser < HTTParty::Parser # def parse # perform_parsing # end # end # # @example Add the atom format and parsing method to the default parser # class AtomParsingIncluded < HTTParty::Parser # SupportedFormats.merge!( # {"application/atom+xml" => :atom} # ) # # def atom # perform_atom_parsing # end # end # # @example Only support the atom format # class ParseOnlyAtom < HTTParty::Parser # SupportedFormats = {"application/atom+xml" => :atom} # # def atom # perform_atom_parsing # end # end # # @abstract Read the Custom Parsers section for more information. class Parser SupportedFormats = { 'text/xml' => :xml, 'application/xml' => :xml, 'application/json' => :json, 'text/json' => :json, 'application/javascript' => :plain, 'text/javascript' => :plain, 'text/html' => :html, 'text/plain' => :plain } # The response body of the request # @return [String] attr_reader :body # The intended parsing format for the request # @return [Symbol] e.g. :json attr_reader :format # Instantiate the parser and call {#parse}. # @param [String] body the response body # @param [Symbol] format the response format # @return parsed response def self.call(body, format) new(body, format).parse end # @return [Hash] the SupportedFormats hash def self.formats const_get(:SupportedFormats) end # @param [String] mimetype response MIME type # @return [Symbol] # @return [nil] mime type not supported def self.format_from_mimetype(mimetype) formats[formats.keys.detect {|k| mimetype.include?(k)}] end # @return [Array] list of supported formats def self.supported_formats formats.values.uniq end # @param [Symbol] format e.g. :json, :xml # @return [Boolean] def self.supports_format?(format) supported_formats.include?(format) end def initialize(body, format) @body = body @format = format end # @return [Object] the parsed body # @return [nil] when the response body is nil, an empty string, spaces only or "null" def parse return nil if body.nil? || body.strip.empty? || body == "null" if supports_format? parse_supported_format else body end end protected def xml MultiXml.parse(body) end def json JSON.load(body, nil) end def html body end def plain body end def supports_format? self.class.supports_format?(format) end def parse_supported_format send(format) rescue NoMethodError => e raise NotImplementedError, "#{self.class.name} has not implemented a parsing method for the #{format.inspect} format.", e.backtrace end end end httparty-0.12.0/lib/httparty/response/0000755000004100000410000000000012254052222017760 5ustar www-datawww-datahttparty-0.12.0/lib/httparty/response/headers.rb0000644000004100000410000000105212254052222021716 0ustar www-datawww-datamodule HTTParty class Response #:nodoc: class Headers include ::Net::HTTPHeader def initialize(header = {}) @header = header end def ==(other) @header == other end def inspect @header.inspect end def method_missing(name, *args, &block) if @header.respond_to?(name) @header.send(name, *args, &block) else super end end def respond_to?(method) super || @header.respond_to?(method) end end end end httparty-0.12.0/lib/httparty/connection_adapter.rb0000644000004100000410000001223512254052222022311 0ustar www-datawww-datamodule HTTParty # Default connection adapter that returns a new Net::HTTP each time # # == Custom Connection Factories # # If you like to implement your own connection adapter, subclassing # HTTPParty::ConnectionAdapter will make it easier. Just override # the #connection method. The uri and options attributes will have # all the info you need to construct your http connection. Whatever # you return from your connection method needs to adhere to the # Net::HTTP interface as this is what HTTParty expects. # # @example log the uri and options # class LoggingConnectionAdapter < HTTParty::ConnectionAdapter # def connection # puts uri # puts options # Net::HTTP.new(uri) # end # end # # @example count number of http calls # class CountingConnectionAdapter < HTTParty::ConnectionAdapter # @@count = 0 # # self.count # @@count # end # # def connection # self.count += 1 # super # end # end # # === Configuration # There is lots of configuration data available for your connection adapter # in the #options attribute. It is up to you to interpret them within your # connection adapter. Take a look at the implementation of # HTTParty::ConnectionAdapter#connection for examples of how they are used. # Something are probably interesting are as follows: # * :+timeout+: timeout in seconds # * :+debug_output+: see HTTParty::ClassMethods.debug_output. # * :+pem+: contains pem data. see HTTParty::ClassMethods.pem. # * :+ssl_ca_file+: see HTTParty::ClassMethods.ssl_ca_file. # * :+ssl_ca_path+: see HTTParty::ClassMethods.ssl_ca_path. # * :+connection_adapter_options+: contains the hash your passed to HTTParty.connection_adapter when you configured your connection adapter class ConnectionAdapter # Private: Regex used to strip brackets from IPv6 URIs. StripIpv6BracketsRegex = /\A\[(.*)\]\z/ # Public def self.call(uri, options) new(uri, options).connection end attr_reader :uri, :options def initialize(uri, options={}) raise ArgumentError, "uri must be a URI, not a #{uri.class}" unless uri.kind_of? URI @uri = uri @options = options end def connection host = clean_host(uri.host) if options[:http_proxyaddr] http = Net::HTTP.new(host, uri.port, options[:http_proxyaddr], options[:http_proxyport], options[:http_proxyuser], options[:http_proxypass]) else http = Net::HTTP.new(host, uri.port) end http.use_ssl = ssl_implied?(uri) attach_ssl_certificates(http, options) if options[:timeout] && (options[:timeout].is_a?(Integer) || options[:timeout].is_a?(Float)) http.open_timeout = options[:timeout] http.read_timeout = options[:timeout] end if options[:debug_output] http.set_debug_output(options[:debug_output]) end if options[:ciphers] http.ciphers = options[:ciphers] end # Bind to a specific local address or port # # @see https://bugs.ruby-lang.org/issues/6617 if options[:local_host] if RUBY_VERSION >= "2.0.0" http.local_host = options[:local_host] else Kernel.warn("Warning: option :local_host requires Ruby version 2.0 or later") end end if options[:local_port] if RUBY_VERSION >= "2.0.0" http.local_port = options[:local_port] else Kernel.warn("Warning: option :local_port requires Ruby version 2.0 or later") end end return http end private def clean_host(host) strip_ipv6_brackets(host) end def strip_ipv6_brackets(host) StripIpv6BracketsRegex =~ host ? $1 : host end def ssl_implied?(uri) uri.port == 443 || uri.instance_of?(URI::HTTPS) end def attach_ssl_certificates(http, options) if http.use_ssl? if options.fetch(:verify, true) http.verify_mode = OpenSSL::SSL::VERIFY_PEER if options[:cert_store] http.cert_store = options[:cert_store] else # Use the default cert store by default, i.e. system ca certs http.cert_store = OpenSSL::X509::Store.new http.cert_store.set_default_paths end else http.verify_mode = OpenSSL::SSL::VERIFY_NONE end # Client certificate authentication if options[:pem] http.cert = OpenSSL::X509::Certificate.new(options[:pem]) http.key = OpenSSL::PKey::RSA.new(options[:pem], options[:pem_password]) http.verify_mode = OpenSSL::SSL::VERIFY_PEER end # SSL certificate authority file and/or directory if options[:ssl_ca_file] http.ca_file = options[:ssl_ca_file] http.verify_mode = OpenSSL::SSL::VERIFY_PEER end if options[:ssl_ca_path] http.ca_path = options[:ssl_ca_path] http.verify_mode = OpenSSL::SSL::VERIFY_PEER end # This is only Ruby 1.9+ if options[:ssl_version] && http.respond_to?(:ssl_version=) http.ssl_version = options[:ssl_version] end end end end end httparty-0.12.0/lib/httparty/request.rb0000644000004100000410000002227412254052222020146 0ustar www-datawww-datamodule 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, Net::HTTP::Move, Net::HTTP::Copy ] SupportedURISchemes = [URI::HTTP, URI::HTTPS, URI::Generic] 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, :options, :last_response, :redirect, :last_uri attr_reader :path def initialize(http_method, path, o={}) self.http_method = http_method self.path = path self.options = { :limit => o.delete(:no_follow) ? 1 : 5, :assume_utf16_is_big_endian => true, :default_params => {}, :follow_redirects => true, :parser => Parser, :connection_adapter => ConnectionAdapter }.merge(o) end def path=(uri) @path = URI.parse(uri) end def request_uri(uri) if uri.respond_to? :request_uri uri.request_uri else uri.path end end def uri new_uri = path.relative? ? URI.parse("#{base_uri}#{path}") : path.clone # 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, HTTPS or Generic" 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 unless http_method == Net::HTTP::Head handle_response(chunked_body, &block) end def raw_body @raw_request.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(request_uri(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 get_charset content_type = last_response["content-type"] if content_type.nil? return nil end if content_type =~ /;\s*charset\s*=\s*([^=,;"\s]+)/i return $1 end if content_type =~ /;\s*charset\s*=\s*"((\\.|[^\\"])+)"/i return $1.gsub(/\\(.)/, '\1') end nil end def encode_with_ruby_encoding(body, charset) begin encoding = Encoding.find(charset) body.force_encoding(encoding) rescue body end end def assume_utf16_is_big_endian options[:assume_utf16_is_big_endian] end def encode_utf_16(body) if body.bytesize >= 2 if body.getbyte(0) == 0xFF && body.getbyte(1) == 0xFE return body.force_encoding("UTF-16LE") elsif body.getbyte(0) == 0xFE && body.getbyte(1) == 0xFF return body.force_encoding("UTF-16BE") end end if assume_utf16_is_big_endian body.force_encoding("UTF-16BE") else body.force_encoding("UTF-16LE") end end def _encode_body(body) charset = get_charset if charset.nil? return body end if "utf-16".casecmp(charset) == 0 encode_utf_16(body) else encode_with_ruby_encoding(body, charset) end end def encode_body(body) if "".respond_to?(:encoding) _encode_body(body) else body end end def handle_response(body, &block) if response_redirects? options[:limit] -= 1 if options[:logger] logger = HTTParty::Logger.build(options[:logger], options[:log_level], options[:log_format]) logger.format(self, last_response) end 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(&block) else body = body || last_response.body body = encode_body(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'] response.get_fields('Set-Cookie').each { |cookie| cookies_hash.add_cookies(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 httparty-0.12.0/lib/httparty/version.rb0000644000004100000410000000005112254052222020130 0ustar www-datawww-datamodule HTTParty VERSION = "0.12.0" end httparty-0.12.0/lib/httparty/core_extensions.rb0000644000004100000410000000136312254052222021661 0ustar www-datawww-datamodule HTTParty if defined?(::BasicObject) BasicObject = ::BasicObject #:nodoc: else class BasicObject #:nodoc: instance_methods.each { |m| undef_method m unless m =~ /^__|instance_eval/ } end end unless defined?(Net::HTTP::Patch) class Net::HTTP def patch(path, data, initheader = nil, dest = nil, &block) #:nodoc: res = nil request(Patch.new(path, initheader), data) {|r| r.read_body dest, &block res = r } unless @newimpl res.value return res, res.body end res end class Patch < Net::HTTPRequest METHOD = 'PATCH' REQUEST_HAS_BODY = true RESPONSE_HAS_BODY = true end end end end httparty-0.12.0/lib/httparty/hash_conversions.rb0000644000004100000410000000273212254052222022026 0ustar www-datawww-datamodule HTTParty module HashConversions # @return This hash as a query string # # @example # { :name => "Bob", # :address => { # :street => '111 Ruby Ave.', # :city => 'Ruby Central', # :phones => ['111-111-1111', '222-222-2222'] # } # }.to_params # #=> "name=Bob&address[city]=Ruby Central&address[phones][]=111-111-1111&address[phones][]=222-222-2222&address[street]=111 Ruby Ave." def self.to_params(hash) params = hash.map { |k,v| normalize_param(k,v) }.join params.chop! # trailing & params end # @param key The key for the param. # @param value The value for the param. # # @return This key value pair as a param # # @example normalize_param(:name, "Bob Jones") #=> "name=Bob%20Jones&" def self.normalize_param(key, value) param = '' stack = [] if value.is_a?(Array) param << value.map { |element| normalize_param("#{key}[]", element) }.join elsif value.is_a?(Hash) stack << [key,value] else param << "#{key}=#{URI.encode(value.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}&" end stack.each do |parent, hash| hash.each do |k, v| if v.is_a?(Hash) stack << ["#{parent}[#{k}]", v] else param << normalize_param("#{parent}[#{k}]", v) end end end param end end end httparty-0.12.0/lib/httparty/cookie_hash.rb0000644000004100000410000000104412254052222020722 0ustar www-datawww-dataclass HTTParty::CookieHash < Hash #:nodoc: CLIENT_COOKIES = %w{path expires domain path secure HTTPOnly} def add_cookies(value) case value when Hash merge!(value) when String value.split('; ').each do |cookie| array = cookie.split('=',2) self[array[0].to_sym] = array[1] end else raise "add_cookies only takes a Hash or a String" end end def to_cookie_string delete_if { |k, v| CLIENT_COOKIES.include?(k.to_s.downcase) }.collect { |k, v| "#{k}=#{v}" }.join("; ") end end httparty-0.12.0/lib/httparty/module_inheritable_attributes.rb0000644000004100000410000000271512254052222024555 0ustar www-datawww-datamodule HTTParty module ModuleInheritableAttributes #:nodoc: def self.included(base) base.extend(ClassMethods) end # borrowed from Rails 3.2 ActiveSupport def self.hash_deep_dup(hash) duplicate = hash.dup duplicate.each_pair do |key, value| duplicate[key] = if value.is_a?(Hash) hash_deep_dup(value) elsif value.is_a?(Proc) duplicate[key] = value.dup else value end end duplicate end module ClassMethods #:nodoc: def mattr_inheritable(*args) @mattr_inheritable_attrs ||= [:mattr_inheritable_attrs] @mattr_inheritable_attrs += args args.each do |arg| module_eval %(class << self; attr_accessor :#{arg} end) end @mattr_inheritable_attrs end def inherited(subclass) super @mattr_inheritable_attrs.each do |inheritable_attribute| ivar = "@#{inheritable_attribute}" subclass.instance_variable_set(ivar, instance_variable_get(ivar).clone) if instance_variable_get(ivar).respond_to?(:merge) method = <<-EOM def self.#{inheritable_attribute} duplicate = ModuleInheritableAttributes.hash_deep_dup(#{ivar}) #{ivar} = superclass.#{inheritable_attribute}.merge(duplicate) end EOM subclass.class_eval method end end end end end end httparty-0.12.0/lib/httparty/exceptions.rb0000644000004100000410000000170312254052222020631 0ustar www-datawww-datamodule HTTParty # Exception raised when you attempt to set a non-existant format class UnsupportedFormat < StandardError; end # Exception raised when using a URI scheme other than HTTP or HTTPS class UnsupportedURIScheme < StandardError; end # @abstract Exceptions which inherit from ResponseError contain the Net::HTTP # response object accessible via the {#response} method. class ResponseError < StandardError # Returns the response of the last request # @return [Net::HTTPResponse] A subclass of Net::HTTPResponse, e.g. # Net::HTTPOK attr_reader :response # Instantiate an instance of ResponseError with a Net::HTTPResponse object # @param [Net::HTTPResponse] def initialize(response) @response = response end end # Exception that is raised when request has redirected too many times. # Calling {#response} returns the Net:HTTP response object. class RedirectionTooDeep < ResponseError; end end httparty-0.12.0/cucumber.yml0000644000004100000410000000004412254052222016023 0ustar www-datawww-datadefault: features --format progress httparty-0.12.0/httparty.gemspec0000644000004100000410000000176012254052222016725 0ustar www-datawww-data# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "httparty/version" Gem::Specification.new do |s| s.name = "httparty" s.version = HTTParty::VERSION s.platform = Gem::Platform::RUBY s.authors = ["John Nunemaker", "Sandro Turriate"] s.email = ["nunemaker@gmail.com"] s.homepage = "http://jnunemaker.github.com/httparty" s.summary = %q{Makes http fun! Also, makes consuming restful web services dead easy.} s.description = %q{Makes http fun! Also, makes consuming restful web services dead easy.} s.required_ruby_version = '>= 1.9.3' s.add_dependency 'json', "~> 1.8" s.add_dependency 'multi_xml', ">= 0.5.2" s.post_install_message = "When you HTTParty, you must party hard!" s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] end httparty-0.12.0/metadata.yml0000644000004100000410000001355512254052222016011 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: httparty version: !ruby/object:Gem::Version version: 0.12.0 platform: ruby authors: - John Nunemaker - Sandro Turriate autorequire: bindir: bin cert_chain: [] date: 2013-10-10 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: json requirement: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '1.8' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version version: '1.8' - !ruby/object:Gem::Dependency name: multi_xml requirement: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: 0.5.2 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: 0.5.2 description: Makes http fun! Also, makes consuming restful web services dead easy. email: - nunemaker@gmail.com executables: - httparty extensions: [] extra_rdoc_files: [] files: - .gitignore - .travis.yml - Gemfile - Guardfile - History - MIT-LICENSE - README.md - Rakefile - bin/httparty - cucumber.yml - examples/aaws.rb - examples/basic.rb - examples/crack.rb - examples/custom_parsers.rb - examples/delicious.rb - examples/google.rb - examples/headers_and_user_agents.rb - examples/nokogiri_html_parser.rb - examples/rubyurl.rb - examples/tripit_sign_in.rb - examples/twitter.rb - examples/whoismyrep.rb - features/basic_authentication.feature - features/command_line.feature - features/deals_with_http_error_codes.feature - features/digest_authentication.feature - features/handles_compressed_responses.feature - features/handles_multiple_formats.feature - features/steps/env.rb - features/steps/httparty_response_steps.rb - features/steps/httparty_steps.rb - features/steps/mongrel_helper.rb - features/steps/remote_service_steps.rb - features/supports_redirection.feature - features/supports_timeout_option.feature - httparty.gemspec - lib/httparty.rb - lib/httparty/connection_adapter.rb - lib/httparty/cookie_hash.rb - lib/httparty/core_extensions.rb - lib/httparty/exceptions.rb - lib/httparty/hash_conversions.rb - lib/httparty/logger/apache_logger.rb - lib/httparty/logger/curl_logger.rb - lib/httparty/logger/logger.rb - lib/httparty/module_inheritable_attributes.rb - lib/httparty/net_digest_auth.rb - lib/httparty/parser.rb - lib/httparty/request.rb - lib/httparty/response.rb - lib/httparty/response/headers.rb - lib/httparty/version.rb - script/release - spec/fixtures/delicious.xml - spec/fixtures/empty.xml - spec/fixtures/google.html - spec/fixtures/ssl/generate.sh - spec/fixtures/ssl/generated/1fe462c2.0 - spec/fixtures/ssl/generated/bogushost.crt - spec/fixtures/ssl/generated/ca.crt - spec/fixtures/ssl/generated/ca.key - spec/fixtures/ssl/generated/selfsigned.crt - spec/fixtures/ssl/generated/server.crt - spec/fixtures/ssl/generated/server.key - spec/fixtures/ssl/openssl-exts.cnf - spec/fixtures/twitter.json - spec/fixtures/twitter.xml - spec/fixtures/undefined_method_add_node_for_nil.xml - spec/httparty/connection_adapter_spec.rb - spec/httparty/cookie_hash_spec.rb - spec/httparty/logger/apache_logger_spec.rb - spec/httparty/logger/curl_logger_spec.rb - spec/httparty/logger/logger_spec.rb - spec/httparty/net_digest_auth_spec.rb - spec/httparty/parser_spec.rb - spec/httparty/request_spec.rb - spec/httparty/response_spec.rb - spec/httparty/ssl_spec.rb - spec/httparty_spec.rb - spec/spec.opts - spec/spec_helper.rb - spec/support/ssl_test_helper.rb - spec/support/ssl_test_server.rb - spec/support/stub_response.rb - website/css/common.css - website/index.html homepage: http://jnunemaker.github.com/httparty licenses: [] metadata: {} post_install_message: When you HTTParty, you must party hard! rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: 1.9.3 required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.0.3 signing_key: specification_version: 4 summary: Makes http fun! Also, makes consuming restful web services dead easy. test_files: - features/basic_authentication.feature - features/command_line.feature - features/deals_with_http_error_codes.feature - features/digest_authentication.feature - features/handles_compressed_responses.feature - features/handles_multiple_formats.feature - features/steps/env.rb - features/steps/httparty_response_steps.rb - features/steps/httparty_steps.rb - features/steps/mongrel_helper.rb - features/steps/remote_service_steps.rb - features/supports_redirection.feature - features/supports_timeout_option.feature - spec/fixtures/delicious.xml - spec/fixtures/empty.xml - spec/fixtures/google.html - spec/fixtures/ssl/generate.sh - spec/fixtures/ssl/generated/1fe462c2.0 - spec/fixtures/ssl/generated/bogushost.crt - spec/fixtures/ssl/generated/ca.crt - spec/fixtures/ssl/generated/ca.key - spec/fixtures/ssl/generated/selfsigned.crt - spec/fixtures/ssl/generated/server.crt - spec/fixtures/ssl/generated/server.key - spec/fixtures/ssl/openssl-exts.cnf - spec/fixtures/twitter.json - spec/fixtures/twitter.xml - spec/fixtures/undefined_method_add_node_for_nil.xml - spec/httparty/connection_adapter_spec.rb - spec/httparty/cookie_hash_spec.rb - spec/httparty/logger/apache_logger_spec.rb - spec/httparty/logger/curl_logger_spec.rb - spec/httparty/logger/logger_spec.rb - spec/httparty/net_digest_auth_spec.rb - spec/httparty/parser_spec.rb - spec/httparty/request_spec.rb - spec/httparty/response_spec.rb - spec/httparty/ssl_spec.rb - spec/httparty_spec.rb - spec/spec.opts - spec/spec_helper.rb - spec/support/ssl_test_helper.rb - spec/support/ssl_test_server.rb - spec/support/stub_response.rb httparty-0.12.0/.gitignore0000644000004100000410000000011212254052222015457 0ustar www-datawww-dataGemfile.lock .DS_Store .yardoc/ doc/ tmp/ log/ pkg/ *.swp /.bundle .rvmrc httparty-0.12.0/History0000644000004100000410000002725712254052222015076 0ustar www-datawww-data== 0.10.1 2013-01-26 * new * [added support for MOVE requests](https://github.com/jnunemaker/httparty/pull/183) * [bump multi xml version](https://github.com/jnunemaker/httparty/pull/181) == 0.10.0 2013-01-10 * changes * removed yaml support because of security risk (see rails yaml issues) == 0.9.0 2012-09-07 * new * [support for connection adapters](https://github.com/jnunemaker/httparty/pull/157) * [allow ssl_version on ruby 1.9](https://github.com/jnunemaker/httparty/pull/159) * bug fixes * [don't treat port 4430 as ssl](https://github.com/jnunemaker/httparty/commit/a296b1c97f83d7dcc6ef85720a43664c265685ac) * [deep clone default options](https://github.com/jnunemaker/httparty/commit/f74227d30f9389b4b23a888c9af49fb9b8248e1f) * a few net digest auth fixes == 0.8.3 2012-04-21 * new * [lazy parsing of responses](https://github.com/jnunemaker/httparty/commit/9fd5259c8dab00e426082b66af44ede2c9068f45) * [add support for PATCH requests](https://github.com/jnunemaker/httparty/commit/7ab6641e37a9e31517e46f6124f38c615395d38a) * bug fixes * [subclasses no longer override superclass options](https://github.com/jnunemaker/httparty/commit/682af8fbf672e7b3009e650da776c85cdfe78d39) == 0.8.2 2012-04-12 * new * add -r to make CLI return failure code if status >= 400 * allow blank username from CLI * bug fixes * return nil for null body * automatically deflate responses with a Content-Encoding: x-gzip header * Do not HEAD on POST request with digest authentication * add support for proxy authentication * fix posting data with CLI * require rexml/document if xml format from CLI * support for fragmented responses == 0.8.1 2011-10-05 * bug fixes * content-encoding header should be removed when automatically inflating the body == 0.8.0 2011-09-13 * new * switch to multi json/xml for parsing by default * bug fixes * fix redirects to relative uri's == 0.7.8 2011-06-06 * bug fix * Make response honor respond to * net http timeout can also be a float == 0.7.7 2011-04-16 * bug fix * Fix NoMethodError when using the NON_RAILS_QUERY_STRING_NORMALIZER with a hash whose key is a symbol and value is nil == 0.7.5 2011-04-16 * bug fix * caused issue with latest rubygems == 0.7.4 2011-02-13 * bug fixes * Set VERIFY_NONE when using https. Ruby 1.9.2 no longer sets this for us. gh-67 == 0.7.3 2011-01-20 * bug fixes * Fix digest auth for unspecified quality of protection (bjoernalbers, mtrudel, dwo) == 0.7.2 2011-01-20 * bug fixes * Fix gem dependencies == 0.7.1 2011-01-19 * bug fixes * Fix uninitialized constant HTTParty::Response::Net in 1.9.2 (cap10morgan) * Other fixes for 1.9.2, full suite still fails (cap10morgan) == 0.7.0 2011-01-18 * minor enhancements * Added query methods for HTTP status codes, i.e. response.success? response.created? (thanks citizenparker) * Added support for ssl_ca_file and ssl_ca_path (dlitz) * Allow custom query string normalization. gh-8 * Unlock private keys with password (freerange) * Added high level request documentation (phildarnowsky) * Added basic post example (pbuckley) * Response object has access to its corresponding request object * Added example of siginin into tripit.com * Added option to follow redirects (rkj). gh-56 * bug fixes * Fixed superclass mismatch exception while running tests (thanks dlitz http://github.com/dlitz/httparty/commit/48224f0615b32133afcff4718ad426df7a4b401b) == 0.6.1 2010-07-07 * minor enhancements * updated to crack 0.1.8 * bug fixes * subclasses always merge into the parent's default_options and default_cookies (l4rk). * subclasses play nicely with grand parents. gh-49 == 0.6.0 2010-06-13 * major enhancements * Digest Auth (bartiaco, sbecker, gilles, and aaronrussell) * Maintain HTTP method across redirects (bartiaco and sbecker) * HTTParty::Response#response returns the Net::HTTPResponse object * HTTParty::Response#headers returns a HTTParty::Response::Headers object which quacks like a Hash + Net::HTTPHeader. The #headers method continues to be backwards-compatible with the old Hash return value but may become deprecated in the future. * minor enhancements * Update crack requirement to version 0.1.7 You may still get a warning because Crack's version constant is out of date * Timeout option can be set for all requests using HTTParty.default_timeout (taazza) * Closed #38 "headers hash should downcase keys so canonical header name can be used" * Closed #40 "Gzip response" wherein gziped and deflated responses are automatically inflated. (carsonmcdonald) == 0.5.2 2010-01-31 * minor enhancements * Update crack requirement to version 0.1.6 == 0.5.1 2010-01-30 * bug fixes * Handle 304 response correctly by returning the HTTParty::Response object instead of redirecting (seth and hellvinz) * Only redirect 300 responses if the header contains a Location * Don't append empty query strings to the uri. Closes #31 * When no_follow is enabled, only raise the RedirectionTooDeep exception when a response tries redirecting. Closes #28 * major enhancements * Removed rubygems dependency. I suggest adding rubygems to RUBYOPT if this causes problems for you. $ export RUBYOPT='rubygems' * HTTParty#debug_output prints debugging information for the current request (iwarshak) * HTTParty#no_follow now available as a class-level option. Sets whether or not to follow redirects. * minor enhancements * HTTParty::VERSION now available * Update crack requirement to version 0.1.5 == 0.5.0 2009-12-07 * bug fixes * inheritable attributes no longer mutable by subclasses (yyyc514) * namespace BasicObject within HTTParty to avoid class name collisions (eric) * major enhancements * Custom Parsers via class or proc * Deprecation warning on HTTParty::AllowedFormats moved to HTTParty::Parser::SupportedFormats * minor enhancements * Curl inspired output when using the binary in verbose mode (alexvollmer) * raise UnsupportedURIScheme when scheme is not HTTP or HTTPS (djspinmonkey) * Allow SSL for ports other than 443 when scheme is HTTPS (stefankroes) * Accept PEM certificates via HTTParty#pem (chrislo) * Support HEAD and OPTION verbs (grempe) * Verify SSL certificates when providing a PEM file (collectiveidea/danielmorrison) == 0.4.5 2009-09-12 * bug fixes * Fixed class-level headers overwritten by cookie management code. Closes #19 * Fixed "superclass mismatch for class BlankSlate" error. Closes #20 * Fixed reading files as post data from the command line (vesan) * minor enhancements * Timeout option added; will raise a Timeout::Error after the timeout has elapsed (attack). Closes #17 HTTParty.get "http://github.com", :timeout => 1 * Building gem with Jeweler == 0.4.4 2009-07-19 * 2 minor update * :query no longer sets form data. Use body and set content type to application/x-www-form-urlencoded if you need it. :query was wrong for that. * Fixed a bug in the cookies class method that caused cookies to be forgotten after the first request. * Also, some general cleanup of tests and such. == 0.4.3 2009-04-23 * 1 minor update * added message to the response object == 0.4.2 2009-03-30 * 2 minor changes * response code now returns an integer instead of a string (jqr) * rubyforge project setup for crack so i'm now depending on that instead of jnunemaker-crack == 0.4.1 2009-03-29 * 1 minor fix * gem 'jnunemaker-crack' instead of gem 'crack' == 0.4.0 2009-03-29 * 1 minor change * Switched xml and json parsing to crack (same code as before just moved to gem for easier reuse in other projects) == 0.3.1 2009-02-10 * 1 minor fix, 1 minor enhancement * Fixed unescaping umlauts (siebertm) * Added yaml response parsing (Miha Filej) == 0.3.0 2009-01-31 * 1 major enhancement, 1 bug fix * JSON gem no longer a requirement. It was conflicting with rails json stuff so I just stole ActiveSupport's json decoding and bundled it with HTTParty. * Fixed bug where query strings were being duplicated on redirects * Added a bunch of specs and moved some code around. == 0.2.10 2009-01-29 * 1 minor enhancement * Made encoding on query parameters treat everything except URI::PATTERN::UNRESERVED as UNSAFE to force encoding of '+' character (Julian Russell) == 0.2.9 2009-01-29 * 3 minor enhancements * Added a 'headers' accessor to the response with a hash of any HTTP headers. (Don Peterson) * Add support for a ":cookies" option to be used at the class level, or as an option on any individual call. It should be passed a hash, which will be converted to the proper format and added to the request headers when the call is made. (Don Peterson) * Refactored several specs and added a full suite of cucumber features (Don Peterson) == 0.2.8 2009-01-28 * 1 major fix * fixed major bug with response where it wouldn't iterate or really work at all with parsed responses == 0.2.7 2009-01-28 * 2 minor fixes, 2 minor enhancements, 2 major enhancements * fixed undefined method add_node for nil class error that occasionally happened (juliocesar) * Handle nil or unexpected values better when typecasting. (Brian Landau) * More robust handling of mime types (Alex Vollmer) * Fixed support for specifying headers and added support for basic auth to CLI. (Alex Vollmer) * Added first class response object that includes original body and status code (Alex Vollmer) * Now parsing all response types as some non-200 responses provide important information, this means no more exception raising (Alex Vollmer) == 0.2.6 2009-01-05 * 1 minor bug fix * added explicit require of time as Time#parse failed outside of rails (willcodeforfoo) == 0.2.5 2009-01-05 * 1 major enhancement * Add command line interface to HTTParty (Alex Vollmer) == 0.2.4 2008-12-23 * 1 bug fix * Fixed that mimetype detection was failing if no mimetype was returned from service (skippy) == 0.2.3 2008-12-23 * 1 bug fix * Fixed typecasting class variable naming issue == 0.2.2 2008-12-08 * 1 bug fix * Added the missing core extension hash method to_xml_attributes == 0.2.1 2008-12-08 * 1 bug fix * Fixed that HTTParty was borking ActiveSupport and as such Rails (thanks to Rob Sanheim) == 0.2.0 2008-12-07 * 1 major enhancement * Removed ActiveSupport as a dependency. Now requires json gem for json deserialization and uses an included class to do the xml parsing. == 0.1.8 2008-11-30 * 3 major enhancements * Moved base_uri normalization into request class and out of httparty module, fixing the problem where base_uri was not always being normalized. * Stupid simple support for HTTParty.get/post/put/delete. (jqr) * Switched gem management to Echoe from newgem. == 0.1.7 2008-11-30 * 1 major enhancement * fixed multiple class definitions overriding each others options == 0.1.6 2008-11-26 * 1 major enhancement * now passing :query to set_form_data if post request to avoid content length errors == 0.1.5 2008-11-14 * 2 major enhancements * Refactored send request method out into its own object. * Added :html format if you just want to do that. == 0.1.4 2008-11-08 * 3 major enhancements: * Removed some cruft * Added ability to follow redirects automatically and turn that off (Alex Vollmer) == 0.1.3 2008-08-22 * 3 major enhancements: * Added http_proxy key for setting proxy server and port (francxk@gmail.com) * Now raises exception when http error occurs (francxk@gmail.com) * Changed auto format detection from file extension to response content type (Jay Pignata) == 0.1.2 2008-08-09 * 1 major enhancement: * default_params were not being appended to query string if option[:query] was blank == 0.1.1 2008-07-30 * 2 major enhancement: * Added :basic_auth key for options when making a request * :query and :body both now work with query string or hash == 0.1.0 2008-07-27 * 1 major enhancement: * Initial release httparty-0.12.0/website/0000755000004100000410000000000012254052222015137 5ustar www-datawww-datahttparty-0.12.0/website/css/0000755000004100000410000000000012254052222015727 5ustar www-datawww-datahttparty-0.12.0/website/css/common.css0000644000004100000410000000435512254052222017740 0ustar www-datawww-data@media screen, projection { /* Copyright (c) 2007, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt version: 2.2.0 */ body {font:13px arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}table {font-size:inherit;font:100%;}select, input, textarea {font:99% arial,helvetica,clean,sans-serif;}pre, code {font:115% monospace;*font-size:100%;}body * {line-height:1.22em;} body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}/*ol,ul {list-style:none;}*/caption,th {text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym {border:0;} /* end of yahoo reset and fonts */ body {color:#333; background:#4b1a1a; line-height:1.3;} p {margin:0 0 20px;} a {color:#4b1a1a;} a:hover {text-decoration:none;} strong {font-weight:bold;} em {font-style:italics;} h1,h2,h3,h4,h5,h6 {font-weight:bold;} h1 {font-size:197%; margin:30px 0; color:#4b1a1a;} h2 {font-size:174%; margin:20px 0; color:#b8111a;} h3 {font-size:152%; margin:10px 0;} h4 {font-size:129%; margin:10px 0;} pre {background:#eee; margin:0 0 20px; padding:20px; border:1px solid #ccc; font-size:100%; overflow:auto;} code {font-size:100%; margin:0; padding:0;} ul, ol {margin:10px 0 10px 25px;} ol li {margin:0 0 10px;} div#wrapper {background:#fff; width:560px; margin:0 auto; padding:20px; border:10px solid #bc8c46; border-width:0 10px;} div#header {position:relative; border-bottom:1px dotted; margin:0 0 10px; padding:0 0 10px;} div#header p {margin:0; padding:0;} div#header h1 {margin:0; padding:0;} ul#nav {position:absolute; top:0; right:0; list-style:none; margin:0; padding:0;} ul#nav li {display:inline; padding:0 0 0 5px;} ul#nav li a {} div#content {} div#footer {margin:40px 0 0; border-top:1px dotted; padding:10px 0 0;} }httparty-0.12.0/website/index.html0000644000004100000410000000511112254052222017132 0ustar www-datawww-data HTTParty by John Nunemaker

Install

$ sudo gem install httparty

Some Quick Examples

The following is a simple example of wrapping Twitter's API for posting updates.

class Twitter
  include HTTParty
  base_uri 'twitter.com'
  basic_auth 'username', 'password'
end

Twitter.post('/statuses/update.json', :query => {:status => "It's an HTTParty and everyone is invited!"})

That is really it! The object returned is a ruby hash that is decoded from Twitter's json response. JSON parsing is used because of the .json extension in the path of the request. You can also explicitly set a format (see the examples).

That works and all but what if you don't want to embed your username and password in the class? Below is an example to fix that:

class Twitter
  include HTTParty
  base_uri 'twitter.com'

  def initialize(u, p)
    @auth = {:username => u, :password => p}
  end

  def post(text)
    options = { :query => {:status => text}, :basic_auth => @auth }
    self.class.post('/statuses/update.json', options)
  end
end

Twitter.new('username', 'password').post("It's an HTTParty and everyone is invited!")

More Examples: There are several examples in the gem itself.

Support

Conversations welcome in the google group and bugs/features over at Github.

httparty-0.12.0/checksums.yaml.gz0000444000004100000410000000041512254052222016763 0ustar www-datawww-dataVRe;N@ D"gצA8=KJ謑޼vr~÷?~5kK$ku0)\UdlP5sDE+ɤ-_ KӠ;x{2A%F-X' 0g |aȪ5G)TB&j&\ڠQ>f4ak#H-GJrzNEH9@6g AYj3ui֎CƂĦxxhttparty-0.12.0/README.md0000644000004100000410000000433512254052222014761 0ustar www-datawww-data# httparty Makes http fun again! ## Install ``` gem install httparty ``` ## Requirements * Ruby 1.9.3 or higher * multi_xml * You like to party! ## Examples ```ruby # Use the class methods to get down to business quickly response = HTTParty.get('http://twitter.com/statuses/public_timeline.json') puts response.body, response.code, response.message, response.headers.inspect response.each do |item| puts item['user']['screen_name'] end # Or wrap things up in your own class class Twitter include HTTParty base_uri 'twitter.com' def initialize(u, p) @auth = {:username => u, :password => p} end # which can be :friends, :user or :public # options[:query] can be things like since, since_id, count, etc. def timeline(which=:friends, options={}) options.merge!({:basic_auth => @auth}) self.class.get("/statuses/#{which}_timeline.json", options) end def post(text) options = { :body => {:status => text}, :basic_auth => @auth } self.class.post('/statuses/update.json', options) end end twitter = Twitter.new(config['email'], config['password']) pp twitter.timeline ``` See the [examples directory](http://github.com/jnunemaker/httparty/tree/master/examples) for even more goodies. ## Command Line Interface httparty also includes the executable `httparty` which can be used to query web services and examine the resulting output. By default it will output the response as a pretty-printed Ruby object (useful for grokking the structure of output). This can also be overridden to output formatted XML or JSON. Execute `httparty --help` for all the options. Below is an example of how easy it is. ``` httparty "http://twitter.com/statuses/public_timeline.json" ``` ## Help and Docs * https://groups.google.com/forum/#!forum/httparty-gem * http://rdoc.info/projects/jnunemaker/httparty ## Contributing * Fork the project. * Make your feature addition or bug fix. * Add tests for it. This is important so I don't break it in a future version unintentionally. * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself in another branch so I can ignore when I pull) * Send me a pull request. Bonus points for topic branches. httparty-0.12.0/Guardfile0000644000004100000410000000052612254052222015325 0ustar www-datawww-datarspec_options = { :version => 1, :all_after_pass => false, :all_on_start => false, } guard 'rspec', rspec_options do watch(%r{^spec/.+_spec\.rb$}) watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } watch('spec/spec_helper.rb') { "spec" } end guard 'bundler' do watch('Gemfile') watch(/^.+\.gemspec/) end