http 0.5.1 → 0.6.0.pre
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.
Potentially problematic release.
This version of http might be problematic. Click here for more details.
- checksums.yaml +4 -4
 - data/.gitignore +3 -3
 - data/.rspec +3 -2
 - data/.rubocop.yml +101 -0
 - data/.travis.yml +19 -8
 - data/Gemfile +24 -6
 - data/LICENSE.txt +1 -1
 - data/README.md +144 -29
 - data/Rakefile +23 -1
 - data/examples/parallel_requests_with_celluloid.rb +2 -2
 - data/http.gemspec +14 -14
 - data/lib/http.rb +5 -4
 - data/lib/http/authorization_header.rb +37 -0
 - data/lib/http/authorization_header/basic_auth.rb +24 -0
 - data/lib/http/authorization_header/bearer_token.rb +29 -0
 - data/lib/http/backports.rb +2 -0
 - data/lib/http/backports/base64.rb +6 -0
 - data/lib/http/{uri_backport.rb → backports/uri.rb} +10 -10
 - data/lib/http/chainable.rb +24 -25
 - data/lib/http/client.rb +97 -67
 - data/lib/http/content_type.rb +27 -0
 - data/lib/http/errors.rb +13 -0
 - data/lib/http/headers.rb +154 -0
 - data/lib/http/headers/mixin.rb +11 -0
 - data/lib/http/mime_type.rb +61 -36
 - data/lib/http/mime_type/adapter.rb +24 -0
 - data/lib/http/mime_type/json.rb +23 -0
 - data/lib/http/options.rb +21 -48
 - data/lib/http/redirector.rb +12 -7
 - data/lib/http/request.rb +82 -33
 - data/lib/http/request/writer.rb +79 -0
 - data/lib/http/response.rb +39 -68
 - data/lib/http/response/body.rb +62 -0
 - data/lib/http/{response_parser.rb → response/parser.rb} +3 -1
 - data/lib/http/version.rb +1 -1
 - data/logo.png +0 -0
 - data/spec/http/authorization_header/basic_auth_spec.rb +29 -0
 - data/spec/http/authorization_header/bearer_token_spec.rb +36 -0
 - data/spec/http/authorization_header_spec.rb +41 -0
 - data/spec/http/backports/base64_spec.rb +13 -0
 - data/spec/http/client_spec.rb +181 -0
 - data/spec/http/content_type_spec.rb +47 -0
 - data/spec/http/headers/mixin_spec.rb +36 -0
 - data/spec/http/headers_spec.rb +417 -0
 - data/spec/http/options/body_spec.rb +6 -7
 - data/spec/http/options/form_spec.rb +4 -5
 - data/spec/http/options/headers_spec.rb +9 -17
 - data/spec/http/options/json_spec.rb +17 -0
 - data/spec/http/options/merge_spec.rb +18 -19
 - data/spec/http/options/new_spec.rb +5 -19
 - data/spec/http/options/proxy_spec.rb +6 -6
 - data/spec/http/options_spec.rb +3 -9
 - data/spec/http/redirector_spec.rb +100 -0
 - data/spec/http/request/writer_spec.rb +25 -0
 - data/spec/http/request_spec.rb +54 -14
 - data/spec/http/response/body_spec.rb +24 -0
 - data/spec/http/response_spec.rb +61 -32
 - data/spec/http_spec.rb +77 -86
 - data/spec/spec_helper.rb +25 -2
 - data/spec/support/example_server.rb +58 -49
 - data/spec/support/proxy_server.rb +27 -11
 - metadata +60 -55
 - data/lib/http/header.rb +0 -11
 - data/lib/http/mime_types/json.rb +0 -19
 - data/lib/http/request_stream.rb +0 -77
 - data/spec/http/options/callbacks_spec.rb +0 -62
 - data/spec/http/options/response_spec.rb +0 -24
 - data/spec/http/request_stream_spec.rb +0 -25
 
    
        data/Rakefile
    CHANGED
    
    | 
         @@ -4,4 +4,26 @@ require 'bundler/gem_tasks' 
     | 
|
| 
       4 
4 
     | 
    
         
             
            require 'rspec/core/rake_task'
         
     | 
| 
       5 
5 
     | 
    
         
             
            RSpec::Core::RakeTask.new
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
            task : 
     | 
| 
      
 7 
     | 
    
         
            +
            task :test => :spec
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            begin
         
     | 
| 
      
 10 
     | 
    
         
            +
              require 'rubocop/rake_task'
         
     | 
| 
      
 11 
     | 
    
         
            +
              Rubocop::RakeTask.new
         
     | 
| 
      
 12 
     | 
    
         
            +
            rescue LoadError
         
     | 
| 
      
 13 
     | 
    
         
            +
              task :rubocop do
         
     | 
| 
      
 14 
     | 
    
         
            +
                $stderr.puts 'Rubocop is disabled'
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            require 'yardstick/rake/measurement'
         
     | 
