rack 2.0.9 → 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.

Files changed (188) hide show
  1. checksums.yaml +4 -4
  2. data/{HISTORY.md → CHANGELOG.md} +220 -155
  3. data/{COPYING → MIT-LICENSE} +4 -2
  4. data/README.rdoc +77 -117
  5. data/Rakefile +25 -18
  6. data/SPEC +3 -4
  7. data/bin/rackup +1 -0
  8. data/example/lobster.ru +2 -0
  9. data/example/protectedlobster.rb +3 -1
  10. data/example/protectedlobster.ru +2 -0
  11. data/lib/rack.rb +63 -60
  12. data/lib/rack/auth/abstract/handler.rb +3 -1
  13. data/lib/rack/auth/abstract/request.rb +2 -0
  14. data/lib/rack/auth/basic.rb +4 -1
  15. data/lib/rack/auth/digest/md5.rb +9 -7
  16. data/lib/rack/auth/digest/nonce.rb +6 -3
  17. data/lib/rack/auth/digest/params.rb +4 -2
  18. data/lib/rack/auth/digest/request.rb +2 -0
  19. data/lib/rack/body_proxy.rb +3 -6
  20. data/lib/rack/builder.rb +38 -15
  21. data/lib/rack/cascade.rb +6 -5
  22. data/lib/rack/chunked.rb +29 -6
  23. data/lib/rack/common_logger.rb +9 -8
  24. data/lib/rack/conditional_get.rb +3 -1
  25. data/lib/rack/config.rb +2 -0
  26. data/lib/rack/content_length.rb +3 -1
  27. data/lib/rack/content_type.rb +3 -1
  28. data/lib/rack/core_ext/regexp.rb +14 -0
  29. data/lib/rack/deflater.rb +28 -17
  30. data/lib/rack/directory.rb +17 -14
  31. data/lib/rack/etag.rb +3 -1
  32. data/lib/rack/events.rb +5 -3
  33. data/lib/rack/file.rb +5 -173
  34. data/lib/rack/files.rb +178 -0
  35. data/lib/rack/handler.rb +7 -2
  36. data/lib/rack/handler/cgi.rb +3 -1
  37. data/lib/rack/handler/fastcgi.rb +4 -2
  38. data/lib/rack/handler/lsws.rb +3 -1
  39. data/lib/rack/handler/scgi.rb +9 -6
  40. data/lib/rack/handler/thin.rb +3 -1
  41. data/lib/rack/handler/webrick.rb +4 -2
  42. data/lib/rack/head.rb +2 -0
  43. data/lib/rack/lint.rb +14 -11
  44. data/lib/rack/lobster.rb +7 -5
  45. data/lib/rack/lock.rb +2 -0
  46. data/lib/rack/logger.rb +2 -0
  47. data/lib/rack/media_type.rb +10 -5
  48. data/lib/rack/method_override.rb +4 -2
  49. data/lib/rack/mime.rb +9 -1
  50. data/lib/rack/mock.rb +74 -15
  51. data/lib/rack/multipart.rb +5 -3
  52. data/lib/rack/multipart/generator.rb +6 -7
  53. data/lib/rack/multipart/parser.rb +51 -45
  54. data/lib/rack/multipart/uploaded_file.rb +2 -0
  55. data/lib/rack/null_logger.rb +2 -0
  56. data/lib/rack/query_parser.rb +51 -25
  57. data/lib/rack/recursive.rb +7 -5
  58. data/lib/rack/reloader.rb +10 -4
  59. data/lib/rack/request.rb +79 -26
  60. data/lib/rack/response.rb +71 -31
  61. data/lib/rack/rewindable_input.rb +4 -2
  62. data/lib/rack/runtime.rb +4 -2
  63. data/lib/rack/sendfile.rb +15 -8
  64. data/lib/rack/server.rb +88 -16
  65. data/lib/rack/session/abstract/id.rb +40 -22
  66. data/lib/rack/session/cookie.rb +10 -9
  67. data/lib/rack/session/memcache.rb +4 -93
  68. data/lib/rack/session/pool.rb +4 -2
  69. data/lib/rack/show_exceptions.rb +15 -9
  70. data/lib/rack/show_status.rb +4 -2
  71. data/lib/rack/static.rb +15 -10
  72. data/lib/rack/tempfile_reaper.rb +2 -0
  73. data/lib/rack/urlmap.rb +11 -2
  74. data/lib/rack/utils.rb +54 -71
  75. data/rack.gemspec +17 -7
  76. metadata +30 -172
  77. data/test/builder/an_underscore_app.rb +0 -5
  78. data/test/builder/anything.rb +0 -5
  79. data/test/builder/comment.ru +0 -4
  80. data/test/builder/end.ru +0 -5
  81. data/test/builder/line.ru +0 -1
  82. data/test/builder/options.ru +0 -2
  83. data/test/cgi/assets/folder/test.js +0 -1
  84. data/test/cgi/assets/fonts/font.eot +0 -1
  85. data/test/cgi/assets/images/image.png +0 -1
  86. data/test/cgi/assets/index.html +0 -1
  87. data/test/cgi/assets/javascripts/app.js +0 -1
  88. data/test/cgi/assets/stylesheets/app.css +0 -1
  89. data/test/cgi/lighttpd.conf +0 -26
  90. data/test/cgi/rackup_stub.rb +0 -6
  91. data/test/cgi/sample_rackup.ru +0 -5
  92. data/test/cgi/test +0 -9
  93. data/test/cgi/test+directory/test+file +0 -1
  94. data/test/cgi/test.fcgi +0 -9
  95. data/test/cgi/test.gz +0 -0
  96. data/test/cgi/test.ru +0 -5
  97. data/test/gemloader.rb +0 -10
  98. data/test/helper.rb +0 -34
  99. data/test/multipart/bad_robots +0 -259
  100. data/test/multipart/binary +0 -0
  101. data/test/multipart/content_type_and_no_filename +0 -6
  102. data/test/multipart/empty +0 -10
  103. data/test/multipart/fail_16384_nofile +0 -814
  104. data/test/multipart/file1.txt +0 -1
  105. data/test/multipart/filename_and_modification_param +0 -7
  106. data/test/multipart/filename_and_no_name +0 -6
  107. data/test/multipart/filename_with_encoded_words +0 -7
  108. data/test/multipart/filename_with_escaped_quotes +0 -6
  109. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  110. data/test/multipart/filename_with_null_byte +0 -7
  111. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  112. data/test/multipart/filename_with_single_quote +0 -7
  113. data/test/multipart/filename_with_unescaped_percentages +0 -6
  114. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  115. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  116. data/test/multipart/filename_with_unescaped_quotes +0 -6
  117. data/test/multipart/ie +0 -6
  118. data/test/multipart/invalid_character +0 -6
  119. data/test/multipart/mixed_files +0 -21
  120. data/test/multipart/nested +0 -10
  121. data/test/multipart/none +0 -9
  122. data/test/multipart/quoted +0 -15
  123. data/test/multipart/rack-logo.png +0 -0
  124. data/test/multipart/semicolon +0 -6
  125. data/test/multipart/text +0 -15
  126. data/test/multipart/three_files_three_fields +0 -31
  127. data/test/multipart/unity3d_wwwform +0 -11
  128. data/test/multipart/webkit +0 -32
  129. data/test/rackup/config.ru +0 -31
  130. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  131. data/test/spec_auth_basic.rb +0 -89
  132. data/test/spec_auth_digest.rb +0 -260
  133. data/test/spec_body_proxy.rb +0 -85
  134. data/test/spec_builder.rb +0 -233
  135. data/test/spec_cascade.rb +0 -63
  136. data/test/spec_cgi.rb +0 -84
  137. data/test/spec_chunked.rb +0 -103
  138. data/test/spec_common_logger.rb +0 -95
  139. data/test/spec_conditional_get.rb +0 -103
  140. data/test/spec_config.rb +0 -23
  141. data/test/spec_content_length.rb +0 -86
  142. data/test/spec_content_type.rb +0 -46
  143. data/test/spec_deflater.rb +0 -375
  144. data/test/spec_directory.rb +0 -148
  145. data/test/spec_etag.rb +0 -108
  146. data/test/spec_events.rb +0 -133
  147. data/test/spec_fastcgi.rb +0 -85
  148. data/test/spec_file.rb +0 -264
  149. data/test/spec_handler.rb +0 -57
  150. data/test/spec_head.rb +0 -46
  151. data/test/spec_lint.rb +0 -515
  152. data/test/spec_lobster.rb +0 -59
  153. data/test/spec_lock.rb +0 -204
  154. data/test/spec_logger.rb +0 -24
  155. data/test/spec_media_type.rb +0 -42
  156. data/test/spec_method_override.rb +0 -110
  157. data/test/spec_mime.rb +0 -51
  158. data/test/spec_mock.rb +0 -359
  159. data/test/spec_multipart.rb +0 -722
  160. data/test/spec_null_logger.rb +0 -21
  161. data/test/spec_recursive.rb +0 -75
  162. data/test/spec_request.rb +0 -1407
  163. data/test/spec_response.rb +0 -528
  164. data/test/spec_rewindable_input.rb +0 -128
  165. data/test/spec_runtime.rb +0 -50
  166. data/test/spec_sendfile.rb +0 -125
  167. data/test/spec_server.rb +0 -193
  168. data/test/spec_session_abstract_id.rb +0 -31
  169. data/test/spec_session_abstract_session_hash.rb +0 -45
  170. data/test/spec_session_cookie.rb +0 -442
  171. data/test/spec_session_memcache.rb +0 -357
  172. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  173. data/test/spec_session_pool.rb +0 -247
  174. data/test/spec_show_exceptions.rb +0 -93
  175. data/test/spec_show_status.rb +0 -104
  176. data/test/spec_static.rb +0 -184
  177. data/test/spec_tempfile_reaper.rb +0 -64
  178. data/test/spec_thin.rb +0 -96
  179. data/test/spec_urlmap.rb +0 -237
  180. data/test/spec_utils.rb +0 -742
  181. data/test/spec_version.rb +0 -11
  182. data/test/spec_webrick.rb +0 -206
  183. data/test/static/another/index.html +0 -1
  184. data/test/static/foo.html +0 -1
  185. data/test/static/index.html +0 -1
  186. data/test/testrequest.rb +0 -78
  187. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  188. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
