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.

Files changed (60) hide show
  1. data/README.rdoc +2 -30
  2. data/Rakefile +1 -0
  3. data/SPEC +68 -4
  4. data/example/protectedlobster.rb +1 -1
  5. data/lib/rack.rb +2 -14
  6. data/lib/rack/auth/abstract/request.rb +1 -5
  7. data/lib/rack/builder.rb +8 -4
  8. data/lib/rack/cascade.rb +2 -2
  9. data/lib/rack/config.rb +5 -0
  10. data/lib/rack/deflater.rb +2 -1
  11. data/lib/rack/file.rb +25 -28
  12. data/lib/rack/handler.rb +18 -5
  13. data/lib/rack/handler/mongrel.rb +1 -1
  14. data/lib/rack/handler/scgi.rb +1 -1
  15. data/lib/rack/handler/thin.rb +6 -3
  16. data/lib/rack/handler/webrick.rb +1 -0
  17. data/lib/rack/head.rb +2 -0
  18. data/lib/rack/lint.rb +132 -7
  19. data/lib/rack/lobster.rb +3 -3
  20. data/lib/rack/lock.rb +2 -0
  21. data/lib/rack/methodoverride.rb +0 -2
  22. data/lib/rack/mime.rb +29 -0
  23. data/lib/rack/multipart/parser.rb +0 -9
  24. data/lib/rack/request.rb +66 -25
  25. data/lib/rack/response.rb +1 -2
  26. data/lib/rack/sendfile.rb +18 -4
  27. data/lib/rack/server.rb +20 -12
  28. data/lib/rack/session/abstract/id.rb +60 -59
  29. data/lib/rack/session/cookie.rb +11 -16
  30. data/lib/rack/utils.rb +97 -85
  31. data/rack.gemspec +1 -6
  32. data/test/spec_builder.rb +7 -0
  33. data/test/spec_cgi.rb +1 -1
  34. data/test/spec_chunked.rb +3 -5
  35. data/test/spec_content_length.rb +3 -6
  36. data/test/spec_deflater.rb +26 -9
  37. data/test/spec_fastcgi.rb +1 -1
  38. data/test/spec_file.rb +24 -11
  39. data/test/spec_head.rb +3 -8
  40. data/test/spec_lint.rb +6 -6
  41. data/test/spec_lock.rb +4 -7
  42. data/test/spec_methodoverride.rb +4 -1
  43. data/test/spec_mime.rb +51 -0
  44. data/test/spec_mongrel.rb +1 -1
  45. data/test/spec_multipart.rb +15 -49
  46. data/test/spec_nulllogger.rb +3 -6
  47. data/test/spec_request.rb +112 -18
  48. data/test/spec_response.rb +8 -8
  49. data/test/spec_sendfile.rb +52 -13
  50. data/test/spec_server.rb +6 -0
  51. data/test/spec_session_abstract_id.rb +11 -1
  52. data/test/spec_session_cookie.rb +140 -153
  53. data/test/spec_thin.rb +6 -1
  54. data/test/spec_utils.rb +23 -17
  55. data/test/spec_webrick.rb +1 -1
  56. metadata +37 -83
  57. checksums.yaml +0 -7
  58. data/test/cgi/lighttpd.errors +0 -1
  59. data/test/multipart/three_files_three_fields +0 -31
  60. data/test/spec_auth.rb +0 -57
@@ -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
- Enumerator.new(res[2]).to_a.should.equal ["Hello, World!"]
18
+ res[2].to_enum.to_a.should.equal ["Hello, World!"]
22
19
  end
23
20
  end
@@ -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
@@ -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 "Content-Type" => "text/html"
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 "Content-Type" => "text/html"
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 "text/html"
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
@@ -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 File.join(Dir.tmpdir, "rack_sendfile")
14
+ FileUtils.touch "/tmp/rack_sendfile"
16
15
  res = ['Hello World']
17
- def res.to_path ; File.join(Dir.tmpdir, "rack_sendfile") ; end
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=sendfile_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
- @request = Rack::MockRequest.new(sendfile_app)
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 request(headers={})
32
- yield @request.get('/', headers)
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 File.join(Dir.tmpdir, "rack_sendfile")
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 File.join(Dir.tmpdir, "rack_sendfile")
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' => "#{Dir.tmpdir}/=/foo/bar/"
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
- @request = Rack::MockRequest.new(sendfile_app(['Not a file...']))
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
@@ -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
- end
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
@@ -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
- cookie = Rack::Session::Cookie.new(incrementor, :coder => identity)
125
- res = Rack::MockRequest.new(cookie).get("/")
126
- res["Set-Cookie"].should.include("rack.session=")
127
- res.body.should.equal '{"counter"=>1}'
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
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).get("/")
133
- res["Set-Cookie"].should.include("rack.session=")
134
- res.body.should.equal '{"counter"=>1}'
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
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).get("/")
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
- renewer = lambda do |env|
150
- env["rack.session.options"][:renew] = true
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
- only_session_id = lambda do |env|
155
- Rack::Response.new(env["rack.session"]["session_id"].to_s).to_a
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
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).get("/")
160
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(only_session_id)).
161
- get("/", "HTTP_COOKIE" => res["Set-Cookie"])
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
- res.body.should.not.equal ""
164
- old_session_id = res.body
153
+ response.body.should.not.equal ""
154
+ old_session_id = response.body
165
155
 
