rack 3.0.11 → 3.1.10

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.
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'ostruct'
4
3
  require 'erb'
5
4
 
6
5
  require_relative 'constants'
@@ -19,6 +18,11 @@ module Rack
19
18
  class ShowExceptions
20
19
  CONTEXT = 7
21
20
 
21
+ Frame = Struct.new(:filename, :lineno, :function,
22
+ :pre_context_lineno, :pre_context,
23
+ :context_line, :post_context_lineno,
24
+ :post_context)
25
+
22
26
  def initialize(app)
23
27
  @app = app
24
28
  end
@@ -79,7 +83,7 @@ module Rack
79
83
  # This double assignment is to prevent an "unused variable" warning.
80
84
  # Yes, it is dumb, but I don't like Ruby yelling at me.
81
85
  frames = frames = exception.backtrace.map { |line|
82
- frame = OpenStruct.new
86
+ frame = Frame.new
83
87
  if line =~ /(.*?):(\d+)(:in `(.*)')?/
84
88
  frame.filename = $1
85
89
  frame.lineno = $2.to_i
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)
@@ -184,20 +177,16 @@ module Rack
184
177
  matches&.first
185
178
  end
186
179
 
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] }
180
+ # Introduced in ERB 4.0. ERB::Escape is an alias for ERB::Utils which
181
+ # doesn't get monkey-patched by rails
182
+ if defined?(ERB::Escape) && ERB::Escape.instance_method(:html_escape)
183
+ define_method(:escape_html, ERB::Escape.instance_method(:html_escape))
184
+ else
185
+ require 'cgi/escape'
186
+ # Escape ampersands, brackets and quotes to their HTML/XML entities.
187
+ def escape_html(string)
188
+ CGI.escapeHTML(string.to_s)
189
+ end
201
190
  end
202
191
 
203
192
  def select_best_encoding(available_encodings, accept_encoding)
@@ -252,21 +241,6 @@ module Rack
252
241
  end
253
242
  end
254
243
 
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
244
  # :call-seq:
271
245
  # parse_cookies(env) -> hash
272
246
  #
@@ -280,6 +254,20 @@ module Rack
280
254
  parse_cookies_header env[HTTP_COOKIE]
281
255
  end
282
256
 
257
+ # A valid cookie key according to RFC2616.
258
+ # 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: ( ) < > @ , ; : \ " / [ ] ? = { }.
259
+ VALID_COOKIE_KEY = /\A[!#$%&'*+\-\.\^_`|~0-9a-zA-Z]+\z/.freeze
260
+ private_constant :VALID_COOKIE_KEY
261
+
262
+ private def escape_cookie_key(key)
263
+ if key =~ VALID_COOKIE_KEY
264
+ key
265
+ else
266
+ warn "Cookie key #{key.inspect} is not valid according to RFC2616; it will be escaped. This behaviour is deprecated and will be removed in a future version of Rack.", uplevel: 2
267
+ escape(key)
268
+ end
269
+ end
270
+
283
271
  # :call-seq:
284
272
  # set_cookie_header(key, value) -> encoded string
285
273
  #
@@ -306,7 +294,7 @@ module Rack
306
294
  def set_cookie_header(key, value)
307
295
  case value
308
296
  when Hash
309
- key = escape(key) unless value[:escape_key] == false
297
+ key = escape_cookie_key(key) unless value[:escape_key] == false
310
298
  domain = "; domain=#{value[:domain]}" if value[:domain]
311
299
  path = "; path=#{value[:path]}" if value[:path]
312
300
  max_age = "; max-age=#{value[:max_age]}" if value[:max_age]
@@ -318,23 +306,24 @@ module Rack
318
306
  when false, nil
319
307
  nil
320
308
  when :none, 'None', :None
321
- '; SameSite=None'
309
+ '; samesite=none'
322
310
  when :lax, 'Lax', :Lax
323
- '; SameSite=Lax'
311
+ '; samesite=lax'
324
312
  when true, :strict, 'Strict', :Strict
325
- '; SameSite=Strict'
313
+ '; samesite=strict'
326
314
  else
327
- raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}"
315
+ raise ArgumentError, "Invalid :same_site value: #{value[:same_site].inspect}"
328
316
  end
