rack 2.0.4 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack might be problematic. Click here for more details.

Files changed (187) hide show
  1. checksums.yaml +4 -4
  2. data/{HISTORY.md → CHANGELOG.md} +220 -155
  3. data/{COPYING → MIT-LICENSE} +4 -2
  4. data/README.rdoc +77 -119
  5. data/Rakefile +25 -18
  6. data/SPEC +3 -4
  7. data/bin/rackup +1 -0
  8. data/example/lobster.ru +2 -0
  9. data/example/protectedlobster.rb +3 -1
  10. data/example/protectedlobster.ru +2 -0
  11. data/lib/rack.rb +63 -60
  12. data/lib/rack/auth/abstract/handler.rb +3 -1
  13. data/lib/rack/auth/abstract/request.rb +2 -0
  14. data/lib/rack/auth/basic.rb +4 -1
  15. data/lib/rack/auth/digest/md5.rb +9 -7
  16. data/lib/rack/auth/digest/nonce.rb +6 -3
  17. data/lib/rack/auth/digest/params.rb +4 -2
  18. data/lib/rack/auth/digest/request.rb +2 -0
  19. data/lib/rack/body_proxy.rb +3 -6
  20. data/lib/rack/builder.rb +38 -15
  21. data/lib/rack/cascade.rb +6 -5
  22. data/lib/rack/chunked.rb +29 -6
  23. data/lib/rack/common_logger.rb +9 -8
  24. data/lib/rack/conditional_get.rb +3 -1
  25. data/lib/rack/config.rb +2 -0
  26. data/lib/rack/content_length.rb +3 -1
  27. data/lib/rack/content_type.rb +3 -1
  28. data/lib/rack/core_ext/regexp.rb +14 -0
  29. data/lib/rack/deflater.rb +28 -17
  30. data/lib/rack/directory.rb +17 -14
  31. data/lib/rack/etag.rb +3 -1
  32. data/lib/rack/events.rb +5 -3
  33. data/lib/rack/file.rb +5 -173
  34. data/lib/rack/files.rb +178 -0
  35. data/lib/rack/handler.rb +7 -2
  36. data/lib/rack/handler/cgi.rb +3 -1
  37. data/lib/rack/handler/fastcgi.rb +4 -2
  38. data/lib/rack/handler/lsws.rb +3 -1
  39. data/lib/rack/handler/scgi.rb +9 -6
  40. data/lib/rack/handler/thin.rb +3 -1
  41. data/lib/rack/handler/webrick.rb +4 -2
  42. data/lib/rack/head.rb +2 -0
  43. data/lib/rack/lint.rb +14 -11
  44. data/lib/rack/lobster.rb +7 -5
  45. data/lib/rack/lock.rb +2 -0
  46. data/lib/rack/logger.rb +2 -0
  47. data/lib/rack/media_type.rb +10 -5
  48. data/lib/rack/method_override.rb +9 -3
  49. data/lib/rack/mime.rb +9 -1
  50. data/lib/rack/mock.rb +74 -15
  51. data/lib/rack/multipart.rb +5 -3
  52. data/lib/rack/multipart/generator.rb +6 -7
  53. data/lib/rack/multipart/parser.rb +54 -51
  54. data/lib/rack/multipart/uploaded_file.rb +2 -0
  55. data/lib/rack/null_logger.rb +2 -0
  56. data/lib/rack/query_parser.rb +51 -25
  57. data/lib/rack/recursive.rb +7 -5
  58. data/lib/rack/reloader.rb +10 -4
  59. data/lib/rack/request.rb +89 -23
  60. data/lib/rack/response.rb +71 -31
  61. data/lib/rack/rewindable_input.rb +4 -2
  62. data/lib/rack/runtime.rb +4 -2
  63. data/lib/rack/sendfile.rb +15 -8
  64. data/lib/rack/server.rb +88 -16
  65. data/lib/rack/session/abstract/id.rb +104 -21
  66. data/lib/rack/session/cookie.rb +21 -11
  67. data/lib/rack/session/memcache.rb +4 -87
  68. data/lib/rack/session/pool.rb +17 -8
  69. data/lib/rack/show_exceptions.rb +16 -10
  70. data/lib/rack/show_status.rb +4 -2
  71. data/lib/rack/static.rb +15 -10
  72. data/lib/rack/tempfile_reaper.rb +2 -0
  73. data/lib/rack/urlmap.rb +11 -2
  74. data/lib/rack/utils.rb +55 -70
  75. data/rack.gemspec +19 -9
  76. metadata +32 -173
  77. data/test/builder/an_underscore_app.rb +0 -5
  78. data/test/builder/anything.rb +0 -5
  79. data/test/builder/comment.ru +0 -4
  80. data/test/builder/end.ru +0 -5
  81. data/test/builder/line.ru +0 -1
  82. data/test/builder/options.ru +0 -2
  83. data/test/cgi/assets/folder/test.js +0 -1
  84. data/test/cgi/assets/fonts/font.eot +0 -1
  85. data/test/cgi/assets/images/image.png +0 -1
  86. data/test/cgi/assets/index.html +0 -1
  87. data/test/cgi/assets/javascripts/app.js +0 -1
  88. data/test/cgi/assets/stylesheets/app.css +0 -1
  89. data/test/cgi/lighttpd.conf +0 -26
  90. data/test/cgi/rackup_stub.rb +0 -6
  91. data/test/cgi/sample_rackup.ru +0 -5
  92. data/test/cgi/test +0 -9
  93. data/test/cgi/test+directory/test+file +0 -1
  94. data/test/cgi/test.fcgi +0 -9
  95. data/test/cgi/test.gz +0 -0
  96. data/test/cgi/test.ru +0 -5
  97. data/test/gemloader.rb +0 -10
  98. data/test/helper.rb +0 -34
  99. data/test/multipart/bad_robots +0 -259
  100. data/test/multipart/binary +0 -0
  101. data/test/multipart/content_type_and_no_filename +0 -6
  102. data/test/multipart/empty +0 -10
  103. data/test/multipart/fail_16384_nofile +0 -814
  104. data/test/multipart/file1.txt +0 -1
  105. data/test/multipart/filename_and_modification_param +0 -7
  106. data/test/multipart/filename_and_no_name +0 -6
  107. data/test/multipart/filename_with_encoded_words +0 -7
  108. data/test/multipart/filename_with_escaped_quotes +0 -6
  109. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  110. data/test/multipart/filename_with_null_byte +0 -7
  111. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  112. data/test/multipart/filename_with_single_quote +0 -7
  113. data/test/multipart/filename_with_unescaped_percentages +0 -6
  114. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  115. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  116. data/test/multipart/filename_with_unescaped_quotes +0 -6
  117. data/test/multipart/ie +0 -6
  118. data/test/multipart/invalid_character +0 -6
  119. data/test/multipart/mixed_files +0 -21
  120. data/test/multipart/nested +0 -10
  121. data/test/multipart/none +0 -9
  122. data/test/multipart/quoted +0 -15
  123. data/test/multipart/rack-logo.png +0 -0
  124. data/test/multipart/semicolon +0 -6
  125. data/test/multipart/text +0 -15
  126. data/test/multipart/three_files_three_fields +0 -31
  127. data/test/multipart/unity3d_wwwform +0 -11
  128. data/test/multipart/webkit +0 -32
  129. data/test/rackup/config.ru +0 -31
  130. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  131. data/test/spec_auth_basic.rb +0 -89
  132. data/test/spec_auth_digest.rb +0 -260
  133. data/test/spec_body_proxy.rb +0 -85
  134. data/test/spec_builder.rb +0 -233
  135. data/test/spec_cascade.rb +0 -63
  136. data/test/spec_cgi.rb +0 -84
  137. data/test/spec_chunked.rb +0 -103
  138. data/test/spec_common_logger.rb +0 -95
  139. data/test/spec_conditional_get.rb +0 -103
  140. data/test/spec_config.rb +0 -23
  141. data/test/spec_content_length.rb +0 -86
  142. data/test/spec_content_type.rb +0 -46
  143. data/test/spec_deflater.rb +0 -375
  144. data/test/spec_directory.rb +0 -148
  145. data/test/spec_etag.rb +0 -108
  146. data/test/spec_events.rb +0 -133
  147. data/test/spec_fastcgi.rb +0 -85
  148. data/test/spec_file.rb +0 -264
  149. data/test/spec_handler.rb +0 -57
  150. data/test/spec_head.rb +0 -46
  151. data/test/spec_lint.rb +0 -515
  152. data/test/spec_lobster.rb +0 -59
  153. data/test/spec_lock.rb +0 -204
  154. data/test/spec_logger.rb +0 -24
  155. data/test/spec_media_type.rb +0 -42
  156. data/test/spec_method_override.rb +0 -96
  157. data/test/spec_mime.rb +0 -51
  158. data/test/spec_mock.rb +0 -359
  159. data/test/spec_multipart.rb +0 -722
  160. data/test/spec_null_logger.rb +0 -21
  161. data/test/spec_recursive.rb +0 -75
  162. data/test/spec_request.rb +0 -1393
  163. data/test/spec_response.rb +0 -510
  164. data/test/spec_rewindable_input.rb +0 -128
  165. data/test/spec_runtime.rb +0 -50
  166. data/test/spec_sendfile.rb +0 -125
  167. data/test/spec_server.rb +0 -193
  168. data/test/spec_session_abstract_id.rb +0 -31
  169. data/test/spec_session_abstract_session_hash.rb +0 -45
  170. data/test/spec_session_cookie.rb +0 -442
  171. data/test/spec_session_memcache.rb +0 -320
  172. data/test/spec_session_pool.rb +0 -210
  173. data/test/spec_show_exceptions.rb +0 -80
  174. data/test/spec_show_status.rb +0 -104
  175. data/test/spec_static.rb +0 -184
  176. data/test/spec_tempfile_reaper.rb +0 -64
  177. data/test/spec_thin.rb +0 -96
  178. data/test/spec_urlmap.rb +0 -237
  179. data/test/spec_utils.rb +0 -742
  180. data/test/spec_version.rb +0 -11
  181. data/test/spec_webrick.rb +0 -206
  182. data/test/static/another/index.html +0 -1
  183. data/test/static/foo.html +0 -1
  184. data/test/static/index.html +0 -1
  185. data/test/testrequest.rb +0 -78
  186. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  187. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
