rack 3.0.5 → 3.2.0

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.

Potentially problematic release.


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

Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +383 -1
  3. data/CONTRIBUTING.md +11 -9
  4. data/README.md +95 -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/body_proxy.rb +18 -2
  10. data/lib/rack/builder.rb +29 -10
  11. data/lib/rack/cascade.rb +0 -3
  12. data/lib/rack/common_logger.rb +3 -2
  13. data/lib/rack/conditional_get.rb +4 -3
  14. data/lib/rack/constants.rb +3 -1
  15. data/lib/rack/etag.rb +3 -0
  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 +18 -9
  20. data/lib/rack/mime.rb +6 -5
  21. data/lib/rack/mock_request.rb +10 -15
  22. data/lib/rack/mock_response.rb +39 -18
  23. data/lib/rack/multipart/parser.rb +169 -73
  24. data/lib/rack/multipart/uploaded_file.rb +42 -5
  25. data/lib/rack/multipart.rb +9 -1
  26. data/lib/rack/query_parser.rb +86 -97
  27. data/lib/rack/request.rb +67 -100
  28. data/lib/rack/response.rb +29 -19
  29. data/lib/rack/rewindable_input.rb +4 -1
  30. data/lib/rack/sendfile.rb +2 -2
  31. data/lib/rack/show_exceptions.rb +10 -4
  32. data/lib/rack/show_status.rb +0 -2
  33. data/lib/rack/static.rb +2 -1
  34. data/lib/rack/utils.rb +78 -110
  35. data/lib/rack/version.rb +3 -20
  36. data/lib/rack.rb +11 -17
  37. metadata +6 -15
  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
@@ -6,6 +6,8 @@ require_relative 'utils'
6
6
  require_relative 'multipart/parser'
7
7
  require_relative 'multipart/generator'
8
8
 
9
+ require_relative 'bad_request'
10
+
9
11
  module Rack
10
12
  # A multipart form data parser, adapted from IOWA.
11
13
  #
@@ -13,6 +15,10 @@ module Rack
13
15
  module Multipart
14
16
  MULTIPART_BOUNDARY = "AaB03x"
15
17
 
18
+ class MissingInputError < StandardError
19
+ include BadRequest
20
+ end
21
+
16
22
  # Accumulator for multipart form data, conforming to the QueryParser API.
17
23
  # In future, the Parser could return the pair list directly, but that would
18
24
  # change its API.
@@ -40,7 +46,9 @@ module Rack
40
46
 
41
47
  class << self
42
48
  def parse_multipart(env, params = Rack::Utils.default_query_parser)
43
- io = env[RACK_INPUT]
49
+ unless io = env[RACK_INPUT]
50
+ raise MissingInputError, "Missing input stream!"
51
+ end
44
52
 
45
53
  if content_length = env['CONTENT_LENGTH']
46
54
  content_length = content_length.to_i
@@ -1,78 +1,77 @@
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
- DEFAULT_SEP = /[&] */n
6
- COMMON_SEP = { ";" => /[;] */n, ";," => /[;,] */n, "&" => /[&] */n }
8
+ DEFAULT_SEP = /& */n
9
+ COMMON_SEP = { ";" => /; */n, ";," => /[;,] */n, "&" => /& */n }
7
10
 
8
11
  # ParameterTypeError is the error that is raised when incoming structural
9
12
  # parameters (parsed by parse_nested_query) contain conflicting types.
10
- class ParameterTypeError < TypeError; end
13
+ class ParameterTypeError < TypeError
14
+ include BadRequest
15
+ end
11
16
 
12
17
  # InvalidParameterError is the error that is raised when incoming structural
13
18
  # parameters (parsed by parse_nested_query) contain invalid format or byte
14
19
  # sequence.
15
- class InvalidParameterError < ArgumentError; end
20
+ class InvalidParameterError < ArgumentError
21
+ include BadRequest
22
+ end
16
23
 
17
- # ParamsTooDeepError is the error that is raised when params are recursively
18
- # nested over the specified limit.
19
- class ParamsTooDeepError < RangeError; end
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
20
29
 
21
- def self.make_default(_key_space_limit=(not_deprecated = true; nil), param_depth_limit)
22
- unless not_deprecated
23
- warn("`first argument `key_space limit` is deprecated and no longer has an effect. Please call with only one argument, which will be required in a future version of Rack", uplevel: 1)
24
- 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
25
35
 