317
+ partitioned = "; partitioned" if value[:partitioned]
329
318
  value = value[:value]
330
319
  else
331
- key = escape(key)
320
+ key = escape_cookie_key(key)
332
321
  end
333
322
 
334
323
  value = [value] unless Array === value
335
324
 
336
325
  return "#{key}=#{value.map { |v| escape v }.join('&')}#{domain}" \
337
- "#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}"
326
+ "#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}#{partitioned}"
338
327
  end
339
328
 
340
329
  # :call-seq:
@@ -375,24 +364,12 @@ module Rack
375
364
  set_cookie_header(key, value.merge(max_age: '0', expires: Time.at(0), value: ''))
376
365
  end
377
366
 
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
367
  def delete_cookie_header!(headers, key, value = {})
385
368
  headers[SET_COOKIE] = delete_set_cookie_header!(headers[SET_COOKIE], key, value)
386
369
 
387
370
  return nil
388
371
  end
389
372
 
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
373
  # :call-seq:
397
374
  # delete_set_cookie_header!(header, key, value = {}) -> header value
398
375
  #
@@ -435,6 +412,8 @@ module Rack
435
412
 
436
413
  def get_byte_ranges(http_range, size)
437
414
  # See <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35>
415
+ # Ignore Range when file size is 0 to avoid a 416 error.
416
+ return nil if size.zero?
438
417
  return nil unless http_range && http_range =~ /bytes=([^;]+)/
439
418
  ranges = []
440
419
  $1.split(/,\s*/).each do |range_spec|
@@ -517,39 +496,12 @@ module Rack
517
496
  end
518
497
  end
519
498
 
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
499
  # Every standard HTTP code mapped to the appropriate message.
549
500
  # 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,"'
501
+ # curl -s https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv \
502
+ # | ruby -rcsv -e "puts CSV.parse(STDIN, headers: true) \
503
+ # .reject {|v| v['Description'] == 'Unassigned' or v['Description'].include? '(' } \
504
+ # .map {|v| %Q/#{v['Value']} => '#{v['Description']}'/ }.join(','+?\n)"
553
505
  HTTP_STATUS_CODES = {
554
506
  100 => 'Continue',
555
507
  101 => 'Switching Protocols',
@@ -571,7 +523,6 @@ module Rack
571
523
  303 => 'See Other',
572
524
  304 => 'Not Modified',
573
525
  305 => 'Use Proxy',
574
- 306 => '(Unused)',
575
526
  307 => 'Temporary Redirect',
576
527
  308 => 'Permanent Redirect',
577
528
  400 => 'Bad Request',
@@ -587,13 +538,13 @@ module Rack
587
538
  410 => 'Gone',
588
539
  411 => 'Length Required',
589
540
  412 => 'Precondition Failed',
590
- 413 => 'Payload Too Large',
541
+ 413 => 'Content Too Large',
591
542
  414 => 'URI Too Long',
592
543
  415 => 'Unsupported Media Type',
593
544
  416 => 'Range Not Satisfiable',
594
545
  417 => 'Expectation Failed',
595
546
  421 => 'Misdirected Request',
596
- 422 => 'Unprocessable Entity',
547
+ 422 => 'Unprocessable Content',
597
548
  423 => 'Locked',
598
549
  424 => 'Failed Dependency',
599
550
  425 => 'Too Early',
@@ -601,7 +552,7 @@ module Rack
601
552
  428 => 'Precondition Required',
602
553
  429 => 'Too Many Requests',
603
554
  431 => 'Request Header Fields Too Large',
604
- 451 => 'Unavailable for Legal Reasons',
555
+ 451 => 'Unavailable For Legal Reasons',
605
556
  500 => 'Internal Server Error',
606
557
  501 => 'Not Implemented',
607
558
  502 => 'Bad Gateway',
@@ -611,8 +562,6 @@ module Rack
611
562
  506 => 'Variant Also Negotiates',
612
563
  507 => 'Insufficient Storage',
613
564
  508 => 'Loop Detected',
614
- 509 => 'Bandwidth Limit Exceeded',
615
- 510 => 'Not Extended',
616
565
  511 => 'Network Authentication Required'
617
566
  }
