rack 3.0.4.2 → 3.0.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36b4b5641dd1307c3ce6c486779ed3ff238dd2e102e65dc2eb07a83467cd0acd
4
- data.tar.gz: 59205f18ca54c8c03018ccc532a05af39b52cb63bf50f8be6138301620e3b4b5
3
+ metadata.gz: 14dbe09610211d4f7ea05476089ae7c5a276f62d267dea6f3902bdfbe8ecab6b
4
+ data.tar.gz: 12354e0b19330b88a4fe73e5675625b3ae096e6e2db087fc2e8d4167f4c10368
5
5
  SHA512:
6
- metadata.gz: ad6b22a618316744e50fc27a90348d7208b764ef7734555dd32d51b88b13e75023e367926bb18a898d742f0e2c97c188949be1c47678a442f804d04bff4a2326
7
- data.tar.gz: b05200d6b7d5c6a0d2035577ffb5c5098d2d78dee3a5f7de5754c65950d53c7dbe7438e1f1a8f6d13d2122e1e6f721541f12ec77886cc32f5c99dd5c0606f5f8
6
+ metadata.gz: eee29ac6d6b1f61355b1e802fece0f3d4af51603cfd0dca142ed7846f26059467a8cc08143f4dab9bfcb2fa20f93fd67d7654b23c9898b545761de0b1ea57003
7
+ data.tar.gz: f654a6cb49ed589ec844f930bc8dc0edec5c818665183011215b72c7b3dc7619b1726a2ec6ff045fd1914de85592c2697a8b10b45073744cba98124cc6f19dbb
data/CHANGELOG.md CHANGED
@@ -12,7 +12,7 @@ All notable changes to this project will be documented in this file. For info on
12
12
  - [CVE-2022-44570] Fix ReDoS in Rack::Utils.get_byte_ranges
13
13
  - [CVE-2022-44572] Forbid control characters in attributes (also ReDoS)
14
14
 
15
- ## [3.0.4] - 2022-01-17
15
+ ## [3.0.4] - 2023-01-17
16
16
 
