em-http-request 1.0.2 → 1.0.3
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 em-http-request might be problematic. Click here for more details.
- data/.gitignore +1 -0
- data/benchmarks/clients.rb +44 -30
- data/benchmarks/server.rb +3 -3
- data/em-http-request.gemspec +33 -33
- data/lib/em-http/client.rb +5 -3
- data/lib/em-http/decoders.rb +34 -12
- data/lib/em-http/http_client_options.rb +1 -2
- data/lib/em-http/http_connection.rb +12 -5
- data/lib/em-http/http_connection_options.rb +6 -1
- data/lib/em-http/http_header.rb +3 -0
- data/lib/em-http/version.rb +1 -1
- data/spec/client_fiber_spec.rb +23 -23
- data/spec/client_spec.rb +80 -10
- data/spec/external_spec.rb +150 -128
- data/spec/fixtures/gzip-sample.gz +0 -0
- data/spec/http_proxy_spec.rb +16 -0
- data/spec/pipelining_spec.rb +65 -65
- data/spec/redirect_spec.rb +15 -0
- data/spec/socksify_proxy_spec.rb +24 -24
- data/spec/stallion.rb +23 -3
- metadata +75 -23
data/.gitignore
CHANGED
data/benchmarks/clients.rb
CHANGED
@@ -9,7 +9,7 @@ require 'rest_client'
|
|
9
9
|
require 'tach'
|
10
10
|
require 'typhoeus'
|
11
11
|
|
12
|
-
url = 'http://127.0.0.1/
|
12
|
+
url = 'http://127.0.0.1:9292/data/10000'
|
13
13
|
|
14
14
|
with_server do
|
15
15
|
Tach.meter(100) do
|
@@ -119,38 +119,52 @@ with_server do
|
|
119
119
|
streamly.get(url)
|
120
120
|
end
|
121
121
|
|
122
|
-
tach('Typhoeus') do
|
123
|
-
|
122
|
+
tach('Typhoeus') do |n|
|
123
|
+
hydra = Typhoeus::Hydra.new( max_concurrency: 8 )
|
124
|
+
hydra.disable_memoization
|
125
|
+
count = 0
|
126
|
+
error = 0
|
127
|
+
n.times {
|
128
|
+
req = Typhoeus::Request.new( url )
|
129
|
+
req.on_complete do |res|
|
130
|
+
count += 1
|
131
|
+
error += 1 if !res.success?
|
132
|
+
p [count, error] if count == n
|
133
|
+
|
134
|
+
end
|
135
|
+
hydra.queue( req )
|
136
|
+
}
|
137
|
+
hydra.run
|
124
138
|
end
|
125
139
|
|
126
140
|
end
|
127
141
|
end
|
128
142
|
|
129
143
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
144
|
+
#+------------------------------+-----------+
|
145
|
+
#| tach | total |
|
146
|
+
#+------------------------------+-----------+
|
147
|
+
#| em-http-request (persistent) | 0.145512 |
|
148
|
+
#+------------------------------+-----------+
|
149
|
+
#| Excon | 0.181564 |
|
150
|
+
#+------------------------------+-----------+
|
151
|
+
#| RestClient | 0.253127 |
|
152
|
+
#+------------------------------+-----------+
|
153
|
+
#| Net::HTTP | 0.294412 |
|
154
|
+
#+------------------------------+-----------+
|
155
|
+
#| HTTParty | 0.305397 |
|
156
|
+
#+------------------------------+-----------+
|
157
|
+
#| open-uri | 0.307007 |
|
158
|
+
#+------------------------------+-----------+
|
159
|
+
#| Net::HTTP (persistent) | 0.313716 |
|
160
|
+
#+------------------------------+-----------+
|
161
|
+
#| Typhoeus | 0.514725 |
|
162
|
+
#+------------------------------+-----------+
|
163
|
+
#| curb (persistent) | 3.981700 |
|
164
|
+
#+------------------------------+-----------+
|
165
|
+
#| StreamlyFFI (persistent) | 3.989063 |
|
166
|
+
#+------------------------------+-----------+
|
167
|
+
#| Excon (persistent) | 4.018761 |
|
168
|
+
#+------------------------------+-----------+
|
169
|
+
#| em-http-request | 15.025291 |
|
170
|
+
#+------------------------------+-----------+
|
data/benchmarks/server.rb
CHANGED
@@ -32,12 +32,12 @@ end
|
|
32
32
|
|
33
33
|
def with_server(&block)
|
34
34
|
pid = Process.fork do
|
35
|
-
|
35
|
+
Benchmark::Server.run
|
36
36
|
end
|
37
37
|
loop do
|
38
38
|
sleep(1)
|
39
39
|
begin
|
40
|
-
#
|
40
|
+
#Excon.get('http://localhost:9292/api/foo')
|
41
41
|
break
|
42
42
|
rescue
|
43
43
|
end
|
@@ -45,4 +45,4 @@ def with_server(&block)
|
|
45
45
|
yield
|
46
46
|
ensure
|
47
47
|
Process.kill(9, pid)
|
48
|
-
end
|
48
|
+
end
|
data/em-http-request.gemspec
CHANGED
@@ -1,33 +1,33 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "em-http/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |s|
|
6
|
-
s.name = "em-http-request"
|
7
|
-
s.version = EventMachine::HttpRequest::VERSION
|
8
|
-
|
9
|
-
s.platform = Gem::Platform::RUBY
|
10
|
-
s.authors = ["Ilya Grigorik"]
|
11
|
-
s.email = ["ilya@igvita.com"]
|
12
|
-
s.homepage = "http://github.com/igrigorik/em-http-request"
|
13
|
-
s.summary = "EventMachine based, async HTTP Request client"
|
14
|
-
s.description = s.summary
|
15
|
-
s.rubyforge_project = "em-http-request"
|
16
|
-
|
17
|
-
s.add_dependency "eventmachine", ">= 1.0.0.beta.4"
|
18
|
-
s.add_dependency "addressable", ">= 2.2.3"
|
19
|
-
s.add_dependency "http_parser.rb", ">= 0.5.3"
|
20
|
-
s.add_dependency "em-socksify"
|
21
|
-
s.add_dependency "cookiejar"
|
22
|
-
|
23
|
-
s.add_development_dependency "rspec"
|
24
|
-
s.add_development_dependency "rake"
|
25
|
-
s.add_development_dependency "rack"
|
26
|
-
s.add_development_dependency "yajl-ruby"
|
27
|
-
s.add_development_dependency "mongrel", "~> 1.2.0.pre2"
|
28
|
-
|
29
|
-
s.files = `git ls-files`.split("\n")
|
30
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
31
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
32
|
-
s.require_paths = ["lib"]
|
33
|
-
end
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "em-http/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "em-http-request"
|
7
|
+
s.version = EventMachine::HttpRequest::VERSION
|
8
|
+
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.authors = ["Ilya Grigorik"]
|
11
|
+
s.email = ["ilya@igvita.com"]
|
12
|
+
s.homepage = "http://github.com/igrigorik/em-http-request"
|
13
|
+
s.summary = "EventMachine based, async HTTP Request client"
|
14
|
+
s.description = s.summary
|
15
|
+
s.rubyforge_project = "em-http-request"
|
16
|
+
|
17
|
+
s.add_dependency "eventmachine", ">= 1.0.0.beta.4"
|
18
|
+
s.add_dependency "addressable", ">= 2.2.3"
|
19
|
+
s.add_dependency "http_parser.rb", ">= 0.5.3"
|
20
|
+
s.add_dependency "em-socksify"
|
21
|
+
s.add_dependency "cookiejar"
|
22
|
+
|
23
|
+
s.add_development_dependency "rspec"
|
24
|
+
s.add_development_dependency "rake"
|
25
|
+
s.add_development_dependency "rack"
|
26
|
+
s.add_development_dependency "yajl-ruby"
|
27
|
+
s.add_development_dependency "mongrel", "~> 1.2.0.pre2"
|
28
|
+
|
29
|
+
s.files = `git ls-files`.split("\n")
|
30
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
31
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
32
|
+
s.require_paths = ["lib"]
|
33
|
+
end
|
data/lib/em-http/client.rb
CHANGED
@@ -133,9 +133,10 @@ module EventMachine
|
|
133
133
|
|
134
134
|
def build_request
|
135
135
|
head = @req.headers ? munge_header_keys(@req.headers) : {}
|
136
|
-
|
137
|
-
if @
|
138
|
-
|
136
|
+
|
137
|
+
if @conn.connopts.http_proxy?
|
138
|
+
proxy = @conn.connopts.proxy
|
139
|
+
head['proxy-authorization'] = proxy[:authorization] if proxy[:authorization]
|
139
140
|
end
|
140
141
|
|
141
142
|
# Set the cookie header if provided
|
@@ -217,6 +218,7 @@ module EventMachine
|
|
217
218
|
end
|
218
219
|
|
219
220
|
def parse_response_header(header, version, status)
|
221
|
+
@response_header.raw = header
|
220
222
|
header.each do |key, val|
|
221
223
|
@response_header[key.upcase.gsub('-','_')] = val
|
222
224
|
end
|
data/lib/em-http/decoders.rb
CHANGED
@@ -10,7 +10,7 @@ module EventMachine::HttpDecoders
|
|
10
10
|
|
11
11
|
class << self
|
12
12
|
def accepted_encodings
|
13
|
-
DECODERS.inject([]) { |r,d| r + d.encoding_names }
|
13
|
+
DECODERS.inject([]) { |r, d| r + d.encoding_names }
|
14
14
|
end
|
15
15
|
|
16
16
|
def decoder_for_encoding(encoding)
|
@@ -44,7 +44,7 @@ module EventMachine::HttpDecoders
|
|
44
44
|
decompressed = finalize
|
45
45
|
receive_decompressed decompressed
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
private
|
49
49
|
|
50
50
|
def receive_decompressed(decompressed)
|
@@ -91,30 +91,52 @@ module EventMachine::HttpDecoders
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
-
##
|
95
|
-
# Oneshot decompressor, due to lack of a streaming Gzip reader
|
96
|
-
# implementation. We may steal code from Zliby to improve this.
|
97
|
-
#
|
98
|
-
# For now, do not put `gzip' or `compressed' in your accept-encoding
|
99
|
-
# header if you expect much data through the :on_response interface.
|
100
94
|
class GZip < Base
|
101
95
|
def self.encoding_names
|
102
96
|
%w(gzip compressed)
|
103
97
|
end
|
104
98
|
|
105
99
|
def decompress(compressed)
|
106
|
-
@buf ||=
|
107
|
-
@buf
|
108
|
-
|
100
|
+
@buf ||= LazyStringIO.new
|
101
|
+
@buf << compressed
|
102
|
+
|
103
|
+
# Zlib::GzipReader loads input in 2048 byte chunks
|
104
|
+
if @buf.size > 2048
|
105
|
+
@gzip ||= Zlib::GzipReader.new @buf
|
106
|
+
@gzip.readline
|
107
|
+
end
|
109
108
|
end
|
110
109
|
|
111
110
|
def finalize
|
112
111
|
begin
|
113
|
-
Zlib::GzipReader.new
|
112
|
+
@gzip ||= Zlib::GzipReader.new @buf
|
113
|
+
@gzip.read
|
114
114
|
rescue Zlib::Error
|
115
115
|
raise DecoderError
|
116
116
|
end
|
117
117
|
end
|
118
|
+
|
119
|
+
class LazyStringIO
|
120
|
+
def initialize(string="")
|
121
|
+
@stream = string
|
122
|
+
end
|
123
|
+
|
124
|
+
def <<(string)
|
125
|
+
@stream << string
|
126
|
+
end
|
127
|
+
|
128
|
+
def read(length=nil, buffer=nil)
|
129
|
+
buffer ||= ""
|
130
|
+
length ||= 0
|
131
|
+
buffer << @stream[0..(length-1)]
|
132
|
+
@stream = @stream[length..-1]
|
133
|
+
buffer
|
134
|
+
end
|
135
|
+
|
136
|
+
def size
|
137
|
+
@stream.size
|
138
|
+
end
|
139
|
+
end
|
118
140
|
end
|
119
141
|
|
120
142
|
DECODERS = [Deflate, GZip]
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class HttpClientOptions
|
2
|
-
attr_reader :uri, :method, :host, :port
|
2
|
+
attr_reader :uri, :method, :host, :port
|
3
3
|
attr_reader :headers, :file, :body, :query, :path
|
4
4
|
attr_reader :keepalive, :pass_cookies, :decoding
|
5
5
|
|
@@ -25,7 +25,6 @@ class HttpClientOptions
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def follow_redirect?; @followed < @redirects; end
|
28
|
-
def http_proxy?; @proxy && [nil, :http].include?(@proxy[:type]); end
|
29
28
|
def ssl?; @uri.scheme == "https" || @uri.port == 443; end
|
30
29
|
def no_body?; @method == "HEAD"; end
|
31
30
|
|
@@ -1,11 +1,13 @@
|
|
1
1
|
module EventMachine
|
2
2
|
|
3
3
|
module HTTPMethods
|
4
|
-
def get
|
5
|
-
def head
|
6
|
-
def delete
|
7
|
-
def put
|
8
|
-
def post
|
4
|
+
def get options = {}, &blk; setup_request(:get, options, &blk); end
|
5
|
+
def head options = {}, &blk; setup_request(:head, options, &blk); end
|
6
|
+
def delete options = {}, &blk; setup_request(:delete, options, &blk); end
|
7
|
+
def put options = {}, &blk; setup_request(:put, options, &blk); end
|
8
|
+
def post options = {}, &blk; setup_request(:post, options, &blk); end
|
9
|
+
def patch options = {}, &blk; setup_request(:patch, options, &blk); end
|
10
|
+
def options options = {}, &blk; setup_request(:options, options, &blk); end
|
9
11
|
end
|
10
12
|
|
11
13
|
class HttpStubConnection < Connection
|
@@ -180,10 +182,15 @@ module EventMachine
|
|
180
182
|
@conn.reconnect(r.req.host, r.req.port)
|
181
183
|
end
|
182
184
|
|
185
|
+
@conn.pending_connect_timeout = @connopts.connect_timeout
|
186
|
+
@conn.comm_inactivity_timeout = @connopts.inactivity_timeout
|
183
187
|
@conn.callback { r.connection_completed }
|
184
188
|
rescue EventMachine::ConnectionError => e
|
185
189
|
@clients.pop.close(e.message)
|
186
190
|
end
|
191
|
+
else
|
192
|
+
@deferred = true
|
193
|
+
@conn.close_connection
|
187
194
|
end
|
188
195
|
end
|
189
196
|
alias :close :unbind
|
@@ -11,7 +11,10 @@ class HttpConnectionOptions
|
|
11
11
|
|
12
12
|
if bind = options[:bind]
|
13
13
|
@bind = bind[:host] || '0.0.0.0'
|
14
|
-
|
14
|
+
|
15
|
+
# Eventmachine will open a UNIX socket if bind :port
|
16
|
+
# is explicitly set to nil
|
17
|
+
@bind_port = bind[:port]
|
15
18
|
end
|
16
19
|
|
17
20
|
uri = uri.kind_of?(Addressable::URI) ? uri : Addressable::URI::parse(uri.to_s)
|
@@ -25,4 +28,6 @@ class HttpConnectionOptions
|
|
25
28
|
@port = uri.port
|
26
29
|
end
|
27
30
|
end
|
31
|
+
|
32
|
+
def http_proxy?; @proxy && [nil, :http].include?(@proxy[:type]); end
|
28
33
|
end
|
data/lib/em-http/http_header.rb
CHANGED
data/lib/em-http/version.rb
CHANGED
data/spec/client_fiber_spec.rb
CHANGED
@@ -1,23 +1,23 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'fiber'
|
3
|
-
|
4
|
-
describe EventMachine::HttpRequest do
|
5
|
-
context "with fibers" do
|
6
|
-
|
7
|
-
it "should be transparent to connection errors" do
|
8
|
-
EventMachine.run do
|
9
|
-
Fiber.new do
|
10
|
-
f = Fiber.current
|
11
|
-
fired = false
|
12
|
-
http = EventMachine::HttpRequest.new('http://non-existing.domain/', :connection_timeout => 0.1).get
|
13
|
-
http.callback { failed(http) }
|
14
|
-
http.errback { f.resume :errback }
|
15
|
-
|
16
|
-
Fiber.yield.should == :errback
|
17
|
-
EM.stop
|
18
|
-
end.resume
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
1
|
+
require 'helper'
|
2
|
+
require 'fiber'
|
3
|
+
|
4
|
+
describe EventMachine::HttpRequest do
|
5
|
+
context "with fibers" do
|
6
|
+
|
7
|
+
it "should be transparent to connection errors" do
|
8
|
+
EventMachine.run do
|
9
|
+
Fiber.new do
|
10
|
+
f = Fiber.current
|
11
|
+
fired = false
|
12
|
+
http = EventMachine::HttpRequest.new('http://non-existing.domain/', :connection_timeout => 0.1).get
|
13
|
+
http.callback { failed(http) }
|
14
|
+
http.errback { f.resume :errback }
|
15
|
+
|
16
|
+
Fiber.yield.should == :errback
|
17
|
+
EM.stop
|
18
|
+
end.resume
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
data/spec/client_spec.rb
CHANGED
@@ -188,6 +188,19 @@ describe EventMachine::HttpRequest do
|
|
188
188
|
}
|
189
189
|
end
|
190
190
|
|
191
|
+
it "should perform successful PATCH" do
|
192
|
+
EventMachine.run {
|
193
|
+
http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/').patch :body => "data"
|
194
|
+
|
195
|
+
http.errback { failed(http) }
|
196
|
+
http.callback {
|
197
|
+
http.response_header.status.should == 200
|
198
|
+
http.response.should match(/data/)
|
199
|
+
EventMachine.stop
|
200
|
+
}
|
201
|
+
}
|
202
|
+
end
|
203
|
+
|
191
204
|
it "should escape body on POST" do
|
192
205
|
EventMachine.run {
|
193
206
|
http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/').post :body => {:stuff => 'string&string'}
|
@@ -214,7 +227,7 @@ describe EventMachine::HttpRequest do
|
|
214
227
|
}
|
215
228
|
}
|
216
229
|
end
|
217
|
-
|
230
|
+
|
218
231
|
it "should set content-length to 0 on posts with empty bodies" do
|
219
232
|
EventMachine.run {
|
220
233
|
http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/echo_content_length_from_header').post
|
@@ -343,6 +356,20 @@ describe EventMachine::HttpRequest do
|
|
343
356
|
}
|
344
357
|
end
|
345
358
|
|
359
|
+
it "should return raw headers in a hash" do
|
360
|
+
EventMachine.run {
|
361
|
+
http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/echo_headers').get
|
362
|
+
|
363
|
+
http.errback { failed(http) }
|
364
|
+
http.callback {
|
365
|
+
http.response_header.status.should == 200
|
366
|
+
http.response_header.raw['Set-Cookie'].should match('test=yes')
|
367
|
+
http.response_header.raw['X-Forward-Host'].should match('proxy.local')
|
368
|
+
EventMachine.stop
|
369
|
+
}
|
370
|
+
}
|
371
|
+
end
|
372
|
+
|
346
373
|
it "should detect deflate encoding" do
|
347
374
|
EventMachine.run {
|
348
375
|
|
@@ -362,18 +389,40 @@ describe EventMachine::HttpRequest do
|
|
362
389
|
it "should detect gzip encoding" do
|
363
390
|
EventMachine.run {
|
364
391
|
|
365
|
-
http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/gzip').get :head => {
|
366
|
-
"accept-encoding" => "gzip, compressed"
|
367
|
-
}
|
392
|
+
http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/gzip').get :head => {"accept-encoding" => "gzip, compressed"}
|
368
393
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
394
|
+
http.errback { failed(http) }
|
395
|
+
http.callback {
|
396
|
+
http.response_header.status.should == 200
|
397
|
+
http.response_header["CONTENT_ENCODING"].should == "gzip"
|
398
|
+
http.response.should == "compressed"
|
374
399
|
|
375
|
-
|
400
|
+
EventMachine.stop
|
401
|
+
}
|
376
402
|
}
|
403
|
+
end
|
404
|
+
|
405
|
+
it "should stream gzip responses" do
|
406
|
+
expected_response = Zlib::GzipReader.open(File.dirname(__FILE__) + "/fixtures/gzip-sample.gz") { |f| f.read }
|
407
|
+
actual_response = ''
|
408
|
+
|
409
|
+
EventMachine.run {
|
410
|
+
|
411
|
+
http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/gzip-large').get :head => {"accept-encoding" => "gzip, compressed"}
|
412
|
+
|
413
|
+
http.errback { failed(http) }
|
414
|
+
http.callback {
|
415
|
+
http.response_header.status.should == 200
|
416
|
+
http.response_header["CONTENT_ENCODING"].should == "gzip"
|
417
|
+
http.response.should == ''
|
418
|
+
|
419
|
+
actual_response.should == expected_response
|
420
|
+
|
421
|
+
EventMachine.stop
|
422
|
+
}
|
423
|
+
http.stream do |chunk|
|
424
|
+
actual_response << chunk
|
425
|
+
end
|
377
426
|
}
|
378
427
|
end
|
379
428
|
|
@@ -633,6 +682,9 @@ describe EventMachine::HttpRequest do
|
|
633
682
|
end
|
634
683
|
|
635
684
|
it "should get the body without Content-Length" do
|
685
|
+
pending "blocked on new http_parser.rb release"
|
686
|
+
# https://github.com/igrigorik/em-http-request/issues/168
|
687
|
+
|
636
688
|
EventMachine.run {
|
637
689
|
@s = StubServer.new("HTTP/1.1 200 OK\r\n\r\nFoo")
|
638
690
|
|
@@ -709,6 +761,24 @@ describe EventMachine::HttpRequest do
|
|
709
761
|
}
|
710
762
|
end
|
711
763
|
|
764
|
+
it "should reconnect if connection was closed between requests" do
|
765
|
+
EventMachine.run {
|
766
|
+
conn = EM::HttpRequest.new('http://127.0.0.1:8090/', :inactivity_timeout => 0.5)
|
767
|
+
req = conn.get :keepalive => true
|
768
|
+
|
769
|
+
req.callback do
|
770
|
+
EM.add_timer(1) do
|
771
|
+
req = conn.get
|
772
|
+
|
773
|
+
req.callback do
|
774
|
+
req.response_header.status.should == 200
|
775
|
+
EventMachine.stop
|
776
|
+
end
|
777
|
+
end
|
778
|
+
end
|
779
|
+
}
|
780
|
+
end
|
781
|
+
|
712
782
|
it 'should handle malformed Content-Type header repetitions' do
|
713
783
|
EventMachine.run {
|
714
784
|
response =<<-HTTP.gsub(/^ +/, '').strip
|