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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +383 -1
- data/CONTRIBUTING.md +11 -9
- data/README.md +95 -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/body_proxy.rb +18 -2
- data/lib/rack/builder.rb +29 -10
- data/lib/rack/cascade.rb +0 -3
- data/lib/rack/common_logger.rb +3 -2
- data/lib/rack/conditional_get.rb +4 -3
- data/lib/rack/constants.rb +3 -1
- data/lib/rack/etag.rb +3 -0
- 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 +18 -9
- data/lib/rack/mime.rb +6 -5
- data/lib/rack/mock_request.rb +10 -15
- data/lib/rack/mock_response.rb +39 -18
- data/lib/rack/multipart/parser.rb +169 -73
- data/lib/rack/multipart/uploaded_file.rb +42 -5
- data/lib/rack/multipart.rb +9 -1
- data/lib/rack/query_parser.rb +86 -97
- data/lib/rack/request.rb +67 -100
- data/lib/rack/response.rb +29 -19
- data/lib/rack/rewindable_input.rb +4 -1
- data/lib/rack/sendfile.rb +2 -2
- data/lib/rack/show_exceptions.rb +10 -4
- data/lib/rack/show_status.rb +0 -2
- data/lib/rack/static.rb +2 -1
- data/lib/rack/utils.rb +78 -110
- data/lib/rack/version.rb +3 -20
- data/lib/rack.rb +11 -17
- metadata +6 -15
- 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/multipart.rb
CHANGED
|
@@ -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
|
data/lib/rack/query_parser.rb
CHANGED
|
@@ -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 =
|
|
6
|
-
COMMON_SEP = { ";" =>
|
|
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
|
|
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
|
|
20
|
+
class InvalidParameterError < ArgumentError
|
|
21
|
+
include BadRequest
|
|
22
|
+
end
|
|
16
23
|
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
class
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
37
|
-
@param_depth_limit = param_depth_limit
|
|
51
|
+
val
|
|
38
52
|
end
|
|
39
53
|
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
51
|
-
|
|
57
|
+
PARAMS_LIMIT = env_int.call("RACK_QUERY_PARSER_PARAMS_LIMIT", 4096)
|
|
58
|
+
private_constant :PARAMS_LIMIT
|
|
52
59
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
211
|
-
|
|
212
|
-
end
|
|
220
|
+
def each_query_pair(qs, separator, unescaper = nil)
|
|
221
|
+
return if !qs || qs.empty?
|
|
213
222
|
|
|
214
|
-
|
|
215
|
-
|
|
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
|
-
|
|
221
|
-
@params[key]
|
|
222
|
-
end
|
|
227
|
+
pairs = qs.split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP, @params_limit + 1)
|
|
223
228
|
|
|
224
|
-
|
|
225
|
-
|
|
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
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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(
|
|
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
|
-
|
|
419
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
510
|
-
if get_header(
|
|
511
|
-
|
|
512
|
-
|
|
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
|
-
|
|
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
|
-
|
|
511
|
+
set_header(RACK_REQUEST_FORM_PAIRS, [])
|
|
539
512
|
elsif form_data? || parseable_data?
|
|
540
|
-
|
|
541
|
-
|
|
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
|
-
|
|
523
|
+
pairs = query_parser.parse_query_pairs(form_vars, '&')
|
|
524
|
+
set_header(RACK_REQUEST_FORM_PAIRS, pairs)
|
|
549
525
|
end
|
|
550
526
|
else
|
|
551
|
-
|
|
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
|
-
|
|
670
|
-
|
|
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
|
|
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 |
|
|
712
|
-
query_parser.normalize_params(params,
|
|
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(/[
|
|
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
|