rack 1.6.11 → 2.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. checksums.yaml +5 -5
  2. data/COPYING +1 -1
  3. data/HISTORY.md +138 -8
  4. data/README.rdoc +18 -28
  5. data/Rakefile +6 -14
  6. data/SPEC +10 -11
  7. data/contrib/rack_logo.svg +164 -111
  8. data/example/protectedlobster.rb +1 -1
  9. data/example/protectedlobster.ru +1 -1
  10. data/lib/rack.rb +70 -21
  11. data/lib/rack/auth/abstract/request.rb +5 -1
  12. data/lib/rack/auth/digest/params.rb +2 -3
  13. data/lib/rack/auth/digest/request.rb +1 -1
  14. data/lib/rack/body_proxy.rb +14 -9
  15. data/lib/rack/builder.rb +3 -3
  16. data/lib/rack/chunked.rb +5 -5
  17. data/lib/rack/{commonlogger.rb → common_logger.rb} +3 -3
  18. data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
  19. data/lib/rack/content_length.rb +2 -2
  20. data/lib/rack/deflater.rb +4 -39
  21. data/lib/rack/directory.rb +66 -54
  22. data/lib/rack/etag.rb +5 -4
  23. data/lib/rack/events.rb +154 -0
  24. data/lib/rack/file.rb +64 -40
  25. data/lib/rack/handler.rb +3 -25
  26. data/lib/rack/handler/cgi.rb +15 -16
  27. data/lib/rack/handler/fastcgi.rb +13 -14
  28. data/lib/rack/handler/lsws.rb +11 -11
  29. data/lib/rack/handler/scgi.rb +15 -15
  30. data/lib/rack/handler/thin.rb +3 -0
  31. data/lib/rack/handler/webrick.rb +24 -26
  32. data/lib/rack/head.rb +15 -17
  33. data/lib/rack/lint.rb +40 -40
  34. data/lib/rack/lobster.rb +1 -1
  35. data/lib/rack/lock.rb +15 -10
  36. data/lib/rack/logger.rb +2 -2
  37. data/lib/rack/media_type.rb +38 -0
  38. data/lib/rack/{methodoverride.rb → method_override.rb} +6 -6
  39. data/lib/rack/mime.rb +18 -5
  40. data/lib/rack/mock.rb +36 -54
  41. data/lib/rack/multipart.rb +35 -6
  42. data/lib/rack/multipart/generator.rb +5 -5
  43. data/lib/rack/multipart/parser.rb +270 -157
  44. data/lib/rack/multipart/uploaded_file.rb +1 -2
  45. data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
  46. data/lib/rack/query_parser.rb +192 -0
  47. data/lib/rack/recursive.rb +8 -8
  48. data/lib/rack/request.rb +394 -305
  49. data/lib/rack/response.rb +130 -57
  50. data/lib/rack/rewindable_input.rb +1 -12
  51. data/lib/rack/runtime.rb +10 -18
  52. data/lib/rack/sendfile.rb +5 -7
  53. data/lib/rack/server.rb +30 -23
  54. data/lib/rack/session/abstract/id.rb +121 -75
  55. data/lib/rack/session/cookie.rb +25 -18
  56. data/lib/rack/session/memcache.rb +2 -2
  57. data/lib/rack/session/pool.rb +9 -9
  58. data/lib/rack/show_exceptions.rb +386 -0
  59. data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
  60. data/lib/rack/static.rb +30 -5
  61. data/lib/rack/tempfile_reaper.rb +2 -2
  62. data/lib/rack/urlmap.rb +15 -14
  63. data/lib/rack/utils.rb +136 -211
  64. data/rack.gemspec +10 -9
  65. data/test/builder/an_underscore_app.rb +5 -0
  66. data/test/builder/options.ru +1 -1
  67. data/test/cgi/test.fcgi +1 -0
  68. data/test/cgi/test.gz +0 -0
  69. data/test/helper.rb +34 -0
  70. data/test/multipart/filename_with_encoded_words +7 -0
  71. data/test/multipart/filename_with_single_quote +7 -0
  72. data/test/multipart/quoted +15 -0
  73. data/test/multipart/rack-logo.png +0 -0
  74. data/test/multipart/unity3d_wwwform +11 -0
  75. data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
  76. data/test/spec_auth_basic.rb +27 -19
  77. data/test/spec_auth_digest.rb +47 -46
  78. data/test/spec_body_proxy.rb +27 -27
  79. data/test/spec_builder.rb +51 -41
  80. data/test/spec_cascade.rb +24 -22
  81. data/test/spec_cgi.rb +49 -67
  82. data/test/spec_chunked.rb +37 -35
  83. data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -21
  84. data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
  85. data/test/spec_config.rb +3 -2
  86. data/test/spec_content_length.rb +18 -17
  87. data/test/spec_content_type.rb +13 -12
  88. data/test/spec_deflater.rb +85 -49
  89. data/test/spec_directory.rb +87 -27
  90. data/test/spec_etag.rb +32 -31
  91. data/test/spec_events.rb +133 -0
  92. data/test/spec_fastcgi.rb +50 -72
  93. data/test/spec_file.rb +120 -77
  94. data/test/spec_handler.rb +19 -34
  95. data/test/spec_head.rb +15 -14
  96. data/test/spec_lint.rb +164 -199
  97. data/test/spec_lobster.rb +24 -23
  98. data/test/spec_lock.rb +79 -39
  99. data/test/spec_logger.rb +4 -3
  100. data/test/spec_media_type.rb +42 -0
  101. data/test/{spec_methodoverride.rb → spec_method_override.rb} +34 -35
  102. data/test/spec_mime.rb +19 -19
  103. data/test/spec_mock.rb +206 -144
  104. data/test/spec_multipart.rb +322 -200
  105. data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
  106. data/test/spec_recursive.rb +17 -14
  107. data/test/spec_request.rb +780 -605
  108. data/test/spec_response.rb +215 -112
  109. data/test/spec_rewindable_input.rb +50 -40
  110. data/test/spec_runtime.rb +11 -10
  111. data/test/spec_sendfile.rb +30 -35
  112. data/test/spec_server.rb +78 -52
  113. data/test/spec_session_abstract_id.rb +11 -33
  114. data/test/spec_session_abstract_session_hash.rb +45 -0
  115. data/test/spec_session_cookie.rb +99 -67
  116. data/test/spec_session_memcache.rb +60 -61
  117. data/test/spec_session_pool.rb +45 -44
  118. data/test/{spec_showexceptions.rb → spec_show_exceptions.rb} +22 -27
  119. data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
  120. data/test/spec_static.rb +71 -32
  121. data/test/spec_tempfile_reaper.rb +11 -10
  122. data/test/spec_thin.rb +55 -50
  123. data/test/spec_urlmap.rb +79 -78
  124. data/test/spec_utils.rb +441 -346
  125. data/test/spec_version.rb +2 -8
  126. data/test/spec_webrick.rb +93 -71
  127. data/test/static/foo.html +1 -0
  128. data/test/testrequest.rb +1 -1
  129. data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
  130. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
  131. metadata +92 -71
  132. data/KNOWN-ISSUES +0 -44
  133. data/lib/rack/backports/uri/common_18.rb +0 -56
  134. data/lib/rack/backports/uri/common_192.rb +0 -52
  135. data/lib/rack/backports/uri/common_193.rb +0 -29
  136. data/lib/rack/handler/evented_mongrel.rb +0 -8
  137. data/lib/rack/handler/mongrel.rb +0 -106
  138. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  139. data/lib/rack/showexceptions.rb +0 -387
  140. data/lib/rack/utils/okjson.rb +0 -600
  141. data/test/spec_mongrel.rb +0 -182
