rack 2.2.8.1 → 3.1.16

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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +486 -69
  3. data/CONTRIBUTING.md +63 -55
  4. data/MIT-LICENSE +1 -1
  5. data/README.md +355 -0
  6. data/SPEC.rdoc +204 -131
  7. data/lib/rack/auth/abstract/handler.rb +3 -1
  8. data/lib/rack/auth/abstract/request.rb +3 -1
  9. data/lib/rack/auth/basic.rb +1 -4
  10. data/lib/rack/bad_request.rb +8 -0
  11. data/lib/rack/body_proxy.rb +21 -3
  12. data/lib/rack/builder.rb +102 -69
  13. data/lib/rack/cascade.rb +2 -3
  14. data/lib/rack/common_logger.rb +25 -19
  15. data/lib/rack/conditional_get.rb +18 -15
  16. data/lib/rack/constants.rb +67 -0
  17. data/lib/rack/content_length.rb +12 -16
  18. data/lib/rack/content_type.rb +8 -5
  19. data/lib/rack/deflater.rb +40 -26
  20. data/lib/rack/directory.rb +9 -3
  21. data/lib/rack/etag.rb +17 -23
  22. data/lib/rack/events.rb +4 -0
  23. data/lib/rack/files.rb +15 -17
  24. data/lib/rack/head.rb +9 -8
  25. data/lib/rack/headers.rb +238 -0
  26. data/lib/rack/lint.rb +840 -644
  27. data/lib/rack/lock.rb +2 -5
  28. data/lib/rack/logger.rb +3 -0
  29. data/lib/rack/media_type.rb +8 -3
  30. data/lib/rack/method_override.rb +5 -1
  31. data/lib/rack/mime.rb +14 -5
  32. data/lib/rack/mock.rb +1 -271
  33. data/lib/rack/mock_request.rb +161 -0
  34. data/lib/rack/mock_response.rb +153 -0
  35. data/lib/rack/multipart/generator.rb +7 -5
  36. data/lib/rack/multipart/parser.rb +216 -90
  37. data/lib/rack/multipart/uploaded_file.rb +4 -0
  38. data/lib/rack/multipart.rb +53 -40
  39. data/lib/rack/null_logger.rb +9 -0
  40. data/lib/rack/query_parser.rb +122 -101
  41. data/lib/rack/recursive.rb +2 -0
  42. data/lib/rack/reloader.rb +0 -2
  43. data/lib/rack/request.rb +260 -123
  44. data/lib/rack/response.rb +151 -66
  45. data/lib/rack/rewindable_input.rb +24 -5
  46. data/lib/rack/runtime.rb +7 -6
  47. data/lib/rack/sendfile.rb +31 -26
  48. data/lib/rack/show_exceptions.rb +21 -4
  49. data/lib/rack/show_status.rb +17 -7
  50. data/lib/rack/static.rb +10 -9
  51. data/lib/rack/tempfile_reaper.rb +15 -4
  52. data/lib/rack/urlmap.rb +3 -1
  53. data/lib/rack/utils.rb +235 -235
  54. data/lib/rack/version.rb +1 -9
  55. data/lib/rack.rb +13 -89
  56. metadata +15 -44
  57. data/README.rdoc +0 -320
  58. data/Rakefile +0 -130
  59. data/bin/rackup +0 -5
  60. data/contrib/rack.png +0 -0
  61. data/contrib/rack.svg +0 -150
  62. data/contrib/rack_logo.svg +0 -164
  63. data/contrib/rdoc.css +0 -412
  64. data/example/lobster.ru +0 -6
  65. data/example/protectedlobster.rb +0 -16
  66. data/example/protectedlobster.ru +0 -10
  67. data/lib/rack/auth/digest/md5.rb +0 -131
  68. data/lib/rack/auth/digest/nonce.rb +0 -54
  69. data/lib/rack/auth/digest/params.rb +0 -54
  70. data/lib/rack/auth/digest/request.rb +0 -43
  71. data/lib/rack/chunked.rb +0 -117
  72. data/lib/rack/core_ext/regexp.rb +0 -14
  73. data/lib/rack/file.rb +0 -7
  74. data/lib/rack/handler/cgi.rb +0 -59
  75. data/lib/rack/handler/fastcgi.rb +0 -100
  76. data/lib/rack/handler/lsws.rb +0 -61
  77. data/lib/rack/handler/scgi.rb +0 -71
  78. data/lib/rack/handler/thin.rb +0 -36
  79. data/lib/rack/handler/webrick.rb +0 -129
  80. data/lib/rack/handler.rb +0 -104
  81. data/lib/rack/lobster.rb +0 -70
  82. data/lib/rack/server.rb +0 -466
  83. data/lib/rack/session/abstract/id.rb +0 -523
  84. data/lib/rack/session/cookie.rb +0 -204
  85. data/lib/rack/session/memcache.rb +0 -10
  86. data/lib/rack/session/pool.rb +0 -85
  87. data/rack.gemspec +0 -46
