httparty-0.15.6/0000755000004100000410000000000013145325011013505 5ustar www-datawww-datahttparty-0.15.6/Rakefile0000644000004100000410000000030313145325011015146 0ustar www-datawww-databegin require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) rescue LoadError end require 'cucumber/rake/task' Cucumber::Rake::Task.new(:features) task default: [:spec, :features] httparty-0.15.6/bin/0000755000004100000410000000000013145325011014255 5ustar www-datawww-datahttparty-0.15.6/bin/httparty0000755000004100000410000000602613145325011016066 0ustar www-datawww-data#!/usr/bin/env ruby require "optparse" require "pp" $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "/../lib")) require "httparty" opts = { action: :get, headers: {}, verbose: false } OptionParser.new do |o| o.banner = "USAGE: #{$PROGRAM_NAME} [options] [url]" o.on("-f", "--format [FORMAT]", "Output format to use instead of pretty-print ruby: " \ "plain, csv, 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 o.on("--version", "Show HTTParty version") do |ver| puts "Version: #{HTTParty::VERSION}" exit end end.parse! if ARGV.empty? STDERR.puts "You need to provide a URL" STDERR.puts "USAGE: #{$PROGRAM_NAME} [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.parsed_response) rescue LoadError puts YAML.dump(response) rescue JSON::JSONError puts response.inspect end when :xml require 'rexml/document' REXML::Document.new(response.body).write(STDOUT, 2) puts when :csv require 'csv' puts CSV.parse(response.body).map(&:to_s) else puts response end end exit false if opts[:response_code] && response.code >= 400 httparty-0.15.6/Gemfile0000644000004100000410000000045413145325011015003 0ustar www-datawww-datasource 'https://rubygems.org' gemspec gem 'rake' gem 'mongrel', '1.2.0.pre2' group :development do gem 'guard' gem 'guard-rspec' gem 'guard-bundler' end group :test do gem 'rspec', '~> 3.4' gem 'simplecov', require: false gem 'aruba' gem 'cucumber', '~> 2.3' gem 'webmock' end httparty-0.15.6/examples/0000755000004100000410000000000013145325011015323 5ustar www-datawww-datahttparty-0.15.6/examples/rescue_json.rb0000644000004100000410000000120613145325011020166 0ustar www-datawww-datadir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') # Take note of the "; 1" at the end of the following line. It's required only if # running this in IRB, because IRB will try to inspect the variable named # "request", triggering the exception. request = HTTParty.get 'https://rubygems.org/api/v1/versions/doesnotexist.json' ; 1 # Check an exception due to parsing the response # because HTTParty evaluate the response lazily begin request.inspect # This would also suffice by forcing the request to be parsed: # request.parsed_response rescue => e puts "Rescued #{e.inspect}" end httparty-0.15.6/examples/custom_parsers.rb0000644000004100000410000000201213145325011020714 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 do |body, format| case format when :json body.to_json when :xml body.to_xml else body end end ) end httparty-0.15.6/examples/tripit_sign_in.rb0000644000004100000410000000214313145325011020671 0ustar www-datawww-datadir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') class TripIt include HTTParty base_uri 'https://www.tripit.com' debug_output def initialize(email, password) @email = email get_response = self.class.get('/account/login') get_response_cookie = parse_cookie(get_response.headers['Set-Cookie']) post_response = self.class.post( '/account/login', body: { login_email_address: email, login_password: password }, headers: {'Cookie' => get_response_cookie.to_cookie_string } ) @cookie = parse_cookie(post_response.headers['Set-Cookie']) end def account_settings self.class.get('/account/edit', headers: { 'Cookie' => @cookie.to_cookie_string }) end def logged_in? account_settings.include? "You're logged in as #{@email}" end private def parse_cookie(resp) cookie_hash = CookieHash.new resp.get_fields('Set-Cookie').each { |c| cookie_hash.add_cookies(c) } cookie_hash end end tripit = TripIt.new('email', 'password') puts "Logged in: #{tripit.logged_in?}" httparty-0.15.6/examples/stackexchange.rb0000644000004100000410000000102513145325011020456 0ustar www-datawww-datadir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') require 'pp' class StackExchange include HTTParty base_uri 'api.stackexchange.com' def initialize(service, page) @options = { query: { site: service, page: page } } end def questions self.class.get("/2.2/questions", @options) end def users self.class.get("/2.2/users", @options) end end stack_exchange = StackExchange.new("stackoverflow", 1) pp stack_exchange.questions pp stack_exchange.users httparty-0.15.6/examples/aaws.rb0000644000004100000410000000201313145325011016577 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.15.6/examples/google.rb0000644000004100000410000000060213145325011017122 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.15.6/examples/crack.rb0000644000004100000410000000065413145325011016740 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 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.15.6/examples/delicious.rb0000644000004100000410000000222313145325011017627 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.15.6/examples/logging.rb0000644000004100000410000000177213145325011017305 0ustar www-datawww-datadir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') require 'logger' require 'pp' my_logger = Logger.new "httparty.log" my_logger.info "Logging can be used on the main HTTParty class. It logs redirects too." HTTParty.get "http://google.com", logger: my_logger my_logger.info '*' * 70 my_logger.info "It can be used also on a custom class." class Google include HTTParty logger ::Logger.new "httparty.log" end Google.get "http://google.com" my_logger.info '*' * 70 my_logger.info "The default formatter is :apache. The :curl formatter can also be used." my_logger.info "You can tell which method to call on the logger too. It is info by default." HTTParty.get "http://google.com", logger: my_logger, log_level: :debug, log_format: :curl my_logger.info '*' * 70 my_logger.info "These configs are also available on custom classes." class Google include HTTParty logger ::Logger.new("httparty.log"), :debug, :curl end Google.get "http://google.com" httparty-0.15.6/examples/rubyurl.rb0000644000004100000410000000053113145325011017353 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.15.6/examples/twitter.rb0000644000004100000410000000172013145325011017352 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.15.6/examples/nokogiri_html_parser.rb0000644000004100000410000000053613145325011022075 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 def html Nokogiri::HTML(body) end end class Page include HTTParty parser HtmlParserIncluded end pp Page.get('http://www.google.com') httparty-0.15.6/examples/stream_download.rb0000644000004100000410000000102713145325011021032 0ustar www-datawww-datadir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) require File.join(dir, 'httparty') require 'pp' # download file linux-4.6.4.tar.xz without using the memory response = nil filename = "linux-4.6.4.tar.xz" url = "https://cdn.kernel.org/pub/linux/kernel/v4.x/#{filename}" File.open(filename, "w") do |file| response = HTTParty.get(url, stream_body: true) do |fragment| print "." file.write(fragment) end end puts pp "Success: #{response.success?}" pp File.stat(filename).inspect File.unlink(filename) httparty-0.15.6/examples/headers_and_user_agents.rb0000644000004100000410000000047513145325011022512 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.15.6/examples/basic.rb0000644000004100000410000000144713145325011016737 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('https://api.stackexchange.com/2.2/questions?site=stackoverflow') puts response.body, response.code, response.message, response.headers.inspect # 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.15.6/examples/README.md0000644000004100000410000000414313145325011016604 0ustar www-datawww-data## Examples * [Amazon Book Search](aaws.rb) * Httparty included into poro class * Uses `get` requests * Transforms query params to uppercased params * [Google Search](google.rb) * Httparty included into poro class * Uses `get` requests * [Crack Custom Parser](crack.rb) * Creates a custom parser for XML using crack gem * Uses `get` request * [Create HTML Nokogiri parser](nokogiri_html_parser.rb) * Adds Html as a format * passed the body of request to Nokogiri * [More Custom Parsers](custom_parsers.rb) * Create an additional parser for atom or make it the ONLY parser * [Basic Auth, Delicious](delicious.rb) * Basic Auth, shows how to merge those into options * Uses `get` requests * [Passing Headers, User Agent](headers_and_user_agents.rb) * Use the class method of Httparty * Pass the User-Agent in the headers * Uses `get` requests * [Basic Post Request](basic.rb) * Httparty included into poro class * Uses `post` requests * [Access Rubyurl Shortener](rubyurl.rb) * Httparty included into poro class * Uses `post` requests * [Add a custom log file](logging.rb) * create a log file and have httparty log requests * [Accessing StackExchange](stackexchange.rb) * Httparty included into poro class * Creates methods for different endpoints * Uses `get` requests * [Accessing Tripit](tripit_sign_in.rb) * Httparty included into poro class * Example of using `debug_output` to see headers/urls passed * Getting and using Cookies * Uses `get` requests * [Accessing Twitter](twitter.rb) * Httparty included into poro class * Basic Auth * Loads settings from a config file * Uses `get` requests * Uses `post` requests * [Accessing WhoIsMyRep](whoismyrep.rb) * Httparty included into poro class * Uses `get` requests * Two ways to pass params to get, inline on the url or in query hash * [Rescue Json Error](rescue_json.rb) * Rescue errors due to parsing response * [Download file using stream mode](stream_download.rb) * Uses `get` requests * Uses `stream_body` mode * Download file without using the memory httparty-0.15.6/examples/whoismyrep.rb0000644000004100000410000000047113145325011020060 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.15.6/.rubocop_todo.yml0000644000004100000410000000536213145325011017012 0ustar www-datawww-data# This configuration was generated by `rubocop --auto-gen-config` # on 2015-04-24 07:22:28 +0200 using RuboCop version 0.30.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. # Offense count: 33 Lint/AmbiguousRegexpLiteral: Enabled: false # Offense count: 1 # Configuration parameters: AlignWith, SupportedStyles. Lint/EndAlignment: Enabled: false # Offense count: 1 Lint/HandleExceptions: Enabled: false # Offense count: 5 Lint/UselessAssignment: Enabled: false # Offense count: 23 Metrics/AbcSize: Max: 86 # Offense count: 1 # Configuration parameters: CountComments. Metrics/ClassLength: Max: 285 # Offense count: 8 Metrics/CyclomaticComplexity: Max: 17 # Offense count: 332 # Configuration parameters: AllowURI, URISchemes. Metrics/LineLength: Max: 266 # Offense count: 17 # Configuration parameters: CountComments. Metrics/MethodLength: Max: 39 # Offense count: 8 Metrics/PerceivedComplexity: Max: 20 # Offense count: 1 Style/AccessorMethodName: Enabled: false # Offense count: 1 Style/AsciiComments: Enabled: false # Offense count: 14 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, ProceduralMethods, FunctionalMethods, IgnoredMethods. Style/BlockDelimiters: Enabled: false # Offense count: 2 Style/CaseEquality: Enabled: false # Offense count: 3 # Configuration parameters: IndentWhenRelativeTo, SupportedStyles, IndentOneStep. Style/CaseIndentation: Enabled: false # Offense count: 4 # Configuration parameters: EnforcedStyle, SupportedStyles. Style/ClassAndModuleChildren: Enabled: false # Offense count: 7 Style/ConstantName: Enabled: false # Offense count: 2 Style/EachWithObject: Enabled: false # Offense count: 2 # Cop supports --auto-correct. Style/ElseAlignment: Enabled: false # Offense count: 3 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. Style/FirstParameterIndentation: Enabled: false # Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, UseHashRocketsWithSymbolValues. Style/HashSyntax: Enabled: false # Offense count: 7 # Cop supports --auto-correct. # Configuration parameters: MaxLineLength. Style/IfUnlessModifier: Enabled: false # Offense count: 11 # Cop supports --auto-correct. Style/Lambda: Enabled: false # Offense count: 1 # Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles. Style/Next: Enabled: false # Offense count: 2 # Configuration parameters: EnforcedStyle, SupportedStyles. Style/RaiseArgs: Enabled: false httparty-0.15.6/script/0000755000004100000410000000000013145325011015011 5ustar www-datawww-datahttparty-0.15.6/script/release0000755000004100000410000000155113145325011016361 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.15.6/features/0000755000004100000410000000000013145325011015323 5ustar www-datawww-datahttparty-0.15.6/features/supports_timeout_option.feature0000644000004100000410000000116113145325011023734 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.15.6/features/handles_compressed_responses.feature0000644000004100000410000000222413145325011024643 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.15.6/features/basic_authentication.feature0000644000004100000410000000167513145325011023071 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.15.6/features/steps/0000755000004100000410000000000013145325011016461 5ustar www-datawww-datahttparty-0.15.6/features/steps/httparty_response_steps.rb0000644000004100000410000000372613145325011024031 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| expect(@response_from_httparty.parsed_response).to be_a(Object.const_get(class_string)) end Then /the return value should match '(.*)'/ do |expected_text| expect(@response_from_httparty.parsed_response).to eq(expected_text) end Then /it should return a Hash equaling:/ do |hash_table| expect(@response_from_httparty.parsed_response).to be_a(Hash) expect(@response_from_httparty.keys.length).to eq(hash_table.rows.length) hash_table.hashes.each do |pair| key, value = pair["key"], pair["value"] expect(@response_from_httparty.keys).to include(key) expect(@response_from_httparty[key]).to eq(value) end end Then /it should return an Array equaling:/ do |array| expect(@response_from_httparty.parsed_response).to be_a(Array) expect(@response_from_httparty.parsed_response).to eq(array.raw) end Then /it should return a response with a (\d+) response code/ do |code| expect(@response_from_httparty.code).to eq(code.to_i) end Then /it should return a response with a (.*) content\-encoding$/ do |content_type| expect(@response_from_httparty.headers['content-encoding']).to eq('gzip') end Then /it should return a response with a blank body$/ do expect(@response_from_httparty.body).to be_nil end Then /it should raise (?:an|a) ([\w:]+) exception/ do |exception| expect(@exception_from_httparty).to_not be_nil expect(@exception_from_httparty).to be_a constantize(exception) end Then /it should not raise (?:an|a) ([\w:]+) exception/ do |exception| expect(@exception_from_httparty).to be_nil end httparty-0.15.6/features/steps/mongrel_helper.rb0000644000004100000410000000660013145325011022012 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 module DigestAuthenticationUsingMD5Sess NONCE = 'nonce' REALM = 'testrealm@host.com' QOP = 'auth,auth-int' def self.extended(base) base.custom_headers["WWW-Authenticate"] = %(Digest realm="#{REALM}",qop="#{QOP}",algorithm="MD5-sess",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 md5(str) Digest::MD5.hexdigest(str) end def authorized?(request) auth = request.params["HTTP_AUTHORIZATION"] params = {} auth.to_s.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }.gsub(/(\w+)=([^,]*)/) { params[$1] = $2 } a1a = [@username,REALM,@password].join(':') a1 = [md5(a1a),NONCE,params['cnonce'] ].join(':') a2 = [ request.params["REQUEST_METHOD"], request.params["REQUEST_URI"] ] .join(':') expected_response = md5( [md5(a1), NONCE, params['nc'], params['cnonce'], QOP, md5(a2)].join(':') ) expected_response == params['response'] 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.15.6/features/steps/remote_service_steps.rb0000644000004100000410000000535013145325011023242 0ustar www-datawww-dataGiven /a remote service that returns '(.*)'/ do |response_body| @handler = BasicMongrelHandler.new step "the response from the service has a body of '#{response_body}'" end Given /^a remote service that returns:$/ do |response_body| @handler = BasicMongrelHandler.new @handler.response_body = 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+) (.*) to generate a response$/ do |time, unit| time = time.to_i time *= 60 if unit =~ /minute/ @server_response_time = time @handler.preprocessor = proc { sleep time } end Given /^a remote deflate service$/ do @handler = DeflateHandler.new end Given /^a remote deflate service on port '(\d+)'/ do |port| run_server(port) @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 is protected by MD5-sess Digest Authentication/ do @handler.extend DigestAuthenticationUsingMD5Sess end Given /that service requires the username '(.*)' with the password '(.*)'/ do |username, password| @handler.username = username @handler.password = password end # customize aruba cucumber step Then /^the output should contain '(.*)'$/ do |expected| expect(all_commands.map(&:output).join("\n")).to match_output_string(expected) end Given /a restricted page at '(.*)'/ do |url| steps " 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.15.6/features/steps/env.rb0000644000004100000410000000075213145325011017602 0ustar www-datawww-datarequire 'mongrel' require './lib/httparty' require 'rspec/expectations' require 'aruba/cucumber' def run_server(port) @host_and_port = "0.0.0.0:#{port}" @server = Mongrel::HttpServer.new("0.0.0.0", port) @server.run @request_options = {} end def new_port server = TCPServer.new('0.0.0.0', nil) port = server.addr[1] ensure server.close end Before('~@command_line') do port = ENV["HTTPARTY_PORT"] || new_port run_server(port) end After do @server.stop if @server end httparty-0.15.6/features/steps/httparty_steps.rb0000644000004100000410000000260713145325011022110 0ustar www-datawww-dataWhen /^I set my HTTParty timeout option to (\d+)$/ do |timeout| @request_options[:timeout] = timeout.to_i end When /^I set my HTTParty open_timeout option to (\d+)$/ do |timeout| @request_options[:open_timeout] = timeout.to_i end When /^I set my HTTParty read_timeout option to (\d+)$/ do |timeout| @request_options[:read_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.15.6/features/command_line.feature0000644000004100000410000001026113145325011021325 0ustar www-datawww-data@command_line Feature: 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 Scenario: Show help information When I run `httparty --help` Then the output should contain "-f, --format [FORMAT]" Scenario: Show current version When I run `httparty --version` Then the output should contain "Version:" And the output should not contain "You need to provide a URL" Scenario: Make a get request Given a remote deflate service on port '4001' And the response from the service has a body of 'GET request' And that service is accessed at the path '/fun' When I run `httparty http://0.0.0.0:4001/fun` Then the output should contain "GET request" Scenario: Make a post request Given a remote deflate service on port '4002' And the response from the service has a body of 'POST request' And that service is accessed at the path '/fun' When I run `httparty http://0.0.0.0:4002/fun --action post --data "a=1&b=2"` Then the output should contain "POST request" Scenario: Make a put request Given a remote deflate service on port '4003' And the response from the service has a body of 'PUT request' And that service is accessed at the path '/fun' When I run `httparty http://0.0.0.0:4003/fun --action put --data "a=1&b=2"` Then the output should contain "PUT request" Scenario: Make a delete request Given a remote deflate service on port '4004' And the response from the service has a body of 'DELETE request' And that service is accessed at the path '/fun' When I run `httparty http://0.0.0.0:4004/fun --action delete` Then the output should contain "DELETE request" Scenario: Set a verbose mode Given a remote deflate service on port '4005' And the response from the service has a body of 'Some request' And that service is accessed at the path '/fun' When I run `httparty http://0.0.0.0:4005/fun --verbose` Then the output should contain "content-length" Scenario: Use service with basic authentication Given a remote deflate service on port '4006' And the response from the service has a body of 'Successfull authentication' And that service is accessed at the path '/fun' And that service is protected by Basic Authentication And that service requires the username 'user' with the password 'pass' When I run `httparty http://0.0.0.0:4006/fun --user 'user:pass'` Then the output should contain "Successfull authentication" Scenario: Get response in plain format Given a remote deflate service on port '4007' And the response from the service has a body of 'Some request' And that service is accessed at the path '/fun' When I run `httparty http://0.0.0.0:4007/fun --format plain` Then the output should contain "Some request" Scenario: Get response in json format Given a remote deflate service on port '4008' 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 run `httparty http://0.0.0.0:4008/service.json --format json` Then the output should contain '"jennings": "waylon"' Scenario: Get response in xml format Given a remote deflate service on port '4009' 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 run `httparty http://0.0.0.0:4009/service.xml --format xml` Then the output should contain "" Scenario: Get response in csv format Given a remote deflate service on port '4010' Given a remote service that returns: """ "Last Name","Name" "jennings","waylon" "cash","johnny" """ And that service is accessed at the path '/service.csv' And the response from the service has a Content-Type of 'application/csv' When I run `httparty http://0.0.0.0:4010/service.csv --format csv` Then the output should contain '["Last Name", "Name"]' httparty-0.15.6/features/supports_redirection.feature0000644000004100000410000000165413145325011023174 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.15.6/features/deals_with_http_error_codes.feature0000644000004100000410000000224013145325011024446 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.15.6/features/digest_authentication.feature0000644000004100000410000000311413145325011023255 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' Scenario: Passing proper credentials to a page requiring Digest Authentication using md5-sess algorithm Given a remote service that returns 'Digest Authenticated Page Using MD5-sess' And that service is accessed at the path '/digest_auth.html' And that service is protected by MD5-sess 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 Using MD5-sess' httparty-0.15.6/features/handles_multiple_formats.feature0000644000004100000410000000451313145325011023767 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 CSV service Given a remote service that returns: """ "Last Name","Name" "jennings","waylon" "cash","johnny" """ And that service is accessed at the path '/service.csv' And the response from the service has a Content-Type of 'application/csv' When I call HTTParty#get with '/service.csv' Then it should return an Array equaling: | Last Name | Name | | jennings | waylon | | cash | johnny | 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.15.6/features/supports_read_timeout_option.feature0000644000004100000410000000120013145325011024721 0ustar www-datawww-dataFeature: Supports the read timeout option In order to handle inappropriately slow response times As a developer I want my request to raise an exception after my specified read_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 read_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.15.6/MIT-LICENSE0000644000004100000410000000204113145325011015136 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.15.6/Changelog.md0000644000004100000410000004351413145325011015725 0ustar www-datawww-data## 0.15.5 Fixed * [Use non-destructive gsub](https://github.com/jnunemaker/httparty/pull/540) ## 0.15.4 Fixed * Prevent gsub errors with different encodings. * Prevent passing nil to encode_body. ## 0.15.3 Fixed * [Fix processing nil body for HEAD requests](https://github.com/jnunemaker/httparty/pull/530). * Add missing require to headers.rb (33439a8). ## 0.15.2 Fixed * Remove symlink from specs. It was reportedly still getting bundled with gem. ## 0.15.1 Fixed * Stop including test files in gem. Fixes installation issues on windows due to symlink in spec dir. ## 0.15.0 Breaking Changes * require Ruby >= 2.0.0 Fixed * [fix numerous bugs](https://github.com/jnunemaker/httparty/pull/513) * [handle utf-8 bom for json parsing](https://github.com/jnunemaker/httparty/pull/520) * [do not overwrite default headers unless specified](https://github.com/jnunemaker/httparty/pull/518) ## 0.14.0 Breaking Changes * None Added * [added status predicate methods to Response#respond_to?](https://github.com/jnunemaker/httparty/pull/482) * [support for MKCOL method](https://github.com/jnunemaker/httparty/pull/465) * one fewer dependency: [remove json gem from gemspec](https://github.com/jnunemaker/httparty/pull/464) * [optional raising exception on certain status codes](https://github.com/jnunemaker/httparty/pull/455) Fixed * [allow empty array to be used as param](https://github.com/jnunemaker/httparty/pull/477) * [stop mutating cookie hash](https://github.com/jnunemaker/httparty/pull/460) ## 0.13.7 aka "party not as hard" * remove post install emoji as it caused installation issues for some people ## 0.13.6 * avoid calling String#strip on invalid Strings * preserve request method on 307 and 308 redirects * output version with --version for command line bin * maintain head request method across redirects by default * add support for RFC2617 MD5-sess algorithm type * add party popper emoji to post install message ## 0.13.5 * allow setting a custom URI adapter ## 0.13.4 * correct redirect url for redirect paths without leading slash * remove core_extensions.rb as backwards compat for ruby 1.8 not needed * replace URI.encode with ERB::Util.url_encode * allow the response to be tapped ## 0.13.3 * minor improvement * added option to allow for streaming large files without loading them into memory (672cdae) ## 0.13.2 * minor improvement * [Set correct path on redirect to filename](https://github.com/jnunemaker/httparty/pull/337) * ensure logger works with curl format ## 0.13.1 2014-04-08 * new * [Added ability to specify a body_stream in HttpRequest](https://github.com/jnunemaker/httparty/pull/275) * [Added read_timeout and open_timeout options](https://github.com/jnunemaker/httparty/pull/278) * change * [Initialize HTTParty requests with an URI object and a String](https://github.com/jnunemaker/httparty/pull/274) * minor improvement * [Add stackexchange API example](https://github.com/jnunemaker/httparty/pull/280) ## 0.13.0 2014-02-14 * new * [Add CSV support](https://github.com/jnunemaker/httparty/pull/269) * [Allows PKCS12 client certificates](https://github.com/jnunemaker/httparty/pull/246) * bug fix * [Digest auth no longer fails when multiple headers are sent by the server](https://github.com/jnunemaker/httparty/pull/272) * [Use 'Basement.copy' when calling 'HTTParty.copy'](https://github.com/jnunemaker/httparty/pull/268) * [No longer appends ampersand when queries are embedded in paths](https://github.com/jnunemaker/httparty/pull/252) * change * [Merge - instead of overwrite - default headers with request provided headers](https://github.com/jnunemaker/httparty/pull/270) * [Modernize respond_to implementations to support second param](https://github.com/jnunemaker/httparty/pull/264) * [Sort query parameters by key before processing](https://github.com/jnunemaker/httparty/pull/245) * minor improvement * [Add HTTParty::Error base class](https://github.com/jnunemaker/httparty/pull/260) ## 0.12.0 2013-10-10 * new * [Added initial logging support](https://github.com/jnunemaker/httparty/pull/243) * [Add support for local host and port binding](https://github.com/jnunemaker/httparty/pull/238) * [content_type_charset_support](https://github.com/jnunemaker/httparty/commit/82e351f0904e8ecc856015ff2854698a2ca47fbc) * bug fix * [No longer attempt to decompress the body on HEAD requests](https://github.com/jnunemaker/httparty/commit/f2b8cc3d49e0e9363d7054b14f30c340d7b8e7f1) * [Adding java check in aliasing of multiple choices](https://github.com/jnunemaker/httparty/pull/204/commits) * change * [MIME-type files of javascript are returned as a string instead of JSON](https://github.com/jnunemaker/httparty/pull/239) * [Made SSL connections use the system certificate store by default](https://github.com/jnunemaker/httparty/pull/226) * [Do not pass proxy options to Net::HTTP connection if not specified](https://github.com/jnunemaker/httparty/pull/222) * [Replace multi_json with stdlib json](https://github.com/jnunemaker/httparty/pull/214) * [Require Ruby >= 1.9.3] * [Response returns array of returned cookie strings](https://github.com/jnunemaker/httparty/pull/218) * [Allow '=' within value of a cookie] * minor improvements * [Improve documentation of ssl_ca_file, ssl_ca_path](https://github.com/jnunemaker/httparty/pull/223) * [Fix example URLs](https://github.com/jnunemaker/httparty/pull/232) ## 0.11.0 2013-04-10 * new * [Add COPY http request handling](https://github.com/jnunemaker/httparty/pull/190) * [Ruby 2.0 tests](https://github.com/jnunemaker/httparty/pull/194) * [Ruby >= 2.0.0 support both multiple_choice? and multiple_choices?] * bug fix * [Maintain blocks passed to 'perform' in redirects](https://github.com/jnunemaker/httparty/pull/191) * [Fixed nc value being quoted, this was against spec](https://github.com/jnunemaker/httparty/pull/196) * [Request#uri no longer duplicates non-relative-path params](https://github.com/jnunemaker/httparty/pull/189) * change * [Client-side-only cookie attributes are removed: case-insensitive](https://github.com/jnunemaker/httparty/pull/188) ## 0.10.2 2013-01-26 * bug fix * [hash_conversions misnamed variable](https://github.com/jnunemaker/httparty/pull/187) ## 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.15.6/spec/0000755000004100000410000000000013145325011014437 5ustar www-datawww-datahttparty-0.15.6/spec/spec_helper.rb0000644000004100000410000000212313145325011017253 0ustar www-datawww-datarequire "simplecov" SimpleCov.start require "httparty" require 'webmock/rspec' def file_fixture(filename) open(File.join(File.dirname(__FILE__), 'fixtures', "#{filename}")).read end Dir[File.expand_path(File.join(File.dirname(__FILE__), 'support', '**', '*.rb'))].each {|f| require f} RSpec.configure do |config| config.include HTTParty::StubResponse config.include HTTParty::SSLTestHelper config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true end config.mock_with :rspec do |mocks| mocks.verify_partial_doubles = false end config.filter_run :focus config.run_all_when_everything_filtered = true config.disable_monkey_patching! config.warnings = true if config.files_to_run.one? config.default_formatter = 'doc' end config.profile_examples = 10 config.order = :random Kernel.srand config.seed end RSpec::Matchers.define :use_ssl do match(&:use_ssl?) end RSpec::Matchers.define :use_cert_store do |cert_store| match do |connection| connection.cert_store == cert_store end end httparty-0.15.6/spec/fixtures/0000755000004100000410000000000013145325011016310 5ustar www-datawww-datahttparty-0.15.6/spec/fixtures/google.html0000644000004100000410000001335413145325011020460 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.15.6/spec/fixtures/twitter.xml0000644000004100000410000004167413145325011020550 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.15.6/spec/fixtures/ssl/0000755000004100000410000000000013145325011017111 5ustar www-datawww-datahttparty-0.15.6/spec/fixtures/ssl/generated/0000755000004100000410000000000013145325011021047 5ustar www-datawww-datahttparty-0.15.6/spec/fixtures/ssl/generated/bogushost.crt0000644000004100000410000000137113145325011023600 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.15.6/spec/fixtures/ssl/generated/ca.crt0000644000004100000410000000161013145325011022142 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.15.6/spec/fixtures/ssl/generated/ca.key0000644000004100000410000000157313145325011022152 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.15.6/spec/fixtures/ssl/generated/selfsigned.crt0000644000004100000410000000143213145325011023704 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.15.6/spec/fixtures/ssl/generated/server.crt0000644000004100000410000000140113145325011023063 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.15.6/spec/fixtures/ssl/generated/server.key0000644000004100000410000000156713145325011023100 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.15.6/spec/fixtures/ssl/openssl-exts.cnf0000644000004100000410000000033413145325011022245 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.15.6/spec/fixtures/ssl/generate.sh0000755000004100000410000000241213145325011021241 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.15.6/spec/fixtures/twitter.csv0000644000004100000410000000041613145325011020530 0ustar www-datawww-data"name","url","id","description","protected","screen_name","followers_count","profile_image_url","location" "Magic 8 Bot",,"17656026","ask me a question","false","magic8bot","90","http://s3.amazonaws.com/twitter_production/profile_images/65565851/8ball_large_normal.jpg",httparty-0.15.6/spec/fixtures/twitter.json0000644000004100000410000003131213145325011020705 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.15.6/spec/fixtures/empty.xml0000644000004100000410000000000013145325011020156 0ustar www-datawww-datahttparty-0.15.6/spec/fixtures/delicious.xml0000644000004100000410000001633513145325011021022 0ustar www-datawww-data httparty-0.15.6/spec/fixtures/undefined_method_add_node_for_nil.xml0000644000004100000410000000024113145325011025655 0ustar www-datawww-data httparty-0.15.6/spec/httparty_spec.rb0000644000004100000410000007123313145325011017663 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper')) RSpec.describe HTTParty do before(:each) do @klass = Class.new @klass.instance_eval { include HTTParty } end describe "pem" do it 'should set the pem content' do @klass.pem 'PEM-CONTENT' expect(@klass.default_options[:pem]).to eq('PEM-CONTENT') end it "should set the password to nil if it's not provided" do @klass.pem 'PEM-CONTENT' expect(@klass.default_options[:pem_password]).to be_nil end it 'should set the password' do @klass.pem 'PEM-CONTENT', 'PASSWORD' expect(@klass.default_options[:pem_password]).to eq('PASSWORD') end end describe "pkcs12" do it 'should set the p12 content' do @klass.pkcs12 'P12-CONTENT', 'PASSWORD' expect(@klass.default_options[:p12]).to eq('P12-CONTENT') end it 'should set the password' do @klass.pkcs12 'P12-CONTENT', 'PASSWORD' expect(@klass.default_options[:p12_password]).to eq('PASSWORD') end end describe 'ssl_version' do it 'should set the ssl_version content' do @klass.ssl_version :SSLv3 expect(@klass.default_options[:ssl_version]).to eq(:SSLv3) end end describe 'ciphers' do it 'should set the ciphers content' do expect(@klass.default_options[:ciphers]).to be_nil @klass.ciphers 'RC4-SHA' expect(@klass.default_options[:ciphers]).to eq('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 expect(options[:http_proxyaddr]).to eq('proxy.foo.com') expect(options[:http_proxyport]).to eq(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 expect(options[:http_proxyuser]).to eq('user') expect(options[:http_proxypass]).to eq('pass') end end describe "base uri" do before(:each) do @klass.base_uri('api.foo.com/v1') end it "should have reader" do expect(@klass.base_uri).to eq('http://api.foo.com/v1') end it 'should have writer' do @klass.base_uri('http://api.foobar.com') expect(@klass.base_uri).to eq('http://api.foobar.com') end it 'should not modify the parameter during assignment' do uri = 'http://api.foobar.com' @klass.base_uri(uri) expect(uri).to eq('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 expect(@klass.default_options[:query_string_normalizer]).to eq(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') expect(uri).to eq('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') expect(uri).to eq('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') expect(uri).to eq('https://api.foo.com/v1:443') end it 'should not modify the parameter' do uri = 'http://api.foobar.com' HTTParty.normalize_base_uri(uri) expect(uri).to eq('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') expect(uri).to eq('http://api.foo.com:4430/v1') end end describe "headers" do def expect_headers(header = {}) expect(HTTParty::Request).to receive(:new) \ .with(anything, anything, hash_including({ headers: header })) \ .and_return(double("mock response", perform: nil)) end it "does not modify default_options when no arguments are passed" do @klass.headers expect(@klass.default_options[:headers]).to eq(nil) end it "should default to empty hash" do expect(@klass.headers).to eq({}) end it "should be able to be updated" do init_headers = {foo: 'bar', baz: 'spax'} @klass.headers init_headers expect(@klass.headers).to eq(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 "merges class headers with request headers" do expect_headers(baz: 'spax', foo: 'bar') @klass.headers(foo: 'bar') @klass.get('', headers: {baz: 'spax'}) end it 'overrides class headers with request headers' do expect_headers(baz: 'spax', foo: 'baz') @klass.headers(foo: 'bar') @klass.get('', headers: {baz: 'spax', foo: 'baz'}) 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 'doesnt modify default headers' do expect(@klass.headers).to eq({}) expect_headers('cookie' => 'type=snickerdoodle') @klass.get('', cookies: {type: 'snickerdoodle'}) expect(@klass.headers).to eq({}) 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) expect(HTTParty::Request).to receive(:new) \ .with(anything, anything, hash_including({ headers: { "cookie" => s } })) \ .and_return(double("mock response", perform: nil)) end it "should not be in the headers by default" do allow(HTTParty::Request).to receive(:new).and_return(double(nil, perform: nil)) @klass.get("") expect(@klass.headers.keys).not_to include("cookie") end it "should raise an ArgumentError if passed a non-Hash" do expect do @klass.cookies("nonsense") end.to 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 expect(@klass.default_params).to eq({}) end it "should be able to be updated" do new_defaults = {foo: 'bar', baz: 'spax'} @klass.default_params new_defaults expect(@klass.default_params).to eq(new_defaults) end end describe "default timeout" do it "should default to nil" do expect(@klass.default_options[:timeout]).to eq(nil) end it "should support updating" do @klass.default_timeout 10 expect(@klass.default_options[:timeout]).to eq(10) end it "should support floats" do @klass.default_timeout 0.5 expect(@klass.default_options[:timeout]).to eq(0.5) end end describe "debug_output" do it "stores the given stream as a default_option" do @klass.debug_output $stdout expect(@klass.default_options[:debug_output]).to eq($stdout) end it "stores the $stderr stream by default" do @klass.debug_output expect(@klass.default_options[:debug_output]).to eq($stderr) end end describe "basic http authentication" do it "should work" do @klass.basic_auth 'foobar', 'secret' expect(@klass.default_options[:basic_auth]).to eq({username: 'foobar', password: 'secret'}) end end describe "digest http authentication" do it "should work" do @klass.digest_auth 'foobar', 'secret' expect(@klass.default_options[:digest_auth]).to eq({username: 'foobar', password: 'secret'}) end end describe "parser" do class CustomParser def self.parse(body) {sexy: true} end end let(:parser) do proc { |data, format| CustomParser.parse(data) } end it "should set parser options" do @klass.parser parser expect(@klass.default_options[:parser]).to eq(parser) end it "should be able parse response with custom parser" do @klass.parser parser stub_request(:get, 'http://twitter.com/statuses/public_timeline.xml') .to_return(body: 'tweets') custom_parsed_response = @klass.get('http://twitter.com/statuses/public_timeline.xml') expect(custom_parsed_response[:sexy]).to eq(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 end end describe "uri_adapter" do require 'forwardable' class CustomURIAdaptor extend Forwardable def_delegators :@uri, :userinfo, :relative?, :query, :query=, :scheme, :path, :host, :port def initialize uri @uri = uri end def self.parse uri new URI.parse uri end end let(:uri_adapter) { CustomURIAdaptor } it "should set the uri_adapter" do @klass.uri_adapter uri_adapter expect(@klass.default_options[:uri_adapter]).to be uri_adapter end it "should raise an ArgumentError if uri_adapter doesn't implement parse method" do expect do @klass.uri_adapter double() end.to raise_error(ArgumentError) end it "should process a request with a uri instance parsed from the uri_adapter" do uri = 'http://foo.com/bar' stub_request(:get, uri).to_return(body: 'stuff') @klass.uri_adapter uri_adapter expect(@klass.get(uri).parsed_response).to eq('stuff') end end describe "connection_adapter" do let(:uri) { 'http://google.com/api.json' } let(:connection_adapter) { double('CustomConnectionAdapter') } it "should set the connection_adapter" do @klass.connection_adapter connection_adapter expect(@klass.default_options[:connection_adapter]).to be connection_adapter end it "should set the connection_adapter_options when provided" do options = {foo: :bar} @klass.connection_adapter connection_adapter, options expect(@klass.default_options[:connection_adapter_options]).to be options end it "should not set the connection_adapter_options when not provided" do @klass.connection_adapter connection_adapter expect(@klass.default_options[:connection_adapter_options]).to be_nil end it "should process a request with a connection from the adapter" do connection_adapter_options = {foo: :bar} expect(connection_adapter).to receive(:call) { |u, o| expect(o[:connection_adapter_options]).to eq(connection_adapter_options) HTTParty::ConnectionAdapter.call(u, o) }.with(URI.parse(uri), kind_of(Hash)) stub_request(:get, uri).to_return(body: 'stuff') @klass.connection_adapter connection_adapter, connection_adapter_options expect(@klass.get(uri).parsed_response).to eq('stuff') end end describe "format" do it "should allow xml" do @klass.format :xml expect(@klass.default_options[:format]).to eq(:xml) end it "should allow csv" do @klass.format :csv expect(@klass.default_options[:format]).to eq(:csv) end it "should allow json" do @klass.format :json expect(@klass.default_options[:format]).to eq(:json) end it "should allow plain" do @klass.format :plain expect(@klass.default_options[:format]).to eq(:plain) end it 'should not allow funky format' do expect do @klass.format :foobar end.to raise_error(HTTParty::UnsupportedFormat) end it 'should only print each format once with an exception' do expect do @klass.format :foobar end.to raise_error(HTTParty::UnsupportedFormat, "':foobar' Must be one of: csv, html, json, plain, xml") end it 'sets the default parser' do expect(@klass.default_options[:parser]).to be_nil @klass.format :json expect(@klass.default_options[:parser]).to eq(HTTParty::Parser) end it 'does not reset parser to the default parser' do my_parser = lambda {} @klass.parser my_parser @klass.format :json expect(@klass.parser).to eq(my_parser) end end describe "#no_follow" do it "sets no_follow to false by default" do @klass.no_follow expect(@klass.default_options[:no_follow]).to be_falsey end it "sets the no_follow option to true" do @klass.no_follow true expect(@klass.default_options[:no_follow]).to be_truthy end end describe "#maintain_method_across_redirects" do it "sets maintain_method_across_redirects to true by default" do @klass.maintain_method_across_redirects expect(@klass.default_options[:maintain_method_across_redirects]).to be_truthy end it "sets the maintain_method_across_redirects option to false" do @klass.maintain_method_across_redirects false expect(@klass.default_options[:maintain_method_across_redirects]).to be_falsey end end describe "#resend_on_redirect" do it "sets resend_on_redirect to true by default" do @klass.resend_on_redirect expect(@klass.default_options[:resend_on_redirect]).to be_truthy end it "sets resend_on_redirect option to false" do @klass.resend_on_redirect false expect(@klass.default_options[:resend_on_redirect]).to be_falsey end end describe ".follow_redirects" do it "sets follow redirects to true by default" do @klass.follow_redirects expect(@klass.default_options[:follow_redirects]).to be_truthy end it "sets the follow_redirects option to false" do @klass.follow_redirects false expect(@klass.default_options[:follow_redirects]).to be_falsey end end describe ".query_string_normalizer" do it "sets the query_string_normalizer option" do normalizer = proc {} @klass.query_string_normalizer normalizer expect(@klass.default_options[:query_string_normalizer]).to eq(normalizer) end end describe ".raise_on" do context 'when parameters is an array' do it 'sets raise_on option' do @klass.raise_on [500, 404] expect(@klass.default_options[:raise_on]).to contain_exactly(404, 500) end end context 'when parameters is a fixnum' do it 'sets raise_on option' do @klass.raise_on 404 expect(@klass.default_options[:raise_on]).to contain_exactly(404) end 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' allow(HTTParty::Request).to receive_messages(new: @request) end it "should fail with redirected GET" do expect do @error = @klass.get('/foo', no_follow: true) end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')} end it "should fail with redirected POST" do expect do @klass.post('/foo', no_follow: true) end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')} end it "should fail with redirected PATCH" do expect do @klass.patch('/foo', no_follow: true) end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')} end it "should fail with redirected DELETE" do expect do @klass.delete('/foo', no_follow: true) end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')} end it "should fail with redirected MOVE" do expect do @klass.move('/foo', no_follow: true) end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')} end it "should fail with redirected COPY" do expect do @klass.copy('/foo', no_follow: true) end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')} end it "should fail with redirected PUT" do expect do @klass.put('/foo', no_follow: true) end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')} end it "should fail with redirected HEAD" do expect do @klass.head('/foo', no_follow: true) end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')} end it "should fail with redirected OPTIONS" do expect do @klass.options('/foo', no_follow: true) end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')} end it "should fail with redirected MKCOL" do expect do @klass.mkcol('/foo', no_follow: true) end.to raise_error(HTTParty::RedirectionTooDeep) {|e| expect(e.response.body).to eq('first redirect')} end end describe "head requests should follow redirects requesting HEAD only" do before do allow(HTTParty::Request).to receive(:new). and_return(double("mock response", perform: nil)) end it "should remain HEAD request across redirects, unless specified otherwise" do expect(@klass).to receive(:ensure_method_maintained_across_redirects).with({}) @klass.head('/foo') end end describe "#ensure_method_maintained_across_redirects" do it "should set maintain_method_across_redirects option if unspecified" do options = {} @klass.send(:ensure_method_maintained_across_redirects, options) expect(options[:maintain_method_across_redirects]).to be_truthy end it "should not set maintain_method_across_redirects option if value is present" do options = { maintain_method_across_redirects: false } @klass.send(:ensure_method_maintained_across_redirects, options) expect(options[:maintain_method_across_redirects]).to be_falsey 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 expect(@klass.default_options).to eq({ base_uri: 'http://first.com', default_params: { one: 1 } }) expect(@additional_klass.default_options).to eq({ 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" expect(@child1.default_options).to eq({ default_params: {joe: "alive"} }) expect(@child2.default_options).to eq({ default_params: {joe: "dead"} }) expect(@parent.default_options).to eq({ }) end it "inherits default_options from the superclass" do @parent.basic_auth 'user', 'password' expect(@child1.default_options).to eq({basic_auth: {username: 'user', password: 'password'}}) @child1.basic_auth 'u', 'p' # modifying child1 has no effect on child2 expect(@child2.default_options).to eq({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' expect(@child1.default_options).to eq({basic_auth: {username: 'u', password: 'p'}}) @child1.basic_auth 'email', 'token' expect(@child1.default_options).to eq({basic_auth: {username: 'email', password: 'token'}}) expect(@parent.default_options).to eq({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' expect(@parent.default_options[:headers]).to eq({'Accept' => 'application/json'}) expect(@child1.default_options[:headers]).to eq({'Accept' => 'application/xml'}) end it "works with lambda values" do @child1.default_options[:imaginary_option] = lambda { "This is a new lambda "} expect(@child1.default_options[:imaginary_option]).to 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 expect(@parent.default_options[:imaginary_option].call).to eq(imaginary_option.call) @child1.default_options[:imaginary_option] expect(@child1.default_options[:imaginary_option].call).to eq(imaginary_option.call) expect(@child1.default_options[:imaginary_option]).not_to be_equal imaginary_option end it "inherits default_cookies from the parent class" do @parent.cookies 'type' => 'chocolate_chip' expect(@child1.default_cookies).to eq({"type" => "chocolate_chip"}) @child1.cookies 'type' => 'snickerdoodle' expect(@child1.default_cookies).to eq({"type" => "snickerdoodle"}) expect(@child2.default_cookies).to eq({"type" => "chocolate_chip"}) end it "doesn't modify the parent's default cookies" do @parent.cookies 'type' => 'chocolate_chip' @child1.cookies 'type' => 'snickerdoodle' expect(@child1.default_cookies).to eq({"type" => "snickerdoodle"}) expect(@parent.default_cookies).to eq({"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) expect(child.instance_variable_get(:@grand_parent)).to be_truthy end end describe "#get" do it "should be able to get html" do stub_http_response_with('google.html') expect(HTTParty.get('http://www.google.com').parsed_response).to eq(file_fixture('google.html')) end it "should be able to get chunked html" do chunks = %w(Chunk1 Chunk2 Chunk3 Chunk4) stub_chunked_http_response_with(chunks) expect( HTTParty.get('http://www.google.com') do |fragment| expect(chunks).to include(fragment) end.parsed_response ).to eq(chunks.join) end it "should return an empty body if stream_body option is turned on" do chunks = %w(Chunk1 Chunk2 Chunk3 Chunk4) options = {stream_body: true, format: 'html'} stub_chunked_http_response_with(chunks, options) expect( HTTParty.get('http://www.google.com', options) do |fragment| expect(chunks).to include(fragment) end.parsed_response ).to eq(nil) 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') expect(tweets.size).to eq(20) expect(tweets.first['user']).to eq({ "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') expect(tweets['statuses'].size).to eq(20) expect(tweets['statuses'].first['user']).to eq({ "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 be able parse response type csv automatically" do stub_http_response_with('twitter.csv') profile = HTTParty.get('http://twitter.com/statuses/profile.csv') expect(profile.size).to eq(2) expect(profile[0]).to eq(%w(name url id description protected screen_name followers_count profile_image_url location)) expect(profile[1]).to eq(["Magic 8 Bot", nil, "17656026", "ask me a question", "false", "magic8bot", "90", "http://s3.amazonaws.com/twitter_production/profile_images/65565851/8ball_large_normal.jpg", 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') expect(result.parsed_response).to eq({"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') expect(result).to be_nil end it "should accept http URIs" do stub_http_response_with('google.html') expect do HTTParty.get('http://google.com') end.not_to raise_error end it "should accept https URIs" do stub_http_response_with('google.html') expect do HTTParty.get('https://google.com') end.not_to raise_error end it "should accept webcal URIs" do uri = 'http://google.com/' stub_request(:get, uri).to_return(body: 'stuff') uri = 'webcal://google.com/' expect do HTTParty.get(uri) end.not_to raise_error end it "should raise an InvalidURIError on URIs that can't be parsed at all" do expect do HTTParty.get("It's the one that says 'Bad URI'") end.to raise_error(URI::InvalidURIError) end end end httparty-0.15.6/spec/support/0000755000004100000410000000000013145325011016153 5ustar www-datawww-datahttparty-0.15.6/spec/support/stub_response.rb0000644000004100000410000000336713145325011021404 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") allow(response).to receive(:body).and_return(data) http_request = HTTParty::Request.new(Net::HTTP::Get, 'http://localhost', format: format) allow(http_request).to receive_message_chain(:http, :request).and_return(response) expect(HTTParty::Request).to receive(:new).and_return(http_request) end def stub_chunked_http_response_with(chunks, options = {format: "html"}) response = Net::HTTPResponse.new("1.1", 200, nil) allow(response).to receive(: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', options) allow(http_request).to receive_message_chain(:http, :request).and_yield(response).and_return(response) expect(HTTParty::Request).to receive(:new).and_return(http_request) end def stub_response(body, code = '200') code = code.to_s @request.options[:base_uri] ||= 'http://localhost' unless defined?(@http) && @http @http = Net::HTTP.new('localhost', 80) allow(@request).to receive(:http).and_return(@http) end # CODE_TO_OBJ currently missing 308 if code == '308' response = Net::HTTPRedirection.new("1.1", code, body) else response = Net::HTTPResponse::CODE_TO_OBJ[code].new("1.1", code, body) end allow(response).to receive(:body).and_return(body) allow(@http).to receive(:request).and_return(response) response end end end httparty-0.15.6/spec/support/ssl_test_helper.rb0000644000004100000410000000276713145325011021713 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.15.6/spec/support/ssl_test_server.rb0000644000004100000410000000356113145325011021733 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 = < true}) end it "should fail when no trusted CA list is specified, with a bogus hostname, by default" do expect do ssl_verify_test(nil, nil, "bogushost.crt") end.to 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 expect(ssl_verify_test(nil, nil, "bogushost.crt", verify: false).parsed_response).to eq({'success' => true}) end it "should work when using ssl_ca_file with a self-signed CA" do expect(ssl_verify_test(:ssl_ca_file, "selfsigned.crt", "selfsigned.crt").parsed_response).to eq({'success' => true}) end it "should work when using ssl_ca_file with a certificate authority" do expect(ssl_verify_test(:ssl_ca_file, "ca.crt", "server.crt").parsed_response).to eq({'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 = double(Net::HTTPResponse, :[] => '', body: '', to_hash: {}) allow(http).to receive(:request).and_return(response) expect(Net::HTTP).to receive(:new).with('www.google.com', 443).and_return(http) expect(http).to 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 expect do ssl_verify_test(:ssl_ca_file, "ca.crt", "selfsigned.crt") end.to raise_error(OpenSSL::SSL::SSLError) end it "should fail when using ssl_ca_path and the server uses an unrecognized certificate authority" do expect do ssl_verify_test(:ssl_ca_path, ".", "selfsigned.crt") end.to raise_error(OpenSSL::SSL::SSLError) end it "should fail when using ssl_ca_file and the server uses a bogus hostname" do expect do ssl_verify_test(:ssl_ca_file, "ca.crt", "bogushost.crt") end.to raise_error(OpenSSL::SSL::SSLError) end it "should fail when using ssl_ca_path and the server uses a bogus hostname" do expect do ssl_verify_test(:ssl_ca_path, ".", "bogushost.crt") end.to raise_error(OpenSSL::SSL::SSLError) end end end httparty-0.15.6/spec/httparty/exception_spec.rb0000644000004100000410000000221413145325011021652 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) RSpec.describe HTTParty::Error do subject { described_class } describe '#ancestors' do subject { super().ancestors } it { is_expected.to include(StandardError) } end describe HTTParty::UnsupportedFormat do describe '#ancestors' do subject { super().ancestors } it { is_expected.to include(HTTParty::Error) } end end describe HTTParty::UnsupportedURIScheme do describe '#ancestors' do subject { super().ancestors } it { is_expected.to include(HTTParty::Error) } end end describe HTTParty::ResponseError do describe '#ancestors' do subject { super().ancestors } it { is_expected.to include(HTTParty::Error) } end end describe HTTParty::RedirectionTooDeep do describe '#ancestors' do subject { super().ancestors } it { is_expected.to include(HTTParty::ResponseError) } end end describe HTTParty::DuplicateLocationHeader do describe '#ancestors' do subject { super().ancestors } it { is_expected.to include(HTTParty::ResponseError) } end end end httparty-0.15.6/spec/httparty/net_digest_auth_spec.rb0000644000004100000410000001742513145325011023034 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) RSpec.describe Net::HTTPHeader::DigestAuthenticator do def setup_digest(response) digest = Net::HTTPHeader::DigestAuthenticator.new("Mufasa", "Circle Of Life", "GET", "/dir/index.html", response) allow(digest).to receive(:random).and_return("deadbeef") allow(Digest::MD5).to receive(:hexdigest) { |str| "md5(#{str})" } digest end def authorization_header @digest.authorization_header.join(", ") end def cookie_header @digest.cookie_header end context 'Net::HTTPHeader#digest_auth' do let(:headers) { (Class.new do include Net::HTTPHeader def initialize @header = {} end end).new } let(:response){ (Class.new do include Net::HTTPHeader def initialize @header = {} self['WWW-Authenticate'] = 'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"' end end).new } it 'should set the authorization header' do expect(headers['authorization']).to be_nil headers.digest_auth('user','pass', response) expect(headers['authorization']).to_not be_empty end end context "with a cookie value in the response header" do before do @digest = setup_digest({ 'www-authenticate' => 'Digest realm="myhost@testrealm.com"', 'Set-Cookie' => 'custom-cookie=1234567' }) end it "should set cookie header" do expect(cookie_header).to include('custom-cookie=1234567') end end context "without a cookie value in the response header" do before do @digest = setup_digest({ 'www-authenticate' => 'Digest realm="myhost@testrealm.com"' }) end it "should set empty cookie header array" do expect(cookie_header).to eql [] end 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 expect(authorization_header).to include('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 expect(authorization_header).not_to include("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 expect(authorization_header).to match(/^Digest /) end it "should set username" do expect(authorization_header).to include('username="Mufasa"') end it "should set digest-uri" do expect(authorization_header).to include('uri="/dir/index.html"') end it "should set qop" do expect(authorization_header).to include('qop="auth"') end it "should set cnonce" do expect(authorization_header).to include('cnonce="md5(deadbeef)"') end it "should set nonce-count" do expect(authorization_header).to include("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))" expect(authorization_header).to include(%(response="#{request_digest}")) end end context "when quality of protection (qop) is unquoted" do before do @digest = setup_digest({ 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop=auth' }) end it "should still set qop" do expect(authorization_header).to include('qop="auth"') 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 expect(authorization_header).to match(/^Digest /) end it "should set username" do expect(authorization_header).to include('username="Mufasa"') end it "should set digest-uri" do expect(authorization_header).to include('uri="/dir/index.html"') end it "should not set qop" do expect(authorization_header).not_to include("qop=") end it "should not set cnonce" do expect(authorization_header).not_to include("cnonce=") end it "should not set nonce-count" do expect(authorization_header).not_to include("nc=") end it "should set response" do request_digest = "md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:md5(GET:/dir/index.html))" expect(authorization_header).to include(%(response="#{request_digest}")) end end context "with http basic auth response when net digest auth expected" do it "should not fail" do @digest = setup_digest({ 'www-authenticate' => 'WWW-Authenticate: Basic realm="testrealm.com""' }) expect(authorization_header).to include("Digest") end end context "with multiple authenticate headers" do before do @digest = setup_digest({ 'www-authenticate' => 'NTLM, Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth"' }) end it "should set prefix" do expect(authorization_header).to match(/^Digest /) end it "should set username" do expect(authorization_header).to include('username="Mufasa"') end it "should set digest-uri" do expect(authorization_header).to include('uri="/dir/index.html"') end it "should set qop" do expect(authorization_header).to include('qop="auth"') end it "should set cnonce" do expect(authorization_header).to include('cnonce="md5(deadbeef)"') end it "should set nonce-count" do expect(authorization_header).to include("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))" expect(authorization_header).to include(%(response="#{request_digest}")) end end context "with algorithm specified" do before do @digest = setup_digest({ 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth", algorithm=MD5' }) end it "should recognise algorithm was specified" do expect( @digest.send :algorithm_present? ).to be(true) end it "should set the algorithm header" do expect(authorization_header).to include('algorithm="MD5"') end end context "with md5-sess algorithm specified" do before do @digest = setup_digest({ 'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth", algorithm=MD5-sess' }) end it "should recognise algorithm was specified" do expect( @digest.send :algorithm_present? ).to be(true) end it "should set the algorithm header" do expect(authorization_header).to include('algorithm="MD5-sess"') end it "should set response using md5-sess algorithm" do request_digest = "md5(md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:md5(deadbeef)):NONCE:00000001:md5(deadbeef):auth:md5(GET:/dir/index.html))" expect(authorization_header).to include(%(response="#{request_digest}")) end end end httparty-0.15.6/spec/httparty/parser_spec.rb0000644000004100000410000001367713145325011021167 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) RSpec.describe HTTParty::Parser do describe ".SupportedFormats" do it "returns a hash" do expect(HTTParty::Parser::SupportedFormats).to be_instance_of(Hash) end end describe ".call" do it "generates an HTTParty::Parser instance with the given body and format" do expect(HTTParty::Parser).to receive(:new).with('body', :plain).and_return(double(parse: nil)) HTTParty::Parser.call('body', :plain) end it "calls #parse on the parser" do parser = double('Parser') expect(parser).to receive(:parse) allow(HTTParty::Parser).to receive_messages(new: parser) parser = HTTParty::Parser.call('body', :plain) end end describe ".formats" do it "returns the SupportedFormats constant" do expect(HTTParty::Parser.formats).to eq(HTTParty::Parser::SupportedFormats) end it "returns the SupportedFormats constant for subclasses" do class MyParser < HTTParty::Parser SupportedFormats = {"application/atom+xml" => :atom} end expect(MyParser.formats).to eq({"application/atom+xml" => :atom}) end end describe ".format_from_mimetype" do it "returns a symbol representing the format mimetype" do expect(HTTParty::Parser.format_from_mimetype("text/plain")).to eq(:plain) end it "returns nil when the mimetype is not supported" do expect(HTTParty::Parser.format_from_mimetype("application/atom+xml")).to be_nil end end describe ".supported_formats" do it "returns a unique set of supported formats represented by symbols" do expect(HTTParty::Parser.supported_formats).to eq(HTTParty::Parser::SupportedFormats.values.uniq) end end describe ".supports_format?" do it "returns true for a supported format" do allow(HTTParty::Parser).to receive_messages(supported_formats: [:json]) expect(HTTParty::Parser.supports_format?(:json)).to be_truthy end it "returns false for an unsupported format" do allow(HTTParty::Parser).to receive_messages(supported_formats: []) expect(HTTParty::Parser.supports_format?(:json)).to be_falsey end end describe "#parse" do it "attempts to parse supported formats" do parser = HTTParty::Parser.new('body', :json) allow(parser).to receive_messages(supports_format?: true) expect(parser).to receive(:parse_supported_format) parser.parse end it "returns the unparsed body when the format is unsupported" do parser = HTTParty::Parser.new('body', :json) allow(parser).to receive_messages(supports_format?: false) expect(parser.parse).to eq(parser.body) end it "returns nil for an empty body" do parser = HTTParty::Parser.new('', :json) expect(parser.parse).to be_nil end it "returns nil for a nil body" do parser = HTTParty::Parser.new(nil, :json) expect(parser.parse).to be_nil end it "returns nil for a 'null' body" do parser = HTTParty::Parser.new("null", :json) expect(parser.parse).to be_nil end it "returns nil for a body with spaces only" do parser = HTTParty::Parser.new(" ", :json) expect(parser.parse).to be_nil end it "does not raise exceptions for bodies with invalid encodings" do parser = HTTParty::Parser.new("\x80", :invalid_format) expect(parser.parse).to_not be_nil end it "ignores utf-8 bom" do parser = HTTParty::Parser.new("\xEF\xBB\xBF\{\"hi\":\"yo\"\}", :json) expect(parser.parse).to eq({"hi"=>"yo"}) end it "parses ascii 8bit encoding" do parser = HTTParty::Parser.new( "{\"currency\":\"\xE2\x82\xAC\"}".force_encoding('ASCII-8BIT'), :json ) expect(parser.parse).to eq({"currency" => "€"}) end it "parses frozen strings" do parser = HTTParty::Parser.new('{"a":1}'.freeze, :json) expect(parser.parse).to eq("a" => 1) end end describe "#supports_format?" do it "utilizes the class method to determine if the format is supported" do expect(HTTParty::Parser).to 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) expect(parser).to 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 expect(MultiXml).to receive(:parse).with('body') subject.send(:xml) end it "parses json with JSON" do expect(JSON).to receive(:parse).with('body', :quirks_mode => true, :allow_nan => true) subject.send(:json) end it "parses html by simply returning the body" do expect(subject.send(:html)).to eq('body') end it "parses plain text by simply returning the body" do expect(subject.send(:plain)).to eq('body') end it "parses csv with CSV" do expect(CSV).to receive(:parse).with('body') subject.send(:csv) end end end httparty-0.15.6/spec/httparty/logger/0000755000004100000410000000000013145325011017575 5ustar www-datawww-datahttparty-0.15.6/spec/httparty/logger/apache_formatter_spec.rb0000644000004100000410000000303213145325011024436 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')) RSpec.describe HTTParty::Logger::ApacheFormatter do let(:subject) { described_class.new(logger_double, :info) } let(:logger_double) { double('Logger') } let(:request_double) { double('Request', http_method: Net::HTTP::Get, path: "http://my.domain.com/my_path") } let(:request_time) { Time.new.strftime("%Y-%m-%d %H:%M:%S %z") } before do subject.current_time = request_time expect(logger_double).to receive(:info).with(log_message) end describe "#format" do let(:log_message) { "[HTTParty] [#{request_time}] 302 \"GET http://my.domain.com/my_path\" - " } it "formats a response in a style that resembles apache's access log" do response_double = double( code: 302, :[] => nil ) subject.format(request_double, response_double) end context 'when there is a parsed response' do let(:log_message) { "[HTTParty] [#{request_time}] 200 \"GET http://my.domain.com/my_path\" 512 "} it "can handle the Content-Length header" do # Simulate a parsed response that is an array, where accessing a string key will raise an error. See Issue #299. response_double = double( code: 200, headers: { 'Content-Length' => 512 } ) allow(response_double).to receive(:[]).with('Content-Length').and_raise(TypeError.new('no implicit conversion of String into Integer')) subject.format(request_double, response_double) end end end end httparty-0.15.6/spec/httparty/logger/logger_spec.rb0000644000004100000410000000245213145325011022416 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')) RSpec.describe HTTParty::Logger do describe ".build" do subject { HTTParty::Logger } it "defaults level to :info" do logger_double = double expect(subject.build(logger_double, nil, nil).level).to eq(:info) end it "defaults format to :apache" do logger_double = double expect(subject.build(logger_double, nil, nil)).to be_an_instance_of(HTTParty::Logger::ApacheFormatter) end it "builds :curl style logger" do logger_double = double expect(subject.build(logger_double, nil, :curl)).to be_an_instance_of(HTTParty::Logger::CurlFormatter) end it "builds :custom style logger" do CustomFormatter = Class.new(HTTParty::Logger::CurlFormatter) HTTParty::Logger.add_formatter(:custom, CustomFormatter) logger_double = double expect(subject.build(logger_double, nil, :custom)). to be_an_instance_of(CustomFormatter) end it "raises error when formatter exists" do CustomFormatter2= Class.new(HTTParty::Logger::CurlFormatter) HTTParty::Logger.add_formatter(:custom2, CustomFormatter2) expect{ HTTParty::Logger.add_formatter(:custom2, CustomFormatter2) }. to raise_error HTTParty::Error end end end httparty-0.15.6/spec/httparty/logger/curl_formatter_spec.rb0000644000004100000410000000725713145325011024177 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')) RSpec.describe HTTParty::Logger::CurlFormatter do describe "#format" do let(:logger) { double('Logger') } let(:response_object) { Net::HTTPOK.new('1.1', 200, 'OK') } let(:parsed_response) { lambda { {"foo" => "bar"} } } let(:response) do HTTParty::Response.new(request, response_object, parsed_response) end let(:request) do HTTParty::Request.new(Net::HTTP::Get, 'http://foo.bar.com/') end subject { described_class.new(logger, :info) } before do allow(logger).to receive(:info) allow(request).to receive(:raw_body).and_return('content') allow(response_object).to receive_messages(body: "{foo:'bar'}") response_object['header-key'] = 'header-value' subject.format request, response end context 'when request is logged' do context "and request's option 'base_uri' is not present" do it 'logs url' do expect(logger).to have_received(:info).with(/\[HTTParty\] \[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\ [+-]\d{4}\] > GET http:\/\/foo.bar.com/) end end context "and request's option 'base_uri' is present" do let(:request) do HTTParty::Request.new(Net::HTTP::Get, '/path', base_uri: 'http://foo.bar.com') end it 'logs url' do expect(logger).to have_received(:info).with(/\[HTTParty\] \[\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\ [+-]\d{4}\] > GET http:\/\/foo.bar.com\/path/) end end context 'and headers are not present' do it 'not log Headers' do expect(logger).not_to have_received(:info).with(/Headers/) end end context 'and headers are present' do let(:request) do HTTParty::Request.new(Net::HTTP::Get, '/path', base_uri: 'http://foo.bar.com', headers: { key: 'value' }) end it 'logs Headers' do expect(logger).to have_received(:info).with(/Headers/) end it 'logs headers keys' do expect(logger).to have_received(:info).with(/key: value/) end end context 'and query is not present' do it 'not logs Query' do expect(logger).not_to have_received(:info).with(/Query/) end end context 'and query is present' do let(:request) do HTTParty::Request.new(Net::HTTP::Get, '/path', query: { key: 'value' }) end it 'logs Query' do expect(logger).to have_received(:info).with(/Query/) end it 'logs query params' do expect(logger).to have_received(:info).with(/key: value/) end end context 'when request raw_body is present' do it 'not logs request body' do expect(logger).to have_received(:info).with(/content/) end end end context 'when response is logged' do it 'logs http version and response code' do expect(logger).to have_received(:info).with(/HTTP\/1.1 200/) end it 'logs headers' do expect(logger).to have_received(:info).with(/Header-key: header-value/) end it 'logs body' do expect(logger).to have_received(:info).with(/{foo:'bar'}/) end end it "formats a response in a style that resembles a -v curl" do logger_double = double expect(logger_double).to 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.15.6/spec/httparty/hash_conversions_spec.rb0000644000004100000410000000271613145325011023236 0ustar www-datawww-dataRSpec.describe HTTParty::HashConversions do describe ".to_params" do it "creates a params string from a hash" do hash = { name: "bob", address: { street: '111 ruby ave.', city: 'ruby central', phones: ['111-111-1111', '222-222-2222'] } } expect(HTTParty::HashConversions.to_params(hash)).to eq("name=bob&address[street]=111%20ruby%20ave.&address[city]=ruby%20central&address[phones][]=111-111-1111&address[phones][]=222-222-2222") end end describe ".normalize_param" do context "value is an array" do it "creates a params string" do expect( HTTParty::HashConversions.normalize_param(:people, ["Bob Jones", "Mike Smith"]) ).to eq("people[]=Bob%20Jones&people[]=Mike%20Smith&") end end context "value is an empty array" do it "creates a params string" do expect( HTTParty::HashConversions.normalize_param(:people, []) ).to eq("people[]=&") end end context "value is hash" do it "creates a params string" do expect( HTTParty::HashConversions.normalize_param(:person, { name: "Bob Jones" }) ).to eq("person[name]=Bob%20Jones&") end end context "value is a string" do it "creates a params string" do expect( HTTParty::HashConversions.normalize_param(:name, "Bob Jones") ).to eq("name=Bob%20Jones&") end end end end httparty-0.15.6/spec/httparty/connection_adapter_spec.rb0000644000004100000410000003752013145325011023523 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) RSpec.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) expect(adapter.uri).to 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) expect(adapter.options.keys).to include(:verify, :verify_peer, :foo) end end describe ".call" do it "generates an HTTParty::ConnectionAdapter instance with the given uri and options" do expect(HTTParty::ConnectionAdapter).to receive(:new).with(@uri, @options).and_return(double(connection: nil)) HTTParty::ConnectionAdapter.call(@uri, @options) end it "calls #connection on the connection adapter" do adapter = double('Adapter') connection = double('Connection') expect(adapter).to receive(:connection).and_return(connection) allow(HTTParty::ConnectionAdapter).to receive_messages(new: adapter) expect(HTTParty::ConnectionAdapter.call(@uri, @options)).to 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 { is_expected.to be_an_instance_of Net::HTTP } context "using port 80" do let(:uri) { URI 'http://foobar.com' } it { is_expected.not_to 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 = double('default_cert_store') expect(system_cert_store).to receive(:set_default_paths) expect(OpenSSL::X509::Store).to receive(:new).and_return(system_cert_store) system_cert_store end it { is_expected.to use_cert_store(system_cert_store) } end context "should use the specified cert store, when one is given" do let(:custom_cert_store) { double('custom_cert_store') } let(:options) { {cert_store: custom_cert_store} } it { is_expected.to use_cert_store(custom_cert_store) } end context "using port 443 for ssl" do let(:uri) { URI 'https://api.foo.com/v1:443' } it { is_expected.to use_ssl } end context "https scheme with default port" do it { is_expected.to use_ssl } end context "https scheme with non-standard port" do let(:uri) { URI 'https://foobar.com:123456' } it { is_expected.to use_ssl } end context "when ssl version is set" do let(:options) { {ssl_version: :TLSv1} } it "sets ssl version" do expect(subject.ssl_version).to eq(: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 expect(subject.address).to eq('fd00::1') end end context "specifying ciphers" do let(:options) { {ciphers: 'RC4-SHA' } } it "should set the ciphers on the connection" do expect(subject.ciphers).to eq('RC4-SHA') end end if RUBY_VERSION > '1.9' context "when timeout is not set" do it "doesn't set the timeout" do http = double( "http", :null_object => true, :use_ssl= => false, :use_ssl? => false ) expect(http).not_to receive(:open_timeout=) expect(http).not_to receive(:read_timeout=) allow(Net::HTTP).to receive_messages(new: http) adapter.connection end end context "when setting timeout" do context "to 5 seconds" do let(:options) { {timeout: 5} } describe '#open_timeout' do subject { super().open_timeout } it { is_expected.to eq(5) } end describe '#read_timeout' do subject { super().read_timeout } it { is_expected.to eq(5) } end end context "and timeout is a string" do let(:options) { {timeout: "five seconds"} } it "doesn't set the timeout" do http = double( "http", :null_object => true, :use_ssl= => false, :use_ssl? => false ) expect(http).not_to receive(:open_timeout=) expect(http).not_to receive(:read_timeout=) allow(Net::HTTP).to receive_messages(new: http) adapter.connection end end end context "when timeout is not set and read_timeout is set to 6 seconds" do let(:options) { {read_timeout: 6} } describe '#read_timeout' do subject { super().read_timeout } it { is_expected.to eq(6) } end it "should not set the open_timeout" do http = double( "http", :null_object => true, :use_ssl= => false, :use_ssl? => false, :read_timeout= => 0 ) expect(http).not_to receive(:open_timeout=) allow(Net::HTTP).to receive_messages(new: http) adapter.connection end end context "when timeout is set and read_timeout is set to 6 seconds" do let(:options) { {timeout: 5, read_timeout: 6} } describe '#open_timeout' do subject { super().open_timeout } it { is_expected.to eq(5) } end describe '#read_timeout' do subject { super().read_timeout } it { is_expected.to eq(6) } end it "should override the timeout option" do http = double( "http", :null_object => true, :use_ssl= => false, :use_ssl? => false, :read_timeout= => 0, :open_timeout= => 0 ) expect(http).to receive(:open_timeout=) expect(http).to receive(:read_timeout=).twice allow(Net::HTTP).to receive_messages(new: http) adapter.connection end end context "when timeout is not set and open_timeout is set to 7 seconds" do let(:options) { {open_timeout: 7} } describe '#open_timeout' do subject { super().open_timeout } it { is_expected.to eq(7) } end it "should not set the read_timeout" do http = double( "http", :null_object => true, :use_ssl= => false, :use_ssl? => false, :open_timeout= => 0 ) expect(http).not_to receive(:read_timeout=) allow(Net::HTTP).to receive_messages(new: http) adapter.connection end end context "when timeout is set and open_timeout is set to 7 seconds" do let(:options) { {timeout: 5, open_timeout: 7} } describe '#open_timeout' do subject { super().open_timeout } it { is_expected.to eq(7) } end describe '#read_timeout' do subject { super().read_timeout } it { is_expected.to eq(5) } end it "should override the timeout option" do http = double( "http", :null_object => true, :use_ssl= => false, :use_ssl? => false, :read_timeout= => 0, :open_timeout= => 0 ) expect(http).to receive(:open_timeout=).twice expect(http).to receive(:read_timeout=) allow(Net::HTTP).to receive_messages(new: http) adapter.connection end end context "when debug_output" do let(:http) { Net::HTTP.new(uri) } before do allow(Net::HTTP).to receive_messages(new: http) end context "is set to $stderr" do let(:options) { {debug_output: $stderr} } it "has debug output set" do expect(http).to receive(:set_debug_output).with($stderr) adapter.connection end end context "is not provided" do it "does not set_debug_output" do expect(http).not_to 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 { is_expected.to be_a_proxy } describe '#proxy_address' do subject { super().proxy_address } it { is_expected.to eq('1.2.3.4') } end describe '#proxy_port' do subject { super().proxy_port } it { is_expected.to eq(8080) } end 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 describe '#proxy_user' do subject { super().proxy_user } it { is_expected.to eq('user') } end describe '#proxy_pass' do subject { super().proxy_pass } it { is_expected.to eq('pass') } end end end context 'when providing nil as proxy address' do let(:uri) { URI 'http://noproxytest.com' } let(:options) { {http_proxyaddr: nil} } it { is_expected.not_to be_a_proxy } it "does pass nil proxy parameters to the connection, this forces to not use a proxy" do http = Net::HTTP.new("noproxytest.com") expect(Net::HTTP).to receive(:new).once.with("noproxytest.com", 80, nil, nil, nil, nil).and_return(http) adapter.connection 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") expect(Net::HTTP).to 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 } } describe '#local_host' do subject { super().local_host } it { is_expected.to eq('127.0.0.1') } end describe '#local_port' do subject { super().local_port } it { is_expected.to eq(12345) } end 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) { double("OpenSSL::X509::Certificate") } let(:key) { double("OpenSSL::PKey::RSA") } before do expect(OpenSSL::X509::Certificate).to receive(:new).with(pem).and_return(cert) expect(OpenSSL::PKey::RSA).to receive(:new).with(pem, "password").and_return(key) end it "uses the provided PEM certificate" do expect(subject.cert).to eq(cert) expect(subject.key).to eq(key) end it "will verify the certificate" do expect(subject.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER) end context "when options include verify=false" do let(:options) { {pem: pem, pem_password: "password", verify: false} } it "should not verify the certificate" do expect(subject.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE) end end context "when options include verify_peer=false" do let(:options) { {pem: pem, pem_password: "password", verify_peer: false} } it "should not verify the certificate" do expect(subject.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE) end end end context "when scheme is not https" do let(:uri) { URI 'http://google.com' } let(:http) { Net::HTTP.new(uri) } before do allow(Net::HTTP).to receive_messages(new: http) expect(OpenSSL::X509::Certificate).not_to receive(:new).with(pem) expect(OpenSSL::PKey::RSA).not_to receive(:new).with(pem, "password") expect(http).not_to receive(:cert=) expect(http).not_to receive(:key=) end it "has no PEM certificate " do expect(subject.cert).to be_nil expect(subject.key).to be_nil end end end context "when providing PKCS12 certificates" do let(:p12) { :p12_contents } let(:options) { {p12: p12, p12_password: "password"} } context "when scheme is https" do let(:uri) { URI 'https://google.com' } let(:pkcs12) { double("OpenSSL::PKCS12", certificate: cert, key: key) } let(:cert) { double("OpenSSL::X509::Certificate") } let(:key) { double("OpenSSL::PKey::RSA") } before do expect(OpenSSL::PKCS12).to receive(:new).with(p12, "password").and_return(pkcs12) end it "uses the provided P12 certificate " do expect(subject.cert).to eq(cert) expect(subject.key).to eq(key) end it "will verify the certificate" do expect(subject.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER) end context "when options include verify=false" do let(:options) { {p12: p12, p12_password: "password", verify: false} } it "should not verify the certificate" do expect(subject.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE) end end context "when options include verify_peer=false" do let(:options) { {p12: p12, p12_password: "password", verify_peer: false} } it "should not verify the certificate" do expect(subject.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE) end end end context "when scheme is not https" do let(:uri) { URI 'http://google.com' } let(:http) { Net::HTTP.new(uri) } before do allow(Net::HTTP).to receive_messages(new: http) expect(OpenSSL::PKCS12).not_to receive(:new).with(p12, "password") expect(http).not_to receive(:cert=) expect(http).not_to receive(:key=) end it "has no PKCS12 certificate " do expect(subject.cert).to be_nil expect(subject.key).to be_nil end end end context "when uri port is not defined" do context "falls back to 80 port on http" do let(:uri) { URI 'http://foobar.com' } before { allow(uri).to receive(:port).and_return(nil) } it { expect(subject.port).to be 80 } end context "falls back to 443 port on https" do let(:uri) { URI 'https://foobar.com' } before { allow(uri).to receive(:port).and_return(nil) } it { expect(subject.port).to be 443 } end end end end end httparty-0.15.6/spec/httparty/response_spec.rb0000644000004100000410000003165413145325011021524 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) RSpec.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') allow(@response_object).to receive_messages(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 expect(HTTParty::Response.underscore("Accepted")).to eq("accepted") end it "works with titlecase" do expect(HTTParty::Response.underscore("BadGateway")).to eq("bad_gateway") end it "works with all caps" do expect(HTTParty::Response.underscore("OK")).to eq("ok") end end describe "initialization" do it "should set the Net::HTTP Response" do expect(@response.response).to eq(@response_object) end it "should set body" do expect(@response.body).to eq(@response_object.body) end it "should set code" do expect(@response.code).to eq(@response_object.code) end it "should set code as a Fixnum" do expect(@response.code).to be_an_instance_of(Fixnum) end context 'when raise_on is supplied' do let(:request) { HTTParty::Request.new(Net::HTTP::Get, '/', raise_on: [404]) } context "and response's status code is in range" do let(:body) { 'Not Found' } let(:response) { Net::HTTPNotFound.new('1.1', 404, body) } before do allow(response).to receive(:body).and_return(body) end subject { described_class.new(request, response, @parsed_response) } it 'throws exception' do expect{ subject }.to raise_error(HTTParty::ResponseError, "Code 404 - #{body}") end end context "and response's status code is not in range" do subject { described_class.new(request, @response_object, @parsed_response) } it 'does not throw exception' do expect{ subject }.not_to raise_error(HTTParty::ResponseError) end end end end it 'does raise an error about itself when using #method' do expect { HTTParty::Response.new(@request_object, @response_object, @parsed_response).method(:qux) }.to raise_error(NameError, /HTTParty\:\:Response/) end it 'does raise an error about itself when invoking a method that does not exist' do expect { HTTParty::Response.new(@request_object, @response_object, @parsed_response).qux }.to raise_error(NoMethodError, /HTTParty\:\:Response/) end it "returns response headers" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) expect(response.headers).to eq({'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) expect(response['foo']).to eq('bar') end it "response to request" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) expect(response.respond_to?(:request)).to be_truthy end it "responds to response" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) expect(response.respond_to?(:response)).to be_truthy end it "responds to body" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) expect(response.respond_to?(:body)).to be_truthy end it "responds to headers" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) expect(response.respond_to?(:headers)).to be_truthy end it "responds to parsed_response" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) expect(response.respond_to?(:parsed_response)).to be_truthy end it "responds to predicates" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) expect(response.respond_to?(:success?)).to be_truthy end it "responds to anything parsed_response responds to" do response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) expect(response.respond_to?(:[])).to be_truthy end context 'response is array' do let(:response_value) { [{'foo' => 'bar'}, {'foo' => 'baz'}] } let(:response) { HTTParty::Response.new(@request_object, @response_object, lambda { response_value }) } it "should be able to iterate" do expect(response.size).to eq(2) expect { response.each { |item| } }.to_not raise_error end it 'should respond to array methods' do expect(response).to respond_to(:bsearch, :compact, :cycle, :delete, :each, :flatten, :flatten!, :compact, :join) end it 'should equal the string response object body' do expect(response.to_s).to eq(@response_object.body.to_s) end it 'should display the same as an array' do a = StringIO.new b = StringIO.new response_value.display(b) response.display(a) expect(a.string).to eq(b.string) end 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) expect(response.headers['Content-LENGTH']).to eq(@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) expect(response.headers['set-cookie']).to eq("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| expect(response.headers.respond_to?(method_name)).to be_truthy end end describe "#is_a?" do subject { HTTParty::Response.new(@request_object, @response_object, @parsed_response) } it { is_expected.to respond_to(:is_a?).with(1).arguments } it { expect(subject.is_a?(HTTParty::Response)).to be_truthy } it { expect(subject.is_a?(Object)).to be_truthy } end describe "#kind_of?" do subject { HTTParty::Response.new(@request_object, @response_object, @parsed_response) } it { is_expected.to respond_to(:kind_of?).with(1).arguments } it { expect(subject.kind_of?(HTTParty::Response)).to be_truthy } it { expect(subject.kind_of?(Object)).to be_truthy } end describe "semantic methods for response codes" do def response_mock(klass) response = klass.new('', '', '') allow(response).to receive(: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, '') expect(response.information?).to be_truthy end it "is success" do net_response = response_mock(Net::HTTPSuccess) response = HTTParty::Response.new(@request_object, net_response, '') expect(response.success?).to be_truthy end it "is redirection" do net_response = response_mock(Net::HTTPRedirection) response = HTTParty::Response.new(@request_object, net_response, '') expect(response.redirection?).to be_truthy end it "is client error" do net_response = response_mock(Net::HTTPClientError) response = HTTParty::Response.new(@request_object, net_response, '') expect(response.client_error?).to be_truthy end it "is server error" do net_response = response_mock(Net::HTTPServerError) response = HTTParty::Response.new(@request_object, net_response, '') expect(response.server_error?).to be_truthy 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, '') expect(response.__send__(method)).to be_truthy end end end end describe "headers" do let (:empty_headers) { HTTParty::Response::Headers.new } let (:some_headers_hash) do {'Cookie' => 'bob', 'Content-Encoding' => 'meow'} end let (:some_headers) do HTTParty::Response::Headers.new.tap do |h| some_headers_hash.each_pair do |k,v| h[k] = v end end end it "can initialize without headers" do expect(empty_headers).to eq({}) end it 'always equals itself' do expect(empty_headers).to eq(empty_headers) expect(some_headers).to eq(some_headers) end it 'does not equal itself when not equivalent' do expect(empty_headers).to_not eq(some_headers) end it 'does equal a hash' do expect(empty_headers).to eq({}) expect(some_headers).to eq(some_headers_hash) end end describe "#tap" do it "is possible to tap into a response" do result = @response.tap(&:code) expect(result).to eq @response end end describe "#inspect" do it "works" do inspect = @response.inspect expect(inspect).to include("HTTParty::Response:0x") expect(inspect).to include("parsed_response={\"foo\"=>\"bar\"}") expect(inspect).to include("@response=#") expect(inspect).to include("@headers={") expect(inspect).to include("last-modified") expect(inspect).to include("content-length") end end end httparty-0.15.6/spec/httparty/cookie_hash_spec.rb0000644000004100000410000000610613145325011022134 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper')) RSpec.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") expect(@cookie_hash.length).to eql(2) end it "should overwrite any existing key" do @cookie_hash.add_cookies(foo: "bar") @cookie_hash.add_cookies(foo: "copter") expect(@cookie_hash.length).to eql(1) expect(@cookie_hash[:foo]).to 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") expect(@cookie_hash[:first]).to eq('one') expect(@cookie_hash[:second]).to eq('two') expect(@cookie_hash[:third]).to eq(nil) end it "should overwrite any existing key" do @cookie_hash[:foo] = 'bar' @cookie_hash.add_cookies("foo=tar") expect(@cookie_hash.length).to eql(1) expect(@cookie_hash[:foo]).to eql("tar") end it "should handle '=' within cookie value" do @cookie_hash.add_cookies("first=one=1; second=two=2==") expect(@cookie_hash.keys).to include(:first, :second) expect(@cookie_hash[:first]).to eq('one=1') expect(@cookie_hash[:second]).to eq('two=2==') end end describe 'with other class' do it "should error" do expect { @cookie_hash.add_cookies([]) }.to raise_error(RuntimeError) 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 expect(@s).to match(/foo=bar/) expect(@s).to match(/rofl=copter/) expect(@s).to 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 expect(@s).not_to 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 expect(@s).not_to match(/Path=\//) end it "should not mutate the hash" do original_hash = { "session" => "91e25e8b-6e32-418d-c72f-2d18adf041cd", "Max-Age" => "15552000", "cart" => "91e25e8b-6e32-418d-c72f-2d18adf041cd", "httponly" => nil, "Path" => "/", "secure" => nil, } cookie_hash = HTTParty::CookieHash[original_hash] cookie_hash.to_cookie_string expect(cookie_hash).to eq(original_hash) end end end httparty-0.15.6/spec/httparty/request_spec.rb0000644000004100000410000014370113145325011021353 0ustar www-datawww-datarequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper')) RSpec.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"] expect(CGI.unescape(query_string)).to eq("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)}] expect(CGI.unescape(query_string)).to eq("foo=bar&foo=baz&page=1") end it "URI encodes array values" do query_string = normalizer[{people: ["Otis Redding", "Bob Marley", "Tim & Jon"], page: 1, xyzzy: 3}] expect(query_string).to eq("page=1&people=Otis%20Redding&people=Bob%20Marley&people=Tim%20%26%20Jon&xyzzy=3") end end context "when the query is a hash" do it "correctly handles nil values" do query_string = normalizer[{page: 1, per_page: nil}] expect(query_string).to eq("page=1&per_page") end end end describe "::JSON_API_QUERY_STRING_NORMALIZER" do let(:normalizer) { HTTParty::Request::JSON_API_QUERY_STRING_NORMALIZER } it "doesn't modify strings" do query_string = normalizer["foo=bar&foo=baz"] expect(CGI.unescape(query_string)).to eq("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)}] expect(CGI.unescape(query_string)).to eq("foo=bar,baz&page=1") end it "URI encodes array values" do query_string = normalizer[{people: ["Otis Redding", "Bob Marley", "Tim & Jon"], page: 1, xyzzy: 3}] expect(query_string).to eq("page=1&people=Otis%20Redding,Bob%20Marley,Tim%20%26%20Jon&xyzzy=3") end end context "when the query is a hash" do it "correctly handles nil values" do query_string = normalizer[{page: 1, per_page: nil}] expect(query_string).to eq('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') expect(request.parser).to eq(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) expect(request.parser).to eq(my_parser) end it "sets connection_adapter to HTTPParty::ConnectionAdapter" do request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com') expect(request.connection_adapter).to eq(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) expect(request.connection_adapter).to eq(my_adapter) end context "when using a query string" do context "and it has an empty array" do it "sets correct query string" do request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com', query: { fake_array: [] }) expect(request.uri).to eq(URI.parse("http://google.com/?fake_array[]=")) end end context "when sending an array with only one element" do it "sets correct query" do request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com', query: { fake_array: [1] }) expect(request.uri).to eq(URI.parse("http://google.com/?fake_array[]=1")) end end end context "when basic authentication credentials provided in uri" do context "when basic auth options wasn't set explicitly" do it "sets basic auth from uri" do request = HTTParty::Request.new(Net::HTTP::Get, 'http://user1:pass1@example.com') expect(request.options[:basic_auth]).to eq({username: 'user1', password: 'pass1'}) end end context "when basic auth options was set explicitly" do it "uses basic auth from url anyway" do basic_auth = {username: 'user2', password: 'pass2'} request = HTTParty::Request.new(Net::HTTP::Get, 'http://user1:pass1@example.com', basic_auth: basic_auth) expect(request.options[:basic_auth]).to eq({username: 'user1', password: 'pass1'}) end end end end describe "#format" do context "request yet to be made" do it "returns format option" do request = HTTParty::Request.new 'get', '/', format: :xml expect(request.format).to eq(:xml) end it "returns nil format" do request = HTTParty::Request.new 'get', '/' expect(request.format).to 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 = double expect(request.format).to eq(:xml) end it "returns the content-type from the last response when the option is not set" do request = HTTParty::Request.new 'get', '/' response = double expect(response).to receive(:[]).with('content-type').and_return('text/json') request.last_response = response expect(request.format).to eq(: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) expect(@request.instance_variable_get(:@raw_request)['authorization']).not_to be_nil end context 'digest_auth' do before do response_sequence = [ { status: ['401', 'Unauthorized' ], headers: { www_authenticate: 'Digest realm="Log Viewer", qop="auth", nonce="2CA0EC6B0E126C4800E56BA0C0003D3C", opaque="5ccc069c403ebaf9f0171e9517f40e41", stale=false', set_cookie: 'custom-cookie=1234567' } }, { status: ['200', 'OK'] } ] stub_request(:get, 'http://api.foo.com/v1').to_return(response_sequence) end it 'should not send credentials more than once' do response_sequence = [ { status: ['401', 'Unauthorized' ], headers: { www_authenticate: 'Digest realm="Log Viewer", qop="auth", nonce="2CA0EC6B0E126C4800E56BA0C0003D3C", opaque="5ccc069c403ebaf9f0171e9517f40e41", stale=false', set_cookie: 'custom-cookie=1234567' } }, { status: ['401', 'Unauthorized' ], headers: { www_authenticate: 'Digest realm="Log Viewer", qop="auth", nonce="2CA0EC6B0E126C4800E56BA0C0003D3C", opaque="5ccc069c403ebaf9f0171e9517f40e41", stale=false', set_cookie: 'custom-cookie=1234567' } }, { status: ['404', 'Not found'] } ] stub_request(:get, 'http://api.foo.com/v1').to_return(response_sequence) @request.options[:digest_auth] = {username: 'foobar', password: 'secret'} response = @request.perform { |v| } expect(response.code).to eq(401) raw_request = @request.instance_variable_get(:@raw_request) expect(raw_request['Authorization']).not_to be_nil end it 'should not be used when configured and the response is 200' do stub_request(:get, 'http://api.foo.com/v1').to_return(status: 200) @request.options[:digest_auth] = {username: 'foobar', password: 'secret'} response = @request.perform { |v| } expect(response.code).to eq(200) raw_request = @request.instance_variable_get(:@raw_request) expect(raw_request['Authorization']).to be_nil end it "should be used when configured and the response is 401" do @request.options[:digest_auth] = {username: 'foobar', password: 'secret'} response = @request.perform { |v| } expect(response.code).to eq(200) raw_request = @request.instance_variable_get(:@raw_request) expect(raw_request['Authorization']).not_to be_nil end it 'should maintain cookies returned from a 401 response' do @request.options[:digest_auth] = {username: 'foobar', password: 'secret'} response = @request.perform {|v|} expect(response.code).to eq(200) raw_request = @request.instance_variable_get(:@raw_request) expect(raw_request.get_fields('cookie')).to eql ["custom-cookie=1234567"] end it 'should merge cookies from request and a 401 response' do @request.options[:digest_auth] = {username: 'foobar', password: 'secret'} @request.options[:headers] = {'cookie' => 'request-cookie=test'} response = @request.perform {|v|} expect(response.code).to eq(200) raw_request = @request.instance_variable_get(:@raw_request) expect(raw_request.get_fields('cookie')).to eql ['request-cookie=test', 'custom-cookie=1234567'] end end it 'should use body_stream when configured' do stream = StringIO.new('foo') request = HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', body_stream: stream) request.send(:setup_raw_request) expect(request.instance_variable_get(:@raw_request).body_stream).to eq(stream) end it 'should normalize base uri when specified as request option' do stub_request(:get, 'http://foo.com/resource').to_return(body: 'Bar') response = HTTParty.get('/resource', { base_uri: 'foo.com' }) expect(response.code).to eq(200) end end describe "#uri" do context "redirects" do it "returns correct path when the server sets the location header to a filename" do @request.last_uri = URI.parse("http://example.com/foo/bar") @request.path = URI.parse("bar?foo=bar") @request.redirect = true expect(@request.uri).to eq(URI.parse("http://example.com/foo/bar?foo=bar")) end context "location header is an absolute path" do it "returns correct path when location has leading slash" do @request.last_uri = URI.parse("http://example.com/foo/bar") @request.path = URI.parse("/bar?foo=bar") @request.redirect = true expect(@request.uri).to eq(URI.parse("http://example.com/bar?foo=bar")) end it "returns the correct path when location has no leading slash" do @request.last_uri = URI.parse("http://example.com") @request.path = URI.parse("bar/") @request.redirect = true expect(@request.uri).to eq(URI.parse("http://example.com/bar/")) end end it "returns correct path when the server sets the location header to a full uri" do @request.last_uri = URI.parse("http://example.com/foo/bar") @request.path = URI.parse("http://example.com/bar?foo=bar") @request.redirect = true expect(@request.uri).to eq(URI.parse("http://example.com/bar?foo=bar")) end it "returns correct path when the server sets the location header to a network-path reference" do @request.last_uri = URI.parse("https://example.com") @request.path = URI.parse("//www.example.com") @request.redirect = true expect(@request.uri).to eq(URI.parse("https://www.example.com")) end end context "query strings" do it "does not add an empty query string when default_params are blank" do @request.options[:default_params] = {} expect(@request.uri.query).to be_nil end it "respects the query string normalization proc" do empty_proc = lambda {|qs| "I"} @request.options[:query_string_normalizer] = empty_proc @request.options[:query] = {foo: :bar} expect(CGI.unescape(@request.uri.query)).to eq("I") end it "does not append an ampersand when queries are embedded in paths" do @request.path = "/path?a=1" @request.options[:query] = {} expect(@request.uri.query).to eq("a=1") end it "does not duplicate query string parameters when uri is called twice" do @request.options[:query] = {foo: :bar} @request.uri expect(@request.uri.query).to eq("foo=bar") end context "when representing an array" do it "returns a Rails style query string" do @request.options[:query] = {foo: %w(bar baz)} expect(CGI.unescape(@request.uri.query)).to eq("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 expect(CGI.unescape(body)).to eq("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 = double('adapter') request = HTTParty::Request.new(Net::HTTP::Get, 'https://api.foo.com/v1:443', connection_adapter: adapter) expect(adapter).to receive(:call).with(request.uri, request.options).and_return(http) expect(request.send(:http)).to 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| expect(@request.send(:format_from_mimetype, ct)).to eq(:xml) end end it 'should handle application/xml' do ["application/xml", "application/xml; charset=iso8859-1"].each do |ct| expect(@request.send(:format_from_mimetype, ct)).to eq(:xml) end end it 'should handle text/json' do ["text/json", "text/json; charset=iso8859-1"].each do |ct| expect(@request.send(:format_from_mimetype, ct)).to eq(:json) end end it 'should handle application/json' do ["application/json", "application/json; charset=iso8859-1"].each do |ct| expect(@request.send(:format_from_mimetype, ct)).to eq(:json) end end it 'should handle text/csv' do ["text/csv", "text/csv; charset=iso8859-1"].each do |ct| expect(@request.send(:format_from_mimetype, ct)).to eq(:csv) end end it 'should handle application/csv' do ["application/csv", "application/csv; charset=iso8859-1"].each do |ct| expect(@request.send(:format_from_mimetype, ct)).to eq(:csv) end end it 'should handle text/comma-separated-values' do ["text/comma-separated-values", "text/comma-separated-values; charset=iso8859-1"].each do |ct| expect(@request.send(:format_from_mimetype, ct)).to eq(:csv) end end it 'should handle text/javascript' do ["text/javascript", "text/javascript; charset=iso8859-1"].each do |ct| expect(@request.send(:format_from_mimetype, ct)).to eq(:plain) end end it 'should handle application/javascript' do ["application/javascript", "application/javascript; charset=iso8859-1"].each do |ct| expect(@request.send(:format_from_mimetype, ct)).to eq(:plain) end end it "returns nil for an unrecognized mimetype" do expect(@request.send(:format_from_mimetype, "application/atom+xml")).to be_nil end it "returns nil when using a default parser" do @request.options[:parser] = lambda {} expect(@request.send(:format_from_mimetype, "text/json")).to be_nil end end describe 'parsing responses' do it 'should handle xml automatically' do xml = '1234Foo Bar!' @request.options[:format] = :xml expect(@request.send(:parse_response, xml)).to eq({'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}) end it 'should handle utf-8 bom in xml' do xml = "\xEF\xBB\xBF1234Foo Bar!" @request.options[:format] = :xml expect(@request.send(:parse_response, xml)).to eq({'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}) end it 'should handle csv automatically' do csv = ['"id","Name"', '"1234","Foo Bar!"'].join("\n") @request.options[:format] = :csv expect(@request.send(:parse_response, csv)).to eq([%w(id Name), ["1234", "Foo Bar!"]]) end it 'should handle json automatically' do json = '{"books": {"book": {"name": "Foo Bar!", "id": "1234"}}}' @request.options[:format] = :json expect(@request.send(:parse_response, json)).to eq({'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}) end it 'should handle utf-8 bom in json' do json = "\xEF\xBB\xBF{\"books\": {\"book\": {\"name\": \"Foo Bar!\", \"id\": \"1234\"}}}" @request.options[:format] = :json expect(@request.send(:parse_response, json)).to eq({'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") expect(@request.perform.headers).to eq({ "key" => ["value"] }) end if "".respond_to?(:encoding) let(:response_charset) { @request.send(:get_charset) } it "should process charset in content type properly" do response = stub_response "Content".force_encoding('ascii-8bit') response.initialize_http_header("Content-Type" => "text/plain;charset = utf-8") resp = @request.perform expect(response_charset).to_not be_empty expect(resp.body.encoding).to eq(Encoding.find("UTF-8")) end it "should process charset in content type properly if it has a different case" do response = stub_response "Content".force_encoding('ascii-8bit') response.initialize_http_header("Content-Type" => "text/plain;CHARSET = utf-8") resp = @request.perform expect(response_charset).to_not be_empty expect(resp.body.encoding).to eq(Encoding.find("UTF-8")) end it "should process quoted charset in content type properly" do response = stub_response "Content".force_encoding('ascii-8bit') response.initialize_http_header("Content-Type" => "text/plain;charset = \"utf-8\"") resp = @request.perform expect(response_charset).to_not be_empty expect(resp.body.encoding).to eq(Encoding.find("UTF-8")) end it "should process response with a nil body" do response = stub_response nil response.initialize_http_header("Content-Type" => "text/html;charset=UTF-8") resp = @request.perform expect(resp.body).to be_nil 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 expect(response_charset).to_not be_empty expect(resp.body.encoding).to eq(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 expect(response_charset).to_not be_empty expect(resp.body.encoding).to eq(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 expect(response_charset).to_not be_empty expect(resp.body.encoding).to eq(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 expect(response_charset).to_not be_empty # This encoding does not exist, thus the string should not be encodd with it expect(resp.body.encoding).to_not eq(response_charset) expect(resp.body).to eq("Content") expect(resp.body.encoding).to eq("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 expect(response_charset).to be_nil expect(resp.body).to eq("Content") expect(resp.body.encoding).to eq("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 expect(resp.code).to eq(304) expect(resp.body).to eq('') expect(resp).to 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) allow(@http).to receive(:request).and_return(redirect, ok) response = @request.perform expect(response.request.base_uri.to_s).to eq("http://foo.com") expect(response.request.path.to_s).to eq("http://foo.com/foo") expect(response.request.uri.request_uri).to eq("/foo") expect(response.request.uri.to_s).to eq("http://foo.com/foo") expect(response.parsed_response).to eq({"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) stub_request(:get, 'http://test.com/redirect') .to_return( status: [300, 'REDIRECT'], headers: { location: 'http://api.foo.com/v2' } ) stub_request(:get, 'http://api.foo.com/v2') .to_return(body: 'bar') body = "" response = @request.perform { |chunk| body += chunk } expect(body.length).to eq(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) allow(@http).to receive(:request).and_return(redirect, ok) response = @request.perform expect(response.request.base_uri.to_s).to eq("http://api.foo.com") expect(response.request.path.to_s).to eq("/foo/bar") expect(response.request.uri.request_uri).to eq("/foo/bar") expect(response.request.uri.to_s).to eq("http://api.foo.com/foo/bar") expect(response.parsed_response).to eq({"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) stub_request(:get, 'http://test.com/redirect') .to_return( status: [300, 'REDIRECT'], headers: { location: "http://api.foo.com/v2" } ) stub_request(:get, 'http://api.foo.com/v2') .to_return( status: [300, 'REDIRECT'], headers: { location: '/v3' } ) stub_request(:get, 'http://api.foo.com/v3') .to_return(body: 'bar') response = @request.perform expect(response.request.base_uri.to_s).to eq("http://api.foo.com") expect(response.request.path.to_s).to eq("/v3") expect(response.request.uri.request_uri).to eq("/v3") expect(response.request.uri.to_s).to eq("http://api.foo.com/v3") expect(response.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "raises an error if redirect has duplicate location header" do @request = HTTParty::Request.new(Net::HTTP::Get, 'http://test.com/redirect', format: :xml) stub_request(:get, 'http://test.com/redirect') .to_return( status: [300, 'REDIRECT'], headers: { location: ['http://api.foo.com/v2', 'http://api.foo.com/v2'] } ) expect {@request.perform}.to raise_error(HTTParty::DuplicateLocationHeader) end it "returns the HTTParty::Response when the 300 does not contain a location header" do stub_response '', 300 expect(HTTParty::Response).to be === @request.perform end it "redirects including port" do stub_request(:get, 'http://withport.com:3000/v1') .to_return( status: [301, 'Moved Permanently'], headers: { location: 'http://withport.com:3000/v2' } ) stub_request(:get, 'http://withport.com:3000/v2') .to_return(status: 200) request = HTTParty::Request.new(Net::HTTP::Get, 'http://withport.com:3000/v1') response = request.perform expect(response.request.base_uri.to_s).to eq("http://withport.com:3000") end end it 'should return a valid object for 4xx response' do stub_response 'yes', 401 resp = @request.perform expect(resp.code).to eq(401) expect(resp.body).to eq("yes") expect(resp['foo']['bar']).to eq("yes") end it 'should return a valid object for 5xx response' do stub_response 'error', 500 resp = @request.perform expect(resp.code).to eq(500) expect(resp.body).to eq("error") expect(resp['foo']['bar']).to eq("error") end it "parses response lazily so codes can be checked prior" do stub_response 'not xml', 500 @request.options[:format] = :xml expect { response = @request.perform expect(response.code).to eq(500) expect(response.body).to eq('not xml') }.not_to 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 expect(@request.perform).to be_nil end end it "should not fail for missing mime type" do stub_response "Content for you" @request.options[:format] = :html expect(@request.perform.parsed_response).to eq('Content for you') end [300, 301, 302, 305].each do |code| describe "a request that #{code} redirects" do before(:each) do @redirect = stub_response("", code) @redirect['location'] = '/foo' @ok = stub_response('bar', 200) end describe "once" do before(:each) do allow(@http).to receive(:request).and_return(@redirect, @ok) end it "should be handled by GET transparently" do expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by POST transparently" do @request.http_method = Net::HTTP::Post expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by DELETE transparently" do @request.http_method = Net::HTTP::Delete expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by MOVE transparently" do @request.http_method = Net::HTTP::Move expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by COPY transparently" do @request.http_method = Net::HTTP::Copy expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by PATCH transparently" do @request.http_method = Net::HTTP::Patch expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by PUT transparently" do @request.http_method = Net::HTTP::Put expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by HEAD transparently" do @request.http_method = Net::HTTP::Head expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by OPTIONS transparently" do @request.http_method = Net::HTTP::Options expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by MKCOL transparently" do @request.http_method = Net::HTTP::Mkcol expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should keep track of cookies between redirects" do @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly' @request.perform expect(@request.options[:headers]['Cookie']).to match(/foo=bar/) expect(@request.options[:headers]['Cookie']).to match(/name=value/) end it 'should update cookies with redirects' do @request.options[:headers] = {'Cookie' => 'foo=bar;'} @redirect['Set-Cookie'] = 'foo=tar;' @request.perform expect(@request.options[:headers]['Cookie']).to match(/foo=tar/) end it 'should keep cookies between redirects' do @request.options[:headers] = {'Cookie' => 'keep=me'} @redirect['Set-Cookie'] = 'foo=tar;' @request.perform expect(@request.options[:headers]['Cookie']).to 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 expect(@request.options[:headers]['Cookie']).to match(/foo=bar/) expect(@request.options[:headers]['Cookie']).to match(/name=value/) expect(@request.options[:headers]['Cookie']).to match(/one=1/) expect(@request.options[:headers]['Cookie']).to match(/two=2/) end it 'should make resulting request a get request if it not already' do @request.http_method = Net::HTTP::Delete expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) expect(@request.http_method).to eq(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 expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) expect(@request.http_method).to eq(Net::HTTP::Delete) end it 'should log the redirection' do logger_double = double expect(logger_double).to receive(:info).twice @request.options[:logger] = logger_double @request.perform end end describe "infinitely" do before(:each) do allow(@http).to receive(:request).and_return(@redirect) end it "should raise an exception" do expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep) end end end end describe "a request that 303 redirects" do before(:each) do @redirect = stub_response("", 303) @redirect['location'] = '/foo' @ok = stub_response('bar', 200) end describe "once" do before(:each) do allow(@http).to receive(:request).and_return(@redirect, @ok) end it "should be handled by GET transparently" do expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by POST transparently" do @request.http_method = Net::HTTP::Post expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by DELETE transparently" do @request.http_method = Net::HTTP::Delete expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by MOVE transparently" do @request.http_method = Net::HTTP::Move expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by COPY transparently" do @request.http_method = Net::HTTP::Copy expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by PATCH transparently" do @request.http_method = Net::HTTP::Patch expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by PUT transparently" do @request.http_method = Net::HTTP::Put expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by HEAD transparently" do @request.http_method = Net::HTTP::Head expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by OPTIONS transparently" do @request.http_method = Net::HTTP::Options expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by MKCOL transparently" do @request.http_method = Net::HTTP::Mkcol expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should keep track of cookies between redirects" do @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly' @request.perform expect(@request.options[:headers]['Cookie']).to match(/foo=bar/) expect(@request.options[:headers]['Cookie']).to match(/name=value/) end it 'should update cookies with redirects' do @request.options[:headers] = {'Cookie' => 'foo=bar;'} @redirect['Set-Cookie'] = 'foo=tar;' @request.perform expect(@request.options[:headers]['Cookie']).to match(/foo=tar/) end it 'should keep cookies between redirects' do @request.options[:headers] = {'Cookie' => 'keep=me'} @redirect['Set-Cookie'] = 'foo=tar;' @request.perform expect(@request.options[:headers]['Cookie']).to 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 expect(@request.options[:headers]['Cookie']).to match(/foo=bar/) expect(@request.options[:headers]['Cookie']).to match(/name=value/) expect(@request.options[:headers]['Cookie']).to match(/one=1/) expect(@request.options[:headers]['Cookie']).to match(/two=2/) end it 'should make resulting request a get request if it not already' do @request.http_method = Net::HTTP::Delete expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) expect(@request.http_method).to eq(Net::HTTP::Get) end it 'should make resulting request a get request if options[:maintain_method_across_redirects] is false' do @request.options[:maintain_method_across_redirects] = false @request.http_method = Net::HTTP::Delete expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) expect(@request.http_method).to eq(Net::HTTP::Get) end it 'should make resulting request a get request if options[:maintain_method_across_redirects] is true but options[:resend_on_redirect] is false' do @request.options[:maintain_method_across_redirects] = true @request.options[:resend_on_redirect] = false @request.http_method = Net::HTTP::Delete expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) expect(@request.http_method).to eq(Net::HTTP::Get) end it 'should not make resulting request a get request if options[:maintain_method_across_redirects] and options[:resend_on_redirect] is true' do @request.options[:maintain_method_across_redirects] = true @request.options[:resend_on_redirect] = true @request.http_method = Net::HTTP::Delete expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) expect(@request.http_method).to eq(Net::HTTP::Delete) end it 'should log the redirection' do logger_double = double expect(logger_double).to receive(:info).twice @request.options[:logger] = logger_double @request.perform end end describe "infinitely" do before(:each) do allow(@http).to receive(:request).and_return(@redirect) end it "should raise an exception" do expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep) end end end describe "a request that returns 304" do before(:each) do @redirect = stub_response("", 304) @redirect['location'] = '/foo' end before(:each) do allow(@http).to receive(:request).and_return(@redirect) end it "should report 304 with a GET request" do expect(@request.perform.code).to eq(304) end it "should report 304 with a POST request" do @request.http_method = Net::HTTP::Post expect(@request.perform.code).to eq(304) end it "should report 304 with a DELETE request" do @request.http_method = Net::HTTP::Delete expect(@request.perform.code).to eq(304) end it "should report 304 with a MOVE request" do @request.http_method = Net::HTTP::Move expect(@request.perform.code).to eq(304) end it "should report 304 with a COPY request" do @request.http_method = Net::HTTP::Copy expect(@request.perform.code).to eq(304) end it "should report 304 with a PATCH request" do @request.http_method = Net::HTTP::Patch expect(@request.perform.code).to eq(304) end it "should report 304 with a PUT request" do @request.http_method = Net::HTTP::Put expect(@request.perform.code).to eq(304) end it "should report 304 with a HEAD request" do @request.http_method = Net::HTTP::Head expect(@request.perform.code).to eq(304) end it "should report 304 with a OPTIONS request" do @request.http_method = Net::HTTP::Options expect(@request.perform.code).to eq(304) end it "should report 304 with a MKCOL request" do @request.http_method = Net::HTTP::Mkcol expect(@request.perform.code).to eq(304) end it 'should not log the redirection' do logger_double = double expect(logger_double).to receive(:info).once @request.options[:logger] = logger_double @request.perform end end [307, 308].each do |code| describe "a request that #{code} redirects" do before(:each) do @redirect = stub_response("", code) @redirect['location'] = '/foo' @ok = stub_response('bar', 200) end describe "once" do before(:each) do allow(@http).to receive(:request).and_return(@redirect, @ok) end it "should be handled by GET transparently" do expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by POST transparently" do @request.http_method = Net::HTTP::Post expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by DELETE transparently" do @request.http_method = Net::HTTP::Delete expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by MOVE transparently" do @request.http_method = Net::HTTP::Move expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by COPY transparently" do @request.http_method = Net::HTTP::Copy expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by PATCH transparently" do @request.http_method = Net::HTTP::Patch expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by PUT transparently" do @request.http_method = Net::HTTP::Put expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by HEAD transparently" do @request.http_method = Net::HTTP::Head expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by OPTIONS transparently" do @request.http_method = Net::HTTP::Options expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should be handled by MKCOL transparently" do @request.http_method = Net::HTTP::Mkcol expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) end it "should keep track of cookies between redirects" do @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly' @request.perform expect(@request.options[:headers]['Cookie']).to match(/foo=bar/) expect(@request.options[:headers]['Cookie']).to match(/name=value/) end it 'should update cookies with redirects' do @request.options[:headers] = {'Cookie' => 'foo=bar;'} @redirect['Set-Cookie'] = 'foo=tar;' @request.perform expect(@request.options[:headers]['Cookie']).to match(/foo=tar/) end it 'should keep cookies between redirects' do @request.options[:headers] = {'Cookie' => 'keep=me'} @redirect['Set-Cookie'] = 'foo=tar;' @request.perform expect(@request.options[:headers]['Cookie']).to 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 expect(@request.options[:headers]['Cookie']).to match(/foo=bar/) expect(@request.options[:headers]['Cookie']).to match(/name=value/) expect(@request.options[:headers]['Cookie']).to match(/one=1/) expect(@request.options[:headers]['Cookie']).to match(/two=2/) end it 'should maintain method in resulting request' do @request.http_method = Net::HTTP::Delete expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) expect(@request.http_method).to eq(Net::HTTP::Delete) end it 'should maintain method in resulting request if options[:maintain_method_across_redirects] is false' do @request.options[:maintain_method_across_redirects] = false @request.http_method = Net::HTTP::Delete expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) expect(@request.http_method).to eq(Net::HTTP::Delete) end it 'should maintain method in resulting request if options[:maintain_method_across_redirects] is true' do @request.options[:maintain_method_across_redirects] = true @request.http_method = Net::HTTP::Delete expect(@request.perform.parsed_response).to eq({"hash" => {"foo" => "bar"}}) expect(@request.http_method).to eq(Net::HTTP::Delete) end it 'should log the redirection' do logger_double = double expect(logger_double).to receive(:info).twice @request.options[:logger] = logger_double @request.perform end end describe "infinitely" do before(:each) do allow(@http).to receive(:request).and_return(@redirect) end it "should raise an exception" do expect { @request.perform }.to raise_error(HTTParty::RedirectionTooDeep) end end end end describe "#send_authorization_header?" do context "basic_auth" do before do @credentials = { username: "username", password: "password" } @authorization = "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" @request.options[:basic_auth] = @credentials @redirect = stub_response("", 302) @ok = stub_response('bar', 200) end before(:each) do allow(@http).to receive(:request).and_return(@redirect, @ok) end it "should not send Authorization header when redirecting to a different host" do @redirect['location'] = 'http://example.com/' @request.perform @request.send(:setup_raw_request) expect(@request.instance_variable_get(:@raw_request)['authorization']).to be_nil end it "should send Authorization header when redirecting to a relative path" do @redirect['location'] = '/v3' @request.perform @request.send(:setup_raw_request) expect(@request.instance_variable_get(:@raw_request)['authorization']).to eq(@authorization) end it "should send Authorization header when redirecting to the same host" do @redirect['location'] = 'http://api.foo.com/v2' @request.perform @request.send(:setup_raw_request) expect(@request.instance_variable_get(:@raw_request)['authorization']).to eq(@authorization) end it "should send Authorization header when redirecting to a different port on the same host" do @redirect['location'] = 'http://api.foo.com:3000/v3' @request.perform @request.send(:setup_raw_request) expect(@request.instance_variable_get(:@raw_request)['authorization']).to eq(@authorization) end end end context "with POST http method" do it "should raise argument error if query is not a hash" do expect { HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', format: :xml, query: 'astring').perform }.to raise_error(ArgumentError) end end describe "argument validation" do it "should raise argument error if basic_auth and digest_auth are both present" do expect { HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', basic_auth: {}, digest_auth: {}).perform }.to 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 expect { HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', basic_auth: %w(foo bar)).perform }.to raise_error(ArgumentError, ":basic_auth must be a hash") end it "should raise argument error if digest_auth is not a hash" do expect { HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', digest_auth: %w(foo bar)).perform }.to raise_error(ArgumentError, ":digest_auth must be a hash") end it "should raise argument error if headers is not a hash" do expect { HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', headers: %w(foo bar)).perform }.to raise_error(ArgumentError, ":headers must be a hash") end it "should raise argument error if options method is not http accepted method" do expect { HTTParty::Request.new('SuperPost', 'http://api.foo.com/v1').perform }.to raise_error(ArgumentError, "only get, post, patch, put, delete, head, and options methods are supported") end it "should raise argument error if http method is post and query is not hash" do expect { HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', query: "message: hello").perform }.to raise_error(ArgumentError, ":query must be hash if using HTTP Post") end it "should raise RedirectionTooDeep error if limit is negative" do expect { HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', limit: -1).perform }.to raise_error(HTTParty::RedirectionTooDeep, 'HTTP redirects too deep') end end context 'with Accept-Encoding header' do it 'should disable content decoding if present' do request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', headers:{'Accept-Encoding' => 'custom'}) request.send(:setup_raw_request) expect(request.instance_variable_get(:@raw_request).decode_content).to eq(false) end it 'should disable content decoding if present and lowercase' do request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', headers:{'accept-encoding' => 'custom'}) request.send(:setup_raw_request) expect(request.instance_variable_get(:@raw_request).decode_content).to eq(false) end it 'should disable content decoding if present' do request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1') request.send(:setup_raw_request) expect(request.instance_variable_get(:@raw_request).decode_content).to eq(true) end end end httparty-0.15.6/.travis.yml0000644000004100000410000000021613145325011015615 0ustar www-datawww-datalanguage: ruby rvm: - 2.0.0 - 2.1.8 - 2.2.4 - 2.3.0 - 2.4.1 bundler_args: --without development before_install: gem install bundler httparty-0.15.6/lib/0000755000004100000410000000000013145325011014253 5ustar www-datawww-datahttparty-0.15.6/lib/httparty.rb0000644000004100000410000005131213145325011016461 0ustar www-datawww-datarequire 'pathname' require 'net/http' require 'net/https' require 'uri' require 'zlib' require 'multi_xml' require 'json' require 'csv' 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 def self.included(base) base.extend ClassMethods base.send :include, 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 an object that responds to #to_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 an object that responds to #to_hash representing it. Normalized according to the same rules as :+body+. If you specify this on a POST, you must use an object which responds to #to_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. # [:+body_stream:] Allow streaming to a REST server to specify a body_stream. # [:+stream_body:] Allow for streaming large files without loading them into memory. # # 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 an object which responds to #to_hash. # * :+maintain_method_across_redirects+: see HTTParty::ClassMethods.maintain_method_across_redirects. # * :+no_follow+: see HTTParty::ClassMethods.no_follow. # * :+parser+: see HTTParty::ClassMethods.parser. # * :+uri_adapter+: see HTTParty::ClassMethods.uri_adapter # * :+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 # 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 # Raises HTTParty::ResponseError if response's code matches this statuses # # class Foo # include HTTParty # raise_on [404, 500] # end def raise_on(codes = []) default_options[:raise_on] = *codes 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. # Specifically, 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 an object which responds to #to_hash' unless h.respond_to?(:to_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 # Allows setting a default open_timeout for all HTTP calls in seconds # # class Foo # include HTTParty # open_timeout 10 # end def open_timeout(t) raise ArgumentError, 'open_timeout must be an integer or float' unless t && (t.is_a?(Integer) || t.is_a?(Float)) default_options[:open_timeout] = t end # Allows setting a default read_timeout for all HTTP calls in seconds # # class Foo # include HTTParty # read_timeout 10 # end def read_timeout(t) raise ArgumentError, 'read_timeout must be an integer or float' unless t && (t.is_a?(Integer) || t.is_a?(Float)) default_options[:read_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 = nil) if h raise ArgumentError, 'Headers must be an object which responds to #to_hash' unless h.respond_to?(:to_hash) default_options[:headers] ||= {} default_options[:headers].merge!(h.to_hash) else default_options[:headers] || {} end end def cookies(h = {}) raise ArgumentError, 'Cookies must be an object which responds to #to_hash' unless h.respond_to?(:to_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, except # if you are making a HEAD request, in which case the default is to # follow all redirects with HEAD requests. # 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 # Declare that you wish to resend the full HTTP request across redirects, # even on redirects that should logically become GET requests. # A 303 redirect in HTTP signifies that the redirected url should normally # retrieved using a GET request, for instance, it is the output of a previous # POST. maintain_method_across_redirects respects this behavior, but you # can force HTTParty to resend_on_redirect even on 303 responses. # # @example # class Foo # include HTTParty # base_uri 'http://google.com' # resend_on_redirect # end def resend_on_redirect(value = true) default_options[:resend_on_redirect] = 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 # Allows setting a PKCS12 file to be used # # class Foo # include HTTParty # pkcs12 File.read('/home/user/my.p12'), "password" # end def pkcs12(p12_contents, password) default_options[:p12] = p12_contents default_options[:p12_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 URI adapter. # # class Foo # include HTTParty # uri_adapter Addressable::URI # end def uri_adapter(uri_adapter) raise ArgumentError, 'The URI adapter should respond to #parse' unless uri_adapter.respond_to?(:parse) default_options[:uri_adapter] = uri_adapter 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 appends the parameters to the URI. # 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) ensure_method_maintained_across_redirects options 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 # Perform a MKCOL request to a path def mkcol(path, options = {}, &block) perform_request Net::HTTP::Mkcol, path, options, &block end attr_reader :default_options private def ensure_method_maintained_across_redirects(options) unless options.key?(:maintain_method_across_redirects) options[:maintain_method_across_redirects] = true end end def perform_request(http_method, path, options, &block) #:nodoc: options = ModuleInheritableAttributes.hash_deep_dup(default_options).merge(options) process_headers(options) process_cookies(options) Request.new(http_method, path, options).perform(&block) end def process_headers(options) if options[:headers] && headers.any? options[:headers] = headers.merge(options[:headers]) end 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(&: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.copy(*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/hash_conversions' require 'httparty/exceptions' require 'httparty/parser' require 'httparty/request' require 'httparty/response' httparty-0.15.6/lib/httparty/0000755000004100000410000000000013145325011016132 5ustar www-datawww-datahttparty-0.15.6/lib/httparty/net_digest_auth.rb0000644000004100000410000000634013145325011021630 0ustar www-datawww-datarequire 'digest/md5' require 'net/http' module Net module HTTPHeader def digest_auth(username, password, response) authenticator = DigestAuthenticator.new( username, password, @method, @path, response ) authenticator.authorization_header.each do |v| add_field('Authorization', v) end authenticator.cookie_header.each do |v| add_field('Cookie', v) end end class DigestAuthenticator def initialize(username, password, method, path, response_header) @username = username @password = password @method = method @path = path @response = parse(response_header) @cookies = parse_cookies(response_header) end def authorization_header @cnonce = md5(random) header = [ %(Digest username="#{@username}"), %(realm="#{@response['realm']}"), %(nonce="#{@response['nonce']}"), %(uri="#{@path}"), %(response="#{request_digest}") ] header << %(algorithm="#{@response['algorithm']}") if algorithm_present? if qop_present? fields = [ %(cnonce="#{@cnonce}"), %(qop="#{@response['qop']}"), "nc=00000001" ] fields.each { |field| header << field } end header << %(opaque="#{@response['opaque']}") if opaque_present? header end def cookie_header @cookies end private def parse(response_header) header = response_header['www-authenticate'] .gsub(/qop=(auth(?:-int)?)/, 'qop="\\1"') header =~ /Digest (.*)/ params = {} if $1 non_quoted = $1.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 } non_quoted.gsub(/(\w+)=([^,]*)/) { params[$1] = $2 } end params end def parse_cookies(response_header) return [] unless response_header['Set-Cookie'] cookies = response_header['Set-Cookie'].split('; ') cookies.reduce([]) do |ret, cookie| ret << cookie ret end cookies end def opaque_present? @response.key?('opaque') && !@response['opaque'].empty? end def qop_present? @response.key?('qop') && !@response['qop'].empty? end def random format "%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 algorithm_present? @response.key?('algorithm') && !@response['algorithm'].empty? end def use_md5_sess? algorithm_present? && @response['algorithm'] == 'MD5-sess' end def a1 a1_user_realm_pwd = [@username, @response['realm'], @password].join(':') if use_md5_sess? [ md5(a1_user_realm_pwd), @response['nonce'], @cnonce ].join(':') else a1_user_realm_pwd end end def a2 [@method, @path].join(":") end end end end httparty-0.15.6/lib/httparty/response.rb0000644000004100000410000000554313145325011020324 0ustar www-datawww-datamodule HTTParty class Response < Object 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 throw_exception end def parsed_response @parsed_response ||= @parsed_block.call end def code response.code.to_i end def tap yield self self end def inspect inspect_id = ::Kernel::format "%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", '') name = "#{underscore(name)}?".to_sym define_method(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 nil? response.nil? || response.body.nil? || response.body.empty? end def to_s if !response.nil? && !response.body.nil? && response.body.respond_to?(:to_s) response.body.to_s else inspect end end def display(port=$>) if !parsed_response.nil? && parsed_response.respond_to?(:display) parsed_response.display(port) elsif !response.nil? && !response.body.nil? && response.body.respond_to?(:display) response.body.display(port) else port.write(inspect) end end def respond_to_missing?(name, *args) return true if super 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 def throw_exception if @request.options[:raise_on] && @request.options[:raise_on].include?(code) ::Kernel.raise ::HTTParty::ResponseError.new(@response), "Code #{code} - #{body}" end end end end require 'httparty/response/headers' httparty-0.15.6/lib/httparty/logger/0000755000004100000410000000000013145325011017411 5ustar www-datawww-datahttparty-0.15.6/lib/httparty/logger/apache_formatter.rb0000644000004100000410000000136513145325011023247 0ustar www-datawww-datamodule HTTParty module Logger class ApacheFormatter #: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.respond_to?(:headers) ? response.headers['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.15.6/lib/httparty/logger/curl_formatter.rb0000644000004100000410000000416013145325011022767 0ustar www-datawww-datamodule HTTParty module Logger class CurlFormatter #:nodoc: TAG_NAME = HTTParty.name OUT = '>'.freeze IN = '<'.freeze attr_accessor :level, :logger def initialize(logger, level) @logger = logger @level = level.to_sym @messages = [] end def format(request, response) @request = request @response = response log_request log_response logger.send level, messages.join("\n") end private attr_reader :request, :response attr_accessor :messages def log_request log_url log_headers log_query log OUT, request.raw_body if request.raw_body log OUT end def log_response log IN, "HTTP/#{response.http_version} #{response.code}" log_response_headers log IN, "\n#{response.body}" log IN end def log_url http_method = request.http_method.name.split("::").last.upcase uri = if request.options[:base_uri] request.options[:base_uri] + request.path.path else request.path.to_s end log OUT, "#{http_method} #{uri}" end def log_headers return unless request.options[:headers] && request.options[:headers].size > 0 log OUT, 'Headers: ' log_hash request.options[:headers] end def log_query return unless request.options[:query] log OUT, 'Query: ' log_hash request.options[:query] end def log_response_headers headers = response.respond_to?(:headers) ? response.headers : response response.each_header do |response_header| log IN, "#{response_header.capitalize}: #{headers[response_header]}" end end def log_hash(hash) hash.each { |k, v| log(OUT, "#{k}: #{v}") } end def log(direction, line = '') messages << "[#{TAG_NAME}] [#{time}] #{direction} #{line}" end def time @time ||= Time.now.strftime("%Y-%m-%d %H:%M:%S %z") end end end end httparty-0.15.6/lib/httparty/logger/logger.rb0000644000004100000410000000127513145325011021222 0ustar www-datawww-datarequire 'httparty/logger/apache_formatter' require 'httparty/logger/curl_formatter' module HTTParty module Logger def self.formatters @formatters ||= { :curl => Logger::CurlFormatter, :apache => Logger::ApacheFormatter } end def self.add_formatter(name, formatter) raise HTTParty::Error.new("Log Formatter with name #{name} already exists") if formatters.include?(name) formatters.merge!(name.to_sym => formatter) end def self.build(logger, level, formatter) level ||= :info formatter ||= :apache logger_klass = formatters[formatter] || Logger::ApacheFormatter logger_klass.new(logger, level) end end end httparty-0.15.6/lib/httparty/parser.rb0000644000004100000410000000740113145325011017755 0ustar www-datawww-datamodule HTTParty # The default parser used by HTTParty, supports xml, json, html, csv 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, 'text/csv' => :csv, 'application/csv' => :csv, 'text/comma-separated-values' => :csv } # 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? return nil if body == "null" return nil if body.valid_encoding? && body.strip.empty? if body.valid_encoding? && body.encoding == Encoding::UTF_8 @body = body.gsub(/\A#{UTF8_BOM}/, '') end if supports_format? parse_supported_format else body end end protected def xml MultiXml.parse(body) end UTF8_BOM = "\xEF\xBB\xBF".freeze def json JSON.parse(body, :quirks_mode => true, :allow_nan => true) end def csv CSV.parse(body) 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.15.6/lib/httparty/response/0000755000004100000410000000000013145325011017770 5ustar www-datawww-datahttparty-0.15.6/lib/httparty/response/headers.rb0000644000004100000410000000144013145325011021727 0ustar www-datawww-datarequire 'delegate' module HTTParty class Response #:nodoc: class Headers < ::SimpleDelegator include ::Net::HTTPHeader def initialize(header_values = nil) @header = {} if header_values header_values.each_pair do |k,v| if v.is_a?(Array) v.each do |sub_v| add_field(k, sub_v) end else add_field(k, v) end end end super(@header) end def ==(other) if other.is_a?(::Net::HTTPHeader) @header == other.instance_variable_get(:@header) elsif other.is_a?(Hash) @header == other || @header == Headers.new(other).instance_variable_get(:@header) end end end end end httparty-0.15.6/lib/httparty/connection_adapter.rb0000644000004100000410000001646513145325011022332 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. # The keys used in options are # * :+timeout+: timeout in seconds # * :+open_timeout+: http connection open_timeout in seconds, overrides timeout if set # * :+read_timeout+: http connection read_timeout in seconds, overrides timeout if set # * :+debug_output+: see HTTParty::ClassMethods.debug_output. # * :+cert_store+: contains certificate data. see method 'attach_ssl_certificates' # * :+pem+: contains pem client certificate data. see method 'attach_ssl_certificates' # * :+p12+: contains PKCS12 client client certificate data. see method 'attach_ssl_certificates' # * :+verify+: verify the server’s certificate against the ca certificate. # * :+verify_peer+: set to false to turn off server verification but still send client certificate # * :+ssl_ca_file+: see HTTParty::ClassMethods.ssl_ca_file. # * :+ssl_ca_path+: see HTTParty::ClassMethods.ssl_ca_path. # * :+ssl_version+: SSL versions to allow. see method 'attach_ssl_certificates' # * :+ciphers+: The list of SSL ciphers to support # * :+connection_adapter_options+: contains the hash you passed to HTTParty.connection_adapter when you configured your connection adapter # * :+local_host+: The local address to bind to # * :+local_port+: The local port to bind to # * :+http_proxyaddr+: HTTP Proxy address # * :+http_proxyport+: HTTP Proxy port # * :+http_proxyuser+: HTTP Proxy user # * :+http_proxypass+: HTTP Proxy password # # === Inherited methods # * :+clean_host+: Method used to sanitize host names class ConnectionAdapter # Private: Regex used to strip brackets from IPv6 URIs. StripIpv6BracketsRegex = /\A\[(.*)\]\z/ OPTION_DEFAULTS = { verify: true, verify_peer: true } # Public def self.call(uri, options) new(uri, options).connection end attr_reader :uri, :options def initialize(uri, options = {}) uri_adapter = options[:uri_adapter] || URI raise ArgumentError, "uri must be a #{uri_adapter}, not a #{uri.class}" unless uri.is_a? uri_adapter @uri = uri @options = OPTION_DEFAULTS.merge(options) end def connection host = clean_host(uri.host) port = uri.port || (uri.scheme == 'https' ? 443 : 80) if options.key?(:http_proxyaddr) http = Net::HTTP.new(host, port, options[:http_proxyaddr], options[:http_proxyport], options[:http_proxyuser], options[:http_proxypass]) else http = Net::HTTP.new(host, 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[:read_timeout] && (options[:read_timeout].is_a?(Integer) || options[:read_timeout].is_a?(Float)) http.read_timeout = options[:read_timeout] end if options[:open_timeout] && (options[:open_timeout].is_a?(Integer) || options[:open_timeout].is_a?(Float)) http.open_timeout = options[:open_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 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.scheme == 'https' end def verify_ssl_certificate? !(options[:verify] == false || options[:verify_peer] == false) 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 # Note: options[:pem] must contain the content of a PEM file having the private key appended 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 = verify_ssl_certificate? ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE end # PKCS12 client certificate authentication if options[:p12] p12 = OpenSSL::PKCS12.new(options[:p12], options[:p12_password]) http.cert = p12.certificate http.key = p12.key http.verify_mode = verify_ssl_certificate? ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE 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.15.6/lib/httparty/request.rb0000644000004100000410000003060313145325011020151 0ustar www-datawww-datarequire 'erb' module HTTParty class Request #:nodoc: SupportedHTTPMethods = [ Net::HTTP::Get, Net::HTTP::Post, Net::HTTP::Patch, Net::HTTP::Put, Net::HTTP::Delete, Net::HTTP::Head, Net::HTTP::Options, Net::HTTP::Move, Net::HTTP::Copy, Net::HTTP::Mkcol, ] SupportedURISchemes = ['http', 'https', 'webcal', nil] NON_RAILS_QUERY_STRING_NORMALIZER = proc do |query| Array(query).sort_by { |a| a[0].to_s }.map do |key, value| if value.nil? key.to_s elsif value.respond_to?(:to_ary) value.to_ary.map {|v| "#{key}=#{ERB::Util.url_encode(v.to_s)}"} else HashConversions.to_params(key => value) end end.flatten.join('&') end JSON_API_QUERY_STRING_NORMALIZER = proc do |query| Array(query).sort_by { |a| a[0].to_s }.map do |key, value| if value.nil? key.to_s elsif value.respond_to?(:to_ary) values = value.to_ary.map{|v| ERB::Util.url_encode(v.to_s)} "#{key}=#{values.join(',')}" else HashConversions.to_params(key => value) end end.flatten.join('&') end attr_accessor :http_method, :options, :last_response, :redirect, :last_uri attr_reader :path def initialize(http_method, path, o = {}) @changed_hosts = false @credentials_sent = false self.http_method = http_method self.options = { limit: o.delete(:no_follow) ? 1 : 5, assume_utf16_is_big_endian: true, default_params: {}, follow_redirects: true, parser: Parser, uri_adapter: URI, connection_adapter: ConnectionAdapter }.merge(o) self.path = path set_basic_auth_from_uri end def path=(uri) uri_adapter = options[:uri_adapter] @path = if uri.is_a?(uri_adapter) uri elsif String.try_convert(uri) uri_adapter.parse uri else raise ArgumentError, "bad argument (expected #{uri_adapter} object or URI string)" end end def request_uri(uri) if uri.respond_to? :request_uri uri.request_uri else uri.path end end def uri if redirect && path.relative? && path.path[0] != "/" last_uri_host = @last_uri.path.gsub(/[^\/]+$/, "") path.path = "/#{path.path}" if last_uri_host[-1] != "/" path.path = last_uri_host + path.path end if path.relative? && path.host new_uri = options[:uri_adapter].parse("#{@last_uri.scheme}:#{path}") elsif path.relative? new_uri = options[:uri_adapter].parse("#{base_uri}#{path}") else new_uri = path.clone end # avoid double query string on redirects [#12] unless redirect new_uri.query = query_string(new_uri) end unless SupportedURISchemes.include? new_uri.scheme raise UnsupportedURIScheme, "'#{new_uri}' Must be HTTP, HTTPS or Generic" end @last_uri = new_uri end def base_uri if redirect base_uri = "#{@last_uri.scheme}://#{@last_uri.host}" base_uri += ":#{@last_uri.port}" if @last_uri.port != 80 base_uri else options[:base_uri] && HTTParty.normalize_base_uri(options[:base_uri]) end 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 unless options[:stream_body] block.call(fragment) end chunked_body = chunks.join end end handle_host_redirection if response_redirects? result = handle_unauthorized result ||= handle_response(chunked_body, &block) result end def handle_unauthorized(&block) return unless digest_auth? && response_unauthorized? && response_has_digest_auth_challenge? return if @credentials_sent @credentials_sent = true perform(&block) end def raw_body @raw_request.body end private def http connection_adapter.call(uri, options) end def body options[:body].respond_to?(:to_hash) ? normalize_query(options[:body]) : options[:body] end def credentials (options[:basic_auth] || options[:digest_auth]).to_hash 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.body_stream = options[:body_stream] if options[:body_stream] if options[:headers].respond_to?(:to_hash) headers_hash = options[:headers].to_hash @raw_request.initialize_http_header(headers_hash) # If the caller specified a header of 'Accept-Encoding', assume they want to # deal with encoding of content. Disable the internal logic in Net:HTTP # that handles encoding, if the platform supports it. if @raw_request.respond_to?(:decode_content) && (headers_hash.key?('Accept-Encoding') || headers_hash.key?('accept-encoding')) # Using the '[]=' sets decode_content to false @raw_request['accept-encoding'] = @raw_request['accept-encoding'] end end if options[:basic_auth] && send_authorization_header? @raw_request.basic_auth(username, password) @credentials_sent = true end setup_digest_auth if digest_auth? && response_unauthorized? && response_has_digest_auth_challenge? end def digest_auth? !!options[:digest_auth] end def response_unauthorized? !!last_response && last_response.code == '401' end def response_has_digest_auth_challenge? !last_response['www-authenticate'].nil? && last_response['www-authenticate'].length > 0 end def setup_digest_auth @raw_request.digest_auth(username, password, last_response) end def query_string(uri) query_string_parts = [] query_string_parts << uri.query unless uri.query.nil? if options[:query].respond_to?(:to_hash) query_string_parts << normalize_query(options[:default_params].merge(options[:query].to_hash)) 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.reject!(&:empty?) unless query_string_parts == [""] 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) encoding = Encoding.find(charset) body.force_encoding(charset) rescue ArgumentError body 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 if last_response.class == Net::HTTPSeeOther unless options[:maintain_method_across_redirects] && options[:resend_on_redirect] self.http_method = Net::HTTP::Get end elsif last_response.code != '307' && last_response.code != '308' unless options[:maintain_method_across_redirects] self.http_method = Net::HTTP::Get end end capture_cookies(last_response) perform(&block) else body ||= last_response.body body = body.nil? ? body : encode_body(body) Response.new(self, last_response, lambda { parse_response(body) }, body: body) end end def handle_host_redirection check_duplicate_location_header redirect_path = options[:uri_adapter].parse last_response['location'] return if redirect_path.relative? || path.host == redirect_path.host @changed_hosts = true end def check_duplicate_location_header location = last_response.get_fields('location') if location.is_a?(Array) && location.count > 1 raise DuplicateLocationHeader.new(last_response) end end def send_authorization_header? !@changed_hosts end def response_redirects? case last_response when Net::HTTPNotModified # 304 false when Net::HTTPRedirection 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].to_hash['Cookie']) if options[:headers] && options[:headers].to_hash['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].respond_to?(:to_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].respond_to?(:to_hash) raise ArgumentError, ':digest_auth must be a hash' if options[:digest_auth] && !options[:digest_auth].respond_to?(:to_hash) raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].respond_to?(:to_hash) end def post? Net::HTTP::Post == http_method end def set_basic_auth_from_uri if path.userinfo username, password = path.userinfo.split(':') options[:basic_auth] = {username: username, password: password} @credentials_sent = true end end end end httparty-0.15.6/lib/httparty/version.rb0000644000004100000410000000005113145325011020140 0ustar www-datawww-datamodule HTTParty VERSION = "0.15.6" end httparty-0.15.6/lib/httparty/hash_conversions.rb0000644000004100000410000000306113145325011022032 0ustar www-datawww-datarequire 'erb' module 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) hash.to_hash.map { |k, v| normalize_param(k, v) }.join.chop 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.respond_to?(:to_ary) param << if value.empty? "#{key}[]=&" else value.to_ary.map { |element| normalize_param("#{key}[]", element) }.join end elsif value.respond_to?(:to_hash) stack << [key, value.to_hash] else param << "#{key}=#{ERB::Util.url_encode(value.to_s)}&" end stack.each do |parent, hash| hash.each do |k, v| if v.respond_to?(:to_hash) stack << ["#{parent}[#{k}]", v.to_hash] else param << normalize_param("#{parent}[#{k}]", v) end end end param end end end httparty-0.15.6/lib/httparty/cookie_hash.rb0000644000004100000410000000104113145325011020727 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 reject { |k, v| CLIENT_COOKIES.include?(k.to_s.downcase) }.collect { |k, v| "#{k}=#{v}" }.join("; ") end end httparty-0.15.6/lib/httparty/module_inheritable_attributes.rb0000644000004100000410000000273613145325011024570 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.15.6/lib/httparty/exceptions.rb0000644000004100000410000000227313145325011020644 0ustar www-datawww-datamodule HTTParty # @abstact Exceptions raised by HTTParty inherit from Error class Error < StandardError; end # Exception raised when you attempt to set a non-existent format class UnsupportedFormat < Error; end # Exception raised when using a URI scheme other than HTTP or HTTPS class UnsupportedURIScheme < Error; end # @abstract Exceptions which inherit from ResponseError contain the Net::HTTP # response object accessible via the {#response} method. class ResponseError < Error # 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 super(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 # Exception that is raised when request redirects and location header is present more than once class DuplicateLocationHeader < ResponseError; end end httparty-0.15.6/cucumber.yml0000644000004100000410000000004413145325011016033 0ustar www-datawww-datadefault: features --format progress httparty-0.15.6/.rubocop.yml0000644000004100000410000000413213145325011015757 0ustar www-datawww-datainherit_from: .rubocop_todo.yml # Offense count: 963 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. Style/StringLiterals: Enabled: false # Offense count: 327 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SupportedStyles. Style/SpaceInsideHashLiteralBraces: Enabled: false # Offense count: 33 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. Style/SpaceInsideBlockBraces: Enabled: false # Offense count: 1 # Cop supports --auto-correct. Style/SpaceBeforeSemicolon: Enabled: false # Offense count: 20 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. Style/SignalException: Enabled: false # Offense count: 1 # Configuration parameters: Methods. Style/SingleLineBlockParams: Enabled: false # Offense count: 6 # Cop supports --auto-correct. Style/PerlBackrefs: Enabled: false # Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: AllowAsExpressionSeparator. Style/Semicolon: Enabled: false # Offense count: 77 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. Style/BracesAroundHashParameters: Enabled: false # Offense count: 36 Style/Documentation: Enabled: false # Offense count: 6 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes. Style/RegexpLiteral: Enabled: false # Offense count: 5 # Cop supports --auto-correct. Style/NumericLiterals: MinDigits: 6 # Offense count: 4 # Cop supports --auto-correct. Lint/UnusedMethodArgument: Enabled: false # Offense count: 11 # Cop supports --auto-correct. Lint/UnusedBlockArgument: Enabled: false # Offense count: 1 Lint/Void: Enabled: false # Offense count: 22 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. Style/IndentHash: Enabled: false # Offense count: 7 # Configuration parameters: MinBodyLength. Style/GuardClause: Enabled: false httparty-0.15.6/httparty.gemspec0000644000004100000410000000214113145325011016727 0ustar www-datawww-data# -*- encoding: utf-8 -*- $LOAD_PATH.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.licenses = ['MIT'] s.authors = ["John Nunemaker", "Sandro Turriate"] s.email = ["nunemaker@gmail.com"] s.homepage = "http://jnunemaker.github.com/httparty" s.summary = 'Makes http fun! Also, makes consuming restful web services dead easy.' s.description = 'Makes http fun! Also, makes consuming restful web services dead easy.' s.required_ruby_version = '>= 2.0.0' s.add_dependency 'multi_xml', ">= 0.5.2" # If this line is removed, all hard partying will cease. s.post_install_message = "When you HTTParty, you must party hard!" all_files = `git ls-files`.split("\n") test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.files = all_files - test_files s.test_files = test_files s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) } s.require_paths = ["lib"] end httparty-0.15.6/.gitignore0000644000004100000410000000013113145325011015470 0ustar www-datawww-dataGemfile.lock .DS_Store .yardoc/ doc/ tmp/ log/ pkg/ *.swp /.bundle .rvmrc coverage *.gem httparty-0.15.6/docs/0000755000004100000410000000000013145325011014435 5ustar www-datawww-datahttparty-0.15.6/docs/README.md0000644000004100000410000000443013145325011015715 0ustar www-datawww-data# httparty Makes http fun again! ## Table of contents - [Parsing JSON](#parsing-json) - [Working with SSL](#working-with-ssl) ## Parsing JSON If the response Content Type is `application/json`, HTTParty will parse the response and return Ruby objects such as a hash or array. The default behavior for parsing JSON will return keys as strings. This can be supressed with the `format` option. To get hash keys as symbols: ``` response = HTTParty.get('http://example.com', format: :plain) JSON.parse response, symbolize_names: true ``` ## Working with SSL You can use this guide to work with SSL certificates. #### Using `pem` option ```ruby # Use this example if you are using a pem file class Client include HTTParty base_uri "https://example.com" pem File.read("#{File.expand_path('.')}/path/to/certs/cert.pem"), "123456" end ``` #### Using `pkcs12` option ```ruby # Use this example if you are using a pkcs12 file class Client include HTTParty base_uri "https://example.com" pkcs12 File.read("#{File.expand_path('.')}/path/to/certs/cert.p12"), "123456" end ``` #### Using `ssl_ca_file` option ```ruby # Use this example if you are using a pkcs12 file class Client include HTTParty base_uri "https://example.com" ssl_ca_file "#{File.expand_path('.')}/path/to/certs/cert.pem" end ``` #### Using `ssl_ca_path` option ```ruby # Use this example if you are using a pkcs12 file class Client include HTTParty base_uri "https://example.com" ssl_ca_path '/path/to/certs' end ``` You can also include this options with the call: ```ruby class Client include HTTParty base_uri "https://example.com" def self.fetch get("/resources", pem: (File.read("#{File.expand_path('.')}/path/to/certs/cert.pem"), "123456") end end ``` ### Avoid SSL verification In some cases you may want to skip SSL verification, because the entity that issue the certificate is not a valid one, but you still want to work with it. You can achieve this through: ```ruby # Skips SSL certificate verification class Client include HTTParty base_uri "https://example.com" pem File.read("#{File.expand_path('.')}/path/to/certs/cert.pem"), "123456" def self.fetch get("/resources", verify: false) # You can also use something like: # get("resources", verify_peer: false) end end ```httparty-0.15.6/CONTRIBUTING.md0000644000004100000410000000204413145325011015736 0ustar www-datawww-data# Contributing * Contributions will not be accepted without tests. * Please post unconfirmed bugs to the mailing list first: https://groups.google.com/forum/#!forum/httparty-gem * Don't change the version. The maintainers will handle that when they release. * Always provide as much information and reproducibility as possible when filing an issue or submitting a pull request. ## Workflow * Fork the project. * Run `bundle` * Run `bundle exec rake` * 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. * Run `bundle exec rake` (No, REALLY :)) * 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. ## Help and Docs * https://groups.google.com/forum/#!forum/httparty-gem * http://stackoverflow.com/questions/tagged/httparty * http://rdoc.info/projects/jnunemaker/httparty httparty-0.15.6/website/0000755000004100000410000000000013145325011015147 5ustar www-datawww-datahttparty-0.15.6/website/css/0000755000004100000410000000000013145325011015737 5ustar www-datawww-datahttparty-0.15.6/website/css/common.css0000644000004100000410000000435513145325011017750 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.15.6/website/index.html0000644000004100000410000000506413145325011017151 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.15.6/README.md0000644000004100000410000000425313145325011014770 0ustar www-datawww-data# httparty Makes http fun again! ## Install ``` gem install httparty ``` ## Requirements * Ruby 2.0.0 or higher * multi_xml * You like to party! ## Examples ```ruby # Use the class methods to get down to business quickly response = HTTParty.get('http://api.stackexchange.com/2.2/questions?site=stackoverflow') puts response.body, response.code, response.message, response.headers.inspect # Or wrap things up in your own class class StackExchange include HTTParty base_uri 'api.stackexchange.com' def initialize(service, page) @options = { query: { site: service, page: page } } end def questions self.class.get("/2.2/questions", @options) end def users self.class.get("/2.2/users", @options) end end stack_exchange = StackExchange.new("stackoverflow", 1) puts stack_exchange.questions puts stack_exchange.users ``` 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 "https://api.stackexchange.com/2.2/questions?site=stackoverflow" ``` ## Help and Docs * [Docs](https://github.com/jnunemaker/httparty/tree/master/docs) * https://groups.google.com/forum/#!forum/httparty-gem * http://rdoc.info/projects/jnunemaker/httparty * http://stackoverflow.com/questions/tagged/httparty ## Contributing * Fork the project. * Run `bundle` * Run `bundle exec rake` * 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. * Run `bundle exec rake` (No, REALLY :)) * 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.15.6/.simplecov0000644000004100000410000000004113145325011015502 0ustar www-datawww-dataSimpleCov.start "test_frameworks"httparty-0.15.6/Guardfile0000644000004100000410000000051413145325011015332 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