166
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(renewer)).
167
- get("/", "HTTP_COOKIE" => res["Set-Cookie"])
168
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(only_session_id)).
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
- res.body.should.not.equal ""
172
- res.body.should.not.equal old_session_id
160
+ response.body.should.not.equal ""
161
+ response.body.should.not.equal old_session_id
173
162
  end
174
163
 
175
- it "survives broken cookies" do
176
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).
177
- get("/", "HTTP_COOKIE" => "rack.session=blarghfasel")
178
- res.body.should.equal '{"counter"=>1}'
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
- app = Rack::Session::Cookie.new(incrementor, :secret => 'test')
181
- res = Rack::MockRequest.new(app).get("/", "HTTP_COOKIE" => "rack.session=")
182
- res.body.should.equal '{"counter"=>1}'
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
- bigcookie = lambda do |env|
186
- env["rack.session"]["cookie"] = "big" * 3000
187
- Rack::Response.new(env["rack.session"].inspect).to_a
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
- Rack::MockRequest.new(Rack::Session::Cookie.new(bigcookie)).
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
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).get("/")
199
- cookie = res["Set-Cookie"]
200
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).
201
- get("/", "HTTP_COOKIE" => cookie)
202
- res.body.should.equal '{"counter"=>2}'
203
- cookie = res["Set-Cookie"]
204
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).
205
- get("/", "HTTP_COOKIE" => cookie)
206
- res.body.should.equal '{"counter"=>3}'
207
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'other')).
208
- get("/", "HTTP_COOKIE" => cookie)
209
- res.body.should.equal '{"counter"=>1}'
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
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).get("/")
214
- cookie = res["Set-Cookie"]
215
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test2', :old_secret => 'test')).
216
- get("/", "HTTP_COOKIE" => cookie)
217
- res.body.should.equal '{"counter"=>2}'
218
- cookie = res["Set-Cookie"]
219
- res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test3', :old_secret => 'test2')).
220
- get("/", "HTTP_COOKIE" => cookie)
221
- res.body.should.equal '{"counter"=>3}'
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 = Rack::Session::Cookie.new(incrementor, :secret => 'test')
226
- response1 = Rack::MockRequest.new(app).get("/")
227
- response1.body.should.equal '{"counter"=>1}'
228
- response1 = Rack::MockRequest.new(app).get("/", "HTTP_COOKIE" => response1["Set-Cookie"])
229
- response1.body.should.equal '{"counter"=>2}'
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 = response1["Set-Cookie"].split("--")
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
- # Tampered cookie was ignored. Counter is back to 1.
237
- response2.body.should.equal '{"counter"=>1}'
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 = Rack::Session::Cookie.new(incrementor, :secret => 'test')
242
- res = Rack::MockRequest.new(app).get("/")
243
- res.body.should.equal '{"counter"=>1}'
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
- it "can handle a middleware that inspects the env" do
265
- class TestEnvInspector
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
- app = Rack::Session::Cookie.new(incrementor)
276
- res = Rack::MockRequest.new(app).get("/")
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
- app = Rack::Session::Cookie.new(TestEnvInspector.new(session_id))
279
- res = Rack::MockRequest.new(app).get("/", "HTTP_COOKIE" => res["Set-Cookie"])
280
- res.body.should.not.be.nil
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
- app = Rack::Session::Cookie.new(incrementor)
287
- res = Rack::MockRequest.new(app).get("/")
288
- res.body.should.equal '{"counter"=>1}'
284
+ response = response_for(:app => incrementor)
285
+ response.body.should.equal '{"counter"=>1}'
289
286
 
290
- app = Rack::Session::Cookie.new(session_id)
291
- res = Rack::MockRequest.new(app).get("/", "HTTP_COOKIE" => res["Set-Cookie"])
292
- res.body.should.match(/"session_id"=>/)
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 = Rack::Session::Cookie.new(incrementor, :secure => true)
298
- res = Rack::MockRequest.new(app).get("/")
299
- res["Set-Cookie"].should.be.nil
293
+ app = [incrementor, { :secure => true }]
300
294
 
301
- res = Rack::MockRequest.new(app).get("/", "HTTPS" => "on")
302
- res["Set-Cookie"].should.not.be.nil
303
- res["Set-Cookie"].should.match(/secure/)
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
- app = Rack::Session::Cookie.new(nothing)
308
- res = Rack::MockRequest.new(app).get("/")
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
- app = Rack::Session::Cookie.new(session_id)
314
- res = Rack::MockRequest.new(app).get("/")
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 = Rack::Session::Cookie.new(nothing, :expire_after => 3600)
320
- res = Rack::MockRequest.new(app).get("/", 'rack.session' => {'not' => 'empty'})
321
- res["Set-Cookie"].should.not.be.nil
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 = Rack::Session::Cookie.new(nothing, :expire_after => 3600)
326
- res = Rack::MockRequest.new(app).get("/")
327
- res["Set-Cookie"].should.be.nil
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
- app = Rack::Session::Cookie.new(session_option[:secret], :secret => "foo")
332
- res = Rack::MockRequest.new(app).get("/")
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
- app = Rack::Session::Cookie.new(session_option[:coder])
338
- res = Rack::MockRequest.new(app).get("/")
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 => incrementor, :request => request)
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