rack 3.0.15 → 3.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +368 -6
- data/CONTRIBUTING.md +11 -9
- data/README.md +103 -28
- data/SPEC.rdoc +206 -288
- data/lib/rack/auth/abstract/request.rb +2 -0
- data/lib/rack/auth/basic.rb +1 -2
- data/lib/rack/bad_request.rb +8 -0
- data/lib/rack/builder.rb +29 -10
- data/lib/rack/cascade.rb +0 -3
- data/lib/rack/conditional_get.rb +4 -3
- data/lib/rack/constants.rb +4 -0
- data/lib/rack/directory.rb +6 -3
- data/lib/rack/events.rb +21 -6
- data/lib/rack/files.rb +1 -1
- data/lib/rack/head.rb +2 -3
- data/lib/rack/headers.rb +86 -2
- data/lib/rack/lint.rb +482 -425
- data/lib/rack/media_type.rb +14 -10
- data/lib/rack/mime.rb +6 -5
- data/lib/rack/mock_request.rb +10 -15
- data/lib/rack/mock_response.rb +50 -20
- data/lib/rack/multipart/parser.rb +255 -76
- data/lib/rack/multipart/uploaded_file.rb +42 -5
- data/lib/rack/multipart.rb +34 -1
- data/lib/rack/query_parser.rb +86 -78
- data/lib/rack/request.rb +78 -65
- data/lib/rack/response.rb +28 -20
- data/lib/rack/rewindable_input.rb +4 -1
- data/lib/rack/sendfile.rb +51 -21
- data/lib/rack/show_exceptions.rb +10 -4
- data/lib/rack/show_status.rb +0 -2
- data/lib/rack/static.rb +7 -3
- data/lib/rack/utils.rb +175 -119
- data/lib/rack/version.rb +3 -20
- data/lib/rack.rb +1 -4
- metadata +6 -12
- data/lib/rack/auth/digest/md5.rb +0 -1
- data/lib/rack/auth/digest/nonce.rb +0 -1
- data/lib/rack/auth/digest/params.rb +0 -1
- data/lib/rack/auth/digest/request.rb +0 -1
- data/lib/rack/auth/digest.rb +0 -256
- data/lib/rack/chunked.rb +0 -120
- data/lib/rack/file.rb +0 -9
- data/lib/rack/logger.rb +0 -22
data/lib/rack/utils.rb
CHANGED
|
@@ -6,6 +6,7 @@ require 'fileutils'
|
|
|
6
6
|
require 'set'
|
|
7
7
|
require 'tempfile'
|
|
8
8
|
require 'time'
|
|
9
|
+
require 'erb'
|
|
9
10
|
|
|
10
11
|
require_relative 'query_parser'
|
|
11
12
|
require_relative 'mime'
|
|
@@ -23,6 +24,7 @@ module Rack
|
|
|
23
24
|
DEFAULT_SEP = QueryParser::DEFAULT_SEP
|
|
24
25
|
COMMON_SEP = QueryParser::COMMON_SEP
|
|
25
26
|
KeySpaceConstrainedParams = QueryParser::Params
|
|
27
|
+
URI_PARSER = defined?(::URI::RFC2396_PARSER) ? ::URI::RFC2396_PARSER : ::URI::DEFAULT_PARSER
|
|
26
28
|
|
|
27
29
|
class << self
|
|
28
30
|
attr_accessor :default_query_parser
|
|
@@ -42,13 +44,13 @@ module Rack
|
|
|
42
44
|
# Like URI escaping, but with %20 instead of +. Strictly speaking this is
|
|
43
45
|
# true URI escaping.
|
|
44
46
|
def escape_path(s)
|
|
45
|
-
|
|
47
|
+
URI_PARSER.escape s
|
|
46
48
|
end
|
|
47
49
|
|
|
48
50
|
# Unescapes the **path** component of a URI. See Rack::Utils.unescape for
|
|
49
51
|
# unescaping query parameters or form components.
|
|
50
52
|
def unescape_path(s)
|
|
51
|
-
|
|
53
|
+
URI_PARSER.unescape s
|
|
52
54
|
end
|
|
53
55
|
|
|
54
56
|
# Unescapes a URI escaped string with +encoding+. +encoding+ will be the
|
|
@@ -85,15 +87,6 @@ module Rack
|
|
|
85
87
|
self.default_query_parser = self.default_query_parser.new_depth_limit(v)
|
|
86
88
|
end
|
|
87
89
|
|
|
88
|
-
def self.key_space_limit
|
|
89
|
-
warn("`Rack::Utils.key_space_limit` is deprecated as this value no longer has an effect. It will be removed in Rack 3.1", uplevel: 1)
|
|
90
|
-
65536
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def self.key_space_limit=(v)
|
|
94
|
-
warn("`Rack::Utils.key_space_limit=` is deprecated and no longer has an effect. It will be removed in Rack 3.1", uplevel: 1)
|
|
95
|
-
end
|
|
96
|
-
|
|
97
90
|
if defined?(Process::CLOCK_MONOTONIC)
|
|
98
91
|
def clock_time
|
|
99
92
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
@@ -153,17 +146,77 @@ module Rack
|
|
|
153
146
|
end
|
|
154
147
|
end
|
|
155
148
|
|
|
149
|
+
ALLOWED_FORWARED_PARAMS = %w[by for host proto].to_h { |name| [name, name.to_sym] }.freeze
|
|
150
|
+
private_constant :ALLOWED_FORWARED_PARAMS
|
|
151
|
+
|
|
156
152
|
def forwarded_values(forwarded_header)
|
|
157
|
-
return
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
153
|
+
return unless forwarded_header
|
|
154
|
+
header = forwarded_header.to_s.tr("\n", ";")
|
|
155
|
+
header.sub!(/\A[\s;,]+/, '')
|
|
156
|
+
num_params = num_escapes = 0
|
|
157
|
+
max_params = max_escapes = 1024
|
|
158
|
+
params = {}
|
|
159
|
+
|
|
160
|
+
# Parse parameter list
|
|
161
|
+
while i = header.index('=')
|
|
162
|
+
# Only parse up to max parameters, to avoid potential denial of service
|
|
163
|
+
num_params += 1
|
|
164
|
+
return if num_params > max_params
|
|
165
|
+
|
|
166
|
+
# Found end of parameter name, ensure forward progress in loop
|
|
167
|
+
param = header.slice!(0, i+1)
|
|
168
|
+
|
|
169
|
+
# Remove ending equals and preceding whitespace from parameter name
|
|
170
|
+
param.chomp!('=')
|
|
171
|
+
param.strip!
|
|
172
|
+
param.downcase!
|
|
173
|
+
return unless param = ALLOWED_FORWARED_PARAMS[param]
|
|
174
|
+
|
|
175
|
+
if header[0] == '"'
|
|
176
|
+
# Parameter value is quoted, parse it, handling backslash escapes
|
|
177
|
+
header.slice!(0, 1)
|
|
178
|
+
value = String.new
|
|
179
|
+
|
|
180
|
+
while i = header.index(/(["\\])/)
|
|
181
|
+
c = $1
|
|
182
|
+
|
|
183
|
+
# Append all content until ending quote or escape
|
|
184
|
+
value << header.slice!(0, i)
|
|
185
|
+
|
|
186
|
+
# Remove either backslash or ending quote,
|
|
187
|
+
# ensures forward progress in loop
|
|
188
|
+
header.slice!(0, 1)
|
|
189
|
+
|
|
190
|
+
# stop parsing parameter value if found ending quote
|
|
191
|
+
break if c == '"'
|
|
192
|
+
|
|
193
|
+
# Only allow up to max escapes, to avoid potential denial of service
|
|
194
|
+
num_escapes += 1
|
|
195
|
+
return if num_escapes > max_escapes
|
|
196
|
+
escaped_char = header.slice!(0, 1)
|
|
197
|
+
value << escaped_char
|
|
198
|
+
end
|
|
199
|
+
else
|
|
200
|
+
if i = header.index(/[;,]/)
|
|
201
|
+
# Parameter value unquoted (which may be invalid), value ends at comma or semicolon
|
|
202
|
+
value = header.slice!(0, i)
|
|
203
|
+
value.sub!(/[\s;,]+\z/, '')
|
|
204
|
+
else
|
|
205
|
+
# If no ending semicolon, assume remainder of line is value and stop parsing
|
|
206
|
+
header.strip!
|
|
207
|
+
value = header
|
|
208
|
+
header = ''
|
|
209
|
+
end
|
|
210
|
+
value.lstrip!
|
|
165
211
|
end
|
|
212
|
+
|
|
213
|
+
(params[param] ||= []) << value
|
|
214
|
+
|
|
215
|
+
# skip trailing semicolons/commas/whitespace, to proceed to next parameter
|
|
216
|
+
header.sub!(/\A[\s;,]+/, '') unless header.empty?
|
|
166
217
|
end
|
|
218
|
+
|
|
219
|
+
params
|
|
167
220
|
end
|
|
168
221
|
module_function :forwarded_values
|
|
169
222
|
|
|
@@ -184,33 +237,57 @@ module Rack
|
|
|
184
237
|
matches&.first
|
|
185
238
|
end
|
|
186
239
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
240
|
+
# Introduced in ERB 4.0. ERB::Escape is an alias for ERB::Utils which
|
|
241
|
+
# doesn't get monkey-patched by rails
|
|
242
|
+
if defined?(ERB::Escape) && ERB::Escape.instance_method(:html_escape)
|
|
243
|
+
define_method(:escape_html, ERB::Escape.instance_method(:html_escape))
|
|
244
|
+
# :nocov:
|
|
245
|
+
# Ruby 3.2/ERB 4.0 added ERB::Escape#html_escape, so the else
|
|
246
|
+
# branch cannot be hit on the current Ruby version.
|
|
247
|
+
else
|
|
248
|
+
require 'cgi/escape'
|
|
249
|
+
# Escape ampersands, brackets and quotes to their HTML/XML entities.
|
|
250
|
+
def escape_html(string)
|
|
251
|
+
CGI.escapeHTML(string.to_s)
|
|
252
|
+
end
|
|
253
|
+
# :nocov:
|
|
201
254
|
end
|
|
202
255
|
|
|
256
|
+
# Given an array of available encoding strings, and an array of
|
|
257
|
+
# acceptable encodings for a request, where each element of the
|
|
258
|
+
# acceptable encodings array is an array where the first element
|
|
259
|
+
# is an encoding name and the second element is the numeric
|
|
260
|
+
# priority for the encoding, return the available encoding with
|
|
261
|
+
# the highest priority.
|
|
262
|
+
#
|
|
263
|
+
# The accept_encoding argument is typically generated by calling
|
|
264
|
+
# Request#accept_encoding.
|
|
265
|
+
#
|
|
266
|
+
# Example:
|
|
267
|
+
#
|
|
268
|
+
# select_best_encoding(%w(compress gzip identity),
|
|
269
|
+
# [["compress", 0.5], ["gzip", 1.0]])
|
|
270
|
+
# # => "gzip"
|
|
271
|
+
#
|
|
272
|
+
# To reduce denial of service potential, only the first 16
|
|
273
|
+
# acceptable encodings are considered.
|
|
203
274
|
def select_best_encoding(available_encodings, accept_encoding)
|
|
204
275
|
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
|
205
276
|
|
|
277
|
+
# Only process the first 16 encodings
|
|
278
|
+
accept_encoding = accept_encoding[0...16]
|
|
206
279
|
expanded_accept_encoding = []
|
|
280
|
+
wildcard_seen = false
|
|
207
281
|
|
|
208
282
|
accept_encoding.each do |m, q|
|
|
209
283
|
preference = available_encodings.index(m) || available_encodings.size
|
|
210
284
|
|
|
211
285
|
if m == "*"
|
|
212
|
-
|
|
213
|
-
|
|
286
|
+
unless wildcard_seen
|
|
287
|
+
(available_encodings - accept_encoding.map(&:first)).each do |m2|
|
|
288
|
+
expanded_accept_encoding << [m2, q, preference]
|
|
289
|
+
end
|
|
290
|
+
wildcard_seen = true
|
|
214
291
|
end
|
|
215
292
|
else
|
|
216
293
|
expanded_accept_encoding << [m, q, preference]
|
|
@@ -218,7 +295,13 @@ module Rack
|
|
|
218
295
|
end
|
|
219
296
|
|
|
220
297
|
encoding_candidates = expanded_accept_encoding
|
|
221
|
-
.
|
|
298
|
+
.sort do |(_, q1, p1), (_, q2, p2)|
|
|
299
|
+
if r = (q1 <=> q2).nonzero?
|
|
300
|
+
-r
|
|
301
|
+
else
|
|
302
|
+
(p1 <=> p2).nonzero? || 0
|
|
303
|
+
end
|
|
304
|
+
end
|
|
222
305
|
.map!(&:first)
|
|
223
306
|
|
|
224
307
|
unless encoding_candidates.include?("identity")
|
|
@@ -252,21 +335,6 @@ module Rack
|
|
|
252
335
|
end
|
|
253
336
|
end
|
|
254
337
|
|
|
255
|
-
def add_cookie_to_header(header, key, value)
|
|
256
|
-
warn("add_cookie_to_header is deprecated and will be removed in Rack 3.1", uplevel: 1)
|
|
257
|
-
|
|
258
|
-
case header
|
|
259
|
-
when nil, ''
|
|
260
|
-
return set_cookie_header(key, value)
|
|
261
|
-
when String
|
|
262
|
-
[header, set_cookie_header(key, value)]
|
|
263
|
-
when Array
|
|
264
|
-
header + [set_cookie_header(key, value)]
|
|
265
|
-
else
|
|
266
|
-
raise ArgumentError, "Unrecognized cookie header value. Expected String, Array, or nil, got #{header.inspect}"
|
|
267
|
-
end
|
|
268
|
-
end
|
|
269
|
-
|
|
270
338
|
# :call-seq:
|
|
271
339
|
# parse_cookies(env) -> hash
|
|
272
340
|
#
|
|
@@ -280,12 +348,18 @@ module Rack
|
|
|
280
348
|
parse_cookies_header env[HTTP_COOKIE]
|
|
281
349
|
end
|
|
282
350
|
|
|
351
|
+
# A valid cookie key according to RFC6265 and RFC2616.
|
|
352
|
+
# A <cookie-name> can be any US-ASCII characters, except control characters, spaces, or tabs. It also must not contain a separator character like the following: ( ) < > @ , ; : \ " / [ ] ? = { }.
|
|
353
|
+
VALID_COOKIE_KEY = /\A[!#$%&'*+\-\.\^_`|~0-9a-zA-Z]+\z/.freeze
|
|
354
|
+
private_constant :VALID_COOKIE_KEY
|
|
355
|
+
|
|
283
356
|
# :call-seq:
|
|
284
357
|
# set_cookie_header(key, value) -> encoded string
|
|
285
358
|
#
|
|
286
359
|
# Generate an encoded string using the provided +key+ and +value+ suitable
|
|
287
360
|
# for the +set-cookie+ header according to RFC6265. The +value+ may be an
|
|
288
|
-
# instance of either +String+ or +Hash+.
|
|
361
|
+
# instance of either +String+ or +Hash+. If the cookie key is invalid (as
|
|
362
|
+
# defined by RFC6265), an +ArgumentError+ will be raised.
|
|
289
363
|
#
|
|
290
364
|
# If the cookie +value+ is an instance of +Hash+, it considers the following
|
|
291
365
|
# cookie attribute keys: +domain+, +max_age+, +expires+ (must be instance
|
|
@@ -293,10 +367,6 @@ module Rack
|
|
|
293
367
|
# details about the interpretation of these fields, consult
|
|
294
368
|
# [RFC6265 Section 5.2](https://datatracker.ietf.org/doc/html/rfc6265#section-5.2).
|
|
295
369
|
#
|
|
296
|
-
# An extra cookie attribute +escape_key+ can be provided to control whether
|
|
297
|
-
# or not the cookie key is URL encoded. If explicitly set to +false+, the
|
|
298
|
-
# cookie key name will not be url encoded (escaped). The default is +true+.
|
|
299
|
-
#
|
|
300
370
|
# set_cookie_header("myname", "myvalue")
|
|
301
371
|
# # => "myname=myvalue"
|
|
302
372
|
#
|
|
@@ -304,9 +374,12 @@ module Rack
|
|
|
304
374
|
# # => "myname=myvalue; max-age=10"
|
|
305
375
|
#
|
|
306
376
|
def set_cookie_header(key, value)
|
|
377
|
+
unless key =~ VALID_COOKIE_KEY
|
|
378
|
+
raise ArgumentError, "invalid cookie key: #{key.inspect}"
|
|
379
|
+
end
|
|
380
|
+
|
|
307
381
|
case value
|
|
308
382
|
when Hash
|
|
309
|
-
key = escape(key) unless value[:escape_key] == false
|
|
310
383
|
domain = "; domain=#{value[:domain]}" if value[:domain]
|
|
311
384
|
path = "; path=#{value[:path]}" if value[:path]
|
|
312
385
|
max_age = "; max-age=#{value[:max_age]}" if value[:max_age]
|
|
@@ -318,23 +391,22 @@ module Rack
|
|
|
318
391
|
when false, nil
|
|
319
392
|
nil
|
|
320
393
|
when :none, 'None', :None
|
|
321
|
-
';
|
|
394
|
+
'; samesite=none'
|
|
322
395
|
when :lax, 'Lax', :Lax
|
|
323
|
-
';
|
|
396
|
+
'; samesite=lax'
|
|
324
397
|
when true, :strict, 'Strict', :Strict
|
|
325
|
-
';
|
|
398
|
+
'; samesite=strict'
|
|
326
399
|
else
|
|
327
|
-
raise ArgumentError, "Invalid
|
|
400
|
+
raise ArgumentError, "Invalid :same_site value: #{value[:same_site].inspect}"
|
|
328
401
|
end
|
|
402
|
+
partitioned = "; partitioned" if value[:partitioned]
|
|
329
403
|
value = value[:value]
|
|
330
|
-
else
|
|
331
|
-
key = escape(key)
|
|
332
404
|
end
|
|
333
405
|
|
|
334
406
|
value = [value] unless Array === value
|
|
335
407
|
|
|
336
408
|
return "#{key}=#{value.map { |v| escape v }.join('&')}#{domain}" \
|
|
337
|
-
"#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}"
|
|
409
|
+
"#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}#{partitioned}"
|
|
338
410
|
end
|
|
339
411
|
|
|
340
412
|
# :call-seq:
|
|
@@ -375,24 +447,12 @@ module Rack
|
|
|
375
447
|
set_cookie_header(key, value.merge(max_age: '0', expires: Time.at(0), value: ''))
|
|
376
448
|
end
|
|
377
449
|
|
|
378
|
-
def make_delete_cookie_header(header, key, value)
|
|
379
|
-
warn("make_delete_cookie_header is deprecated and will be removed in Rack 3.1, use delete_set_cookie_header! instead", uplevel: 1)
|
|
380
|
-
|
|
381
|
-
delete_set_cookie_header!(header, key, value)
|
|
382
|
-
end
|
|
383
|
-
|
|
384
450
|
def delete_cookie_header!(headers, key, value = {})
|
|
385
451
|
headers[SET_COOKIE] = delete_set_cookie_header!(headers[SET_COOKIE], key, value)
|
|
386
452
|
|
|
387
453
|
return nil
|
|
388
454
|
end
|
|
389
455
|
|
|
390
|
-
def add_remove_cookie_to_header(header, key, value = {})
|
|
391
|
-
warn("add_remove_cookie_to_header is deprecated and will be removed in Rack 3.1, use delete_set_cookie_header! instead", uplevel: 1)
|
|
392
|
-
|
|
393
|
-
delete_set_cookie_header!(header, key, value)
|
|
394
|
-
end
|
|
395
|
-
|
|
396
456
|
# :call-seq:
|
|
397
457
|
# delete_set_cookie_header!(header, key, value = {}) -> header value
|
|
398
458
|
#
|
|
@@ -429,15 +489,19 @@ module Rack
|
|
|
429
489
|
# Parses the "Range:" header, if present, into an array of Range objects.
|
|
430
490
|
# Returns nil if the header is missing or syntactically invalid.
|
|
431
491
|
# Returns an empty array if none of the ranges are satisfiable.
|
|
432
|
-
def byte_ranges(env, size)
|
|
433
|
-
get_byte_ranges env['HTTP_RANGE'], size
|
|
492
|
+
def byte_ranges(env, size, max_ranges: 100)
|
|
493
|
+
get_byte_ranges env['HTTP_RANGE'], size, max_ranges: max_ranges
|
|
434
494
|
end
|
|
435
495
|
|
|
436
|
-
def get_byte_ranges(http_range, size)
|
|
496
|
+
def get_byte_ranges(http_range, size, max_ranges: 100)
|
|
437
497
|
# See <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35>
|
|
498
|
+
# Ignore Range when file size is 0 to avoid a 416 error.
|
|
499
|
+
return nil if size.zero?
|
|
438
500
|
return nil unless http_range && http_range =~ /bytes=([^;]+)/
|
|
501
|
+
byte_range = $1
|
|
502
|
+
return nil if byte_range.count(',') >= max_ranges
|
|
439
503
|
ranges = []
|
|
440
|
-
|
|
504
|
+
byte_range.split(/,[ \t]*/).each do |range_spec|
|
|
441
505
|
return nil unless range_spec.include?('-')
|
|
442
506
|
range = range_spec.split('-')
|
|
443
507
|
r0, r1 = range[0], range[1]
|
|
@@ -517,39 +581,12 @@ module Rack
|
|
|
517
581
|
end
|
|
518
582
|
end
|
|
519
583
|
|
|
520
|
-
# A wrapper around Headers
|
|
521
|
-
# header when set.
|
|
522
|
-
#
|
|
523
|
-
# @api private
|
|
524
|
-
class HeaderHash < Hash # :nodoc:
|
|
525
|
-
def self.[](headers)
|
|
526
|
-
warn "Rack::Utils::HeaderHash is deprecated and will be removed in Rack 3.1, switch to Rack::Headers", uplevel: 1
|
|
527
|
-
if headers.is_a?(Headers) && !headers.frozen?
|
|
528
|
-
return headers
|
|
529
|
-
end
|
|
530
|
-
|
|
531
|
-
new_headers = Headers.new
|
|
532
|
-
headers.each{|k,v| new_headers[k] = v}
|
|
533
|
-
new_headers
|
|
534
|
-
end
|
|
535
|
-
|
|
536
|
-
def self.new(hash = {})
|
|
537
|
-
warn "Rack::Utils::HeaderHash is deprecated and will be removed in Rack 3.1, switch to Rack::Headers", uplevel: 1
|
|
538
|
-
headers = Headers.new
|
|
539
|
-
hash.each{|k,v| headers[k] = v}
|
|
540
|
-
headers
|
|
541
|
-
end
|
|
542
|
-
|
|
543
|
-
def self.allocate
|
|
544
|
-
raise TypeError, "cannot allocate HeaderHash"
|
|
545
|
-
end
|
|
546
|
-
end
|
|
547
|
-
|
|
548
584
|
# Every standard HTTP code mapped to the appropriate message.
|
|
549
585
|
# Generated with:
|
|
550
|
-
# curl -s https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv
|
|
551
|
-
# ruby -
|
|
552
|
-
#
|
|
586
|
+
# curl -s https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv \
|
|
587
|
+
# | ruby -rcsv -e "puts CSV.parse(STDIN, headers: true) \
|
|
588
|
+
# .reject {|v| v['Description'] == 'Unassigned' or v['Description'].include? '(' } \
|
|
589
|
+
# .map {|v| %Q/#{v['Value']} => '#{v['Description']}'/ }.join(','+?\n)"
|
|
553
590
|
HTTP_STATUS_CODES = {
|
|
554
591
|
100 => 'Continue',
|
|
555
592
|
101 => 'Switching Protocols',
|
|
@@ -571,7 +608,6 @@ module Rack
|
|
|
571
608
|
303 => 'See Other',
|
|
572
609
|
304 => 'Not Modified',
|
|
573
610
|
305 => 'Use Proxy',
|
|
574
|
-
306 => '(Unused)',
|
|
575
611
|
307 => 'Temporary Redirect',
|
|
576
612
|
308 => 'Permanent Redirect',
|
|
577
613
|
400 => 'Bad Request',
|
|
@@ -587,13 +623,13 @@ module Rack
|
|
|
587
623
|
410 => 'Gone',
|
|
588
624
|
411 => 'Length Required',
|
|
589
625
|
412 => 'Precondition Failed',
|
|
590
|
-
413 => '
|
|
626
|
+
413 => 'Content Too Large',
|
|
591
627
|
414 => 'URI Too Long',
|
|
592
628
|
415 => 'Unsupported Media Type',
|
|
593
629
|
416 => 'Range Not Satisfiable',
|
|
594
630
|
417 => 'Expectation Failed',
|
|
595
631
|
421 => 'Misdirected Request',
|
|
596
|
-
422 => 'Unprocessable
|
|
632
|
+
422 => 'Unprocessable Content',
|
|
597
633
|
423 => 'Locked',
|
|
598
634
|
424 => 'Failed Dependency',
|
|
599
635
|
425 => 'Too Early',
|
|
@@ -601,7 +637,7 @@ module Rack
|
|
|
601
637
|
428 => 'Precondition Required',
|
|
602
638
|
429 => 'Too Many Requests',
|
|
603
639
|
431 => 'Request Header Fields Too Large',
|
|
604
|
-
451 => 'Unavailable
|
|
640
|
+
451 => 'Unavailable For Legal Reasons',
|
|
605
641
|
500 => 'Internal Server Error',
|
|
606
642
|
501 => 'Not Implemented',
|
|
607
643
|
502 => 'Bad Gateway',
|
|
@@ -611,8 +647,6 @@ module Rack
|
|
|
611
647
|
506 => 'Variant Also Negotiates',
|
|
612
648
|
507 => 'Insufficient Storage',
|
|
613
649
|
508 => 'Loop Detected',
|
|
614
|
-
509 => 'Bandwidth Limit Exceeded',
|
|
615
|
-
510 => 'Not Extended',
|
|
616
650
|
511 => 'Network Authentication Required'
|
|
617
651
|
}
|
|
618
652
|
|
|
@@ -620,12 +654,34 @@ module Rack
|
|
|
620
654
|
STATUS_WITH_NO_ENTITY_BODY = Hash[((100..199).to_a << 204 << 304).product([true])]
|
|
621
655
|
|
|
622
656
|
SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message|
|
|
623
|
-
[message.downcase.gsub(/\s
|
|
657
|
+
[message.downcase.gsub(/\s|-/, '_').to_sym, code]
|
|
624
658
|
}.flatten]
|
|
625
659
|
|
|
660
|
+
OBSOLETE_SYMBOLS_TO_STATUS_CODES = {
|
|
661
|
+
payload_too_large: 413,
|
|
662
|
+
unprocessable_entity: 422,
|
|
663
|
+
bandwidth_limit_exceeded: 509,
|
|
664
|
+
not_extended: 510
|
|
665
|
+
}.freeze
|
|
666
|
+
private_constant :OBSOLETE_SYMBOLS_TO_STATUS_CODES
|
|
667
|
+
|
|
668
|
+
OBSOLETE_SYMBOL_MAPPINGS = {
|
|
669
|
+
payload_too_large: :content_too_large,
|
|
670
|
+
unprocessable_entity: :unprocessable_content
|
|
671
|
+
}.freeze
|
|
672
|
+
private_constant :OBSOLETE_SYMBOL_MAPPINGS
|
|
673
|
+
|
|
626
674
|
def status_code(status)
|
|
627
675
|
if status.is_a?(Symbol)
|
|
628
|
-
SYMBOL_TO_STATUS_CODE.fetch(status)
|
|
676
|
+
SYMBOL_TO_STATUS_CODE.fetch(status) do
|
|
677
|
+
fallback_code = OBSOLETE_SYMBOLS_TO_STATUS_CODES.fetch(status) { raise ArgumentError, "Unrecognized status code #{status.inspect}" }
|
|
678
|
+
message = "Status code #{status.inspect} is deprecated and will be removed in a future version of Rack."
|
|
679
|
+
if canonical_symbol = OBSOLETE_SYMBOL_MAPPINGS[status]
|
|
680
|
+
message = "#{message} Please use #{canonical_symbol.inspect} instead."
|
|
681
|
+
end
|
|
682
|
+
warn message, uplevel: 3
|
|
683
|
+
fallback_code
|
|
684
|
+
end
|
|
629
685
|
else
|
|
630
686
|
status.to_i
|
|
631
687
|
end
|
data/lib/rack/version.rb
CHANGED
|
@@ -5,30 +5,13 @@
|
|
|
5
5
|
# Rack is freely distributable under the terms of an MIT-style license.
|
|
6
6
|
# See MIT-LICENSE or https://opensource.org/licenses/MIT.
|
|
7
7
|
|
|
8
|
-
# The Rack main module, serving as a namespace for all core Rack
|
|
9
|
-
# modules and classes.
|
|
10
|
-
#
|
|
11
|
-
# All modules meant for use in your application are <tt>autoload</tt>ed here,
|
|
12
|
-
# so it should be enough just to <tt>require 'rack'</tt> in your code.
|
|
13
|
-
|
|
14
8
|
module Rack
|
|
15
|
-
|
|
16
|
-
VERSION = [1, 3].freeze
|
|
17
|
-
deprecate_constant :VERSION
|
|
9
|
+
VERSION = "3.2.6"
|
|
18
10
|
|
|
19
|
-
|
|
20
|
-
deprecate_constant :VERSION_STRING
|
|
21
|
-
|
|
22
|
-
# The Rack protocol version number implemented.
|
|
23
|
-
def self.version
|
|
24
|
-
warn "Rack.version is deprecated and will be removed in Rack 3.1!", uplevel: 1
|
|
25
|
-
VERSION
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
RELEASE = "3.0.15"
|
|
11
|
+
RELEASE = VERSION
|
|
29
12
|
|
|
30
13
|
# Return the Rack release as a dotted string.
|
|
31
14
|
def self.release
|
|
32
|
-
|
|
15
|
+
VERSION
|
|
33
16
|
end
|
|
34
17
|
end
|
data/lib/rack.rb
CHANGED
|
@@ -15,10 +15,10 @@ require_relative 'rack/version'
|
|
|
15
15
|
require_relative 'rack/constants'
|
|
16
16
|
|
|
17
17
|
module Rack
|
|
18
|
+
autoload :BadRequest, "rack/bad_request"
|
|
18
19
|
autoload :BodyProxy, "rack/body_proxy"
|
|
19
20
|
autoload :Builder, "rack/builder"
|
|
20
21
|
autoload :Cascade, "rack/cascade"
|
|
21
|
-
autoload :Chunked, "rack/chunked"
|
|
22
22
|
autoload :CommonLogger, "rack/common_logger"
|
|
23
23
|
autoload :ConditionalGet, "rack/conditional_get"
|
|
24
24
|
autoload :Config, "rack/config"
|
|
@@ -28,14 +28,12 @@ module Rack
|
|
|
28
28
|
autoload :Directory, "rack/directory"
|
|
29
29
|
autoload :ETag, "rack/etag"
|
|
30
30
|
autoload :Events, "rack/events"
|
|
31
|
-
autoload :File, "rack/file"
|
|
32
31
|
autoload :Files, "rack/files"
|
|
33
32
|
autoload :ForwardRequest, "rack/recursive"
|
|
34
33
|
autoload :Head, "rack/head"
|
|
35
34
|
autoload :Headers, "rack/headers"
|
|
36
35
|
autoload :Lint, "rack/lint"
|
|
37
36
|
autoload :Lock, "rack/lock"
|
|
38
|
-
autoload :Logger, "rack/logger"
|
|
39
37
|
autoload :MediaType, "rack/media_type"
|
|
40
38
|
autoload :MethodOverride, "rack/method_override"
|
|
41
39
|
autoload :Mime, "rack/mime"
|
|
@@ -60,7 +58,6 @@ module Rack
|
|
|
60
58
|
|
|
61
59
|
module Auth
|
|
62
60
|
autoload :Basic, "rack/auth/basic"
|
|
63
|
-
autoload :Digest, "rack/auth/digest"
|
|
64
61
|
autoload :AbstractHandler, "rack/auth/abstract/handler"
|
|
65
62
|
autoload :AbstractRequest, "rack/auth/abstract/request"
|
|
66
63
|
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rack
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.2.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Leah Neukirchen
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: minitest
|
|
@@ -75,9 +75,9 @@ email: leah@vuxu.org
|
|
|
75
75
|
executables: []
|
|
76
76
|
extensions: []
|
|
77
77
|
extra_rdoc_files:
|
|
78
|
-
- README.md
|
|
79
78
|
- CHANGELOG.md
|
|
80
79
|
- CONTRIBUTING.md
|
|
80
|
+
- README.md
|
|
81
81
|
files:
|
|
82
82
|
- CHANGELOG.md
|
|
83
83
|
- CONTRIBUTING.md
|
|
@@ -88,15 +88,10 @@ files:
|
|
|
88
88
|
- lib/rack/auth/abstract/handler.rb
|
|
89
89
|
- lib/rack/auth/abstract/request.rb
|
|
90
90
|
- lib/rack/auth/basic.rb
|
|
91
|
-
- lib/rack/
|
|
92
|
-
- lib/rack/auth/digest/md5.rb
|
|
93
|
-
- lib/rack/auth/digest/nonce.rb
|
|
94
|
-
- lib/rack/auth/digest/params.rb
|
|
95
|
-
- lib/rack/auth/digest/request.rb
|
|
91
|
+
- lib/rack/bad_request.rb
|
|
96
92
|
- lib/rack/body_proxy.rb
|
|
97
93
|
- lib/rack/builder.rb
|
|
98
94
|
- lib/rack/cascade.rb
|
|
99
|
-
- lib/rack/chunked.rb
|
|
100
95
|
- lib/rack/common_logger.rb
|
|
101
96
|
- lib/rack/conditional_get.rb
|
|
102
97
|
- lib/rack/config.rb
|
|
@@ -107,13 +102,11 @@ files:
|
|
|
107
102
|
- lib/rack/directory.rb
|
|
108
103
|
- lib/rack/etag.rb
|
|
109
104
|
- lib/rack/events.rb
|
|
110
|
-
- lib/rack/file.rb
|
|
111
105
|
- lib/rack/files.rb
|
|
112
106
|
- lib/rack/head.rb
|
|
113
107
|
- lib/rack/headers.rb
|
|
114
108
|
- lib/rack/lint.rb
|
|
115
109
|
- lib/rack/lock.rb
|
|
116
|
-
- lib/rack/logger.rb
|
|
117
110
|
- lib/rack/media_type.rb
|
|
118
111
|
- lib/rack/method_override.rb
|
|
119
112
|
- lib/rack/mime.rb
|
|
@@ -148,6 +141,7 @@ metadata:
|
|
|
148
141
|
changelog_uri: https://github.com/rack/rack/blob/main/CHANGELOG.md
|
|
149
142
|
documentation_uri: https://rubydoc.info/github/rack/rack
|
|
150
143
|
source_code_uri: https://github.com/rack/rack
|
|
144
|
+
rubygems_mfa_required: 'true'
|
|
151
145
|
rdoc_options: []
|
|
152
146
|
require_paths:
|
|
153
147
|
- lib
|
|
@@ -162,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
162
156
|
- !ruby/object:Gem::Version
|
|
163
157
|
version: '0'
|
|
164
158
|
requirements: []
|
|
165
|
-
rubygems_version:
|
|
159
|
+
rubygems_version: 4.0.6
|
|
166
160
|
specification_version: 4
|
|
167
161
|
summary: A modular Ruby webserver interface.
|
|
168
162
|
test_files: []
|
data/lib/rack/auth/digest/md5.rb
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
require_relative '../digest'
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
require_relative '../digest'
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
require_relative '../digest'
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
require_relative '../digest'
|