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/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
- # 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:8090/').get(:query => {:q => 'test'}))
14
- multi.add(EventMachine::HttpRequest.new('http://127.0.0.1:8090/').get)
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
- it "should accept multiple open connections and return once all of them are complete" do
27
- EventMachine.run {
28
- http1 = EventMachine::HttpRequest.new('http://127.0.0.1:8090/').get(:query => {:q => 'test'})
29
- http2 = EventMachine::HttpRequest.new('http://127.0.0.1:8090/').get
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
- multi = EventMachine::MultiRequest.new([http1, http2]) do
32
- multi.responses[:succeeded].size.should == 2
33
- multi.responses[:succeeded][0].response.should match(/test|Hello/)
34
- multi.responses[:succeeded][1].response.should match(/test|Hello/)
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
- end
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
@@ -27,7 +27,7 @@ requires_connection do
27
27
  pipe2.callback {
28
28
  processed += 1
29
29
  pipe2.response_header.status.should == 200
30
- pipe2.response.should match('biography')
30
+ pipe2.response.should match(/ilya/i)
31
31
  stop.call
32
32
  }
33
33
 
@@ -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
@@ -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
- describe EventMachine::HttpRequest do
7
+ # ssh -D 8080 igvita
8
+ let(:proxy) { {:proxy => { :host => '127.0.0.1', :port => 8080, :type => :socks5 }} }
6
9
 
7
- # ssh -D 8080 igvita
8
- let(:proxy) { {:proxy => { :host => '127.0.0.1', :port => 8080, :type => :socks5 }} }
10
+ it "should use SOCKS5 proxy" do
11
+ EventMachine.run {
12
+ http = EventMachine::HttpRequest.new('http://jsonip.com/', proxy).get
9
13
 
10
- it "should use SOCKS5 proxy" do
11
- EventMachine.run {
12
- http = EventMachine::HttpRequest.new('http://whatismyip.everdot.org/', proxy).get
13
-
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
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
- stable.response.write Zlib::Deflate.deflate("compressed")
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.3
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-03-12 00:00:00 -05:00
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: "0"
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: mongrel
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: *id009
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/http_options.rb
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
@@ -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