rack 1.2.8 → 1.3.0.beta

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 (89) hide show
  1. data/README +9 -177
  2. data/Rakefile +2 -1
  3. data/SPEC +2 -2
  4. data/lib/rack.rb +2 -13
  5. data/lib/rack/auth/abstract/request.rb +7 -5
  6. data/lib/rack/auth/digest/md5.rb +6 -2
  7. data/lib/rack/auth/digest/params.rb +5 -7
  8. data/lib/rack/auth/digest/request.rb +1 -1
  9. data/lib/rack/backports/uri/common.rb +64 -0
  10. data/lib/rack/builder.rb +60 -3
  11. data/lib/rack/chunked.rb +29 -22
  12. data/lib/rack/conditionalget.rb +35 -16
  13. data/lib/rack/content_length.rb +3 -3
  14. data/lib/rack/deflater.rb +5 -2
  15. data/lib/rack/etag.rb +38 -10
  16. data/lib/rack/file.rb +76 -43
  17. data/lib/rack/handler.rb +13 -7
  18. data/lib/rack/handler/cgi.rb +0 -2
  19. data/lib/rack/handler/fastcgi.rb +13 -4
  20. data/lib/rack/handler/lsws.rb +0 -2
  21. data/lib/rack/handler/mongrel.rb +12 -2
  22. data/lib/rack/handler/scgi.rb +9 -1
  23. data/lib/rack/handler/thin.rb +7 -1
  24. data/lib/rack/handler/webrick.rb +12 -5
  25. data/lib/rack/lint.rb +2 -2
  26. data/lib/rack/lock.rb +29 -3
  27. data/lib/rack/methodoverride.rb +1 -1
  28. data/lib/rack/mime.rb +2 -2
  29. data/lib/rack/mock.rb +28 -33
  30. data/lib/rack/multipart.rb +34 -0
  31. data/lib/rack/multipart/generator.rb +93 -0
  32. data/lib/rack/multipart/parser.rb +164 -0
  33. data/lib/rack/multipart/uploaded_file.rb +30 -0
  34. data/lib/rack/request.rb +55 -19
  35. data/lib/rack/response.rb +10 -8
  36. data/lib/rack/sendfile.rb +14 -18
  37. data/lib/rack/server.rb +55 -8
  38. data/lib/rack/session/abstract/id.rb +233 -22
  39. data/lib/rack/session/cookie.rb +99 -46
  40. data/lib/rack/session/memcache.rb +30 -56
  41. data/lib/rack/session/pool.rb +22 -43
  42. data/lib/rack/showexceptions.rb +40 -11
  43. data/lib/rack/showstatus.rb +9 -2
  44. data/lib/rack/static.rb +29 -9
  45. data/lib/rack/urlmap.rb +6 -1
  46. data/lib/rack/utils.rb +67 -326
  47. data/rack.gemspec +2 -3
  48. data/test/builder/anything.rb +5 -0
  49. data/test/builder/comment.ru +4 -0
  50. data/test/builder/end.ru +3 -0
  51. data/test/builder/options.ru +2 -0
  52. data/test/cgi/lighttpd.conf +1 -1
  53. data/test/cgi/lighttpd.errors +412 -0
  54. data/test/multipart/content_type_and_no_filename +6 -0
  55. data/test/multipart/text +5 -0
  56. data/test/multipart/webkit +32 -0
  57. data/test/registering_handler/rack/handler/registering_myself.rb +8 -0
  58. data/test/spec_auth_digest.rb +20 -5
  59. data/test/spec_builder.rb +29 -0
  60. data/test/spec_cgi.rb +11 -0
  61. data/test/spec_chunked.rb +1 -1
  62. data/test/spec_commonlogger.rb +1 -1
  63. data/test/spec_conditionalget.rb +47 -0
  64. data/test/spec_content_length.rb +0 -6
  65. data/test/spec_content_type.rb +5 -5
  66. data/test/spec_deflater.rb +46 -2
  67. data/test/spec_etag.rb +68 -1
  68. data/test/spec_fastcgi.rb +11 -0
  69. data/test/spec_file.rb +54 -3
  70. data/test/spec_handler.rb +23 -5
  71. data/test/spec_lint.rb +2 -2
  72. data/test/spec_lock.rb +111 -5
  73. data/test/spec_methodoverride.rb +2 -2
  74. data/test/spec_mock.rb +3 -3
  75. data/test/spec_mongrel.rb +1 -2
  76. data/test/spec_multipart.rb +279 -0
  77. data/test/spec_request.rb +222 -38
  78. data/test/spec_response.rb +9 -3
  79. data/test/spec_server.rb +74 -0
  80. data/test/spec_session_abstract_id.rb +43 -0
  81. data/test/spec_session_cookie.rb +97 -15
  82. data/test/spec_session_memcache.rb +60 -50
  83. data/test/spec_session_pool.rb +63 -40
  84. data/test/spec_showexceptions.rb +64 -0
  85. data/test/spec_static.rb +23 -0
  86. data/test/spec_utils.rb +65 -351
  87. data/test/spec_webrick.rb +23 -4
  88. metadata +35 -15
  89. data/test/spec_auth.rb +0 -57
