em-http-request-samesite 1.1.7

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.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +9 -0
  4. data/.rspec +0 -0
  5. data/.travis.yml +7 -0
  6. data/Changelog.md +68 -0
  7. data/Gemfile +14 -0
  8. data/README.md +63 -0
  9. data/Rakefile +10 -0
  10. data/benchmarks/clients.rb +170 -0
  11. data/benchmarks/em-excon.rb +87 -0
  12. data/benchmarks/em-profile.gif +0 -0
  13. data/benchmarks/em-profile.txt +65 -0
  14. data/benchmarks/server.rb +48 -0
  15. data/em-http-request.gemspec +32 -0
  16. data/examples/.gitignore +1 -0
  17. data/examples/digest_auth/client.rb +25 -0
  18. data/examples/digest_auth/server.rb +28 -0
  19. data/examples/fetch.rb +30 -0
  20. data/examples/fibered-http.rb +51 -0
  21. data/examples/multi.rb +25 -0
  22. data/examples/oauth-tweet.rb +35 -0
  23. data/examples/socks5.rb +23 -0
  24. data/lib/em-http-request.rb +1 -0
  25. data/lib/em-http.rb +20 -0
  26. data/lib/em-http/client.rb +341 -0
  27. data/lib/em-http/core_ext/bytesize.rb +6 -0
  28. data/lib/em-http/decoders.rb +252 -0
  29. data/lib/em-http/http_client_options.rb +49 -0
  30. data/lib/em-http/http_connection.rb +321 -0
  31. data/lib/em-http/http_connection_options.rb +70 -0
  32. data/lib/em-http/http_encoding.rb +149 -0
  33. data/lib/em-http/http_header.rb +83 -0
  34. data/lib/em-http/http_status_codes.rb +57 -0
  35. data/lib/em-http/middleware/digest_auth.rb +112 -0
  36. data/lib/em-http/middleware/json_response.rb +15 -0
  37. data/lib/em-http/middleware/oauth.rb +40 -0
  38. data/lib/em-http/middleware/oauth2.rb +28 -0
  39. data/lib/em-http/multi.rb +57 -0
  40. data/lib/em-http/request.rb +23 -0
  41. data/lib/em-http/version.rb +5 -0
  42. data/lib/em/io_streamer.rb +49 -0
  43. data/spec/client_fiber_spec.rb +23 -0
  44. data/spec/client_spec.rb +1000 -0
  45. data/spec/digest_auth_spec.rb +48 -0
  46. data/spec/dns_spec.rb +41 -0
  47. data/spec/encoding_spec.rb +49 -0
  48. data/spec/external_spec.rb +150 -0
  49. data/spec/fixtures/google.ca +16 -0
  50. data/spec/fixtures/gzip-sample.gz +0 -0
  51. data/spec/gzip_spec.rb +91 -0
  52. data/spec/helper.rb +31 -0
  53. data/spec/http_proxy_spec.rb +268 -0
  54. data/spec/middleware/oauth2_spec.rb +15 -0
  55. data/spec/middleware_spec.rb +143 -0
  56. data/spec/multi_spec.rb +104 -0
  57. data/spec/pipelining_spec.rb +66 -0
  58. data/spec/redirect_spec.rb +430 -0
  59. data/spec/socksify_proxy_spec.rb +60 -0
  60. data/spec/spec_helper.rb +25 -0
  61. data/spec/ssl_spec.rb +71 -0
  62. data/spec/stallion.rb +334 -0
  63. data/spec/stub_server.rb +45 -0
  64. metadata +265 -0