@@ -1,54 +1,50 @@
1
1
  # AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net
2
2
  # bugrep: Andreas Zehnder
3
3
 
4
+ require 'rack'
4
5
  require 'time'
5
6
  require 'rack/request'
6
7
  require 'rack/response'
7
- begin
8
- require 'securerandom'
9
- rescue LoadError
10
- # We just won't get securerandom
11
- end
8
+ require 'securerandom'
12
9
 
13
10
  module Rack
14
11
 
15
12
  module Session
16
13
 
17
14
  module Abstract
18
- ENV_SESSION_KEY = 'rack.session'.freeze
19
- ENV_SESSION_OPTIONS_KEY = 'rack.session.options'.freeze
20
-
21
15
  # SessionHash is responsible to lazily load the session from store.
22
16
 
23
17
  class SessionHash
24
18
  include Enumerable
25
19
  attr_writer :id
26
20
 
27
- def self.find(env)
28
- env[ENV_SESSION_KEY]
21
+ Unspecified = Object.new
22
+
23
+ def self.find(req)
24
+ req.get_header RACK_SESSION
29
25
  end
30
26
 
31
- def self.set(env, session)
32
- env[ENV_SESSION_KEY] = session
27
+ def self.set(req, session)
28
+ req.set_header RACK_SESSION, session
33
29
  end