@@ -0,0 +1,43 @@
1
+ ### WARNING: there be hax in this file.
2
+
3
+ require 'rack/session/abstract/id'
4
+
5
+ describe Rack::Session::Abstract::ID do
6
+ id = Rack::Session::Abstract::ID
7
+
8
+ def silence_warning
9
+ o, $VERBOSE = $VERBOSE, nil
10
+ yield
11
+ ensure
12
+ $VERBOSE = o
13
+ end
14
+
15
+ def reload_id
16
+ $".delete $".find { |part| part =~ %r{session/abstract/id.rb} }
17
+ silence_warning { require 'rack/session/abstract/id' }
18
+ end
19
+
20
+ should "use securerandom when available" do
21
+ begin
22
+ fake = false
23
+ silence_warning do
24
+ ::SecureRandom = fake = true unless defined?(SecureRandom)
25
+ end
26
+ reload_id
27
+ id::DEFAULT_OPTIONS[:secure_random].should.eql(fake || SecureRandom)
28
+ ensure
29
+ Object.send(:remove_const, :SecureRandom) if fake
30
+ end
31
+ end
32
+
33
+ should "not use securerandom when unavailable" do
34
+ begin
35
+ sr = Object.send(:remove_const, :SecureRandom) if defined?(SecureRandom)
36
+ reload_id
37
+ id::DEFAULT_OPTIONS[:secure_random].should.eql false
38
+ ensure
39
+ ::SecureRandom = sr if defined?(sr)
40
+ end
41
+ end
42
+
43
+ end
@@ -5,26 +5,68 @@ describe Rack::Session::Cookie do
5
5
  incrementor = lambda do |env|
6
6
  env["rack.session"]["counter"] ||= 0
7
7
  env["rack.session"]["counter"] += 1
8
+ hash = env["rack.session"].dup
9
+ hash.delete("session_id")
10
+ Rack::Response.new(hash.inspect).to_a
11
+ end
12
+
13
+ session_id = lambda do |env|
8
14
  Rack::Response.new(env["rack.session"].inspect).to_a
9
15
  end
10
16
 
11
- before do
12
- @warnings = warnings = []
13
- Rack::Session::Cookie.class_eval do
14
- define_method(:warn) { |m| warnings << m }
15
- end
17
+ nothing = lambda do |env|
18
+ Rack::Response.new("Nothing").to_a
16
19
  end
17
20
 
18
- after do
19
- Rack::Session::Cookie.class_eval { remove_method :warn }
21
+ describe 'Base64' do
22
+ it 'uses base64 to encode' do
23
+ coder = Rack::Session::Cookie::Base64.new
24
+ str = 'fuuuuu'
25
+ coder.encode(str).should.equal [str].pack('m')
26
+ end
27
+
28
+ it 'uses base64 to decode' do
29
+ coder = Rack::Session::Cookie::Base64.new
30
+ str = ['fuuuuu'].pack('m')
31
+ coder.decode(str).should.equal str.unpack('m').first
32
+ end
33
+
34
+ describe 'Marshal' do
35
+ it 'marshals and base64 encodes' do
36
+ coder = Rack::Session::Cookie::Base64::Marshal.new
37
+ str = 'fuuuuu'
38
+ coder.encode(str).should.equal [::Marshal.dump(str)].pack('m')
39
+ end
40
+
41
+ it 'marshals and base64 decodes' do
42
+ coder = Rack::Session::Cookie::Base64::Marshal.new
43
+ str = [::Marshal.dump('fuuuuu')].pack('m')
44
+ coder.decode(str).should.equal ::Marshal.load(str.unpack('m').first)
45
+ end
46
+
47
+ it 'rescues failures on decode' do
48
+ coder = Rack::Session::Cookie::Base64::Marshal.new
49
+ coder.decode('lulz').should.equal nil
50
+ end
51
+ end
20
52
  end
