em-http-request 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
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
|