34
30
 
35
- def self.set_options(env, options)
36
- env[ENV_SESSION_OPTIONS_KEY] = options.dup
31
+ def self.set_options(req, options)
32
+ req.set_header RACK_SESSION_OPTIONS, options.dup
37
33
  end
38
34
 
39
- def initialize(store, env)
35
+ def initialize(store, req)
40
36
  @store = store
41
- @env = env
37
+ @req = req
42
38
  @loaded = false
43
39
  end
44
40
 
45
41
  def id
46
42
  return @id if @loaded or instance_variable_defined?(:@id)
47
- @id = @store.send(:extract_session_id, @env)
43
+ @id = @store.send(:extract_session_id, @req)
48
44
  end
49
45
 
50
46
  def options
51
- @env[ENV_SESSION_OPTIONS_KEY]
47
+ @req.session_options
52
48
  end
53
49
 
54
50
  def each(&block)
@@ -60,7 +56,15 @@ module Rack
60
56
  load_for_read!
61
57
  @data[key.to_s]
62
58
  end
63
- alias :fetch :[]
59
+
60
+ def fetch(key, default=Unspecified, &block)
61
+ load_for_read!
62
+ if default == Unspecified
63
+ @data.fetch(key.to_s, &block)
64
+ else
65
+ @data.fetch(key.to_s, default, &block)
66
+ end
67
+ end
64
68
 
65
69
  def has_key?(key)
66
70
  load_for_read!
@@ -82,7 +86,7 @@ module Rack
82
86
 
83
87
  def destroy
84
88
  clear
85
- @id = @store.send(:destroy_session, @env, id, options)
89
+ @id = @store.send(:delete_session, @req, id, options)
86
90
  end
87
91
 
88
92
  def to_hash
@@ -117,7 +121,7 @@ module Rack
117
121
  def exists?
118
122
  return @exists if instance_variable_defined?(:@exists)
119
123
  @data = {}
120
- @exists = @store.send(:session_exists?, @env)
124
+ @exists = @store.send(:session_exists?, @req)
121
125
  end
122
126
 
123
127
  def loaded?
@@ -130,10 +134,12 @@ module Rack
130
134
  end
131
135
 
132
136
  def keys
137
+ load_for_read!
133
138
  @data.keys
134
139
  end
135
140
 
136
141
  def values
142
+ load_for_read!
137
143
  @data.values
138
144
  end
139
145
 
@@ -148,7 +154,7 @@ module Rack
148
154
  end
149
155
 
150
156
  def load!
151
- @id, session = @store.send(:load_session, @env)
157
+ @id, session = @store.send(:load_session, @req)
152
158
  @data = stringify_keys(session)
153
159
  @loaded = true
154
160
  end
@@ -164,14 +170,14 @@ module Rack
164
170
 
165
171
  # ID sets up a basic framework for implementing an id based sessioning
166
172
  # service. Cookies sent to the client for maintaining sessions will only
167
- # contain an id reference. Only #get_session and #set_session are
173
+ # contain an id reference. Only #find_session and #write_session are
168
174
  # required to be overwritten.
169
175
  #
170
176
  # All parameters are optional.
171
177
  # * :key determines the name of the cookie, by default it is