21
53
 
22
- it "warns if no secret is given" do
23
- cookie = Rack::Session::Cookie.new(incrementor)
24
- @warnings.first.should =~ /no secret/i
25
- @warnings.clear
26
- cookie = Rack::Session::Cookie.new(incrementor, :secret => 'abc')
27
- @warnings.should.be.empty?
54
+ it 'uses a coder' do
55
+ identity = Class.new {
56
+ attr_reader :calls
57
+
58
+ def initialize
59
+ @calls = []
60
+ end
61
+
62
+ def encode(str); @calls << :encode; str; end
63
+ def decode(str); @calls << :decode; str; end
64
+ }.new
65
+ cookie = Rack::Session::Cookie.new(incrementor, :coder => identity)
66
+ res = Rack::MockRequest.new(cookie).get("/")
67
+ res["Set-Cookie"].should.include("rack.session=")
68
+ res.body.should.equal '{"counter"=>1}'
69
+ identity.calls.should.equal [:decode, :encode]
28
70
  end
29
71
 
30
72
  it "creates a new cookie" do
@@ -78,12 +120,52 @@ describe Rack::Session::Cookie do
78
120
  it "ignores tampered with session cookies" do
79
121
  app = Rack::Session::Cookie.new(incrementor, :secret => 'test')
80
122
  response1 = Rack::MockRequest.new(app).get("/")
123
+ response1.body.should.equal '{"counter"=>1}'
124
+
81
125
  _, digest = response1["Set-Cookie"].split("--")
82
126
  tampered_with_cookie = "hackerman-was-here" + "--" + digest
83
127
  response2 = Rack::MockRequest.new(app).get("/", "HTTP_COOKIE" =>
84
128
  tampered_with_cookie)
85
129
 
86
- # The tampered-with cookie is ignored, so we get back an identical Set-Cookie
87
- response2["Set-Cookie"].should.equal(response1["Set-Cookie"])
130
+ # Tampared cookie was ignored. Counter is back to 1.
131
+ response2.body.should.equal '{"counter"=>1}'
132
+ end
133
+
134
+ it "returns the session id in the session hash" do
135
+ app = Rack::Session::Cookie.new(incrementor)
136
+ res = Rack::MockRequest.new(app).get("/")
137
+ res.body.should.equal '{"counter"=>1}'
138
+
139
+ app = Rack::Session::Cookie.new(session_id)
140
+ res = Rack::MockRequest.new(app).get("/", "HTTP_COOKIE" => res["Set-Cookie"])
141
+ res.body.should.match(/"session_id"=>/)
142
+ res.body.should.match(/"counter"=>1/)
143
+ end
144
+
145
+ it "does not return a cookie if set to secure but not using ssl" do
146
+ app = Rack::Session::Cookie.new(incrementor, :secure => true)
147
+ res = Rack::MockRequest.new(app).get("/")
148
+ res["Set-Cookie"].should.be.nil
149
+
150
+ res = Rack::MockRequest.new(app).get("/", "HTTPS" => "on")
151
+ res["Set-Cookie"].should.not.be.nil
152
+ end
153
+
154
+ it "does not return a cookie if cookie was not read/written" do
155
+ app = Rack::Session::Cookie.new(nothing)
156
+ res = Rack::MockRequest.new(app).get("/")
157
+ res["Set-Cookie"].should.be.nil
158
+ end
159
+
160
+ it "does not return a cookie if cookie was not written (only read)" do
161
+ app = Rack::Session::Cookie.new(session_id)
162
+ res = Rack::MockRequest.new(app).get("/")
163
+ res["Set-Cookie"].should.be.nil
164
+ end
165
+
166
+ it "returns even if not read/written if :expire_after is set" do
167
+ app = Rack::Session::Cookie.new(nothing, :expire_after => 3600)
168
+ res = Rack::MockRequest.new(app).get("/")
169
+ res["Set-Cookie"].should.not.be.nil
88
170
  end
