em-http-request 0.2.15 → 0.3.0

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.

@@ -0,0 +1,71 @@
1
+ module EventMachine
2
+ # A simple hash is returned for each request made by HttpClient with the
3
+ # headers that were given by the server for that request.
4
+ class HttpResponseHeader < Hash
5
+ # The reason returned in the http response ("OK","File not found",etc.)
6
+ attr_accessor :http_reason
7
+
8
+ # The HTTP version returned.
9
+ attr_accessor :http_version
10
+
11
+ # The status code (as a string!)
12
+ attr_accessor :http_status
13
+
14
+ # E-Tag
15
+ def etag
16
+ self[HttpClient::ETAG]
17
+ end
18
+
19
+ def last_modified
20
+ self[HttpClient::LAST_MODIFIED]
21
+ end
22
+
23
+ # HTTP response status as an integer
24
+ def status
25
+ Integer(http_status) rescue 0
26
+ end
27
+
28
+ # Length of content as an integer, or nil if chunked/unspecified
29
+ def content_length
30
+ @content_length ||= ((s = self[HttpClient::CONTENT_LENGTH]) &&
31
+ (s =~ /^(\d+)$/)) ? $1.to_i : nil
32
+ end
33
+
34
+ # Cookie header from the server
35
+ def cookie
36
+ self[HttpClient::SET_COOKIE]
37
+ end
38
+
39
+ # Is the transfer encoding chunked?
40
+ def chunked_encoding?
41
+ /chunked/i === self[HttpClient::TRANSFER_ENCODING]
42
+ end
43
+
44
+ def keep_alive?
45
+ /keep-alive/i === self[HttpClient::KEEP_ALIVE]
46
+ end
47
+
48
+ def compressed?
49
+ /gzip|compressed|deflate/i === self[HttpClient::CONTENT_ENCODING]
50
+ end
51
+
52
+ def location
53
+ self[HttpClient::LOCATION]
54
+ end
55
+ end
56
+
57
+ class HttpChunkHeader < Hash
58
+ # When parsing chunked encodings this is set
59
+ attr_accessor :http_chunk_size
60
+
61
+ def initialize
62
+ super
63
+ @http_chunk_size = '0'
64
+ end
65
+
66
+ # Size of the chunk as an integer
67
+ def chunk_size
68
+ @http_chunk_size.to_i(base=16)
69
+ end
70
+ end
71
+ end
@@ -2,7 +2,7 @@ class HttpOptions
2
2
  attr_reader :uri, :method, :host, :port, :options
3
3
 
4
4
  def initialize(method, uri, options)
5
- uri.normalize!
5
+ uri.path = '/' if uri.path.empty?
6
6
 
7
7
  @options = options
8
8
  @method = method.to_s.upcase
@@ -18,8 +18,9 @@ class HttpOptions
18
18
  @port = uri.port
19
19
  end
20
20
 
21
- @options[:timeout] ||= 10 # default connect & inactivity timeouts
22
- @options[:redirects] ||= 0 # default number of redirects to follow
21
+ @options[:timeout] ||= 10 # default connect & inactivity timeouts
22
+ @options[:redirects] ||= 0 # default number of redirects to follow
23
+ @options[:keepalive] ||= false # default to single request per connection
23
24
 
24
25
  # Make sure the ports are set as Addressable::URI doesn't
25
26
  # set the port if it isn't there
@@ -1,6 +1,3 @@
1
- require 'base64'
2
- require 'addressable/uri'
3
-
4
1
  module EventMachine
5
2
 
6
3
  # EventMachine based HTTP request class with support for streaming consumption
@@ -0,0 +1,5 @@
1
+ module EventMachine
2
+ class HttpRequest
3
+ VERSION = "0.3.0"
4
+ end
5
+ end
@@ -1,4 +1,4 @@
1
- require 'spec/helper'
1
+ require 'helper'
2
2
 
3
3
  describe EventMachine::HttpEncoding do
4
4
  include EventMachine::HttpEncoding
@@ -31,4 +31,10 @@ describe EventMachine::HttpEncoding do
31
31
  params.should == "bad%26str[key%26key][0]=bad%2B%26stuff&bad%26str[key%26key][1]=%5Btest%5D"
32
32
  end
33
33
 
34
+ it "should be fast on long string escapes" do
35
+ s = Time.now
36
+ 5000.times { |n| form_encode_body({:a => "{a:'b', d:'f', g:['a','b']}"*50}) }
37
+ (Time.now - s).should satisfy { |t| t < 1.5 }
38
+ end
39
+
34
40
  end
@@ -1,4 +1,4 @@
1
- require 'spec/helper'
1
+ require 'helper'
2
2
 
3
3
  describe 'em-http mock' do
4
4
 