172
178
  # 'rack.session'
173
179
  # * :path, :domain, :expire_after, :secure, and :httponly set the related
174
- # cookie options as by Rack::Response#add_cookie
180
+ # cookie options as by Rack::Response#set_cookie
175
181
  # * :skip will not a set a cookie in the response nor update the session state
176
182
  # * :defer will not set a cookie in the response but still update the session
177
183
  # state if it is used with a backend
@@ -182,18 +188,18 @@ module Rack
182
188
  # id will be.
183
189
  #
184
190
  # These options can be set on a per request basis, at the location of
185
- # env['rack.session.options']. Additionally the id of the session can be
186
- # found within the options hash at the key :id. It is highly not
187
- # recommended to change its value.
191
+ # <tt>env['rack.session.options']</tt>. Additionally the id of the
192
+ # session can be found within the options hash at the key :id. It is
193
+ # highly not recommended to change its value.
188
194
  #
189
195
  # Is Rack::Utils::Context compatible.
190
196
  #
191
197
  # Not included by default; you must require 'rack/session/abstract/id'
192
198
  # to use.
193
199
 
194
- class ID
200
+ class Persisted
195
201
  DEFAULT_OPTIONS = {
196
- :key => 'rack.session',
202
+ :key => RACK_SESSION,
197
203
  :path => '/',
198
204
  :domain => nil,
199
205
  :expire_after => nil,
@@ -203,10 +209,10 @@ module Rack
203
209
  :renew => false,
204
210
  :sidbits => 128,
205
211
  :cookie_only => true,
206
- :secure_random => (::SecureRandom rescue false)
207
- }
212
+ :secure_random => ::SecureRandom
213
+ }.freeze
208
214
 
209
- attr_reader :key, :default_options
215
+ attr_reader :key, :default_options, :sid_secure
210
216
 
211
217
  def initialize(app, options={})
212
218
  @app = app
@@ -221,13 +227,20 @@ module Rack
221
227
  end
222
228
 
223
229
  def context(env, app=@app)
224
- prepare_session(env)
225
- status, headers, body = app.call(env)
226
- commit_session(env, status, headers, body)
230
+ req = make_request env
231
+ prepare_session(req)
232
+ status, headers, body = app.call(req.env)
233
+ res = Rack::Response::Raw.new status, headers
234
+ commit_session(req, res)
235
+ [status, headers, body]
227
236
  end
228
237
 
229
238
  private
230
239
 
240
+ def make_request(env)
241
+ Rack::Request.new env
242
+ end
243
+
231
244
  def initialize_sid
232
245
  @sidbits = @default_options[:sidbits]
233
246
  @sid_secure = @default_options[:secure_random]
@@ -251,26 +264,26 @@ module Rack
251
264
  # Sets the lazy session at 'rack.session' and places options and session
252
265
  # metadata into 'rack.session.options'.
253
266
 
254
- def prepare_session(env)
255
- session_was = env[ENV_SESSION_KEY]
256
- env[ENV_SESSION_KEY] = session_class.new(self, env)
257
- env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup
258
- env[ENV_SESSION_KEY].merge! session_was if session_was
267
+ def prepare_session(req)
268
+ session_was = req.get_header RACK_SESSION
269
+ session = session_class.new(self, req)
270
+ req.set_header RACK_SESSION, session
271
+ req.set_header RACK_SESSION_OPTIONS, @default_options.dup
272
+ session.merge! session_was if session_was
259
273
  end
260
274
 
261
275
  # Extracts the session id from provided cookies and passes it and the
262
- # environment to #get_session.
276
+ # environment to #find_session.
263
277
 
264
- def load_session(env)
265
- sid = current_session_id(env)
266
- sid, session = get_session(env, sid)
278
+ def load_session(req)
279
+ sid = current_session_id(req)
280
+ sid, session = find_session(req, sid)
267
281
  [sid, session || {}]
268
282
  end
269
283
 
270
284
  # Extract session id from request object.
271
285
 
272
- def extract_session_id(env)
273
- request = Rack::Request.new(env)
286
+ def extract_session_id(request)
274
287
  sid = request.cookies[@key]