26
- new Params, param_depth_limit
36
+ def self.make_default(param_depth_limit, **options)
37
+ new(Params, param_depth_limit, **options)
27
38
  end
28
39
 
29
40
  attr_reader :param_depth_limit
30
41
 
31
- def initialize(params_class, _key_space_limit=(not_deprecated = true; nil), param_depth_limit)
32
- unless not_deprecated
33
- warn("`second argument `key_space limit` is deprecated and no longer has an effect. Please call with only two arguments, which will be required in a future version of Rack", uplevel: 1)
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
34
49
  end
35
50
 
36
- @params_class = params_class
37
- @param_depth_limit = param_depth_limit
51
+ val
38
52
  end
39
53
 
40
- # Originally stolen from Mongrel, now with some modifications:
41
- # Parses a query string by breaking it up at the '&'. You can also use this
42
- # to parse cookies by changing the characters used in the second parameter
43
- # (which defaults to '&').
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 = []
54
+ BYTESIZE_LIMIT = env_int.call("RACK_QUERY_PARSER_BYTESIZE_LIMIT", 4194304)
55
+ private_constant :BYTESIZE_LIMIT
49
56
 
50
- if qs && !qs.empty?
51
- unescaper ||= method(:unescape)
57
+ PARAMS_LIMIT = env_int.call("RACK_QUERY_PARSER_PARAMS_LIMIT", 4096)
58
+ private_constant :PARAMS_LIMIT
52
59
 
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
60
-
61
- pairs
62
- rescue ArgumentError => e
63
- raise InvalidParameterError, e.message, e.backtrace
60
+ def initialize(params_class, param_depth_limit, bytesize_limit: BYTESIZE_LIMIT, params_limit: PARAMS_LIMIT)
61
+ @params_class = params_class
62
+ @param_depth_limit = param_depth_limit
63
+ @bytesize_limit = bytesize_limit
64
+ @params_limit = params_limit
64
65
  end
65
66
 
67
+ # Stolen from Mongrel, with some small modifications:
66
68
  # Parses a query string by breaking it up at the '&'. You can also use this
67
69
  # to parse cookies by changing the characters used in the second parameter
68
70
  # (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
71
  def parse_query(qs, separator = nil, &unescaper)
73
72
  params = make_params
74
73
 
75
- split_query(qs, separator, &unescaper).each do |k, v|
74
+ each_query_pair(qs, separator, unescaper) do |k, v|
76
75
  if cur = params[k]
77
76
  if cur.class == Array
78
77
  params[k] << v
@@ -84,7 +83,20 @@ module Rack
84
83
  end
85
84
  end
86
85
 
87
- params.to_h
86
+ return params.to_h
87
+ end
88
+
89
+ # Parses a query string by breaking it up at the '&', returning all key-value
90
+ # pairs as an array of [key, value] arrays. Unlike parse_query, this preserves
91
+ # all duplicate keys rather than collapsing them.
92
+ def parse_query_pairs(qs, separator = nil)
93
+ pairs = []
94
+
95
+ each_query_pair(qs, separator) do |k, v|
96
+ pairs << [k, v]
97
+ end
98
+
99
+ pairs
88
100
  end
89
101
 
90
102
  # parse_nested_query expands a query string into structural types. Supported
@@ -95,11 +107,11 @@ module Rack
95
107
  def parse_nested_query(qs, separator = nil)
96
108
  params = make_params
97
109
 
98
- split_query(qs, separator).each do |k, v|
110
+ each_query_pair(qs, separator) do |k, v|
99
111
  _normalize_params(params, k, v, 0)
100
112
  end
101
113
 
102
- params.to_h
114
+ return params.to_h
103
115
  end
104
116
 
105
117
  # normalize_params recursively expands parameters into structural types. If
@@ -145,8 +157,6 @@ module Rack
145
157
 
146
158
  return if k.empty?
147
159
 
148
- v ||= String.new
149
-
150
160
  if after == ''
151
161
  if k == '[]' && depth != 0
152
162
  return [v]
@@ -207,63 +217,42 @@ module Rack
207
217
  true
208
218
  end
209
219
 
