http 0.5.1 → 0.6.0.pre

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of http might be problematic. Click here for more details.

Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -3
  3. data/.rspec +3 -2
  4. data/.rubocop.yml +101 -0
  5. data/.travis.yml +19 -8
  6. data/Gemfile +24 -6
  7. data/LICENSE.txt +1 -1
  8. data/README.md +144 -29
  9. data/Rakefile +23 -1
  10. data/examples/parallel_requests_with_celluloid.rb +2 -2
  11. data/http.gemspec +14 -14
  12. data/lib/http.rb +5 -4
  13. data/lib/http/authorization_header.rb +37 -0
  14. data/lib/http/authorization_header/basic_auth.rb +24 -0
  15. data/lib/http/authorization_header/bearer_token.rb +29 -0
  16. data/lib/http/backports.rb +2 -0
  17. data/lib/http/backports/base64.rb +6 -0
  18. data/lib/http/{uri_backport.rb → backports/uri.rb} +10 -10
  19. data/lib/http/chainable.rb +24 -25
  20. data/lib/http/client.rb +97 -67
  21. data/lib/http/content_type.rb +27 -0
  22. data/lib/http/errors.rb +13 -0
  23. data/lib/http/headers.rb +154 -0
  24. data/lib/http/headers/mixin.rb +11 -0
  25. data/lib/http/mime_type.rb +61 -36
  26. data/lib/http/mime_type/adapter.rb +24 -0
  27. data/lib/http/mime_type/json.rb +23 -0
  28. data/lib/http/options.rb +21 -48
  29. data/lib/http/redirector.rb +12 -7
  30. data/lib/http/request.rb +82 -33
  31. data/lib/http/request/writer.rb +79 -0
  32. data/lib/http/response.rb +39 -68
  33. data/lib/http/response/body.rb +62 -0
  34. data/lib/http/{response_parser.rb → response/parser.rb} +3 -1
  35. data/lib/http/version.rb +1 -1
  36. data/logo.png +0 -0
  37. data/spec/http/authorization_header/basic_auth_spec.rb +29 -0
  38. data/spec/http/authorization_header/bearer_token_spec.rb +36 -0
  39. data/spec/http/authorization_header_spec.rb +41 -0
  40. data/spec/http/backports/base64_spec.rb +13 -0
  41. data/spec/http/client_spec.rb +181 -0
  42. data/spec/http/content_type_spec.rb +47 -0
  43. data/spec/http/headers/mixin_spec.rb +36 -0
  44. data/spec/http/headers_spec.rb +417 -0
  45. data/spec/http/options/body_spec.rb +6 -7
  46. data/spec/http/options/form_spec.rb +4 -5
  47. data/spec/http/options/headers_spec.rb +9 -17
  48. data/spec/http/options/json_spec.rb +17 -0
  49. data/spec/http/options/merge_spec.rb +18 -19
  50. data/spec/http/options/new_spec.rb +5 -19
  51. data/spec/http/options/proxy_spec.rb +6 -6
  52. data/spec/http/options_spec.rb +3 -9
  53. data/spec/http/redirector_spec.rb +100 -0
  54. data/spec/http/request/writer_spec.rb +25 -0
  55. data/spec/http/request_spec.rb +54 -14
  56. data/spec/http/response/body_spec.rb +24 -0
  57. data/spec/http/response_spec.rb +61 -32
  58. data/spec/http_spec.rb +77 -86
  59. data/spec/spec_helper.rb +25 -2
  60. data/spec/support/example_server.rb +58 -49
  61. data/spec/support/proxy_server.rb +27 -11
  62. metadata +60 -55
  63. data/lib/http/header.rb +0 -11
  64. data/lib/http/mime_types/json.rb +0 -19
  65. data/lib/http/request_stream.rb +0 -77
  66. data/spec/http/options/callbacks_spec.rb +0 -62
  67. data/spec/http/options/response_spec.rb +0 -24
  68. 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 :default => :spec
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: Celluloid::IO::TCPSocket).response
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(http://www.ruby-lang.org/ http://www.rubygems.org/ http://celluloid.io/)
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
- # -*- encoding: utf-8 -*-
2
- require File.expand_path('../lib/http/version', __FILE__)
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 = ["Tony Arcieri"]
6
- gem.email = ["tony.arcieri@gmail.com"]
7
- gem.description = "HTTP so awesome it will lure Catherine Zeta Jones into your unicorn petting zoo"
8
- gem.summary = "HTTP should be easy"
9
- gem.homepage = "https://github.com/tarcieri/http"
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 = "http"
15
- gem.require_paths = ["lib"]
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 'rake'
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/request_stream'
8
+ require 'http/request/writer'
9
9
  require 'http/response'
10
- require 'http/response_parser'
11
- require 'http/uri_backport' if RUBY_VERSION < "1.9.0"
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
@@ -0,0 +1,2 @@
1
+ require 'http/backports/uri'
2
+ require 'http/backports/base64'
@@ -0,0 +1,6 @@
1
+ module Base64
2
+ # :nodoc:
3
+ def self.strict_encode64(data)
4
+ encode64(data).gsub(/\n/, '')
5
+ end
6
+ 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' % i
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' % [h, l]] = i.chr
20
- TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
21
- TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
22
- TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
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
- raise ArgumentError, "invalid %-encoding (#{str})" unless /\A[^%]*(?:%\h\h[^%]*)*\z/ =~ str
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
- raise ArgumentError, "invalid data of application/x-www-form-urlencoded (#{str})"
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($1), decode_www_form_component($2)]
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
@@ -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] = proxy[0] if proxy[0].is_a? String
62
- proxy_hash[:proxy_port] = proxy[1] if proxy[1].is_a? Integer
63
- proxy_hash[:proxy_username]= proxy[2] if proxy[2].is_a? String
64
- proxy_hash[:proxy_password]= proxy[3] if proxy[3].is_a? String
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 >=2
63
+ if [2, 4].include?(proxy_hash.keys.size)
67
64
  branch default_options.with_proxy(proxy_hash)
