jugend-httparty 0.5.2.3 → 0.5.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History +25 -7
- data/Rakefile +4 -4
- data/VERSION +1 -1
- data/features/digest_authentication.feature +20 -0
- data/features/steps/env.rb +8 -1
- data/features/steps/httparty_steps.rb +8 -0
- data/features/steps/mongrel_helper.rb +22 -0
- data/features/steps/remote_service_steps.rb +11 -2
- data/features/supports_timeout_option.feature +1 -0
- data/jugend-httparty.gemspec +14 -12
- data/lib/httparty.rb +45 -6
- data/lib/httparty/net_digest_auth.rb +35 -0
- data/lib/httparty/request.rb +103 -91
- data/lib/httparty/response.rb +54 -10
- data/spec/httparty/request_spec.rb +38 -0
- data/spec/httparty/response_spec.rb +53 -32
- data/spec/httparty_spec.rb +31 -1
- data/spec/spec_helper.rb +6 -2
- data/spec/support/stub_response.rb +1 -1
- metadata +13 -12
    
        data/History
    CHANGED
    
    | @@ -1,12 +1,30 @@ | |
| 1 | 
            -
            == 0.5. | 
| 2 | 
            -
              *  | 
| 1 | 
            +
            == 0.5.3.4
         | 
| 2 | 
            +
              * Update gem name to jugend-httparty
         | 
| 3 | 
            +
              
         | 
| 4 | 
            +
            == 0.5.3.3
         | 
| 5 | 
            +
              * Remove RubyforgeTasks
         | 
| 6 | 
            +
              
         | 
| 7 | 
            +
            == 0.5.3.2
         | 
| 8 | 
            +
              * Remove deprecated rubyforge gem push
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
            == 0.5.3.1
         | 
| 11 | 
            +
              * Update Pathname initialization to support earlier version of ruby (<=1.8.4)
         | 
| 3 12 |  | 
| 4 | 
            -
            == 0.5. | 
| 5 | 
            -
             | 
| 13 | 
            +
            == 0.5.3 (master)
         | 
| 14 | 
            +
            * major enhancements
         | 
| 15 | 
            +
              * Digest Auth (bartiaco, sbecker, gilles, and aaronrussell)
         | 
| 16 | 
            +
              * Maintain HTTP method across redirects (bartiaco and sbecker)
         | 
| 17 | 
            +
              * HTTParty::Response#response returns the Net::HTTPResponse object
         | 
| 18 | 
            +
              * HTTParty::Response#headers returns a HTTParty::Response::Headers object
         | 
| 19 | 
            +
                which quacks like a Hash + Net::HTTPHeader. The #headers method continues
         | 
| 20 | 
            +
                to be backwards-compatible with the old Hash return value but may become
         | 
| 21 | 
            +
                deprecated in the future.
         | 
| 6 22 |  | 
| 7 | 
            -
             | 
| 8 | 
            -
              * Update  | 
| 9 | 
            -
             | 
| 23 | 
            +
            * minor enhancements
         | 
| 24 | 
            +
              * Update crack requirement to version 0.1.7
         | 
| 25 | 
            +
                You may still get a warning because Crack's version constant is out of date
         | 
| 26 | 
            +
              * Timeout option can be set for all requests using HTTParty.default_timeout (taazza)
         | 
| 27 | 
            +
              * Closed #38 "headers hash should downcase keys so canonical header name can be used"
         | 
| 10 28 |  | 
| 11 29 | 
             
            == 0.5.2 2010-01-31
         | 
| 12 30 | 
             
            * minor enhancements
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -7,14 +7,14 @@ begin | |
| 7 7 | 
             
                gem.summary = %Q{Makes http fun! Also, makes consuming restful web services dead easy.}
         | 
| 8 8 | 
             
                gem.description = %Q{Makes http fun! Also, makes consuming restful web services dead easy.}
         | 
| 9 9 | 
             
                gem.email = "nunemaker@gmail.com"
         | 
| 10 | 
            -
                gem.homepage = "http://httparty | 
| 10 | 
            +
                gem.homepage = "http://github.com/jugend/httparty"
         | 
| 11 11 | 
             
                gem.authors = ["John Nunemaker", "Sandro Turriate"]
         | 
| 12 | 
            -
                gem.add_dependency 'crack', '0.1. | 
| 12 | 
            +
                gem.add_dependency 'crack', '0.1.7'
         | 
| 13 13 | 
             
                gem.add_development_dependency "activesupport", "~>2.3"
         | 
| 14 | 
            -
                gem.add_development_dependency "cucumber", "~>0. | 
| 14 | 
            +
                gem.add_development_dependency "cucumber", "~>0.7"
         | 
| 15 15 | 
             
                gem.add_development_dependency "fakeweb", "~>1.2"
         | 
| 16 16 | 
             
                gem.add_development_dependency "mongrel", "~>1.1"
         | 
| 17 | 
            -
                gem.add_development_dependency "rspec", "1. | 
| 17 | 
            +
                gem.add_development_dependency "rspec", "~>1.3"
         | 
| 18 18 | 
             
                gem.post_install_message = "When you HTTParty, you must party hard!"
         | 
| 19 19 | 
             
                # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
         | 
| 20 20 | 
             
              end
         | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0.5. | 
| 1 | 
            +
            0.5.3.4
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            Feature:  Digest Authentication
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              As a developer
         | 
| 4 | 
            +
              I want to be able to use a service that requires Digest Authentication
         | 
| 5 | 
            +
              Because that is not an uncommon requirement
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              Scenario: Passing no credentials to a page requiring Digest Authentication
         | 
| 8 | 
            +
                Given a restricted page at '/protected.html'
         | 
| 9 | 
            +
                When I call HTTParty#get with '/protected.html'
         | 
| 10 | 
            +
                Then it should return a response with a 401 response code
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              Scenario: Passing proper credentials to a page requiring Digest Authentication
         | 
| 13 | 
            +
                Given a remote service that returns 'Digest Authenticated Page'
         | 
| 14 | 
            +
                And that service is accessed at the path '/protected.html'
         | 
| 15 | 
            +
                And that service is protected by Digest Authentication
         | 
| 16 | 
            +
                And that service requires the username 'jcash' with the password 'maninblack'
         | 
| 17 | 
            +
                When I call HTTParty#get with '/protected.html' and a digest_auth hash:
         | 
| 18 | 
            +
                   | username | password   |
         | 
| 19 | 
            +
                   | jcash    | maninblack |
         | 
| 20 | 
            +
                Then the return value should match 'Digest Authenticated Page'
         | 
    
        data/features/steps/env.rb
    CHANGED
    
    | @@ -4,7 +4,14 @@ require 'lib/httparty' | |
| 4 4 | 
             
            require 'spec/expectations'
         | 
| 5 5 |  | 
| 6 6 | 
             
            Before do
         | 
| 7 | 
            -
               | 
| 7 | 
            +
              def new_port
         | 
| 8 | 
            +
                server = TCPServer.new('0.0.0.0', nil)
         | 
| 9 | 
            +
                port = server.addr[1]
         | 
| 10 | 
            +
              ensure
         | 
| 11 | 
            +
                server.close
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              port = ENV["HTTPARTY_PORT"] || new_port
         | 
| 8 15 | 
             
              @host_and_port = "0.0.0.0:#{port}"
         | 
| 9 16 | 
             
              @server = Mongrel::HttpServer.new("0.0.0.0", port)
         | 
| 10 17 | 
             
              @server.run
         | 
| @@ -17,3 +17,11 @@ When /I call HTTParty#get with '(.*)' and a basic_auth hash:/ do |url, auth_tabl | |
| 17 17 | 
             
                :basic_auth => { :username => h["username"], :password => h["password"] }
         | 
| 18 18 | 
             
              )
         | 
| 19 19 | 
             
            end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            When /I call HTTParty#get with '(.*)' and a digest_auth hash:/ do |url, auth_table|
         | 
| 22 | 
            +
              h = auth_table.hashes.first
         | 