275
288
  sid ||= request.params[@key] unless @cookie_only
276
289
  sid
@@ -278,26 +291,26 @@ module Rack
278
291
 
279
292
  # Returns the current session id from the SessionHash.
280
293
 
281
- def current_session_id(env)
282
- env[ENV_SESSION_KEY].id
294
+ def current_session_id(req)
295
+ req.get_header(RACK_SESSION).id
283
296
  end
284
297
 
285
298
  # Check if the session exists or not.
286
299
 
287
- def session_exists?(env)
288
- value = current_session_id(env)
300
+ def session_exists?(req)
301
+ value = current_session_id(req)
289
302
  value && !value.empty?
290
303
  end
291
304
 
292
305
  # Session should be committed if it was loaded, any of specific options like :renew, :drop
293
306
  # or :expire_after was given and the security permissions match. Skips if skip is given.
294
307
 
295
- def commit_session?(env, session, options)
308
+ def commit_session?(req, session, options)
296
309
  if options[:skip]
297
310
  false
298
311
  else
299
312
  has_session = loaded_session?(session) || forced_session_update?(session, options)
300
- has_session && security_matches?(env, options)
313
+ has_session && security_matches?(req, options)
301
314
  end
302
315
  end
303
316
 
@@ -313,54 +326,52 @@ module Rack
313
326
  options.values_at(:max_age, :renew, :drop, :defer, :expire_after).any?
314
327
  end
315
328
 
316
- def security_matches?(env, options)
329
+ def security_matches?(request, options)
317
330
  return true unless options[:secure]
318
- request = Rack::Request.new(env)
319
331
  request.ssl?
320
332
  end
321
333
 
322
334
  # Acquires the session from the environment and the session id from
323
- # the session options and passes them to #set_session. If successful
335
+ # the session options and passes them to #write_session. If successful
324
336
  # and the :defer option is not true, a cookie will be added to the
325
337
  # response with the session's id.
326
338
 
327
- def commit_session(env, status, headers, body)
328
- session = env[ENV_SESSION_KEY]
339
+ def commit_session(req, res)
340
+ session = req.get_header RACK_SESSION
329
341
  options = session.options
330
342
 
331
343
  if options[:drop] || options[:renew]
332
- session_id = destroy_session(env, session.id || generate_sid, options)
333
- return [status, headers, body] unless session_id
344
+ session_id = delete_session(req, session.id || generate_sid, options)
345
+ return unless session_id
334
346
  end
335
347
 
336
- return [status, headers, body] unless commit_session?(env, session, options)
348
+ return unless commit_session?(req, session, options)
337
349
 
338
350
  session.send(:load!) unless loaded_session?(session)
339
351
  session_id ||= session.id
340
352
  session_data = session.to_hash.delete_if { |k,v| v.nil? }
341
353
 
342
- if not data = set_session(env, session_id, session_data, options)
343
- env["rack.errors"].puts("Warning! #{self.class.name} failed to save session. Content dropped.")
354
+ if not data = write_session(req, session_id, session_data, options)
355
+ req.get_header(RACK_ERRORS).puts("Warning! #{self.class.name} failed to save session. Content dropped.")
344
356
  elsif options[:defer] and not options[:renew]
345
- env["rack.errors"].puts("Deferring cookie for #{session_id}") if $VERBOSE
357
+ req.get_header(RACK_ERRORS).puts("Deferring cookie for #{session_id}") if $VERBOSE
346
358
  else
347
359
  cookie = Hash.new
348
360
  cookie[:value] = data
349
361
  cookie[:expires] = Time.now + options[:expire_after] if options[:expire_after]
350
362
  cookie[:expires] = Time.now + options[:max_age] if options[:max_age]
351
- set_cookie(env, headers, cookie.merge!(options))
363
+ set_cookie(req, res, cookie.merge!(options))
352
364
  end
353
-
354
- [status, headers, body]
355
365
  end
366
+ public :commit_session
356
367
 
357
368
  # Sets the cookie back to the client with session id. We skip the cookie
358
369
  # setting if the value didn't change (sid is the same) or expires was given.