210
- def unescape(s)
211
- Utils.unescape(s)
212
- end
220
+ def each_query_pair(qs, separator, unescaper = nil)
221
+ return if !qs || qs.empty?
213
222
 
214
- class Params
215
- def initialize
216
- @size = 0
217
- @params = {}
223
+ if qs.bytesize > @bytesize_limit
224
+ raise QueryLimitError, "total query size (#{qs.bytesize}) exceeds limit (#{@bytesize_limit})"
218
225
  end
219
226
 
220
- def [](key)
221
- @params[key]
222
- end
227
+ pairs = qs.split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP, @params_limit + 1)
223
228
 
224
- def []=(key, value)
225
- @params[key] = value
229
+ if pairs.size > @params_limit
230
+ param_count = pairs.size + pairs.last.count(separator || "&")
231
+ raise QueryLimitError, "total number of query parameters (#{param_count}) exceeds limit (#{@params_limit})"
226
232
  end
227
233
 
228
- def key?(key)
229
- @params.key?(key)
230
- end
231
-
232
- # Recursively unwraps nested `Params` objects and constructs an object
233
- # of the same shape, but using the objects' internal representations
234
- # (Ruby hashes) in place of the objects. The result is a hash consisting
235
- # purely of Ruby primitives.
236
- #
237
- # Mutation warning!
238
- #
239
- # 1. This method mutates the internal representation of the `Params`
240
- # objects in order to save object allocations.
241
- #
242
- # 2. The value you get back is a reference to the internal hash
243
- # representation, not a copy.
244
- #
245
- # 3. Because the `Params` object's internal representation is mutable
246
- # through the `#[]=` method, it is not thread safe. The result of
247
- # getting the hash representation while another thread is adding a
248
- # key to it is non-deterministic.
249
- #
250
- def to_h
251
- @params.each do |key, value|
252
- case value
253
- when self
254
- # Handle circular references gracefully.
255
- @params[key] = @params
256
- when Params
257
- @params[key] = value.to_h
258
- when Array
259
- value.map! { |v| v.kind_of?(Params) ? v.to_h : v }
260
- else
261
- # Ignore anything that is not a `Params` object or
262
- # a collection that can contain one.
263
- end
234
+ if unescaper
235
+ pairs.each do |p|
236
+ next if p.empty?
237
+ k, v = p.split('=', 2).map!(&unescaper)
238
+ yield k, v
239
+ end
240
+ else
241
+ pairs.each do |p|
242
+ next if p.empty?
243
+ k, v = p.split('=', 2).map! { |s| unescape(s) }
244
+ yield k, v
264
245
  end
265
- @params
266
246
  end
247
+ rescue ArgumentError => e
248
+ raise InvalidParameterError, e.message, e.backtrace
249
+ end
250
+
251
+ def unescape(string, encoding = Encoding::UTF_8)
252
+ URI.decode_www_form_component(string, encoding)
253
+ end
254
+
255
+ class Params < Hash
267
256
  alias_method :to_params_hash, :to_h
268
257
  end
269
258
  end
data/lib/rack/request.rb CHANGED
@@ -61,9 +61,14 @@ module Rack
61
61
 
62
62
  def initialize(env)
63
63
  @env = env
64
+ @ip = nil
64
65
  @params = nil
65
66
  end
66
67
 
68
+ def ip
69
+ @ip ||= super
70
+ end
71
+
67
72
  def params
68
73
  @params ||= super
69
74
  end
@@ -398,8 +403,8 @@ module Rack
398
403
  return forwarded.last
399
404
  end
400
405
  when :x_forwarded
401
- if value = get_header(HTTP_X_FORWARDED_HOST)
402
- return wrap_ipv6(split_header(value).last)
406
+ if (value = get_header(HTTP_X_FORWARDED_HOST)) && (x_forwarded_host = split_header(value).last)
407
+ return wrap_ipv6(x_forwarded_host)
403
408
  end
404
409
  end
405
410
  end
@@ -413,10 +418,9 @@ module Rack
413
418
 
414
419
  def ip
415
420
  remote_addresses = split_header(get_header('REMOTE_ADDR'))
416
- external_addresses = reject_trusted_ip_addresses(remote_addresses)
417
421
 
418
- unless external_addresses.empty?
419
- return external_addresses.last
422
+ remote_addresses.reverse_each do |ip|
423
+ return ip unless trusted_proxy?(ip)
420
424
  end