@@ -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".freeze # :nodoc:
12
- HEADER_NAME = "X-Runtime".freeze # :nodoc:
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
@@ -1,4 +1,6 @@
1
- require 'rack/file'
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::File and other components implement +to_path+ so there's
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: http://wiki.codemongers.com/NginxXSendfile
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
- headers[type] = url
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
- internal, external = mapping.split('=', 2).map(&:strip)
154
- path.sub(/^#{internal}/i, external)
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
@@ -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("-s", "--server SERVER", "serve using SERVER (thin/puma/webrick/mongrel)") { |s|
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 name.to_s.match(/^(Host|Port)[^a-zA-Z]/) # ignore handler's host and port options, we do our own.
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
- :environment => environment,
210
- :pid => nil,
211
- :Port => 9292,
212
- :Host => default_host,
213
- :AccessLog => [],
214
- :config => "config.ru"
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 =~ /CGI/ || server.options[:quiet] ? nil : [Rack::CommonLogger, $stderr]
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
- wrapped_app
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
- hash = {}
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
- :key => RACK_SESSION,
230
- :path => '/',
231
- :domain => nil,
232
- :expire_after => nil,
233
- :secure => false,
234
- :httponly => true,
235
- :defer => false,
236
- :renew => false,
237
- :sidbits => 128,
238
- :cookie_only => true,
239
- :secure_random => ::SecureRandom
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=@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 if id
463
+ id.public_id
446
464
  else
447
465
  super
448
466
  end
@@ -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
- [str].pack('m')
55
+ ::Base64.strict_encode64(str)
53
56
  end
54
57
 
55
58
  def decode(str)
56
- str.unpack('m').first
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 = options[:coder] ||= Base64::Marshal.new
120
- super(app, options.merge!(:cookie_only => true))
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
- digest, session_data = session_data.reverse.split("--", 2)
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