em-http-request 1.0.0.beta.3 → 1.0.0.beta.4
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/.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
|