421
425
 
422
426
  if (forwarded_for = self.forwarded_for) && !forwarded_for.empty?
@@ -424,7 +428,10 @@ module Rack
424
428
  # So we reject all the trusted addresses (proxy*) and return the
425
429
  # last client. Or if we trust everyone, we just return the first
426
430
  # address.
427
- return reject_trusted_ip_addresses(forwarded_for).last || forwarded_for.first
431
+ forwarded_for.reverse_each do |ip|
432
+ return ip unless trusted_proxy?(ip)
433
+ end
434
+ return forwarded_for.first
428
435
  end
429
436
 
430
437
  # If all the addresses are trusted, and we aren't forwarded, just return
@@ -482,84 +489,64 @@ module Rack
482
489
 
483
490
  # Returns the data received in the query string.
484
491
  def GET
485
- if get_header(RACK_REQUEST_QUERY_STRING) == query_string
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)
497
- else
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)
502
- end
492
+ get_header(RACK_REQUEST_QUERY_HASH) || set_header(RACK_REQUEST_QUERY_HASH, parse_query(query_string, '&'))
503
493
  end
504
494
 
505
- # Returns the data received in the request body.
495
+ # Returns the form data pairs received in the request body.
506
496
  #
507
497
  # This method support both application/x-www-form-urlencoded and
508
498
  # multipart/form-data.
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
520
- if error = get_header(RACK_REQUEST_FORM_ERROR)
499
+ def form_pairs
500
+ if pairs = get_header(RACK_REQUEST_FORM_PAIRS)
501
+ return pairs
502
+ elsif error = get_header(RACK_REQUEST_FORM_ERROR)
521
503
  raise error.class, error.message, cause: error.cause
522
504
  end
523
505
 
524
506
  begin
525
507
  rack_input = get_header(RACK_INPUT)
526
508
 
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
-
509
+ # Otherwise, figure out how to parse the input:
537
510
  if rack_input.nil?
538
- form_pairs = []
511
+ set_header(RACK_REQUEST_FORM_PAIRS, [])
539
512
  elsif form_data? || parseable_data?
540
- unless form_pairs = Rack::Multipart.extract_multipart(self, Rack::Multipart::ParamList)
541
- form_vars = rack_input.read
513
+ if pairs = Rack::Multipart.parse_multipart(env, Rack::Multipart::ParamList)
514
+ set_header RACK_REQUEST_FORM_PAIRS, pairs
515
+ else
516
+ form_vars = get_header(RACK_INPUT).read
542
517
 
543
518
  # Fix for Safari Ajax postings that always append \0
544
519
  # form_vars.sub!(/\0\z/, '') # performance replacement:
545
520
  form_vars.slice!(-1) if form_vars.end_with?("\0")
546
521
 
547
522
  set_header RACK_REQUEST_FORM_VARS, form_vars
548
- form_pairs = split_query(form_vars, '&')
523
+ pairs = query_parser.parse_query_pairs(form_vars, '&')
524
+ set_header(RACK_REQUEST_FORM_PAIRS, pairs)
549
525
  end
550
526
  else
551
- form_pairs = []
527
+ set_header(RACK_REQUEST_FORM_PAIRS, [])
552
528
  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)
557
529
  rescue => error
558
530
  set_header(RACK_REQUEST_FORM_ERROR, error)
559
531
  raise
560
532
  end
561
533
  end
562
534
 
535
+ # Returns the data received in the request body.
536
+ #
537
+ # This method support both application/x-www-form-urlencoded and
538
+ # multipart/form-data.
539
+ def POST
540
+ if form_hash = get_header(RACK_REQUEST_FORM_HASH)
541
+ return form_hash
542
+ elsif error = get_header(RACK_REQUEST_FORM_ERROR)
543
+ raise error.class, error.message, cause: error.cause
544
+ end
545
+
546
+ pairs = form_pairs
547
+ set_header RACK_REQUEST_FORM_HASH, expand_param_pairs(pairs)
548
+ end
549
+
563
550
  # The union of GET and POST data.
564
551
  #
565
552
  # Note that modifications will not be persisted in the env. Use update_param or delete_param if you want to destructively modify params.
@@ -567,6 +554,10 @@ module Rack
567
554
  self.GET.merge(self.POST)
568
555
  end
569
556
 
