rack 1.4.1 → 1.4.5
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.
- data/COPYING +1 -1
- data/KNOWN-ISSUES +9 -0
- data/README.rdoc +105 -7
- data/Rakefile +18 -11
- data/SPEC +3 -1
- data/contrib/rack.png +0 -0
- data/contrib/rack.svg +150 -0
- data/contrib/rdoc.css +412 -0
- data/lib/rack/auth/abstract/request.rb +5 -1
- data/lib/rack/auth/basic.rb +1 -1
- data/lib/rack/auth/digest/nonce.rb +1 -1
- data/lib/rack/backports/uri/common_18.rb +14 -28
- data/lib/rack/backports/uri/common_192.rb +14 -17
- data/lib/rack/backports/uri/common_193.rb +29 -0
- data/lib/rack/body_proxy.rb +10 -0
- data/lib/rack/builder.rb +1 -1
- data/lib/rack/cascade.rb +11 -0
- data/lib/rack/commonlogger.rb +18 -5
- data/lib/rack/deflater.rb +5 -1
- data/lib/rack/directory.rb +1 -1
- data/lib/rack/etag.rb +6 -3
- data/lib/rack/file.rb +19 -15
- data/lib/rack/head.rb +1 -0
- data/lib/rack/lint.rb +3 -1
- data/lib/rack/lock.rb +3 -4
- data/lib/rack/mime.rb +1 -1
- data/lib/rack/mock.rb +3 -2
- data/lib/rack/multipart/parser.rb +16 -7
- data/lib/rack/multipart.rb +2 -2
- data/lib/rack/reloader.rb +1 -1
- data/lib/rack/request.rb +2 -4
- data/lib/rack/response.rb +2 -1
- data/lib/rack/server.rb +28 -2
- data/lib/rack/session/abstract/id.rb +5 -0
- data/lib/rack/session/cookie.rb +10 -1
- data/lib/rack/static.rb +90 -8
- data/lib/rack/utils.rb +28 -10
- data/lib/rack.rb +12 -0
- data/rack.gemspec +3 -3
- data/test/builder/line.ru +1 -0
- data/test/cgi/assets/folder/test.js +1 -0
- data/test/cgi/assets/fonts/font.eot +1 -0
- data/test/cgi/assets/images/image.png +1 -0
- data/test/cgi/assets/index.html +1 -0
- data/test/cgi/assets/javascripts/app.js +1 -0
- data/test/cgi/assets/stylesheets/app.css +1 -0
- data/test/spec_auth.rb +57 -0
- data/test/spec_auth_basic.rb +8 -0
- data/test/spec_auth_digest.rb +14 -0
- data/test/spec_body_proxy.rb +4 -0
- data/test/spec_builder.rb +7 -1
- data/test/spec_cascade.rb +8 -0
- data/test/spec_chunked.rb +6 -6
- data/test/spec_config.rb +0 -1
- data/test/spec_content_length.rb +26 -13
- data/test/spec_content_type.rb +15 -5
- data/test/spec_deflater.rb +35 -17
- data/test/spec_directory.rb +20 -1
- data/test/spec_etag.rb +29 -13
- data/test/spec_file.rb +42 -25
- data/test/spec_head.rb +25 -7
- data/test/spec_lobster.rb +20 -5
- data/test/spec_lock.rb +46 -21
- data/test/spec_logger.rb +2 -7
- data/test/spec_methodoverride.rb +21 -22
- data/test/spec_mock.rb +12 -7
- data/test/spec_multipart.rb +82 -0
- data/test/spec_nulllogger.rb +13 -2
- data/test/spec_recursive.rb +12 -9
- data/test/spec_request.rb +2 -2
- data/test/spec_response.rb +30 -0
- data/test/spec_runtime.rb +15 -5
- data/test/spec_sendfile.rb +13 -9
- data/test/spec_server.rb +47 -0
- data/test/spec_session_cookie.rb +68 -1
- data/test/spec_session_memcache.rb +10 -8
- data/test/spec_session_pool.rb +13 -10
- data/test/spec_showexceptions.rb +9 -4
- data/test/spec_showstatus.rb +10 -5
- data/test/spec_static.rb +85 -9
- data/test/spec_urlmap.rb +10 -10
- data/test/spec_utils.rb +19 -1
- data/test/static/another/index.html +1 -0
- metadata +23 -8
data/test/spec_multipart.rb
CHANGED
|
@@ -48,6 +48,59 @@ describe Rack::Multipart do
|
|
|
48
48
|
params['profile']['bio'].should.include 'hello'
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
+
should "reject insanely long boundaries" do
|
|
52
|
+
# using a pipe since a tempfile can use up too much space
|
|
53
|
+
rd, wr = IO.pipe
|
|
54
|
+
|
|
55
|
+
# we only call rewind once at start, so make sure it succeeds
|
|
56
|
+
# and doesn't hit ESPIPE
|
|
57
|
+
def rd.rewind; end
|
|
58
|
+
wr.sync = true
|
|
59
|
+
|
|
60
|
+
# mock out length to make this pipe look like a Tempfile
|
|
61
|
+
def rd.length
|
|
62
|
+
1024 * 1024 * 8
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# write to a pipe in a background thread, this will write a lot
|
|
66
|
+
# unless Rack (properly) shuts down the read end
|
|
67
|
+
thr = Thread.new do
|
|
68
|
+
begin
|
|
69
|
+
wr.write("--AaB03x")
|
|
70
|
+
|
|
71
|
+
# make the initial boundary a few gigs long
|
|
72
|
+
longer = "0123456789" * 1024 * 1024
|
|
73
|
+
(1024 * 1024).times { wr.write(longer) }
|
|
74
|
+
|
|
75
|
+
wr.write("\r\n")
|
|
76
|
+
wr.write('Content-Disposition: form-data; name="a"; filename="a.txt"')
|
|
77
|
+
wr.write("\r\n")
|
|
78
|
+
wr.write("Content-Type: text/plain\r\n")
|
|
79
|
+
wr.write("\r\na")
|
|
80
|
+
wr.write("--AaB03x--\r\n")
|
|
81
|
+
wr.close
|
|
82
|
+
rescue => err # this is EPIPE if Rack shuts us down
|
|
83
|
+
err
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
fixture = {
|
|
88
|
+
"CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
|
|
89
|
+
"CONTENT_LENGTH" => rd.length.to_s,
|
|
90
|
+
:input => rd,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
env = Rack::MockRequest.env_for '/', fixture
|
|
94
|
+
lambda {
|
|
95
|
+
Rack::Multipart.parse_multipart(env)
|
|
96
|
+
}.should.raise(EOFError)
|
|
97
|
+
rd.close
|
|
98
|
+
|
|
99
|
+
err = thr.value
|
|
100
|
+
err.should.be.instance_of Errno::EPIPE
|
|
101
|
+
wr.close
|
|
102
|
+
end
|
|
103
|
+
|
|
51
104
|
should "parse multipart upload with text file" do
|
|
52
105
|
env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
|
|
53
106
|
params = Rack::Multipart.parse_multipart(env)
|
|
@@ -360,4 +413,33 @@ EOF
|
|
|
360
413
|
params.should.equal({"description"=>"Very very blue"})
|
|
361
414
|
end
|
|
362
415
|
|
|
416
|
+
should "parse multipart upload with no content-length header" do
|
|
417
|
+
env = Rack::MockRequest.env_for '/', multipart_fixture(:webkit)
|
|
418
|
+
env['CONTENT_TYPE'] = "multipart/form-data; boundary=----WebKitFormBoundaryWLHCs9qmcJJoyjKR"
|
|
419
|
+
env.delete 'CONTENT_LENGTH'
|
|
420
|
+
params = Rack::Multipart.parse_multipart(env)
|
|
421
|
+
params['profile']['bio'].should.include 'hello'
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
should "parse very long unquoted multipart file names" do
|
|
425
|
+
data = <<-EOF
|
|
426
|
+
--AaB03x\r
|
|
427
|
+
Content-Type: text/plain\r
|
|
428
|
+
Content-Disposition: attachment; name=file; filename=#{'long' * 100}\r
|
|
429
|
+
\r
|
|
430
|
+
contents\r
|
|
431
|
+
--AaB03x--\r
|
|
432
|
+
EOF
|
|
433
|
+
|
|
434
|
+
options = {
|
|
435
|
+
"CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
|
|
436
|
+
"CONTENT_LENGTH" => data.length.to_s,
|
|
437
|
+
:input => StringIO.new(data)
|
|
438
|
+
}
|
|
439
|
+
env = Rack::MockRequest.env_for("/", options)
|
|
440
|
+
params = Rack::Utils::Multipart.parse_multipart(env)
|
|
441
|
+
|
|
442
|
+
params["file"][:filename].should.equal('long' * 100)
|
|
443
|
+
end
|
|
444
|
+
|
|
363
445
|
end
|
data/test/spec_nulllogger.rb
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
|
+
require 'enumerator'
|
|
2
|
+
require 'rack/lint'
|
|
3
|
+
require 'rack/mock'
|
|
1
4
|
require 'rack/nulllogger'
|
|
2
5
|
|
|
3
6
|
describe Rack::NullLogger do
|
|
7
|
+
::Enumerator = ::Enumerable::Enumerator unless Object.const_defined?(:Enumerator)
|
|
8
|
+
|
|
4
9
|
should "act as a noop logger" do
|
|
5
10
|
app = lambda { |env|
|
|
6
11
|
env['rack.logger'].warn "b00m"
|
|
7
12
|
[200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]]
|
|
8
13
|
}
|
|
9
|
-
|
|
10
|
-
|
|
14
|
+
|
|
15
|
+
logger = Rack::Lint.new(Rack::NullLogger.new(app))
|
|
16
|
+
|
|
17
|
+
res = logger.call(Rack::MockRequest.env_for)
|
|
18
|
+
res[0..1].should.equal [
|
|
19
|
+
200, {'Content-Type' => 'text/plain'}
|
|
20
|
+
]
|
|
21
|
+
Enumerator.new(res[2]).to_a.should.equal ["Hello, World!"]
|
|
11
22
|
end
|
|
12
23
|
end
|
data/test/spec_recursive.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require 'rack/lint'
|
|
1
2
|
require 'rack/recursive'
|
|
2
3
|
require 'rack/mock'
|
|
3
4
|
|
|
@@ -28,11 +29,14 @@ describe Rack::Recursive do
|
|
|
28
29
|
@app4 = lambda { |env|
|
|
29
30
|
raise Rack::ForwardRequest.new("http://example.org/app1/quux?meh")
|
|
30
31
|
}
|
|
32
|
+
|
|
33
|
+
def recursive(map)
|
|
34
|
+
Rack::Lint.new Rack::Recursive.new(Rack::URLMap.new(map))
|
|
35
|
+
end
|
|
31
36
|
|
|
32
37
|
should "allow for subrequests" do
|
|
33
|
-
res = Rack::MockRequest.new(
|
|
34
|
-
|
|
35
|
-
"/app2" => @app2))).
|
|
38
|
+
res = Rack::MockRequest.new(recursive("/app1" => @app1,
|
|
39
|
+
"/app2" => @app2)).
|
|
36
40
|
get("/app2")
|
|
37
41
|
|
|
38
42
|
res.should.be.ok
|
|
@@ -41,9 +45,8 @@ describe Rack::Recursive do
|
|
|
41
45
|
|
|
42
46
|
should "raise error on requests not below the app" do
|
|
43
47
|
app = Rack::URLMap.new("/app1" => @app1,
|
|
44
|
-
"/app" =>
|
|
45
|
-
|
|
46
|
-
"/2" => @app2)))
|
|
48
|
+
"/app" => recursive("/1" => @app1,
|
|
49
|
+
"/2" => @app2))
|
|
47
50
|
|
|
48
51
|
lambda {
|
|
49
52
|
Rack::MockRequest.new(app).get("/app/2")
|
|
@@ -52,9 +55,9 @@ describe Rack::Recursive do
|
|
|
52
55
|
end
|
|
53
56
|
|
|
54
57
|
should "support forwarding" do
|
|
55
|
-
app =
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
app = recursive("/app1" => @app1,
|
|
59
|
+
"/app3" => @app3,
|
|
60
|
+
"/app4" => @app4)
|
|
58
61
|
|
|
59
62
|
res = Rack::MockRequest.new(app).get("/app3")
|
|
60
63
|
res.should.be.ok
|
data/test/spec_request.rb
CHANGED
|
@@ -411,9 +411,9 @@ describe Rack::Request do
|
|
|
411
411
|
req.cookies.should.equal 'foo' => 'bar'
|
|
412
412
|
end
|
|
413
413
|
|
|
414
|
-
should "
|
|
414
|
+
should "pass through non-uri escaped cookies as-is" do
|
|
415
415
|
req = Rack::Request.new Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=%")
|
|
416
|
-
|
|
416
|
+
req.cookies["foo"].should == "%"
|
|
417
417
|
end
|
|
418
418
|
|
|
419
419
|
should "parse cookies according to RFC 2109" do
|
data/test/spec_response.rb
CHANGED
|
@@ -280,4 +280,34 @@ describe Rack::Response do
|
|
|
280
280
|
res.close
|
|
281
281
|
res.body.should.be.closed
|
|
282
282
|
end
|
|
283
|
+
|
|
284
|
+
it "calls close on #body when 204, 205, or 304" do
|
|
285
|
+
res = Rack::Response.new
|
|
286
|
+
res.body = StringIO.new
|
|
287
|
+
res.finish
|
|
288
|
+
res.body.should.not.be.closed
|
|
289
|
+
|
|
290
|
+
res.status = 204
|
|
291
|
+
_, _, b = res.finish
|
|
292
|
+
res.body.should.be.closed
|
|
293
|
+
b.should.not == res.body
|
|
294
|
+
|
|
295
|
+
res.body = StringIO.new
|
|
296
|
+
res.status = 205
|
|
297
|
+
_, _, b = res.finish
|
|
298
|
+
res.body.should.be.closed
|
|
299
|
+
b.should.not == res.body
|
|
300
|
+
|
|
301
|
+
res.body = StringIO.new
|
|
302
|
+
res.status = 304
|
|
303
|
+
_, _, b = res.finish
|
|
304
|
+
res.body.should.be.closed
|
|
305
|
+
b.should.not == res.body
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
it "wraps the body from #to_ary to prevent infinite loops" do
|
|
309
|
+
res = Rack::Response.new
|
|
310
|
+
res.finish.last.should.not.respond_to?(:to_ary)
|
|
311
|
+
lambda { res.finish.last.to_ary }.should.raise(NoMethodError)
|
|
312
|
+
end
|
|
283
313
|
end
|
data/test/spec_runtime.rb
CHANGED
|
@@ -1,27 +1,37 @@
|
|
|
1
|
+
require 'rack/lint'
|
|
2
|
+
require 'rack/mock'
|
|
1
3
|
require 'rack/runtime'
|
|
2
4
|
|
|
3
5
|
describe Rack::Runtime do
|
|
6
|
+
def runtime_app(app, *args)
|
|
7
|
+
Rack::Lint.new Rack::Runtime.new(app, *args)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def request
|
|
11
|
+
Rack::MockRequest.env_for
|
|
12
|
+
end
|
|
13
|
+
|
|
4
14
|
it "sets X-Runtime is none is set" do
|
|
5
15
|
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
|
6
|
-
response =
|
|
16
|
+
response = runtime_app(app).call(request)
|
|
7
17
|
response[1]['X-Runtime'].should =~ /[\d\.]+/
|
|
8
18
|
end
|
|
9
19
|
|
|
10
20
|
it "doesn't set the X-Runtime if it is already set" do
|
|
11
21
|
app = lambda { |env| [200, {'Content-Type' => 'text/plain', "X-Runtime" => "foobar"}, "Hello, World!"] }
|
|
12
|
-
response =
|
|
22
|
+
response = runtime_app(app).call(request)
|
|
13
23
|
response[1]['X-Runtime'].should == "foobar"
|
|
14
24
|
end
|
|
15
25
|
|
|
16
26
|
should "allow a suffix to be set" do
|
|
17
27
|
app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
|
18
|
-
response =
|
|
28
|
+
response = runtime_app(app, "Test").call(request)
|
|
19
29
|
response[1]['X-Runtime-Test'].should =~ /[\d\.]+/
|
|
20
30
|
end
|
|
21
31
|
|
|
22
32
|
should "allow multiple timers to be set" do
|
|
23
33
|
app = lambda { |env| sleep 0.1; [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] }
|
|
24
|
-
runtime =
|
|
34
|
+
runtime = runtime_app(app, "App")
|
|
25
35
|
|
|
26
36
|
# wrap many times to guarantee a measurable difference
|
|
27
37
|
100.times do |i|
|
|
@@ -29,7 +39,7 @@ describe Rack::Runtime do
|
|
|
29
39
|
end
|
|
30
40
|
runtime = Rack::Runtime.new(runtime, "All")
|
|
31
41
|
|
|
32
|
-
response = runtime.call(
|
|
42
|
+
response = runtime.call(request)
|
|
33
43
|
|
|
34
44
|
response[1]['X-Runtime-App'].should =~ /[\d\.]+/
|
|
35
45
|
response[1]['X-Runtime-All'].should =~ /[\d\.]+/
|
data/test/spec_sendfile.rb
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
require 'rack/lint'
|
|
1
3
|
require 'rack/sendfile'
|
|
2
4
|
require 'rack/mock'
|
|
5
|
+
require 'tmpdir'
|
|
3
6
|
|
|
4
7
|
describe Rack::File do
|
|
5
8
|
should "respond to #to_path" do
|
|
@@ -9,8 +12,9 @@ end
|
|
|
9
12
|
|
|
10
13
|
describe Rack::Sendfile do
|
|
11
14
|
def sendfile_body
|
|
15
|
+
FileUtils.touch File.join(Dir.tmpdir, "rack_sendfile")
|
|
12
16
|
res = ['Hello World']
|
|
13
|
-
def res.to_path ;
|
|
17
|
+
def res.to_path ; File.join(Dir.tmpdir, "rack_sendfile") ; end
|
|
14
18
|
res
|
|
15
19
|
end
|
|
16
20
|
|
|
@@ -19,7 +23,7 @@ describe Rack::Sendfile do
|
|
|
19
23
|
end
|
|
20
24
|
|
|
21
25
|
def sendfile_app(body=sendfile_body)
|
|
22
|
-
Rack::Sendfile.new(simple_app(body))
|
|
26
|
+
Rack::Lint.new Rack::Sendfile.new(simple_app(body))
|
|
23
27
|
end
|
|
24
28
|
|
|
25
29
|
@request = Rack::MockRequest.new(sendfile_app)
|
|
@@ -40,8 +44,8 @@ describe Rack::Sendfile do
|
|
|
40
44
|
request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
|
|
41
45
|
response.should.be.ok
|
|
42
46
|
response.body.should.be.empty
|
|
43
|
-
response.headers['Content-Length'].should
|
|
44
|
-
response.headers['X-Sendfile'].should.equal
|
|
47
|
+
response.headers['Content-Length'].should.equal '0'
|
|
48
|
+
response.headers['X-Sendfile'].should.equal File.join(Dir.tmpdir, "rack_sendfile")
|
|
45
49
|
end
|
|
46
50
|
end
|
|
47
51
|
|
|
@@ -49,21 +53,21 @@ describe Rack::Sendfile do
|
|
|
49
53
|
request 'HTTP_X_SENDFILE_TYPE' => 'X-Lighttpd-Send-File' do |response|
|
|
50
54
|
response.should.be.ok
|
|
51
55
|
response.body.should.be.empty
|
|
52
|
-
response.headers['Content-Length'].should
|
|
53
|
-
response.headers['X-Lighttpd-Send-File'].should.equal
|
|
56
|
+
response.headers['Content-Length'].should.equal '0'
|
|
57
|
+
response.headers['X-Lighttpd-Send-File'].should.equal File.join(Dir.tmpdir, "rack_sendfile")
|
|
54
58
|
end
|
|
55
59
|
end
|
|
56
60
|
|
|
57
61
|
it "sets X-Accel-Redirect response header and discards body" do
|
|
58
62
|
headers = {
|
|
59
63
|
'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect',
|
|
60
|
-
'HTTP_X_ACCEL_MAPPING' =>
|
|
64
|
+
'HTTP_X_ACCEL_MAPPING' => "#{Dir.tmpdir}/=/foo/bar/"
|
|
61
65
|
}
|
|
62
66
|
request headers do |response|
|
|
63
67
|
response.should.be.ok
|
|
64
68
|
response.body.should.be.empty
|
|
65
|
-
response.headers['Content-Length'].should
|
|
66
|
-
response.headers['X-Accel-Redirect'].should.equal '/foo/bar/
|
|
69
|
+
response.headers['Content-Length'].should.equal '0'
|
|
70
|
+
response.headers['X-Accel-Redirect'].should.equal '/foo/bar/rack_sendfile'
|
|
67
71
|
end
|
|
68
72
|
end
|
|
69
73
|
|
data/test/spec_server.rb
CHANGED
|
@@ -10,6 +10,13 @@ describe Rack::Server do
|
|
|
10
10
|
lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['success']] }
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
def with_stderr
|
|
14
|
+
old, $stderr = $stderr, StringIO.new
|
|
15
|
+
yield $stderr
|
|
16
|
+
ensure
|
|
17
|
+
$stderr = old
|
|
18
|
+
end
|
|
19
|
+
|
|
13
20
|
it "overrides :config if :app is passed in" do
|
|
14
21
|
server = Rack::Server.new(:app => "FOO")
|
|
15
22
|
server.app.should == "FOO"
|
|
@@ -71,4 +78,44 @@ describe Rack::Server do
|
|
|
71
78
|
open(pidfile) { |f| f.read.should.eql $$.to_s }
|
|
72
79
|
end
|
|
73
80
|
|
|
81
|
+
should "check pid file presence and running process" do
|
|
82
|
+
pidfile = Tempfile.open('pidfile') { |f| f.write($$); break f }.path
|
|
83
|
+
server = Rack::Server.new(:pid => pidfile)
|
|
84
|
+
server.send(:pidfile_process_status).should.eql :running
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
should "check pid file presence and dead process" do
|
|
88
|
+
dead_pid = `echo $$`.to_i
|
|
89
|
+
pidfile = Tempfile.open('pidfile') { |f| f.write(dead_pid); break f }.path
|
|
90
|
+
server = Rack::Server.new(:pid => pidfile)
|
|
91
|
+
server.send(:pidfile_process_status).should.eql :dead
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
should "check pid file presence and exited process" do
|
|
95
|
+
pidfile = Tempfile.open('pidfile') { |f| break f }.path
|
|
96
|
+
::File.delete(pidfile)
|
|
97
|
+
server = Rack::Server.new(:pid => pidfile)
|
|
98
|
+
server.send(:pidfile_process_status).should.eql :exited
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
should "check pid file presence and not owned process" do
|
|
102
|
+
pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path
|
|
103
|
+
server = Rack::Server.new(:pid => pidfile)
|
|
104
|
+
server.send(:pidfile_process_status).should.eql :not_owned
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
should "inform the user about existing pidfiles with running processes" do
|
|
108
|
+
pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path
|
|
109
|
+
server = Rack::Server.new(:pid => pidfile)
|
|
110
|
+
with_stderr do |err|
|
|
111
|
+
should.raise(SystemExit) do
|
|
112
|
+
server.start
|
|
113
|
+
end
|
|
114
|
+
err.rewind
|
|
115
|
+
output = err.read
|
|
116
|
+
output.should.match(/already running/)
|
|
117
|
+
output.should.include? pidfile
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
74
121
|
end
|
data/test/spec_session_cookie.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'rack/session/cookie'
|
|
2
|
+
require 'rack/lint'
|
|
2
3
|
require 'rack/mock'
|
|
3
4
|
|
|
4
5
|
describe Rack::Session::Cookie do
|
|
@@ -9,7 +10,7 @@ describe Rack::Session::Cookie do
|
|
|
9
10
|
hash.delete("session_id")
|
|
10
11
|
Rack::Response.new(hash.inspect).to_a
|
|
11
12
|
end
|
|
12
|
-
|
|
13
|
+
|
|
13
14
|
session_id = lambda do |env|
|
|
14
15
|
Rack::Response.new(env["rack.session"].to_hash.inspect).to_a
|
|
15
16
|
end
|
|
@@ -24,6 +25,50 @@ describe Rack::Session::Cookie do
|
|
|
24
25
|
Rack::Response.new("Nothing").to_a
|
|
25
26
|
end
|
|
26
27
|
|
|
28
|
+
renewer = lambda do |env|
|
|
29
|
+
env["rack.session.options"][:renew] = true
|
|
30
|
+
Rack::Response.new("Nothing").to_a
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
only_session_id = lambda do |env|
|
|
34
|
+
Rack::Response.new(env["rack.session"]["session_id"].to_s).to_a
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
bigcookie = lambda do |env|
|
|
38
|
+
env["rack.session"]["cookie"] = "big" * 3000
|
|
39
|
+
Rack::Response.new(env["rack.session"].inspect).to_a
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
destroy_session = lambda do |env|
|
|
43
|
+
env["rack.session"].destroy
|
|
44
|
+
Rack::Response.new("Nothing").to_a
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def response_for(options={})
|
|
48
|
+
request_options = options.fetch(:request, {})
|
|
49
|
+
cookie = if options[:cookie].is_a?(Rack::Response)
|
|
50
|
+
options[:cookie]["Set-Cookie"]
|
|
51
|
+
else
|
|
52
|
+
options[:cookie]
|
|
53
|
+
end
|
|
54
|
+
request_options["HTTP_COOKIE"] = cookie || ""
|
|
55
|
+
|
|
56
|
+
app_with_cookie = Rack::Session::Cookie.new(*options[:app])
|
|
57
|
+
app_with_cookie = Rack::Lint.new(app_with_cookie)
|
|
58
|
+
Rack::MockRequest.new(app_with_cookie).get("/", request_options)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
before do
|
|
62
|
+
@warnings = warnings = []
|
|
63
|
+
Rack::Session::Cookie.class_eval do
|
|
64
|
+
define_method(:warn) { |m| warnings << m }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
after do
|
|
69
|
+
Rack::Session::Cookie.class_eval { remove_method :warn }
|
|
70
|
+
end
|
|
71
|
+
|
|
27
72
|
describe 'Base64' do
|
|
28
73
|
it 'uses base64 to encode' do
|
|
29
74
|
coder = Rack::Session::Cookie::Base64.new
|
|
@@ -57,6 +102,14 @@ describe Rack::Session::Cookie do
|
|
|
57
102
|
end
|
|
58
103
|
end
|
|
59
104
|
|
|
105
|
+
it "warns if no secret is given" do
|
|
106
|
+
cookie = Rack::Session::Cookie.new(incrementor)
|
|
107
|
+
@warnings.first.should =~ /no secret/i
|
|
108
|
+
@warnings.clear
|
|
109
|
+
cookie = Rack::Session::Cookie.new(incrementor, :secret => 'abc')
|
|
110
|
+
@warnings.should.be.empty?
|
|
111
|
+
end
|
|
112
|
+
|
|
60
113
|
it 'uses a coder' do
|
|
61
114
|
identity = Class.new {
|
|
62
115
|
attr_reader :calls
|
|
@@ -291,4 +344,18 @@ describe Rack::Session::Cookie do
|
|
|
291
344
|
res = Rack::MockRequest.new(app).get("/", 'rack.session' => {:foo => 'bar'})
|
|
292
345
|
res.body.should.match(/foo/)
|
|
293
346
|
end
|
|
347
|
+
|
|
348
|
+
it "allows modifying session data with session data from middleware in front" do
|
|
349
|
+
request = { 'rack.session' => { :foo => 'bar' }}
|
|
350
|
+
response = response_for(:app => incrementor, :request => request)
|
|
351
|
+
response.body.should.match(/counter/)
|
|
352
|
+
response.body.should.match(/foo/)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
it "allows modifying session data with session data from middleware in front" do
|
|
356
|
+
request = { 'rack.session' => { :foo => 'bar' }}
|
|
357
|
+
response = response_for(:app => incrementor, :request => request)
|
|
358
|
+
response.body.should.match(/counter/)
|
|
359
|
+
response.body.should.match(/foo/)
|
|
360
|
+
end
|
|
294
361
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
begin
|
|
2
2
|
require 'rack/session/memcache'
|
|
3
|
+
require 'rack/lint'
|
|
3
4
|
require 'rack/mock'
|
|
4
5
|
require 'thread'
|
|
5
6
|
|
|
@@ -11,22 +12,23 @@ begin
|
|
|
11
12
|
env["rack.session"]["counter"] += 1
|
|
12
13
|
Rack::Response.new(env["rack.session"].inspect).to_a
|
|
13
14
|
end
|
|
14
|
-
drop_session = proc do |env|
|
|
15
|
+
drop_session = Rack::Lint.new(proc do |env|
|
|
15
16
|
env['rack.session.options'][:drop] = true
|
|
16
17
|
incrementor.call(env)
|
|
17
|
-
end
|
|
18
|
-
renew_session = proc do |env|
|
|
18
|
+
end)
|
|
19
|
+
renew_session = Rack::Lint.new(proc do |env|
|
|
19
20
|
env['rack.session.options'][:renew] = true
|
|
20
21
|
incrementor.call(env)
|
|
21
|
-
end
|
|
22
|
-
defer_session = proc do |env|
|
|
22
|
+
end)
|
|
23
|
+
defer_session = Rack::Lint.new(proc do |env|
|
|
23
24
|
env['rack.session.options'][:defer] = true
|
|
24
25
|
incrementor.call(env)
|
|
25
|
-
end
|
|
26
|
-
skip_session = proc do |env|
|
|
26
|
+
end)
|
|
27
|
+
skip_session = Rack::Lint.new(proc do |env|
|
|
27
28
|
env['rack.session.options'][:skip] = true
|
|
28
29
|
incrementor.call(env)
|
|
29
|
-
end
|
|
30
|
+
end)
|
|
31
|
+
incrementor = Rack::Lint.new(incrementor)
|
|
30
32
|
|
|
31
33
|
# test memcache connection
|
|
32
34
|
Rack::Session::Memcache.new(incrementor)
|
data/test/spec_session_pool.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'thread'
|
|
2
|
+
require 'rack/lint'
|
|
2
3
|
require 'rack/mock'
|
|
3
4
|
require 'rack/session/pool'
|
|
4
5
|
|
|
@@ -12,28 +13,30 @@ describe Rack::Session::Pool do
|
|
|
12
13
|
Rack::Response.new(env["rack.session"].inspect).to_a
|
|
13
14
|
end
|
|
14
15
|
|
|
15
|
-
session_id = lambda do |env|
|
|
16
|
+
session_id = Rack::Lint.new(lambda do |env|
|
|
16
17
|
Rack::Response.new(env["rack.session"].inspect).to_a
|
|
17
|
-
end
|
|
18
|
+
end)
|
|
18
19
|
|
|
19
|
-
nothing = lambda do |env|
|
|
20
|
+
nothing = Rack::Lint.new(lambda do |env|
|
|
20
21
|
Rack::Response.new("Nothing").to_a
|
|
21
|
-
end
|
|
22
|
+
end)
|
|
22
23
|
|
|
23
|
-
drop_session = lambda do |env|
|
|
24
|
+
drop_session = Rack::Lint.new(lambda do |env|
|
|
24
25
|
env['rack.session.options'][:drop] = true
|
|
25
26
|
incrementor.call(env)
|
|
26
|
-
end
|
|
27
|
+
end)
|
|
27
28
|
|
|
28
|
-
renew_session = lambda do |env|
|
|
29
|
+
renew_session = Rack::Lint.new(lambda do |env|
|
|
29
30
|
env['rack.session.options'][:renew] = true
|
|
30
31
|
incrementor.call(env)
|
|
31
|
-
end
|
|
32
|
+
end)
|
|
32
33
|
|
|
33
|
-
defer_session = lambda do |env|
|
|
34
|
+
defer_session = Rack::Lint.new(lambda do |env|
|
|
34
35
|
env['rack.session.options'][:defer] = true
|
|
35
36
|
incrementor.call(env)
|
|
36
|
-
end
|
|
37
|
+
end)
|
|
38
|
+
|
|
39
|
+
incrementor = Rack::Lint.new(incrementor)
|
|
37
40
|
|
|
38
41
|
it "creates a new cookie" do
|
|
39
42
|
pool = Rack::Session::Pool.new(incrementor)
|
data/test/spec_showexceptions.rb
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
require 'rack/showexceptions'
|
|
2
|
+
require 'rack/lint'
|
|
2
3
|
require 'rack/mock'
|
|
3
4
|
|
|
4
5
|
describe Rack::ShowExceptions do
|
|
6
|
+
def show_exceptions(app)
|
|
7
|
+
Rack::Lint.new Rack::ShowExceptions.new(app)
|
|
8
|
+
end
|
|
9
|
+
|
|
5
10
|
it "catches exceptions" do
|
|
6
11
|
res = nil
|
|
7
12
|
|
|
8
13
|
req = Rack::MockRequest.new(
|
|
9
|
-
|
|
14
|
+
show_exceptions(
|
|
10
15
|
lambda{|env| raise RuntimeError }
|
|
11
16
|
))
|
|
12
17
|
|
|
@@ -25,7 +30,7 @@ describe Rack::ShowExceptions do
|
|
|
25
30
|
res = nil
|
|
26
31
|
|
|
27
32
|
req = Rack::MockRequest.new(
|
|
28
|
-
|
|
33
|
+
show_exceptions(
|
|
29
34
|
lambda{|env| raise RuntimeError, "It was never supposed to work" }
|
|
30
35
|
))
|
|
31
36
|
|
|
@@ -46,7 +51,7 @@ describe Rack::ShowExceptions do
|
|
|
46
51
|
res = nil
|
|
47
52
|
|
|
48
53
|
req = Rack::MockRequest.new(
|
|
49
|
-
|
|
54
|
+
show_exceptions(
|
|
50
55
|
lambda{|env| raise RuntimeError, "It was never supposed to work" }
|
|
51
56
|
))
|
|
52
57
|
|
|
@@ -68,7 +73,7 @@ describe Rack::ShowExceptions do
|
|
|
68
73
|
res = nil
|
|
69
74
|
|
|
70
75
|
req = Rack::MockRequest.new(
|
|
71
|
-
|
|
76
|
+
show_exceptions(
|
|
72
77
|
lambda{|env| raise RuntimeError, "", [] }
|
|
73
78
|
)
|
|
74
79
|
)
|
data/test/spec_showstatus.rb
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
require 'rack/showstatus'
|
|
2
|
+
require 'rack/lint'
|
|
2
3
|
require 'rack/mock'
|
|
3
4
|
|
|
4
5
|
describe Rack::ShowStatus do
|
|
6
|
+
def show_status(app)
|
|
7
|
+
Rack::Lint.new Rack::ShowStatus.new(app)
|
|
8
|
+
end
|
|
9
|
+
|
|
5
10
|
should "provide a default status message" do
|
|
6
11
|
req = Rack::MockRequest.new(
|
|
7
|
-
|
|
12
|
+
show_status(lambda{|env|
|
|
8
13
|
[404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, []]
|
|
9
14
|
}))
|
|
10
15
|
|
|
@@ -19,7 +24,7 @@ describe Rack::ShowStatus do
|
|
|
19
24
|
|
|
20
25
|
should "let the app provide additional information" do
|
|
21
26
|
req = Rack::MockRequest.new(
|
|
22
|
-
|
|
27
|
+
show_status(
|
|
23
28
|
lambda{|env|
|
|
24
29
|
env["rack.showstatus.detail"] = "gone too meta."
|
|
25
30
|
[404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, []]
|
|
@@ -37,7 +42,7 @@ describe Rack::ShowStatus do
|
|
|
37
42
|
|
|
38
43
|
should "not replace existing messages" do
|
|
39
44
|
req = Rack::MockRequest.new(
|
|
40
|
-
|
|
45
|
+
show_status(
|
|
41
46
|
lambda{|env|
|
|
42
47
|
[404, {"Content-Type" => "text/plain", "Content-Length" => "4"}, ["foo!"]]
|
|
43
48
|
}))
|
|
@@ -52,7 +57,7 @@ describe Rack::ShowStatus do
|
|
|
52
57
|
headers = {"WWW-Authenticate" => "Basic blah"}
|
|
53
58
|
|
|
54
59
|
req = Rack::MockRequest.new(
|
|
55
|
-
|
|
60
|
+
show_status(lambda{|env| [401, headers, []] }))
|
|
56
61
|
res = req.get("/", :lint => true)
|
|
57
62
|
|
|
58
63
|
res["WWW-Authenticate"].should.equal("Basic blah")
|
|
@@ -60,7 +65,7 @@ describe Rack::ShowStatus do
|
|
|
60
65
|
|
|
61
66
|
should "replace existing messages if there is detail" do
|
|
62
67
|
req = Rack::MockRequest.new(
|
|
63
|
-
|
|
68
|
+
show_status(
|
|
64
69
|
lambda{|env|
|
|
65
70
|
env["rack.showstatus.detail"] = "gone too meta."
|
|
66
71
|
[404, {"Content-Type" => "text/plain", "Content-Length" => "4"}, ["foo!"]]
|