89
171
  end
@@ -24,16 +24,13 @@ begin
24
24
  incrementor.call(env)
25
25
  end
26
26
 
27
+ # test memcache connection
28
+ Rack::Session::Memcache.new(incrementor)
29
+
27
30
  it "faults on no connection" do
28
- if RUBY_VERSION < "1.9"
29
- lambda{
30
- Rack::Session::Memcache.new(incrementor, :memcache_server => 'nosuchserver')
31
- }.should.raise
32
- else
33
- lambda{
34
- Rack::Session::Memcache.new(incrementor, :memcache_server => 'nosuchserver')
35
- }.should.raise ArgumentError
36
- end
31
+ lambda{
32
+ Rack::Session::Memcache.new(incrementor, :memcache_server => 'nosuchserver')
33
+ }.should.raise
37
34
  end
38
35
 
39
36
  it "connects to existing server" do
@@ -64,6 +61,28 @@ begin
64
61
  body.should.equal '{"counter"=>3}'
65
62
  end
66
63
 
64
+ it "determines session only from a cookie by default" do
65
+ pool = Rack::Session::Memcache.new(incrementor)
66
+ req = Rack::MockRequest.new(pool)
67
+ res = req.get("/")
68
+ sid = res["Set-Cookie"][session_match, 1]
69
+ req.get("/?rack.session=#{sid}").
70
+ body.should.equal '{"counter"=>1}'
71
+ req.get("/?rack.session=#{sid}").
72
+ body.should.equal '{"counter"=>1}'
73
+ end
74
+
75
+ it "determines session from params" do
76
+ pool = Rack::Session::Memcache.new(incrementor, :cookie_only => false)
77
+ req = Rack::MockRequest.new(pool)
78
+ res = req.get("/")
79
+ sid = res["Set-Cookie"][session_match, 1]
80
+ req.get("/?rack.session=#{sid}").
81
+ body.should.equal '{"counter"=>2}'
82
+ req.get("/?rack.session=#{sid}").
83
+ body.should.equal '{"counter"=>3}'
84
+ end
85
+
67
86
  it "survives nonexistant cookies" do
68
87
  bad_cookie = "rack.session=blarghfasel"
69
88
  pool = Rack::Session::Memcache.new(incrementor)
@@ -89,23 +108,36 @@ begin
89
108
  res.body.should.include '"counter"=>1'
90
109
  end
91
110
 
92
- it "deletes cookies with :drop option" do
111
+ it "does not send the same session id if it did not change" do
93
112
  pool = Rack::Session::Memcache.new(incrementor)
94
113
  req = Rack::MockRequest.new(pool)
95
- drop = Rack::Utils::Context.new(pool, drop_session)
96
- dreq = Rack::MockRequest.new(drop)
97
114
 
98
115
  res0 = req.get("/")
99
- session = (cookie = res0["Set-Cookie"])[session_match]
116
+ cookie = res0["Set-Cookie"][session_match]
100
117
  res0.body.should.equal '{"counter"=>1}'
101
118
 
102
119
  res1 = req.get("/", "HTTP_COOKIE" => cookie)
103
- res1["Set-Cookie"][session_match].should.equal session
120
+ res1["Set-Cookie"].should.be.nil
104
121
  res1.body.should.equal '{"counter"=>2}'
105
122
 
123
+ res2 = req.get("/", "HTTP_COOKIE" => cookie)
124
+ res2["Set-Cookie"].should.be.nil
125
+ res2.body.should.equal '{"counter"=>3}'
126
+ end
127
+
128
+ it "deletes cookies with :drop option" do
129
+ pool = Rack::Session::Memcache.new(incrementor)
130
+ req = Rack::MockRequest.new(pool)
131
+ drop = Rack::Utils::Context.new(pool, drop_session)
132
+ dreq = Rack::MockRequest.new(drop)
133
+
134
+ res1 = req.get("/")
135
+ session = (cookie = res1["Set-Cookie"])[session_match]
136
+ res1.body.should.equal '{"counter"=>1}'
137
+
106
138
  res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