17
17
  - `Rack::Request#POST` should consistently raise errors. Cache errors that occur when invoking `Rack::Request#POST` so they can be raised again later. ([#2010](https://github.com/rack/rack/pull/2010), [@ioquatix])
18
18
  - Fix `Rack::Lint` error message for `HTTP_CONTENT_TYPE` and `HTTP_CONTENT_LENGTH`. ([#2007](https://github.com/rack/rack/pull/2007), [@byroot](https://github.com/byroot))
@@ -54,11 +54,13 @@ module Rack
54
54
  RACK_RESPONSE_FINISHED = 'rack.response_finished'
55
55
  RACK_REQUEST_FORM_INPUT = 'rack.request.form_input'
56
56
  RACK_REQUEST_FORM_HASH = 'rack.request.form_hash'
57
+ RACK_REQUEST_FORM_PAIRS = 'rack.request.form_pairs'
57
58
  RACK_REQUEST_FORM_VARS = 'rack.request.form_vars'
58
59
  RACK_REQUEST_FORM_ERROR = 'rack.request.form_error'
59
60
  RACK_REQUEST_COOKIE_HASH = 'rack.request.cookie_hash'
60
61
  RACK_REQUEST_COOKIE_STRING = 'rack.request.cookie_string'
61
62
  RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash'
63
+ RACK_REQUEST_QUERY_PAIRS = 'rack.request.query_pairs'
62
64
  RACK_REQUEST_QUERY_STRING = 'rack.request.query_string'
63
65
  RACK_METHODOVERRIDE_ORIGINAL_METHOD = 'rack.methodoverride.original_method'
64
66
  end
@@ -13,6 +13,31 @@ module Rack
13
13
  module Multipart
14
14
  MULTIPART_BOUNDARY = "AaB03x"
15
15
 
16
+ # Accumulator for multipart form data, conforming to the QueryParser API.
17
+ # In future, the Parser could return the pair list directly, but that would
18
+ # change its API.
19
+ class ParamList # :nodoc:
20
+ def self.make_params
21
+ new
22
+ end
23
+
24
+ def self.normalize_params(params, key, value)
25
+ params << [key, value]
26
+ end
27
+
28
+ def initialize
29
+ @pairs = []
30
+ end
31
+
32
+ def <<(pair)
33
+ @pairs << pair
34
+ end
35
+
36
+ def to_params_hash
37
+ @pairs
38
+ end
39
+ end
40
+
16
41
  class << self
17
42
  def parse_multipart(env, params = Rack::Utils.default_query_parser)
18
43
  io = env[RACK_INPUT]
@@ -37,19 +37,42 @@ module Rack
37
37
  @param_depth_limit = param_depth_limit
38
38
  end
39
39
 
40
- # Stolen from Mongrel, with some small modifications:
40
+ # Originally stolen from Mongrel, now with some modifications:
41
41
  # Parses a query string by breaking it up at the '&'. You can also use this
42
42
  # to parse cookies by changing the characters used in the second parameter
43
43
  # (which defaults to '&').
44
- def parse_query(qs, separator = nil, &unescaper)
45
- unescaper ||= method(:unescape)
44
+ #
45
+ # Returns an array of 2-element arrays, where the first element is the
46
+ # key and the second element is the value.
47
+ def split_query(qs, separator = nil, &unescaper)
48
+ pairs = []
49
+
50
+ if qs && !qs.empty?
51
+ unescaper ||= method(:unescape)
52
+
53
+ qs.split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p|
54
+ next if p.empty?
55
+ pair = p.split('=', 2).map!(&unescaper)
56
+ pair << nil if pair.length == 1
57
+ pairs << pair
58
+ end
59
+ end
46
60
 
47
- params = make_params
61
+ pairs
62
+ rescue ArgumentError => e
63
+ raise InvalidParameterError, e.message, e.backtrace
64
+ end
48
65
 
49
- (qs || '').split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p|
50
- next if p.empty?
51
- k, v = p.split('=', 2).map!(&unescaper)
66
+ # Parses a query string by breaking it up at the '&'. You can also use this
67
+ # to parse cookies by changing the characters used in the second parameter
68
+ # (which defaults to '&').
69
+ #
70
+ # Returns a hash where each value is a string (when a key only appears once)
71
+ # or an array of strings (when a key appears more than once).
72
+ def parse_query(qs, separator = nil, &unescaper)
73
+ params = make_params
52
74
 
75
+ split_query(qs, separator, &unescaper).each do |k, v|
53
76
  if cur = params[k]
54
77
  if cur.class == Array
55
78
  params[k] << v
@@ -61,7 +84,7 @@ module Rack
61
84
  end
62
85
  end
63
86
 
64
- return params.to_h
87
+ params.to_h
65
88
  end
66
89
 
67
90
  # parse_nested_query expands a query string into structural types. Supported
@@ -72,17 +95,11 @@ module Rack
72
95
  def parse_nested_query(qs, separator = nil)
73
96
  params = make_params
74
97
 
75
- unless qs.nil? || qs.empty?
76
- (qs || '').split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p|
77
- k, v = p.split('=', 2).map! { |s| unescape(s) }
78
-
79
- _normalize_params(params, k, v, 0)
80
- end
98
+ split_query(qs, separator).each do |k, v|
99
+ _normalize_params(params, k, v, 0)
81
100
  end
82
101
 
83
- return params.to_h
84
- rescue ArgumentError => e
85
- raise InvalidParameterError, e.message, e.backtrace
102
+ params.to_h
86
103
  end
87
104
 
88
105
  # normalize_params recursively expands parameters into structural types. If
data/lib/rack/request.rb CHANGED
@@ -483,11 +483,22 @@ module Rack
483
483
  # Returns the data received in the query string.
484
484
  def GET
485
485
  if get_header(RACK_REQUEST_QUERY_STRING) == query_string
486
- get_header(RACK_REQUEST_QUERY_HASH)
486
+ if query_hash = get_header(RACK_REQUEST_QUERY_HASH)
487
+ return query_hash
488
+ end
489
+ end
490
+
491
+ set_header(RACK_REQUEST_QUERY_HASH, expand_params(query_param_list))
492
+ end
493
+
494
+ def query_param_list
495
+ if get_header(RACK_REQUEST_QUERY_STRING) == query_string
496
+ get_header(RACK_REQUEST_QUERY_PAIRS)
487
497
  else
488
- query_hash = parse_query(query_string, '&')
489
- set_header(RACK_REQUEST_QUERY_STRING, query_string)
490
- set_header(RACK_REQUEST_QUERY_HASH, query_hash)
498
+ query_pairs = split_query(query_string, '&')
499
+ set_header RACK_REQUEST_QUERY_STRING, query_string
500
+ set_header RACK_REQUEST_QUERY_HASH, nil
501
+ set_header(RACK_REQUEST_QUERY_PAIRS, query_pairs)
491
502
  end
492
503
  end
493
504
 
@@ -496,32 +507,53 @@ module Rack
496
507
  # This method support both application/x-www-form-urlencoded and
497
508
  # multipart/form-data.
498
509
  def POST
510
+ if get_header(RACK_REQUEST_FORM_INPUT).equal?(get_header(RACK_INPUT))
511
+ if form_hash = get_header(RACK_REQUEST_FORM_HASH)
512
+ return form_hash
513
+ end
514
+ end
515
+
516
+ set_header(RACK_REQUEST_FORM_HASH, expand_params(body_param_list))
517
+ end
518
+
519
+ def body_param_list
499
520
  if error = get_header(RACK_REQUEST_FORM_ERROR)
500
521
  raise error.class, error.message, cause: error.cause
501
522
  end
502
523
 
503
524
  begin
504
- if get_header(RACK_INPUT).nil?
505
- raise "Missing rack.input"
506
- elsif get_header(RACK_REQUEST_FORM_INPUT) == get_header(RACK_INPUT)
507
- get_header(RACK_REQUEST_FORM_HASH)
525
+ rack_input = get_header(RACK_INPUT)
526
+
527
+ form_pairs = nil
528
+
529
+ # If the form data has already been memoized from the same
530
+ # input:
531
+ if get_header(RACK_REQUEST_FORM_INPUT).equal?(rack_input)
532
+ if form_pairs = get_header(RACK_REQUEST_FORM_PAIRS)
533
+ return form_pairs
534
+ end
535
+ end
536
+
537
+ if rack_input.nil?
538
+ form_pairs = []
508
539
  elsif form_data? || parseable_data?
509
- unless set_header(RACK_REQUEST_FORM_HASH, parse_multipart)
510
- form_vars = get_header(RACK_INPUT).read
540
+ unless form_pairs = Rack::Multipart.extract_multipart(self, Rack::Multipart::ParamList)
541
+ form_vars = rack_input.read
511
542
 
512
543
  # Fix for Safari Ajax postings that always append \0
513
544
  # form_vars.sub!(/\0\z/, '') # performance replacement:
514
545
  form_vars.slice!(-1) if form_vars.end_with?("\0")
515
546
 
516
547
  set_header RACK_REQUEST_FORM_VARS, form_vars
517
- set_header RACK_REQUEST_FORM_HASH, parse_query(form_vars, '&')
548
+ form_pairs = split_query(form_vars, '&')
518
549
  end
519
- set_header RACK_REQUEST_FORM_INPUT, get_header(RACK_INPUT)
520
- get_header RACK_REQUEST_FORM_HASH
521
550
  else
522
- set_header RACK_REQUEST_FORM_INPUT, get_header(RACK_INPUT)
523
- set_header(RACK_REQUEST_FORM_HASH, {})
551
+ form_pairs = []
524
552
  end
553
+
554
+ set_header RACK_REQUEST_FORM_INPUT, rack_input
555
+ set_header RACK_REQUEST_FORM_HASH, nil
556
+ set_header(RACK_REQUEST_FORM_PAIRS, form_pairs)
525
557
  rescue => error
526
558
  set_header(RACK_REQUEST_FORM_ERROR, error)
527
559
  raise
@@ -661,6 +693,28 @@ module Rack
661
693
  Rack::Multipart.extract_multipart(self, query_parser)
662
694
  end
663
695
 
696
+ def split_query(query, d = '&')
697
+ query_parser = query_parser()
698
+ unless query_parser.respond_to?(:split_query)
699
+ query_parser = Utils.default_query_parser
700
+ unless query_parser.respond_to?(:split_query)
701
+ query_parser = QueryParser.make_default(0)
702
+ end
703
+ end
704
+
705
+ query_parser.split_query(query, d)
706
+ end
707
+
708
+ def expand_params(pairs, query_parser = query_parser())
709
+ params = query_parser.make_params
710
+
711
+ pairs.each do |key, value|
712
+ query_parser.normalize_params(params, key, value)
713
+ end
714
+
715
+ params.to_params_hash
716
+ end
717
+
664
718
  def split_header(value)
665
719
  value ? value.strip.split(/[,\s]+/) : []
666
720
  end
data/lib/rack/version.rb CHANGED
@@ -25,7 +25,7 @@ module Rack
25
25
  VERSION
26
26
  end
27
27
 
28
- RELEASE = "3.0.4.2"
28
+ RELEASE = "3.0.5"
29
29
 
30
30
  # Return the Rack release as a dotted string.
31
31
  def self.release
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.4.2
4
+ version: 3.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leah Neukirchen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-02 00:00:00.000000000 Z
11
+ date: 2023-03-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -164,7 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
164
  - !ruby/object:Gem::Version
165
165
  version: '0'
166
166
  requirements: []
167
- rubygems_version: 3.4.1
167
+ rubygems_version: 3.4.6
168
168
  signing_key:
169
169
  specification_version: 4
170
170
  summary: A modular Ruby webserver interface.