359
370
 
360
- def set_cookie(env, headers, cookie)
361
- request = Rack::Request.new(env)
371
+ def set_cookie(request, res, cookie)
362
372
  if request.cookies[@key] != cookie[:value] || cookie[:expires]
363
- Utils.set_cookie_header!(headers, @key, cookie)
373
+ res.set_cookie_header =
374
+ Utils.add_cookie_to_header(res.set_cookie_header, @key, cookie)
364
375
  end
365
376
  end
366
377
 
@@ -375,23 +386,58 @@ module Rack
375
386
  # If nil is provided as the session id, generation of a new valid id
376
387
  # should occur within.
377
388
 
378
- def get_session(env, sid)
379
- raise '#get_session not implemented.'
389
+ def find_session(env, sid)
390
+ raise '#find_session not implemented.'
391
+ end
392
+
393
+ # All thread safety and session storage procedures should occur here.
394
+ # Must return the session id if the session was saved successfully, or
395
+ # false if the session could not be saved.
396
+
397
+ def write_session(req, sid, session, options)
398
+ raise '#write_session not implemented.'
399
+ end
400
+
401
+ # All thread safety and session destroy procedures should occur here.
402
+ # Should return a new session id or nil if options[:drop]
403
+
404
+ def delete_session(req, sid, options)
405
+ raise '#delete_session not implemented'
406
+ end
407
+ end
408
+
409
+ class ID < Persisted
410
+ def self.inherited(klass)
411
+ k = klass.ancestors.find { |kl| kl.respond_to?(:superclass) && kl.superclass == ID }
412
+ unless k.instance_variable_defined?(:"@_rack_warned")
413
+ warn "#{klass} is inheriting from #{ID}. Inheriting from #{ID} is deprecated, please inherit from #{Persisted} instead" if $VERBOSE
414
+ k.instance_variable_set(:"@_rack_warned", true)
415
+ end
416
+ super
417
+ end
418
+
419
+ # All thread safety and session retrieval procedures should occur here.
420
+ # Should return [session_id, session].
421
+ # If nil is provided as the session id, generation of a new valid id
422
+ # should occur within.
423
+
424
+ def find_session(req, sid)
425
+ get_session req.env, sid
380
426
  end
381
427
 
382
428
  # All thread safety and session storage procedures should occur here.
383
429
  # Must return the session id if the session was saved successfully, or
384
430
  # false if the session could not be saved.
385
431
 
386
- def set_session(env, sid, session, options)
387
- raise '#set_session not implemented.'
432
+ def write_session(req, sid, session, options)
433
+ set_session req.env, sid, session, options
388
434
  end
389
435
 
390
436
  # All thread safety and session destroy procedures should occur here.
391
437
  # Should return a new session id or nil if options[:drop]
392
438
 
393
- def destroy_session(env, sid, options)
394
- raise '#destroy_session not implemented'
439
+ def delete_session(req, sid, options)
440
+ destroy_session req.env, sid, options
395
441
  end
396
442
  end
397
443
  end
@@ -3,6 +3,7 @@ require 'zlib'
3
3
  require 'rack/request'
4
4
  require 'rack/response'
5
5
  require 'rack/session/abstract/id'
6
+ require 'json'
6
7
 
7
8
  module Rack
8
9
 
@@ -44,7 +45,7 @@ module Rack
44
45
  # })
45
46
  #
46
47
 
47
- class Cookie < Abstract::ID
48
+ class Cookie < Abstract::Persisted
48
49
  # Encode session cookies as Base64
49
50
  class Base64
50
51
  def encode(str)
@@ -71,23 +72,23 @@ module Rack
71
72
  # valid JSON composite type, either a Hash or an Array.
72
73
  class JSON < Base64
73
74
  def encode(obj)
74
- super(::Rack::Utils::OkJson.encode(obj))
75
+ super(::JSON.dump(obj))
75
76
  end
76
77
 
77
78
  def decode(str)
78
79
  return unless str
79
- ::Rack::Utils::OkJson.decode(super(str)) rescue nil
80
+ ::JSON.parse(super(str)) rescue nil
80
81
  end