107
139
  res2["Set-Cookie"].should.equal nil
108
- res2.body.should.equal '{"counter"=>3}'
140
+ res2.body.should.equal '{"counter"=>2}'
109
141
 
110
142
  res3 = req.get("/", "HTTP_COOKIE" => cookie)
111
143
  res3["Set-Cookie"][session_match].should.not.equal session
@@ -118,50 +150,35 @@ begin
118
150
  renew = Rack::Utils::Context.new(pool, renew_session)
119
151
  rreq = Rack::MockRequest.new(renew)
120
152
 
121
- res0 = req.get("/")
122
- session = (cookie = res0["Set-Cookie"])[session_match]
123
- res0.body.should.equal '{"counter"=>1}'
124
-
125
- res1 = req.get("/", "HTTP_COOKIE" => cookie)
126
- res1["Set-Cookie"][session_match].should.equal session
127
- res1.body.should.equal '{"counter"=>2}'
153
+ res1 = req.get("/")
154
+ session = (cookie = res1["Set-Cookie"])[session_match]
155
+ res1.body.should.equal '{"counter"=>1}'
128
156
 
129
157
  res2 = rreq.get("/", "HTTP_COOKIE" => cookie)
130
158
  new_cookie = res2["Set-Cookie"]
131
159
  new_session = new_cookie[session_match]
132
160
  new_session.should.not.equal session
133
- res2.body.should.equal '{"counter"=>3}'
161
+ res2.body.should.equal '{"counter"=>2}'
134
162
 
135
163
  res3 = req.get("/", "HTTP_COOKIE" => new_cookie)
136
- res3["Set-Cookie"][session_match].should.equal new_session
137
- res3.body.should.equal '{"counter"=>4}'
164
+ res3.body.should.equal '{"counter"=>3}'
165
+
166
+ # Old cookie was deleted
167
+ res4 = req.get("/", "HTTP_COOKIE" => cookie)
168
+ res4.body.should.equal '{"counter"=>1}'
138
169
  end
139
170
 
140
171
  it "omits cookie with :defer option" do
141
172
  pool = Rack::Session::Memcache.new(incrementor)
142
- req = Rack::MockRequest.new(pool)
143
173
  defer = Rack::Utils::Context.new(pool, defer_session)
144
174
  dreq = Rack::MockRequest.new(defer)
145
175
 
146
- res0 = req.get("/")
147
- session = (cookie = res0["Set-Cookie"])[session_match]
176
+ res0 = dreq.get("/")
177
+ res0["Set-Cookie"].should.equal nil
148
178
  res0.body.should.equal '{"counter"=>1}'
149
-
150
- res1 = req.get("/", "HTTP_COOKIE" => cookie)
151
- res1["Set-Cookie"][session_match].should.equal session
152
- res1.body.should.equal '{"counter"=>2}'
153
-
154
- res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
155
- res2["Set-Cookie"].should.equal nil
156
- res2.body.should.equal '{"counter"=>3}'
157
-
158
- res3 = req.get("/", "HTTP_COOKIE" => cookie)
159
- res3["Set-Cookie"][session_match].should.equal session
160
- res3.body.should.equal '{"counter"=>4}'
161
179
  end
162
180
 
163
181
  it "updates deep hashes correctly" do
164
- store = nil
165
182
  hash_check = proc do |env|
166
183
  session = env['rack.session']
167
184
  unless session.include? 'test'
@@ -170,7 +187,7 @@ begin
170
187
  else
171
188
  session[:f][:g][:h] = :j
172
189
  end
173
- [200, {}, session.inspect]
190
+ [200, {}, [session.inspect]]
174
191
  end
175
192
  pool = Rack::Session::Memcache.new(hash_check)
176
193
  req = Rack::MockRequest.new(pool)
@@ -179,7 +196,7 @@ begin
179
196
  session_id = (cookie = res0["Set-Cookie"])[session_match, 1]
180
197
  ses0 = pool.pool.get(session_id, true)
181
198
 
182
- res1 = req.get("/", "HTTP_COOKIE" => cookie)
199
+ req.get("/", "HTTP_COOKIE" => cookie)
183
200
  ses1 = pool.pool.get(session_id, true)
184
201
 
185
202
  ses1.should.not.equal ses0