@@ -1,68 +1,68 @@
1
- require 'spec/helper'
2
- require 'spec/stallion'
3
-
4
- describe EventMachine::MultiRequest do
5
-
6
- it "should submit multiple requests in parallel and return once all of them are complete" do
7
- EventMachine.run {
8
-
9
- # create an instance of multi-request handler, and the requests themselves
10
- multi = EventMachine::MultiRequest.new
11
-
12
- # add multiple requests to the multi-handler
13
- multi.add(EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get(:query => {:q => 'test'}))
14
- multi.add(EventMachine::HttpRequest.new('http://0.0.0.0:8083/').get(:timeout => 1))
15
-
16
- multi.callback {
17
- # verify successful request
18
- multi.responses[:succeeded].size.should == 1
19
- multi.responses[:succeeded].first.response.should match(/test/)
20
-
21
- # verify invalid requests
22
- multi.responses[:failed].size.should == 1
23
- multi.responses[:failed].first.response_header.status.should == 0
24
-
25
- EventMachine.stop
26
- }
27
- }
28
- end
29
-
30
- it "should accept multiple open connections and return once all of them are complete" do
31
- EventMachine.run {
32
- http1 = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get(:query => {:q => 'test'})
33
- http2 = EventMachine::HttpRequest.new('http://0.0.0.0:8083/').get(:timeout => 1)
34
-
35
- multi = EventMachine::MultiRequest.new([http1, http2]) do
36
- multi.responses[:succeeded].size.should == 1
37
- multi.responses[:succeeded].first.response.should match(/test/)
38
-
39
- multi.responses[:failed].size.should == 1
40
- multi.responses[:failed].first.response_header.status.should == 0
41
-
42
- EventMachine.stop
43
- end
44
- }
45
- end
46
-
47
- it "should handle multiple mock requests" do
48
- EventMachine::MockHttpRequest.register_file('http://127.0.0.1:8080/', :get, {}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
49
- EventMachine::MockHttpRequest.register_file('http://0.0.0.0:8083/', :get, {}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
50
-
51
- EventMachine.run {
52
-
53
- # create an instance of multi-request handler, and the requests themselves
54
- multi = EventMachine::MultiRequest.new
55
-
56
- # add multiple requests to the multi-handler
57
- multi.add(EventMachine::MockHttpRequest.new('http://127.0.0.1:8080/').get)
58
- multi.add(EventMachine::MockHttpRequest.new('http://0.0.0.0:8083/').get)
59
-
60
- multi.callback {
61
- # verify successful request
62
- multi.responses[:succeeded].size.should == 2
63
-
64
- EventMachine.stop
65
- }
66
- }
67
- end
68
- end
1
+ require 'helper'
2
+ require 'stallion'
3
+
4
+ describe EventMachine::MultiRequest do
5
+
6
+ it "should submit multiple requests in parallel and return once all of them are complete" do
7
+ EventMachine.run {
8
+
9
+ # create an instance of multi-request handler, and the requests themselves
10
+ multi = EventMachine::MultiRequest.new
11
+
12
+ # add multiple requests to the multi-handler
13
+ multi.add(EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get(:query => {:q => 'test'}))
14
+ multi.add(EventMachine::HttpRequest.new('http://0.0.0.0:8083/').get(:timeout => 1))
15
+
16
+ multi.callback {
17
+ # verify successful request
18
+ multi.responses[:succeeded].size.should == 1
19
+ multi.responses[:succeeded].first.response.should match(/test/)
20
+
21
+ # verify invalid requests
22
+ multi.responses[:failed].size.should == 1
23
+ multi.responses[:failed].first.response_header.status.should == 0
24
+
25
+ EventMachine.stop
26
+ }
27
+ }
28
+ end
29
+
30
+ it "should accept multiple open connections and return once all of them are complete" do
31
+ EventMachine.run {
32
+ http1 = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get(:query => {:q => 'test'})
33
+ http2 = EventMachine::HttpRequest.new('http://0.0.0.0:8083/').get(:timeout => 1)
34
+
35
+ multi = EventMachine::MultiRequest.new([http1, http2]) do
36
+ multi.responses[:succeeded].size.should == 1
37
+ multi.responses[:succeeded].first.response.should match(/test/)
38
+
39
+ multi.responses[:failed].size.should == 1
40
+ multi.responses[:failed].first.response_header.status.should == 0
41
+
42
+ EventMachine.stop
43
+ end
44
+ }
45
+ end
46
+
47
+ it "should handle multiple mock requests" do
48
+ EventMachine::MockHttpRequest.register_file('http://127.0.0.1:8080/', :get, {}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
49
+ EventMachine::MockHttpRequest.register_file('http://0.0.0.0:8083/', :get, {}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
50
+
51
+ EventMachine.run {
52
+
53
+ # create an instance of multi-request handler, and the requests themselves
54
+ multi = EventMachine::MultiRequest.new
55
+
56
+ # add multiple requests to the multi-handler
57
+ multi.add(EventMachine::MockHttpRequest.new('http://127.0.0.1:8080/').get)
58
+ multi.add(EventMachine::MockHttpRequest.new('http://0.0.0.0:8083/').get)
59
+
60
+ multi.callback {
61
+ # verify successful request
62
+ multi.responses[:succeeded].size.should == 2
63
+
64
+ EventMachine.stop
65
+ }
66
+ }
67
+ end
68
+ end
@@ -1,19 +1,19 @@
1
- require 'spec/helper'
2
- require 'spec/stallion'
3
- require 'spec/stub_server'
1
+ require 'helper'
2
+ require 'stallion'
3
+ require 'stub_server'
4
4
 
5
5
  describe EventMachine::HttpRequest do
6
6
 
7
- def failed
7
+ def failed(http=nil)
8
8
  EventMachine.stop
9
- fail
9
+ http ? fail(http.error) : fail
10
10
  end
11
11
 
12
12
  it "should fail GET on DNS timeout" do
13
13
  EventMachine.run {
14
14
  EventMachine.heartbeat_interval = 0.1
15
15
  http = EventMachine::HttpRequest.new('http://127.1.1.1/').get :timeout => 1
16
- http.callback { failed }
16
+ http.callback { failed(http) }
17
17
  http.errback {
18
18
  http.response_header.status.should == 0
19
19
  EventMachine.stop
@@ -25,7 +25,7 @@ describe EventMachine::HttpRequest do
25
25
  EventMachine.run {
26
26
  EventMachine.heartbeat_interval = 0.1
27
27
  http = EventMachine::HttpRequest.new('http://somethinglocal/').get :timeout => 1
28
- http.callback { failed }
28
+ http.callback { failed(http) }
29
29
  http.errback {
30
30
  http.response_header.status.should == 0
31
31
  http.error.should match(/unable to resolve server address/)
@@ -59,7 +59,7 @@ describe EventMachine::HttpRequest do
59
59
  EventMachine.run {
60
60
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get
61
61
 
62
- http.errback { failed }
62
+ http.errback { failed(http) }
63
63
  http.callback {
64
64
  http.response_header.status.should == 200
65
65
  http.response.should match(/Hello/)
@@ -74,7 +74,7 @@ describe EventMachine::HttpRequest do
74
74
  EventMachine.run {
75
75
  http = EventMachine::HttpRequest.new('http://google.com:8080/').get :host => '127.0.0.1'
76
76
 
77
- http.errback { failed }
77
+ http.errback { failed(http) }
78
78
  http.callback {
79
79
  http.response_header.status.should == 200
80
80
  http.response.should match(/Hello/)
@@ -87,7 +87,7 @@ describe EventMachine::HttpRequest do
87
87
  EventMachine.run {
88
88
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/redirect').get :redirects => 1, :host => '127.0.0.1'
89
89
 
90
- http.errback { failed }
90
+ http.errback { failed(http) }
91
91
  http.callback {
92
92
  http.response_header.status.should == 200
93
93
  http.response_header["CONTENT_ENCODING"].should == "gzip"
@@ -105,7 +105,7 @@ describe EventMachine::HttpRequest do
105
105
  @s = StubServer.new("HTTP/1.0 301 MOVED PERMANENTLY\r\nlocation: http://127.0.0.1:8080/redirect\r\n\r\n")
106
106
 
107
107
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8081/').get :redirects => 2
108
- http.errback { failed }
108
+ http.errback { failed(http) }
109
109
 
110
110
  http.callback {
111
111
  http.response_header.status.should == 200
@@ -123,7 +123,7 @@ describe EventMachine::HttpRequest do
123
123
  it "should follow redirects on HEAD method" do
124
124
  EventMachine.run {
125
125
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/redirect/head').head :redirects => 1
126
- http.errback { failed }
126
+ http.errback { failed(http) }
127
127
  http.callback {
128
128
  http.response_header.status.should == 200
129
129
  http.last_effective_url.to_s.should == 'http://127.0.0.1:8080/'
@@ -136,7 +136,7 @@ describe EventMachine::HttpRequest do
136
136
 
137
137
  EventMachine.run {
138
138
  http = EventMachine::HttpRequest.new('http://www.google.com/').head :redirects => 1
139
- http.errback { failed }
139
+ http.errback { failed(http) }
140
140
  http.callback {
141
141
  http.response_header.status.should == 200
142
142
  EM.stop
@@ -151,7 +151,7 @@ describe EventMachine::HttpRequest do
151
151
  uri = URI.parse('http://127.0.0.1:8080/')
152
152
  http = EventMachine::HttpRequest.new(uri).get
153
153
 
154
- http.errback { failed }
154
+ http.errback { failed(http) }
155
155
  http.callback {
156
156
  http.response_header.status.should == 200
157
157
  http.response.should match(/Hello/)
@@ -165,7 +165,7 @@ describe EventMachine::HttpRequest do
165
165
  uri = URI.parse('http://127.0.0.1:8080/')
166
166
  http = EventMachine::HttpRequest.new(uri).head
167
167
 
168
- http.errback { p http; failed }
168
+ http.errback { failed(http) }
169
169
  http.callback {
170
170
  http.response_header.status.should == 200
171
171
  http.response.should == ""
@@ -180,7 +180,7 @@ describe EventMachine::HttpRequest do
180
180
  uri = URI.parse('http://127.0.0.1:8080/')
181
181
  http = EventMachine::HttpRequest.new(uri).delete
182
182
 
183
- http.errback { failed }
183
+ http.errback { failed(http) }
184
184
  http.callback {
185
185
  http.response_header.status.should == 200
186
186
  http.response.should == ""
@@ -193,7 +193,7 @@ describe EventMachine::HttpRequest do
193
193
  EventMachine.run {
194
194
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/fail').get
195
195
 
196
- http.errback { failed }
196
+ http.errback { failed(http) }
197
197
  http.callback {
198
198
  http.response_header.status.should == 404
199
199
  EventMachine.stop
@@ -205,7 +205,7 @@ describe EventMachine::HttpRequest do
205
205
  EventMachine.run {
206
206
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get :query => {:q => 'test'}
207
207
 
208
- http.errback { failed }
208
+ http.errback { failed(http) }
209
209
  http.callback {
210
210
  http.response_header.status.should == 200
211
211
  http.response.should match(/test/)
@@ -218,7 +218,7 @@ describe EventMachine::HttpRequest do
218
218
  EventMachine.run {
219
219
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get :query => "q=test"
220
220
 
221
- http.errback { failed }
221
+ http.errback { failed(http) }
222
222
  http.callback {
223
223
  http.response_header.status.should == 200
224
224
  http.response.should match(/test/)
@@ -231,7 +231,7 @@ describe EventMachine::HttpRequest do
231
231
  EventMachine.run {
232
232
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/echo_query').get :query => {:hash => ['value1', 'value2']}
233
233
 
234
- http.errback { failed }
234
+ http.errback { failed(http) }
235
235
  http.callback {
236
236
  http.response_header.status.should == 200
237
237
  http.response.should match(/hash\[\]=value1&hash\[\]=value2/)
@@ -245,7 +245,7 @@ describe EventMachine::HttpRequest do
245
245
  EventMachine.run {
246
246
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').put :body => "data"
247
247
 
248
- http.errback { failed }
248
+ http.errback { failed(http) }
249
249
  http.callback {
250
250
  http.response_header.status.should == 200
251
251
  http.response.should match(/data/)
@@ -258,7 +258,7 @@ describe EventMachine::HttpRequest do
258
258
  EventMachine.run {
259
259
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').post :body => "data"
260
260
 
261
- http.errback { failed }
261
+ http.errback { failed(http) }
262
262
  http.callback {
263
263
  http.response_header.status.should == 200
264
264
  http.response.should match(/data/)
@@ -271,7 +271,7 @@ describe EventMachine::HttpRequest do
271
271
  EventMachine.run {
272
272
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').post :body => {:stuff => 'string&string'}
273
273
 
274
- http.errback { failed }
274
+ http.errback { failed(http) }
275
275
  http.callback {
276
276
  http.response_header.status.should == 200
277
277
  http.response.should == "stuff=string%26string"
@@ -284,7 +284,7 @@ describe EventMachine::HttpRequest do
284
284
  EventMachine.run {
285
285
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').post :body => {"key1" => 1, "key2" => [2,3]}
286
286
 
287
- http.errback { failed }
287
+ http.errback { failed(http) }
288
288
  http.callback {
289
289
  http.response_header.status.should == 200
290
290
 
@@ -298,7 +298,7 @@ describe EventMachine::HttpRequest do
298
298
  EventMachine.run {
299
299
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/echo_content_length').post :body => {"key1" => "data1"}
300
300
 
301
- http.errback { failed }
301
+ http.errback { failed(http) }
302
302
  http.callback {
303
303
  http.response_header.status.should == 200
304
304
 
@@ -312,7 +312,7 @@ describe EventMachine::HttpRequest do
312
312
  EventMachine.run {
313
313
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get :head => {'if-none-match' => 'evar!'}
314
314
 
315
- http.errback { failed }
315
+ http.errback { failed(http) }
316
316
  http.callback {
317
317
  http.response_header.status.should == 304
318
318
  EventMachine.stop
@@ -326,7 +326,7 @@ describe EventMachine::HttpRequest do
326
326
  # digg.com uses chunked encoding
327
327
  http = EventMachine::HttpRequest.new('http://digg.com/news').get
328
328
 
329
- http.errback { failed }
329
+ http.errback { failed(http) }
330
330
  http.callback {
331
331
  http.response_header.status.should == 200
332
332
  EventMachine.stop
@@ -339,7 +339,7 @@ describe EventMachine::HttpRequest do
339
339
 
340
340
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get :head => {'authorization' => ['user', 'pass']}
341
341
 
342
- http.errback { failed }
342
+ http.errback { failed(http) }
343
343
  http.callback {
344
344
  http.response_header.status.should == 200
345
345
  EventMachine.stop
@@ -352,7 +352,7 @@ describe EventMachine::HttpRequest do
352
352
  oauth_header = 'OAuth oauth_nonce="oqwgSYFUD87MHmJJDv7bQqOF2EPnVus7Wkqj5duNByU", b=c, d=e'
353
353
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/oauth_auth').get :head => {'authorization' => oauth_header}
354
354
 
355
- http.errback { failed }
355
+ http.errback { failed(http) }
356
356
  http.callback {
357
357
  http.response_header.status.should == 200
358
358
  http.response.should == oauth_header
@@ -361,24 +361,39 @@ describe EventMachine::HttpRequest do
361
361
  }
362
362
  end
363
363
 
364
- it "should work with keep-alive servers" do
365
- EventMachine.run {
364
+ context "keepalive" do
365
+ it "should default to non-keepalive" do
366
+ EventMachine.run {
367
+ headers = {'If-Modified-Since' => 'Thu, 05 Aug 2010 22:54:44 GMT'}
368
+ http = EventMachine::HttpRequest.new('http://www.google.com/images/logos/ps_logo2.png').get :head => headers
366
369
 
367
- http = EventMachine::HttpRequest.new('http://mexicodiario.com/touch.public.json.php').get
370
+ http.errback { fail }
371
+ start = Time.now.to_i
372
+ http.callback {
373
+ (start - Time.now.to_i).should be_within(1).of(0)
374
+ EventMachine.stop
375
+ }
376
+ }
377
+ end
368
378
 
369
- http.errback { failed }
370
- http.callback {
371
- http.response_header.status.should == 200
372
- EventMachine.stop
379
+ it "should work with keep-alive servers" do
380
+ EventMachine.run {
381
+ http = EventMachine::HttpRequest.new('http://mexicodiario.com/touch.public.json.php').get :keepalive => true
382
+
383
+ http.errback { failed(http) }
384
+ http.callback {
385
+ http.response_header.status.should == 200
386
+ EventMachine.stop
387
+ }
373
388
  }
374
- }
389
+ end
375
390
  end
376
391
 
377
392
  it "should return ETag and Last-Modified headers" do
378
393
  EventMachine.run {
379
394
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/echo_query').get
380
395
 
381
- http.errback { failed }
396
+ http.errback { failed(http) }
382
397
  http.callback {
383
398
  http.response_header.status.should == 200
384
399
  http.response_header.etag.should match('abcdefg')
@@ -393,7 +408,7 @@ describe EventMachine::HttpRequest do
393
408
 
394
409
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/deflate').get :head => {"accept-encoding" => "deflate"}
395
410
 
396
- http.errback { failed }
411
+ http.errback { failed(http) }
397
412
  http.callback {
398
413
  http.response_header.status.should == 200
399
414
  http.response_header["CONTENT_ENCODING"].should == "deflate"
@@ -409,7 +424,7 @@ describe EventMachine::HttpRequest do
409
424
 
410
425
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/gzip').get :head => {"accept-encoding" => "gzip, compressed"}
411
426
 
412
- http.errback { failed }
427
+ http.errback { failed(http) }
413
428
  http.callback {
414
429
  http.response_header.status.should == 200
415
430
  http.response_header["CONTENT_ENCODING"].should == "gzip"
@@ -430,7 +445,7 @@ describe EventMachine::HttpRequest do
430
445
  (Time.now.to_i - t).should <= 5
431
446
  EventMachine.stop
432
447
  }
433
- http.callback { failed }
448
+ http.callback { failed(http) }
434
449
  }
435
450
  end
436
451
 
@@ -438,7 +453,7 @@ describe EventMachine::HttpRequest do
438
453
  it "should report last_effective_url" do
439
454
  EventMachine.run {
440
455
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get
441
- http.errback { failed }
456
+ http.errback { failed(http) }
442
457
  http.callback {
443
458
  http.response_header.status.should == 200
444
459
  http.last_effective_url.to_s.should == 'http://127.0.0.1:8080/'
@@ -451,7 +466,7 @@ describe EventMachine::HttpRequest do
451
466
  it "should follow location redirects" do
452
467
  EventMachine.run {
453
468
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/redirect').get :redirects => 1
454
- http.errback { failed }
469
+ http.errback { failed(http) }
455
470
  http.callback {
456
471
  http.response_header.status.should == 200
457
472
  http.response_header["CONTENT_ENCODING"].should == "gzip"
@@ -467,7 +482,7 @@ describe EventMachine::HttpRequest do
467
482
  it "should default to 0 redirects" do
468
483
  EventMachine.run {
469
484
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/redirect').get
470
- http.errback { failed }
485
+ http.errback { failed(http) }
471
486
  http.callback {
472
487
  http.response_header.status.should == 301
473
488
  http.last_effective_url.to_s.should == 'http://127.0.0.1:8080/gzip'
@@ -478,10 +493,10 @@ describe EventMachine::HttpRequest do
478
493
  }
479
494
  end
480
495
 
481
- it "should not invoke redirect logic on failed connections" do
496
+ it "should not invoke redirect logic on failed(http) connections" do
482
497
  EventMachine.run {
483
498
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8081/').get :timeout => 0.1, :redirects => 5
484
- http.callback { failed }
499
+ http.callback { failed(http) }
485
500
  http.errback {
486
501
  http.redirects.should == 0
487
502
  EM.stop
@@ -492,7 +507,7 @@ describe EventMachine::HttpRequest do
492
507
  it "should normalize redirect urls" do
493
508
  EventMachine.run {
494
509
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/redirect/bad').get :redirects => 1
495
- http.errback { failed }
510
+ http.errback { failed(http) }
496
511
  http.callback {
497
512
  http.last_effective_url.to_s.should match('http://127.0.0.1:8080/')
498
513
  http.response.should match('Hello, World!')
@@ -504,7 +519,7 @@ describe EventMachine::HttpRequest do
504
519
  it "should fail gracefully on a missing host in absolute Location header" do
505
520
  EventMachine.run {
506
521
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/redirect/nohost').get :redirects => 1
507
- http.callback { failed }
522
+ http.callback { failed(http) }
508
523
  http.errback {
509
524
  http.error.should == 'Location header format error'
510
525
  EM.stop
@@ -515,7 +530,7 @@ describe EventMachine::HttpRequest do
515
530
  it "should fail gracefully on an invalid host in Location header" do
516
531
  EventMachine.run {
517
532
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/redirect/badhost').get :redirects => 1
518
- http.callback { failed }
533
+ http.callback { failed(http) }
519
534
  http.errback {
520
535
  http.error.should == 'unable to resolve server address'
521
536
  EM.stop
@@ -529,7 +544,7 @@ describe EventMachine::HttpRequest do
529
544
  body = ''
530
545
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get
531
546
 
532
- http.errback { failed }
547
+ http.errback { failed(http) }
533
548
  http.stream { |chunk| body += chunk }
534
549
 
535
550
  http.callback {
@@ -546,7 +561,7 @@ describe EventMachine::HttpRequest do
546
561
  EventMachine.run {
547
562
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get
548
563
 
549
- http.errback { failed }
564
+ http.errback { failed(http) }
550
565
  http.headers { |hash|
551
566
  hash.should be_an_kind_of Hash
552
567
  hash.should include 'CONNECTION'
@@ -565,7 +580,7 @@ describe EventMachine::HttpRequest do
565
580
  EventMachine.run {
566
581
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get
567
582
 
568
- http.callback { failed }
583
+ http.callback { failed(http) }
569
584
  http.headers { |hash|
570
585
  hash.should be_an_kind_of Hash
571
586
  hash.should include 'CONNECTION'
@@ -589,7 +604,7 @@ describe EventMachine::HttpRequest do
589
604
  body = ''
590
605
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/deflate').get :head => {"accept-encoding" => "deflate, compressed"}
591
606
 
592
- http.errback { failed }
607
+ http.errback { failed(http) }
593
608
  http.stream { |chunk| body += chunk }
594
609
 
595
610
  http.callback {
@@ -606,7 +621,7 @@ describe EventMachine::HttpRequest do
606
621
  EventMachine.run {
607
622
  http = EventMachine::HttpRequest.new('https://mail.google.com:443/mail/').get
608
623
 
609
- http.errback { failed }
624
+ http.errback { failed(http) }
610
625
  http.callback {
611
626
  http.response_header.status.should == 302
612
627
  EventMachine.stop
@@ -618,7 +633,7 @@ describe EventMachine::HttpRequest do
618
633
  EventMachine.run {
619
634
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/set_cookie').get
620
635
 
621
- http.errback { failed }
636
+ http.errback { failed(http) }
622
637
  http.callback {
623
638
  http.response_header.status.should == 200
624
639
  http.response_header.cookie.should == "id=1; expires=Tue, 09-Aug-2011 17:53:39 GMT; path=/;"
@@ -631,7 +646,7 @@ describe EventMachine::HttpRequest do
631
646
  EventMachine.run {
632
647
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/echo_cookie').get :head => {'cookie' => 'id=2;'}
633
648
 
634
- http.errback { failed }
649
+ http.errback { failed(http) }
635
650
  http.callback {
636
651
  http.response.should == "id=2;"
637
652
  EventMachine.stop
@@ -643,7 +658,7 @@ describe EventMachine::HttpRequest do
643
658
  EventMachine.run {
644
659
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/echo_cookie').get :head => {'cookie' => {'id' => 2}}
645
660
 
646
- http.errback { failed }
661
+ http.errback { failed(http) }
647
662
  http.callback {
648
663
  http.response.should == "id=2;"
649
664
  EventMachine.stop
@@ -657,7 +672,7 @@ describe EventMachine::HttpRequest do
657
672
  @s = StubServer.new("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nFoo")
658
673
 
659
674
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8081/').get
660
- http.errback { failed }
675
+ http.errback { failed(http) }
661
676
  http.callback {
662
677
  http.response.should match(/Foo/)
663
678
  http.response_header['CONTENT_LENGTH'].should_not == 0
@@ -673,7 +688,7 @@ describe EventMachine::HttpRequest do
673
688
  @s = StubServer.new("HTTP/1.0 200 OK\nContent-Type: text/plain\nContent-Length: 3\nConnection: close\n\nFoo")
674
689
 
675
690
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8081/').get
676
- http.errback { failed }
691
+ http.errback { failed(http) }
677
692
  http.callback {
678
693
  http.response_header.status.should == 200
679
694
  http.response_header['CONTENT_TYPE'].should == 'text/plain'
@@ -691,7 +706,7 @@ describe EventMachine::HttpRequest do
691
706
  EventMachine.run {
692
707
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/echo_content_type').post :body => "data"
693
708
 
694
- http.errback { failed }
709
+ http.errback { failed(http) }
695
710
  http.callback {
696
711
  http.response_header.status.should == 200
697
712
  http.response.should be_empty
@@ -704,7 +719,7 @@ describe EventMachine::HttpRequest do
704
719
  EventMachine.run {
705
720
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/echo_content_type').post :body => {:a => :b}
706
721
 
707
- http.errback { failed }
722
+ http.errback { failed(http) }
708
723
  http.callback {
709
724
  http.response_header.status.should == 200
710
725
  http.response.should match("application/x-www-form-urlencoded")
@@ -715,24 +730,59 @@ describe EventMachine::HttpRequest do
715
730
 
716
731
  it "should not override content-type when passing in ruby hash/array for body" do
717
732
  EventMachine.run {
733
+ ct = 'text; charset=utf-8'
718
734
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/echo_content_type').post({
719
- :body => {:a => :b}, :head => {'content-type' => 'text'}})
735
+ :body => {:a => :b}, :head => {'content-type' => ct}})
720
736
 
721
- http.errback { failed }
737
+ http.errback { failed(http) }
722
738
  http.callback {
723
739
  http.response_header.status.should == 200
724
- http.response.should match("text")
740
+ http.content_charset.should == Encoding.find('utf-8')
741
+ http.response_header["CONTENT_TYPE"].should == ct
725
742
  EventMachine.stop
726
743
  }
727
744
  }
728
745
  end
746
+
747
+ it "should default to external encoding on invalid encoding" do
748
+ EventMachine.run {
749
+ ct = 'text/html; charset=utf-8lias'
750
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/echo_content_type').post({
751
+ :body => {:a => :b}, :head => {'content-type' => ct}})
752
+
753
+ http.errback { failed(http) }
754
+ http.callback {
755
+ http.response_header.status.should == 200
756
+ http.content_charset.should == Encoding.find('utf-8')
757
+ http.response_header["CONTENT_TYPE"].should == ct
758
+ EventMachine.stop
759
+ }
760
+ }
761
+ end
762
+
763
+ it "should processed escaped content-type" do
764
+ EventMachine.run {
765
+ ct = "text/html; charset=\"ISO-8859-4\""
766
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/echo_content_type').post({
767
+ :body => {:a => :b}, :head => {'content-type' => ct}})
768
+
769
+ http.errback { failed(http) }
770
+ http.callback {
771
+ http.response_header.status.should == 200
772
+ http.content_charset.should == Encoding.find('ISO-8859-4')
773
+ http.response_header["CONTENT_TYPE"].should == ct
774
+ EventMachine.stop
775
+ }
776
+ }
777
+ end
778
+
729
779
  end
730
780
 
731
781
  it "should complete a Location: with a relative path" do
732
782
  EventMachine.run {
733
783
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/relative-location').get
734
784
 
735
- http.errback { failed }
785
+ http.errback { failed(http) }
736
786
  http.callback {
737
787
  http.response_header['LOCATION'].should == 'http://127.0.0.1:8080/forwarded'
738
788
  EventMachine.stop
@@ -744,7 +794,7 @@ describe EventMachine::HttpRequest do
744
794
  EventMachine.run {
745
795
  http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').post :file => 'spec/fixtures/google.ca'
746
796
 
747
- http.errback { failed }
797
+ http.errback { failed(http) }
748
798
  http.callback {
749
799
  http.response.should match('google')
750
800
  EventMachine.stop
@@ -760,7 +810,7 @@ describe EventMachine::HttpRequest do
760
810
  c.options[:body] = {:callback_run => 'yes'}
761
811
  client = c
762
812
  }
763
- http.errback { failed }
813
+ http.errback { failed(http) }
764
814
  http.callback {
765
815
  client.should be_kind_of(EventMachine::HttpClient)
766
816
  http.response_header.status.should == 200
@@ -797,7 +847,7 @@ describe EventMachine::HttpRequest do
797
847
  :host => '127.0.0.1', :port => 8083
798
848
  }
799
849
 
800
- http.errback { p http.inspect; failed }
850
+ http.errback { failed(http) }
801
851
  http.callback {
802
852
  http.response_header.status.should == 200
803
853
  http.response.should match('test')
@@ -813,7 +863,7 @@ describe EventMachine::HttpRequest do
813
863
  :host => '127.0.0.1', :port => 8083
814
864
  }
815
865
 
816
- http.errback { p http.inspect; failed }
866
+ http.errback { failed(http) }
817
867
  http.callback {
818
868
  http.response_header.status.should == 200
819
869
  # The test proxy server gives the requested uri back in this header
@@ -833,7 +883,7 @@ describe EventMachine::HttpRequest do
833
883
  :query => { 'q' => 'test' }
834
884
  )
835
885
 
836
- http.errback { p http.inspect; failed }
886
+ http.errback { failed(http) }
837
887
  http.callback {
838
888
  http.response_header.status.should == 200
839
889
  http.response.should match('test')
@@ -851,7 +901,7 @@ describe EventMachine::HttpRequest do
851
901
  :proxy => {:host => '127.0.0.1', :port => 8082, :use_connect => true}
852
902
  })
853
903
 
854
- http.errback { p http.inspect; failed }
904
+ http.errback { failed(http) }
855
905
  http.callback {
856
906
  http.response_header.status.should == 200
857
907
  http.response.should == 'Hello, World!'
@@ -867,7 +917,7 @@ describe EventMachine::HttpRequest do
867
917
  :body => "data", :proxy => {:host => '127.0.0.1', :port => 8082, :use_connect => true}
868
918
  })
869
919
 
870
- http.errback { failed }
920
+ http.errback { failed(http) }
871
921
  http.callback {
872
922
  http.response_header.status.should == 200
873
923
  http.response.should match(/data/)
@@ -890,7 +940,7 @@ describe EventMachine::HttpRequest do
890
940
  EventMachine.run {
891
941
  http = EventMachine::HttpRequest.new('ws://127.0.0.1:8080/').get :timeout => 0
892
942
 
893
- http.callback { failed }
943
+ http.callback { failed(http) }
894
944
  http.errback {
895
945
  http.response_header.status.should == 200
896
946
  EventMachine.stop
@@ -907,7 +957,7 @@ describe EventMachine::HttpRequest do
907
957
  end
908
958
 
909
959
  http = EventMachine::HttpRequest.new('ws://127.0.0.1:8085/').get :timeout => 1
910
- http.errback { failed }
960
+ http.errback { failed(http) }
911
961
  http.callback {
912
962
  http.response_header.status.should == 101
913
963
  http.response_header['CONNECTION'].should match(/Upgrade/)
@@ -938,7 +988,7 @@ describe EventMachine::HttpRequest do
938
988
 
939
989
  EventMachine.add_timer(0.1) do
940
990
  http = EventMachine::HttpRequest.new('ws://127.0.0.1:8085/').get :timeout => 0
941
- http.errback { failed }
991
+ http.errback { failed(http) }
942
992
  http.callback { http.response_header.status.should == 101 }
943
993
  http.stream {|msg|
944
994
  msg.should == messages[recieved.size]