rack 1.4.7 → 1.5.0.beta.1
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/README.rdoc +2 -30
- data/Rakefile +1 -0
- data/SPEC +68 -4
- data/example/protectedlobster.rb +1 -1
- data/lib/rack.rb +2 -14
- data/lib/rack/auth/abstract/request.rb +1 -5
- data/lib/rack/builder.rb +8 -4
- data/lib/rack/cascade.rb +2 -2
- data/lib/rack/config.rb +5 -0
- data/lib/rack/deflater.rb +2 -1
- data/lib/rack/file.rb +25 -28
- data/lib/rack/handler.rb +18 -5
- data/lib/rack/handler/mongrel.rb +1 -1
- data/lib/rack/handler/scgi.rb +1 -1
- data/lib/rack/handler/thin.rb +6 -3
- data/lib/rack/handler/webrick.rb +1 -0
- data/lib/rack/head.rb +2 -0
- data/lib/rack/lint.rb +132 -7
- data/lib/rack/lobster.rb +3 -3
- data/lib/rack/lock.rb +2 -0
- data/lib/rack/methodoverride.rb +0 -2
- data/lib/rack/mime.rb +29 -0
- data/lib/rack/multipart/parser.rb +0 -9
- data/lib/rack/request.rb +66 -25
- data/lib/rack/response.rb +1 -2
- data/lib/rack/sendfile.rb +18 -4
- data/lib/rack/server.rb +20 -12
- data/lib/rack/session/abstract/id.rb +60 -59
- data/lib/rack/session/cookie.rb +11 -16
- data/lib/rack/utils.rb +97 -85
- data/rack.gemspec +1 -6
- data/test/spec_builder.rb +7 -0
- data/test/spec_cgi.rb +1 -1
- data/test/spec_chunked.rb +3 -5
- data/test/spec_content_length.rb +3 -6
- data/test/spec_deflater.rb +26 -9
- data/test/spec_fastcgi.rb +1 -1
- data/test/spec_file.rb +24 -11
- data/test/spec_head.rb +3 -8
- data/test/spec_lint.rb +6 -6
- data/test/spec_lock.rb +4 -7
- data/test/spec_methodoverride.rb +4 -1
- data/test/spec_mime.rb +51 -0
- data/test/spec_mongrel.rb +1 -1
- data/test/spec_multipart.rb +15 -49
- data/test/spec_nulllogger.rb +3 -6
- data/test/spec_request.rb +112 -18
- data/test/spec_response.rb +8 -8
- data/test/spec_sendfile.rb +52 -13
- data/test/spec_server.rb +6 -0
- data/test/spec_session_abstract_id.rb +11 -1
- data/test/spec_session_cookie.rb +140 -153
- data/test/spec_thin.rb +6 -1
- data/test/spec_utils.rb +23 -17
- data/test/spec_webrick.rb +1 -1
- metadata +37 -83
- checksums.yaml +0 -7
- data/test/cgi/lighttpd.errors +0 -1
- data/test/multipart/three_files_three_fields +0 -31
- data/test/spec_auth.rb +0 -57
data/test/spec_nulllogger.rb
CHANGED
@@ -1,23 +1,20 @@
|
|
1
|
-
require 'enumerator'
|
2
1
|
require 'rack/lint'
|
3
2
|
require 'rack/mock'
|
4
3
|
require 'rack/nulllogger'
|
5
4
|
|
6
5
|
describe Rack::NullLogger do
|
7
|
-
::Enumerator = ::Enumerable::Enumerator unless Object.const_defined?(:Enumerator)
|
8
|
-
|
9
6
|
should "act as a noop logger" do
|
10
7
|
app = lambda { |env|
|
11
8
|
env['rack.logger'].warn "b00m"
|
12
9
|
[200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]]
|
13
10
|
}
|
14
|
-
|
11
|
+
|
15
12
|
logger = Rack::Lint.new(Rack::NullLogger.new(app))
|
16
|
-
|
13
|
+
|
17
14
|
res = logger.call(Rack::MockRequest.env_for)
|
18
15
|
res[0..1].should.equal [
|
19
16
|
200, {'Content-Type' => 'text/plain'}
|
20
17
|
]
|
21
|
-
|
18
|
+
res[2].to_enum.to_a.should.equal ["Hello, World!"]
|
22
19
|
end
|
23
20
|
end
|
data/test/spec_request.rb
CHANGED
@@ -2,7 +2,6 @@ require 'stringio'
|
|
2
2
|
require 'cgi'
|
3
3
|
require 'rack/request'
|
4
4
|
require 'rack/mock'
|
5
|
-
require 'securerandom'
|
6
5
|
|
7
6
|
describe Rack::Request do
|
8
7
|
should "wrap the rack variables" do
|
@@ -412,6 +411,103 @@ describe Rack::Request do
|
|
412
411
|
req.cookies.should.equal 'foo' => 'bar'
|
413
412
|
end
|
414
413
|
|
414
|
+
should "not modify the params hash in place" do
|
415
|
+
e = Rack::MockRequest.env_for("")
|
416
|
+
req1 = Rack::Request.new(e)
|
417
|
+
req1.params.should.equal({})
|
418
|
+
req1.params['foo'] = 'bar'
|
419
|
+
req1.params.should.equal 'foo' => 'bar'
|
420
|
+
req2 = Rack::Request.new(e)
|
421
|
+
req2.params.should.equal({})
|
422
|
+
end
|
423
|
+
|
424
|
+
should "modify params hash if param is in GET" do
|
425
|
+
e = Rack::MockRequest.env_for("?foo=duh")
|
426
|
+
req1 = Rack::Request.new(e)
|
427
|
+
req1.params.should.equal 'foo' => 'duh'
|
428
|
+
req1.update_param 'foo', 'bar'
|
429
|
+
req1.params.should.equal 'foo' => 'bar'
|
430
|
+
req2 = Rack::Request.new(e)
|
431
|
+
req2.params.should.equal 'foo' => 'bar'
|
432
|
+
end
|
433
|
+
|
434
|
+
should "modify params hash if param is in POST" do
|
435
|
+
e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => 'foo=duh')
|
436
|
+
req1 = Rack::Request.new(e)
|
437
|
+
req1.params.should.equal 'foo' => 'duh'
|
438
|
+
req1.update_param 'foo', 'bar'
|
439
|
+
req1.params.should.equal 'foo' => 'bar'
|
440
|
+
req2 = Rack::Request.new(e)
|
441
|
+
req2.params.should.equal 'foo' => 'bar'
|
442
|
+
end
|
443
|
+
|
444
|
+
should "modify params hash, even if param didn't exist before" do
|
445
|
+
e = Rack::MockRequest.env_for("")
|
446
|
+
req1 = Rack::Request.new(e)
|
447
|
+
req1.params.should.equal({})
|
448
|
+
req1.update_param 'foo', 'bar'
|
449
|
+
req1.params.should.equal 'foo' => 'bar'
|
450
|
+
req2 = Rack::Request.new(e)
|
451
|
+
req2.params.should.equal 'foo' => 'bar'
|
452
|
+
end
|
453
|
+
|
454
|
+
should "modify params hash by changing only GET" do
|
455
|
+
e = Rack::MockRequest.env_for("?foo=duhget")
|
456
|
+
req = Rack::Request.new(e)
|
457
|
+
req.GET.should.equal 'foo' => 'duhget'
|
458
|
+
req.POST.should.equal({})
|
459
|
+
req.update_param 'foo', 'bar'
|
460
|
+
req.GET.should.equal 'foo' => 'bar'
|
461
|
+
req.POST.should.equal({})
|
462
|
+
end
|
463
|
+
|
464
|
+
should "modify params hash by changing only POST" do
|
465
|
+
e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => "foo=duhpost")
|
466
|
+
req = Rack::Request.new(e)
|
467
|
+
req.GET.should.equal({})
|
468
|
+
req.POST.should.equal 'foo' => 'duhpost'
|
469
|
+
req.update_param 'foo', 'bar'
|
470
|
+
req.GET.should.equal({})
|
471
|
+
req.POST.should.equal 'foo' => 'bar'
|
472
|
+
end
|
473
|
+
|
474
|
+
should "modify params hash, even if param is defined in both POST and GET" do
|
475
|
+
e = Rack::MockRequest.env_for("?foo=duhget", "REQUEST_METHOD" => 'POST', :input => "foo=duhpost")
|
476
|
+
req1 = Rack::Request.new(e)
|
477
|
+
req1.GET.should.equal 'foo' => 'duhget'
|
478
|
+
req1.POST.should.equal 'foo' => 'duhpost'
|
479
|
+
req1.params.should.equal 'foo' => 'duhpost'
|
480
|
+
req1.update_param 'foo', 'bar'
|
481
|
+
req1.GET.should.equal 'foo' => 'bar'
|
482
|
+
req1.POST.should.equal 'foo' => 'bar'
|
483
|
+
req1.params.should.equal 'foo' => 'bar'
|
484
|
+
req2 = Rack::Request.new(e)
|
485
|
+
req2.GET.should.equal 'foo' => 'bar'
|
486
|
+
req2.POST.should.equal 'foo' => 'bar'
|
487
|
+
req2.params.should.equal 'foo' => 'bar'
|
488
|
+
req2.params.should.equal 'foo' => 'bar'
|
489
|
+
end
|
490
|
+
|
491
|
+
should "allow deleting from params hash if param is in GET" do
|
492
|
+
e = Rack::MockRequest.env_for("?foo=bar")
|
493
|
+
req1 = Rack::Request.new(e)
|
494
|
+
req1.params.should.equal 'foo' => 'bar'
|
495
|
+
req1.delete_param('foo').should.equal 'bar'
|
496
|
+
req1.params.should.equal({})
|
497
|
+
req2 = Rack::Request.new(e)
|
498
|
+
req2.params.should.equal({})
|
499
|
+
end
|
500
|
+
|
501
|
+
should "allow deleting from params hash if param is in POST" do
|
502
|
+
e = Rack::MockRequest.env_for("", "REQUEST_METHOD" => 'POST', :input => 'foo=bar')
|
503
|
+
req1 = Rack::Request.new(e)
|
504
|
+
req1.params.should.equal 'foo' => 'bar'
|
505
|
+
req1.delete_param('foo').should.equal 'bar'
|
506
|
+
req1.params.should.equal({})
|
507
|
+
req2 = Rack::Request.new(e)
|
508
|
+
req2.params.should.equal({})
|
509
|
+
end
|
510
|
+
|
415
511
|
should "pass through non-uri escaped cookies as-is" do
|
416
512
|
req = Rack::Request.new Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=%")
|
417
513
|
req.cookies["foo"].should == "%"
|
@@ -473,7 +569,10 @@ describe Rack::Request do
|
|
473
569
|
should.equal "http://example.org:8080/"
|
474
570
|
Rack::Request.new(Rack::MockRequest.env_for("https://example.org/")).url.
|
475
571
|
should.equal "https://example.org/"
|
476
|
-
|
572
|
+
Rack::Request.new(Rack::MockRequest.env_for("coffee://example.org/")).url.
|
573
|
+
should.equal "coffee://example.org/"
|
574
|
+
Rack::Request.new(Rack::MockRequest.env_for("coffee://example.org:443/")).url.
|
575
|
+
should.equal "coffee://example.org:443/"
|
477
576
|
Rack::Request.new(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).url.
|
478
577
|
should.equal "https://example.com:8080/foo?foo"
|
479
578
|
end
|
@@ -614,22 +713,6 @@ EOF
|
|
614
713
|
f[:tempfile].size.should.equal 76
|
615
714
|
end
|
616
715
|
|
617
|
-
should "MultipartLimitError when request has too many multipart parts if limit set" do
|
618
|
-
begin
|
619
|
-
data = 10000.times.map { "--AaB03x\r\nContent-Type: text/plain\r\nContent-Disposition: attachment; name=#{SecureRandom.hex(10)}; filename=#{SecureRandom.hex(10)}\r\n\r\ncontents\r\n" }.join("\r\n")
|
620
|
-
data += "--AaB03x--\r"
|
621
|
-
|
622
|
-
options = {
|
623
|
-
"CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
|
624
|
-
"CONTENT_LENGTH" => data.length.to_s,
|
625
|
-
:input => StringIO.new(data)
|
626
|
-
}
|
627
|
-
|
628
|
-
request = Rack::Request.new Rack::MockRequest.env_for("/", options)
|
629
|
-
lambda { request.POST }.should.raise(Rack::Multipart::MultipartLimitError)
|
630
|
-
end
|
631
|
-
end
|
632
|
-
|
633
716
|
should "parse big multipart form data" do
|
634
717
|
input = <<EOF
|
635
718
|
--AaB03x\r
|
@@ -909,6 +992,17 @@ EOF
|
|
909
992
|
|
910
993
|
res = mock.get '/', 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, fe80::202:b3ff:fe1e:8329'
|
911
994
|
res.body.should.equal 'fe80::202:b3ff:fe1e:8329'
|
995
|
+
|
996
|
+
# Unix Sockets
|
997
|
+
res = mock.get '/',
|
998
|
+
'REMOTE_ADDR' => 'unix',
|
999
|
+
'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
|
1000
|
+
res.body.should.equal '3.4.5.6'
|
1001
|
+
|
1002
|
+
res = mock.get '/',
|
1003
|
+
'REMOTE_ADDR' => 'unix:/tmp/foo',
|
1004
|
+
'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
|
1005
|
+
res.body.should.equal '3.4.5.6'
|
912
1006
|
end
|
913
1007
|
|
914
1008
|
class MyRequest < Rack::Request
|
data/test/spec_response.rb
CHANGED
@@ -6,7 +6,7 @@ describe Rack::Response do
|
|
6
6
|
response = Rack::Response.new
|
7
7
|
status, header, body = response.finish
|
8
8
|
status.should.equal 200
|
9
|
-
header.should.equal
|
9
|
+
header.should.equal({})
|
10
10
|
body.each { |part|
|
11
11
|
part.should.equal ""
|
12
12
|
}
|
@@ -14,7 +14,7 @@ describe Rack::Response do
|
|
14
14
|
response = Rack::Response.new
|
15
15
|
status, header, body = *response
|
16
16
|
status.should.equal 200
|
17
|
-
header.should.equal
|
17
|
+
header.should.equal({})
|
18
18
|
body.each { |part|
|
19
19
|
part.should.equal ""
|
20
20
|
}
|
@@ -37,7 +37,7 @@ describe Rack::Response do
|
|
37
37
|
|
38
38
|
it "can set and read headers" do
|
39
39
|
response = Rack::Response.new
|
40
|
-
response["Content-Type"].should.equal
|
40
|
+
response["Content-Type"].should.equal nil
|
41
41
|
response["Content-Type"] = "text/plain"
|
42
42
|
response["Content-Type"].should.equal "text/plain"
|
43
43
|
end
|
@@ -92,7 +92,7 @@ describe Rack::Response do
|
|
92
92
|
response.delete_cookie "foo"
|
93
93
|
response["Set-Cookie"].should.equal [
|
94
94
|
"foo2=bar2",
|
95
|
-
"foo=; expires=Thu, 01-Jan-1970 00:00:00 GMT"
|
95
|
+
"foo=; max-age=0; expires=Thu, 01-Jan-1970 00:00:00 GMT"
|
96
96
|
].join("\n")
|
97
97
|
end
|
98
98
|
|
@@ -102,10 +102,10 @@ describe Rack::Response do
|
|
102
102
|
response.set_cookie "foo", {:value => "bar", :domain => ".example.com"}
|
103
103
|
response["Set-Cookie"].should.equal ["foo=bar; domain=sample.example.com", "foo=bar; domain=.example.com"].join("\n")
|
104
104
|
response.delete_cookie "foo", :domain => ".example.com"
|
105
|
-
response["Set-Cookie"].should.equal ["foo=bar; domain=sample.example.com", "foo=; domain=.example.com; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
|
105
|
+
response["Set-Cookie"].should.equal ["foo=bar; domain=sample.example.com", "foo=; domain=.example.com; max-age=0; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
|
106
106
|
response.delete_cookie "foo", :domain => "sample.example.com"
|
107
|
-
response["Set-Cookie"].should.equal ["foo=; domain=.example.com; expires=Thu, 01-Jan-1970 00:00:00 GMT",
|
108
|
-
"foo=; domain=sample.example.com; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
|
107
|
+
response["Set-Cookie"].should.equal ["foo=; domain=.example.com; max-age=0; expires=Thu, 01-Jan-1970 00:00:00 GMT",
|
108
|
+
"foo=; domain=sample.example.com; max-age=0; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
|
109
109
|
end
|
110
110
|
|
111
111
|
it "can delete cookies with the same name with different paths" do
|
@@ -117,7 +117,7 @@ describe Rack::Response do
|
|
117
117
|
|
118
118
|
response.delete_cookie "foo", :path => "/path"
|
119
119
|
response["Set-Cookie"].should.equal ["foo=bar; path=/",
|
120
|
-
"foo=; path=/path; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
|
120
|
+
"foo=; path=/path; max-age=0; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
|
121
121
|
end
|
122
122
|
|
123
123
|
it "can do redirects" do
|
data/test/spec_sendfile.rb
CHANGED
@@ -2,7 +2,6 @@ require 'fileutils'
|
|
2
2
|
require 'rack/lint'
|
3
3
|
require 'rack/sendfile'
|
4
4
|
require 'rack/mock'
|
5
|
-
require 'tmpdir'
|
6
5
|
|
7
6
|
describe Rack::File do
|
8
7
|
should "respond to #to_path" do
|
@@ -12,9 +11,9 @@ end
|
|
12
11
|
|
13
12
|
describe Rack::Sendfile do
|
14
13
|
def sendfile_body
|
15
|
-
FileUtils.touch
|
14
|
+
FileUtils.touch "/tmp/rack_sendfile"
|
16
15
|
res = ['Hello World']
|
17
|
-
def res.to_path ;
|
16
|
+
def res.to_path ; "/tmp/rack_sendfile" ; end
|
18
17
|
res
|
19
18
|
end
|
20
19
|
|
@@ -22,14 +21,20 @@ describe Rack::Sendfile do
|
|
22
21
|
lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
|
23
22
|
end
|
24
23
|
|
25
|
-
def sendfile_app(body=
|
26
|
-
Rack::Lint.new Rack::Sendfile.new(simple_app(body))
|
24
|
+
def sendfile_app(body, mappings = [])
|
25
|
+
Rack::Lint.new Rack::Sendfile.new(simple_app(body), nil, mappings)
|
27
26
|
end
|
28
27
|
|
29
|
-
|
28
|
+
def request(headers={}, body=sendfile_body, mappings=[])
|
29
|
+
yield Rack::MockRequest.new(sendfile_app(body, mappings)).get('/', headers)
|
30
|
+
end
|
30
31
|
|
31
|
-
def
|
32
|
-
|
32
|
+
def open_file(path)
|
33
|
+
Class.new(File) do
|
34
|
+
unless method_defined?(:to_path)
|
35
|
+
alias :to_path :path
|
36
|
+
end
|
37
|
+
end.open(path, 'w+')
|
33
38
|
end
|
34
39
|
|
35
40
|
it "does nothing when no X-Sendfile-Type header present" do
|
@@ -45,7 +50,7 @@ describe Rack::Sendfile do
|
|
45
50
|
response.should.be.ok
|
46
51
|
response.body.should.be.empty
|
47
52
|
response.headers['Content-Length'].should.equal '0'
|
48
|
-
response.headers['X-Sendfile'].should.equal
|
53
|
+
response.headers['X-Sendfile'].should.equal '/tmp/rack_sendfile'
|
49
54
|
end
|
50
55
|
end
|
51
56
|
|
@@ -54,14 +59,14 @@ describe Rack::Sendfile do
|
|
54
59
|
response.should.be.ok
|
55
60
|
response.body.should.be.empty
|
56
61
|
response.headers['Content-Length'].should.equal '0'
|
57
|
-
response.headers['X-Lighttpd-Send-File'].should.equal
|
62
|
+
response.headers['X-Lighttpd-Send-File'].should.equal '/tmp/rack_sendfile'
|
58
63
|
end
|
59
64
|
end
|
60
65
|
|
61
66
|
it "sets X-Accel-Redirect response header and discards body" do
|
62
67
|
headers = {
|
63
68
|
'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect',
|
64
|
-
'HTTP_X_ACCEL_MAPPING' =>
|
69
|
+
'HTTP_X_ACCEL_MAPPING' => '/tmp/=/foo/bar/'
|
65
70
|
}
|
66
71
|
request headers do |response|
|
67
72
|
response.should.be.ok
|
@@ -81,10 +86,44 @@ describe Rack::Sendfile do
|
|
81
86
|
end
|
82
87
|
|
83
88
|
it 'does nothing when body does not respond to #to_path' do
|
84
|
-
|
85
|
-
request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
|
89
|
+
request({'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile'}, ['Not a file...']) do |response|
|
86
90
|
response.body.should.equal 'Not a file...'
|
87
91
|
response.headers.should.not.include 'X-Sendfile'
|
88
92
|
end
|
89
93
|
end
|
94
|
+
|
95
|
+
it "sets X-Accel-Redirect response header and discards body when initialized with multiple mappings" do
|
96
|
+
begin
|
97
|
+
dir1 = Dir.mktmpdir
|
98
|
+
dir2 = Dir.mktmpdir
|
99
|
+
|
100
|
+
first_body = open_file(File.join(dir1, 'rack_sendfile'))
|
101
|
+
first_body.puts 'hello world'
|
102
|
+
|
103
|
+
second_body = open_file(File.join(dir2, 'rack_sendfile'))
|
104
|
+
second_body.puts 'goodbye world'
|
105
|
+
|
106
|
+
mappings = [
|
107
|
+
["#{dir1}/", '/foo/bar/'],
|
108
|
+
["#{dir2}/", '/wibble/']
|
109
|
+
]
|
110
|
+
|
111
|
+
request({'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect'}, first_body, mappings) do |response|
|
112
|
+
response.should.be.ok
|
113
|
+
response.body.should.be.empty
|
114
|
+
response.headers['Content-Length'].should.equal '0'
|
115
|
+
response.headers['X-Accel-Redirect'].should.equal '/foo/bar/rack_sendfile'
|
116
|
+
end
|
117
|
+
|
118
|
+
request({'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect'}, second_body, mappings) do |response|
|
119
|
+
response.should.be.ok
|
120
|
+
response.body.should.be.empty
|
121
|
+
response.headers['Content-Length'].should.equal '0'
|
122
|
+
response.headers['X-Accel-Redirect'].should.equal '/wibble/rack_sendfile'
|
123
|
+
end
|
124
|
+
ensure
|
125
|
+
FileUtils.remove_entry_secure dir1
|
126
|
+
FileUtils.remove_entry_secure dir2
|
127
|
+
end
|
128
|
+
end
|
90
129
|
end
|
data/test/spec_server.rb
CHANGED
@@ -22,6 +22,12 @@ describe Rack::Server do
|
|
22
22
|
server.app.should == "FOO"
|
23
23
|
end
|
24
24
|
|
25
|
+
should "prefer to use :builder when it is passed in" do
|
26
|
+
server = Rack::Server.new(:builder => "run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['success']] }")
|
27
|
+
server.app.class.should == Proc
|
28
|
+
Rack::MockRequest.new(server.app).get("/").body.to_s.should.equal 'success'
|
29
|
+
end
|
30
|
+
|
25
31
|
should "not include Rack::Lint in deployment or none environments" do
|
26
32
|
server = Rack::Server.new(:app => 'foo')
|
27
33
|
server.middleware['deployment'].flatten.should.not.include(Rack::Lint)
|
@@ -40,4 +40,14 @@ describe Rack::Session::Abstract::ID do
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
|
43
|
+
should "allow to use another securerandom provider" do
|
44
|
+
secure_random = Class.new do
|
45
|
+
def hex(*args)
|
46
|
+
'fake_hex'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
id = Rack::Session::Abstract::ID.new nil, :secure_random => secure_random.new
|
50
|
+
id.send(:generate_sid).should.eql 'fake_hex'
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/test/spec_session_cookie.rb
CHANGED
@@ -121,234 +121,221 @@ describe Rack::Session::Cookie do
|
|
121
121
|
def encode(str); @calls << :encode; str; end
|
122
122
|
def decode(str); @calls << :decode; str; end
|
123
123
|
}.new
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
124
|
+
response = response_for(:app => [incrementor, { :coder => identity }])
|
125
|
+
|
126
|
+
response["Set-Cookie"].should.include("rack.session=")
|
127
|
+
response.body.should.equal '{"counter"=>1}'
|
128
128
|
identity.calls.should.equal [:decode, :encode]
|
129
129
|
end
|
130
130
|
|
131
131
|
it "creates a new cookie" do
|
132
|
-
|
133
|
-
|
134
|
-
|
132
|
+
response = response_for(:app => incrementor)
|
133
|
+
response["Set-Cookie"].should.include("rack.session=")
|
134
|
+
response.body.should.equal '{"counter"=>1}'
|
135
135
|
end
|
136
136
|
|
137
137
|
it "loads from a cookie" do
|
138
|
-
|
139
|
-
cookie = res["Set-Cookie"]
|
140
|
-
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).
|
141
|
-
get("/", "HTTP_COOKIE" => cookie)
|
142
|
-
res.body.should.equal '{"counter"=>2}'
|
143
|
-
cookie = res["Set-Cookie"]
|
144
|
-
res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).
|
145
|
-
get("/", "HTTP_COOKIE" => cookie)
|
146
|
-
res.body.should.equal '{"counter"=>3}'
|
147
|
-
end
|
138
|
+
response = response_for(:app => incrementor)
|
148
139
|
|
149
|
-
|
150
|
-
|
151
|
-
Rack::Response.new("Nothing").to_a
|
152
|
-
end
|
140
|
+
response = response_for(:app => incrementor, :cookie => response)
|
141
|
+
response.body.should.equal '{"counter"=>2}'
|
153
142
|
|
154
|
-
|
155
|
-
|
143
|
+
response = response_for(:app => incrementor, :cookie => response)
|
144
|
+
response.body.should.equal '{"counter"=>3}'
|
156
145
|
end
|
157
146
|
|
158
147
|
it "renew session id" do
|
159
|
-
|
160
|
-
|
161
|
-
|
148
|
+
response = response_for(:app => incrementor)
|
149
|
+
cookie = response['Set-Cookie']
|
150
|
+
response = response_for(:app => only_session_id, :cookie => cookie)
|
151
|
+
cookie = response['Set-Cookie'] if response['Set-Cookie']
|
162
152
|
|
163
|
-
|
164
|
-
old_session_id =
|
153
|
+
response.body.should.not.equal ""
|
154
|
+
old_session_id = response.body
|
165
155
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
get("/", "HTTP_COOKIE" => res["Set-Cookie"])
|
156
|
+
response = response_for(:app => renewer, :cookie => cookie)
|
157
|
+
cookie = response['Set-Cookie'] if response['Set-Cookie']
|
158
|
+
response = response_for(:app => only_session_id, :cookie => cookie)
|
170
159
|
|
171
|
-
|
172
|
-
|
160
|
+
response.body.should.not.equal ""
|
161
|
+
response.body.should.not.equal old_session_id
|
173
162
|
end
|
174
163
|
|
175
|
-
it "
|
176
|
-
|
177
|
-
|
178
|
-
|
164
|
+
it "destroys session" do
|
165
|
+
response = response_for(:app => incrementor)
|
166
|
+
response = response_for(:app => only_session_id, :cookie => response)
|
167
|
+
|
168
|
+
response.body.should.not.equal ""
|
169
|
+
old_session_id = response.body
|
179
170
|
|
180
|
-
|
181
|
-
|
182
|
-
|
171
|
+
response = response_for(:app => destroy_session, :cookie => response)
|
172
|
+
response = response_for(:app => only_session_id, :cookie => response)
|
173
|
+
|
174
|
+
response.body.should.not.equal ""
|
175
|
+
response.body.should.not.equal old_session_id
|
183
176
|
end
|
184
177
|
|
185
|
-
|
186
|
-
|
187
|
-
|
178
|
+
it "survives broken cookies" do
|
179
|
+
response = response_for(
|
180
|
+
:app => incrementor,
|
181
|
+
:cookie => "rack.session=blarghfasel"
|
182
|
+
)
|
183
|
+
response.body.should.equal '{"counter"=>1}'
|
184
|
+
|
185
|
+
response = response_for(
|
186
|
+
:app => [incrementor, { :secret => "test" }],
|
187
|
+
:cookie => "rack.session="
|
188
|
+
)
|
189
|
+
response.body.should.equal '{"counter"=>1}'
|
188
190
|
end
|
189
191
|
|
190
192
|
it "barks on too big cookies" do
|
191
193
|
lambda{
|
192
|
-
|
193
|
-
get("/", :fatal => true)
|
194
|
+
response_for(:app => bigcookie, :request => { :fatal => true })
|
194
195
|
}.should.raise(Rack::MockRequest::FatalWarning)
|
195
196
|
end
|
196
197
|
|
197
198
|
it "loads from a cookie with integrity hash" do
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
199
|
+
app = [incrementor, { :secret => "test" }]
|
200
|
+
|
201
|
+
response = response_for(:app => app)
|
202
|
+
response = response_for(:app => app, :cookie => response)
|
203
|
+
response.body.should.equal '{"counter"=>2}'
|
204
|
+
|
205
|
+
response = response_for(:app => app, :cookie => response)
|
206
|
+
response.body.should.equal '{"counter"=>3}'
|
207
|
+
|
208
|
+
app = [incrementor, { :secret => "other" }]
|
209
|
+
|
210
|
+
response = response_for(:app => app, :cookie => response)
|
211
|
+
response.body.should.equal '{"counter"=>1}'
|
210
212
|
end
|
211
213
|
|
212
214
|
it "loads from a cookie wih accept-only integrity hash for graceful key rotation" do
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
215
|
+
response = response_for(:app => [incrementor, { :secret => "test" }])
|
216
|
+
|
217
|
+
app = [incrementor, { :secret => "test2", :old_secret => "test" }]
|
218
|
+
response = response_for(:app => app, :cookie => response)
|
219
|
+
response.body.should.equal '{"counter"=>2}'
|
220
|
+
|
221
|
+
app = [incrementor, { :secret => "test3", :old_secret => "test2" }]
|
222
|
+
response = response_for(:app => app, :cookie => response)
|
223
|
+
response.body.should.equal '{"counter"=>3}'
|
222
224
|
end
|
223
225
|
|
224
226
|
it "ignores tampered with session cookies" do
|
225
|
-
app =
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
227
|
+
app = [incrementor, { :secret => "test" }]
|
228
|
+
response = response_for(:app => app)
|
229
|
+
response.body.should.equal '{"counter"=>1}'
|
230
|
+
|
231
|
+
response = response_for(:app => app, :cookie => response)
|
232
|
+
response.body.should.equal '{"counter"=>2}'
|
230
233
|
|
231
|
-
_, digest =
|
234
|
+
_, digest = response["Set-Cookie"].split("--")
|
232
235
|
tampered_with_cookie = "hackerman-was-here" + "--" + digest
|
233
|
-
response2 = Rack::MockRequest.new(app).get("/", "HTTP_COOKIE" =>
|
234
|
-
tampered_with_cookie)
|
235
236
|
|
236
|
-
|
237
|
-
|
237
|
+
response = response_for(:app => app, :cookie => tampered_with_cookie)
|
238
|
+
response.body.should.equal '{"counter"=>1}'
|
238
239
|
end
|
239
240
|
|
240
241
|
it "supports either of secret or old_secret" do
|
241
|
-
app =
|
242
|
-
|
243
|
-
|
244
|
-
res = Rack::MockRequest.new(app).get("/", "HTTP_COOKIE" => res["Set-Cookie"])
|
245
|
-
res.body.should.equal '{"counter"=>2}'
|
246
|
-
app = Rack::Session::Cookie.new(incrementor, :old_secret => 'test')
|
247
|
-
res = Rack::MockRequest.new(app).get("/")
|
248
|
-
res.body.should.equal '{"counter"=>1}'
|
249
|
-
res = Rack::MockRequest.new(app).get("/", "HTTP_COOKIE" => res["Set-Cookie"])
|
250
|
-
res.body.should.equal '{"counter"=>2}'
|
251
|
-
end
|
252
|
-
|
253
|
-
describe "1.9 bugs relating to inspecting yet-to-be-loaded from cookie data: Rack::Session::Abstract::SessionHash" do
|
254
|
-
|
255
|
-
it "can handle Rack::Lint middleware" do
|
256
|
-
app = Rack::Session::Cookie.new(incrementor)
|
257
|
-
res = Rack::MockRequest.new(app).get("/")
|
258
|
-
|
259
|
-
app = Rack::Session::Cookie.new(Rack::Lint.new(session_id))
|
260
|
-
res = Rack::MockRequest.new(app).get("/", "HTTP_COOKIE" => res["Set-Cookie"])
|
261
|
-
res.body.should.not.be.nil
|
262
|
-
end
|
242
|
+
app = [incrementor, { :secret => "test" }]
|
243
|
+
response = response_for(:app => app)
|
244
|
+
response.body.should.equal '{"counter"=>1}'
|
263
245
|
|
264
|
-
|
265
|
-
|
266
|
-
def initialize(app)
|
267
|
-
@app = app
|
268
|
-
end
|
269
|
-
def call(env)
|
270
|
-
env.inspect
|
271
|
-
@app.call(env)
|
272
|
-
end
|
273
|
-
end
|
246
|
+
response = response_for(:app => app, :cookie => response)
|
247
|
+
response.body.should.equal '{"counter"=>2}'
|
274
248
|
|
275
|
-
|
276
|
-
|
249
|
+
app = [incrementor, { :old_secret => "test" }]
|
250
|
+
response = response_for(:app => app)
|
251
|
+
response.body.should.equal '{"counter"=>1}'
|
252
|
+
|
253
|
+
response = response_for(:app => app, :cookie => response)
|
254
|
+
response.body.should.equal '{"counter"=>2}'
|
255
|
+
end
|
256
|
+
|
257
|
+
it "can handle Rack::Lint middleware" do
|
258
|
+
response = response_for(:app => incrementor)
|
259
|
+
|
260
|
+
lint = Rack::Lint.new(session_id)
|
261
|
+
response = response_for(:app => lint, :cookie => response)
|
262
|
+
response.body.should.not.be.nil
|
263
|
+
end
|
277
264
|
|
278
|
-
|
279
|
-
|
280
|
-
|
265
|
+
it "can handle middleware that inspects the env" do
|
266
|
+
class TestEnvInspector
|
267
|
+
def initialize(app)
|
268
|
+
@app = app
|
269
|
+
end
|
270
|
+
def call(env)
|
271
|
+
env.inspect
|
272
|
+
@app.call(env)
|
273
|
+
end
|
281
274
|
end
|
282
275
|
|
276
|
+
response = response_for(:app => incrementor)
|
277
|
+
|
278
|
+
inspector = TestEnvInspector.new(session_id)
|
279
|
+
response = response_for(:app => inspector, :cookie => response)
|
280
|
+
response.body.should.not.be.nil
|
283
281
|
end
|
284
282
|
|
285
283
|
it "returns the session id in the session hash" do
|
286
|
-
|
287
|
-
|
288
|
-
res.body.should.equal '{"counter"=>1}'
|
284
|
+
response = response_for(:app => incrementor)
|
285
|
+
response.body.should.equal '{"counter"=>1}'
|
289
286
|
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
res.body.should.match(/"counter"=>1/)
|
287
|
+
response = response_for(:app => session_id, :cookie => response)
|
288
|
+
response.body.should.match(/"session_id"=>/)
|
289
|
+
response.body.should.match(/"counter"=>1/)
|
294
290
|
end
|
295
291
|
|
296
292
|
it "does not return a cookie if set to secure but not using ssl" do
|
297
|
-
app =
|
298
|
-
res = Rack::MockRequest.new(app).get("/")
|
299
|
-
res["Set-Cookie"].should.be.nil
|
293
|
+
app = [incrementor, { :secure => true }]
|
300
294
|
|
301
|
-
|
302
|
-
|
303
|
-
|
295
|
+
response = response_for(:app => app)
|
296
|
+
response["Set-Cookie"].should.be.nil
|
297
|
+
|
298
|
+
response = response_for(:app => app, :request => { "HTTPS" => "on" })
|
299
|
+
response["Set-Cookie"].should.not.be.nil
|
300
|
+
response["Set-Cookie"].should.match(/secure/)
|
304
301
|
end
|
305
302
|
|
306
303
|
it "does not return a cookie if cookie was not read/written" do
|
307
|
-
|
308
|
-
|
309
|
-
res["Set-Cookie"].should.be.nil
|
304
|
+
response = response_for(:app => nothing)
|
305
|
+
response["Set-Cookie"].should.be.nil
|
310
306
|
end
|
311
307
|
|
312
308
|
it "does not return a cookie if cookie was not written (only read)" do
|
313
|
-
|
314
|
-
|
315
|
-
res["Set-Cookie"].should.be.nil
|
309
|
+
response = response_for(:app => session_id)
|
310
|
+
response["Set-Cookie"].should.be.nil
|
316
311
|
end
|
317
312
|
|
318
313
|
it "returns even if not read/written if :expire_after is set" do
|
319
|
-
app =
|
320
|
-
|
321
|
-
|
314
|
+
app = [nothing, { :expire_after => 3600 }]
|
315
|
+
request = { "rack.session" => { "not" => "empty" }}
|
316
|
+
response = response_for(:app => app, :request => request)
|
317
|
+
response["Set-Cookie"].should.not.be.nil
|
322
318
|
end
|
323
319
|
|
324
320
|
it "returns no cookie if no data was written and no session was created previously, even if :expire_after is set" do
|
325
|
-
app =
|
326
|
-
|
327
|
-
|
321
|
+
app = [nothing, { :expire_after => 3600 }]
|
322
|
+
response = response_for(:app => app)
|
323
|
+
response["Set-Cookie"].should.be.nil
|
328
324
|
end
|
329
325
|
|
330
326
|
it "exposes :secret in env['rack.session.option']" do
|
331
|
-
|
332
|
-
|
333
|
-
res.body.should == '"foo"'
|
327
|
+
response = response_for(:app => [session_option[:secret], { :secret => "foo" }])
|
328
|
+
response.body.should == '"foo"'
|
334
329
|
end
|
335
330
|
|
336
331
|
it "exposes :coder in env['rack.session.option']" do
|
337
|
-
|
338
|
-
|
339
|
-
res.body.should.match(/Base64::Marshal/)
|
332
|
+
response = response_for(:app => session_option[:coder])
|
333
|
+
response.body.should.match(/Base64::Marshal/)
|
340
334
|
end
|
341
335
|
|
342
336
|
it "allows passing in a hash with session data from middleware in front" do
|
343
|
-
app = Rack::Session::Cookie.new(session_id)
|
344
|
-
res = Rack::MockRequest.new(app).get("/", 'rack.session' => {:foo => 'bar'})
|
345
|
-
res.body.should.match(/foo/)
|
346
|
-
end
|
347
|
-
|
348
|
-
it "allows modifying session data with session data from middleware in front" do
|
349
337
|
request = { 'rack.session' => { :foo => 'bar' }}
|
350
|
-
response = response_for(:app =>
|
351
|
-
response.body.should.match(/counter/)
|
338
|
+
response = response_for(:app => session_id, :request => request)
|
352
339
|
response.body.should.match(/foo/)
|
353
340
|
end
|
354
341
|
|