rack 2.0.9.4 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/{HISTORY.md → CHANGELOG.md} +214 -164
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +79 -133
- data/Rakefile +25 -18
- data/SPEC +9 -9
- 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/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 +38 -15
- data/lib/rack/cascade.rb +6 -5
- data/lib/rack/chunked.rb +29 -6
- data/lib/rack/common_logger.rb +9 -11
- 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 +28 -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 +5 -173
- data/lib/rack/files.rb +178 -0
- 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/handler.rb +7 -2
- data/lib/rack/head.rb +2 -0
- data/lib/rack/lint.rb +15 -12
- 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/generator.rb +6 -7
- data/lib/rack/multipart/parser.rb +55 -62
- data/lib/rack/multipart/uploaded_file.rb +2 -0
- data/lib/rack/multipart.rb +6 -3
- 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 +79 -26
- 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 -16
- data/lib/rack/session/abstract/id.rb +40 -22
- data/lib/rack/session/cookie.rb +10 -9
- data/lib/rack/session/memcache.rb +4 -93
- data/lib/rack/session/pool.rb +4 -2
- 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 +64 -93
- data/lib/rack.rb +63 -60
- data/rack.gemspec +17 -7
- metadata +33 -175
- 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 -107
- 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 -520
- 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 -721
- data/test/spec_null_logger.rb +0 -21
- data/test/spec_recursive.rb +0 -75
- data/test/spec_request.rb +0 -1423
- data/test/spec_response.rb +0 -528
- 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 -357
- data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
- data/test/spec_session_pool.rb +0 -247
- 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/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,12 +254,12 @@ 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
265
|
[Rack::Chunked],
|
@@ -280,7 +312,9 @@ module Rack
|
|
280
312
|
|
281
313
|
# Touch the wrapped app, so that the config.ru is loaded before
|
282
314
|
# daemonization (i.e. before chdir, etc).
|
283
|
-
|
315
|
+
handle_profiling(options[:heapfile], options[:profile_mode], options[:profile_file]) do
|
316
|
+
wrapped_app
|
317
|
+
end
|
284
318
|
|
285
319
|
daemonize_app if options[:daemonize]
|
286
320
|
|
@@ -321,6 +355,44 @@ module Rack
|
|
321
355
|
app
|
322
356
|
end
|
323
357
|
|
358
|
+
def handle_profiling(heapfile, profile_mode, filename)
|
359
|
+
if heapfile
|
360
|
+
require "objspace"
|
361
|
+
ObjectSpace.trace_object_allocations_start
|
362
|
+
yield
|
363
|
+
GC.start
|
364
|
+
::File.open(heapfile, "w") { |f| ObjectSpace.dump_all(output: f) }
|
365
|
+
exit
|
366
|
+
end
|
367
|
+
|
368
|
+
if profile_mode
|
369
|
+
require "stackprof"
|
370
|
+
require "tempfile"
|
371
|
+
|
372
|
+
make_profile_name(filename) do |filename|
|
373
|
+
::File.open(filename, "w") do |f|
|
374
|
+
StackProf.run(mode: profile_mode, out: f) do
|
375
|
+
yield
|
376
|
+
end
|
377
|
+
puts "Profile written to: #{filename}"
|
378
|
+
end
|
379
|
+
end
|
380
|
+
exit
|
381
|
+
end
|
382
|
+
|
383
|
+
yield
|
384
|
+
end
|
385
|
+
|
386
|
+
def make_profile_name(filename)
|
387
|
+
if filename
|
388
|
+
yield filename
|
389
|
+
else
|
390
|
+
::Dir::Tmpname.create("profile.dump") do |tmpname, _, _|
|
391
|
+
yield tmpname
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
324
396
|
def build_app_from_string
|
325
397
|
Rack::Builder.new_from_string(self.options[:builder])
|
326
398
|
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
|
|
@@ -26,9 +28,9 @@ module Rack
|
|
26
28
|
end
|
27
29
|
|
28
30
|
alias :cookie_value :public_id
|
29
|
-
alias :to_s :public_id
|
30
31
|
|
31
32
|
def empty?; false; end
|
33
|
+
def to_s; raise; end
|
32
34
|
def inspect; public_id.inspect; end
|
33
35
|
|
34
36
|
private
|
@@ -42,6 +44,26 @@ module Rack
|
|
42
44
|
# SessionHash is responsible to lazily load the session from store.
|
43
45
|
|
44
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
|
+
|
59
|
+
def transform_keys(&block)
|
60
|
+
hash = dup
|
61
|
+
each do |key, value|
|
62
|
+
hash[block.call(key)] = value
|
63
|
+
end
|
64
|
+
hash
|
65
|
+
end
|
66
|
+
|
45
67
|
include Enumerable
|
46
68
|
attr_writer :id
|
47
69
|
|
@@ -84,7 +106,7 @@ module Rack
|
|
84
106
|
@data[key.to_s]
|
85
107
|
end
|
86
108
|
|
87
|
-
def fetch(key, default=Unspecified, &block)
|
109
|
+
def fetch(key, default = Unspecified, &block)
|
88
110
|
load_for_read!
|
89
111
|
if default == Unspecified
|
90
112
|
@data.fetch(key.to_s, &block)
|
@@ -187,11 +209,7 @@ module Rack
|
|
187
209
|
end
|
188
210
|
|
189
211
|
def stringify_keys(other)
|
190
|
-
|
191
|
-
other.each do |key, value|
|
192
|
-
hash[key.to_s] = value
|
193
|
-
end
|
194
|
-
hash
|
212
|
+
other.transform_keys(&:to_s)
|
195
213
|
end
|
196
214
|
end
|
197
215
|
|
@@ -226,22 +244,22 @@ module Rack
|
|
226
244
|
|
227
245
|
class Persisted
|
228
246
|
DEFAULT_OPTIONS = {
|
229
|
-
:
|
230
|
-
:
|
231
|
-
:
|
232
|
-
:
|
233
|
-
:
|
234
|
-
:
|
235
|
-
:
|
236
|
-
:
|
237
|
-
:
|
238
|
-
:
|
239
|
-
:
|
247
|
+
key: RACK_SESSION,
|
248
|
+
path: '/',
|
249
|
+
domain: nil,
|
250
|
+
expire_after: nil,
|
251
|
+
secure: false,
|
252
|
+
httponly: true,
|
253
|
+
defer: false,
|
254
|
+
renew: false,
|
255
|
+
sidbits: 128,
|
256
|
+
cookie_only: true,
|
257
|
+
secure_random: ::SecureRandom
|
240
258
|
}.freeze
|
241
259
|
|
242
260
|
attr_reader :key, :default_options, :sid_secure
|
243
261
|
|
244
|
-
def initialize(app, options={})
|
262
|
+
def initialize(app, options = {})
|
245
263
|
@app = app
|
246
264
|
@default_options = self.class::DEFAULT_OPTIONS.merge(options)
|
247
265
|
@key = @default_options.delete(:key)
|
@@ -253,7 +271,7 @@ module Rack
|
|
253
271
|
context(env)
|
254
272
|
end
|
255
273
|
|
256
|
-
def context(env, app
|
274
|
+
def context(env, app = @app)
|
257
275
|
req = make_request env
|
258
276
|
prepare_session(req)
|
259
277
|
status, headers, body = app.call(req.env)
|
@@ -376,7 +394,7 @@ module Rack
|
|
376
394
|
|
377
395
|
session.send(:load!) unless loaded_session?(session)
|
378
396
|
session_id ||= session.id
|
379
|
-
session_data = session.to_hash.delete_if { |k,v| v.nil? }
|
397
|
+
session_data = session.to_hash.delete_if { |k, v| v.nil? }
|
380
398
|
|
381
399
|
if not data = write_session(req, session_id, session_data, options)
|
382
400
|
req.get_header(RACK_ERRORS).puts("Warning! #{self.class.name} failed to save session. Content dropped.")
|
@@ -442,7 +460,7 @@ module Rack
|
|
442
460
|
def [](key)
|
443
461
|
if key == "session_id"
|
444
462
|
load_for_read!
|
445
|
-
id.public_id
|
463
|
+
id.public_id
|
446
464
|
else
|
447
465
|
super
|
448
466
|
end
|
data/lib/rack/session/cookie.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'openssl'
|
2
4
|
require 'zlib'
|
3
5
|
require 'rack/request'
|
4
6
|
require 'rack/response'
|
5
7
|
require 'rack/session/abstract/id'
|
6
8
|
require 'json'
|
9
|
+
require 'base64'
|
7
10
|
|
8
11
|
module Rack
|
9
12
|
|
@@ -49,11 +52,11 @@ module Rack
|
|
49
52
|
# Encode session cookies as Base64
|
50
53
|
class Base64
|
51
54
|
def encode(str)
|
52
|
-
|
55
|
+
::Base64.strict_encode64(str)
|
53
56
|
end
|
54
57
|
|
55
58
|
def decode(str)
|
56
|
-
|
59
|
+
::Base64.decode64(str)
|
57
60
|
end
|
58
61
|
|
59
62
|
# Encode session cookies as Marshaled Base64 data
|
@@ -103,7 +106,7 @@ module Rack
|
|
103
106
|
|
104
107
|
attr_reader :coder
|
105
108
|
|
106
|
-
def initialize(app, options={})
|
109
|
+
def initialize(app, options = {})
|
107
110
|
@secrets = options.values_at(:secret, :old_secret).compact
|
108
111
|
@hmac = options.fetch(:hmac, OpenSSL::Digest::SHA1)
|
109
112
|
|
@@ -116,8 +119,8 @@ module Rack
|
|
116
119
|
|
117
120
|
Called from: #{caller[0]}.
|
118
121
|
MSG
|
119
|
-
@coder
|
120
|
-
super(app, options.merge!(:
|
122
|
+
@coder = options[:coder] ||= Base64::Marshal.new
|
123
|
+
super(app, options.merge!(cookie_only: true))
|
121
124
|
end
|
122
125
|
|
123
126
|
private
|
@@ -137,9 +140,7 @@ module Rack
|
|
137
140
|
session_data = request.cookies[@key]
|
138
141
|
|
139
142
|
if @secrets.size > 0 && session_data
|
140
|
-
|
141
|
-
digest.reverse! if digest
|
142
|
-
session_data.reverse! if session_data
|
143
|
+
session_data, _, digest = session_data.rpartition('--')
|
143
144
|
session_data = nil unless digest_match?(session_data, digest)
|
144
145
|
end
|
145
146
|
|
@@ -147,7 +148,7 @@ module Rack
|
|
147
148
|
end
|
148
149
|
end
|
149
150
|
|
150
|
-
def persistent_session_id!(data, sid=nil)
|
151
|
+
def persistent_session_id!(data, sid = nil)
|
151
152
|
data ||= {}
|
152
153
|
data["session_id"] ||= sid || generate_sid
|
153
154
|
data
|
@@ -1,99 +1,10 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'rack/session/
|
4
|
-
require 'memcache'
|
3
|
+
require 'rack/session/dalli'
|
5
4
|
|
6
5
|
module Rack
|
7
6
|
module Session
|
8
|
-
|
9
|
-
|
10
|
-
# maintained in the cookie.
|
11
|
-
# You may treat Session::Memcache as you would Session::Pool with the
|
12
|
-
# following caveats.
|
13
|
-
#
|
14
|
-
# * Setting :expire_after to 0 would note to the Memcache server to hang
|
15
|
-
# onto the session data until it would drop it according to it's own
|
16
|
-
# specifications. However, the cookie sent to the client would expire
|
17
|
-
# immediately.
|
18
|
-
#
|
19
|
-
# Note that memcache does drop data before it may be listed to expire. For
|
20
|
-
# a full description of behaviour, please see memcache's documentation.
|
21
|
-
|
22
|
-
class Memcache < Abstract::PersistedSecure
|
23
|
-
attr_reader :mutex, :pool
|
24
|
-
|
25
|
-
DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge \
|
26
|
-
:namespace => 'rack:session',
|
27
|
-
:memcache_server => 'localhost:11211'
|
28
|
-
|
29
|
-
def initialize(app, options={})
|
30
|
-
super
|
31
|
-
|
32
|
-
@mutex = Mutex.new
|
33
|
-
mserv = @default_options[:memcache_server]
|
34
|
-
mopts = @default_options.reject{|k,v| !MemCache::DEFAULT_OPTIONS.include? k }
|
35
|
-
|
36
|
-
@pool = options[:cache] || MemCache.new(mserv, mopts)
|
37
|
-
unless @pool.active? and @pool.servers.any?(&:alive?)
|
38
|
-
raise 'No memcache servers'
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def generate_sid
|
43
|
-
loop do
|
44
|
-
sid = super
|
45
|
-
break sid unless @pool.get(sid.private_id, true)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def find_session(req, sid)
|
50
|
-
with_lock(req) do
|
51
|
-
unless sid and session = get_session_with_fallback(sid)
|
52
|
-
sid, session = generate_sid, {}
|
53
|
-
unless /^STORED/ =~ @pool.add(sid.private_id, session)
|
54
|
-
raise "Session collision on '#{sid.inspect}'"
|
55
|
-
end
|
56
|
-
end
|
57
|
-
[sid, session]
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def write_session(req, session_id, new_session, options)
|
62
|
-
expiry = options[:expire_after]
|
63
|
-
expiry = expiry.nil? ? 0 : expiry + 1
|
64
|
-
|
65
|
-
with_lock(req) do
|
66
|
-
@pool.set session_id.private_id, new_session, expiry
|
67
|
-
session_id
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def delete_session(req, session_id, options)
|
72
|
-
with_lock(req) do
|
73
|
-
@pool.delete(session_id.public_id)
|
74
|
-
@pool.delete(session_id.private_id)
|
75
|
-
generate_sid unless options[:drop]
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def with_lock(req)
|
80
|
-
@mutex.lock if req.multithread?
|
81
|
-
yield
|
82
|
-
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
|
83
|
-
if $VERBOSE
|
84
|
-
warn "#{self} is unable to find memcached server."
|
85
|
-
warn $!.inspect
|
86
|
-
end
|
87
|
-
raise
|
88
|
-
ensure
|
89
|
-
@mutex.unlock if @mutex.locked?
|
90
|
-
end
|
91
|
-
|
92
|
-
private
|
93
|
-
|
94
|
-
def get_session_with_fallback(sid)
|
95
|
-
@pool.get(sid.private_id) || @pool.get(sid.public_id)
|
96
|
-
end
|
97
|
-
end
|
7
|
+
warn "Rack::Session::Memcache is deprecated, please use Rack::Session::Dalli from 'dalli' gem instead."
|
8
|
+
Memcache = Dalli
|
98
9
|
end
|
99
10
|
end
|
data/lib/rack/session/pool.rb
CHANGED
@@ -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
|
# THANKS:
|
3
5
|
# apeiros, for session id generation, expiry setup, and threadiness
|
@@ -26,9 +28,9 @@ module Rack
|
|
26
28
|
|
27
29
|
class Pool < Abstract::PersistedSecure
|
28
30
|
attr_reader :mutex, :pool
|
29
|
-
DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge :
|
31
|
+
DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge drop: false
|
30
32
|
|
31
|
-
def initialize(app, options={})
|
33
|
+
def initialize(app, options = {})
|
32
34
|
super
|
33
35
|
@pool = Hash.new
|
34
36
|
@mutex = Mutex.new
|
data/lib/rack/show_exceptions.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'ostruct'
|
2
4
|
require 'erb'
|
3
5
|
require 'rack/request'
|
@@ -55,7 +57,7 @@ module Rack
|
|
55
57
|
private :accepts_html?
|
56
58
|
|
57
59
|
def dump_exception(exception)
|
58
|
-
string = "#{exception.class}: #{exception.message}\n"
|
60
|
+
string = "#{exception.class}: #{exception.message}\n".dup
|
59
61
|
string << exception.backtrace.map { |l| "\t#{l}" }.join("\n")
|
60
62
|
string
|
61
63
|
end
|
@@ -77,13 +79,13 @@ module Rack
|
|
77
79
|
frame.function = $4
|
78
80
|
|
79
81
|
begin
|
80
|
-
lineno = frame.lineno-1
|
82
|
+
lineno = frame.lineno - 1
|
81
83
|
lines = ::File.readlines(frame.filename)
|
82
|
-
frame.pre_context_lineno = [lineno-CONTEXT, 0].max
|
84
|
+
frame.pre_context_lineno = [lineno - CONTEXT, 0].max
|
83
85
|
frame.pre_context = lines[frame.pre_context_lineno...lineno]
|
84
86
|
frame.context_line = lines[lineno].chomp
|
85
|
-
frame.post_context_lineno = [lineno+CONTEXT, lines.size].min
|
86
|
-
frame.post_context = lines[lineno+1..frame.post_context_lineno]
|
87
|
+
frame.post_context_lineno = [lineno + CONTEXT, lines.size].min
|
88
|
+
frame.post_context = lines[lineno + 1..frame.post_context_lineno]
|
87
89
|
rescue
|
88
90
|
end
|
89
91
|
|
@@ -93,7 +95,11 @@ module Rack
|
|
93
95
|
end
|
94
96
|
}.compact
|
95
97
|
|
96
|
-
|
98
|
+
template.result(binding)
|
99
|
+
end
|
100
|
+
|
101
|
+
def template
|
102
|
+
TEMPLATE
|
97
103
|
end
|
98
104
|
|
99
105
|
def h(obj) # :nodoc:
|
@@ -107,8 +113,8 @@ module Rack
|
|
107
113
|
|
108
114
|
# :stopdoc:
|
109
115
|
|
110
|
-
# adapted from Django <djangoproject.com>
|
111
|
-
# Copyright (c)
|
116
|
+
# adapted from Django <www.djangoproject.com>
|
117
|
+
# Copyright (c) Django Software Foundation and individual contributors.
|
112
118
|
# Used under the modified BSD license:
|
113
119
|
# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
|
114
120
|
TEMPLATE = ERB.new(<<-'HTML'.gsub(/^ /, ''))
|
@@ -363,7 +369,7 @@ module Rack
|
|
363
369
|
<% env.sort_by { |k, v| k.to_s }.each { |key, val| %>
|
364
370
|
<tr>
|
365
371
|
<td><%=h key %></td>
|
366
|
-
<td class="code"><div><%=h val %></div></td>
|
372
|
+
<td class="code"><div><%=h val.inspect %></div></td>
|
367
373
|
</tr>
|
368
374
|
<% } %>
|
369
375
|
</tbody>
|
data/lib/rack/show_status.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'erb'
|
2
4
|
require 'rack/request'
|
3
5
|
require 'rack/utils'
|
@@ -52,8 +54,8 @@ module Rack
|
|
52
54
|
|
53
55
|
# :stopdoc:
|
54
56
|
|
55
|
-
# adapted from Django <djangoproject.com>
|
56
|
-
# Copyright (c)
|
57
|
+
# adapted from Django <www.djangoproject.com>
|
58
|
+
# Copyright (c) Django Software Foundation and individual contributors.
|
57
59
|
# Used under the modified BSD license:
|
58
60
|
# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
|
59
61
|
TEMPLATE = <<'HTML'
|