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.
- data/.gitignore +2 -1
- data/.rspec +0 -0
- data/Changelog.md +13 -0
- data/Gemfile +2 -14
- data/README.md +7 -0
- data/Rakefile +6 -35
- data/em-http-request.gemspec +25 -94
- data/ext/buffer/extconf.rb +53 -53
- data/ext/http11_client/ext_help.h +14 -14
- data/ext/http11_client/extconf.rb +6 -6
- data/ext/http11_client/http11_client.c +328 -328
- data/ext/http11_client/http11_parser.h +48 -48
- data/lib/em-http.rb +15 -16
- data/lib/em-http/client.rb +15 -222
- data/lib/em-http/http_encoding.rb +135 -0
- data/lib/em-http/http_header.rb +71 -0
- data/lib/em-http/http_options.rb +4 -3
- data/lib/em-http/request.rb +0 -3
- data/lib/em-http/version.rb +5 -0
- data/spec/encoding_spec.rb +7 -1
- data/spec/mock_spec.rb +1 -1
- data/spec/multi_spec.rb +68 -68
- data/spec/request_spec.rb +125 -75
- data/spec/stallion.rb +1 -0
- metadata +100 -25
- data/LICENSE +0 -58
- data/VERSION +0 -1
- data/autotest/discover.rb +0 -1
@@ -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
|
data/lib/em-http/http_options.rb
CHANGED
@@ -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.
|
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
|
22
|
-
@options[:redirects] ||= 0
|
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
|
data/lib/em-http/request.rb
CHANGED
data/spec/encoding_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
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
|
data/spec/mock_spec.rb
CHANGED
data/spec/multi_spec.rb
CHANGED
@@ -1,68 +1,68 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
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
|
data/spec/request_spec.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require '
|
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 {
|
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
|
-
|
365
|
-
|
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
|
-
|
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
|
-
|
370
|
-
|
371
|
-
http.
|
372
|
-
|
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' =>
|
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.
|
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 {
|
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 {
|
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 {
|
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 {
|
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]
|