68
65
  else
69
- raise ArgumentError, "invalid HTTP proxy: #{proxy_hash}"
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; with_response(:object); end
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
- if type.is_a? String
95
- with :accept => type
96
- else
97
- mime_type = HTTP::MimeType[type]
98
- raise ArgumentError, "unknown MIME type: #{type}" unless mime_type
99
- with :accept => mime_type.type
100
- end
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
- private
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
- BUFFER_SIZE = 4096 # Input buffer size
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
- end
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(method, uri, options = {})
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
- method_body = body(opts, headers)
36
- if opts.params && !opts.params.empty?
37
- uri="#{uri}?#{URI.encode_www_form(opts.params)}"
38
- end
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 method, uri, headers, proxy, method_body
41
- opts.callbacks[:request].each { |c| c.call(request) }
32
+ request = HTTP::Request.new(verb, uri, headers, proxy, request_body)
33
+ perform request, opts
34
+ end
42
35
 
43
- response = perform request, opts
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 opts.follow
46
- response = Redirector.new(opts.follow).perform request, response do |req|
47
- perform req, opts
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
- opts.callbacks[:response].each { |c| c.call(response) }
52
- format_response method, response, opts.response
46
+ res
53
47
  end
54
48
 
55
- def perform(request, options)
56
- parser = HTTP::Response::Parser.new
57
- uri = request.uri
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
- if uri.is_a?(URI::HTTPS)
61
- if options[:ssl_context] == nil
62
- context = OpenSSL::SSL::SSLContext.new
63
- else
64
- context = options[:ssl_context]
65
- end
66
- socket = options[:ssl_socket_class].new(socket, context)
67
- socket.connect
68
- end
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
- request.stream socket
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
- parser << socket.readpartial(BUFFER_SIZE) until parser.headers
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
- response = HTTP::Response.new(parser.status_code, parser.http_version, parser.headers) do
79
- if !parser.finished? || (@body_remaining && @body_remaining > 0)
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
- @body_remaining -= chunk.length if @body_remaining
86
- @body_remaining = nil if @body_remaining && @body_remaining < 1
88
+ finish_response if :head == req.verb
87
89
 
88
- chunk
89
- end
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
- @body_remaining = Integer(response['Content-Length']) if response['Content-Length']
93
- response
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
- def format_response(method, response, option)
97
- case option
98
- when :auto, NilClass
99
- if method == :head
100
- response
101
- else
102
- HTTP::Response::BodyDelegator.new(response, response.parse_body)
103
- end
104
- when :object
105
- response
106
- when :parsed_body
107
- HTTP::Response::BodyDelegator.new(response, response.parse_body)
108
- when :body
109
- HTTP::Response::BodyDelegator.new(response)
110
- else raise ArgumentError, "invalid response type: #{option}"
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