81
82
  end
82
83
 
83
84
  class ZipJSON < Base64
84
85
  def encode(obj)
85
- super(Zlib::Deflate.deflate(::Rack::Utils::OkJson.encode(obj)))
86
+ super(Zlib::Deflate.deflate(::JSON.dump(obj)))
86
87
  end
87
88
 
88
89
  def decode(str)
89
90
  return unless str
90
- ::Rack::Utils::OkJson.decode(Zlib::Inflate.inflate(super(str)))
91
+ ::JSON.parse(Zlib::Inflate.inflate(super(str)))
91
92
  rescue
92
93
  nil
93
94
  end
@@ -104,7 +105,9 @@ module Rack
104
105
 
105
106
  def initialize(app, options={})
106
107
  @secrets = options.values_at(:secret, :old_secret).compact
107
- warn <<-MSG unless @secrets.size >= 1
108
+ @hmac = options.fetch(:hmac, OpenSSL::Digest::SHA1)
109
+
110
+ warn <<-MSG unless secure?(options)
108
111
  SECURITY WARNING: No secret option provided to Rack::Session::Cookie.
109
112
  This poses a security threat. It is strongly recommended that you
110
113
  provide a secret to prevent exploits that may be possible from crafted
@@ -119,19 +122,18 @@ module Rack
119
122
 
120
123
  private
121
124
 
122
- def get_session(env, sid)
123
- data = unpacked_cookie_data(env)
125
+ def find_session(req, sid)
126
+ data = unpacked_cookie_data(req)
124
127
  data = persistent_session_id!(data)
125
128
  [data["session_id"], data]
126
129
  end
127
130
 
128
- def extract_session_id(env)
129
- unpacked_cookie_data(env)["session_id"]
131
+ def extract_session_id(request)
132
+ unpacked_cookie_data(request)["session_id"]
130
133
  end
131
134
 
132
- def unpacked_cookie_data(env)
133
- env["rack.session.unpacked_cookie_data"] ||= begin
134
- request = Rack::Request.new(env)
135
+ def unpacked_cookie_data(request)
136
+ request.fetch_header(RACK_SESSION_UNPACKED_COOKIE_DATA) do |k|
135
137
  session_data = request.cookies[@key]
136
138
 
137
139
  if @secrets.size > 0 && session_data
@@ -141,7 +143,7 @@ module Rack
141
143
  session_data = nil unless digest_match?(session_data, digest)
142
144
  end
143
145
 
144
- coder.decode(session_data) || {}
146
+ request.set_header(k, coder.decode(session_data) || {})
145
147
  end
146
148
  end
147
149
 
@@ -151,7 +153,7 @@ module Rack
151
153
  data
152
154
  end
153
155
 
154
- def set_session(env, session_id, session, options)
156
+ def write_session(req, session_id, session, options)
155
157
  session = session.merge("session_id" => session_id)
156
158
  session_data = coder.encode(session)
157
159
 
@@ -160,14 +162,14 @@ module Rack
160
162
  end
161
163
 
162
164
  if session_data.size > (4096 - @key.size)
163
- env["rack.errors"].puts("Warning! Rack::Session::Cookie data size exceeds 4K.")
165
+ req.get_header(RACK_ERRORS).puts("Warning! Rack::Session::Cookie data size exceeds 4K.")
164
166
  nil
165
167
  else
166
168
  session_data
167
169
  end
168
170
  end
169
171
 
170
- def destroy_session(env, session_id, options)
172
+ def delete_session(req, session_id, options)
171
173
  # Nothing to do here, data is in the client
172
174
  generate_sid unless options[:drop]
173
175
  end
@@ -180,7 +182,12 @@ module Rack
180
182
  end
181
183
 
182
184
  def generate_hmac(data, secret)
183
- OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, secret, data)
185
+ OpenSSL::HMAC.hexdigest(@hmac.new, secret, data)
186
+ end
187
+
188
+ def secure?(options)
189
+ @secrets.size >= 1 ||
190
+ (options[:coder] && options[:let_coder_handle_secure_encoding])
184
191
  end
185
192
 
186
193
  end