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