@@ -0,0 +1,15 @@
1
+ describe EventMachine::Middleware::OAuth2 do
2
+ it "should add an access token to a URI with no query parameters" do
3
+ middleware = EventMachine::Middleware::OAuth2.new(:access_token => "fedcba9876543210")
4
+ uri = Addressable::URI.parse("https://graph.facebook.com/me")
5
+ middleware.update_uri! uri
6
+ uri.to_s.should == "https://graph.facebook.com/me?access_token=fedcba9876543210"
7
+ end
8
+
9
+ it "should add an access token to a URI with query parameters" do
10
+ middleware = EventMachine::Middleware::OAuth2.new(:access_token => "fedcba9876543210")
11
+ uri = Addressable::URI.parse("https://graph.facebook.com/me?fields=photo")
12
+ middleware.update_uri! uri
13
+ uri.to_s.should == "https://graph.facebook.com/me?fields=photo&access_token=fedcba9876543210"
14
+ end
15
+ end
@@ -0,0 +1,143 @@
1
+ require 'helper'
2
+
3
+ describe EventMachine::HttpRequest do
4
+
5
+ class EmptyMiddleware; end
6
+
7
+ class GlobalMiddleware
8
+ def response(resp)
9
+ resp.response_header['X-Global'] = 'middleware'
10
+ end
11
+ end
12
+
13
+ it "should accept middleware" do
14
+ EventMachine.run {
15
+ lambda {
16
+ conn = EM::HttpRequest.new('http://127.0.0.1:8090')
17
+ conn.use ResponseMiddleware
18
+ conn.use EmptyMiddleware
19
+
20
+ EM.stop
21
+ }.should_not raise_error
22
+ }
23
+ end
24
+
25
+ context "configuration" do
26
+ class ConfigurableMiddleware
27
+ def initialize(conf, &block)
28
+ @conf = conf
29
+ @block = block
30
+ end
31
+
32
+ def response(resp)
33
+ resp.response_header['X-Conf'] = @conf
34
+ resp.response_header['X-Block'] = @block.call
35
+ end
36
+ end
37
+
38
+ it "should accept middleware initialization parameters" do
39
+ EventMachine.run {
40
+ conn = EM::HttpRequest.new('http://127.0.0.1:8090')
41
+ conn.use ConfigurableMiddleware, 'conf-value' do
42
+ 'block-value'
43
+ end
44
+
45
+ req = conn.get
46
+ req.callback {
47
+ req.response_header['X-Conf'].should match('conf-value')
48
+ req.response_header['X-Block'].should match('block-value')
49
+ EM.stop
50
+ }
51
+ }
52
+ end
53
+ end
54
+
55
+ context "request" do
56
+ class ResponseMiddleware
57
+ def response(resp)
58
+ resp.response_header['X-Header'] = 'middleware'
59
+ resp.response = 'Hello, Middleware!'
60
+ end
61
+ end
62
+
63
+ it "should execute response middleware before user callbacks" do
64
+ EventMachine.run {
65
+ conn = EM::HttpRequest.new('http://127.0.0.1:8090')
66
+ conn.use ResponseMiddleware
67
+
68
+ req = conn.get
69
+ req.callback {
70
+ req.response_header['X-Header'].should match('middleware')
71
+ req.response.should match('Hello, Middleware!')
72
+ EM.stop
73
+ }
74
+ }
75
+ end
76
+
77
+ it "should execute global response middleware before user callbacks" do
78
+ EventMachine.run {
79
+ EM::HttpRequest.use GlobalMiddleware
80
+
81
+ conn = EM::HttpRequest.new('http://127.0.0.1:8090')
82
+
83
+ req = conn.get
84
+ req.callback {
85
+ req.response_header['X-Global'].should match('middleware')
86
+ EM.stop
87
+ }
88
+ }
89
+ end
90
+ end
91
+
92
+ context "request" do
93
+ class RequestMiddleware
94
+ def request(client, head, body)
95
+ head['X-Middleware'] = 'middleware' # insert new header
96
+ body += ' modified' # modify post body
97
+
98
+ [head, body]
99
+ end
100
+ end
101
+
102
+ it "should execute request middleware before dispatching request" do
103
+ EventMachine.run {
104
+ conn = EventMachine::HttpRequest.new('http://127.0.0.1:8090/')
105
+ conn.use RequestMiddleware
106
+
107
+ req = conn.post :body => "data"
108
+ req.callback {
109
+ req.response_header.status.should == 200
110
+ req.response.should match(/data modified/)
111
+ EventMachine.stop
112
+ }
113
+ }
114
+ end
115
+ end
116
+
117
+ context "jsonify" do
118
+ class JSONify
119
+ def request(client, head, body)
120
+ [head, MultiJson.dump(body)]
121
+ end
122
+
123
+ def response(resp)
124
+ resp.response = MultiJson.load(resp.response)
125
+ end
126
+ end
127
+
128
+ it "should use middleware to JSON encode and JSON decode the body" do
129
+ EventMachine.run {
130
+ conn = EventMachine::HttpRequest.new('http://127.0.0.1:8090/')
131
+ conn.use JSONify
132
+
133
+ req = conn.post :body => {:ruby => :hash}
134
+ req.callback {
135
+ req.response_header.status.should == 200
136
+ req.response.should == {"ruby" => "hash"}
137
+ EventMachine.stop
138
+ }
139
+ }
140
+ end
141
+ end
142
+
143
+ end
@@ -0,0 +1,104 @@
1
+ require 'helper'
2
+ require 'stallion'
3
+
4
+ describe EventMachine::MultiRequest do
5
+
6
+ let(:multi) { EventMachine::MultiRequest.new }
7
+ let(:url) { 'http://127.0.0.1:8090/' }
8
+
9
+ it "should submit multiple requests in parallel and return once all of them are complete" do
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
16
+
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
24
+
25
+ EventMachine.stop
26
+ }
27
+ }
28
+ end
29
+
30
+ it "should require unique keys for each deferrable" do
31
+ lambda do
32
+ multi.add :df1, EM::DefaultDeferrable.new
33
+ multi.add :df1, EM::DefaultDeferrable.new
34
+ end.should raise_error("Duplicate Multi key")
35
+ end
36
+
37
+
38
+ describe "#requests" do
39
+ it "should return the added requests" do
40
+ request1 = double('request1', :callback => nil, :errback => nil)
41
+ request2 = double('request2', :callback => nil, :errback => nil)
42
+
43
+ multi.add :a, request1
44
+ multi.add :b, request2
45
+
46
+ multi.requests.should == {:a => request1, :b => request2}
47
+ end
48
+ end
49
+
50
+ describe "#responses" do
51
+ it "should have an empty :callback hash" do
52
+ multi.responses[:callback].should be_a(Hash)
53
+ multi.responses[:callback].size.should == 0
54
+ end
55
+
56
+ it "should have an empty :errback hash" do
57
+ multi.responses[:errback].should be_a(Hash)
58
+ multi.responses[:errback].size.should == 0
59
+ end
60
+
61
+ it "should provide access to the requests by name" do
62
+ EventMachine.run {
63
+ request1 = EventMachine::HttpRequest.new(url).get
64
+ request2 = EventMachine::HttpRequest.new(url).post
65
+ multi.add :a, request1
66
+ multi.add :b, request2
67
+
68
+ multi.callback {
69
+ multi.responses[:callback][:a].should equal(request1)
70
+ multi.responses[:callback][:b].should equal(request2)
71
+
72
+ EventMachine.stop
73
+ }
74
+ }
75
+ end
76
+ end
77
+
78
+ describe "#finished?" do
79
+ it "should be true when no requests have been added" do
80
+ multi.should be_finished
81
+ end
82
+
83
+ it "should be false while the requests are not finished" do
84
+ EventMachine.run {
85
+ multi.add :a, EventMachine::HttpRequest.new(url).get
86
+ multi.should_not be_finished
87
+
88
+ EventMachine.stop
89
+ }
90
+ end
91
+
92
+ it "should be finished when all requests are finished" do
93
+ EventMachine.run {
94
+ multi.add :a, EventMachine::HttpRequest.new(url).get
95
+ multi.callback {
96
+ multi.should be_finished
97
+
98
+ EventMachine.stop
99
+ }
100
+ }
101
+ end
102
+ end
103
+
104
+ end
@@ -0,0 +1,66 @@
1
+ require 'helper'
2
+
3
+ requires_connection do
4
+
5
+ describe EventMachine::HttpRequest do
6
+
7
+ it "should perform successful pipelined GETs" do
8
+ EventMachine.run do
9
+
10
+ # Mongrel doesn't support pipelined requests - bah!
11
+ conn = EventMachine::HttpRequest.new('http://www.bing.com/')
12
+
13
+ pipe1 = conn.get :keepalive => true
14
+ pipe2 = conn.get :path => '/news', :keepalive => true
15
+
16
+ processed = 0
17
+ stop = proc { EM.stop if processed == 2}
18
+
19
+ pipe1.errback { failed(conn) }
20
+ pipe1.callback {
21
+ processed += 1
22
+ pipe1.response_header.status.should == 200
23
+ stop.call
24
+ }
25
+
26
+ pipe2.errback { failed(conn) }
27
+ pipe2.callback {
28
+ processed += 1
29
+ pipe2.response_header.status.should == 200
30
+ pipe2.response.should match(/html/i)
31
+ stop.call
32
+ }
33
+
34
+ end
35
+ end
36
+
37
+ it "should perform successful pipelined HEAD requests" do
38
+ EventMachine.run do
39
+ conn = EventMachine::HttpRequest.new('http://www.bing.com/')
40
+
41
+ pipe1 = conn.head :keepalive => true
42
+ pipe2 = conn.head :path => '/news', :keepalive => true
43
+
44
+ processed = 0
45
+ stop = proc { EM.stop if processed == 2}
46
+
47
+ pipe1.errback { failed(conn) }
48
+ pipe1.callback {
49
+ processed += 1
50
+ pipe1.response_header.status.should == 200
51
+ stop.call
52
+ }
53
+
54
+ pipe2.errback { failed(conn) }
55
+ pipe2.callback {
56
+ processed += 1
57
+ pipe2.response_header.status.should == 200
58
+ stop.call
59
+ }
60
+
61
+ end
62
+
63
+ end
64
+ end
65
+
66
+ end
@@ -0,0 +1,430 @@
1
+ require 'helper'
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].chr == '3'
19
+ # set redirects to 0 to avoid further processing
20
+ r.req.redirects = 0
21
+ end
22
+ end
23
+ end
24
+
25
+ describe EventMachine::HttpRequest do
26
+
27
+ it "should follow location redirects" do
28
+ EventMachine.run {
29
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect').get :redirects => 1
30
+ http.errback { failed(http) }
31
+ http.callback {
32
+ http.response_header.status.should == 200
33
+ http.response_header["CONTENT_ENCODING"].should == "gzip"
34
+ http.response.should == "compressed"
35
+ http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/gzip'
36
+ http.redirects.should == 1
37
+
38
+ EM.stop
39
+ }
40
+ }
41
+ end
42
+
43
+ it "should not follow redirects on created" do
44
+ EventMachine.run {
45
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/created').get :redirects => 1
46
+ http.errback { failed(http) }
47
+ http.callback {
48
+ http.response_header.status.should == 201
49
+ http.response.should match(/Hello/)
50
+ EM.stop
51
+ }
52
+ }
53
+ end
54
+
55
+ it "should not forward cookies across domains with http redirect" do
56
+
57
+ expires = (Date.today + 2).strftime('%a, %d %b %Y %T GMT')
58
+ response =<<-HTTP.gsub(/^ +/, '')
59
+ HTTP/1.1 301 MOVED PERMANENTLY
60
+ Location: http://localhost:8071/
61
+ Set-Cookie: foo=bar; expires=#{expires}; path=/; HttpOnly
62
+
63
+ HTTP
64
+
65
+ EventMachine.run do
66
+ @stub = StubServer.new(:host => '127.0.0.1', :port => 8070, :response => response)
67
+ @echo = StubServer.new(:host => 'localhost', :port => 8071, :echo => true)
68
+
69
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8070/').get :redirects => 1
70
+
71
+ http.errback { failed(http) }
72
+ http.callback do
73
+ http.response.should_not match(/Cookie/)
74
+ @stub.stop
75
+ @echo.stop
76
+ EM.stop
77
+ end
78
+ end
79
+ end
80
+
81
+ it "should forward valid cookies across domains with http redirect" do
82
+
83
+ expires = (Date.today + 2).strftime('%a, %d %b %Y %T GMT')
84
+ response =<<-HTTP.gsub(/^ +/, '')
85
+ HTTP/1.1 301 MOVED PERMANENTLY
86
+ Location: http://127.0.0.1:8071/
87
+ Set-Cookie: foo=bar; expires=#{expires}; path=/; HttpOnly
88
+
89
+ HTTP
90
+
91
+ EventMachine.run do
92
+ @stub = StubServer.new(:host => '127.0.0.1', :port => 8070, :response => response)
93
+ @echo = StubServer.new(:host => '127.0.0.1', :port => 8071, :echo => true)
94
+
95
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8070/').get :redirects => 1
96
+
97
+ http.errback { failed(http) }
98
+ http.callback do
99
+ http.response.should match(/Cookie/)
100
+ @stub.stop
101
+ @echo.stop
102
+ EM.stop
103
+ end
104
+ end
105
+ end
106
+
107
+
108
+ it "should normalize path and forward valid cookies across domains" do
109
+
110
+ expires = (Date.today + 2).strftime('%a, %d %b %Y %T GMT')
111
+ response =<<-HTTP.gsub(/^ +/, '')
112
+ HTTP/1.1 301 MOVED PERMANENTLY
113
+ Location: http://127.0.0.1:8071?omg=ponies
114
+ Set-Cookie: foo=bar; expires=#{expires}; path=/; HttpOnly
115
+
116
+ HTTP
117
+
118
+ EventMachine.run do
119
+ @stub = StubServer.new(:host => '127.0.0.1', :port => 8070, :response => response)
120
+ @echo = StubServer.new(:host => '127.0.0.1', :port => 8071, :echo => true)
121
+
122
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8070/').get :redirects => 1
123
+
124
+ http.errback { failed(http) }
125
+ http.callback do
126
+ http.response.should match(/Cookie/)
127
+ @stub.stop
128
+ @echo.stop
129
+ EM.stop
130
+ end
131
+ end
132
+ end
133
+
134
+ it "should redirect with missing content-length" do
135
+ EventMachine.run {
136
+ response = "HTTP/1.0 301 MOVED PERMANENTLY\r\nlocation: http://127.0.0.1:8090/redirect\r\n\r\n"
137
+ @stub = StubServer.new(:host => '127.0.0.1', :port => 8070, :response => response)
138
+
139
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8070/').get :redirects => 3
140
+ http.errback { failed(http) }
141
+
142
+ http.callback {
143
+ http.response_header.status.should == 200
144
+ http.response_header["CONTENT_ENCODING"].should == "gzip"
145
+ http.response.should == "compressed"
146
+ http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/gzip'
147
+ http.redirects.should == 3
148
+
149
+ @stub.stop
150
+ EM.stop
151
+ }
152
+ }
153
+ end
154
+
155
+ it "should follow redirects on HEAD method" do
156
+ EventMachine.run {
157
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/head').head :redirects => 1
158
+ http.errback { failed(http) }
159
+ http.callback {
160
+ http.response_header.status.should == 200
161
+ http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/'
162
+ EM.stop
163
+ }
164
+ }
165
+ end
166
+
167
+ it "should report last_effective_url" do
168
+ EventMachine.run {
169
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/').get
170
+ http.errback { failed(http) }
171
+ http.callback {
172
+ http.response_header.status.should == 200
173
+ http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/'
174
+
175
+ EM.stop
176
+ }
177
+ }
178
+ end
179
+
180
+ it "should default to 0 redirects" do
181
+ EventMachine.run {
182
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect').get
183
+ http.errback { failed(http) }
184
+ http.callback {
185
+ http.response_header.status.should == 301
186
+ http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/redirect'
187
+ http.redirects.should == 0
188
+
189
+ EM.stop
190
+ }
191
+ }
192
+ end
193
+
194
+ it "should not invoke redirect logic on failed(http) connections" do
195
+ EventMachine.run {
196
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8070/', :connect_timeout => 0.1).get :redirects => 5
197
+ http.callback { failed(http) }
198
+ http.errback {
199
+ http.redirects.should == 0
200
+ EM.stop
201
+ }
202
+ }
203
+ end
204
+
205
+ it "should normalize redirect urls" do
206
+ EventMachine.run {
207
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/bad').get :redirects => 1
208
+ http.errback { failed(http) }
209
+ http.callback {
210
+ http.last_effective_url.to_s.should match('http://127.0.0.1:8090/')
211
+ http.response.should match('Hello, World!')
212
+ EM.stop
213
+ }
214
+ }
215
+ end
216
+
217
+ it "should fail gracefully on a missing host in absolute Location header" do
218
+ EventMachine.run {
219
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/nohost').get :redirects => 1
220
+ http.callback { failed(http) }
221
+ http.errback {
222
+ http.error.should == 'Location header format error'
223
+ EM.stop
224
+ }
225
+ }
226
+ end
227
+
228
+ it "should apply timeout settings on redirects" do
229
+ EventMachine.run {
230
+ t = Time.now.to_i
231
+ EventMachine.heartbeat_interval = 0.1
232
+
233
+ conn = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/timeout', :inactivity_timeout => 0.1)
234
+ http = conn.get :redirects => 1
235
+ http.callback { failed(http) }
236
+ http.errback {
237
+ (Time.now.to_i - t).should <= 1
238
+ EM.stop
239
+ }
240
+ }
241
+ end
242
+
243
+ it "should capture and pass cookies on redirect and pass_cookies by default" do
244
+ EventMachine.run {
245
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/multiple-with-cookie').get :redirects => 2, :head => {'cookie' => 'id=2;'}
246
+ http.errback { failed(http) }
247
+ http.callback {
248
+ http.response_header.status.should == 200
249
+ http.response_header["CONTENT_ENCODING"].should == "gzip"
250
+ http.response.should == "compressed"
251
+ http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/gzip'
252
+ http.redirects.should == 2
253
+ http.cookies.should include("id=2;")
254
+ http.cookies.should include("another_id=1")
255
+
256
+ EM.stop
257
+ }
258
+ }
259
+ end
260
+
261
+ it "should capture and not pass cookies on redirect if passing is disabled via pass_cookies" do
262
+ EventMachine.run {
263
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/multiple-with-cookie').get :redirects => 2, :pass_cookies => false, :head => {'cookie' => 'id=2;'}
264
+ http.errback { failed(http) }
265
+ http.callback {
266
+ http.response_header.status.should == 200
267
+ http.response_header["CONTENT_ENCODING"].should == "gzip"
268
+ http.response.should == "compressed"
269
+ http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/gzip'
270
+ http.redirects.should == 2
271
+ http.cookies.should include("id=2;")
272
+ http.cookies.should_not include("another_id=1; expires=Sat, 09 Aug 2031 17:53:39 GMT; path=/;")
273
+
274
+ EM.stop
275
+ }
276
+ }
277
+ end
278
+
279
+ it "should follow location redirects with path" do
280
+ EventMachine.run {
281
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect').get :path => '/redirect', :redirects => 1
282
+ http.errback { failed(http) }
283
+ http.callback {
284
+ http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/gzip'
285
+ http.response_header.status.should == 200
286
+ http.redirects.should == 1
287
+
288
+ EM.stop
289
+ }
290
+ }
291
+ end
292
+
293
+ it "should call middleware each time it redirects" do
294
+ EventMachine.run {
295
+ conn = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/middleware_redirects_1')
296
+ conn.use RedirectMiddleware
297
+ http = conn.get :redirects => 3
298
+ http.errback { failed(http) }
299
+ http.callback {
300
+ http.response_header.status.should == 200
301
+ http.response_header['EM_MIDDLEWARE'].to_i.should == 3
302
+ EM.stop
303
+ }
304
+ }
305
+ end
306
+
307
+ it "should call middleware which may reject a redirection" do
308
+ EventMachine.run {
309
+ conn = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/middleware_redirects_1')
310
+ conn.use PickyRedirectMiddleware
311
+ http = conn.get :redirects => 3
312
+ http.errback { failed(http) }
313
+ http.callback {
314
+ http.response_header.status.should == 301
315
+ http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/redirect/middleware_redirects_2'
316
+ EM.stop
317
+ }
318
+ }
319
+ end
320
+
321
+ it "should not add default http port to redirect url that don't include it" do
322
+ EventMachine.run {
323
+ conn = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/http_no_port')
324
+ http = conn.get :redirects => 1
325
+ http.errback {
326
+ http.last_effective_url.to_s.should == 'http://host/'
327
+ EM.stop
328
+ }
329
+ }
330
+ end
331
+
332
+ it "should not add default https port to redirect url that don't include it" do
333
+ EventMachine.run {
334
+ conn = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/https_no_port')
335
+ http = conn.get :redirects => 1
336
+ http.errback {
337
+ http.last_effective_url.to_s.should == 'https://host/'
338
+ EM.stop
339
+ }
340
+ }
341
+ end
342
+
343
+ it "should keep default http port in redirect url that include it" do
344
+ EventMachine.run {
345
+ conn = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/http_with_port')
346
+ http = conn.get :redirects => 1
347
+ http.errback {
348
+ http.last_effective_url.to_s.should == 'http://host:80/'
349
+ EM.stop
350
+ }
351
+ }
352
+ end
353
+
354
+ it "should keep default https port in redirect url that include it" do
355
+ EventMachine.run {
356
+ conn = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/https_with_port')
357
+ http = conn.get :redirects => 1
358
+ http.errback {
359
+ http.last_effective_url.to_s.should == 'https://host:443/'
360
+ EM.stop
361
+ }
362
+ }
363
+ end
364
+
365
+ it "should ignore query option when redirecting" do
366
+ EventMachine.run {
367
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/ignore_query_option').get :redirects => 1, :query => 'ignore=1'
368
+ http.errback { failed(http) }
369
+ http.callback {
370
+ http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/redirect/url'
371
+ http.redirects.should == 1
372
+
373
+ redirect_url = http.response
374
+ redirect_url.should == http.last_effective_url.to_s
375
+
376
+ EM.stop
377
+ }
378
+ }
379
+ end
380
+
381
+ it "should work with keep-alive connections with cross-origin redirect" do
382
+ Timeout.timeout(1) {
383
+ EventMachine.run {
384
+ response =<<-HTTP.gsub(/^ +/, '')
385
+ HTTP/1.1 301 MOVED PERMANENTLY
386
+ Location: http://127.0.0.1:8090/
387
+ Content-Length: 0
388
+
389
+ HTTP
390
+
391
+ stub_server = StubServer.new(:host => '127.0.0.1', :port => 8070, :keepalive => true, :response => response)
392
+ conn = EventMachine::HttpRequest.new('http://127.0.0.1:8070/', :inactivity_timeout => 60)
393
+ http = conn.get :redirects => 1, :keepalive => true
394
+ http.errback { failed(http) }
395
+ http.callback {
396
+ http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/'
397
+ http.redirects.should == 1
398
+
399
+ stub_server.stop
400
+ EM.stop
401
+ }
402
+ }
403
+ }
404
+ end
405
+
406
+ it "should work with keep-alive connections with same-origin redirect" do
407
+ Timeout.timeout(1) {
408
+ EventMachine.run {
409
+ response =<<-HTTP.gsub(/^ +/, '')
410
+ HTTP/1.1 301 MOVED PERMANENTLY
411
+ Location: http://127.0.0.1:8070/
412
+ Content-Length: 0
413
+
414
+ HTTP
415
+
416
+ stub_server = StubServer.new(:host => '127.0.0.1', :port => 8070, :keepalive => true, :response => response)
417
+ conn = EventMachine::HttpRequest.new('http://127.0.0.1:8070/', :inactivity_timeout => 60)
418
+ http = conn.get :redirects => 1, :keepalive => true
419
+ http.errback { failed(http) }
420
+ http.callback {
421
+ http.last_effective_url.to_s.should == 'http://127.0.0.1:8070/'
422
+ http.redirects.should == 1
423
+
424
+ stub_server.stop
425
+ EM.stop
426
+ }
427
+ }
428
+ }
429
+ end
430
+ end