em-http-request 1.0.0.beta.3 → 1.0.0.beta.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of em-http-request might be problematic. Click here for more details.
- data/.gemtest +0 -0
- data/Gemfile +12 -1
- data/README.md +2 -2
- data/Rakefile +2 -1
- data/benchmarks/clients.rb +156 -0
- data/benchmarks/em-excon.rb +87 -0
- data/benchmarks/em-profile.gif +0 -0
- data/benchmarks/em-profile.txt +65 -0
- data/benchmarks/server.rb +48 -0
- data/em-http-request.gemspec +2 -1
- data/examples/.gitignore +1 -0
- data/examples/fibered-http.rb +10 -6
- data/examples/oauth-tweet.rb +22 -37
- data/lib/em-http.rb +3 -2
- data/lib/em-http/client.rb +52 -37
- data/lib/em-http/decoders.rb +1 -1
- data/lib/em-http/http_client_options.rb +56 -0
- data/lib/em-http/http_connection.rb +97 -41
- data/lib/em-http/http_connection_options.rb +23 -0
- data/lib/em-http/http_encoding.rb +1 -1
- data/lib/em-http/middleware/cookie_jar.rb +38 -0
- data/lib/em-http/middleware/json_response.rb +15 -0
- data/lib/em-http/middleware/oauth.rb +21 -0
- data/lib/em-http/multi.rb +18 -18
- data/lib/em-http/request.rb +7 -29
- data/lib/em-http/version.rb +1 -1
- data/spec/client_spec.rb +39 -0
- data/spec/external_spec.rb +17 -1
- data/spec/helper.rb +12 -0
- data/spec/middleware_spec.rb +85 -7
- data/spec/multi_spec.rb +77 -22
- data/spec/pipelining_spec.rb +1 -1
- data/spec/redirect_spec.rb +86 -0
- data/spec/socksify_proxy_spec.rb +14 -14
- data/spec/stallion.rb +33 -2
- metadata +28 -6
- data/lib/em-http/http_options.rb +0 -53
data/spec/multi_spec.rb
CHANGED
@@ -3,39 +3,94 @@ require 'stallion'
|
|
3
3
|
|
4
4
|
describe EventMachine::MultiRequest do
|
5
5
|
|
6
|
+
let(:multi) { EventMachine::MultiRequest.new }
|
7
|
+
let(:url) { 'http://127.0.0.1:8090/' }
|
8
|
+
|
6
9
|
it "should submit multiple requests in parallel and return once all of them are complete" do
|
7
10
|
EventMachine.run {
|
11
|
+
multi.add :a, EventMachine::HttpRequest.new(url).get
|
12
|
+
multi.add :b, EventMachine::HttpRequest.new(url).post
|
13
|
+
multi.add :c, EventMachine::HttpRequest.new(url).head
|
14
|
+
multi.add :d, EventMachine::HttpRequest.new(url).delete
|
15
|
+
multi.add :e, EventMachine::HttpRequest.new(url).put
|
8
16
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
multi.callback {
|
17
|
-
multi.responses[:succeeded].size.should == 2
|
18
|
-
multi.responses[:succeeded][0].response.should match(/test|Hello/)
|
19
|
-
multi.responses[:succeeded][1].response.should match(/test|Hello/)
|
17
|
+
multi.callback {
|
18
|
+
multi.responses[:callback].size.should == 5
|
19
|
+
multi.responses[:callback].each { |name, response|
|
20
|
+
[ :a, :b, :c, :d, :e ].should include(name)
|
21
|
+
response.response_header.status.should == 200
|
22
|
+
}
|
23
|
+
multi.responses[:errback].size.should == 0
|
20
24
|
|
21
25
|
EventMachine.stop
|
22
26
|
}
|
23
27
|
}
|
24
28
|
end
|
25
29
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
+
describe "#requests" do
|
31
|
+
it "should return the added requests" do
|
32
|
+
request1 = stub('request1', :callback => nil, :errback => nil)
|
33
|
+
request2 = stub('request2', :callback => nil, :errback => nil)
|
34
|
+
|
35
|
+
multi.add :a, request1
|
36
|
+
multi.add :b, request2
|
37
|
+
|
38
|
+
multi.requests.should == [ request1, request2 ]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#responses" do
|
43
|
+
it "should have an empty :callback hash" do
|
44
|
+
multi.responses[:callback].should be_a(Hash)
|
45
|
+
multi.responses[:callback].size.should == 0
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should have an empty :errback hash" do
|
49
|
+
multi.responses[:errback].should be_a(Hash)
|
50
|
+
multi.responses[:errback].size.should == 0
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should provide access to the requests by name" do
|
54
|
+
EventMachine.run {
|
55
|
+
request1 = EventMachine::HttpRequest.new(url).get
|
56
|
+
request2 = EventMachine::HttpRequest.new(url).post
|
57
|
+
multi.add :a, request1
|
58
|
+
multi.add :b, request2
|
30
59
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
60
|
+
multi.callback {
|
61
|
+
multi.responses[:callback][:a].should equal(request1)
|
62
|
+
multi.responses[:callback][:b].should equal(request2)
|
63
|
+
|
64
|
+
EventMachine.stop
|
65
|
+
}
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#finished?" do
|
71
|
+
it "should be true when no requests have been added" do
|
72
|
+
multi.should be_finished
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should be false while the requests are not finished" do
|
76
|
+
EventMachine.run {
|
77
|
+
multi.add :a, EventMachine::HttpRequest.new(url).get
|
78
|
+
multi.should_not be_finished
|
35
79
|
|
36
80
|
EventMachine.stop
|
37
|
-
|
38
|
-
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should be finished when all requests are finished" do
|
85
|
+
EventMachine.run {
|
86
|
+
multi.add :a, EventMachine::HttpRequest.new(url).get
|
87
|
+
multi.callback {
|
88
|
+
multi.should be_finished
|
89
|
+
|
90
|
+
EventMachine.stop
|
91
|
+
}
|
92
|
+
}
|
93
|
+
end
|
39
94
|
end
|
40
95
|
|
41
|
-
end
|
96
|
+
end
|
data/spec/pipelining_spec.rb
CHANGED
data/spec/redirect_spec.rb
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
|
+
class RedirectMiddleware
|
4
|
+
attr_reader :call_count
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@call_count = 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def request(c, h, r)
|
11
|
+
@call_count += 1
|
12
|
+
[h.merge({'EM-Middleware' => @call_count.to_s}), r]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class PickyRedirectMiddleware < RedirectMiddleware
|
17
|
+
def response(r)
|
18
|
+
if r.redirect? && r.response_header['LOCATION'][-1] == '3'
|
19
|
+
# set redirects to 0 to avoid further processing
|
20
|
+
r.req.redirects = 0
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
3
25
|
describe EventMachine::HttpRequest do
|
4
26
|
|
5
27
|
it "should follow location redirects" do
|
@@ -111,4 +133,68 @@ describe EventMachine::HttpRequest do
|
|
111
133
|
}
|
112
134
|
end
|
113
135
|
|
136
|
+
it "should capture and pass cookies on redirect and pass_cookies by default" do
|
137
|
+
EventMachine.run {
|
138
|
+
http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/multiple-with-cookie').get :redirects => 2, :head => {'cookie' => 'id=2;'}
|
139
|
+
http.errback { failed(http) }
|
140
|
+
http.callback {
|
141
|
+
http.response_header.status.should == 200
|
142
|
+
http.response_header["CONTENT_ENCODING"].should == "gzip"
|
143
|
+
http.response.should == "compressed"
|
144
|
+
http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/gzip'
|
145
|
+
http.redirects.should == 2
|
146
|
+
http.cookies.should include("id=2;")
|
147
|
+
http.cookies.should include("another_id=1; expires=Tue, 09-Aug-2011 17:53:39 GMT; path=/;")
|
148
|
+
|
149
|
+
EM.stop
|
150
|
+
}
|
151
|
+
}
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should capture and not pass cookies on redirect if passing is disabled via pass_cookies" do
|
155
|
+
EventMachine.run {
|
156
|
+
http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/multiple-with-cookie').get :redirects => 2, :pass_cookies => false, :head => {'cookie' => 'id=2;'}
|
157
|
+
http.errback { failed(http) }
|
158
|
+
http.callback {
|
159
|
+
http.response_header.status.should == 200
|
160
|
+
http.response_header["CONTENT_ENCODING"].should == "gzip"
|
161
|
+
http.response.should == "compressed"
|
162
|
+
http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/gzip'
|
163
|
+
http.redirects.should == 2
|
164
|
+
http.cookies.should include("id=2;")
|
165
|
+
http.cookies.should_not include("another_id=1; expires=Tue, 09-Aug-2011 17:53:39 GMT; path=/;")
|
166
|
+
|
167
|
+
EM.stop
|
168
|
+
}
|
169
|
+
}
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should call middleware each time it redirects" do
|
173
|
+
EventMachine.run {
|
174
|
+
conn = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/middleware_redirects_1')
|
175
|
+
conn.use RedirectMiddleware
|
176
|
+
http = conn.get :redirects => 3
|
177
|
+
http.errback { failed(http) }
|
178
|
+
http.callback {
|
179
|
+
http.response_header.status.should == 200
|
180
|
+
http.response_header['EM_MIDDLEWARE'].to_i.should == 3
|
181
|
+
EM.stop
|
182
|
+
}
|
183
|
+
}
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should call middleware which may reject a redirection" do
|
187
|
+
EventMachine.run {
|
188
|
+
conn = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/middleware_redirects_1')
|
189
|
+
conn.use PickyRedirectMiddleware
|
190
|
+
http = conn.get :redirects => 3
|
191
|
+
http.errback { failed(http) }
|
192
|
+
http.callback {
|
193
|
+
http.response_header.status.should == 301
|
194
|
+
http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/redirect/middleware_redirects_2'
|
195
|
+
EM.stop
|
196
|
+
}
|
197
|
+
}
|
198
|
+
end
|
199
|
+
|
114
200
|
end
|
data/spec/socksify_proxy_spec.rb
CHANGED
@@ -1,24 +1,24 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
requires_connection do
|
4
|
+
requires_port(8080) do
|
5
|
+
describe EventMachine::HttpRequest do
|
4
6
|
|
5
|
-
|
7
|
+
# ssh -D 8080 igvita
|
8
|
+
let(:proxy) { {:proxy => { :host => '127.0.0.1', :port => 8080, :type => :socks5 }} }
|
6
9
|
|
7
|
-
|
8
|
-
|
10
|
+
it "should use SOCKS5 proxy" do
|
11
|
+
EventMachine.run {
|
12
|
+
http = EventMachine::HttpRequest.new('http://jsonip.com/', proxy).get
|
9
13
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
http.response_header.status.should == 200
|
17
|
-
http.response.should match('72.52.131')
|
18
|
-
EventMachine.stop
|
14
|
+
http.errback { failed(http) }
|
15
|
+
http.callback {
|
16
|
+
http.response_header.status.should == 200
|
17
|
+
http.response.should match('72.52.131')
|
18
|
+
EventMachine.stop
|
19
|
+
}
|
19
20
|
}
|
20
|
-
|
21
|
+
end
|
21
22
|
end
|
22
23
|
end
|
23
|
-
|
24
24
|
end
|
data/spec/stallion.rb
CHANGED
@@ -113,11 +113,21 @@ Stallion.saddle :spec do |stable|
|
|
113
113
|
sleep(10)
|
114
114
|
stable.response.write 'timeout'
|
115
115
|
|
116
|
+
elsif stable.request.path_info == '/cookie_parrot'
|
117
|
+
stable.response.status = 200
|
118
|
+
stable.response["Set-Cookie"] = stable.request.env['HTTP_COOKIE']
|
119
|
+
|
116
120
|
elsif stable.request.path_info == '/redirect'
|
117
121
|
stable.response.status = 301
|
118
122
|
stable.response["Location"] = "/gzip"
|
119
123
|
stable.response.write 'redirect'
|
120
124
|
|
125
|
+
elsif stable.request.path_info == '/redirect/multiple-with-cookie'
|
126
|
+
stable.response.status = 301
|
127
|
+
stable.response["Set-Cookie"] = "another_id=1; expires=Tue, 09-Aug-2011 17:53:39 GMT; path=/;"
|
128
|
+
stable.response["Location"] = "/redirect"
|
129
|
+
stable.response.write 'redirect'
|
130
|
+
|
121
131
|
elsif stable.request.path_info == '/redirect/bad'
|
122
132
|
stable.response.status = 301
|
123
133
|
stable.response["Location"] = "http://127.0.0.1:8090"
|
@@ -126,6 +136,20 @@ Stallion.saddle :spec do |stable|
|
|
126
136
|
stable.response.status = 301
|
127
137
|
stable.response["Location"] = "/"
|
128
138
|
|
139
|
+
elsif stable.request.path_info == '/redirect/middleware_redirects_1'
|
140
|
+
stable.response.status = 301
|
141
|
+
stable.response["EM-Middleware"] = stable.request.env["HTTP_EM_MIDDLEWARE"]
|
142
|
+
stable.response["Location"] = "/redirect/middleware_redirects_2"
|
143
|
+
|
144
|
+
elsif stable.request.path_info == '/redirect/middleware_redirects_2'
|
145
|
+
stable.response.status = 301
|
146
|
+
stable.response["EM-Middleware"] = stable.request.env["HTTP_EM_MIDDLEWARE"]
|
147
|
+
stable.response["Location"] = "/redirect/middleware_redirects_3"
|
148
|
+
|
149
|
+
elsif stable.request.path_info == '/redirect/middleware_redirects_3'
|
150
|
+
stable.response.status = 200
|
151
|
+
stable.response["EM-Middleware"] = stable.request.env["HTTP_EM_MIDDLEWARE"]
|
152
|
+
|
129
153
|
elsif stable.request.path_info == '/redirect/nohost'
|
130
154
|
stable.response.status = 301
|
131
155
|
stable.response["Location"] = "http:/"
|
@@ -144,9 +168,16 @@ Stallion.saddle :spec do |stable|
|
|
144
168
|
stable.response["Content-Encoding"] = "gzip"
|
145
169
|
|
146
170
|
elsif stable.request.path_info == '/deflate'
|
147
|
-
|
171
|
+
deflater = Zlib::Deflate.new(
|
172
|
+
Zlib::DEFAULT_COMPRESSION,
|
173
|
+
-Zlib::MAX_WBITS, # drop the zlib header which causes both Safari and IE to choke
|
174
|
+
Zlib::DEF_MEM_LEVEL,
|
175
|
+
Zlib::DEFAULT_STRATEGY
|
176
|
+
)
|
177
|
+
deflater.deflate("compressed")
|
178
|
+
stable.response.write deflater.finish
|
148
179
|
stable.response["Content-Encoding"] = "deflate"
|
149
|
-
|
180
|
+
|
150
181
|
elsif stable.request.env["HTTP_IF_NONE_MATCH"]
|
151
182
|
stable.response.status = 304
|
152
183
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: em-http-request
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: 6
|
5
|
-
version: 1.0.0.beta.
|
5
|
+
version: 1.0.0.beta.4
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Ilya Grigorik
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-05-27 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
requirements:
|
22
22
|
- - ">="
|
23
23
|
- !ruby/object:Gem::Version
|
24
|
-
version:
|
24
|
+
version: 1.0.0.beta.3
|
25
25
|
type: :runtime
|
26
26
|
version_requirements: *id001
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -102,16 +102,27 @@ dependencies:
|
|
102
102
|
type: :development
|
103
103
|
version_requirements: *id008
|
104
104
|
- !ruby/object:Gem::Dependency
|
105
|
-
name:
|
105
|
+
name: cookiejar
|
106
106
|
prerelease: false
|
107
107
|
requirement: &id009 !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: "0"
|
113
|
+
type: :development
|
114
|
+
version_requirements: *id009
|
115
|
+
- !ruby/object:Gem::Dependency
|
116
|
+
name: mongrel
|
117
|
+
prerelease: false
|
118
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
108
119
|
none: false
|
109
120
|
requirements:
|
110
121
|
- - ~>
|
111
122
|
- !ruby/object:Gem::Version
|
112
123
|
version: 1.2.0.pre2
|
113
124
|
type: :development
|
114
|
-
version_requirements: *
|
125
|
+
version_requirements: *id010
|
115
126
|
description: EventMachine based, async HTTP Request client
|
116
127
|
email:
|
117
128
|
- ilya@igvita.com
|
@@ -122,13 +133,20 @@ extensions: []
|
|
122
133
|
extra_rdoc_files: []
|
123
134
|
|
124
135
|
files:
|
136
|
+
- .gemtest
|
125
137
|
- .gitignore
|
126
138
|
- .rspec
|
127
139
|
- Changelog.md
|
128
140
|
- Gemfile
|
129
141
|
- README.md
|
130
142
|
- Rakefile
|
143
|
+
- benchmarks/clients.rb
|
144
|
+
- benchmarks/em-excon.rb
|
145
|
+
- benchmarks/em-profile.gif
|
146
|
+
- benchmarks/em-profile.txt
|
147
|
+
- benchmarks/server.rb
|
131
148
|
- em-http-request.gemspec
|
149
|
+
- examples/.gitignore
|
132
150
|
- examples/fetch.rb
|
133
151
|
- examples/fibered-http.rb
|
134
152
|
- examples/oauth-tweet.rb
|
@@ -138,10 +156,14 @@ files:
|
|
138
156
|
- lib/em-http/client.rb
|
139
157
|
- lib/em-http/core_ext/bytesize.rb
|
140
158
|
- lib/em-http/decoders.rb
|
159
|
+
- lib/em-http/http_client_options.rb
|
141
160
|
- lib/em-http/http_connection.rb
|
161
|
+
- lib/em-http/http_connection_options.rb
|
142
162
|
- lib/em-http/http_encoding.rb
|
143
163
|
- lib/em-http/http_header.rb
|
144
|
-
- lib/em-http/
|
164
|
+
- lib/em-http/middleware/cookie_jar.rb
|
165
|
+
- lib/em-http/middleware/json_response.rb
|
166
|
+
- lib/em-http/middleware/oauth.rb
|
145
167
|
- lib/em-http/multi.rb
|
146
168
|
- lib/em-http/request.rb
|
147
169
|
- lib/em-http/version.rb
|
data/lib/em-http/http_options.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
class HttpOptions
|
2
|
-
attr_reader :uri, :method, :host, :port, :options
|
3
|
-
|
4
|
-
def initialize(uri, options, method = :none)
|
5
|
-
@options = options
|
6
|
-
@method = method.to_s.upcase
|
7
|
-
|
8
|
-
set_uri(uri)
|
9
|
-
|
10
|
-
@options[:keepalive] ||= false # default to single request per connection
|
11
|
-
@options[:redirects] ||= 0 # default number of redirects to follow
|
12
|
-
@options[:followed] ||= 0 # keep track of number of followed requests
|
13
|
-
|
14
|
-
@options[:connect_timeout] ||= 5 # default connection setup timeout
|
15
|
-
@options[:inactivity_timeout] ||= 10 # default connection inactivity (post-setup) timeout
|
16
|
-
end
|
17
|
-
|
18
|
-
def proxy
|
19
|
-
@options[:proxy]
|
20
|
-
end
|
21
|
-
|
22
|
-
def follow_redirect?
|
23
|
-
@options[:followed] < @options[:redirects]
|
24
|
-
end
|
25
|
-
|
26
|
-
def set_uri(uri)
|
27
|
-
uri = uri.kind_of?(Addressable::URI) ? uri : Addressable::URI::parse(uri.to_s)
|
28
|
-
|
29
|
-
uri.path = '/' if uri.path.empty?
|
30
|
-
if path = @options.delete(:path)
|
31
|
-
uri.path = path
|
32
|
-
end
|
33
|
-
|
34
|
-
@uri = uri
|
35
|
-
|
36
|
-
# Make sure the ports are set as Addressable::URI doesn't
|
37
|
-
# set the port if it isn't there
|
38
|
-
if @uri.scheme == "https"
|
39
|
-
@uri.port ||= 443
|
40
|
-
else
|
41
|
-
@uri.port ||= 80
|
42
|
-
end
|
43
|
-
|
44
|
-
if proxy = @options[:proxy]
|
45
|
-
@host = proxy[:host]
|
46
|
-
@port = proxy[:port]
|
47
|
-
else
|
48
|
-
@host = @uri.host
|
49
|
-
@port = @uri.port
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
53
|
-
end
|