| 
      
 19 
     | 
    
         
            +
            Yardstick::Rake::Measurement.new do |measurement|
         
     | 
| 
      
 20 
     | 
    
         
            +
              measurement.output = 'measurement/report.txt'
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            require 'yardstick/rake/verify'
         
     | 
| 
      
 24 
     | 
    
         
            +
            Yardstick::Rake::Verify.new do |verify|
         
     | 
| 
      
 25 
     | 
    
         
            +
              verify.require_exact_threshold = false
         
     | 
| 
      
 26 
     | 
    
         
            +
              verify.threshold = 58
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            task :default => [:spec, :rubocop, :verify_measurements]
         
     | 
| 
         @@ -15,13 +15,13 @@ class HttpFetcher 
     | 
|
| 
       15 
15 
     | 
    
         
             
              def fetch(url)
         
     | 
| 
       16 
16 
     | 
    
         
             
                # Note: For SSL support specify:
         
     | 
| 
       17 
17 
     | 
    
         
             
                # ssl_socket_class: Celluloid::IO::SSLSocket
         
     | 
| 
       18 
     | 
    
         
            -
                HTTP.get(url, socket_class 
     | 
| 
      
 18 
     | 
    
         
            +
                HTTP.get(url, :socket_class => Celluloid::IO::TCPSocket).response
         
     | 
| 
       19 
19 
     | 
    
         
             
              end
         
     | 
| 
       20 
20 
     | 
    
         
             
            end
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
            fetcher = HttpFetcher.new
         
     | 
| 
       23 
23 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
            urls = %w 
     | 
| 
      
 24 
     | 
    
         
            +
            urls = %w[http://www.ruby-lang.org/ http://www.rubygems.org/ http://celluloid.io/]
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
            # Kick off a bunch of future calls to HttpFetcher to grab the URLs in parallel
         
     | 
| 
       27 
27 
     | 
    
         
             
            futures = urls.map { |u| [u, fetcher.future.fetch(u)] }
         
     | 
    
        data/http.gemspec
    CHANGED
    
    | 
         @@ -1,23 +1,23 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
      
 1 
     | 
    
         
            +
            lib = File.expand_path('../lib', __FILE__)
         
     | 
| 
      
 2 
     | 
    
         
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'http/version'
         
     | 
| 
       3 
4 
     | 
    
         | 
| 
       4 
5 
     | 
    
         
             
            Gem::Specification.new do |gem|
         
     | 
| 
       5 
     | 
    
         
            -
              gem.authors       = [ 
     | 
| 
       6 
     | 
    
         
            -
              gem.email         = [ 
     | 
| 
       7 
     | 
    
         
            -
              gem.description   =  
     | 
| 
       8 
     | 
    
         
            -
              gem.summary       =  
     | 
| 
       9 
     | 
    
         
            -
              gem.homepage      =  
     | 
| 
      
 6 
     | 
    
         
            +
              gem.authors       = %w[Tony Arcieri]
         
     | 
| 
      
 7 
     | 
    
         
            +
              gem.email         = %w[tony.arcieri@gmail.com]
         
     | 
| 
      
 8 
     | 
    
         
            +
              gem.description   = 'HTTP so awesome it will lure Catherine Zeta Jones into your unicorn petting zoo'
         
     | 
| 
      
 9 
     | 
    
         
            +
              gem.summary       = 'HTTP should be easy'
         
     | 
| 
      
 10 
     | 
    
         
            +
              gem.homepage      = 'https://github.com/tarcieri/http'
         
     | 
| 
      
 11 
     | 
    
         
            +
              gem.licenses      = %w[MIT]
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
              gem.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
         
     | 
| 
      
 13 
     | 
    
         
            +
              gem.executables   = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
         
     | 
| 
       12 
14 
     | 
    
         
             
              gem.files         = `git ls-files`.split("\n")
         
     | 
| 
       13 
15 
     | 
    
         
             
              gem.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
         
     | 
| 
       14 
     | 
    
         
            -
              gem.name          =  
     | 
| 
       15 
     | 
    
         
            -
              gem.require_paths = [ 
     | 
| 
      
 16 
     | 
    
         
            +
              gem.name          = 'http'
         
     | 
| 
      
 17 
     | 
    
         
            +
              gem.require_paths = %w[lib]
         
     | 
| 
       16 
18 
     | 
    
         
             
              gem.version       = HTTP::VERSION
         
     | 
| 
       17 
19 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
              gem.add_runtime_dependency 'http_parser.rb'
         
     | 
| 
      
 20 
     | 
    
         
            +
              gem.add_runtime_dependency 'http_parser.rb', '~> 0.6.0'
         
     | 
| 
       19 
21 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
              gem.add_development_dependency ' 
     | 
| 
       21 
     | 
    
         
            -
              gem.add_development_dependency 'rspec', '>= 2.11'
         
     | 
| 
       22 
     | 
    
         
            -
              gem.add_development_dependency 'json'
         
     | 
| 
      
 22 
     | 
    
         
            +
              gem.add_development_dependency 'bundler', '~> 1.0'
         
     | 
| 
       23 
23 
     | 
    
         
             
            end
         
     | 
    
        data/lib/http.rb
    CHANGED
    
    | 
         @@ -1,14 +1,15 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'http/parser'
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            require 'http/errors'
         
     | 
| 
       3 
4 
     | 
    
         
             
            require 'http/chainable'
         
     | 
| 
       4 
5 
     | 
    
         
             
            require 'http/client'
         
     | 
| 
       5 
     | 
    
         
            -
            require 'http/mime_type'
         
     | 
| 
       6 
6 
     | 
    
         
             
            require 'http/options'
         
     | 
| 
       7 
7 
     | 
    
         
             
            require 'http/request'
         
     | 
| 
       8 
     | 
    
         
            -
            require 'http/ 
     | 
| 
      
 8 
     | 
    
         
            +
            require 'http/request/writer'
         
     | 
| 
       9 
9 
     | 
    
         
             
            require 'http/response'
         
     | 
| 
       10 
     | 
    
         
            -
            require 'http/ 
     | 
| 
       11 
     | 
    
         
            -
            require 'http/ 
     | 
| 
      
 10 
     | 
    
         
            +
            require 'http/response/body'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'http/response/parser'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'http/backports' if RUBY_VERSION < '1.9.0'
         
     | 
| 
       12 
13 
     | 
    
         | 
| 
       13 
14 
     | 
    
         
             
            # HTTP should be easy
         
     | 
| 
       14 
15 
     | 
    
         
             
            module HTTP
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module HTTP
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Authorization header value builders
         
     | 
| 
      
 3 
     | 
    
         
            +
              module AuthorizationHeader
         
     | 
| 
      
 4 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 5 
     | 
    
         
            +
                  # Associate type with given builder.
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # @param [#to_sym] type
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # @param [Class] klass
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # @return [void]
         
     | 
| 
      
 9 
     | 
    
         
            +
                  def register(type, klass)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    builders[type.to_sym] = klass
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  # Builds Authorization header value with associated builder.
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # @param [#to_sym] type
         
     | 
| 
      
 15 
     | 
    
         
            +
                  # @param [Object] opts
         
     | 
| 
      
 16 
     | 
    
         
            +
                  # @return [String]
         
     | 
| 
      
 17 
     | 
    
         
            +
                  def build(type, opts)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    klass = builders[type.to_sym]
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    fail Error, "Unknown authorization type #{type}" unless klass
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    klass.new opts
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                private
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  # :nodoc:
         
     | 
| 
      
 28 
     | 
    
         
            +
                  def builders
         
     | 
| 
      
 29 
     | 
    
         
            +
                    @builders ||= {}
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            # built-in builders
         
     | 
| 
      
 36 
     | 
    
         
            +
            require 'http/authorization_header/basic_auth'
         
     | 
| 
      
 37 
     | 
    
         
            +
            require 'http/authorization_header/bearer_token'
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'base64'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module HTTP
         
     | 
| 
      
 4 
     | 
    
         
            +
              module AuthorizationHeader
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Basic authorization header builder
         
     | 
| 
      
 6 
     | 
    
         
            +
                # @see http://tools.ietf.org/html/rfc2617
         
     | 
| 
      
 7 
     | 
    
         
            +
                class BasicAuth
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # @param [#fetch] opts
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # @option opts [#to_s] :user
         
     | 
| 
      
 10 
     | 
    
         
            +
                  # @option opts [#to_s] :pass
         
     | 
| 
      
 11 
     | 
    
         
            +
                  def initialize(opts)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @user = opts.fetch :user
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @pass = opts.fetch :pass
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  # :nodoc:
         
     | 
| 
      
 17 
     | 
    
         
            +
                  def to_s
         
     | 
| 
      
 18 
     | 
    
         
            +
                    'Basic ' << Base64.strict_encode64("#{@user}:#{@pass}")
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                register :basic, BasicAuth
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'base64'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module HTTP
         
     | 
| 
      
 4 
     | 
    
         
            +
              module AuthorizationHeader
         
     | 
| 
      
 5 
     | 
    
         
            +
                # OAuth2 Bearer token authorization header builder
         
     | 
| 
      
 6 
     | 
    
         
            +
                # @see http://tools.ietf.org/html/rfc6750
         
     | 
| 
      
 7 
     | 
    
         
            +
                class BearerToken
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # @param [#fetch] opts
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # @option opts [#to_s] :token
         
     | 
| 
      
 10 
     | 
    
         
            +
                  # @option opts [#to_s] :encode (false)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  def initialize(opts)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @encode = opts.fetch :encode, false
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @token  = opts.fetch :token
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  def token
         
     | 
| 
      
 17 
     | 
    
         
            +
                    return Base64.strict_encode64 @token if @encode
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @token
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  # :nodoc:
         
     | 
| 
      
 22 
     | 
    
         
            +
                  def to_s
         
     | 
| 
      
 23 
     | 
    
         
            +
                    "Bearer #{token}"
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                register :bearer, BearerToken
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -9,17 +9,17 @@ require 'uri' 
     | 
|
| 
       9 
9 
     | 
    
         
             
            module URI
         
     | 
| 
       10 
10 
     | 
    
         
             
              TBLENCWWWCOMP_ = {} # :nodoc:
         
     | 
| 
       11 
11 
     | 
    
         
             
              256.times do |i|
         
     | 
| 
       12 
     | 
    
         
            -
                TBLENCWWWCOMP_[i.chr] = '%%%02X'  
     | 
| 
      
 12 
     | 
    
         
            +
                TBLENCWWWCOMP_[i.chr] = format('%%%02X', i)
         
     | 
| 
       13 
13 
     | 
    
         
             
              end
         
     | 
| 
       14 
14 
     | 
    
         
             
              TBLENCWWWCOMP_[' '] = '+'
         
     | 
| 
       15 
15 
     | 
    
         
             
              TBLENCWWWCOMP_.freeze
         
     | 
| 
       16 
16 
     | 
    
         
             
              TBLDECWWWCOMP_ = {} # :nodoc:
         
     | 
| 
       17 
17 
     | 
    
         
             
              256.times do |i|
         
     | 
| 
       18 
     | 
    
         
            -
                h, l = i>>4, i&15
         
     | 
| 
       19 
     | 
    
         
            -
                TBLDECWWWCOMP_['%%%X%X'  
     | 
| 
       20 
     | 
    
         
            -
                TBLDECWWWCOMP_['%%%x%X'  
     | 
| 
       21 
     | 
    
         
            -
                TBLDECWWWCOMP_['%%%X%x'  
     | 
| 
       22 
     | 
    
         
            -
                TBLDECWWWCOMP_['%%%x%x'  
     | 
| 
      
 18 
     | 
    
         
            +
                h, l = i >> 4, i & 15
         
     | 
| 
      
 19 
     | 
    
         
            +
                TBLDECWWWCOMP_[format('%%%X%X', h, l)] = i.chr
         
     | 
| 
      
 20 
     | 
    
         
            +
                TBLDECWWWCOMP_[format('%%%x%X', h, l)] = i.chr
         
     | 
| 
      
 21 
     | 
    
         
            +
                TBLDECWWWCOMP_[format('%%%X%x', h, l)] = i.chr
         
     | 
| 
      
 22 
     | 
    
         
            +
                TBLDECWWWCOMP_[format('%%%x%x', h, l)] = i.chr
         
     | 
| 
       23 
23 
     | 
    
         
             
              end
         
     | 
| 
       24 
24 
     | 
    
         
             
              TBLDECWWWCOMP_['+'] = ' '
         
     | 
| 
       25 
25 
     | 
    
         
             
              TBLDECWWWCOMP_.freeze
         
     | 
| 
         @@ -43,7 +43,7 @@ module URI 
     | 
|
| 
       43 
43 
     | 
    
         
             
              #
         
     | 
| 
       44 
44 
     | 
    
         
             
              # See URI.encode_www_form_component, URI.decode_www_form
         
     | 
| 
       45 
45 
     | 
    
         
             
              def self.decode_www_form_component(str)
         
     | 
| 
       46 
     | 
    
         
            -
                 
     | 
| 
      
 46 
     | 
    
         
            +
                fail(ArgumentError, "invalid %-encoding (#{str})") unless /\A[^%]*(?:%\h\h[^%]*)*\z/ =~ str
         
     | 
| 
       47 
47 
     | 
    
         
             
                str.gsub(/\+|%\h\h/) { |chr| TBLDECWWWCOMP_[chr] }
         
     | 
| 
       48 
48 
     | 
    
         
             
              end
         
     | 
| 
       49 
49 
     | 
    
         | 
| 
         @@ -76,7 +76,7 @@ module URI 
     | 
|
| 
       76 
76 
     | 
    
         
             
              #
         
     | 
| 
       77 
77 
     | 
    
         
             
              # See URI.encode_www_form_component, URI.decode_www_form
         
     | 
| 
       78 
78 
     | 
    
         
             
              def self.encode_www_form(enum)
         
     | 
| 
       79 
     | 
    
         
            -
                enum.map do |k,v|
         
     | 
| 
      
 79 
     | 
    
         
            +
                enum.map do |k, v|
         
     | 
| 
       80 
80 
     | 
    
         
             
                  if v.nil?
         
     | 
| 
       81 
81 
     | 
    
         
             
                    encode_www_form_component(k)
         
     | 
| 
       82 
82 
     | 
    
         
             
                  elsif v.respond_to?(:to_ary)
         
     | 
| 
         @@ -120,11 +120,11 @@ module URI 
     | 
|
| 
       120 
120 
     | 
    
         
             
              def self.decode_www_form(str)
         
     | 
| 
       121 
121 
     | 
    
         
             
                return [] if str.empty?
         
     | 
| 
       122 
122 
     | 
    
         
             
                unless /\A#{WFKV_}=#{WFKV_}(?:[;&]#{WFKV_}=#{WFKV_})*\z/o =~ str
         
     | 
| 
       123 
     | 
    
         
            -
                   
     | 
| 
      
 123 
     | 
    
         
            +
                  fail(ArgumentError, "invalid data of application/x-www-form-urlencoded (#{str})")
         
     | 
| 
       124 
124 
     | 
    
         
             
                end
         
     | 
| 
       125 
125 
     | 
    
         
             
                ary = []
         
     | 
| 
       126 
126 
     | 
    
         
             
                $&.scan(/([^=;&]+)=([^;&]*)/) do
         
     | 
| 
       127 
     | 
    
         
            -
                  ary << [decode_www_form_component( 
     | 
| 
      
 127 
     | 
    
         
            +
                  ary << [decode_www_form_component(Regexp.last_match[1]), decode_www_form_component(Regexp.last_match[2])]
         
     | 
| 
       128 
128 
     | 
    
         
             
                end
         
     | 
| 
       129 
129 
     | 
    
         
             
                ary
         
     | 
| 
       130 
130 
     | 
    
         
             
              end
         
     | 
    
        data/lib/http/chainable.rb
    CHANGED
    
    | 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'http/authorization_header'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module HTTP
         
     | 
| 
       2 
4 
     | 
    
         
             
              module Chainable
         
     | 
| 
       3 
5 
     | 
    
         
             
                # Request a get sans response body
         
     | 
| 
         @@ -50,34 +52,26 @@ module HTTP 
     | 
|
| 
       50 
52 
     | 
    
         
             
                  branch(options).request verb, uri
         
     | 
| 
       51 
53 
     | 
    
         
             
                end
         
     | 
| 
       52 
54 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
                # Make a request invoking the given event callbacks
         
     | 
| 
       54 
     | 
    
         
            -
                def on(event, &block)
         
     | 
| 
       55 
     | 
    
         
            -
                  branch default_options.with_callback(event, block)
         
     | 
| 
       56 
     | 
    
         
            -
                end
         
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
55 
     | 
    
         
             
                # Make a request through an HTTP proxy
         
     | 
| 
       59 
56 
     | 
    
         
             
                def via(*proxy)
         
     | 
| 
       60 
57 
     | 
    
         
             
                  proxy_hash = {}
         
     | 
| 
       61 
     | 
    
         
            -
                  proxy_hash[:proxy_address] 
     | 
| 
       62 
     | 
    
         
            -
                  proxy_hash[:proxy_port] 
     | 
| 
       63 
     | 
    
         
            -
                  proxy_hash[:proxy_username]= proxy[2] if proxy[2].is_a? 
     | 
| 
       64 
     | 
    
         
            -
                  proxy_hash[:proxy_password]= proxy[3] if proxy[3].is_a? 
     | 
| 
      
 58 
     | 
    
         
            +
                  proxy_hash[:proxy_address]  = proxy[0] if proxy[0].is_a?(String)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  proxy_hash[:proxy_port]     = proxy[1] if proxy[1].is_a?(Integer)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  proxy_hash[:proxy_username] = proxy[2] if proxy[2].is_a?(String)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  proxy_hash[:proxy_password] = proxy[3] if proxy[3].is_a?(String)
         
     | 
| 
       65 
62 
     | 
    
         | 
| 
       66 
     | 
    
         
            -
                  if proxy_hash.keys.size 
     | 
| 
      
 63 
     | 
    
         
            +
                  if [2, 4].include?(proxy_hash.keys.size)
         
     | 
| 
       67 
64 
     | 
    
         
             
                    branch default_options.with_proxy(proxy_hash)
         
     | 
| 
       68 
65 
     | 
    
         
             
                  else
         
     | 
| 
       69 
     | 
    
         
            -
                     
     | 
| 
      
 66 
     | 
    
         
            +
                    fail(RequestError, "invalid HTTP proxy: #{proxy_hash}")
         
     | 
| 
       70 
67 
     | 
    
         
             
                  end
         
     | 
| 
       71 
68 
     | 
    
         
             
                end
         
     | 
| 
       72 
69 
     | 
    
         
             
                alias_method :through, :via
         
     | 
| 
       73 
70 
     | 
    
         | 
| 
       74 
     | 
    
         
            -
                # Specify the kind of response to return (:auto, :object, :body, :parsed_body)
         
     | 
| 
       75 
     | 
    
         
            -
                def with_response(response_type)
         
     | 
| 
       76 
     | 
    
         
            -
                  branch default_options.with_response(response_type)
         
     | 
| 
       77 
     | 
    
         
            -
                end
         
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
71 
     | 
    
         
             
                # Alias for with_response(:object)
         
     | 
| 
       80 
     | 
    
         
            -
                def stream 
     | 
| 
      
 72 
     | 
    
         
            +
                def stream
         
     | 
| 
      
 73 
     | 
    
         
            +
                  with_response(:object)
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
       81 
75 
     | 
    
         | 
| 
       82 
76 
     | 
    
         
             
                def with_follow(follow)
         
     | 
| 
       83 
77 
     | 
    
         
             
                  branch default_options.with_follow(follow)
         
     | 
| 
         @@ -91,13 +85,18 @@ module HTTP 
     | 
|
| 
       91 
85 
     | 
    
         | 
| 
       92 
86 
     | 
    
         
             
                # Accept the given MIME type(s)
         
     | 
| 
       93 
87 
     | 
    
         
             
                def accept(type)
         
     | 
| 
       94 
     | 
    
         
            -
                   
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
      
 88 
     | 
    
         
            +
                  with :accept => MimeType.normalize(type)
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                # Make a request with the given Authorization header
         
     | 
| 
      
 92 
     | 
    
         
            +
                def auth(*args)
         
     | 
| 
      
 93 
     | 
    
         
            +
                  value = case args.count
         
     | 
| 
      
 94 
     | 
    
         
            +
                          when 1 then args.first
         
     | 
| 
      
 95 
     | 
    
         
            +
                          when 2 then AuthorizationHeader.build(*args)
         
     | 
| 
      
 96 
     | 
    
         
            +
                          else fail ArgumentError, "wrong number of arguments (#{args.count} for 1..2)"
         
     | 
| 
      
 97 
     | 
    
         
            +
                          end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                  with :authorization => value.to_s
         
     | 
| 
       101 
100 
     | 
    
         
             
                end
         
     | 
| 
       102 
101 
     | 
    
         | 
| 
       103 
102 
     | 
    
         
             
                def default_options
         
     | 
| 
         @@ -128,7 +127,7 @@ module HTTP 
     | 
|
| 
       128 
127 
     | 
    
         
             
                  end
         
     | 
| 
       129 
128 
     | 
    
         
             
                end
         
     | 
| 
       130 
129 
     | 
    
         | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
      
 130 
     | 
    
         
            +
              private
         
     | 
| 
       132 
131 
     | 
    
         | 
| 
       133 
132 
     | 
    
         
             
                def branch(options)
         
     | 
| 
       134 
133 
     | 
    
         
             
                  HTTP::Client.new(options)
         
     | 
    
        data/lib/http/client.rb
    CHANGED
    
    | 
         @@ -7,108 +7,138 @@ module HTTP 
     | 
|
| 
       7 
7 
     | 
    
         
             
              class Client
         
     | 
| 
       8 
8 
     | 
    
         
             
                include Chainable
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
                 
     | 
| 
      
 10 
     | 
    
         
            +
                # Input buffer size
         
     | 
| 
      
 11 
     | 
    
         
            +
                BUFFER_SIZE = 16_384
         
     | 
| 
       11 
12 
     | 
    
         | 
| 
       12 
13 
     | 
    
         
             
                attr_reader :default_options
         
     | 
| 
       13 
14 
     | 
    
         | 
| 
       14 
15 
     | 
    
         
             
                def initialize(default_options = {})
         
     | 
| 
       15 
16 
     | 
    
         
             
                  @default_options = HTTP::Options.new(default_options)
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                def body(opts, headers)
         
     | 
| 
       19 
     | 
    
         
            -
                  if opts.body
         
     | 
| 
       20 
     | 
    
         
            -
                    body = opts.body
         
     | 
| 
       21 
     | 
    
         
            -
                  elsif opts.form
         
     | 
| 
       22 
     | 
    
         
            -
                    headers['Content-Type'] ||= 'application/x-www-form-urlencoded'
         
     | 
| 
       23 
     | 
    
         
            -
                    body = URI.encode_www_form(opts.form)
         
     | 
| 
       24 
     | 
    
         
            -
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @parser = HTTP::Response::Parser.new
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @socket = nil
         
     | 
| 
       25 
19 
     | 
    
         
             
                end
         
     | 
| 
       26 
20 
     | 
    
         | 
| 
       27 
21 
     | 
    
         
             
                # Make an HTTP request
         
     | 
| 
       28 
     | 
    
         
            -
                def request( 
     | 
| 
      
 22 
     | 
    
         
            +
                def request(verb, uri, options = {})
         
     | 
| 
       29 
23 
     | 
    
         
             
                  opts = @default_options.merge(options)
         
     | 
| 
       30 
     | 
    
         
            -
                  host = URI.parse(uri).host
         
     | 
| 
       31 
     | 
    
         
            -
                  opts.headers["Host"] = host
         
     | 
| 
       32 
24 
     | 
    
         
             
                  headers = opts.headers
         
     | 
| 
       33 
25 
     | 
    
         
             
                  proxy = opts.proxy
         
     | 
| 
       34 
26 
     | 
    
         | 
| 
       35 
     | 
    
         
            -
                   
     | 
| 
       36 
     | 
    
         
            -
                   
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
                   
     | 
| 
      
 27 
     | 
    
         
            +
                  request_body = make_request_body(opts, headers)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  uri, opts = normalize_get_params(uri, opts) if verb == :get
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  uri = "#{uri}?#{URI.encode_www_form(opts.params)}" if opts.params && !opts.params.empty?
         
     | 
| 
       39 
31 
     | 
    
         | 
| 
       40 
     | 
    
         
            -
                  request = HTTP::Request.new 
     | 
| 
       41 
     | 
    
         
            -
                   
     | 
| 
      
 32 
     | 
    
         
            +
                  request = HTTP::Request.new(verb, uri, headers, proxy, request_body)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  perform request, opts
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
       42 
35 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
      
 36 
     | 
    
         
            +
                # Perform the HTTP request (following redirects if needed)
         
     | 
| 
      
 37 
     | 
    
         
            +
                def perform(req, options)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  res = perform_without_following_redirects req, options
         
     | 
| 
       44 
39 
     | 
    
         | 
| 
       45 
     | 
    
         
            -
                  if  
     | 
| 
       46 
     | 
    
         
            -
                     
     | 
| 
       47 
     | 
    
         
            -
                       
     | 
| 
      
 40 
     | 
    
         
            +
                  if options.follow
         
     | 
| 
      
 41 
     | 
    
         
            +
                    res = Redirector.new(options.follow).perform req, res do |request|
         
     | 
| 
      
 42 
     | 
    
         
            +
                      perform_without_following_redirects request, options
         
     | 
| 
       48 
43 
     | 
    
         
             
                    end
         
     | 
| 
       49 
44 
     | 
    
         
             
                  end
         
     | 
| 
       50 
45 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
                   
     | 
| 
       52 
     | 
    
         
            -
                  format_response method, response, opts.response
         
     | 
| 
      
 46 
     | 
    
         
            +
                  res
         
     | 
| 
       53 
47 
     | 
    
         
             
                end
         
     | 
| 
       54 
48 
     | 
    
         | 
| 
       55 
     | 
    
         
            -
                 
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
                   
     | 
| 
       58 
     | 
    
         
            -
                  socket = options[:socket_class].open(uri.host, uri.port) # TODO: proxy support
         
     | 
| 
      
 49 
     | 
    
         
            +
                # Read a chunk of the body
         
     | 
| 
      
 50 
     | 
    
         
            +
                def readpartial(size = BUFFER_SIZE)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  return unless @socket
         
     | 
| 
       59 
52 
     | 
    
         | 
| 
       60 
     | 
    
         
            -
                   
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
      
 53 
     | 
    
         
            +
                  read_more size
         
     | 
| 
      
 54 
     | 
    
         
            +
                  chunk = @parser.chunk
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  finish_response if @parser.finished?
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  chunk
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
              private
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                # Perform a single (no follow) HTTP request
         
     | 
| 
      
 64 
     | 
    
         
            +
                def perform_without_following_redirects(req, options)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  # finish previous response if client was re-used
         
     | 
| 
      
 66 
     | 
    
         
            +
                  # TODO: this is pretty wrong, as socket shoud be part of response
         
     | 
| 
      
 67 
     | 
    
         
            +
                  #       connection, so that re-use of client will not break multiple
         
     | 
| 
      
 68 
     | 
    
         
            +
                  #       chunked responses
         
     | 
| 
      
 69 
     | 
    
         
            +
                  finish_response
         
     | 
| 
       69 
70 
     | 
    
         | 
| 
       70 
     | 
    
         
            -
                   
     | 
| 
      
 71 
     | 
    
         
            +
                  uri = req.uri
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  # TODO: keep-alive support
         
     | 
| 
      
 74 
     | 
    
         
            +
                  @socket = options[:socket_class].open(req.socket_host, req.socket_port)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  @socket = start_tls(@socket, options) if uri.is_a?(URI::HTTPS)
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                  req.stream @socket
         
     | 
| 
       71 
78 
     | 
    
         | 
| 
       72 
79 
     | 
    
         
             
                  begin
         
     | 
| 
       73 
     | 
    
         
            -
                     
     | 
| 
      
 80 
     | 
    
         
            +
                    read_more BUFFER_SIZE until @parser.headers
         
     | 
| 
       74 
81 
     | 
    
         
             
                  rescue IOError, Errno::ECONNRESET, Errno::EPIPE => ex
         
     | 
| 
       75 
82 
     | 
    
         
             
                    raise IOError, "problem making HTTP request: #{ex}"
         
     | 
| 
       76 
83 
     | 
    
         
             
                  end
         
     | 
| 
       77 
84 
     | 
    
         | 
| 
       78 
     | 
    
         
            -
                   
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
                      chunk = parser.chunk || begin
         
     | 
| 
       81 
     | 
    
         
            -
                        parser << socket.readpartial(BUFFER_SIZE)
         
     | 
| 
       82 
     | 
    
         
            -
                        parser.chunk || ""
         
     | 
| 
       83 
     | 
    
         
            -
                      end
         
     | 
| 
      
 85 
     | 
    
         
            +
                  body = Response::Body.new(self)
         
     | 
| 
      
 86 
     | 
    
         
            +
                  res  = Response.new(@parser.status_code, @parser.http_version, @parser.headers, body, uri)
         
     | 
| 
       84 
87 
     | 
    
         | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
                      @body_remaining = nil if @body_remaining && @body_remaining < 1
         
     | 
| 
      
 88 
     | 
    
         
            +
                  finish_response if :head == req.verb
         
     | 
| 
       87 
89 
     | 
    
         | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
      
 90 
     | 
    
         
            +
                  res
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                # Initialize TLS connection
         
     | 
| 
      
 94 
     | 
    
         
            +
                def start_tls(socket, options)
         
     | 
| 
      
 95 
     | 
    
         
            +
                  # TODO: abstract away SSLContexts so we can use other TLS libraries
         
     | 
| 
      
 96 
     | 
    
         
            +
                  context = options[:ssl_context] || OpenSSL::SSL::SSLContext.new
         
     | 
| 
      
 97 
     | 
    
         
            +
                  socket  = options[:ssl_socket_class].new(socket, context)
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                  socket.connect
         
     | 
| 
      
 100 
     | 
    
         
            +
                  socket
         
     | 
| 
      
 101 
     | 
    
         
            +
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                # Create the request body object to send
         
     | 
| 
      
 104 
     | 
    
         
            +
                def make_request_body(opts, headers)
         
     | 
| 
      
 105 
     | 
    
         
            +
                  if opts.body
         
     | 
| 
      
 106 
     | 
    
         
            +
                    opts.body
         
     | 
| 
      
 107 
     | 
    
         
            +
                  elsif opts.form
         
     | 
| 
      
 108 
     | 
    
         
            +
                    headers['Content-Type'] ||= 'application/x-www-form-urlencoded'
         
     | 
| 
      
 109 
     | 
    
         
            +
                    URI.encode_www_form(opts.form)
         
     | 
| 
      
 110 
     | 
    
         
            +
                  elsif opts.json
         
     | 
| 
      
 111 
     | 
    
         
            +
                    headers['Content-Type'] ||= 'application/json'
         
     | 
| 
      
 112 
     | 
    
         
            +
                    MimeType[:json].encode opts.json
         
     | 
| 
       90 
113 
     | 
    
         
             
                  end
         
     | 
| 
      
 114 
     | 
    
         
            +
                end
         
     | 
| 
       91 
115 
     | 
    
         | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
      
 116 
     | 
    
         
            +
                # Callback for when we've reached the end of a response
         
     | 
| 
      
 117 
     | 
    
         
            +
                def finish_response
         
     | 
| 
      
 118 
     | 
    
         
            +
                  @socket.close if @socket && !@socket.closed?
         
     | 
| 
      
 119 
     | 
    
         
            +
                  @parser.reset
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                  @socket = nil
         
     | 
| 
       94 
122 
     | 
    
         
             
                end
         
     | 
| 
       95 
123 
     | 
    
         | 
| 
       96 
     | 
    
         
            -
                 
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
                   
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
                   
     | 
| 
       109 
     | 
    
         
            -
                     
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
      
 124 
     | 
    
         
            +
                # Feeds some more data into parser
         
     | 
| 
      
 125 
     | 
    
         
            +
                def read_more(size)
         
     | 
| 
      
 126 
     | 
    
         
            +
                  @parser << @socket.readpartial(size) unless @parser.finished?
         
     | 
| 
      
 127 
     | 
    
         
            +
                  return true
         
     | 
| 
      
 128 
     | 
    
         
            +
                rescue EOFError
         
     | 
| 
      
 129 
     | 
    
         
            +
                  return false
         
     | 
| 
      
 130 
     | 
    
         
            +
                end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                # Moves uri get params into the opts.params hash
         
     | 
| 
      
 133 
     | 
    
         
            +
                # @return [Array<URI, Hash>]
         
     | 
| 
      
 134 
     | 
    
         
            +
                def normalize_get_params(uri, opts)
         
     | 
| 
      
 135 
     | 
    
         
            +
                  uri = URI(uri) unless uri.is_a?(URI)
         
     | 
| 
      
 136 
     | 
    
         
            +
                  if uri.query
         
     | 
| 
      
 137 
     | 
    
         
            +
                    extracted_params_from_uri = Hash[URI.decode_www_form(uri.query)]
         
     | 
| 
      
 138 
     | 
    
         
            +
                    opts = opts.with_params(extracted_params_from_uri.merge(opts.params || {}))
         
     | 
| 
      
 139 
     | 
    
         
            +
                    uri.query = nil
         
     | 
| 
       111 
140 
     | 
    
         
             
                  end
         
     | 
| 
      
 141 
     | 
    
         
            +
                  [uri, opts]
         
     | 
| 
       112 
142 
     | 
    
         
             
                end
         
     | 
| 
       113 
143 
     | 
    
         
             
              end
         
     | 
| 
       114 
144 
     | 
    
         
             
            end
         
     |