@@ -226,13 +243,6 @@ begin
226
243
 
227
244
  tnum = rand(7).to_i+5
228
245
  r = Array.new(tnum) do |i|
229
- delta_time = proc do |env|
230
- env['rack.session'][i] = Time.now
231
- Thread.stop
232
- env['rack.session'] = env['rack.session'].dup
233
- env['rack.session'][i] -= Time.now
234
- incrementor.call(env)
235
- end
236
246
  app = Rack::Utils::Context.new pool, time_delta
237
247
  req = Rack::MockRequest.new app
238
248
  Thread.new(req) do |run|
@@ -12,6 +12,14 @@ describe Rack::Session::Pool do
12
12
  Rack::Response.new(env["rack.session"].inspect).to_a
13
13
  end
14
14
 
15
+ session_id = lambda do |env|
16
+ Rack::Response.new(env["rack.session"].inspect).to_a
17
+ end
18
+
19
+ nothing = lambda do |env|
20
+ Rack::Response.new("Nothing").to_a
21
+ end
22
+
15
23
  drop_session = lambda do |env|
16
24
  env['rack.session.options'][:drop] = true
17
25
  incrementor.call(env)
@@ -51,25 +59,40 @@ describe Rack::Session::Pool do
51
59
  res.body.should.equal '{"counter"=>1}'
52
60
  end
53
61
 
54
- it "deletes cookies with :drop option" do
62
+ it "does not send the same session id if it did not change" do
55
63
  pool = Rack::Session::Pool.new(incrementor)
56
64
  req = Rack::MockRequest.new(pool)
57
- drop = Rack::Utils::Context.new(pool, drop_session)
58
- dreq = Rack::MockRequest.new(drop)
59
65
 
60
66
  res0 = req.get("/")
61
- session = (cookie = res0["Set-Cookie"])[session_match]
67
+ cookie = res0["Set-Cookie"][session_match]
62
68
  res0.body.should.equal '{"counter"=>1}'
63
69
  pool.pool.size.should.equal 1
64
70
 
65
71
  res1 = req.get("/", "HTTP_COOKIE" => cookie)
66
- res1["Set-Cookie"][session_match].should.equal session
72
+ res1["Set-Cookie"].should.be.nil
67
73
  res1.body.should.equal '{"counter"=>2}'
68
74
  pool.pool.size.should.equal 1
69
75
 
70
- res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
71
- res2["Set-Cookie"].should.equal nil
76
+ res2 = req.get("/", "HTTP_COOKIE" => cookie)
77
+ res2["Set-Cookie"].should.be.nil
72
78
  res2.body.should.equal '{"counter"=>3}'
79
+ pool.pool.size.should.equal 1
80
+ end
81
+
82
+ it "deletes cookies with :drop option" do
83
+ pool = Rack::Session::Pool.new(incrementor)
84
+ req = Rack::MockRequest.new(pool)
85
+ drop = Rack::Utils::Context.new(pool, drop_session)
86
+ dreq = Rack::MockRequest.new(drop)
87
+
88
+ res1 = req.get("/")
89
+ session = (cookie = res1["Set-Cookie"])[session_match]
90
+ res1.body.should.equal '{"counter"=>1}'
91
+ pool.pool.size.should.equal 1
92
+
93
+ res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
94
+ res2["Set-Cookie"].should.be.nil
95
+ res2.body.should.equal '{"counter"=>2}'
73
96
  pool.pool.size.should.equal 0
74
97
 
75
98
  res3 = req.get("/", "HTTP_COOKIE" => cookie)
@@ -84,53 +107,35 @@ describe Rack::Session::Pool do
84
107
  renew = Rack::Utils::Context.new(pool, renew_session)
85
108
  rreq = Rack::MockRequest.new(renew)
86
109
 
87
- res0 = req.get("/")
88
- session = (cookie = res0["Set-Cookie"])[session_match]
89
- res0.body.should.equal '{"counter"=>1}'
90
- pool.pool.size.should.equal 1
91
-
92
- res1 = req.get("/", "HTTP_COOKIE" => cookie)
93
- res1["Set-Cookie"][session_match].should.equal session
94
- res1.body.should.equal '{"counter"=>2}'
110
+ res1 = req.get("/")
111
+ session = (cookie = res1["Set-Cookie"])[session_match]
112
+ res1.body.should.equal '{"counter"=>1}'
95
113
  pool.pool.size.should.equal 1
