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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +368 -6
  3. data/CONTRIBUTING.md +11 -9
  4. data/README.md +103 -28
  5. data/SPEC.rdoc +206 -288
  6. data/lib/rack/auth/abstract/request.rb +2 -0
  7. data/lib/rack/auth/basic.rb +1 -2
  8. data/lib/rack/bad_request.rb +8 -0
  9. data/lib/rack/builder.rb +29 -10
  10. data/lib/rack/cascade.rb +0 -3
  11. data/lib/rack/conditional_get.rb +4 -3
  12. data/lib/rack/constants.rb +4 -0
  13. data/lib/rack/directory.rb +6 -3
  14. data/lib/rack/events.rb +21 -6
  15. data/lib/rack/files.rb +1 -1
  16. data/lib/rack/head.rb +2 -3
  17. data/lib/rack/headers.rb +86 -2
  18. data/lib/rack/lint.rb +482 -425
  19. data/lib/rack/media_type.rb +14 -10
  20. data/lib/rack/mime.rb +6 -5
  21. data/lib/rack/mock_request.rb +10 -15
  22. data/lib/rack/mock_response.rb +50 -20
  23. data/lib/rack/multipart/parser.rb +255 -76
  24. data/lib/rack/multipart/uploaded_file.rb +42 -5
  25. data/lib/rack/multipart.rb +34 -1
  26. data/lib/rack/query_parser.rb +86 -78
  27. data/lib/rack/request.rb +78 -65
  28. data/lib/rack/response.rb +28 -20
  29. data/lib/rack/rewindable_input.rb +4 -1
  30. data/lib/rack/sendfile.rb +51 -21
  31. data/lib/rack/show_exceptions.rb +10 -4
  32. data/lib/rack/show_status.rb +0 -2
  33. data/lib/rack/static.rb +7 -3
  34. data/lib/rack/utils.rb +175 -119
  35. data/lib/rack/version.rb +3 -20
  36. data/lib/rack.rb +1 -4
  37. metadata +6 -12
  38. data/lib/rack/auth/digest/md5.rb +0 -1
  39. data/lib/rack/auth/digest/nonce.rb +0 -1
  40. data/lib/rack/auth/digest/params.rb +0 -1
  41. data/lib/rack/auth/digest/request.rb +0 -1
  42. data/lib/rack/auth/digest.rb +0 -256
  43. data/lib/rack/chunked.rb +0 -120
  44. data/lib/rack/file.rb +0 -9
  45. 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
- ::URI::DEFAULT_PARSER.escape s
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
- ::URI::DEFAULT_PARSER.unescape s
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 nil unless forwarded_header
158
- forwarded_header = forwarded_header.to_s.gsub("\n", ";")
159
-
160
- forwarded_header.split(';').each_with_object({}) do |field, values|
161
- field.split(',').each do |pair|
162
- pair = pair.split('=').map(&:strip).join('=')
163
- return nil unless pair =~ /\A(by|for|host|proto)="?([^"]+)"?\Z/i
164
- (values[$1.downcase.to_sym] ||= []) << $2
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
- ESCAPE_HTML = {
188
- "&" => "&amp;",
189
- "<" => "&lt;",
190
- ">" => "&gt;",
191
- "'" => "&#x27;",
192
- '"' => "&quot;",
193
- "/" => "&#x2F;"
194
- }
195
-
196
- ESCAPE_HTML_PATTERN = Regexp.union(*ESCAPE_HTML.keys)
197
-
198
- # Escape ampersands, brackets and quotes to their HTML/XML entities.
199
- def escape_html(string)
200
- string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] }
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
- (available_encodings - accept_encoding.map(&:first)).each do |m2|
213
- expanded_accept_encoding << [m2, q, preference]
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
- .sort_by { |_, q, p| [-q, p] }
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
- '; SameSite=None'
394
+ '; samesite=none'
322
395
  when :lax, 'Lax', :Lax
323
- '; SameSite=Lax'
396
+ '; samesite=lax'
324
397
  when true, :strict, 'Strict', :Strict
325
- '; SameSite=Strict'
398
+ '; samesite=strict'
326
399
  else
327
- raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}"
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
- $1.split(/,\s*/).each do |range_spec|
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 -ne 'm = /^(\d{3}),(?!Unassigned|\(Unused\))([^,]+)/.match($_) and \
552
- # puts "#{m[1]} => \x27#{m[2].strip}\x27,"'
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 => 'Payload Too Large',
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 Entity',
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 for Legal Reasons',
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|-|'/, '_').to_sym, code]
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) { raise ArgumentError, "Unrecognized status code #{status.inspect}" }
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
- # The Rack protocol version number implemented.
16
- VERSION = [1, 3].freeze
17
- deprecate_constant :VERSION
9
+ VERSION = "3.2.6"
18
10
 
19
- VERSION_STRING = "1.3".freeze
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
- RELEASE
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.0.15
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: 2025-04-13 00:00:00.000000000 Z
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/auth/digest.rb
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: 3.6.2
159
+ rubygems_version: 4.0.6
166
160
  specification_version: 4
167
161
  summary: A modular Ruby webserver interface.
168
162
  test_files: []
@@ -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'