557
+ # Allow overriding the query parser that the receiver will use.
558
+ # By default Rack::Utils.default_query_parser is used.
559
+ attr_writer :query_parser
560
+
570
561
  # Destructively update a parameter, whether it's in GET and/or POST. Returns nil.
571
562
  #
572
563
  # The parameter is updated wherever it was previous defined, so GET, POST, or both. If it wasn't previously defined, it's inserted into GET.
@@ -626,27 +617,6 @@ module Rack
626
617
  Rack::Request.ip_filter.call(ip)
627
618
  end
628
619
 
629
- # shortcut for <tt>request.params[key]</tt>
630
- def [](key)
631
- warn("Request#[] is deprecated and will be removed in a future version of Rack. Please use request.params[] instead", uplevel: 1)
632
-
633
- params[key.to_s]
634
- end
635
-
636
- # shortcut for <tt>request.params[key] = value</tt>
637
- #
638
- # Note that modifications will not be persisted in the env. Use update_param or delete_param if you want to destructively modify params.
639
- def []=(key, value)
640
- warn("Request#[]= is deprecated and will be removed in a future version of Rack. Please use request.params[]= instead", uplevel: 1)
641
-
642
- params[key.to_s] = value
643
- end
644
-
645
- # like Hash#values_at
646
- def values_at(*keys)
647
- keys.map { |key| params[key] }
648
- end
649
-
650
620
  private
651
621
 
652
622
  def default_session; {}; end
@@ -666,14 +636,26 @@ module Rack
666
636
  end
667
637
 
668
638
  def parse_http_accept_header(header)
669
- header.to_s.split(/\s*,\s*/).map do |part|
670
- attribute, parameters = part.split(/\s*;\s*/, 2)
639
+ # It would be nice to use filter_map here, but it's Ruby 2.7+
640
+ parts = header.to_s.split(',')
641
+
642
+ parts.map! do |part|
643
+ part.strip!
644
+ next if part.empty?
645
+
646
+ attribute, parameters = part.split(';', 2)
647
+ attribute.strip!
648
+ parameters&.strip!
671
649
  quality = 1.0
672
650
  if parameters and /\Aq=([\d.]+)/ =~ parameters
673
651
  quality = $1.to_f
674
652
  end
675
653
  [attribute, quality]
676
654
  end
655
+
656
+ parts.compact!
657
+
658
+ parts
677
659
  end
678
660
 
679
661
  # Get an array of values set in the RFC 7239 `Forwarded` request header.
@@ -682,7 +664,7 @@ module Rack
682
664
  end
683
665
 
684
666
  def query_parser
685
- Utils.default_query_parser
667
+ @query_parser || Utils.default_query_parser
686
668
  end
687
669
 
688
670
  def parse_query(qs, d = '&')
@@ -690,33 +672,22 @@ module Rack
690
672
  end
691
673
 
692
674
  def parse_multipart
675
+ warn "Rack::Request#parse_multipart is deprecated and will be removed in a future version of Rack.", uplevel: 1
693
676
  Rack::Multipart.extract_multipart(self, query_parser)
694
677
  end
695
678
 
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())
679
+ def expand_param_pairs(pairs, query_parser = query_parser())
709
680
  params = query_parser.make_params
710
681
 
711
- pairs.each do |key, value|
712
- query_parser.normalize_params(params, key, value)
682
+ pairs.each do |k, v|
683
+ query_parser.normalize_params(params, k, v)
713
684
  end
714
685
 
715
686
  params.to_params_hash
716
687
  end
717
688
 
718
689
  def split_header(value)
719
- value ? value.strip.split(/[,\s]+/) : []
690
+ value ? value.strip.split(/[, \t]+/) : []
720
691
  end
721
692
 
722
693
  # ipv6 extracted from resolv stdlib, simplified
@@ -764,10 +735,6 @@ module Rack
764
735
  return match[:host], match[:address], match[:port]&.to_i
765
736
  end
766
737
 
767
- def reject_trusted_ip_addresses(ip_addresses)
768
- ip_addresses.reject { |ip| trusted_proxy?(ip) }
769
- end
770
-
771
738
  FORWARDED_SCHEME_HEADERS = {
772
739
  proto: HTTP_X_FORWARDED_PROTO,
773
740
  scheme: HTTP_X_FORWARDED_SCHEME