618
567
 
@@ -620,12 +569,36 @@ module Rack
620
569
  STATUS_WITH_NO_ENTITY_BODY = Hash[((100..199).to_a << 204 << 304).product([true])]
621
570
 
622
571
  SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message|
623
- [message.downcase.gsub(/\s|-|'/, '_').to_sym, code]
572
+ [message.downcase.gsub(/\s|-/, '_').to_sym, code]
624
573
  }.flatten]
625
574
 
575
+ OBSOLETE_SYMBOLS_TO_STATUS_CODES = {
576
+ payload_too_large: 413,
577
+ unprocessable_entity: 422,
578
+ bandwidth_limit_exceeded: 509,
579
+ not_extended: 510
580
+ }.freeze
581
+ private_constant :OBSOLETE_SYMBOLS_TO_STATUS_CODES
582
+
583
+ OBSOLETE_SYMBOL_MAPPINGS = {
584
+ payload_too_large: :content_too_large,
585
+ unprocessable_entity: :unprocessable_content
586
+ }.freeze
587
+ private_constant :OBSOLETE_SYMBOL_MAPPINGS
588
+
626
589
  def status_code(status)
627
590
  if status.is_a?(Symbol)
628
- SYMBOL_TO_STATUS_CODE.fetch(status) { raise ArgumentError, "Unrecognized status code #{status.inspect}" }
591
+ SYMBOL_TO_STATUS_CODE.fetch(status) do
592
+ fallback_code = OBSOLETE_SYMBOLS_TO_STATUS_CODES.fetch(status) { raise ArgumentError, "Unrecognized status code #{status.inspect}" }
593
+ message = "Status code #{status.inspect} is deprecated and will be removed in a future version of Rack."
594
+ if canonical_symbol = OBSOLETE_SYMBOL_MAPPINGS[status]
595
+ # message = "#{message} Please use #{canonical_symbol.inspect} instead."
596
+ # For now, let's not emit any warning when there is a mapping.
597
+ else
598
+ warn message, uplevel: 3
599
+ end
600
+ fallback_code
601
+ end
629
602
  else
630
603
  status.to_i
631
604
  end
data/lib/rack/version.rb CHANGED
@@ -12,20 +12,7 @@
12
12
  # so it should be enough just to <tt>require 'rack'</tt> in your code.
13
13
 
14
14
  module Rack
15
- # The Rack protocol version number implemented.
16
- VERSION = [1, 3].freeze
17
- deprecate_constant :VERSION
18
-
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.11"
15
+ RELEASE = "3.1.10"
29
16
 
30
17
  # Return the Rack release as a dotted string.
31
18
  def self.release
data/lib/rack.rb CHANGED
@@ -15,23 +15,21 @@ require_relative 'rack/version'
15
15
  require_relative 'rack/constants'
16
16
 
17
17
  module Rack
18
- autoload :Builder, "rack/builder"
18
+ autoload :BadRequest, "rack/bad_request"
19
19
  autoload :BodyProxy, "rack/body_proxy"
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"
25
25
  autoload :ContentLength, "rack/content_length"
26
26
  autoload :ContentType, "rack/content_type"
27
+ autoload :Deflater, "rack/deflater"
28
+ autoload :Directory, "rack/directory"
27
29
  autoload :ETag, "rack/etag"
28
30
  autoload :Events, "rack/events"
29
- autoload :File, "rack/file"
30
31
  autoload :Files, "rack/files"
31
- autoload :Deflater, "rack/deflater"
32
- autoload :Directory, "rack/directory"
33
32
  autoload :ForwardRequest, "rack/recursive"
34
- autoload :Handler, "rack/handler"
35
33
  autoload :Head, "rack/head"
36
34
  autoload :Headers, "rack/headers"
37
35
  autoload :Lint, "rack/lint"
@@ -40,32 +38,28 @@ module Rack
40
38
  autoload :MediaType, "rack/media_type"
