rack 0.4.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- data/RDOX +61 -3
- data/README +52 -37
- data/Rakefile +9 -0
- data/SPEC +6 -3
- data/bin/rackup +0 -0
- data/lib/rack.rb +7 -2
- data/lib/rack/adapter/camping.rb +1 -1
- data/lib/rack/auth/openid.rb +4 -3
- data/lib/rack/builder.rb +12 -1
- data/lib/rack/conditionalget.rb +43 -0
- data/lib/rack/content_length.rb +25 -0
- data/lib/rack/deflater.rb +29 -5
- data/lib/rack/directory.rb +82 -91
- data/lib/rack/file.rb +45 -76
- data/lib/rack/handler.rb +4 -0
- data/lib/rack/handler/evented_mongrel.rb +1 -1
- data/lib/rack/handler/fastcgi.rb +2 -0
- data/lib/rack/handler/mongrel.rb +6 -2
- data/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
- data/lib/rack/handler/thin.rb +15 -0
- data/lib/rack/handler/webrick.rb +8 -4
- data/lib/rack/head.rb +19 -0
- data/lib/rack/lint.rb +74 -10
- data/lib/rack/lobster.rb +13 -13
- data/lib/rack/methodoverride.rb +27 -0
- data/lib/rack/mime.rb +204 -0
- data/lib/rack/request.rb +10 -1
- data/lib/rack/response.rb +7 -2
- data/lib/rack/session/abstract/id.rb +14 -1
- data/lib/rack/session/cookie.rb +19 -1
- data/lib/rack/session/memcache.rb +1 -1
- data/lib/rack/session/pool.rb +1 -1
- data/lib/rack/showexceptions.rb +5 -1
- data/lib/rack/showstatus.rb +3 -2
- data/lib/rack/urlmap.rb +1 -1
- data/lib/rack/utils.rb +42 -13
- data/test/cgi/lighttpd.conf +1 -1
- data/test/cgi/test +0 -0
- data/test/cgi/test.fcgi +0 -0
- data/test/cgi/test.ru +0 -0
- data/test/spec_rack_builder.rb +34 -0
- data/test/spec_rack_conditionalget.rb +41 -0
- data/test/spec_rack_content_length.rb +43 -0
- data/test/spec_rack_deflater.rb +49 -14
- data/test/spec_rack_file.rb +7 -0
- data/test/spec_rack_handler.rb +3 -3
- data/test/spec_rack_head.rb +30 -0
- data/test/spec_rack_lint.rb +79 -2
- data/test/spec_rack_methodoverride.rb +60 -0
- data/test/spec_rack_mock.rb +1 -1
- data/test/spec_rack_mongrel.rb +20 -1
- data/test/spec_rack_request.rb +46 -1
- data/test/spec_rack_response.rb +10 -3
- data/test/spec_rack_session_cookie.rb +33 -0
- data/test/spec_rack_thin.rb +90 -0
- data/test/spec_rack_utils.rb +20 -18
- data/test/spec_rack_webrick.rb +17 -0
- data/test/testrequest.rb +12 -0
- metadata +91 -5
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rack/mock'
|
2
|
+
require 'rack/content_length'
|
3
|
+
|
4
|
+
context "Rack::ContentLength" do
|
5
|
+
specify "sets Content-Length on String bodies if none is set" do
|
6
|
+
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
7
|
+
response = Rack::ContentLength.new(app).call({})
|
8
|
+
response[1]['Content-Length'].should.equal '13'
|
9
|
+
end
|
10
|
+
|
11
|
+
specify "sets Content-Length on Array bodies if none is set" do
|
12
|
+
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
|
13
|
+
response = Rack::ContentLength.new(app).call({})
|
14
|
+
response[1]['Content-Length'].should.equal '13'
|
15
|
+
end
|
16
|
+
|
17
|
+
specify "does not set Content-Length on variable length bodies" do
|
18
|
+
body = lambda { "Hello World!" }
|
19
|
+
def body.each ; yield call ; end
|
20
|
+
|
21
|
+
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
|
22
|
+
response = Rack::ContentLength.new(app).call({})
|
23
|
+
response[1]['Content-Length'].should.be.nil
|
24
|
+
end
|
25
|
+
|
26
|
+
specify "does not change Content-Length if it is already set" do
|
27
|
+
app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Content-Length' => '1'}, "Hello, World!"] }
|
28
|
+
response = Rack::ContentLength.new(app).call({})
|
29
|
+
response[1]['Content-Length'].should.equal '1'
|
30
|
+
end
|
31
|
+
|
32
|
+
specify "does not set Content-Length on 304 responses" do
|
33
|
+
app = lambda { |env| [304, {'Content-Type' => 'text/plain'}, []] }
|
34
|
+
response = Rack::ContentLength.new(app).call({})
|
35
|
+
response[1]['Content-Length'].should.equal nil
|
36
|
+
end
|
37
|
+
|
38
|
+
specify "does not set Content-Length when Transfer-Encoding is chunked" do
|
39
|
+
app = lambda { |env| [200, {'Transfer-Encoding' => 'chunked'}, []] }
|
40
|
+
response = Rack::ContentLength.new(app).call({})
|
41
|
+
response[1]['Content-Length'].should.equal nil
|
42
|
+
end
|
43
|
+
end
|
data/test/spec_rack_deflater.rb
CHANGED
@@ -3,10 +3,11 @@ require 'test/spec'
|
|
3
3
|
require 'rack/mock'
|
4
4
|
require 'rack/deflater'
|
5
5
|
require 'stringio'
|
6
|
+
require 'time' # for Time#httpdate
|
6
7
|
|
7
8
|
context "Rack::Deflater" do
|
8
|
-
def build_response(body, accept_encoding, headers = {})
|
9
|
-
app = lambda { |env| [
|
9
|
+
def build_response(status, body, accept_encoding, headers = {})
|
10
|
+
app = lambda { |env| [status, {}, body] }
|
10
11
|
request = Rack::MockRequest.env_for("", headers.merge("HTTP_ACCEPT_ENCODING" => accept_encoding))
|
11
12
|
response = Rack::Deflater.new(app).call(request)
|
12
13
|
|
@@ -17,19 +18,19 @@ context "Rack::Deflater" do
|
|
17
18
|
body = Object.new
|
18
19
|
class << body; def each; yield("foo"); yield("bar"); end; end
|
19
20
|
|
20
|
-
response = build_response(body, "deflate")
|
21
|
+
response = build_response(200, body, "deflate")
|
21
22
|
|
22
23
|
response[0].should.equal(200)
|
23
|
-
response[1].should.equal({ "Content-Encoding" => "deflate" })
|
24
|
+
response[1].should.equal({ "Content-Encoding" => "deflate", "Vary" => "Accept-Encoding" })
|
24
25
|
response[2].to_s.should.equal("K\313\317OJ,\002\000")
|
25
26
|
end
|
26
27
|
|
27
28
|
# TODO: This is really just a special case of the above...
|
28
29
|
specify "should be able to deflate String bodies" do
|
29
|
-
response = build_response("Hello world!", "deflate")
|
30
|
+
response = build_response(200, "Hello world!", "deflate")
|
30
31
|
|
31
32
|
response[0].should.equal(200)
|
32
|
-
response[1].should.equal({ "Content-Encoding" => "deflate" })
|
33
|
+
response[1].should.equal({ "Content-Encoding" => "deflate", "Vary" => "Accept-Encoding" })
|
33
34
|
response[2].to_s.should.equal("\363H\315\311\311W(\317/\312IQ\004\000")
|
34
35
|
end
|
35
36
|
|
@@ -37,10 +38,10 @@ context "Rack::Deflater" do
|
|
37
38
|
body = Object.new
|
38
39
|
class << body; def each; yield("foo"); yield("bar"); end; end
|
39
40
|
|
40
|
-
response = build_response(body, "gzip")
|
41
|
+
response = build_response(200, body, "gzip")
|
41
42
|
|
42
43
|
response[0].should.equal(200)
|
43
|
-
response[1].should.equal({ "Content-Encoding" => "gzip" })
|
44
|
+
response[1].should.equal({ "Content-Encoding" => "gzip", "Vary" => "Accept-Encoding" })
|
44
45
|
|
45
46
|
io = StringIO.new(response[2].to_s)
|
46
47
|
gz = Zlib::GzipReader.new(io)
|
@@ -49,22 +50,56 @@ context "Rack::Deflater" do
|
|
49
50
|
end
|
50
51
|
|
51
52
|
specify "should be able to fallback to no deflation" do
|
52
|
-
response = build_response("Hello world!", "superzip")
|
53
|
+
response = build_response(200, "Hello world!", "superzip")
|
53
54
|
|
54
55
|
response[0].should.equal(200)
|
55
|
-
response[1].should.equal({})
|
56
|
+
response[1].should.equal({ "Vary" => "Accept-Encoding" })
|
56
57
|
response[2].should.equal("Hello world!")
|
57
58
|
end
|
58
59
|
|
60
|
+
specify "should be able to skip when there is no response entity body" do
|
61
|
+
response = build_response(304, [], "gzip")
|
62
|
+
|
63
|
+
response[0].should.equal(304)
|
64
|
+
response[1].should.equal({})
|
65
|
+
response[2].should.equal([])
|
66
|
+
end
|
67
|
+
|
59
68
|
specify "should handle the lack of an acceptable encoding" do
|
60
|
-
response1 = build_response("Hello world!", "identity;q=0", "PATH_INFO" => "/")
|
69
|
+
response1 = build_response(200, "Hello world!", "identity;q=0", "PATH_INFO" => "/")
|
61
70
|
response1[0].should.equal(406)
|
62
71
|
response1[1].should.equal({"Content-Type" => "text/plain"})
|
63
|
-
response1[2].should.equal("An acceptable encoding for the requested resource / could not be found.")
|
72
|
+
response1[2].should.equal(["An acceptable encoding for the requested resource / could not be found."])
|
64
73
|
|
65
|
-
response2 = build_response("Hello world!", "identity;q=0", "SCRIPT_NAME" => "/foo", "PATH_INFO" => "/bar")
|
74
|
+
response2 = build_response(200, "Hello world!", "identity;q=0", "SCRIPT_NAME" => "/foo", "PATH_INFO" => "/bar")
|
66
75
|
response2[0].should.equal(406)
|
67
76
|
response2[1].should.equal({"Content-Type" => "text/plain"})
|
68
|
-
response2[2].should.equal("An acceptable encoding for the requested resource /foo/bar could not be found.")
|
77
|
+
response2[2].should.equal(["An acceptable encoding for the requested resource /foo/bar could not be found."])
|
78
|
+
end
|
79
|
+
|
80
|
+
specify "should handle gzip response with Last-Modified header" do
|
81
|
+
last_modified = Time.now.httpdate
|
82
|
+
|
83
|
+
app = lambda { |env| [200, { "Last-Modified" => last_modified }, "Hello World!"] }
|
84
|
+
request = Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => "gzip")
|
85
|
+
response = Rack::Deflater.new(app).call(request)
|
86
|
+
|
87
|
+
response[0].should.equal(200)
|
88
|
+
response[1].should.equal({ "Content-Encoding" => "gzip", "Vary" => "Accept-Encoding", "Last-Modified" => last_modified })
|
89
|
+
|
90
|
+
io = StringIO.new(response[2].to_s)
|
91
|
+
gz = Zlib::GzipReader.new(io)
|
92
|
+
gz.read.should.equal("Hello World!")
|
93
|
+
gz.close
|
94
|
+
end
|
95
|
+
|
96
|
+
specify "should do nothing when no-transform Cache-Control directive present" do
|
97
|
+
app = lambda { |env| [200, {'Cache-Control' => 'no-transform'}, ['Hello World!']] }
|
98
|
+
request = Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => "gzip")
|
99
|
+
response = Rack::Deflater.new(app).call(request)
|
100
|
+
|
101
|
+
response[0].should.equal(200)
|
102
|
+
response[1].should.not.include "Content-Encoding"
|
103
|
+
response[2].join.should.equal("Hello World!")
|
69
104
|
end
|
70
105
|
end
|
data/test/spec_rack_file.rb
CHANGED
data/test/spec_rack_handler.rb
CHANGED
@@ -2,10 +2,10 @@ require 'test/spec'
|
|
2
2
|
|
3
3
|
require 'rack/handler'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
class RockLobster; end
|
5
|
+
class Rack::Handler::Lobster; end
|
6
|
+
class RockLobster; end
|
8
7
|
|
8
|
+
context "Rack::Handler" do
|
9
9
|
specify "has registered default handlers" do
|
10
10
|
Rack::Handler.get('cgi').should.equal Rack::Handler::CGI
|
11
11
|
Rack::Handler.get('fastcgi').should.equal Rack::Handler::FastCGI
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rack/head'
|
2
|
+
require 'rack/mock'
|
3
|
+
|
4
|
+
context "Rack::Head" do
|
5
|
+
def test_response(headers = {})
|
6
|
+
app = lambda { |env| [200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]] }
|
7
|
+
request = Rack::MockRequest.env_for("/", headers)
|
8
|
+
response = Rack::Head.new(app).call(request)
|
9
|
+
|
10
|
+
return response
|
11
|
+
end
|
12
|
+
|
13
|
+
specify "passes GET, POST, PUT, DELETE, OPTIONS, TRACE requests" do
|
14
|
+
%w[GET POST PUT DELETE OPTIONS TRACE].each do |type|
|
15
|
+
resp = test_response("REQUEST_METHOD" => type)
|
16
|
+
|
17
|
+
resp[0].should.equal(200)
|
18
|
+
resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"})
|
19
|
+
resp[2].should.equal(["foo"])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
specify "removes body from HEAD requests" do
|
24
|
+
resp = test_response("REQUEST_METHOD" => "HEAD")
|
25
|
+
|
26
|
+
resp[0].should.equal(200)
|
27
|
+
resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"})
|
28
|
+
resp[2].should.equal([])
|
29
|
+
end
|
30
|
+
end
|
data/test/spec_rack_lint.rb
CHANGED
@@ -67,9 +67,9 @@ context "Rack::Lint" do
|
|
67
67
|
message.should.match(/url_scheme unknown/)
|
68
68
|
|
69
69
|
lambda {
|
70
|
-
Rack::Lint.new(nil).call(env("REQUEST_METHOD" => "FUCKUP"))
|
70
|
+
Rack::Lint.new(nil).call(env("REQUEST_METHOD" => "FUCKUP?"))
|
71
71
|
}.should.raise(Rack::Lint::LintError).
|
72
|
-
message.should.match(/REQUEST_METHOD
|
72
|
+
message.should.match(/REQUEST_METHOD/)
|
73
73
|
|
74
74
|
lambda {
|
75
75
|
Rack::Lint.new(nil).call(env("SCRIPT_NAME" => "howdy"))
|
@@ -203,6 +203,47 @@ context "Rack::Lint" do
|
|
203
203
|
}).call(env({}))
|
204
204
|
}.should.raise(Rack::Lint::LintError).
|
205
205
|
message.should.match(/No Content-Type/)
|
206
|
+
|
207
|
+
[100, 101, 204, 304].each do |status|
|
208
|
+
lambda {
|
209
|
+
Rack::Lint.new(lambda { |env|
|
210
|
+
[status, {"Content-type" => "text/plain", "Content-length" => "0"}, ""]
|
211
|
+
}).call(env({}))
|
212
|
+
}.should.raise(Rack::Lint::LintError).
|
213
|
+
message.should.match(/Content-Type header found/)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
specify "notices content-length errors" do
|
218
|
+
lambda {
|
219
|
+
Rack::Lint.new(lambda { |env|
|
220
|
+
[200, {"Content-type" => "text/plain"}, ""]
|
221
|
+
}).call(env({}))
|
222
|
+
}.should.raise(Rack::Lint::LintError).
|
223
|
+
message.should.match(/No Content-Length/)
|
224
|
+
|
225
|
+
[100, 101, 204, 304].each do |status|
|
226
|
+
lambda {
|
227
|
+
Rack::Lint.new(lambda { |env|
|
228
|
+
[status, {"Content-length" => "0"}, ""]
|
229
|
+
}).call(env({}))
|
230
|
+
}.should.raise(Rack::Lint::LintError).
|
231
|
+
message.should.match(/Content-Length header found/)
|
232
|
+
end
|
233
|
+
|
234
|
+
lambda {
|
235
|
+
Rack::Lint.new(lambda { |env|
|
236
|
+
[200, {"Content-type" => "text/plain", "Content-Length" => "0", "Transfer-Encoding" => "chunked"}, ""]
|
237
|
+
}).call(env({}))
|
238
|
+
}.should.raise(Rack::Lint::LintError).
|
239
|
+
message.should.match(/Content-Length header should not be used/)
|
240
|
+
|
241
|
+
lambda {
|
242
|
+
Rack::Lint.new(lambda { |env|
|
243
|
+
[200, {"Content-type" => "text/plain", "Content-Length" => "1"}, ""]
|
244
|
+
}).call(env({}))
|
245
|
+
}.should.raise(Rack::Lint::LintError).
|
246
|
+
message.should.match(/Content-Length header was 1, but should be 0/)
|
206
247
|
end
|
207
248
|
|
208
249
|
specify "notices body errors" do
|
@@ -300,4 +341,40 @@ context "Rack::Lint" do
|
|
300
341
|
message.should.match(/close must not be called/)
|
301
342
|
end
|
302
343
|
|
344
|
+
specify "notices HEAD errors" do
|
345
|
+
lambda {
|
346
|
+
Rack::Lint.new(lambda { |env|
|
347
|
+
[200, {"Content-type" => "test/plain", "Content-length" => "3"}, []]
|
348
|
+
}).call(env({"REQUEST_METHOD" => "HEAD"}))
|
349
|
+
}.should.not.raise
|
350
|
+
|
351
|
+
lambda {
|
352
|
+
Rack::Lint.new(lambda { |env|
|
353
|
+
[200, {"Content-type" => "test/plain", "Content-length" => "3"}, "foo"]
|
354
|
+
}).call(env({"REQUEST_METHOD" => "HEAD"}))
|
355
|
+
}.should.raise(Rack::Lint::LintError).
|
356
|
+
message.should.match(/body was given for HEAD/)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
context "Rack::Lint::InputWrapper" do
|
361
|
+
specify "delegates :size to underlying IO object" do
|
362
|
+
class IOMock
|
363
|
+
def size
|
364
|
+
101
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
wrapper = Rack::Lint::InputWrapper.new(IOMock.new)
|
369
|
+
wrapper.size.should == 101
|
370
|
+
end
|
371
|
+
|
372
|
+
specify "delegates :rewind to underlying IO object" do
|
373
|
+
io = StringIO.new("123")
|
374
|
+
wrapper = Rack::Lint::InputWrapper.new(io)
|
375
|
+
wrapper.read.should == "123"
|
376
|
+
wrapper.read.should == ""
|
377
|
+
wrapper.rewind
|
378
|
+
wrapper.read.should == "123"
|
379
|
+
end
|
303
380
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'test/spec'
|
2
|
+
|
3
|
+
require 'rack/mock'
|
4
|
+
require 'rack/methodoverride'
|
5
|
+
require 'stringio'
|
6
|
+
|
7
|
+
context "Rack::MethodOverride" do
|
8
|
+
specify "should not affect GET requests" do
|
9
|
+
env = Rack::MockRequest.env_for("/?_method=delete", :method => "GET")
|
10
|
+
app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) })
|
11
|
+
req = app.call(env)
|
12
|
+
|
13
|
+
req.env["REQUEST_METHOD"].should.equal "GET"
|
14
|
+
end
|
15
|
+
|
16
|
+
specify "_method parameter should modify REQUEST_METHOD for POST requests" do
|
17
|
+
env = Rack::MockRequest.env_for("/", :method => "POST", :input => "_method=put")
|
18
|
+
app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) })
|
19
|
+
req = app.call(env)
|
20
|
+
|
21
|
+
req.env["REQUEST_METHOD"].should.equal "PUT"
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "X-HTTP-Method-Override header should modify REQUEST_METHOD for POST requests" do
|
25
|
+
env = Rack::MockRequest.env_for("/",
|
26
|
+
:method => "POST",
|
27
|
+
"HTTP_X_HTTP_METHOD_OVERRIDE" => "PUT"
|
28
|
+
)
|
29
|
+
app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) })
|
30
|
+
req = app.call(env)
|
31
|
+
|
32
|
+
req.env["REQUEST_METHOD"].should.equal "PUT"
|
33
|
+
end
|
34
|
+
|
35
|
+
specify "should not modify REQUEST_METHOD if the method is unknown" do
|
36
|
+
env = Rack::MockRequest.env_for("/", :method => "POST", :input => "_method=foo")
|
37
|
+
app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) })
|
38
|
+
req = app.call(env)
|
39
|
+
|
40
|
+
req.env["REQUEST_METHOD"].should.equal "POST"
|
41
|
+
end
|
42
|
+
|
43
|
+
specify "should not modify REQUEST_METHOD when _method is nil" do
|
44
|
+
env = Rack::MockRequest.env_for("/", :method => "POST", :input => "foo=bar")
|
45
|
+
app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) })
|
46
|
+
req = app.call(env)
|
47
|
+
|
48
|
+
req.env["REQUEST_METHOD"].should.equal "POST"
|
49
|
+
end
|
50
|
+
|
51
|
+
specify "should store the original REQUEST_METHOD prior to overriding" do
|
52
|
+
env = Rack::MockRequest.env_for("/",
|
53
|
+
:method => "POST",
|
54
|
+
:input => "_method=options")
|
55
|
+
app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) })
|
56
|
+
req = app.call(env)
|
57
|
+
|
58
|
+
req.env["rack.methodoverride.original_method"].should.equal "POST"
|
59
|
+
end
|
60
|
+
end
|
data/test/spec_rack_mock.rb
CHANGED
@@ -125,7 +125,7 @@ context "Rack::MockResponse" do
|
|
125
125
|
res.original_headers["Content-Type"].should.equal "text/yaml"
|
126
126
|
res["Content-Type"].should.equal "text/yaml"
|
127
127
|
res.content_type.should.equal "text/yaml"
|
128
|
-
res.content_length.should.be.
|
128
|
+
res.content_length.should.be 381 # needs change often.
|
129
129
|
res.location.should.be.nil
|
130
130
|
end
|
131
131
|
|
data/test/spec_rack_mongrel.rb
CHANGED
@@ -5,7 +5,8 @@ require 'rack/handler/mongrel'
|
|
5
5
|
require 'rack/urlmap'
|
6
6
|
require 'rack/lint'
|
7
7
|
require 'testrequest'
|
8
|
-
|
8
|
+
require 'timeout'
|
9
|
+
|
9
10
|
Thread.abort_on_exception = true
|
10
11
|
$tcp_defer_accept_opts = nil
|
11
12
|
$tcp_cork_opts = nil
|
@@ -17,6 +18,8 @@ context "Rack::Handler::Mongrel" do
|
|
17
18
|
server = Mongrel::HttpServer.new(@host='0.0.0.0', @port=9201)
|
18
19
|
server.register('/test',
|
19
20
|
Rack::Handler::Mongrel.new(Rack::Lint.new(TestRequest.new)))
|
21
|
+
server.register('/stream',
|
22
|
+
Rack::Handler::Mongrel.new(Rack::Lint.new(StreamingRequest)))
|
20
23
|
@acc = server.run
|
21
24
|
end
|
22
25
|
|
@@ -160,6 +163,22 @@ context "Rack::Handler::Mongrel" do
|
|
160
163
|
block_ran.should.be true
|
161
164
|
end
|
162
165
|
|
166
|
+
specify "should stream #each part of the response" do
|
167
|
+
body = ''
|
168
|
+
begin
|
169
|
+
Timeout.timeout(1) do
|
170
|
+
Net::HTTP.start(@host, @port) do |http|
|
171
|
+
get = Net::HTTP::Get.new('/stream')
|
172
|
+
http.request(get) do |response|
|
173
|
+
response.read_body { |part| body << part }
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
rescue Timeout::Error
|
178
|
+
end
|
179
|
+
body.should.not.be.empty
|
180
|
+
end
|
181
|
+
|
163
182
|
teardown do
|
164
183
|
@acc.raise Mongrel::StopServer
|
165
184
|
end
|
data/test/spec_rack_request.rb
CHANGED
@@ -83,6 +83,26 @@ context "Rack::Request" do
|
|
83
83
|
req.body.read.should.equal "foo=bar&quux=bla"
|
84
84
|
end
|
85
85
|
|
86
|
+
specify "rewinds input after parsing POST data" do
|
87
|
+
input = StringIO.new("foo=bar&quux=bla")
|
88
|
+
req = Rack::Request.new \
|
89
|
+
Rack::MockRequest.env_for("/",
|
90
|
+
"CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
|
91
|
+
:input => input)
|
92
|
+
req.params.should.equal "foo" => "bar", "quux" => "bla"
|
93
|
+
input.read.should.equal "foo=bar&quux=bla"
|
94
|
+
end
|
95
|
+
|
96
|
+
specify "does not rewind unwindable CGI input" do
|
97
|
+
input = StringIO.new("foo=bar&quux=bla")
|
98
|
+
input.instance_eval "undef :rewind"
|
99
|
+
req = Rack::Request.new \
|
100
|
+
Rack::MockRequest.env_for("/",
|
101
|
+
"CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar',
|
102
|
+
:input => input)
|
103
|
+
req.params.should.equal "foo" => "bar", "quux" => "bla"
|
104
|
+
end
|
105
|
+
|
86
106
|
specify "can get value by key from params with #[]" do
|
87
107
|
req = Rack::Request.new \
|
88
108
|
Rack::MockRequest.env_for("?foo=quux")
|
@@ -289,7 +309,7 @@ EOF
|
|
289
309
|
"CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x",
|
290
310
|
"CONTENT_LENGTH" => input.size,
|
291
311
|
:input => input)
|
292
|
-
|
312
|
+
|
293
313
|
req.POST["huge"][:tempfile].size.should.equal 32768
|
294
314
|
req.POST["mean"][:tempfile].size.should.equal 10
|
295
315
|
req.POST["mean"][:tempfile].read.should.equal "--AaB03xha"
|
@@ -398,4 +418,29 @@ EOF
|
|
398
418
|
|
399
419
|
lambda { parser.call("gzip ; q=1.0") }.should.raise(RuntimeError)
|
400
420
|
end
|
421
|
+
|
422
|
+
specify 'should provide ip information' do
|
423
|
+
app = lambda { |env|
|
424
|
+
request = Rack::Request.new(env)
|
425
|
+
response = Rack::Response.new
|
426
|
+
response.write request.ip
|
427
|
+
response.finish
|
428
|
+
}
|
429
|
+
|
430
|
+
mock = Rack::MockRequest.new(Rack::Lint.new(app))
|
431
|
+
res = mock.get '/', 'REMOTE_ADDR' => '123.123.123.123'
|
432
|
+
res.body.should == '123.123.123.123'
|
433
|
+
|
434
|
+
res = mock.get '/',
|
435
|
+
'REMOTE_ADDR' => '123.123.123.123',
|
436
|
+
'HTTP_X_FORWARDED_FOR' => '234.234.234.234'
|
437
|
+
|
438
|
+
res.body.should == '234.234.234.234'
|
439
|
+
|
440
|
+
res = mock.get '/',
|
441
|
+
'REMOTE_ADDR' => '123.123.123.123',
|
442
|
+
'HTTP_X_FORWARDED_FOR' => '234.234.234.234,212.212.212.212'
|
443
|
+
|
444
|
+
res.body.should == '212.212.212.212'
|
445
|
+
end
|
401
446
|
end
|