typhoeus 0.3.3 → 0.4.0
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/{CHANGELOG.markdown → CHANGELOG.md} +21 -12
- data/LICENSE +2 -0
- data/README.md +455 -0
- data/Rakefile +6 -26
- data/lib/typhoeus.rb +4 -6
- data/lib/typhoeus/curl.rb +453 -0
- data/lib/typhoeus/easy.rb +60 -358
- data/lib/typhoeus/easy/auth.rb +14 -0
- data/lib/typhoeus/easy/callbacks.rb +33 -0
- data/lib/typhoeus/easy/ffi_helper.rb +61 -0
- data/lib/typhoeus/easy/infos.rb +90 -0
- data/lib/typhoeus/easy/options.rb +115 -0
- data/lib/typhoeus/easy/proxy.rb +20 -0
- data/lib/typhoeus/easy/ssl.rb +82 -0
- data/lib/typhoeus/form.rb +30 -1
- data/lib/typhoeus/{normalized_header_hash.rb → header.rb} +2 -6
- data/lib/typhoeus/hydra.rb +9 -12
- data/lib/typhoeus/hydra_mock.rb +2 -2
- data/lib/typhoeus/multi.rb +118 -9
- data/lib/typhoeus/param_processor.rb +43 -0
- data/lib/typhoeus/request.rb +18 -21
- data/lib/typhoeus/response.rb +5 -4
- data/lib/typhoeus/utils.rb +14 -27
- data/lib/typhoeus/version.rb +1 -1
- metadata +155 -152
- data/Gemfile.lock +0 -37
- data/ext/typhoeus/.gitignore +0 -7
- data/ext/typhoeus/extconf.rb +0 -65
- data/ext/typhoeus/native.c +0 -12
- data/ext/typhoeus/native.h +0 -22
- data/ext/typhoeus/typhoeus_easy.c +0 -232
- data/ext/typhoeus/typhoeus_easy.h +0 -20
- data/ext/typhoeus/typhoeus_form.c +0 -59
- data/ext/typhoeus/typhoeus_form.h +0 -13
- data/ext/typhoeus/typhoeus_multi.c +0 -217
- data/ext/typhoeus/typhoeus_multi.h +0 -16
- data/lib/typhoeus/.gitignore +0 -1
- data/lib/typhoeus/service.rb +0 -20
- data/spec/fixtures/placeholder.gif +0 -0
- data/spec/fixtures/placeholder.txt +0 -1
- data/spec/fixtures/placeholder.ukn +0 -0
- data/spec/fixtures/result_set.xml +0 -60
- data/spec/servers/app.rb +0 -97
- data/spec/spec_helper.rb +0 -19
- data/spec/support/typhoeus_localhost_server.rb +0 -58
- data/spec/typhoeus/easy_spec.rb +0 -391
- data/spec/typhoeus/filter_spec.rb +0 -35
- data/spec/typhoeus/form_spec.rb +0 -117
- data/spec/typhoeus/hydra_mock_spec.rb +0 -300
- data/spec/typhoeus/hydra_spec.rb +0 -602
- data/spec/typhoeus/multi_spec.rb +0 -74
- data/spec/typhoeus/normalized_header_hash_spec.rb +0 -41
- data/spec/typhoeus/remote_method_spec.rb +0 -141
- data/spec/typhoeus/remote_proxy_object_spec.rb +0 -65
- data/spec/typhoeus/remote_spec.rb +0 -695
- data/spec/typhoeus/request_spec.rb +0 -387
- data/spec/typhoeus/response_spec.rb +0 -192
- data/spec/typhoeus/utils_spec.rb +0 -22
- data/typhoeus.gemspec +0 -33
@@ -1,5 +1,5 @@
|
|
1
1
|
module Typhoeus
|
2
|
-
class
|
2
|
+
class Header < ::Hash
|
3
3
|
def initialize(constructor = {})
|
4
4
|
if constructor.is_a?(Hash)
|
5
5
|
super
|
@@ -17,10 +17,6 @@ module Typhoeus
|
|
17
17
|
super(convert_key(key))
|
18
18
|
end
|
19
19
|
|
20
|
-
[:include?, :has_key?, :member?].each do |method|
|
21
|
-
alias_method method, :key?
|
22
|
-
end
|
23
|
-
|
24
20
|
def [](key)
|
25
21
|
super(convert_key(key))
|
26
22
|
end
|
@@ -39,7 +35,7 @@ module Typhoeus
|
|
39
35
|
alias_method :merge!, :update
|
40
36
|
|
41
37
|
def dup
|
42
|
-
self.class.new(self)
|
38
|
+
self.class.new(Marshal.load(Marshal.dump(self)))
|
43
39
|
end
|
44
40
|
|
45
41
|
def merge(hash)
|
data/lib/typhoeus/hydra.rb
CHANGED
@@ -64,7 +64,7 @@ module Typhoeus
|
|
64
64
|
@queued_requests << request
|
65
65
|
else
|
66
66
|
if request.method == :get
|
67
|
-
if @memoize_requests && @memoized_requests.
|
67
|
+
if @memoize_requests && @memoized_requests.key?(request.url)
|
68
68
|
if response = @retrieved_from_cache[request.url]
|
69
69
|
request.response = response
|
70
70
|
request.call_handlers
|
@@ -120,6 +120,8 @@ module Typhoeus
|
|
120
120
|
@on_complete = proc
|
121
121
|
end
|
122
122
|
|
123
|
+
private
|
124
|
+
|
123
125
|
def get_from_cache_or_queue(request)
|
124
126
|
if @cache_getter
|
125
127
|
val = @cache_getter.call(request)
|
@@ -134,7 +136,6 @@ module Typhoeus
|
|
134
136
|
@multi.add(get_easy_object(request))
|
135
137
|
end
|
136
138
|
end
|
137
|
-
private :get_from_cache_or_queue
|
138
139
|
|
139
140
|
def get_easy_object(request)
|
140
141
|
@running_requests += 1
|
@@ -143,27 +144,27 @@ module Typhoeus
|
|
143
144
|
easy.verbose = request.verbose
|
144
145
|
if request.username || request.password
|
145
146
|
auth = { :username => request.username, :password => request.password }
|
146
|
-
auth[:method] =
|
147
|
+
auth[:method] = request.auth_method if request.auth_method
|
147
148
|
easy.auth = auth
|
148
149
|
end
|
149
150
|
|
150
151
|
if request.proxy
|
151
152
|
proxy = { :server => request.proxy }
|
152
|
-
proxy[:type] =
|
153
|
+
proxy[:type] = request.proxy_type if request.proxy_type
|
153
154
|
easy.proxy = proxy if request.proxy
|
154
155
|
end
|
155
156
|
|
156
157
|
if request.proxy_username || request.proxy_password
|
157
158
|
auth = { :username => request.proxy_username, :password => request.proxy_password }
|
158
|
-
auth[:method] =
|
159
|
+
auth[:method] = request.proxy_auth_method if request.proxy_auth_method
|
159
160
|
easy.proxy_auth = auth
|
160
161
|
end
|
161
162
|
|
162
163
|
easy.url = request.url
|
163
164
|
easy.method = request.method
|
164
|
-
easy.params = request.params if request.method
|
165
|
+
easy.params = request.params if [:post, :put].include?(request.method) && !request.params.nil?
|
165
166
|
easy.headers = request.headers if request.headers
|
166
|
-
easy.request_body = request.body if request.body
|
167
|
+
easy.request_body = request.body if [:post, :put].include?(request.method) && !request.body.nil?
|
167
168
|
easy.timeout = request.timeout if request.timeout
|
168
169
|
easy.connect_timeout = request.connect_timeout if request.connect_timeout
|
169
170
|
easy.interface = request.interface if request.interface
|
@@ -194,19 +195,16 @@ module Typhoeus
|
|
194
195
|
easy.set_headers
|
195
196
|
easy
|
196
197
|
end
|
197
|
-
private :get_easy_object
|
198
198
|
|
199
199
|
def queue_next
|
200
200
|
@running_requests -= 1
|
201
201
|
queue(@queued_requests.shift) unless @queued_requests.empty?
|
202
202
|
end
|
203
|
-
private :queue_next
|
204
203
|
|
205
204
|
def release_easy_object(easy)
|
206
205
|
easy.reset
|
207
206
|
@easy_pool.push easy
|
208
207
|
end
|
209
|
-
private :release_easy_object
|
210
208
|
|
211
209
|
def handle_request(request, response, live_request = true)
|
212
210
|
request.response = response
|
@@ -227,7 +225,6 @@ module Typhoeus
|
|
227
225
|
end
|
228
226
|
end
|
229
227
|
end
|
230
|
-
private :handle_request
|
231
228
|
|
232
229
|
def response_from_easy(easy, request)
|
233
230
|
Response.new(:code => easy.response_code,
|
@@ -243,8 +240,8 @@ module Typhoeus
|
|
243
240
|
:primary_ip => easy.primary_ip,
|
244
241
|
:curl_return_code => easy.curl_return_code,
|
245
242
|
:curl_error_message => easy.curl_error_message,
|
243
|
+
:redirect_count => easy.redirect_count,
|
246
244
|
:request => request)
|
247
245
|
end
|
248
|
-
private :response_from_easy
|
249
246
|
end
|
250
247
|
end
|
data/lib/typhoeus/hydra_mock.rb
CHANGED
@@ -9,7 +9,7 @@ module Typhoeus
|
|
9
9
|
@requests = []
|
10
10
|
@options = options
|
11
11
|
if @options[:headers]
|
12
|
-
@options[:headers] = Typhoeus::
|
12
|
+
@options[:headers] = Typhoeus::Header.new(@options[:headers])
|
13
13
|
end
|
14
14
|
|
15
15
|
@current_response_index = 0
|
@@ -93,7 +93,7 @@ module Typhoeus
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def headers_match?(request)
|
96
|
-
request_headers =
|
96
|
+
request_headers = Header.new(request.headers)
|
97
97
|
|
98
98
|
if empty_headers?(self.headers)
|
99
99
|
empty_headers?(request_headers)
|
data/lib/typhoeus/multi.rb
CHANGED
@@ -3,35 +3,144 @@ module Typhoeus
|
|
3
3
|
attr_reader :easy_handles
|
4
4
|
|
5
5
|
def initialize
|
6
|
+
Curl.init
|
7
|
+
|
8
|
+
@handle = Curl.multi_init
|
9
|
+
@active = 0
|
10
|
+
@running = 0
|
6
11
|
@easy_handles = []
|
12
|
+
|
13
|
+
@timeout = ::FFI::MemoryPointer.new(:long)
|
14
|
+
@timeval = Curl::Timeval.new
|
15
|
+
@fd_read = Curl::FDSet.new
|
16
|
+
@fd_write = Curl::FDSet.new
|
17
|
+
@fd_excep = Curl::FDSet.new
|
18
|
+
@max_fd = ::FFI::MemoryPointer.new(:int)
|
19
|
+
|
20
|
+
ObjectSpace.define_finalizer(self, self.class.finalizer(self))
|
7
21
|
end
|
8
22
|
|
9
|
-
def
|
10
|
-
|
23
|
+
def self.finalizer(multi)
|
24
|
+
proc { Curl.multi_cleanup(multi.handle) }
|
11
25
|
end
|
12
26
|
|
13
27
|
def add(easy)
|
14
28
|
raise "trying to add easy handle twice" if @easy_handles.include?(easy)
|
15
29
|
easy.set_headers() if easy.headers.empty?
|
16
|
-
|
30
|
+
|
31
|
+
code = Curl.multi_add_handle(@handle, easy.handle)
|
32
|
+
raise RuntimeError.new("An error occured adding the handle: #{code}: #{Curl.multi_strerror(code)}") if code != :call_multi_perform and code != :ok
|
33
|
+
|
34
|
+
do_perform if code == :call_multi_perform
|
35
|
+
|
36
|
+
@active += 1
|
37
|
+
@easy_handles << easy
|
38
|
+
easy
|
17
39
|
end
|
18
40
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
41
|
+
def remove(easy)
|
42
|
+
if @easy_handles.include?(easy)
|
43
|
+
@active -= 1
|
44
|
+
Curl.multi_remove_handle(@handle, easy.handle)
|
45
|
+
@easy_handles.delete(easy)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def perform
|
50
|
+
while @active > 0
|
51
|
+
run
|
52
|
+
while @running > 0
|
53
|
+
# get the curl-suggested timeout
|
54
|
+
code = Curl.multi_timeout(@handle, @timeout)
|
55
|
+
raise RuntimeError.new("an error occured getting the timeout: #{code}: #{Curl.multi_strerror(code)}") if code != :ok
|
56
|
+
timeout = @timeout.read_long
|
57
|
+
if timeout == 0 # no delay
|
58
|
+
run
|
59
|
+
next
|
60
|
+
elsif timeout < 0
|
61
|
+
timeout = 1
|
62
|
+
end
|
63
|
+
|
64
|
+
# load the fd sets from the multi handle
|
65
|
+
@fd_read.clear
|
66
|
+
@fd_write.clear
|
67
|
+
@fd_excep.clear
|
68
|
+
code = Curl.multi_fdset(@handle, @fd_read, @fd_write, @fd_excep, @max_fd)
|
69
|
+
raise RuntimeError.new("an error occured getting the fdset: #{code}: #{Curl.multi_strerror(code)}") if code != :ok
|
70
|
+
|
71
|
+
max_fd = @max_fd.read_int
|
72
|
+
if max_fd == -1
|
73
|
+
# curl is doing something special so let it run for a moment
|
74
|
+
sleep(0.001)
|
75
|
+
else
|
76
|
+
@timeval[:sec] = timeout / 1000
|
77
|
+
@timeval[:usec] = (timeout * 1000) % 1000000
|
78
|
+
|
79
|
+
code = Curl.select(max_fd + 1, @fd_read, @fd_write, @fd_excep, @timeval)
|
80
|
+
raise RuntimeError.new("error on thread select: #{::FFI.errno}") if code < 0
|
81
|
+
end
|
82
|
+
|
83
|
+
run
|
84
|
+
end
|
22
85
|
end
|
23
86
|
reset_easy_handles
|
24
87
|
end
|
25
88
|
|
26
|
-
def
|
27
|
-
|
89
|
+
def fire_and_forget
|
90
|
+
run
|
91
|
+
end
|
92
|
+
|
93
|
+
# check for finished easy handles and remove from the multi handle
|
94
|
+
def read_info
|
95
|
+
msgs_left = ::FFI::MemoryPointer.new(:int)
|
96
|
+
while not (msg = Curl.multi_info_read(@handle, msgs_left)).null?
|
97
|
+
next if msg[:code] != :done
|
98
|
+
|
99
|
+
easy = @easy_handles.find {|easy| easy.handle == msg[:easy_handle] }
|
100
|
+
next if not easy
|
101
|
+
|
102
|
+
response_code = ::FFI::MemoryPointer.new(:long)
|
103
|
+
response_code.write_long(-1)
|
104
|
+
Curl.easy_getinfo(easy.handle, :response_code, response_code)
|
105
|
+
response_code = response_code.read_long
|
106
|
+
remove(easy)
|
107
|
+
|
108
|
+
easy.curl_return_code = msg[:data][:code]
|
109
|
+
if easy.curl_return_code != 0 then easy.failure
|
110
|
+
elsif (200..299).member?(response_code) or response_code == 0 then easy.success
|
111
|
+
else easy.failure
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def cleanup
|
117
|
+
Curl.multi_cleanup(@handle)
|
118
|
+
@active = 0
|
119
|
+
@running = 0
|
120
|
+
@easy_handles = []
|
28
121
|
end
|
29
122
|
|
30
123
|
def reset_easy_handles
|
31
124
|
@easy_handles.dup.each do |easy|
|
32
|
-
|
125
|
+
remove(easy)
|
33
126
|
yield easy if block_given?
|
34
127
|
end
|
35
128
|
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
# called by perform and fire_and_forget
|
133
|
+
def run
|
134
|
+
begin code = do_perform end while code == :call_multi_perform
|
135
|
+
raise RuntimeError.new("an error occured while running perform: #{code}: #{Curl.multi_strerror(code)}") if code != :ok
|
136
|
+
read_info
|
137
|
+
end
|
138
|
+
|
139
|
+
def do_perform
|
140
|
+
running = ::FFI::MemoryPointer.new(:int)
|
141
|
+
code = Curl.multi_perform(@handle, running)
|
142
|
+
@running = running.read_int
|
143
|
+
code
|
144
|
+
end
|
36
145
|
end
|
37
146
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module Typhoeus
|
4
|
+
class ParamProcessor
|
5
|
+
class << self
|
6
|
+
def traverse_params_hash(hash, result = nil, current_key = nil)
|
7
|
+
result ||= { :files => [], :params => [] }
|
8
|
+
|
9
|
+
hash.keys.sort { |a, b| a.to_s <=> b.to_s }.collect do |key|
|
10
|
+
new_key = (current_key ? "#{current_key}[#{key}]" : key).to_s
|
11
|
+
current_value = hash[key]
|
12
|
+
process_value current_value, :result => result, :new_key => new_key
|
13
|
+
end
|
14
|
+
result
|
15
|
+
end
|
16
|
+
|
17
|
+
def process_value(current_value, options)
|
18
|
+
result = options[:result]
|
19
|
+
new_key = options[:new_key]
|
20
|
+
|
21
|
+
case current_value
|
22
|
+
when Hash
|
23
|
+
traverse_params_hash(current_value, result, new_key)
|
24
|
+
when Array
|
25
|
+
current_value.each do |v|
|
26
|
+
result[:params] << [new_key, v.to_s]
|
27
|
+
end
|
28
|
+
when File, Tempfile
|
29
|
+
filename = File.basename(current_value.path)
|
30
|
+
types = MIME::Types.type_for(filename)
|
31
|
+
result[:files] << [
|
32
|
+
new_key,
|
33
|
+
filename,
|
34
|
+
types.empty? ? 'application/octet-stream' : types[0].to_s,
|
35
|
+
File.expand_path(current_value.path)
|
36
|
+
]
|
37
|
+
else
|
38
|
+
result[:params] << [new_key, current_value.to_s]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/typhoeus/request.rb
CHANGED
@@ -7,6 +7,7 @@ module Typhoeus
|
|
7
7
|
:params,
|
8
8
|
:body,
|
9
9
|
:headers,
|
10
|
+
:cache_key_basis,
|
10
11
|
:connect_timeout,
|
11
12
|
:timeout,
|
12
13
|
:user_agent,
|
@@ -32,12 +33,10 @@ module Typhoeus
|
|
32
33
|
:username,
|
33
34
|
:password,
|
34
35
|
:auth_method,
|
35
|
-
:user_agent,
|
36
36
|
:proxy_auth_method,
|
37
37
|
:proxy_type
|
38
38
|
]
|
39
39
|
|
40
|
-
attr_reader :url
|
41
40
|
attr_accessor *ACCESSOR_OPTIONS
|
42
41
|
|
43
42
|
# Initialize a new Request
|
@@ -69,9 +68,9 @@ module Typhoeus
|
|
69
68
|
# ** +:username
|
70
69
|
# ** +:password
|
71
70
|
# ** +:auth_method
|
72
|
-
# ** +:user_agent+ : user agent (string) - DEPRECATED
|
73
71
|
#
|
74
72
|
def initialize(url, options = {})
|
73
|
+
@url = url
|
75
74
|
@method = options[:method] || :get
|
76
75
|
@params = options[:params]
|
77
76
|
@body = options[:body]
|
@@ -80,10 +79,6 @@ module Typhoeus
|
|
80
79
|
@interface = options[:interface]
|
81
80
|
@headers = options[:headers] || {}
|
82
81
|
|
83
|
-
if options.has_key?(:user_agent)
|
84
|
-
self.user_agent = options[:user_agent]
|
85
|
-
end
|
86
|
-
|
87
82
|
@cache_timeout = safe_to_i(options[:cache_timeout])
|
88
83
|
@follow_location = options[:follow_location]
|
89
84
|
@max_redirects = options[:max_redirects]
|
@@ -107,14 +102,6 @@ module Typhoeus
|
|
107
102
|
@password = options[:password]
|
108
103
|
@auth_method = options[:auth_method]
|
109
104
|
|
110
|
-
if @method == :post
|
111
|
-
@url = url
|
112
|
-
else
|
113
|
-
@url = @params ? "#{url}?#{params_string}" : url
|
114
|
-
end
|
115
|
-
|
116
|
-
@parsed_uri = URI.parse(@url)
|
117
|
-
|
118
105
|
@on_complete = nil
|
119
106
|
@after_complete = nil
|
120
107
|
@handled_response = nil
|
@@ -123,16 +110,25 @@ module Typhoeus
|
|
123
110
|
LOCALHOST_ALIASES = %w[ localhost 127.0.0.1 0.0.0.0 ]
|
124
111
|
|
125
112
|
def localhost?
|
126
|
-
LOCALHOST_ALIASES.include?(
|
113
|
+
LOCALHOST_ALIASES.include?(parsed_uri.host)
|
127
114
|
end
|
128
115
|
|
129
116
|
def user_agent
|
130
117
|
headers['User-Agent']
|
131
118
|
end
|
132
119
|
|
133
|
-
def
|
134
|
-
|
135
|
-
|
120
|
+
def url
|
121
|
+
if [:post, :put].include?(@method)
|
122
|
+
@url
|
123
|
+
else
|
124
|
+
url = "#{@url}?#{params_string}"
|
125
|
+
url += "&#{URI.escape(@body)}" if @body
|
126
|
+
url.gsub("?&", "?").gsub(/\?$/, '')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def parsed_uri
|
131
|
+
@parsed_uri ||= URI.parse(@url)
|
136
132
|
end
|
137
133
|
|
138
134
|
def host
|
@@ -146,10 +142,11 @@ module Typhoeus
|
|
146
142
|
end
|
147
143
|
|
148
144
|
def host_domain
|
149
|
-
|
145
|
+
parsed_uri.host
|
150
146
|
end
|
151
147
|
|
152
148
|
def params_string
|
149
|
+
return nil unless params
|
153
150
|
traversal = Typhoeus::Utils.traverse_params_hash(params)
|
154
151
|
Typhoeus::Utils.traversal_to_param_string(traversal)
|
155
152
|
end
|
@@ -208,7 +205,7 @@ module Typhoeus
|
|
208
205
|
end
|
209
206
|
|
210
207
|
def cache_key
|
211
|
-
Digest::SHA1.hexdigest(url)
|
208
|
+
Digest::SHA1.hexdigest(cache_key_basis || url)
|
212
209
|
end
|
213
210
|
|
214
211
|
def self.run(url, params)
|
data/lib/typhoeus/response.rb
CHANGED
@@ -8,7 +8,7 @@ module Typhoeus
|
|
8
8
|
:app_connect_time, :pretransfer_time,
|
9
9
|
:connect_time, :name_lookup_time,
|
10
10
|
:curl_return_code, :curl_error_message,
|
11
|
-
:primary_ip
|
11
|
+
:primary_ip, :redirect_count
|
12
12
|
|
13
13
|
attr_writer :headers_hash
|
14
14
|
|
@@ -32,8 +32,9 @@ module Typhoeus
|
|
32
32
|
@request = params[:request]
|
33
33
|
@effective_url = params[:effective_url]
|
34
34
|
@primary_ip = params[:primary_ip]
|
35
|
+
@redirect_count = params[:redirect_count]
|
35
36
|
@mock = params[:mock] || false # default
|
36
|
-
@headers_hash =
|
37
|
+
@headers_hash = Header.new(params[:headers_hash]) if params[:headers_hash]
|
37
38
|
end
|
38
39
|
|
39
40
|
# Returns true if this is a mock response.
|
@@ -47,7 +48,7 @@ module Typhoeus
|
|
47
48
|
|
48
49
|
def headers_hash
|
49
50
|
@headers_hash ||= begin
|
50
|
-
headers.split("\n").map {|o| o.strip}.inject(Typhoeus::
|
51
|
+
headers.split("\n").map {|o| o.strip}.inject(Typhoeus::Header.new) do |hash, o|
|
51
52
|
if o.empty? || o =~ /^HTTP\/[\d\.]+/
|
52
53
|
hash
|
53
54
|
else
|
@@ -55,7 +56,7 @@ module Typhoeus
|
|
55
56
|
key = o.slice(0, i)
|
56
57
|
value = o.slice(i + 1, o.size)
|
57
58
|
value = value.strip unless value.nil?
|
58
|
-
if hash.
|
59
|
+
if hash.key? key
|
59
60
|
hash[key] = [hash[key], value].flatten
|
60
61
|
else
|
61
62
|
hash[key] = value
|