41
39
  autoload :MethodOverride, "rack/method_override"
42
40
  autoload :Mime, "rack/mime"
41
+ autoload :MockRequest, "rack/mock_request"
42
+ autoload :MockResponse, "rack/mock_response"
43
+ autoload :Multipart, "rack/multipart"
43
44
  autoload :NullLogger, "rack/null_logger"
44
45
  autoload :QueryParser, "rack/query_parser"
45
46
  autoload :Recursive, "rack/recursive"
46
47
  autoload :Reloader, "rack/reloader"
48
+ autoload :Request, "rack/request"
49
+ autoload :Response, "rack/response"
47
50
  autoload :RewindableInput, "rack/rewindable_input"
48
51
  autoload :Runtime, "rack/runtime"
49
52
  autoload :Sendfile, "rack/sendfile"
50
- autoload :Server, "rack/server"
51
53
  autoload :ShowExceptions, "rack/show_exceptions"
52
54
  autoload :ShowStatus, "rack/show_status"
53
55
  autoload :Static, "rack/static"
54
56
  autoload :TempfileReaper, "rack/tempfile_reaper"
55
57
  autoload :URLMap, "rack/urlmap"
56
58
  autoload :Utils, "rack/utils"
57
- autoload :Multipart, "rack/multipart"
58
-
59
- autoload :MockRequest, "rack/mock_request"
60
- autoload :MockResponse, "rack/mock_response"
61
-
62
- autoload :Request, "rack/request"
63
- autoload :Response, "rack/response"
64
59
 
65
60
  module Auth
66
61
  autoload :Basic, "rack/auth/basic"
67
- autoload :AbstractRequest, "rack/auth/abstract/request"
68
62
  autoload :AbstractHandler, "rack/auth/abstract/handler"
69
- autoload :Digest, "rack/auth/digest"
63
+ autoload :AbstractRequest, "rack/auth/abstract/request"
70
64
  end
71
65
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.11
4
+ version: 3.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leah Neukirchen
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-05-09 00:00:00.000000000 Z
10
+ date: 2025-02-12 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: minitest
@@ -89,15 +88,10 @@ files:
89
88
  - lib/rack/auth/abstract/handler.rb
90
89
  - lib/rack/auth/abstract/request.rb
91
90
  - lib/rack/auth/basic.rb
92
- - lib/rack/auth/digest.rb
93
- - lib/rack/auth/digest/md5.rb
94
- - lib/rack/auth/digest/nonce.rb
95
- - lib/rack/auth/digest/params.rb
96
- - lib/rack/auth/digest/request.rb
91
+ - lib/rack/bad_request.rb
97
92
  - lib/rack/body_proxy.rb
98
93
  - lib/rack/builder.rb
99
94
  - lib/rack/cascade.rb
100
- - lib/rack/chunked.rb
101
95
  - lib/rack/common_logger.rb
102
96
  - lib/rack/conditional_get.rb
103
97
  - lib/rack/config.rb
@@ -108,7 +102,6 @@ files:
108
102
  - lib/rack/directory.rb
109
103
  - lib/rack/etag.rb
110
104
  - lib/rack/events.rb
111
- - lib/rack/file.rb
112
105
  - lib/rack/files.rb
113
106
  - lib/rack/head.rb
114
107
  - lib/rack/headers.rb
@@ -149,7 +142,6 @@ metadata:
149
142
  changelog_uri: https://github.com/rack/rack/blob/main/CHANGELOG.md
150
143
  documentation_uri: https://rubydoc.info/github/rack/rack
151
144
  source_code_uri: https://github.com/rack/rack
152
- post_install_message:
153
145
  rdoc_options: []
154
146
  require_paths:
155
147
  - lib
@@ -164,8 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
156
  - !ruby/object:Gem::Version
165
157
  version: '0'
166
158
  requirements: []
167
- rubygems_version: 3.5.3
168
- signing_key:
159
+ rubygems_version: 3.6.2
169
160
  specification_version: 4
170
161
  summary: A modular Ruby webserver interface.
171
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'