| 23 | 
            +
              @response_from_httparty = HTTParty.get(
         | 
| 24 | 
            +
                "http://#{@host_and_port}#{url}",
         | 
| 25 | 
            +
                :digest_auth => { :username => h["username"], :password => h["password"] }
         | 
| 26 | 
            +
              )
         | 
| 27 | 
            +
            end
         | 
| @@ -50,6 +50,28 @@ def add_basic_authentication_to(handler) | |
| 50 50 | 
             
              handler.extend(m)
         | 
| 51 51 | 
             
            end
         | 
| 52 52 |  | 
| 53 | 
            +
            def add_digest_authentication_to(handler)
         | 
| 54 | 
            +
              m = Module.new do
         | 
| 55 | 
            +
                attr_writer :username, :password
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                def self.extended(base)
         | 
| 58 | 
            +
                  base.instance_eval { @custom_headers["WWW-Authenticate"] = 'Digest realm="testrealm@host.com",qop="auth,auth-int",nonce="nonce",opaque="opaque"' }
         | 
| 59 | 
            +
                  base.class_eval { alias_method_chain :process, :digest_authentication }
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def process_with_digest_authentication(request, response)
         | 
| 63 | 
            +
                  if authorized?(request) then process_without_digest_authentication(request, response)
         | 
| 64 | 
            +
                  else reply_with(response, 401, "Incorrect.  You have 20 seconds to comply.")
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                def authorized?(request)
         | 
| 69 | 
            +
                  request.params["HTTP_AUTHORIZATION"] =~ /Digest.*uri=/
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
              handler.extend(m)
         | 
| 73 | 
            +
            end
         | 
| 74 | 
            +
             | 
| 53 75 | 
             
            def new_mongrel_redirector(target_url, relative_path = false)
         | 
| 54 76 | 
             
              target_url = "http://#{@host_and_port}#{target_url}" unless relative_path
         | 
| 55 77 | 
             
              Mongrel::RedirectHandler.new(target_url)
         | 
| @@ -13,8 +13,8 @@ Given /that service is accessed at the path '(.*)'/ do |path| | |
| 13 13 | 
             
            end
         | 
| 14 14 |  | 
| 15 15 | 
             
            Given /^that service takes (\d+) seconds to generate a response$/ do |time|
         | 
| 16 | 
            -
               | 
| 17 | 
            -
              @handler.preprocessor =  | 
| 16 | 
            +
              @server_response_time = time.to_i
         | 
| 17 | 
            +
              @handler.preprocessor = lambda { sleep time.to_i }
         | 
| 18 18 | 
             
            end
         | 
| 19 19 |  | 
| 20 20 | 
             
            Given /the response from the service has a Content-Type of '(.*)'/ do |content_type|
         | 
| @@ -33,6 +33,10 @@ Given /that service is protected by Basic Authentication/ do | |
| 33 33 | 
             
              add_basic_authentication_to @handler
         | 
| 34 34 | 
             
            end
         | 
| 35 35 |  | 
| 36 | 
            +
            Given /that service is protected by Digest Authentication/ do
         | 
| 37 | 
            +
              add_digest_authentication_to @handler
         | 
| 38 | 
            +
            end
         | 
| 39 | 
            +
             | 
| 36 40 | 
             
            Given /that service requires the username '(.*)' with the password '(.*)'/ do |username, password|
         | 
| 37 41 | 
             
              @handler.username = username
         | 
| 38 42 | 
             
              @handler.password = password
         | 
| @@ -50,3 +54,8 @@ end | |
| 50 54 | 
             
            Given /I want to hit this in a browser/ do
         | 
| 51 55 | 
             
              @server.acceptor.join
         | 
| 52 56 | 
             
            end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            Then /I wait for the server to recover/ do
         | 
| 59 | 
            +
              timeout = @request_options[:timeout] || 0
         | 
| 60 | 
            +
              sleep @server_response_time - timeout
         | 
| 61 | 
            +
            end
         | 
    
        data/jugend-httparty.gemspec
    CHANGED
    
    | @@ -5,11 +5,11 @@ | |
| 5 5 |  | 
| 6 6 | 
             
            Gem::Specification.new do |s|
         | 
| 7 7 | 
             
              s.name = %q{jugend-httparty}
         | 
| 8 | 
            -
              s.version = "0.5. | 
| 8 | 
            +
              s.version = "0.5.3.4"
         | 
| 9 9 |  | 
| 10 10 | 
             
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         | 
| 11 11 | 
             
              s.authors = ["John Nunemaker", "Sandro Turriate"]
         | 
| 12 | 
            -
              s.date = %q{2010- | 
| 12 | 
            +
              s.date = %q{2010-05-26}
         | 
| 13 13 | 
             
              s.default_executable = %q{httparty}
         | 
| 14 14 | 
             
              s.description = %q{Makes http fun! Also, makes consuming restful web services dead easy.}
         | 
| 15 15 | 
             
              s.email = %q{nunemaker@gmail.com}
         | 
| @@ -38,6 +38,7 @@ Gem::Specification.new do |s| | |
| 38 38 | 
             
                 "features/basic_authentication.feature",
         | 
| 39 39 | 
             
                 "features/command_line.feature",
         | 
| 40 40 | 
             
                 "features/deals_with_http_error_codes.feature",
         | 
| 41 | 
            +
                 "features/digest_authentication.feature",
         | 
| 41 42 | 
             
                 "features/handles_multiple_formats.feature",
         | 
| 42 43 | 
             
                 "features/steps/env.rb",
         | 
| 43 44 | 
             
                 "features/steps/httparty_response_steps.rb",
         | 
| @@ -52,6 +53,7 @@ Gem::Specification.new do |s| | |
| 52 53 | 
             
                 "lib/httparty/core_extensions.rb",
         | 
| 53 54 | 
             
                 "lib/httparty/exceptions.rb",
         | 
| 54 55 | 
             
                 "lib/httparty/module_inheritable_attributes.rb",
         | 
| 56 | 
            +
                 "lib/httparty/net_digest_auth.rb",
         | 
| 55 57 | 
             
                 "lib/httparty/parser.rb",
         | 
| 56 58 | 
             
                 "lib/httparty/request.rb",
         | 
| 57 59 | 
             
                 "lib/httparty/response.rb",
         | 
| @@ -72,7 +74,7 @@ Gem::Specification.new do |s| | |
| 72 74 | 
             
                 "website/css/common.css",
         | 
| 73 75 | 
             
                 "website/index.html"
         | 
| 74 76 | 
             
              ]
         | 
