rack 2.0.6 → 2.1.2
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 +4 -4
- data/CHANGELOG.md +69 -0
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +77 -117
- data/Rakefile +25 -18
- data/SPEC +3 -4
- data/bin/rackup +1 -0
- data/example/lobster.ru +2 -0
- data/example/protectedlobster.rb +3 -1
- data/example/protectedlobster.ru +2 -0
- data/lib/rack.rb +63 -60
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +2 -0
- data/lib/rack/auth/basic.rb +4 -1
- data/lib/rack/auth/digest/md5.rb +9 -7
- data/lib/rack/auth/digest/nonce.rb +6 -3
- data/lib/rack/auth/digest/params.rb +4 -2
- data/lib/rack/auth/digest/request.rb +2 -0
- data/lib/rack/body_proxy.rb +3 -6
- data/lib/rack/builder.rb +39 -15
- data/lib/rack/cascade.rb +6 -5
- data/lib/rack/chunked.rb +29 -6
- data/lib/rack/common_logger.rb +9 -8
- data/lib/rack/conditional_get.rb +3 -1
- data/lib/rack/config.rb +2 -0
- data/lib/rack/content_length.rb +3 -1
- data/lib/rack/content_type.rb +3 -1
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +32 -17
- data/lib/rack/directory.rb +17 -14
- data/lib/rack/etag.rb +3 -1
- data/lib/rack/events.rb +5 -3
- data/lib/rack/file.rb +4 -173
- data/lib/rack/files.rb +178 -0
- data/lib/rack/handler.rb +7 -2
- data/lib/rack/handler/cgi.rb +3 -1
- data/lib/rack/handler/fastcgi.rb +4 -2
- data/lib/rack/handler/lsws.rb +3 -1
- data/lib/rack/handler/scgi.rb +9 -6
- data/lib/rack/handler/thin.rb +3 -1
- data/lib/rack/handler/webrick.rb +4 -2
- data/lib/rack/head.rb +2 -0
- data/lib/rack/lint.rb +14 -11
- data/lib/rack/lobster.rb +7 -5
- data/lib/rack/lock.rb +2 -0
- data/lib/rack/logger.rb +2 -0
- data/lib/rack/media_type.rb +10 -5
- data/lib/rack/method_override.rb +4 -2
- data/lib/rack/mime.rb +9 -1
- data/lib/rack/mock.rb +74 -15
- data/lib/rack/multipart.rb +5 -3
- data/lib/rack/multipart/generator.rb +6 -7
- data/lib/rack/multipart/parser.rb +55 -52
- data/lib/rack/multipart/uploaded_file.rb +2 -0
- data/lib/rack/null_logger.rb +2 -0
- data/lib/rack/query_parser.rb +51 -25
- data/lib/rack/recursive.rb +7 -5
- data/lib/rack/reloader.rb +10 -4
- data/lib/rack/request.rb +80 -27
- data/lib/rack/response.rb +71 -31
- data/lib/rack/rewindable_input.rb +4 -2
- data/lib/rack/runtime.rb +4 -2
- data/lib/rack/sendfile.rb +15 -8
- data/lib/rack/server.rb +88 -18
- data/lib/rack/session/abstract/id.rb +96 -21
- data/lib/rack/session/cookie.rb +21 -11
- data/lib/rack/session/memcache.rb +4 -87
- data/lib/rack/session/pool.rb +17 -8
- data/lib/rack/show_exceptions.rb +15 -9
- data/lib/rack/show_status.rb +4 -2
- data/lib/rack/static.rb +15 -10
- data/lib/rack/tempfile_reaper.rb +2 -0
- data/lib/rack/urlmap.rb +11 -2
- data/lib/rack/utils.rb +55 -70
- data/rack.gemspec +17 -7
- metadata +30 -171
- data/HISTORY.md +0 -505
- data/test/builder/an_underscore_app.rb +0 -5
- data/test/builder/anything.rb +0 -5
- data/test/builder/comment.ru +0 -4
- data/test/builder/end.ru +0 -5
- data/test/builder/line.ru +0 -1
- data/test/builder/options.ru +0 -2
- data/test/cgi/assets/folder/test.js +0 -1
- data/test/cgi/assets/fonts/font.eot +0 -1
- data/test/cgi/assets/images/image.png +0 -1
- data/test/cgi/assets/index.html +0 -1
- data/test/cgi/assets/javascripts/app.js +0 -1
- data/test/cgi/assets/stylesheets/app.css +0 -1
- data/test/cgi/lighttpd.conf +0 -26
- data/test/cgi/rackup_stub.rb +0 -6
- data/test/cgi/sample_rackup.ru +0 -5
- data/test/cgi/test +0 -9
- data/test/cgi/test+directory/test+file +0 -1
- data/test/cgi/test.fcgi +0 -9
- data/test/cgi/test.gz +0 -0
- data/test/cgi/test.ru +0 -5
- data/test/gemloader.rb +0 -10
- data/test/helper.rb +0 -34
- data/test/multipart/bad_robots +0 -259
- data/test/multipart/binary +0 -0
- data/test/multipart/content_type_and_no_filename +0 -6
- data/test/multipart/empty +0 -10
- data/test/multipart/fail_16384_nofile +0 -814
- data/test/multipart/file1.txt +0 -1
- data/test/multipart/filename_and_modification_param +0 -7
- data/test/multipart/filename_and_no_name +0 -6
- data/test/multipart/filename_with_encoded_words +0 -7
- data/test/multipart/filename_with_escaped_quotes +0 -6
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
- data/test/multipart/filename_with_null_byte +0 -7
- data/test/multipart/filename_with_percent_escaped_quotes +0 -6
- data/test/multipart/filename_with_single_quote +0 -7
- data/test/multipart/filename_with_unescaped_percentages +0 -6
- data/test/multipart/filename_with_unescaped_percentages2 +0 -6
- data/test/multipart/filename_with_unescaped_percentages3 +0 -6
- data/test/multipart/filename_with_unescaped_quotes +0 -6
- data/test/multipart/ie +0 -6
- data/test/multipart/invalid_character +0 -6
- data/test/multipart/mixed_files +0 -21
- data/test/multipart/nested +0 -10
- data/test/multipart/none +0 -9
- data/test/multipart/quoted +0 -15
- data/test/multipart/rack-logo.png +0 -0
- data/test/multipart/semicolon +0 -6
- data/test/multipart/text +0 -15
- data/test/multipart/three_files_three_fields +0 -31
- data/test/multipart/unity3d_wwwform +0 -11
- data/test/multipart/webkit +0 -32
- data/test/rackup/config.ru +0 -31
- data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
- data/test/spec_auth_basic.rb +0 -89
- data/test/spec_auth_digest.rb +0 -260
- data/test/spec_body_proxy.rb +0 -85
- data/test/spec_builder.rb +0 -233
- data/test/spec_cascade.rb +0 -63
- data/test/spec_cgi.rb +0 -84
- data/test/spec_chunked.rb +0 -103
- data/test/spec_common_logger.rb +0 -95
- data/test/spec_conditional_get.rb +0 -103
- data/test/spec_config.rb +0 -23
- data/test/spec_content_length.rb +0 -86
- data/test/spec_content_type.rb +0 -46
- data/test/spec_deflater.rb +0 -375
- data/test/spec_directory.rb +0 -148
- data/test/spec_etag.rb +0 -108
- data/test/spec_events.rb +0 -133
- data/test/spec_fastcgi.rb +0 -85
- data/test/spec_file.rb +0 -264
- data/test/spec_handler.rb +0 -57
- data/test/spec_head.rb +0 -46
- data/test/spec_lint.rb +0 -515
- data/test/spec_lobster.rb +0 -59
- data/test/spec_lock.rb +0 -204
- data/test/spec_logger.rb +0 -24
- data/test/spec_media_type.rb +0 -42
- data/test/spec_method_override.rb +0 -110
- data/test/spec_mime.rb +0 -51
- data/test/spec_mock.rb +0 -359
- data/test/spec_multipart.rb +0 -722
- data/test/spec_null_logger.rb +0 -21
- data/test/spec_recursive.rb +0 -75
- data/test/spec_request.rb +0 -1398
- data/test/spec_response.rb +0 -510
- data/test/spec_rewindable_input.rb +0 -128
- data/test/spec_runtime.rb +0 -50
- data/test/spec_sendfile.rb +0 -125
- data/test/spec_server.rb +0 -193
- data/test/spec_session_abstract_id.rb +0 -31
- data/test/spec_session_abstract_session_hash.rb +0 -45
- data/test/spec_session_cookie.rb +0 -442
- data/test/spec_session_memcache.rb +0 -320
- data/test/spec_session_pool.rb +0 -210
- data/test/spec_show_exceptions.rb +0 -93
- data/test/spec_show_status.rb +0 -104
- data/test/spec_static.rb +0 -184
- data/test/spec_tempfile_reaper.rb +0 -64
- data/test/spec_thin.rb +0 -96
- data/test/spec_urlmap.rb +0 -237
- data/test/spec_utils.rb +0 -742
- data/test/spec_version.rb +0 -11
- data/test/spec_webrick.rb +0 -206
- data/test/static/another/index.html +0 -1
- data/test/static/foo.html +0 -1
- data/test/static/index.html +0 -1
- data/test/testrequest.rb +0 -78
- data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/lib/rack/runtime.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rack/utils'
|
2
4
|
|
3
5
|
module Rack
|
@@ -8,8 +10,8 @@ module Rack
|
|
8
10
|
# time, or before all the other middlewares to include time for them,
|
9
11
|
# too.
|
10
12
|
class Runtime
|
11
|
-
FORMAT_STRING = "%0.6f"
|
12
|
-
HEADER_NAME = "X-Runtime"
|
13
|
+
FORMAT_STRING = "%0.6f" # :nodoc:
|
14
|
+
HEADER_NAME = "X-Runtime" # :nodoc:
|
13
15
|
|
14
16
|
def initialize(app, name = nil)
|
15
17
|
@app = app
|
data/lib/rack/sendfile.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rack/files'
|
2
4
|
require 'rack/body_proxy'
|
3
5
|
|
4
6
|
module Rack
|
@@ -14,7 +16,7 @@ module Rack
|
|
14
16
|
#
|
15
17
|
# In order to take advantage of this middleware, the response body must
|
16
18
|
# respond to +to_path+ and the request must include an X-Sendfile-Type
|
17
|
-
# header. Rack::
|
19
|
+
# header. Rack::Files and other components implement +to_path+ so there's
|
18
20
|
# rarely anything you need to do in your application. The X-Sendfile-Type
|
19
21
|
# header is typically set in your web servers configuration. The following
|
20
22
|
# sections attempt to document
|
@@ -53,7 +55,7 @@ module Rack
|
|
53
55
|
# that it maps to. The middleware performs a simple substitution on the
|
54
56
|
# resulting path.
|
55
57
|
#
|
56
|
-
# See Also:
|
58
|
+
# See Also: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile
|
57
59
|
#
|
58
60
|
# === lighttpd
|
59
61
|
#
|
@@ -99,7 +101,7 @@ module Rack
|
|
99
101
|
# will be matched with case indifference.
|
100
102
|
|
101
103
|
class Sendfile
|
102
|
-
def initialize(app, variation=nil, mappings=[])
|
104
|
+
def initialize(app, variation = nil, mappings = [])
|
103
105
|
@app = app
|
104
106
|
@variation = variation
|
105
107
|
@mappings = mappings.map do |internal, external|
|
@@ -115,7 +117,8 @@ module Rack
|
|
115
117
|
path = ::File.expand_path(body.to_path)
|
116
118
|
if url = map_accel_path(env, path)
|
117
119
|
headers[CONTENT_LENGTH] = '0'
|
118
|
-
|
120
|
+
# '?' must be percent-encoded because it is not query string but a part of path
|
121
|
+
headers[type] = ::Rack::Utils.escape_path(url).gsub('?', '%3F')
|
119
122
|
obody = body
|
120
123
|
body = Rack::BodyProxy.new([]) do
|
121
124
|
obody.close if obody.respond_to?(:close)
|
@@ -147,11 +150,15 @@ module Rack
|
|
147
150
|
end
|
148
151
|
|
149
152
|
def map_accel_path(env, path)
|
150
|
-
if mapping = @mappings.find { |internal,_| internal =~ path }
|
153
|
+
if mapping = @mappings.find { |internal, _| internal =~ path }
|
151
154
|
path.sub(*mapping)
|
152
155
|
elsif mapping = env['HTTP_X_ACCEL_MAPPING']
|
153
|
-
|
154
|
-
|
156
|
+
mapping.split(',').map(&:strip).each do |m|
|
157
|
+
internal, external = m.split('=', 2).map(&:strip)
|
158
|
+
new_path = path.sub(/^#{internal}/i, external)
|
159
|
+
return new_path unless path == new_path
|
160
|
+
end
|
161
|
+
path
|
155
162
|
end
|
156
163
|
end
|
157
164
|
end
|
data/lib/rack/server.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'optparse'
|
2
4
|
require 'fileutils'
|
3
5
|
|
6
|
+
require_relative 'core_ext/regexp'
|
4
7
|
|
5
8
|
module Rack
|
6
9
|
|
7
10
|
class Server
|
11
|
+
using ::Rack::RegexpExtensions
|
8
12
|
|
9
13
|
class Options
|
10
14
|
def parse!(args)
|
@@ -21,10 +25,6 @@ module Rack
|
|
21
25
|
lineno += 1
|
22
26
|
}
|
23
27
|
|
24
|
-
opts.on("-b", "--builder BUILDER_LINE", "evaluate a BUILDER_LINE of code as a builder script") { |line|
|
25
|
-
options[:builder] = line
|
26
|
-
}
|
27
|
-
|
28
28
|
opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") {
|
29
29
|
options[:debug] = true
|
30
30
|
}
|
@@ -47,7 +47,11 @@ module Rack
|
|
47
47
|
|
48
48
|
opts.separator ""
|
49
49
|
opts.separator "Rack options:"
|
50
|
-
opts.on("-
|
50
|
+
opts.on("-b", "--builder BUILDER_LINE", "evaluate a BUILDER_LINE of code as a builder script") { |line|
|
51
|
+
options[:builder] = line
|
52
|
+
}
|
53
|
+
|
54
|
+
opts.on("-s", "--server SERVER", "serve using SERVER (thin/puma/webrick)") { |s|
|
51
55
|
options[:server] = s
|
52
56
|
}
|
53
57
|
|
@@ -77,6 +81,24 @@ module Rack
|
|
77
81
|
options[:pid] = ::File.expand_path(f)
|
78
82
|
}
|
79
83
|
|
84
|
+
opts.separator ""
|
85
|
+
opts.separator "Profiling options:"
|
86
|
+
|
87
|
+
opts.on("--heap HEAPFILE", "Build the application, then dump the heap to HEAPFILE") do |e|
|
88
|
+
options[:heapfile] = e
|
89
|
+
end
|
90
|
+
|
91
|
+
opts.on("--profile PROFILE", "Dump CPU or Memory profile to PROFILE (defaults to a tempfile)") do |e|
|
92
|
+
options[:profile_file] = e
|
93
|
+
end
|
94
|
+
|
95
|
+
opts.on("--profile-mode MODE", "Profile mode (cpu|wall|object)") do |e|
|
96
|
+
{ cpu: true, wall: true, object: true }.fetch(e.to_sym) do
|
97
|
+
raise OptionParser::InvalidOption, "unknown profile mode: #{e}"
|
98
|
+
end
|
99
|
+
options[:profile_mode] = e.to_sym
|
100
|
+
end
|
101
|
+
|
80
102
|
opts.separator ""
|
81
103
|
opts.separator "Common options:"
|
82
104
|
|
@@ -114,7 +136,7 @@ module Rack
|
|
114
136
|
|
115
137
|
has_options = false
|
116
138
|
server.valid_options.each do |name, description|
|
117
|
-
next if
|
139
|
+
next if /^(Host|Port)[^a-zA-Z]/.match?(name.to_s) # ignore handler's host and port options, we do our own.
|
118
140
|
info << " -O %-21s %s" % [name, description]
|
119
141
|
has_options = true
|
120
142
|
end
|
@@ -152,7 +174,9 @@ module Rack
|
|
152
174
|
|
153
175
|
# Options may include:
|
154
176
|
# * :app
|
155
|
-
# a rack application to run (overrides :config)
|
177
|
+
# a rack application to run (overrides :config and :builder)
|
178
|
+
# * :builder
|
179
|
+
# a string to evaluate a Rack::Builder from
|
156
180
|
# * :config
|
157
181
|
# a rackup configuration file path to load (.ru)
|
158
182
|
# * :environment
|
@@ -182,6 +206,14 @@ module Rack
|
|
182
206
|
# add given paths to $LOAD_PATH
|
183
207
|
# * :require
|
184
208
|
# require the given libraries
|
209
|
+
#
|
210
|
+
# Additional options for profiling app initialization include:
|
211
|
+
# * :heapfile
|
212
|
+
# location for ObjectSpace.dump_all to write the output to
|
213
|
+
# * :profile_file
|
214
|
+
# location for CPU/Memory (StackProf) profile output (defaults to a tempfile)
|
215
|
+
# * :profile_mode
|
216
|
+
# StackProf profile mode (cpu|wall|object)
|
185
217
|
def initialize(options = nil)
|
186
218
|
@ignore_options = []
|
187
219
|
|
@@ -206,12 +238,12 @@ module Rack
|
|
206
238
|
default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
|
207
239
|
|
208
240
|
{
|
209
|
-
:
|
210
|
-
:
|
211
|
-
:
|
212
|
-
:
|
213
|
-
:
|
214
|
-
:
|
241
|
+
environment: environment,
|
242
|
+
pid: nil,
|
243
|
+
Port: 9292,
|
244
|
+
Host: default_host,
|
245
|
+
AccessLog: [],
|
246
|
+
config: "config.ru"
|
215
247
|
}
|
216
248
|
end
|
217
249
|
|
@@ -222,21 +254,19 @@ module Rack
|
|
222
254
|
class << self
|
223
255
|
def logging_middleware
|
224
256
|
lambda { |server|
|
225
|
-
server.server.name
|
257
|
+
/CGI/.match?(server.server.name) || server.options[:quiet] ? nil : [Rack::CommonLogger, $stderr]
|
226
258
|
}
|
227
259
|
end
|
228
260
|
|
229
261
|
def default_middleware_by_environment
|
230
|
-
m = Hash.new {|h,k| h[k] = []}
|
262
|
+
m = Hash.new {|h, k| h[k] = []}
|
231
263
|
m["deployment"] = [
|
232
264
|
[Rack::ContentLength],
|
233
|
-
[Rack::Chunked],
|
234
265
|
logging_middleware,
|
235
266
|
[Rack::TempfileReaper]
|
236
267
|
]
|
237
268
|
m["development"] = [
|
238
269
|
[Rack::ContentLength],
|
239
|
-
[Rack::Chunked],
|
240
270
|
logging_middleware,
|
241
271
|
[Rack::ShowExceptions],
|
242
272
|
[Rack::Lint],
|
@@ -280,7 +310,9 @@ module Rack
|
|
280
310
|
|
281
311
|
# Touch the wrapped app, so that the config.ru is loaded before
|
282
312
|
# daemonization (i.e. before chdir, etc).
|
283
|
-
|
313
|
+
handle_profiling(options[:heapfile], options[:profile_mode], options[:profile_file]) do
|
314
|
+
wrapped_app
|
315
|
+
end
|
284
316
|
|
285
317
|
daemonize_app if options[:daemonize]
|
286
318
|
|
@@ -321,6 +353,44 @@ module Rack
|
|
321
353
|
app
|
322
354
|
end
|
323
355
|
|
356
|
+
def handle_profiling(heapfile, profile_mode, filename)
|
357
|
+
if heapfile
|
358
|
+
require "objspace"
|
359
|
+
ObjectSpace.trace_object_allocations_start
|
360
|
+
yield
|
361
|
+
GC.start
|
362
|
+
::File.open(heapfile, "w") { |f| ObjectSpace.dump_all(output: f) }
|
363
|
+
exit
|
364
|
+
end
|
365
|
+
|
366
|
+
if profile_mode
|
367
|
+
require "stackprof"
|
368
|
+
require "tempfile"
|
369
|
+
|
370
|
+
make_profile_name(filename) do |filename|
|
371
|
+
::File.open(filename, "w") do |f|
|
372
|
+
StackProf.run(mode: profile_mode, out: f) do
|
373
|
+
yield
|
374
|
+
end
|
375
|
+
puts "Profile written to: #{filename}"
|
376
|
+
end
|
377
|
+
end
|
378
|
+
exit
|
379
|
+
end
|
380
|
+
|
381
|
+
yield
|
382
|
+
end
|
383
|
+
|
384
|
+
def make_profile_name(filename)
|
385
|
+
if filename
|
386
|
+
yield filename
|
387
|
+
else
|
388
|
+
::Dir::Tmpname.create("profile.dump") do |tmpname, _, _|
|
389
|
+
yield tmpname
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
324
394
|
def build_app_from_string
|
325
395
|
Rack::Builder.new_from_string(self.options[:builder])
|
326
396
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net
|
2
4
|
# bugrep: Andreas Zehnder
|
3
5
|
|
@@ -6,15 +8,54 @@ require 'time'
|
|
6
8
|
require 'rack/request'
|
7
9
|
require 'rack/response'
|
8
10
|
require 'securerandom'
|
11
|
+
require 'digest/sha2'
|
9
12
|
|
10
13
|
module Rack
|
11
14
|
|
12
15
|
module Session
|
13
16
|
|
17
|
+
class SessionId
|
18
|
+
ID_VERSION = 2
|
19
|
+
|
20
|
+
attr_reader :public_id
|
21
|
+
|
22
|
+
def initialize(public_id)
|
23
|
+
@public_id = public_id
|
24
|
+
end
|
25
|
+
|
26
|
+
def private_id
|
27
|
+
"#{ID_VERSION}::#{hash_sid(public_id)}"
|
28
|
+
end
|
29
|
+
|
30
|
+
alias :cookie_value :public_id
|
31
|
+
alias :to_s :public_id
|
32
|
+
|
33
|
+
def empty?; false; end
|
34
|
+
def inspect; public_id.inspect; end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def hash_sid(sid)
|
39
|
+
Digest::SHA256.hexdigest(sid)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
14
43
|
module Abstract
|
15
44
|
# SessionHash is responsible to lazily load the session from store.
|
16
45
|
|
17
46
|
class SessionHash
|
47
|
+
using Module.new {
|
48
|
+
refine Hash do
|
49
|
+
def transform_keys(&block)
|
50
|
+
hash = {}
|
51
|
+
each do |key, value|
|
52
|
+
hash[block.call(key)] = value
|
53
|
+
end
|
54
|
+
hash
|
55
|
+
end
|
56
|
+
end
|
57
|
+
} unless {}.respond_to?(:transform_keys)
|
58
|
+
|
18
59
|
include Enumerable
|
19
60
|
attr_writer :id
|
20
61
|
|
@@ -57,7 +98,7 @@ module Rack
|
|
57
98
|
@data[key.to_s]
|
58
99
|
end
|
59
100
|
|
60
|
-
def fetch(key, default=Unspecified, &block)
|
101
|
+
def fetch(key, default = Unspecified, &block)
|
61
102
|
load_for_read!
|
62
103
|
if default == Unspecified
|
63
104
|
@data.fetch(key.to_s, &block)
|
@@ -160,11 +201,7 @@ module Rack
|
|
160
201
|
end
|
161
202
|
|
162
203
|
def stringify_keys(other)
|
163
|
-
|
164
|
-
other.each do |key, value|
|
165
|
-
hash[key.to_s] = value
|
166
|
-
end
|
167
|
-
hash
|
204
|
+
other.to_hash.transform_keys(&:to_s)
|
168
205
|
end
|
169
206
|
end
|
170
207
|
|
@@ -199,22 +236,22 @@ module Rack
|
|
199
236
|
|
200
237
|
class Persisted
|
201
238
|
DEFAULT_OPTIONS = {
|
202
|
-
:
|
203
|
-
:
|
204
|
-
:
|
205
|
-
:
|
206
|
-
:
|
207
|
-
:
|
208
|
-
:
|
209
|
-
:
|
210
|
-
:
|
211
|
-
:
|
212
|
-
:
|
239
|
+
key: RACK_SESSION,
|
240
|
+
path: '/',
|
241
|
+
domain: nil,
|
242
|
+
expire_after: nil,
|
243
|
+
secure: false,
|
244
|
+
httponly: true,
|
245
|
+
defer: false,
|
246
|
+
renew: false,
|
247
|
+
sidbits: 128,
|
248
|
+
cookie_only: true,
|
249
|
+
secure_random: ::SecureRandom
|
213
250
|
}.freeze
|
214
251
|
|
215
252
|
attr_reader :key, :default_options, :sid_secure
|
216
253
|
|
217
|
-
def initialize(app, options={})
|
254
|
+
def initialize(app, options = {})
|
218
255
|
@app = app
|
219
256
|
@default_options = self.class::DEFAULT_OPTIONS.merge(options)
|
220
257
|
@key = @default_options.delete(:key)
|
@@ -226,7 +263,7 @@ module Rack
|
|
226
263
|
context(env)
|
227
264
|
end
|
228
265
|
|
229
|
-
def context(env, app
|
266
|
+
def context(env, app = @app)
|
230
267
|
req = make_request env
|
231
268
|
prepare_session(req)
|
232
269
|
status, headers, body = app.call(req.env)
|
@@ -349,7 +386,7 @@ module Rack
|
|
349
386
|
|
350
387
|
session.send(:load!) unless loaded_session?(session)
|
351
388
|
session_id ||= session.id
|
352
|
-
session_data = session.to_hash.delete_if { |k,v| v.nil? }
|
389
|
+
session_data = session.to_hash.delete_if { |k, v| v.nil? }
|
353
390
|
|
354
391
|
if not data = write_session(req, session_id, session_data, options)
|
355
392
|
req.get_header(RACK_ERRORS).puts("Warning! #{self.class.name} failed to save session. Content dropped.")
|
@@ -357,7 +394,7 @@ module Rack
|
|
357
394
|
req.get_header(RACK_ERRORS).puts("Deferring cookie for #{session_id}") if $VERBOSE
|
358
395
|
else
|
359
396
|
cookie = Hash.new
|
360
|
-
cookie[:value] = data
|
397
|
+
cookie[:value] = cookie_value(data)
|
361
398
|
cookie[:expires] = Time.now + options[:expire_after] if options[:expire_after]
|
362
399
|
cookie[:expires] = Time.now + options[:max_age] if options[:max_age]
|
363
400
|
set_cookie(req, res, cookie.merge!(options))
|
@@ -365,6 +402,10 @@ module Rack
|
|
365
402
|
end
|
366
403
|
public :commit_session
|
367
404
|
|
405
|
+
def cookie_value(data)
|
406
|
+
data
|
407
|
+
end
|
408
|
+
|
368
409
|
# Sets the cookie back to the client with session id. We skip the cookie
|
369
410
|
# setting if the value didn't change (sid is the same) or expires was given.
|
370
411
|
|
@@ -406,6 +447,40 @@ module Rack
|
|
406
447
|
end
|
407
448
|
end
|
408
449
|
|
450
|
+
class PersistedSecure < Persisted
|
451
|
+
class SecureSessionHash < SessionHash
|
452
|
+
def [](key)
|
453
|
+
if key == "session_id"
|
454
|
+
load_for_read!
|
455
|
+
id.public_id if id
|
456
|
+
else
|
457
|
+
super
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
def generate_sid(*)
|
463
|
+
public_id = super
|
464
|
+
|
465
|
+
SessionId.new(public_id)
|
466
|
+
end
|
467
|
+
|
468
|
+
def extract_session_id(*)
|
469
|
+
public_id = super
|
470
|
+
public_id && SessionId.new(public_id)
|
471
|
+
end
|
472
|
+
|
473
|
+
private
|
474
|
+
|
475
|
+
def session_class
|
476
|
+
SecureSessionHash
|
477
|
+
end
|
478
|
+
|
479
|
+
def cookie_value(data)
|
480
|
+
data.cookie_value
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
409
484
|
class ID < Persisted
|
410
485
|
def self.inherited(klass)
|
411
486
|
k = klass.ancestors.find { |kl| kl.respond_to?(:superclass) && kl.superclass == ID }
|