@@ -1,31 +0,0 @@
1
- require 'minitest/autorun'
2
- ### WARNING: there be hax in this file.
3
-
4
- require 'rack/session/abstract/id'
5
-
6
- describe Rack::Session::Abstract::ID do
7
- attr_reader :id
8
-
9
- def setup
10
- super
11
- @id = Rack::Session::Abstract::ID
12
- end
13
-
14
- it "use securerandom" do
15
- assert_equal ::SecureRandom, id::DEFAULT_OPTIONS[:secure_random]
16
-
17
- id = @id.new nil
18
- assert_equal ::SecureRandom, id.sid_secure
19
- end
20
-
21
- it "allow to use another securerandom provider" do
22
- secure_random = Class.new do
23
- def hex(*args)
24
- 'fake_hex'
25
- end
26
- end
27
- id = Rack::Session::Abstract::ID.new nil, :secure_random => secure_random.new
28
- id.send(:generate_sid).must_equal 'fake_hex'
29
- end
30
-
31
- end
@@ -1,45 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/session/abstract/id'
3
-
4
- describe Rack::Session::Abstract::SessionHash do
5
- attr_reader :hash
6
-
7
- def setup
8
- super
9
- store = Class.new do
10
- def load_session(req)
11
- ["id", {foo: :bar, baz: :qux}]
12
- end
13
- def session_exists?(req)
14
- true
15
- end
16
- end
17
- @hash = Rack::Session::Abstract::SessionHash.new(store.new, nil)
18
- end
19
-
20
- it "returns keys" do
21
- assert_equal ["foo", "baz"], hash.keys
22
- end
23
-
24
- it "returns values" do
25
- assert_equal [:bar, :qux], hash.values
26
- end
27
-
28
- describe "#fetch" do
29
- it "returns value for a matching key" do
30
- assert_equal :bar, hash.fetch(:foo)
31
- end
32
-
33
- it "works with a default value" do
34
- assert_equal :default, hash.fetch(:unknown, :default)
35
- end
36
-
37
- it "works with a block" do
38
- assert_equal :default, hash.fetch(:unkown) { :default }
39
- end
40
-
41
- it "it raises when fetching unknown keys without defaults" do
42
- lambda { hash.fetch(:unknown) }.must_raise KeyError
43
- end
44
- end
45
- end
@@ -1,442 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/session/cookie'
3
- require 'rack/lint'
4
- require 'rack/mock'
5
-
6
- describe Rack::Session::Cookie do
7
- incrementor = lambda do |env|
8
- env["rack.session"]["counter"] ||= 0
9
- env["rack.session"]["counter"] += 1
10
- hash = env["rack.session"].dup
11
- hash.delete("session_id")
12
- Rack::Response.new(hash.inspect).to_a
13
- end
14
-
15
- session_id = lambda do |env|
16
- Rack::Response.new(env["rack.session"].to_hash.inspect).to_a
17
- end
18
-
19
- session_option = lambda do |opt|
20
- lambda do |env|
21
- Rack::Response.new(env["rack.session.options"][opt].inspect).to_a
22
- end
23
- end
24
-
25
- nothing = lambda do |env|
26
- Rack::Response.new("Nothing").to_a
27
- end
28
-
29
- renewer = lambda do |env|
30
- env["rack.session.options"][:renew] = true
31
- Rack::Response.new("Nothing").to_a
32
- end
33
-
34
- only_session_id = lambda do |env|
35
- Rack::Response.new(env["rack.session"]["session_id"].to_s).to_a
36
- end
37
-
38
- bigcookie = lambda do |env|
39
- env["rack.session"]["cookie"] = "big" * 3000
40
- Rack::Response.new(env["rack.session"].inspect).to_a
41
- end
42
-
43
- destroy_session = lambda do |env|
44
- env["rack.session"].destroy
45
- Rack::Response.new("Nothing").to_a
46
- end
47
-
48
- def response_for(options={})
49
- request_options = options.fetch(:request, {})
50
- cookie = if options[:cookie].is_a?(Rack::Response)
51
- options[:cookie]["Set-Cookie"]
52
- else
53
- options[:cookie]
54
- end
55
- request_options["HTTP_COOKIE"] = cookie || ""
56
-
57
- app_with_cookie = Rack::Session::Cookie.new(*options[:app])
58
- app_with_cookie = Rack::Lint.new(app_with_cookie)
59
- Rack::MockRequest.new(app_with_cookie).get("/", request_options)
60
- end
61
-
62
- before do
63
- @warnings = warnings = []
64
- Rack::Session::Cookie.class_eval do
65
- define_method(:warn) { |m| warnings << m }
66
- end
67
- end
68
-
69
- after do
70
- Rack::Session::Cookie.class_eval { remove_method :warn }
71
- end
72
-
73
- describe 'Base64' do
74
- it 'uses base64 to encode' do
75
- coder = Rack::Session::Cookie::Base64.new
76
- str = 'fuuuuu'
77
- coder.encode(str).must_equal [str].pack('m')
78
- end
79
-
80
- it 'uses base64 to decode' do
81
- coder = Rack::Session::Cookie::Base64.new
82
- str = ['fuuuuu'].pack('m')
83
- coder.decode(str).must_equal str.unpack('m').first
84
- end
85
-
86
- describe 'Marshal' do
87
- it 'marshals and base64 encodes' do
88
- coder = Rack::Session::Cookie::Base64::Marshal.new
89
- str = 'fuuuuu'
90
- coder.encode(str).must_equal [::Marshal.dump(str)].pack('m')
91
- end
92
-
93
- it 'marshals and base64 decodes' do
94
- coder = Rack::Session::Cookie::Base64::Marshal.new
95
- str = [::Marshal.dump('fuuuuu')].pack('m')
96
- coder.decode(str).must_equal ::Marshal.load(str.unpack('m').first)
97
- end
98
-
99
- it 'rescues failures on decode' do
100
- coder = Rack::Session::Cookie::Base64::Marshal.new
101
- coder.decode('lulz').must_be_nil
102
- end
103
- end
104
-
105
- describe 'JSON' do
106
- it 'JSON and base64 encodes' do
107
- coder = Rack::Session::Cookie::Base64::JSON.new
108
- obj = %w[fuuuuu]
109
- coder.encode(obj).must_equal [::JSON.dump(obj)].pack('m')
110
- end
111
-
112
- it 'JSON and base64 decodes' do
113
- coder = Rack::Session::Cookie::Base64::JSON.new
114
- str = [::JSON.dump(%w[fuuuuu])].pack('m')
115
- coder.decode(str).must_equal ::JSON.parse(str.unpack('m').first)
116
- end
117
-
118
- it 'rescues failures on decode' do
119
- coder = Rack::Session::Cookie::Base64::JSON.new
120
- coder.decode('lulz').must_be_nil
121
- end
122
- end
123
-
124
- describe 'ZipJSON' do
125
- it 'jsons, deflates, and base64 encodes' do
126
- coder = Rack::Session::Cookie::Base64::ZipJSON.new
127
- obj = %w[fuuuuu]
128
- json = JSON.dump(obj)
129
- coder.encode(obj).must_equal [Zlib::Deflate.deflate(json)].pack('m')
130
- end
131
-
132
- it 'base64 decodes, inflates, and decodes json' do
133
- coder = Rack::Session::Cookie::Base64::ZipJSON.new
134
- obj = %w[fuuuuu]
135
- json = JSON.dump(obj)
136
- b64 = [Zlib::Deflate.deflate(json)].pack('m')
137
- coder.decode(b64).must_equal obj
138
- end
139
-
140
- it 'rescues failures on decode' do
141
- coder = Rack::Session::Cookie::Base64::ZipJSON.new
142
- coder.decode('lulz').must_be_nil
143
- end
144
- end
145
- end
146
-
147
- it "warns if no secret is given" do
148
- Rack::Session::Cookie.new(incrementor)
149
- @warnings.first.must_match(/no secret/i)
150
- @warnings.clear
151
- Rack::Session::Cookie.new(incrementor, :secret => 'abc')
152
- @warnings.must_be :empty?
153
- end
154
-
155
- it "doesn't warn if coder is configured to handle encoding" do
156
- Rack::Session::Cookie.new(
157
- incrementor,
158
- :coder => Object.new,
159
- :let_coder_handle_secure_encoding => true)
160
- @warnings.must_be :empty?
161
- end
162
-
163
- it "still warns if coder is not set" do
164
- Rack::Session::Cookie.new(
165
- incrementor,
166
- :let_coder_handle_secure_encoding => true)
167
- @warnings.first.must_match(/no secret/i)
168
- end
169
-
170
- it 'uses a coder' do
171
- identity = Class.new {
172
- attr_reader :calls
173
-
174
- def initialize
175
- @calls = []
176
- end
177
-
178
- def encode(str); @calls << :encode; str; end
179
- def decode(str); @calls << :decode; str; end
180
- }.new
181
- response = response_for(:app => [incrementor, { :coder => identity }])
182
-
183
- response["Set-Cookie"].must_include "rack.session="
184
- response.body.must_equal '{"counter"=>1}'
185
- identity.calls.must_equal [:decode, :encode]
186
- end
187
-
188
- it "creates a new cookie" do
189
- response = response_for(:app => incrementor)
190
- response["Set-Cookie"].must_include "rack.session="
191
- response.body.must_equal '{"counter"=>1}'
192
- end
193
-
194
- it "loads from a cookie" do
195
- response = response_for(:app => incrementor)
196
-
197
- response = response_for(:app => incrementor, :cookie => response)
198
- response.body.must_equal '{"counter"=>2}'
199
-
200
- response = response_for(:app => incrementor, :cookie => response)
201
- response.body.must_equal '{"counter"=>3}'
202
- end
203
-
204
- it "renew session id" do
205
- response = response_for(:app => incrementor)
206
- cookie = response['Set-Cookie']
207
- response = response_for(:app => only_session_id, :cookie => cookie)
208
- cookie = response['Set-Cookie'] if response['Set-Cookie']
209
-
210
- response.body.wont_equal ""
211
- old_session_id = response.body
212
-
213
- response = response_for(:app => renewer, :cookie => cookie)
214
- cookie = response['Set-Cookie'] if response['Set-Cookie']
215
- response = response_for(:app => only_session_id, :cookie => cookie)
216
-
217
- response.body.wont_equal ""
218
- response.body.wont_equal old_session_id
219
- end
220
-
221
- it "destroys session" do
222
- response = response_for(:app => incrementor)
223
- response = response_for(:app => only_session_id, :cookie => response)
224
-
225
- response.body.wont_equal ""
226
- old_session_id = response.body
227
-
228
- response = response_for(:app => destroy_session, :cookie => response)
229
- response = response_for(:app => only_session_id, :cookie => response)
230
-
231
- response.body.wont_equal ""
232
- response.body.wont_equal old_session_id
233
- end
234
-
235
- it "survives broken cookies" do
236
- response = response_for(
237
- :app => incrementor,
238
- :cookie => "rack.session=blarghfasel"
239
- )
240
- response.body.must_equal '{"counter"=>1}'
241
-
242
- response = response_for(
243
- :app => [incrementor, { :secret => "test" }],
244
- :cookie => "rack.session="
245
- )
246
- response.body.must_equal '{"counter"=>1}'
247
- end
248
-
249
- it "barks on too big cookies" do
250
- lambda{
251
- response_for(:app => bigcookie, :request => { :fatal => true })
252
- }.must_raise Rack::MockRequest::FatalWarning
253
- end
254
-
255
- it "loads from a cookie with integrity hash" do
256
- app = [incrementor, { :secret => "test" }]
257
-
258
- response = response_for(:app => app)
259
- response = response_for(:app => app, :cookie => response)
260
- response.body.must_equal '{"counter"=>2}'
261
-
262
- response = response_for(:app => app, :cookie => response)
263
- response.body.must_equal '{"counter"=>3}'
264
-
265
- app = [incrementor, { :secret => "other" }]
266
-
267
- response = response_for(:app => app, :cookie => response)
268
- response.body.must_equal '{"counter"=>1}'
269
- end
270
-
271
- it "loads from a cookie with accept-only integrity hash for graceful key rotation" do
272
- response = response_for(:app => [incrementor, { :secret => "test" }])
273
-
274
- app = [incrementor, { :secret => "test2", :old_secret => "test" }]
275
- response = response_for(:app => app, :cookie => response)
276
- response.body.must_equal '{"counter"=>2}'
277
-
278
- app = [incrementor, { :secret => "test3", :old_secret => "test2" }]
279
- response = response_for(:app => app, :cookie => response)
280
- response.body.must_equal '{"counter"=>3}'
281
- end
282
-
283
- it "ignores tampered with session cookies" do
284
- app = [incrementor, { :secret => "test" }]
285
- response = response_for(:app => app)
286
- response.body.must_equal '{"counter"=>1}'
287
-
288
- response = response_for(:app => app, :cookie => response)
289
- response.body.must_equal '{"counter"=>2}'
290
-
291
- _, digest = response["Set-Cookie"].split("--")
292
- tampered_with_cookie = "hackerman-was-here" + "--" + digest
293
-
294
- response = response_for(:app => app, :cookie => tampered_with_cookie)
295
- response.body.must_equal '{"counter"=>1}'
296
- end
297
-
298
- it "supports either of secret or old_secret" do
299
- app = [incrementor, { :secret => "test" }]
300
- response = response_for(:app => app)
301
- response.body.must_equal '{"counter"=>1}'
302
-
303
- response = response_for(:app => app, :cookie => response)
304
- response.body.must_equal '{"counter"=>2}'
305
-
306
- app = [incrementor, { :old_secret => "test" }]
307
- response = response_for(:app => app)
308
- response.body.must_equal '{"counter"=>1}'
309
-
310
- response = response_for(:app => app, :cookie => response)
311
- response.body.must_equal '{"counter"=>2}'
312
- end
313
-
314
- it "supports custom digest class" do
315
- app = [incrementor, { :secret => "test", hmac: OpenSSL::Digest::SHA256 }]
316
-
317
- response = response_for(:app => app)
318
- response = response_for(:app => app, :cookie => response)
319
- response.body.must_equal '{"counter"=>2}'
320
-
321
- response = response_for(:app => app, :cookie => response)
322
- response.body.must_equal '{"counter"=>3}'
323
-
324
- app = [incrementor, { :secret => "other" }]
325
-
326
- response = response_for(:app => app, :cookie => response)
327
- response.body.must_equal '{"counter"=>1}'
328
- end
329
-
330
- it "can handle Rack::Lint middleware" do
331
- response = response_for(:app => incrementor)
332
-
333
- lint = Rack::Lint.new(session_id)
334
- response = response_for(:app => lint, :cookie => response)
335
- response.body.wont_be :nil?
336
- end
337
-
338
- it "can handle middleware that inspects the env" do
339
- class TestEnvInspector
340
- def initialize(app)
341
- @app = app
342
- end
343
- def call(env)
344
- env.inspect
345
- @app.call(env)
346
- end
347
- end
348
-
349
- response = response_for(:app => incrementor)
350
-
351
- inspector = TestEnvInspector.new(session_id)
352
- response = response_for(:app => inspector, :cookie => response)
353
- response.body.wont_be :nil?
354
- end
355
-
356
- it "returns the session id in the session hash" do
357
- response = response_for(:app => incrementor)
358
- response.body.must_equal '{"counter"=>1}'
359
-
360
- response = response_for(:app => session_id, :cookie => response)
361
- response.body.must_match(/"session_id"=>/)
362
- response.body.must_match(/"counter"=>1/)
363
- end
364
-
365
- it "does not return a cookie if set to secure but not using ssl" do
366
- app = [incrementor, { :secure => true }]
367
-
368
- response = response_for(:app => app)
369
- response["Set-Cookie"].must_be_nil
370
-
371
- response = response_for(:app => app, :request => { "HTTPS" => "on" })
372
- response["Set-Cookie"].wont_be :nil?
373
- response["Set-Cookie"].must_match(/secure/)
374
- end
375
-
376
- it "does not return a cookie if cookie was not read/written" do
377
- response = response_for(:app => nothing)
378
- response["Set-Cookie"].must_be_nil
379
- end
380
-
381
- it "does not return a cookie if cookie was not written (only read)" do
382
- response = response_for(:app => session_id)
383
- response["Set-Cookie"].must_be_nil
384
- end
385
-
386
- it "returns even if not read/written if :expire_after is set" do
387
- app = [nothing, { :expire_after => 3600 }]
388
- request = { "rack.session" => { "not" => "empty" }}
389
- response = response_for(:app => app, :request => request)
390
- response["Set-Cookie"].wont_be :nil?
391
- end
392
-
393
- it "returns no cookie if no data was written and no session was created previously, even if :expire_after is set" do
394
- app = [nothing, { :expire_after => 3600 }]
395
- response = response_for(:app => app)
396
- response["Set-Cookie"].must_be_nil
397
- end
398
-
399
- it "exposes :secret in env['rack.session.option']" do
400
- response = response_for(:app => [session_option[:secret], { :secret => "foo" }])
401
- response.body.must_equal '"foo"'
402
- end
403
-
404
- it "exposes :coder in env['rack.session.option']" do
405
- response = response_for(:app => session_option[:coder])
406
- response.body.must_match(/Base64::Marshal/)
407
- end
408
-
409
- it "allows passing in a hash with session data from middleware in front" do
410
- request = { 'rack.session' => { :foo => 'bar' }}
411
- response = response_for(:app => session_id, :request => request)
412
- response.body.must_match(/foo/)
413
- end
414
-
415
- it "allows modifying session data with session data from middleware in front" do
416
- request = { 'rack.session' => { :foo => 'bar' }}
417
- response = response_for(:app => incrementor, :request => request)
418
- response.body.must_match(/counter/)
419
- response.body.must_match(/foo/)
420
- end
421
-
422
- it "allows more than one '--' in the cookie when calculating digests" do
423
- @counter = 0
424
- app = lambda do |env|
425
- env["rack.session"]["message"] ||= ""
426
- env["rack.session"]["message"] << "#{(@counter += 1).to_s}--"
427
- hash = env["rack.session"].dup
428
- hash.delete("session_id")
429
- Rack::Response.new(hash["message"]).to_a
430
- end
431
- # another example of an unsafe coder is Base64.urlsafe_encode64
432
- unsafe_coder = Class.new {
433
- def encode(hash); hash.inspect end
434
- def decode(str); eval(str) if str; end
435
- }.new
436
- _app = [ app, { :secret => "test", :coder => unsafe_coder } ]
437
- response = response_for(:app => _app)
438
- response.body.must_equal "1--"
439
- response = response_for(:app => _app, :cookie => response)
440
- response.body.must_equal "1--2--"
441
- end
442
- end