| 75 | 
            -
              s.homepage = %q{http://httparty | 
| 77 | 
            +
              s.homepage = %q{http://github.com/jugend/httparty}
         | 
| 76 78 | 
             
              s.post_install_message = %q{When you HTTParty, you must party hard!}
         | 
| 77 79 | 
             
              s.rdoc_options = ["--charset=UTF-8"]
         | 
| 78 80 | 
             
              s.require_paths = ["lib"]
         | 
| @@ -101,27 +103,27 @@ Gem::Specification.new do |s| | |
| 101 103 | 
             
                s.specification_version = 3
         | 
| 102 104 |  | 
| 103 105 | 
             
                if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
         | 
| 104 | 
            -
                  s.add_runtime_dependency(%q<crack>, ["= 0.1. | 
| 106 | 
            +
                  s.add_runtime_dependency(%q<crack>, ["= 0.1.7"])
         | 
| 105 107 | 
             
                  s.add_development_dependency(%q<activesupport>, ["~> 2.3"])
         | 
| 106 | 
            -
                  s.add_development_dependency(%q<cucumber>, ["~> 0. | 
| 108 | 
            +
                  s.add_development_dependency(%q<cucumber>, ["~> 0.7"])
         | 
| 107 109 | 
             
                  s.add_development_dependency(%q<fakeweb>, ["~> 1.2"])
         | 
| 108 110 | 
             
                  s.add_development_dependency(%q<mongrel>, ["~> 1.1"])
         | 
| 109 | 
            -
                  s.add_development_dependency(%q<rspec>, [" | 
| 111 | 
            +
                  s.add_development_dependency(%q<rspec>, ["~> 1.3"])
         | 
| 110 112 | 
             
                else
         | 
| 111 | 
            -
                  s.add_dependency(%q<crack>, ["= 0.1. | 
| 113 | 
            +
                  s.add_dependency(%q<crack>, ["= 0.1.7"])
         | 
| 112 114 | 
             
                  s.add_dependency(%q<activesupport>, ["~> 2.3"])
         | 
| 113 | 
            -
                  s.add_dependency(%q<cucumber>, ["~> 0. | 
| 115 | 
            +
                  s.add_dependency(%q<cucumber>, ["~> 0.7"])
         | 
| 114 116 | 
             
                  s.add_dependency(%q<fakeweb>, ["~> 1.2"])
         | 
| 115 117 | 
             
                  s.add_dependency(%q<mongrel>, ["~> 1.1"])
         | 
| 116 | 
            -
                  s.add_dependency(%q<rspec>, [" | 
| 118 | 
            +
                  s.add_dependency(%q<rspec>, ["~> 1.3"])
         | 
| 117 119 | 
             
                end
         | 
| 118 120 | 
             
              else
         | 
| 119 | 
            -
                s.add_dependency(%q<crack>, ["= 0.1. | 
| 121 | 
            +
                s.add_dependency(%q<crack>, ["= 0.1.7"])
         | 
| 120 122 | 
             
                s.add_dependency(%q<activesupport>, ["~> 2.3"])
         | 
| 121 | 
            -
                s.add_dependency(%q<cucumber>, ["~> 0. | 
| 123 | 
            +
                s.add_dependency(%q<cucumber>, ["~> 0.7"])
         | 
| 122 124 | 
             
                s.add_dependency(%q<fakeweb>, ["~> 1.2"])
         | 
| 123 125 | 
             
                s.add_dependency(%q<mongrel>, ["~> 1.1"])
         | 
| 124 | 
            -
                s.add_dependency(%q<rspec>, [" | 
| 126 | 
            +
                s.add_dependency(%q<rspec>, ["~> 1.3"])
         | 
| 125 127 | 
             
              end
         | 
| 126 128 | 
             
            end
         | 
| 127 129 |  | 
    
        data/lib/httparty.rb
    CHANGED
    
    | @@ -3,17 +3,15 @@ require 'net/http' | |
| 3 3 | 
             
            require 'net/https'
         | 
| 4 4 | 
             
            require 'crack'
         | 
| 5 5 |  | 
| 6 | 
            -
             | 
| 7 | 
            -
              warn "warning: HTTParty depends on version 0.1.6 of crack, not #{Crack::VERSION}."
         | 
| 8 | 
            -
            end
         | 
| 9 | 
            -
             | 
| 10 | 
            -
            dir = Pathname(__FILE__).dirname.expand_path
         | 
| 6 | 
            +
            dir = Pathname.new(__FILE__).dirname.expand_path
         | 
| 11 7 |  | 
| 12 8 | 
             
            require dir + 'httparty/module_inheritable_attributes'
         | 
| 13 9 | 
             
            require dir + 'httparty/cookie_hash'
         | 
| 10 | 
            +
            require dir + 'httparty/net_digest_auth'
         | 
| 14 11 |  | 
| 15 12 | 
             
            module HTTParty
         | 
| 16 13 | 
             
              VERSION = "0.5.2".freeze
         | 
| 14 | 
            +
              CRACK_DEPENDENCY = "0.1.7".freeze
         | 
| 17 15 |  | 
| 18 16 | 
             
              module AllowedFormatsDeprecation
         | 
| 19 17 | 
             
                def const_missing(const)
         | 
| @@ -73,6 +71,16 @@ module HTTParty | |
| 73 71 | 
             
                  default_options[:basic_auth] = {:username => u, :password => p}
         | 
| 74 72 | 
             
                end
         | 
| 75 73 |  | 
| 74 | 
            +
                # Allows setting digest authentication username and password.
         | 
| 75 | 
            +
                #
         | 
| 76 | 
            +
                #   class Foo
         | 
| 77 | 
            +
                #     include HTTParty
         | 
| 78 | 
            +
                #     digest_auth 'username', 'password'
         | 
| 79 | 
            +
                #   end
         | 
| 80 | 
            +
                def digest_auth(u, p)
         | 
| 81 | 
            +
                  default_options[:digest_auth] = {:username => u, :password => p}
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 76 84 | 
             
                # Allows setting default parameters to be appended to each request.
         | 
| 77 85 | 
             
                # Great for api keys and such.
         | 
| 78 86 | 
             
                #
         | 
| @@ -86,6 +94,18 @@ module HTTParty | |
| 86 94 | 
             
                  default_options[:default_params].merge!(h)
         | 
| 87 95 | 
             
                end
         | 
| 88 96 |  | 
| 97 | 
            +
                # Allows setting a default timeout for all HTTP calls
         | 
| 98 | 
            +
                # Timeout is specified in seconds.
         | 
| 99 | 
            +
                #
         | 
| 100 | 
            +
                #   class Foo
         | 
| 101 | 
            +
                #     include HTTParty
         | 
| 102 | 
            +
                #     default_timeout 10
         | 
| 103 | 
            +
                #   end
         | 
| 104 | 
            +
                def default_timeout(t)
         | 
| 105 | 
            +
                  raise ArgumentError, 'Timeout must be an integer' unless t && t.is_a?(Integer)
         | 
| 106 | 
            +
                  default_options[:timeout] = t
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
             | 
| 89 109 | 
             
                # Set an output stream for debugging, defaults to $stderr.
         | 
| 90 110 | 
             
                # The output stream is passed on to Net::HTTP#set_debug_output.
         | 
| 91 111 | 
             
                #
         | 
| @@ -97,7 +117,7 @@ module HTTParty | |
| 97 117 | 
             
                  default_options[:debug_output] = stream
         | 
| 98 118 | 
             
                end
         | 
| 99 119 |  | 
| 100 | 
            -
                # Allows setting  | 
| 120 | 
            +
                # Allows setting HTTP headers to be used for each request.
         | 
| 101 121 | 
             
                #
         | 
| 102 122 | 
             
                #   class Foo
         | 
| 103 123 | 
             
                #     include HTTParty
         | 
| @@ -154,6 +174,21 @@ module HTTParty | |
| 154 174 | 
             
                  default_options[:no_follow] = value
         | 
| 155 175 | 
             
                end
         | 
| 156 176 |  | 
| 177 | 
            +
                # Declare that you wish to maintain the chosen HTTP method across redirects.
         | 
| 178 | 
            +
                # The default behavior is to follow redirects via the GET method.
         | 
| 179 | 
            +
                # If you wish to maintain the original method, you can set this option to true.
         | 
| 180 | 
            +
                #
         | 
| 181 | 
            +
                # @example
         | 
| 182 | 
            +
                #   class Foo
         | 
| 183 | 
            +
                #     include HTTParty
         | 
| 184 | 
            +
                #     base_uri 'http://google.com'
         | 
| 185 | 
            +
                #     maintain_method_across_redirects true
         | 
| 186 | 
            +
                #   end
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                def maintain_method_across_redirects(value = true)
         | 
| 189 | 
            +
                  default_options[:maintain_method_across_redirects] = value
         | 
| 190 | 
            +
                end
         | 
| 191 | 
            +
             | 
| 157 192 | 
             
                # Allows setting a PEM file to be used
         | 
| 158 193 | 
             
                #
         | 
| 159 194 | 
             
                #   class Foo
         | 
| @@ -302,3 +337,7 @@ require dir + 'httparty/exceptions' | |
| 302 337 | 
             
            require dir + 'httparty/parser'
         | 
| 303 338 | 
             
            require dir + 'httparty/request'
         | 
| 304 339 | 
             
            require dir + 'httparty/response'
         | 
| 340 | 
            +
             | 
| 341 | 
            +
            if Crack::VERSION != HTTParty::CRACK_DEPENDENCY
         | 
| 342 | 
            +
              warn "warning: HTTParty depends on version #{HTTParty::CRACK_DEPENDENCY} of crack, not #{Crack::VERSION}."
         | 
| 343 | 
            +
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            require 'digest/md5'
         | 
| 2 | 
            +
            require 'net/http'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Net
         | 
| 5 | 
            +
              module HTTPHeader
         | 
| 6 | 
            +
                def digest_auth(user, password, response)
         | 
| 7 | 
            +
                  response['www-authenticate'] =~ /^(\w+) (.*)/
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  params = {}
         | 
| 10 | 
            +
                  $2.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
         | 
| 11 | 
            +
                  params.merge!("cnonce" => Digest::MD5.hexdigest("%x" % (Time.now.to_i + rand(65535))))
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  a_1 = Digest::MD5.hexdigest("#{user}:#{params['realm']}:#{password}")
         | 
| 14 | 
            +
                  a_2 = Digest::MD5.hexdigest("#{@method}:#{@path}")
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  request_digest = Digest::MD5.hexdigest(
         | 
| 17 | 
            +
                    [a_1, params['nonce'], "0", params['cnonce'], params['qop'], a_2].join(":")
         | 
| 18 | 
            +
                  )
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  header = [
         | 
| 21 | 
            +
                    %Q(Digest username="#{user}"),
         | 
| 22 | 
            +
                    %Q(realm="#{params['realm']}"),
         | 
| 23 | 
            +
                    %Q(qop="#{params['qop']}"),
         | 
| 24 | 
            +
                    %Q(uri="#{@path}"),
         | 
| 25 | 
            +
                    %Q(nonce="#{params['nonce']}"),
         | 
| 26 | 
            +
                    %Q(nc="0"),
         | 
| 27 | 
            +
                    %Q(cnonce="#{params['cnonce']}"),
         | 
| 28 | 
            +
                    %Q(opaque="#{params['opaque']}"),
         | 
| 29 | 
            +
                    %Q(response="#{request_digest}")
         | 
| 30 | 
            +
                  ]
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  @header['Authorization'] = header
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
    
        data/lib/httparty/request.rb
    CHANGED
    
    | @@ -13,7 +13,7 @@ module HTTParty | |
| 13 13 |  | 
| 14 14 | 
             
                SupportedURISchemes  = [URI::HTTP, URI::HTTPS]
         | 
| 15 15 |  | 
| 16 | 
            -
                attr_accessor :http_method, :path, :options, :last_response
         | 
| 16 | 
            +
                attr_accessor :http_method, :path, :options, :last_response, :redirect
         | 
| 17 17 |  | 
| 18 18 | 
             
                def initialize(http_method, path, o={})
         | 
| 19 19 | 
             
                  self.http_method = http_method
         | 
| @@ -33,7 +33,7 @@ module HTTParty | |
| 33 33 | 
             
                  new_uri = path.relative? ? URI.parse("#{options[:base_uri]}#{path}") : path
         | 
| 34 34 |  | 
| 35 35 | 
             
                  # avoid double query string on redirects [#12]
         | 
| 36 | 
            -
                  unless  | 
| 36 | 
            +
                  unless redirect
         | 
| 37 37 | 
             
                    new_uri.query = query_string(new_uri)
         | 
| 38 38 | 
             
                  end
         | 
| 39 39 |  | 
| @@ -52,7 +52,6 @@ module HTTParty | |
| 52 52 | 
             
                  options[:parser]
         | 
| 53 53 | 
             
                end
         | 
| 54 54 |  | 
| 55 | 
            -
             | 
| 56 55 | 
             
                def perform
         | 
| 57 56 | 
             
                  validate
         | 
| 58 57 | 
             
                  setup_raw_request
         | 
| @@ -62,133 +61,146 @@ module HTTParty | |
| 62 61 |  | 
| 63 62 | 
             
                private
         | 
| 64 63 |  | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
                    if options[:timeout] && options[:timeout].is_a?(Integer)
         | 
| 70 | 
            -
                      http.open_timeout = options[:timeout]
         | 
| 71 | 
            -
                      http.read_timeout = options[:timeout]
         | 
| 72 | 
            -
                    end
         | 
| 73 | 
            -
             | 
| 74 | 
            -
                    if options[:pem] && http.use_ssl?
         | 
| 75 | 
            -
                      http.cert = OpenSSL::X509::Certificate.new(options[:pem])
         | 
| 76 | 
            -
                      http.key = OpenSSL::PKey::RSA.new(options[:pem])
         | 
| 77 | 
            -
                      http.verify_mode = OpenSSL::SSL::VERIFY_PEER
         | 
| 78 | 
            -
                    else
         | 
| 79 | 
            -
                      http.verify_mode = OpenSSL::SSL::VERIFY_NONE
         | 
| 80 | 
            -
                    end
         | 
| 81 | 
            -
             | 
| 82 | 
            -
                    if options[:debug_output]
         | 
| 83 | 
            -
                      http.set_debug_output(options[:debug_output])
         | 
| 84 | 
            -
                    end
         | 
| 64 | 
            +
                def http
         | 
| 65 | 
            +
                  http = Net::HTTP.new(uri.host, uri.port, options[:http_proxyaddr], options[:http_proxyport])
         | 
| 66 | 
            +
                  http.use_ssl = ssl_implied?
         | 
| 85 67 |  | 
| 86 | 
            -
             | 
| 68 | 
            +
                  if options[:timeout] && options[:timeout].is_a?(Integer)
         | 
| 69 | 
            +
                    http.open_timeout = options[:timeout]
         | 
| 70 | 
            +
                    http.read_timeout = options[:timeout]
         | 
| 87 71 | 
             
                  end
         | 
| 88 72 |  | 
| 89 | 
            -
                   | 
| 90 | 
            -
                     | 
| 73 | 
            +
                  if options[:pem] && http.use_ssl?
         | 
| 74 | 
            +
                    http.cert = OpenSSL::X509::Certificate.new(options[:pem])
         | 
| 75 | 
            +
                    http.key = OpenSSL::PKey::RSA.new(options[:pem])
         | 
| 76 | 
            +
                    http.verify_mode = OpenSSL::SSL::VERIFY_PEER
         | 
| 77 | 
            +
                  else
         | 
| 78 | 
            +
                    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
         | 
| 91 79 | 
             
                  end
         | 
| 92 80 |  | 
| 93 | 
            -
                   | 
| 94 | 
            -
                     | 
| 81 | 
            +
                  if options[:debug_output]
         | 
| 82 | 
            +
                    http.set_debug_output(options[:debug_output])
         | 
| 95 83 | 
             
                  end
         | 
| 96 84 |  | 
| 97 | 
            -
                   | 
| 98 | 
            -
             | 
| 99 | 
            -
                  end
         | 
| 85 | 
            +
                  http
         | 
| 86 | 
            +
                end
         | 
| 100 87 |  | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 88 | 
            +
                def ssl_implied?
         | 
| 89 | 
            +
                  uri.port == 443 || uri.instance_of?(URI::HTTPS)
         | 
| 90 | 
            +
                end
         | 
| 104 91 |  | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 108 | 
            -
                    @raw_request.initialize_http_header(options[:headers])
         | 
| 109 | 
            -
                    @raw_request.basic_auth(username, password) if options[:basic_auth]
         | 
| 110 | 
            -
                  end
         | 
| 92 | 
            +
                def body
         | 
| 93 | 
            +
                  options[:body].is_a?(Hash) ? options[:body].to_params : options[:body]
         | 
| 94 | 
            +
                end
         | 
| 111 95 |  | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 96 | 
            +
                def credentials
         | 
| 97 | 
            +
                  options[:basic_auth] || options[:digest_auth]
         | 
| 98 | 
            +
                end
         | 
| 115 99 |  | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 118 | 
            -
             | 
| 100 | 
            +
                def username
         | 
| 101 | 
            +
                  credentials[:username]
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                def password
         | 
| 105 | 
            +
                  credentials[:password]
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                def setup_raw_request
         | 
| 109 | 
            +
                  @raw_request = http_method.new(uri.request_uri)
         | 
| 110 | 
            +
                  @raw_request.body = body if body
         | 
| 111 | 
            +
                  @raw_request.initialize_http_header(options[:headers])
         | 
| 112 | 
            +
                  @raw_request.basic_auth(username, password) if options[:basic_auth]
         | 
| 113 | 
            +
                  setup_digest_auth if options[:digest_auth]
         | 
| 114 | 
            +
                end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                def setup_digest_auth
         | 
| 117 | 
            +
                  res = http.head(uri.request_uri, options[:headers])
         | 
| 118 | 
            +
                  if res['www-authenticate'] != nil && res['www-authenticate'].length > 0
         | 
| 119 | 
            +
                    @raw_request.digest_auth(username, password, res)
         | 
| 119 120 | 
             
                  end
         | 
| 121 | 
            +
                end
         | 
| 120 122 |  | 
| 121 | 
            -
             | 
| 122 | 
            -
             | 
| 123 | 
            -
             | 
| 123 | 
            +
                def perform_actual_request
         | 
| 124 | 
            +
                  http.request(@raw_request)
         | 
| 125 | 
            +
                end
         | 
| 124 126 |  | 
| 125 | 
            -
             | 
| 126 | 
            -
             | 
| 127 | 
            -
             | 
| 128 | 
            -
             | 
| 129 | 
            -
                      query_string_parts << options[:query] unless options[:query].nil?
         | 
| 130 | 
            -
                    end
         | 
| 127 | 
            +
                def get_response
         | 
| 128 | 
            +
                  self.last_response = perform_actual_request
         | 
| 129 | 
            +
                  options[:format] ||= format_from_mimetype(last_response['content-type'])
         | 
| 130 | 
            +
                end
         | 
| 131 131 |  | 
| 132 | 
            -
             | 
| 132 | 
            +
                def query_string(uri)
         | 
| 133 | 
            +
                  query_string_parts = []
         | 
| 134 | 
            +
                  query_string_parts << uri.query unless uri.query.nil?
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                  if options[:query].is_a?(Hash)
         | 
| 137 | 
            +
                    query_string_parts << options[:default_params].merge(options[:query]).to_params
         | 
| 138 | 
            +
                  else
         | 
| 139 | 
            +
                    query_string_parts << options[:default_params].to_params unless options[:default_params].empty?
         | 
| 140 | 
            +
                    query_string_parts << options[:query] unless options[:query].nil?
         | 
| 133 141 | 
             
                  end
         | 
| 134 142 |  | 
| 135 | 
            -
                   | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 138 | 
            -
             | 
| 139 | 
            -
             | 
| 140 | 
            -
             | 
| 141 | 
            -
             | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 143 | 
            +
                  query_string_parts.size > 0 ? query_string_parts.join('&') : nil
         | 
| 144 | 
            +
                end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                # Raises exception Net::XXX (http error code) if an http error occured
         | 
| 147 | 
            +
                def handle_response
         | 
| 148 | 
            +
                  case last_response
         | 
| 149 | 
            +
                    when Net::HTTPMultipleChoice, # 300
         | 
| 150 | 
            +
                    Net::HTTPMovedPermanently, # 301
         | 
| 151 | 
            +
                    Net::HTTPFound, # 302
         | 
| 152 | 
            +
                    Net::HTTPSeeOther, # 303
         | 
| 153 | 
            +
                    Net::HTTPUseProxy, # 305
         | 
| 154 | 
            +
                    Net::HTTPTemporaryRedirect
         | 
| 144 155 | 
             
                      if last_response.key?('location')
         | 
| 145 156 | 
             
                        options[:limit] -= 1
         | 
| 146 157 | 
             
                        self.path = last_response['location']
         | 
| 147 | 
            -
                         | 
| 148 | 
            -
                        self.http_method = Net::HTTP::Get
         | 
| 158 | 
            +
                        self.redirect = true
         | 
| 159 | 
            +
                        self.http_method = Net::HTTP::Get unless options[:maintain_method_across_redirects]
         | 
| 149 160 | 
             
                        capture_cookies(last_response)
         | 
| 150 161 | 
             
                        perform
         | 
| 151 162 | 
             
                      else
         | 
| 152 163 | 
             
                        last_response
         | 
| 153 164 | 
             
                      end
         | 
| 154 165 | 
             
                    else
         | 
| 155 | 
            -
                      Response.new( | 
| 156 | 
            -
                    end
         | 
| 166 | 
            +
                      Response.new(last_response, parse_response(last_response.body))
         | 
| 157 167 | 
             
                  end
         | 
| 168 | 
            +
                end
         | 
| 158 169 |  | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 161 | 
            -
             | 
| 170 | 
            +
                def parse_response(body)
         | 
| 171 | 
            +
                  parser.call(body, format)
         | 
| 172 | 
            +
                end
         | 
| 162 173 |  | 
| 163 | 
            -
             | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 169 | 
            -
             | 
| 170 | 
            -
             | 
| 174 | 
            +
                def capture_cookies(response)
         | 
| 175 | 
            +
                  return unless response['Set-Cookie']
         | 
| 176 | 
            +
                  cookies_hash = HTTParty::CookieHash.new()
         | 
| 177 | 
            +
                  cookies_hash.add_cookies(options[:headers]['Cookie']) if options[:headers] && options[:headers]['Cookie']
         | 
| 178 | 
            +
                  cookies_hash.add_cookies(response['Set-Cookie'])
         | 
| 179 | 
            +
                  options[:headers] ||= {}
         | 
| 180 | 
            +
                  options[:headers]['Cookie'] = cookies_hash.to_cookie_string
         | 
| 181 | 
            +
                end
         | 
| 171 182 |  | 
| 172 | 
            -
             | 
| 173 | 
            -
             | 
| 174 | 
            -
             | 
| 175 | 
            -
             | 
| 176 | 
            -
             | 
| 177 | 
            -
             | 
| 178 | 
            -
                    end
         | 
| 183 | 
            +
                # Uses the HTTP Content-Type header to determine the format of the
         | 
| 184 | 
            +
                # response It compares the MIME type returned to the types stored in the
         | 
| 185 | 
            +
                # SupportedFormats hash
         | 
| 186 | 
            +
                def format_from_mimetype(mimetype)
         | 
| 187 | 
            +
                  if mimetype && parser.respond_to?(:format_from_mimetype)
         | 
| 188 | 
            +
                    parser.format_from_mimetype(mimetype)
         | 
| 179 189 | 
             
                  end
         | 
| 190 | 
            +
                end
         | 
| 180 191 |  | 
| 181 192 | 
             
                  def validate
         | 
| 182 193 | 
             
                    raise HTTParty::RedirectionTooDeep.new(last_response), 'HTTP redirects too deep' if options[:limit].to_i <= 0
         | 
| 183 194 | 
             
                    raise ArgumentError, 'only get, post, put, delete, head, and options methods are supported' unless SupportedHTTPMethods.include?(http_method)
         | 
| 184 195 | 
             
                    raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].is_a?(Hash)
         | 
| 196 | 
            +
                    raise ArgumentError, 'only one authentication method, :basic_auth or :digest_auth may be used at a time' if options[:basic_auth] && options[:digest_auth]
         | 
| 185 197 | 
             
                    raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].is_a?(Hash)
         | 
| 198 | 
            +
                    raise ArgumentError, ':digest_auth must be a hash' if options[:digest_auth] && !options[:digest_auth].is_a?(Hash)
         | 
| 186 199 | 
             
                    raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].is_a?(Hash)
         | 
| 187 200 | 
             
                  end
         | 
| 188 201 |  | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 191 | 
            -
             | 
| 202 | 
            +
                def post?
         | 
| 203 | 
            +
                  Net::HTTP::Post == http_method
         | 
| 204 | 
            +
                end
         | 
| 192 205 | 
             
              end
         | 
| 193 206 | 
             
            end
         | 
| 194 | 
            -
             | 
    
        data/lib/httparty/response.rb
    CHANGED
    
    | @@ -1,18 +1,62 @@ | |
| 1 1 | 
             
            module HTTParty
         | 
| 2 2 | 
             
              class Response < HTTParty::BasicObject #:nodoc:
         | 
| 3 | 
            -
                 | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
                   | 
| 9 | 
            -
             | 
| 10 | 
            -
                   | 
| 11 | 
            -
             | 
| 3 | 
            +
                class Headers
         | 
| 4 | 
            +
                  include Net::HTTPHeader
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(header)
         | 
| 7 | 
            +
                    @header = header
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def ==(other)
         | 
| 11 | 
            +
                    @header == other
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def inspect
         | 
| 15 | 
            +
                    @header.inspect
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def method_missing(name, *args, &block)
         | 
| 19 | 
            +
                    if @header.respond_to?(name)
         | 
| 20 | 
            +
                      @header.send(name, *args, &block)
         | 
| 21 | 
            +
                    else
         | 
| 22 | 
            +
                      super
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def respond_to?(method)
         | 
| 27 | 
            +
                    super || @header.respond_to?(method)
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                attr_reader :response, :parsed_response, :body, :headers
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def initialize(response, parsed_response)
         | 
| 34 | 
            +
                  @response = response
         | 
| 35 | 
            +
                  @body = response.body
         | 
| 36 | 
            +
                  @parsed_response = parsed_response
         | 
| 37 | 
            +
                  @headers = Headers.new(response.to_hash)
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def class
         | 
| 41 | 
            +
                  Object.instance_method(:class).bind(self).call
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def code
         | 
| 45 | 
            +
                  response.code.to_i
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def inspect
         | 
| 49 | 
            +
                  %(<#{self.class} @response=#{response.inspect}>)
         | 
| 12 50 | 
             
                end
         | 
| 13 51 |  | 
| 14 52 | 
             
                def method_missing(name, *args, &block)
         | 
| 15 | 
            -
                   | 
| 53 | 
            +
                  if parsed_response.respond_to?(name)
         | 
| 54 | 
            +
                    parsed_response.send(name, *args, &block)
         | 
| 55 | 
            +
                  elsif response.respond_to?(name)
         | 
| 56 | 
            +
                    response.send(name, *args, &block)
         | 
| 57 | 
            +
                  else
         | 
| 58 | 
            +
                    super
         | 
| 59 | 
            +
                  end
         | 
| 16 60 | 
             
                end
         | 
| 17 61 | 
             
              end
         | 
| 18 62 | 
             
            end
         | 
| @@ -30,6 +30,17 @@ describe HTTParty::Request do | |
| 30 30 | 
             
                  @request.send(:setup_raw_request)
         | 
| 31 31 | 
             
                  @request.instance_variable_get(:@raw_request)['authorization'].should_not be_nil
         | 
| 32 32 | 
             
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                it "should use digest auth when configured" do
         | 
| 35 | 
            +
                  FakeWeb.register_uri(:head, "http://api.foo.com/v1",
         | 
| 36 | 
            +
                    :www_authenticate => 'Digest realm="Log Viewer", qop="auth", nonce="2CA0EC6B0E126C4800E56BA0C0003D3C", opaque="5ccc069c403ebaf9f0171e9517f40e41", stale=false')
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  @request.options[:digest_auth] = {:username => 'foobar', :password => 'secret'}
         | 
| 39 | 
            +
                  @request.send(:setup_raw_request)
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  raw_request = @request.instance_variable_get(:@raw_request)
         | 
| 42 | 
            +
                  raw_request.instance_variable_get(:@header)['Authorization'].should_not be_nil
         | 
| 43 | 
            +
                end
         | 
| 33 44 | 
             
              end
         | 
| 34 45 |  | 
| 35 46 | 
             
              describe "#uri" do
         | 
| @@ -353,6 +364,13 @@ describe HTTParty::Request do | |
| 353 364 | 
             
                    @request.perform.should == {"hash" => {"foo" => "bar"}}
         | 
| 354 365 | 
             
                    @request.http_method.should == Net::HTTP::Get
         | 
| 355 366 | 
             
                  end
         | 
| 367 | 
            +
             | 
| 368 | 
            +
                  it 'should not make resulting request a get request if options[:maintain_method_across_redirects] is true' do
         | 
| 369 | 
            +
                    @request.options[:maintain_method_across_redirects] = true
         | 
| 370 | 
            +
                    @request.http_method = Net::HTTP::Delete
         | 
| 371 | 
            +
                    @request.perform.should == {"hash" => {"foo" => "bar"}}
         | 
| 372 | 
            +
                    @request.http_method.should == Net::HTTP::Delete
         | 
| 373 | 
            +
                  end
         | 
| 356 374 | 
             
                end
         | 
| 357 375 |  | 
| 358 376 | 
             
                describe "infinitely" do
         | 
| @@ -373,5 +391,25 @@ describe HTTParty::Request do | |
| 373 391 | 
             
                  }.should raise_error(ArgumentError)
         | 
| 374 392 | 
             
                end
         | 
| 375 393 | 
             
              end
         | 
| 394 | 
            +
             | 
| 395 | 
            +
              describe "argument validation" do
         | 
| 396 | 
            +
                it "should raise argument error if basic_auth and digest_auth are both present" do
         | 
| 397 | 
            +
                  lambda {
         | 
| 398 | 
            +
                    HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :basic_auth => {}, :digest_auth => {}).perform
         | 
| 399 | 
            +
                  }.should raise_error(ArgumentError, "only one authentication method, :basic_auth or :digest_auth may be used at a time")
         | 
| 400 | 
            +
                end
         | 
| 401 | 
            +
             | 
| 402 | 
            +
                it "should raise argument error if basic_auth is not a hash" do
         | 
| 403 | 
            +
                  lambda {
         | 
| 404 | 
            +
                    HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :basic_auth => ["foo", "bar"]).perform
         | 
| 405 | 
            +
                  }.should raise_error(ArgumentError, ":basic_auth must be a hash")
         | 
| 406 | 
            +
                end
         | 
| 407 | 
            +
             | 
| 408 | 
            +
                it "should raise argument error if digest_auth is not a hash" do
         | 
| 409 | 
            +
                  lambda {
         | 
| 410 | 
            +
                    HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :digest_auth => ["foo", "bar"]).perform
         | 
| 411 | 
            +
                  }.should raise_error(ArgumentError, ":digest_auth must be a hash")
         | 
| 412 | 
            +
                end
         | 
| 413 | 
            +
              end
         | 
| 376 414 | 
             
            end
         | 
| 377 415 |  | 
| @@ -1,62 +1,83 @@ | |
| 1 1 | 
             
            require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
         | 
| 2 2 |  | 
| 3 3 | 
             
            describe HTTParty::Response do
         | 
| 4 | 
            +
              before do
         | 
| 5 | 
            +
                @last_modified = Date.new(2010, 1, 15).to_s
         | 
| 6 | 
            +
                @content_length = '1024'
         | 
| 7 | 
            +
                @response_object = {'foo' => 'bar'}
         | 
| 8 | 
            +
                @response_object = Net::HTTPOK.new('1.1', 200, 'OK')
         | 
| 9 | 
            +
                @response_object.stub(:body => "{foo:'bar'}")
         | 
| 10 | 
            +
                @response_object['last-modified'] = @last_modified
         | 
| 11 | 
            +
                @response_object['content-length'] = @content_length
         | 
| 12 | 
            +
                @parsed_response = {"foo" => "bar"}
         | 
| 13 | 
            +
                @response = HTTParty::Response.new(@response_object, @parsed_response)
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 4 16 | 
             
              describe "initialization" do
         | 
| 5 | 
            -
                 | 
| 6 | 
            -
                  @ | 
| 7 | 
            -
                  @body = "{foo:'bar'}"
         | 
| 8 | 
            -
                  @code = '200'
         | 
| 9 | 
            -
                  @message = 'OK'
         | 
| 10 | 
            -
                  @response = HTTParty::Response.new(@response_object, @body, @code, @message)
         | 
| 11 | 
            -
                end
         | 
| 12 | 
            -
                
         | 
| 13 | 
            -
                it "should set delegate" do
         | 
| 14 | 
            -
                  @response.delegate.should == @response_object
         | 
| 17 | 
            +
                it "should set the Net::HTTP Response" do
         | 
| 18 | 
            +
                  @response.response.should == @response_object
         | 
| 15 19 | 
             
                end
         | 
| 16 | 
            -
             | 
| 20 | 
            +
             | 
| 17 21 | 
             
                it "should set body" do
         | 
| 18 | 
            -
                  @response.body.should == @body
         | 
| 22 | 
            +
                  @response.body.should == @response_object.body
         | 
| 19 23 | 
             
                end
         | 
| 20 | 
            -
             | 
| 24 | 
            +
             | 
| 21 25 | 
             
                it "should set code" do
         | 
| 22 | 
            -
                  @response.code.should.to_s == @code
         | 
| 26 | 
            +
                  @response.code.should.to_s == @response_object.code
         | 
| 23 27 | 
             
                end
         | 
| 24 28 |  | 
| 25 29 | 
             
                it "should set code as a Fixnum" do
         | 
| 26 30 | 
             
                  @response.code.should be_an_instance_of(Fixnum)
         | 
| 27 31 | 
             
                end
         | 
| 28 | 
            -
                
         | 
| 29 | 
            -
                it "should set body" do
         | 
| 30 | 
            -
                  @response.body.should == @body
         | 
| 31 | 
            -
                end
         | 
| 32 32 | 
             
              end
         | 
| 33 | 
            -
             | 
| 34 | 
            -
              it " | 
| 35 | 
            -
                response = HTTParty::Response.new( | 
| 36 | 
            -
                response.headers.should == {' | 
| 33 | 
            +
             | 
| 34 | 
            +
              it "returns response headers" do
         | 
| 35 | 
            +
                response = HTTParty::Response.new(@response_object, @parsed_response)
         | 
| 36 | 
            +
                response.headers.should == {'last-modified' => [@last_modified], 'content-length' => [@content_length]}
         | 
| 37 37 | 
             
              end
         | 
| 38 | 
            -
             | 
| 38 | 
            +
             | 
| 39 39 | 
             
              it "should send missing methods to delegate" do
         | 
| 40 | 
            -
                response = HTTParty::Response.new({'foo' => 'bar'} | 
| 40 | 
            +
                response = HTTParty::Response.new(@response_object, {'foo' => 'bar'})
         | 
| 41 41 | 
             
                response['foo'].should == 'bar'
         | 
| 42 42 | 
             
              end
         | 
| 43 | 
            -
             | 
| 44 | 
            -
              it "should be able to iterate  | 
| 45 | 
            -
                response = HTTParty::Response.new([{'foo' => 'bar'}, {'foo' => 'baz'}] | 
| 43 | 
            +
             | 
| 44 | 
            +
              it "should be able to iterate if it is array" do
         | 
| 45 | 
            +
                response = HTTParty::Response.new(@response_object, [{'foo' => 'bar'}, {'foo' => 'baz'}])
         | 
| 46 46 | 
             
                response.size.should == 2
         | 
| 47 | 
            -
                 | 
| 47 | 
            +
                expect {
         | 
| 48 48 | 
             
                  response.each { |item| }
         | 
| 49 | 
            -
                }. | 
| 49 | 
            +
                }.to_not raise_error
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              it "allows headers to be accessed by mixed-case names in hash notation" do
         | 
| 53 | 
            +
                response = HTTParty::Response.new(@response_object, @parsed_response)
         | 
| 54 | 
            +
                response.headers['Content-LENGTH'].should == @content_length
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              it "returns a comma-delimited value when multiple values exist" do
         | 
| 58 | 
            +
                @response_object.add_field 'set-cookie', 'csrf_id=12345; path=/'
         | 
| 59 | 
            +
                @response_object.add_field 'set-cookie', '_github_ses=A123CdE; path=/'
         | 
| 60 | 
            +
                response = HTTParty::Response.new(@response_object, @parsed_response)
         | 
| 61 | 
            +
                response.headers['set-cookie'].should == "csrf_id=12345; path=/, _github_ses=A123CdE; path=/"
         | 
| 50 62 | 
             
              end
         | 
| 51 | 
            -
             | 
| 63 | 
            +
             | 
| 64 | 
            +
              # Backwards-compatibility - previously, #headers returned a Hash
         | 
| 65 | 
            +
              it "responds to hash methods" do
         | 
| 66 | 
            +
                response = HTTParty::Response.new(@response_object, @parsed_response)
         | 
| 67 | 
            +
                hash_methods = {}.methods - response.headers.methods
         | 
| 68 | 
            +
                hash_methods.each do |method_name|
         | 
| 69 | 
            +
                  response.headers.respond_to?(method_name).should be_true
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 52 73 | 
             
              xit "should allow hashes to be accessed with dot notation" do
         | 
| 53 74 | 
             
                response = HTTParty::Response.new({'foo' => 'bar'}, "{foo:'bar'}", 200, 'OK')
         | 
| 54 75 | 
             
                response.foo.should == 'bar'
         | 
| 55 76 | 
             
              end
         | 
| 56 | 
            -
             | 
| 77 | 
            +
             | 
| 57 78 | 
             
              xit "should allow nested hashes to be accessed with dot notation" do
         | 
| 58 79 | 
             
                response = HTTParty::Response.new({'foo' => {'bar' => 'baz'}}, "{foo: {bar:'baz'}}", 200, 'OK')
         | 
| 59 80 | 
             
                response.foo.should == {'bar' => 'baz'}
         | 
| 60 81 | 
             
                response.foo.bar.should == 'baz'
         | 
| 61 82 | 
             
              end
         | 
| 62 | 
            -
            end
         | 
| 83 | 
            +
            end
         | 
    
        data/spec/httparty_spec.rb
    CHANGED
    
    | @@ -203,6 +203,17 @@ describe HTTParty do | |
| 203 203 | 
             
                end
         | 
| 204 204 | 
             
              end
         | 
| 205 205 |  | 
| 206 | 
            +
              describe "default timeout" do
         | 
| 207 | 
            +
                it "should default to nil" do
         | 
| 208 | 
            +
                  @klass.default_options[:timeout].should == nil
         | 
| 209 | 
            +
                end
         | 
| 210 | 
            +
             | 
| 211 | 
            +
                it "should support updating" do
         | 
| 212 | 
            +
                  @klass.default_timeout 10
         | 
| 213 | 
            +
                  @klass.default_options[:timeout].should == 10
         | 
| 214 | 
            +
                end
         | 
| 215 | 
            +
              end
         | 
| 216 | 
            +
             | 
| 206 217 | 
             
              describe "debug_output" do
         | 
| 207 218 | 
             
                it "stores the given stream as a default_option" do
         | 
| 208 219 | 
             
                  @klass.debug_output $stdout
         | 
| @@ -222,6 +233,13 @@ describe HTTParty do | |
| 222 233 | 
             
                end
         | 
| 223 234 | 
             
              end
         | 
| 224 235 |  | 
| 236 | 
            +
              describe "digest http authentication" do
         | 
| 237 | 
            +
                it "should work" do
         | 
| 238 | 
            +
                  @klass.digest_auth 'foobar', 'secret'
         | 
| 239 | 
            +
                  @klass.default_options[:digest_auth].should == {:username => 'foobar', :password => 'secret'}
         | 
| 240 | 
            +
                end
         | 
| 241 | 
            +
              end
         | 
| 242 | 
            +
             | 
| 225 243 | 
             
              describe "parser" do
         | 
| 226 244 | 
             
                let(:parser) do
         | 
| 227 245 | 
             
                  Proc.new{ |data, format| CustomParser.parse(data) }
         | 
| @@ -243,7 +261,7 @@ describe HTTParty do | |
| 243 261 | 
             
                  @klass.format :json
         | 
| 244 262 | 
             
                  class MyParser < HTTParty::Parser
         | 
| 245 263 | 
             
                    SupportedFormats = {}
         | 
| 246 | 
            -
                  end
         | 
| 264 | 
            +
                  end unless defined?(MyParser)
         | 
| 247 265 | 
             
                  expect do
         | 
| 248 266 | 
             
                    @klass.parser MyParser
         | 
| 249 267 | 
             
                  end.to raise_error(HTTParty::UnsupportedFormat)
         | 
| @@ -316,6 +334,18 @@ describe HTTParty do | |
| 316 334 | 
             
                end
         | 
| 317 335 | 
             
              end
         | 
| 318 336 |  | 
| 337 | 
            +
              describe "#maintain_method_across_redirects" do
         | 
| 338 | 
            +
                it "sets maintain_method_across_redirects to true by default" do
         | 
| 339 | 
            +
                  @klass.maintain_method_across_redirects
         | 
| 340 | 
            +
                  @klass.default_options[:maintain_method_across_redirects].should be_true
         | 
| 341 | 
            +
                end
         | 
| 342 | 
            +
             | 
| 343 | 
            +
                it "sets the maintain_method_across_redirects option to false" do
         | 
| 344 | 
            +
                  @klass.maintain_method_across_redirects false
         | 
| 345 | 
            +
                  @klass.default_options[:maintain_method_across_redirects].should be_false
         | 
| 346 | 
            +
                end
         | 
| 347 | 
            +
              end
         | 
| 348 | 
            +
             | 
| 319 349 | 
             
              describe "with explicit override of automatic redirect handling" do
         | 
| 320 350 | 
             
                before do
         | 
| 321 351 | 
             
                  @request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', :format => :xml, :no_follow => true)
         | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | @@ -2,8 +2,6 @@ require File.join(File.dirname(__FILE__), '..', 'lib', 'httparty') | |
| 2 2 | 
             
            require 'spec/autorun'
         | 
| 3 3 | 
             
            require 'fakeweb'
         | 
| 4 4 |  | 
| 5 | 
            -
            FakeWeb.allow_net_connect = false
         | 
| 6 | 
            -
             | 
| 7 5 | 
             
            def file_fixture(filename)
         | 
| 8 6 | 
             
              open(File.join(File.dirname(__FILE__), 'fixtures', "#{filename.to_s}")).read
         | 
| 9 7 | 
             
            end
         | 
| @@ -12,4 +10,10 @@ Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].e | |
| 12 10 |  | 
| 13 11 | 
             
            Spec::Runner.configure do |config|
         | 
| 14 12 | 
             
              config.include HTTParty::StubResponse
         | 
| 13 | 
            +
              config.before(:suite) do
         | 
| 14 | 
            +
                FakeWeb.allow_net_connect = false
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
              config.after(:suite) do
         | 
| 17 | 
            +
                FakeWeb.allow_net_connect = true
         | 
| 18 | 
            +
              end
         | 
| 15 19 | 
             
            end
         | 
| @@ -14,7 +14,7 @@ module HTTParty | |
| 14 14 | 
             
                end
         | 
| 15 15 |  | 
| 16 16 | 
             
                def stub_response(body, code = 200)
         | 
| 17 | 
            -
                  unless @http
         | 
| 17 | 
            +
                  unless defined?(@http) && @http
         | 
| 18 18 | 
             
                    @http = Net::HTTP.new('localhost', 80)
         | 
| 19 19 | 
             
                    @request.stub!(:http).and_return(@http)
         | 
| 20 20 | 
             
                    @request.stub!(:uri).and_return(URI.parse("http://foo.com/foobar"))
         | 
    
        metadata
    CHANGED
    
    | @@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version | |
| 5 5 | 
             
              segments: 
         | 
| 6 6 | 
             
              - 0
         | 
| 7 7 | 
             
              - 5
         | 
| 8 | 
            -
              - 2
         | 
| 9 8 | 
             
              - 3
         | 
| 10 | 
            -
               | 
| 9 | 
            +
              - 4
         | 
| 10 | 
            +
              version: 0.5.3.4
         | 
| 11 11 | 
             
            platform: ruby
         | 
| 12 12 | 
             
            authors: 
         | 
| 13 13 | 
             
            - John Nunemaker
         | 
| @@ -16,7 +16,7 @@ autorequire: | |
| 16 16 | 
             
            bindir: bin
         | 
| 17 17 | 
             
            cert_chain: []
         | 
| 18 18 |  | 
| 19 | 
            -
            date: 2010- | 
| 19 | 
            +
            date: 2010-05-26 00:00:00 +08:00
         | 
| 20 20 | 
             
            default_executable: httparty
         | 
| 21 21 | 
             
            dependencies: 
         | 
| 22 22 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -29,8 +29,8 @@ dependencies: | |
| 29 29 | 
             
                    segments: 
         | 
| 30 30 | 
             
                    - 0
         | 
| 31 31 | 
             
                    - 1
         | 
| 32 | 
            -
                    -  | 
| 33 | 
            -
                    version: 0.1. | 
| 32 | 
            +
                    - 7
         | 
| 33 | 
            +
                    version: 0.1.7
         | 
| 34 34 | 
             
              type: :runtime
         | 
| 35 35 | 
             
              version_requirements: *id001
         | 
| 36 36 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -55,8 +55,8 @@ dependencies: | |
| 55 55 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 56 56 | 
             
                    segments: 
         | 
| 57 57 | 
             
                    - 0
         | 
| 58 | 
            -
                    -  | 
| 59 | 
            -
                    version: "0. | 
| 58 | 
            +
                    - 7
         | 
| 59 | 
            +
                    version: "0.7"
         | 
| 60 60 | 
             
              type: :development
         | 
| 61 61 | 
             
              version_requirements: *id003
         | 
| 62 62 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -90,13 +90,12 @@ dependencies: | |
| 90 90 | 
             
              prerelease: false
         | 
| 91 91 | 
             
              requirement: &id006 !ruby/object:Gem::Requirement 
         | 
| 92 92 | 
             
                requirements: 
         | 
| 93 | 
            -
                - -  | 
| 93 | 
            +
                - - ~>
         | 
| 94 94 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 95 95 | 
             
                    segments: 
         | 
| 96 96 | 
             
                    - 1
         | 
| 97 | 
            -
                    -  | 
| 98 | 
            -
                     | 
| 99 | 
            -
                    version: 1.2.9
         | 
| 97 | 
            +
                    - 3
         | 
| 98 | 
            +
                    version: "1.3"
         | 
| 100 99 | 
             
              type: :development
         | 
| 101 100 | 
             
              version_requirements: *id006
         | 
| 102 101 | 
             
            description: Makes http fun! Also, makes consuming restful web services dead easy.
         | 
| @@ -128,6 +127,7 @@ files: | |
| 128 127 | 
             
            - features/basic_authentication.feature
         | 
| 129 128 | 
             
            - features/command_line.feature
         | 
| 130 129 | 
             
            - features/deals_with_http_error_codes.feature
         | 
| 130 | 
            +
            - features/digest_authentication.feature
         | 
| 131 131 | 
             
            - features/handles_multiple_formats.feature
         | 
| 132 132 | 
             
            - features/steps/env.rb
         | 
| 133 133 | 
             
            - features/steps/httparty_response_steps.rb
         | 
| @@ -142,6 +142,7 @@ files: | |
| 142 142 | 
             
            - lib/httparty/core_extensions.rb
         | 
| 143 143 | 
             
            - lib/httparty/exceptions.rb
         | 
| 144 144 | 
             
            - lib/httparty/module_inheritable_attributes.rb
         | 
| 145 | 
            +
            - lib/httparty/net_digest_auth.rb
         | 
| 145 146 | 
             
            - lib/httparty/parser.rb
         | 
| 146 147 | 
             
            - lib/httparty/request.rb
         | 
| 147 148 | 
             
            - lib/httparty/response.rb
         | 
| @@ -162,7 +163,7 @@ files: | |
| 162 163 | 
             
            - website/css/common.css
         | 
| 163 164 | 
             
            - website/index.html
         | 
| 164 165 | 
             
            has_rdoc: true
         | 
| 165 | 
            -
            homepage: http://httparty | 
| 166 | 
            +
            homepage: http://github.com/jugend/httparty
         | 
| 166 167 | 
             
            licenses: []
         | 
| 167 168 |  | 
| 168 169 | 
             
            post_install_message: When you HTTParty, you must party hard!
         |