@@ -1,64 +1,77 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'constants'
4
+ require_relative 'utils'
5
+
3
6
  require_relative 'multipart/parser'
7
+ require_relative 'multipart/generator'
8
+
9
+ require_relative 'bad_request'
4
10
 
5
11
  module Rack
6
12
  # A multipart form data parser, adapted from IOWA.
7
13
  #
8
14
  # Usually, Rack::Request#POST takes care of calling this.
9
15
  module Multipart
10
- autoload :UploadedFile, 'rack/multipart/uploaded_file'
11
- autoload :Generator, 'rack/multipart/generator'
12
-
13
- EOL = "\r\n"
14
16
  MULTIPART_BOUNDARY = "AaB03x"
15
- MULTIPART = %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|ni
16
- TOKEN = /[^\s()<>,;:\\"\/\[\]?=]+/
17
- CONDISP = /Content-Disposition:\s*#{TOKEN}\s*/i
18
- VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/
19
- BROKEN = /^#{CONDISP}.*;\s*filename=(#{VALUE})/i
20
- MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{EOL}/ni
21
- MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:[^:]*;\s*name=(#{VALUE})/ni
22
- MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{EOL}]*)/ni
23
- # Updated definitions from RFC 2231
24
- ATTRIBUTE_CHAR = %r{[^ \x00-\x1f\x7f)(><@,;:\\"/\[\]?='*%]}
25
- ATTRIBUTE = /#{ATTRIBUTE_CHAR}+/
26
- SECTION = /\*[0-9]+/
27
- REGULAR_PARAMETER_NAME = /#{ATTRIBUTE}#{SECTION}?/
28
- REGULAR_PARAMETER = /(#{REGULAR_PARAMETER_NAME})=(#{VALUE})/
29
- EXTENDED_OTHER_NAME = /#{ATTRIBUTE}\*[1-9][0-9]*\*/
30
- EXTENDED_OTHER_VALUE = /%[0-9a-fA-F]{2}|#{ATTRIBUTE_CHAR}/
31
- EXTENDED_OTHER_PARAMETER = /(#{EXTENDED_OTHER_NAME})=(#{EXTENDED_OTHER_VALUE}*)/
32
- EXTENDED_INITIAL_NAME = /#{ATTRIBUTE}(?:\*0)?\*/
33
- EXTENDED_INITIAL_VALUE = /[a-zA-Z0-9\-]*'[a-zA-Z0-9\-]*'#{EXTENDED_OTHER_VALUE}*/
34
- EXTENDED_INITIAL_PARAMETER = /(#{EXTENDED_INITIAL_NAME})=(#{EXTENDED_INITIAL_VALUE})/
35
- EXTENDED_PARAMETER = /#{EXTENDED_INITIAL_PARAMETER}|#{EXTENDED_OTHER_PARAMETER}/
36
- DISPPARM = /;\s*(?:#{REGULAR_PARAMETER}|#{EXTENDED_PARAMETER})\s*/
37
- RFC2183 = /^#{CONDISP}(#{DISPPARM})+$/i
17
+
18
+ class MissingInputError < StandardError
19
+ include BadRequest
20
+ end
21
+
22
+ # Accumulator for multipart form data, conforming to the QueryParser API.
23
+ # In future, the Parser could return the pair list directly, but that would
24
+ # change its API.
25
+ class ParamList # :nodoc:
26
+ def self.make_params
27
+ new
28
+ end
29
+
30
+ def self.normalize_params(params, key, value)
31
+ params << [key, value]
32
+ end
33
+
34
+ def initialize
35
+ @pairs = []
36
+ end
37
+
38
+ def <<(pair)
39
+ @pairs << pair
40
+ end
41
+
42
+ def to_params_hash
43
+ @pairs
44
+ end
45
+ end
38
46
 
39
47
  class << self
40
48
  def parse_multipart(env, params = Rack::Utils.default_query_parser)
41
- extract_multipart Rack::Request.new(env), params
42
- end
49
+ unless io = env[RACK_INPUT]
50
+ raise MissingInputError, "Missing input stream!"
51
+ end
43
52
 
44
- def extract_multipart(req, params = Rack::Utils.default_query_parser)
45
- io = req.get_header(RACK_INPUT)
46
- io.rewind
47
- content_length = req.content_length
48
- content_length = content_length.to_i if content_length
53
+ if content_length = env['CONTENT_LENGTH']
54
+ content_length = content_length.to_i
55
+ end
49
56
 
50
- tempfile = req.get_header(RACK_MULTIPART_TEMPFILE_FACTORY) || Parser::TEMPFILE_FACTORY
51
- bufsize = req.get_header(RACK_MULTIPART_BUFFER_SIZE) || Parser::BUFSIZE
57
+ content_type = env['CONTENT_TYPE']
52
58
 
53
- info = Parser.parse io, content_length, req.get_header('CONTENT_TYPE'), tempfile, bufsize, params
54
- req.set_header(RACK_TEMPFILES, info.tmp_files)
55
- info.params
59
+ tempfile = env[RACK_MULTIPART_TEMPFILE_FACTORY] || Parser::TEMPFILE_FACTORY
60
+ bufsize = env[RACK_MULTIPART_BUFFER_SIZE] || Parser::BUFSIZE
61
+
62
+ info = Parser.parse(io, content_length, content_type, tempfile, bufsize, params)
63
+ env[RACK_TEMPFILES] = info.tmp_files
64
+
65
+ return info.params
66
+ end
67
+
68
+ def extract_multipart(request, params = Rack::Utils.default_query_parser)
69
+ parse_multipart(request.env)
56
70
  end
57
71
 
58
72
  def build_multipart(params, first = true)
59
73
  Generator.new(params, first).dump
60
74
  end
61
75
  end
62
-
63
76
  end
64
77
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'constants'
4
+
3
5
  module Rack
4
6
  class NullLogger
5
7
  def initialize(app)
@@ -22,6 +24,11 @@ module Rack
22
24
  def warn? ; end
23
25
  def error? ; end
24
26
  def fatal? ; end
27
+ def debug! ; end
28
+ def error! ; end
29
+ def fatal! ; end
30
+ def info! ; end
31
+ def warn! ; end
25
32
  def level ; end
26
33
  def progname ; end
27
34
  def datetime_format ; end
@@ -34,6 +41,8 @@ module Rack
34
41
  def sev_threshold=(sev_threshold); end
35
42
  def close ; end
36
43
  def add(severity, message = nil, progname = nil, &block); end
44
+ def log(severity, message = nil, progname = nil, &block); end
37
45
  def <<(msg); end
46
+ def reopen(logdev = nil); end
38
47
  end
39
48
  end
@@ -1,48 +1,79 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'bad_request'
4
+ require 'uri'
5
+
3
6
  module Rack
4
7
  class QueryParser
5
- (require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4'
6
-
7
- DEFAULT_SEP = /[&;] */n
8
- COMMON_SEP = { ";" => /[;] */n, ";," => /[;,] */n, "&" => /[&] */n }
8
+ DEFAULT_SEP = /& */n
9
+ COMMON_SEP = { ";" => /; */n, ";," => /[;,] */n, "&" => /& */n }
9
10
 
10
11
  # ParameterTypeError is the error that is raised when incoming structural
11
12
  # parameters (parsed by parse_nested_query) contain conflicting types.
12
- class ParameterTypeError < TypeError; end
13
+ class ParameterTypeError < TypeError
14
+ include BadRequest
15
+ end
13
16
 
14
17
  # InvalidParameterError is the error that is raised when incoming structural
15
18
  # parameters (parsed by parse_nested_query) contain invalid format or byte
16
19
  # sequence.
17
- class InvalidParameterError < ArgumentError; end
20
+ class InvalidParameterError < ArgumentError
21
+ include BadRequest
22
+ end
23
+
24
+ # QueryLimitError is for errors raised when the query provided exceeds one
25
+ # of the query parser limits.
26
+ class QueryLimitError < RangeError
27
+ include BadRequest
28
+ end
18
29
 
19
- # ParamsTooDeepError is the error that is raised when params are recursively
20
- # nested over the specified limit.
21
- class ParamsTooDeepError < RangeError; end
30
+ # ParamsTooDeepError is the old name for the error that is raised when params
31
+ # are recursively nested over the specified limit. Make it the same as
32
+ # as QueryLimitError, so that code that rescues ParamsTooDeepError error
33
+ # to handle bad query strings also now handles other limits.
34
+ ParamsTooDeepError = QueryLimitError
22
35
 
23
- def self.make_default(key_space_limit, param_depth_limit)
24
- new Params, key_space_limit, param_depth_limit
36
+ def self.make_default(param_depth_limit, **options)
37
+ new(Params, param_depth_limit, **options)
25
38
  end
26
39
 
27
- attr_reader :key_space_limit, :param_depth_limit
40
+ attr_reader :param_depth_limit
28
41
 
29
- def initialize(params_class, key_space_limit, param_depth_limit)
42
+ env_int = lambda do |key, val|
43
+ if str_val = ENV[key]
44
+ begin
45
+ val = Integer(str_val, 10)
46
+ rescue ArgumentError
47
+ raise ArgumentError, "non-integer value provided for environment variable #{key}"
48
+ end
49
+ end
50
+
51
+ val
52
+ end
53
+
54
+ BYTESIZE_LIMIT = env_int.call("RACK_QUERY_PARSER_BYTESIZE_LIMIT", 4194304)
55
+ private_constant :BYTESIZE_LIMIT
56
+
57
+ PARAMS_LIMIT = env_int.call("RACK_QUERY_PARSER_PARAMS_LIMIT", 4096)
58
+ private_constant :PARAMS_LIMIT
59
+
60
+ def initialize(params_class, param_depth_limit, bytesize_limit: BYTESIZE_LIMIT, params_limit: PARAMS_LIMIT)
30
61
  @params_class = params_class
31
- @key_space_limit = key_space_limit
32
62
  @param_depth_limit = param_depth_limit
63
+ @bytesize_limit = bytesize_limit
64
+ @params_limit = params_limit
33
65
  end
34
66
 
35
67
  # Stolen from Mongrel, with some small modifications:
36
- # Parses a query string by breaking it up at the '&'
37
- # and ';' characters. You can also use this to parse
38
- # cookies by changing the characters used in the second
39
- # parameter (which defaults to '&;').
40
- def parse_query(qs, d = nil, &unescaper)
68
+ # Parses a query string by breaking it up at the '&'. You can also use this
69
+ # to parse cookies by changing the characters used in the second parameter
70
+ # (which defaults to '&').
71
+ def parse_query(qs, separator = nil, &unescaper)
41
72
  unescaper ||= method(:unescape)
42
73
 
43
74
  params = make_params
44
75
 
45
- (qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
76
+ check_query_string(qs, separator).split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p|
46
77
  next if p.empty?
47
78
  k, v = p.split('=', 2).map!(&unescaper)
48
79
 
@@ -65,14 +96,14 @@ module Rack
65
96
  # query strings with parameters of conflicting types, in this case a
66
97
  # ParameterTypeError is raised. Users are encouraged to return a 400 in this
67
98
  # case.
68
- def parse_nested_query(qs, d = nil)
99
+ def parse_nested_query(qs, separator = nil)
69
100
  params = make_params
70
101
 
71
102
  unless qs.nil? || qs.empty?
72
- (qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
103
+ check_query_string(qs, separator).split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p|
73
104
  k, v = p.split('=', 2).map! { |s| unescape(s) }
74
105
 
75
- normalize_params(params, k, v, param_depth_limit)
106
+ _normalize_params(params, k, v, 0)
76
107
  end
77
108
  end
78
109
 
@@ -83,58 +114,87 @@ module Rack
83
114
 
84
115
  # normalize_params recursively expands parameters into structural types. If
85
116
  # the structural types represented by two different parameter names are in
86
- # conflict, a ParameterTypeError is raised.
87
- def normalize_params(params, name, v, depth)
88
- raise ParamsTooDeepError if depth <= 0
89
-
90
- name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
91
- k = $1 || ''
92
- after = $' || ''
117
+ # conflict, a ParameterTypeError is raised. The depth argument is deprecated
118
+ # and should no longer be used, it is kept for backwards compatibility with
119
+ # earlier versions of rack.
120
+ def normalize_params(params, name, v, _depth=nil)
121
+ _normalize_params(params, name, v, 0)
122
+ end
93
123
 
94
- if k.empty?
95
- if !v.nil? && name == "[]"
96
- return Array(v)
124
+ private def _normalize_params(params, name, v, depth)
125
+ raise ParamsTooDeepError if depth >= param_depth_limit
126
+
127
+ if !name
128
+ # nil name, treat same as empty string (required by tests)
129
+ k = after = ''
130
+ elsif depth == 0
131
+ # Start of parsing, don't treat [] or [ at start of string specially
132
+ if start = name.index('[', 1)
133
+ # Start of parameter nesting, use part before brackets as key
134
+ k = name[0, start]
135
+ after = name[start, name.length]
97
136
  else
98
- return
137
+ # Plain parameter with no nesting
138
+ k = name
139
+ after = ''
99
140
  end
141
+ elsif name.start_with?('[]')
142
+ # Array nesting
143
+ k = '[]'
144
+ after = name[2, name.length]
145
+ elsif name.start_with?('[') && (start = name.index(']', 1))
146
+ # Hash nesting, use the part inside brackets as the key
147
+ k = name[1, start-1]
148
+ after = name[start+1, name.length]
149
+ else
150
+ # Probably malformed input, nested but not starting with [
151
+ # treat full name as key for backwards compatibility.
152
+ k = name
153
+ after = ''
100
154
  end
101
155
 
156
+ return if k.empty?
157
+
102
158
  if after == ''
103
- params[k] = v
159
+ if k == '[]' && depth != 0
160
+ return [v]
161
+ else
162
+ params[k] = v
163
+ end
104
164
  elsif after == "["
105
165
  params[name] = v
106
166
  elsif after == "[]"
107
167
  params[k] ||= []
108
168
  raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
109
169
  params[k] << v
110
- elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
111
- child_key = $1
170
+ elsif after.start_with?('[]')
171
+ # Recognize x[][y] (hash inside array) parameters
172
+ unless after[2] == '[' && after.end_with?(']') && (child_key = after[3, after.length-4]) && !child_key.empty? && !child_key.index('[') && !child_key.index(']')
173
+ # Handle other nested array parameters
174
+ child_key = after[2, after.length]
175
+ end
112
176
  params[k] ||= []
113
177
  raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
114
178
  if params_hash_type?(params[k].last) && !params_hash_has_key?(params[k].last, child_key)
115
- normalize_params(params[k].last, child_key, v, depth - 1)
179
+ _normalize_params(params[k].last, child_key, v, depth + 1)
116
180
  else
117
- params[k] << normalize_params(make_params, child_key, v, depth - 1)
181
+ params[k] << _normalize_params(make_params, child_key, v, depth + 1)
118
182
  end
119
183
  else
120
184
  params[k] ||= make_params
121
185
  raise ParameterTypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k])
122
- params[k] = normalize_params(params[k], after, v, depth - 1)
186
+ params[k] = _normalize_params(params[k], after, v, depth + 1)
123
187
  end
124
188
 
125
189
  params
126
190
  end
127
191
 
128
192
  def make_params
129
- @params_class.new @key_space_limit
130
- end
131
-
132
- def new_space_limit(key_space_limit)
133
- self.class.new @params_class, key_space_limit, param_depth_limit
193
+ @params_class.new
134
194
  end
135
195
 
136
196
  def new_depth_limit(param_depth_limit)
137
- self.class.new @params_class, key_space_limit, param_depth_limit
197
+ self.class.new @params_class, param_depth_limit
138
198
  end
139
199
 
140
200
  private
@@ -155,66 +215,27 @@ module Rack
155
215
  true
156
216
  end
157
217
 
158
- def unescape(s)
159
- Utils.unescape(s)
160
- end
161
-
162
- class Params
163
- def initialize(limit)
164
- @limit = limit
165
- @size = 0
166
- @params = {}
167
- end
218
+ def check_query_string(qs, sep)
219
+ if qs
220
+ if qs.bytesize > @bytesize_limit
221
+ raise QueryLimitError, "total query size (#{qs.bytesize}) exceeds limit (#{@bytesize_limit})"
222
+ end
168
223
 
169
- def [](key)
170
- @params[key]
171
- end
224
+ if (param_count = qs.count(sep.is_a?(String) ? sep : '&')) >= @params_limit
225
+ raise QueryLimitError, "total number of query parameters (#{param_count+1}) exceeds limit (#{@params_limit})"
226
+ end
172
227
 
173
- def []=(key, value)
174
- @size += key.size if key && !@params.key?(key)
175
- raise ParamsTooDeepError, 'exceeded available parameter key space' if @size > @limit
176
- @params[key] = value
228
+ qs
229
+ else
230
+ ''
177
231
  end
232
+ end
178
233
 
179
- def key?(key)
180
- @params.key?(key)
181
- end
234
+ def unescape(string, encoding = Encoding::UTF_8)
235
+ URI.decode_www_form_component(string, encoding)
236
+ end
182
237
 
183
- # Recursively unwraps nested `Params` objects and constructs an object
184
- # of the same shape, but using the objects' internal representations
185
- # (Ruby hashes) in place of the objects. The result is a hash consisting
186
- # purely of Ruby primitives.
187
- #
188
- # Mutation warning!
189
- #
190
- # 1. This method mutates the internal representation of the `Params`
191
- # objects in order to save object allocations.
192
- #
193
- # 2. The value you get back is a reference to the internal hash
194
- # representation, not a copy.
195
- #
196
- # 3. Because the `Params` object's internal representation is mutable
197
- # through the `#[]=` method, it is not thread safe. The result of
198
- # getting the hash representation while another thread is adding a
199
- # key to it is non-deterministic.
200
- #
201
- def to_h
202
- @params.each do |key, value|
203
- case value
204
- when self
205
- # Handle circular references gracefully.
206
- @params[key] = @params
207
- when Params
208
- @params[key] = value.to_h
209
- when Array
210
- value.map! { |v| v.kind_of?(Params) ? v.to_h : v }
211
- else
212
- # Ignore anything that is not a `Params` object or
213
- # a collection that can contain one.
214
- end
215
- end
216
- @params
217
- end
238
+ class Params < Hash
218
239
  alias_method :to_params_hash, :to_h
219
240
  end
220
241
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'uri'
4
4
 
5
+ require_relative 'constants'
6
+
5
7
  module Rack
6
8
  # Rack::ForwardRequest gets caught by Rack::Recursive and redirects
7
9
  # the current request to the app at +url+.
data/lib/rack/reloader.rb CHANGED
@@ -22,8 +22,6 @@ module Rack
22
22
  # It is performing a check/reload cycle at the start of every request, but
23
23
  # also respects a cool down time, during which nothing will be done.
24
24
  class Reloader
25
- (require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4'
26
-
27
25
  def initialize(app, cooldown = 10, backend = Stat)
28
26
  @app = app
29
27
  @cooldown = cooldown