em-http-request 0.2.15 → 0.3.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.

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]