96
114
 
97
115
  res2 = rreq.get("/", "HTTP_COOKIE" => cookie)
98
116
  new_cookie = res2["Set-Cookie"]
99
117
  new_session = new_cookie[session_match]
100
118
  new_session.should.not.equal session
101
- res2.body.should.equal '{"counter"=>3}'
119
+ res2.body.should.equal '{"counter"=>2}'
102
120
  pool.pool.size.should.equal 1
103
121
 
104
122
  res3 = req.get("/", "HTTP_COOKIE" => new_cookie)
105
- res3["Set-Cookie"][session_match].should.equal new_session
106
- res3.body.should.equal '{"counter"=>4}'
123
+ res3.body.should.equal '{"counter"=>3}'
107
124
  pool.pool.size.should.equal 1
125
+
126
+ res4 = req.get("/", "HTTP_COOKIE" => cookie)
127
+ res4.body.should.equal '{"counter"=>1}'
128
+ pool.pool.size.should.equal 2
108
129
  end
109
130
 
110
131
  it "omits cookie with :defer option" do
111
132
  pool = Rack::Session::Pool.new(incrementor)
112
- req = Rack::MockRequest.new(pool)
113
133
  defer = Rack::Utils::Context.new(pool, defer_session)
114
134
  dreq = Rack::MockRequest.new(defer)
115
135
 
116
- res0 = req.get("/")
117
- session = (cookie = res0["Set-Cookie"])[session_match]
118
- res0.body.should.equal '{"counter"=>1}'
119
- pool.pool.size.should.equal 1
120
-
121
- res1 = req.get("/", "HTTP_COOKIE" => cookie)
122
- res1["Set-Cookie"][session_match].should.equal session
123
- res1.body.should.equal '{"counter"=>2}'
124
- pool.pool.size.should.equal 1
125
-
126
- res2 = dreq.get("/", "HTTP_COOKIE" => cookie)
127
- res2["Set-Cookie"].should.equal nil
128
- res2.body.should.equal '{"counter"=>3}'
129
- pool.pool.size.should.equal 1
130
-
131
- res3 = req.get("/", "HTTP_COOKIE" => cookie)
132
- res3["Set-Cookie"][session_match].should.equal session
133
- res3.body.should.equal '{"counter"=>4}'
136
+ res1 = dreq.get("/")
137
+ res1["Set-Cookie"].should.equal nil
138
+ res1.body.should.equal '{"counter"=>1}'
134
139
  pool.pool.size.should.equal 1
135
140
  end
136
141
 
@@ -165,13 +170,31 @@ describe Rack::Session::Pool do
165
170
  run.get('/', "HTTP_COOKIE" => cookie, 'rack.multithread' => true)
166
171
  end
167
172
  end.reverse.map{|t| t.run.join.value }
168
- r.each do |res|
169
- res['Set-Cookie'].should.equal cookie
170
- res.body.should.include '"counter"=>2'
173
+ r.each do |resp|
174
+ resp['Set-Cookie'].should.equal cookie
175
+ resp.body.should.include '"counter"=>2'
171
176
  end
172
177
 
173
178
  session = pool.pool[sess_id]
174
179
  session.size.should.equal tnum+1 # counter
175
180
  session['counter'].should.equal 2 # meeeh
176
181
  end
182
+
183
+ it "does not return a cookie if cookie was not read/written" do
184
+ app = Rack::Session::Cookie.new(nothing)
185
+ res = Rack::MockRequest.new(app).get("/")
186
+ res["Set-Cookie"].should.be.nil
187
+ end
188
+
189
+ it "does not return a cookie if cookie was not written (only read)" do
190
+ app = Rack::Session::Cookie.new(session_id)
191
+ res = Rack::MockRequest.new(app).get("/")
192
+ res["Set-Cookie"].should.be.nil
193
+ end
194
+
195
+ it "returns even if not read/written if :expire_after is set" do
196
+ app = Rack::Session::Cookie.new(nothing, :expire_after => 3600)
197
+ res = Rack::MockRequest.new(app).get("/")
198
+ res["Set-Cookie"].should.not.be.nil
199
+ end
177
200
  end