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.
- checksums.yaml +5 -5
- data/COPYING +1 -1
- data/HISTORY.md +138 -8
- data/README.rdoc +18 -28
- data/Rakefile +6 -14
- data/SPEC +10 -11
- data/contrib/rack_logo.svg +164 -111
- data/example/protectedlobster.rb +1 -1
- data/example/protectedlobster.ru +1 -1
- data/lib/rack.rb +70 -21
- data/lib/rack/auth/abstract/request.rb +5 -1
- data/lib/rack/auth/digest/params.rb +2 -3
- 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} +3 -3
- data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
- data/lib/rack/content_length.rb +2 -2
- data/lib/rack/deflater.rb +4 -39
- data/lib/rack/directory.rb +66 -54
- data/lib/rack/etag.rb +5 -4
- data/lib/rack/events.rb +154 -0
- data/lib/rack/file.rb +64 -40
- data/lib/rack/handler.rb +3 -25
- 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 +24 -26
- data/lib/rack/head.rb +15 -17
- data/lib/rack/lint.rb +40 -40
- data/lib/rack/lobster.rb +1 -1
- data/lib/rack/lock.rb +15 -10
- data/lib/rack/logger.rb +2 -2
- data/lib/rack/media_type.rb +38 -0
- data/lib/rack/{methodoverride.rb → method_override.rb} +6 -6
- data/lib/rack/mime.rb +18 -5
- data/lib/rack/mock.rb +36 -54
- data/lib/rack/multipart.rb +35 -6
- data/lib/rack/multipart/generator.rb +5 -5
- data/lib/rack/multipart/parser.rb +270 -157
- 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 +192 -0
- data/lib/rack/recursive.rb +8 -8
- data/lib/rack/request.rb +394 -305
- data/lib/rack/response.rb +130 -57
- 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 +30 -23
- data/lib/rack/session/abstract/id.rb +121 -75
- data/lib/rack/session/cookie.rb +25 -18
- data/lib/rack/session/memcache.rb +2 -2
- data/lib/rack/session/pool.rb +9 -9
- 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 +15 -14
- data/lib/rack/utils.rb +136 -211
- data/rack.gemspec +10 -9
- 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 +34 -0
- data/test/multipart/filename_with_encoded_words +7 -0
- data/test/multipart/filename_with_single_quote +7 -0
- data/test/multipart/quoted +15 -0
- data/test/multipart/rack-logo.png +0 -0
- data/test/multipart/unity3d_wwwform +11 -0
- data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
- data/test/spec_auth_basic.rb +27 -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 +37 -35
- 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 +85 -49
- data/test/spec_directory.rb +87 -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 +120 -77
- data/test/spec_handler.rb +19 -34
- data/test/spec_head.rb +15 -14
- data/test/spec_lint.rb +164 -199
- data/test/spec_lobster.rb +24 -23
- data/test/spec_lock.rb +79 -39
- data/test/spec_logger.rb +4 -3
- data/test/spec_media_type.rb +42 -0
- data/test/{spec_methodoverride.rb → spec_method_override.rb} +34 -35
- data/test/spec_mime.rb +19 -19
- data/test/spec_mock.rb +206 -144
- data/test/spec_multipart.rb +322 -200
- data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
- data/test/spec_recursive.rb +17 -14
- data/test/spec_request.rb +780 -605
- data/test/spec_response.rb +215 -112
- 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_abstract_session_hash.rb +45 -0
- data/test/spec_session_cookie.rb +99 -67
- data/test/spec_session_memcache.rb +60 -61
- data/test/spec_session_pool.rb +45 -44
- data/test/{spec_showexceptions.rb → spec_show_exceptions.rb} +22 -27
- 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 +441 -346
- data/test/spec_version.rb +2 -8
- data/test/spec_webrick.rb +93 -71
- 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 +92 -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_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
|
-
|
|
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
|
-
|
|
28
|
-
|
|
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(
|
|
32
|
-
|
|
27
|
+
def self.set(req, session)
|
|
28
|
+
req.set_header RACK_SESSION, session
|
|
33
29
|
end
|
|
34
30
|
|
|
35
|
-
def self.set_options(
|
|
36
|
-
|
|
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,
|
|
35
|
+
def initialize(store, req)
|
|
40
36
|
@store = store
|
|
41
|
-
@
|
|
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, @
|
|
43
|
+
@id = @store.send(:extract_session_id, @req)
|
|
48
44
|
end
|
|
49
45
|
|
|
50
46
|
def options
|
|
51
|
-
@
|
|
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
|
-
|
|
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(:
|
|
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?, @
|
|
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, @
|
|
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 #
|
|
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#
|
|
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']
|
|
186
|
-
# found within the options hash at the key :id. It is
|
|
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
|
|
200
|
+
class Persisted
|
|
195
201
|
DEFAULT_OPTIONS = {
|
|
196
|
-
:key =>
|
|
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 =>
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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(
|
|
255
|
-
session_was
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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 #
|
|
276
|
+
# environment to #find_session.
|
|
263
277
|
|
|
264
|
-
def load_session(
|
|
265
|
-
sid = current_session_id(
|
|
266
|
-
sid, session =
|
|
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(
|
|
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(
|
|
282
|
-
|
|
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?(
|
|
288
|
-
value = current_session_id(
|
|
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?(
|
|
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?(
|
|
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?(
|
|
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 #
|
|
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(
|
|
328
|
-
session =
|
|
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 =
|
|
333
|
-
return
|
|
344
|
+
session_id = delete_session(req, session.id || generate_sid, options)
|
|
345
|
+
return unless session_id
|
|
334
346
|
end
|
|
335
347
|
|
|
336
|
-
return
|
|
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 =
|
|
343
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
361
|
-
request = Rack::Request.new(env)
|
|
371
|
+
def set_cookie(request, res, cookie)
|
|
362
372
|
if request.cookies[@key] != cookie[:value] || cookie[:expires]
|
|
363
|
-
|
|
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
|
|
379
|
-
raise '#
|
|
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
|
|
387
|
-
|
|
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
|
|
394
|
-
|
|
439
|
+
def delete_session(req, sid, options)
|
|
440
|
+
destroy_session req.env, sid, options
|
|
395
441
|
end
|
|
396
442
|
end
|
|
397
443
|
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,7 +153,7 @@ module Rack
|
|
|
151
153
|
data
|
|
152
154
|
end
|
|
153
155
|
|
|
154
|
-
def
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|