rack 2.2.8.1 → 3.0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +213 -83
- data/CONTRIBUTING.md +53 -47
- data/MIT-LICENSE +1 -1
- data/README.md +309 -0
- data/SPEC.rdoc +174 -126
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +3 -1
- data/lib/rack/auth/basic.rb +0 -2
- data/lib/rack/auth/digest/md5.rb +1 -131
- data/lib/rack/auth/digest/nonce.rb +1 -54
- data/lib/rack/auth/digest/params.rb +1 -54
- data/lib/rack/auth/digest/request.rb +1 -43
- data/lib/rack/auth/digest.rb +256 -0
- data/lib/rack/body_proxy.rb +3 -1
- data/lib/rack/builder.rb +83 -63
- data/lib/rack/cascade.rb +2 -0
- data/lib/rack/chunked.rb +16 -13
- data/lib/rack/common_logger.rb +23 -18
- data/lib/rack/conditional_get.rb +18 -15
- data/lib/rack/constants.rb +64 -0
- data/lib/rack/content_length.rb +12 -16
- data/lib/rack/content_type.rb +8 -5
- data/lib/rack/deflater.rb +40 -26
- data/lib/rack/directory.rb +9 -3
- data/lib/rack/etag.rb +14 -23
- data/lib/rack/events.rb +4 -0
- data/lib/rack/file.rb +2 -0
- data/lib/rack/files.rb +15 -17
- data/lib/rack/head.rb +9 -8
- data/lib/rack/headers.rb +154 -0
- data/lib/rack/lint.rb +758 -646
- data/lib/rack/lock.rb +2 -5
- data/lib/rack/logger.rb +2 -0
- data/lib/rack/method_override.rb +5 -1
- data/lib/rack/mime.rb +8 -0
- data/lib/rack/mock.rb +1 -271
- data/lib/rack/mock_request.rb +166 -0
- data/lib/rack/mock_response.rb +126 -0
- data/lib/rack/multipart/generator.rb +7 -5
- data/lib/rack/multipart/parser.rb +120 -64
- data/lib/rack/multipart/uploaded_file.rb +4 -0
- data/lib/rack/multipart.rb +20 -40
- data/lib/rack/null_logger.rb +9 -0
- data/lib/rack/query_parser.rb +78 -46
- data/lib/rack/recursive.rb +2 -0
- data/lib/rack/reloader.rb +0 -2
- data/lib/rack/request.rb +224 -106
- data/lib/rack/response.rb +138 -61
- data/lib/rack/rewindable_input.rb +24 -5
- data/lib/rack/runtime.rb +7 -6
- data/lib/rack/sendfile.rb +30 -25
- data/lib/rack/show_exceptions.rb +15 -2
- data/lib/rack/show_status.rb +17 -7
- data/lib/rack/static.rb +8 -8
- data/lib/rack/tempfile_reaper.rb +15 -4
- data/lib/rack/urlmap.rb +3 -1
- data/lib/rack/utils.rb +203 -176
- data/lib/rack/version.rb +9 -4
- data/lib/rack.rb +6 -76
- metadata +13 -33
- data/README.rdoc +0 -320
- data/Rakefile +0 -130
- data/bin/rackup +0 -5
- data/contrib/rack.png +0 -0
- data/contrib/rack.svg +0 -150
- data/contrib/rack_logo.svg +0 -164
- data/contrib/rdoc.css +0 -412
- data/example/lobster.ru +0 -6
- data/example/protectedlobster.rb +0 -16
- data/example/protectedlobster.ru +0 -10
- data/lib/rack/core_ext/regexp.rb +0 -14
- data/lib/rack/handler/cgi.rb +0 -59
- data/lib/rack/handler/fastcgi.rb +0 -100
- data/lib/rack/handler/lsws.rb +0 -61
- data/lib/rack/handler/scgi.rb +0 -71
- data/lib/rack/handler/thin.rb +0 -36
- data/lib/rack/handler/webrick.rb +0 -129
- data/lib/rack/handler.rb +0 -104
- data/lib/rack/lobster.rb +0 -70
- data/lib/rack/server.rb +0 -466
- data/lib/rack/session/abstract/id.rb +0 -523
- data/lib/rack/session/cookie.rb +0 -204
- data/lib/rack/session/memcache.rb +0 -10
- data/lib/rack/session/pool.rb +0 -85
- data/rack.gemspec +0 -46
data/lib/rack/request.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'constants'
|
4
|
+
require_relative 'utils'
|
5
|
+
require_relative 'media_type'
|
6
|
+
|
3
7
|
module Rack
|
4
8
|
# Rack::Request provides a convenient interface to a Rack
|
5
9
|
# environment. It is stateless, the environment +env+ passed to the
|
@@ -10,22 +14,54 @@ module Rack
|
|
10
14
|
# req.params["data"]
|
11
15
|
|
12
16
|
class Request
|
13
|
-
(require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4'
|
14
|
-
|
15
17
|
class << self
|
16
18
|
attr_accessor :ip_filter
|
17
|
-
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
# The priority when checking forwarded headers. The default
|
21
|
+
# is <tt>[:forwarded, :x_forwarded]</tt>, which means, check the
|
22
|
+
# +Forwarded+ header first, followed by the appropriate
|
23
|
+
# <tt>X-Forwarded-*</tt> header. You can revert the priority by
|
24
|
+
# reversing the priority, or remove checking of either
|
25
|
+
# or both headers by removing elements from the array.
|
26
|
+
#
|
27
|
+
# This should be set as appropriate in your environment
|
28
|
+
# based on what reverse proxies are in use. If you are not
|
29
|
+
# using reverse proxies, you should probably use an empty
|
30
|
+
# array.
|
31
|
+
attr_accessor :forwarded_priority
|
32
|
+
|
33
|
+
# The priority when checking either the <tt>X-Forwarded-Proto</tt>
|
34
|
+
# or <tt>X-Forwarded-Scheme</tt> header for the forwarded protocol.
|
35
|
+
# The default is <tt>[:proto, :scheme]</tt>, to try the
|
36
|
+
# <tt>X-Forwarded-Proto</tt> header before the
|
37
|
+
# <tt>X-Forwarded-Scheme</tt> header. Rack 2 had behavior
|
38
|
+
# similar to <tt>[:scheme, :proto]</tt>. You can remove either or
|
39
|
+
# both of the entries in array to ignore that respective header.
|
40
|
+
attr_accessor :x_forwarded_proto_priority
|
24
41
|
end
|
25
42
|
|
43
|
+
@forwarded_priority = [:forwarded, :x_forwarded]
|
44
|
+
@x_forwarded_proto_priority = [:proto, :scheme]
|
45
|
+
|
46
|
+
valid_ipv4_octet = /\.(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])/
|
47
|
+
|
48
|
+
trusted_proxies = Regexp.union(
|
49
|
+
/\A127#{valid_ipv4_octet}{3}\z/, # localhost IPv4 range 127.x.x.x, per RFC-3330
|
50
|
+
/\A::1\z/, # localhost IPv6 ::1
|
51
|
+
/\Af[cd][0-9a-f]{2}(?::[0-9a-f]{0,4}){0,7}\z/i, # private IPv6 range fc00 .. fdff
|
52
|
+
/\A10#{valid_ipv4_octet}{3}\z/, # private IPv4 range 10.x.x.x
|
53
|
+
/\A172\.(1[6-9]|2[0-9]|3[01])#{valid_ipv4_octet}{2}\z/, # private IPv4 range 172.16.0.0 .. 172.31.255.255
|
54
|
+
/\A192\.168#{valid_ipv4_octet}{2}\z/, # private IPv4 range 192.168.x.x
|
55
|
+
/\Alocalhost\z|\Aunix(\z|:)/i, # localhost hostname, and unix domain sockets
|
56
|
+
)
|
57
|
+
|
58
|
+
self.ip_filter = lambda { |ip| trusted_proxies.match?(ip) }
|
59
|
+
|
60
|
+
ALLOWED_SCHEMES = %w(https http wss ws).freeze
|
61
|
+
|
26
62
|
def initialize(env)
|
63
|
+
@env = env
|
27
64
|
@params = nil
|
28
|
-
super(env)
|
29
65
|
end
|
30
66
|
|
31
67
|
def params
|
@@ -49,6 +85,8 @@ module Rack
|
|
49
85
|
|
50
86
|
def initialize(env)
|
51
87
|
@env = env
|
88
|
+
# This module is included at least in `ActionDispatch::Request`
|
89
|
+
# The call to `super()` allows additional mixed-in initializers are called
|
52
90
|
super()
|
53
91
|
end
|
54
92
|
|
@@ -135,6 +173,8 @@ module Rack
|
|
135
173
|
# The contents of the host/:authority header sent to the proxy.
|
136
174
|
HTTP_X_FORWARDED_HOST = 'HTTP_X_FORWARDED_HOST'
|
137
175
|
|
176
|
+
HTTP_FORWARDED = 'HTTP_FORWARDED'
|
177
|
+
|
138
178
|
# The value of the scheme sent to the proxy.
|
139
179
|
HTTP_X_FORWARDED_SCHEME = 'HTTP_X_FORWARDED_SCHEME'
|
140
180
|
|
@@ -144,7 +184,7 @@ module Rack
|
|
144
184
|
# The port used to connect to the proxy.
|
145
185
|
HTTP_X_FORWARDED_PORT = 'HTTP_X_FORWARDED_PORT'
|
146
186
|
|
147
|
-
# Another way for
|
187
|
+
# Another way for specifying https scheme was used.
|
148
188
|
HTTP_X_FORWARDED_SSL = 'HTTP_X_FORWARDED_SSL'
|
149
189
|
|
150
190
|
def body; get_header(RACK_INPUT) end
|
@@ -159,7 +199,6 @@ module Rack
|
|
159
199
|
def content_length; get_header('CONTENT_LENGTH') end
|
160
200
|
def logger; get_header(RACK_LOGGER) end
|
161
201
|
def user_agent; get_header('HTTP_USER_AGENT') end
|
162
|
-
def multithread?; get_header(RACK_MULTITHREAD) end
|
163
202
|
|
164
203
|
# the referer of the client
|
165
204
|
def referer; get_header('HTTP_REFERER') end
|
@@ -248,9 +287,7 @@ module Rack
|
|
248
287
|
end
|
249
288
|
|
250
289
|
def server_port
|
251
|
-
|
252
|
-
Integer(port)
|
253
|
-
end
|
290
|
+
get_header(SERVER_PORT)
|
254
291
|
end
|
255
292
|
|
256
293
|
def cookies
|
@@ -307,44 +344,67 @@ module Rack
|
|
307
344
|
|
308
345
|
def port
|
309
346
|
if authority = self.authority
|
310
|
-
_, _, port = split_authority(
|
311
|
-
|
312
|
-
if port
|
313
|
-
return port
|
314
|
-
end
|
347
|
+
_, _, port = split_authority(authority)
|
315
348
|
end
|
316
349
|
|
317
|
-
|
318
|
-
return forwarded_port.first
|
319
|
-
end
|
320
|
-
|
321
|
-
if scheme = self.scheme
|
322
|
-
if port = DEFAULT_PORTS[self.scheme]
|
323
|
-
return port
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
self.server_port
|
350
|
+
port || forwarded_port&.last || DEFAULT_PORTS[scheme] || server_port
|
328
351
|
end
|
329
352
|
|
330
353
|
def forwarded_for
|
331
|
-
|
332
|
-
|
333
|
-
|
354
|
+
forwarded_priority.each do |type|
|
355
|
+
case type
|
356
|
+
when :forwarded
|
357
|
+
if forwarded_for = get_http_forwarded(:for)
|
358
|
+
return(forwarded_for.map! do |authority|
|
359
|
+
split_authority(authority)[1]
|
360
|
+
end)
|
361
|
+
end
|
362
|
+
when :x_forwarded
|
363
|
+
if value = get_header(HTTP_X_FORWARDED_FOR)
|
364
|
+
return(split_header(value).map do |authority|
|
365
|
+
split_authority(wrap_ipv6(authority))[1]
|
366
|
+
end)
|
367
|
+
end
|
334
368
|
end
|
335
369
|
end
|
370
|
+
|
371
|
+
nil
|
336
372
|
end
|
337
373
|
|
338
374
|
def forwarded_port
|
339
|
-
|
340
|
-
|
375
|
+
forwarded_priority.each do |type|
|
376
|
+
case type
|
377
|
+
when :forwarded
|
378
|
+
if forwarded = get_http_forwarded(:for)
|
379
|
+
return(forwarded.map do |authority|
|
380
|
+
split_authority(authority)[2]
|
381
|
+
end.compact)
|
382
|
+
end
|
383
|
+
when :x_forwarded
|
384
|
+
if value = get_header(HTTP_X_FORWARDED_PORT)
|
385
|
+
return split_header(value).map(&:to_i)
|
386
|
+
end
|
387
|
+
end
|
341
388
|
end
|
389
|
+
|
390
|
+
nil
|
342
391
|
end
|
343
392
|
|
344
393
|
def forwarded_authority
|
345
|
-
|
346
|
-
|
394
|
+
forwarded_priority.each do |type|
|
395
|
+
case type
|
396
|
+
when :forwarded
|
397
|
+
if forwarded = get_http_forwarded(:host)
|
398
|
+
return forwarded.last
|
399
|
+
end
|
400
|
+
when :x_forwarded
|
401
|
+
if value = get_header(HTTP_X_FORWARDED_HOST)
|
402
|
+
return wrap_ipv6(split_header(value).last)
|
403
|
+
end
|
404
|
+
end
|
347
405
|
end
|
406
|
+
|
407
|
+
nil
|
348
408
|
end
|
349
409
|
|
350
410
|
def ssl?
|
@@ -356,17 +416,15 @@ module Rack
|
|
356
416
|
external_addresses = reject_trusted_ip_addresses(remote_addresses)
|
357
417
|
|
358
418
|
unless external_addresses.empty?
|
359
|
-
return external_addresses.
|
419
|
+
return external_addresses.last
|
360
420
|
end
|
361
421
|
|
362
|
-
if forwarded_for = self.forwarded_for
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
return reject_trusted_ip_addresses(forwarded_for).last || forwarded_for.first
|
369
|
-
end
|
422
|
+
if (forwarded_for = self.forwarded_for) && !forwarded_for.empty?
|
423
|
+
# The forwarded for addresses are ordered: client, proxy1, proxy2.
|
424
|
+
# So we reject all the trusted addresses (proxy*) and return the
|
425
|
+
# last client. Or if we trust everyone, we just return the first
|
426
|
+
# address.
|
427
|
+
return reject_trusted_ip_addresses(forwarded_for).last || forwarded_for.first
|
370
428
|
end
|
371
429
|
|
372
430
|
# If all the addresses are trusted, and we aren't forwarded, just return
|
@@ -402,13 +460,13 @@ module Rack
|
|
402
460
|
end
|
403
461
|
|
404
462
|
# Determine whether the request body contains form-data by checking
|
405
|
-
# the request
|
463
|
+
# the request content-type for one of the media-types:
|
406
464
|
# "application/x-www-form-urlencoded" or "multipart/form-data". The
|
407
465
|
# list of form-data media types can be modified through the
|
408
466
|
# +FORM_DATA_MEDIA_TYPES+ array.
|
409
467
|
#
|
410
468
|
# A request body is also assumed to contain form-data when no
|
411
|
-
#
|
469
|
+
# content-type header is provided and the request_method is POST.
|
412
470
|
def form_data?
|
413
471
|
type = media_type
|
414
472
|
meth = get_header(RACK_METHODOVERRIDE_ORIGINAL_METHOD) || get_header(REQUEST_METHOD)
|
@@ -427,7 +485,7 @@ module Rack
|
|
427
485
|
if get_header(RACK_REQUEST_QUERY_STRING) == query_string
|
428
486
|
get_header(RACK_REQUEST_QUERY_HASH)
|
429
487
|
else
|
430
|
-
query_hash = parse_query(query_string, '
|
488
|
+
query_hash = parse_query(query_string, '&')
|
431
489
|
set_header(RACK_REQUEST_QUERY_STRING, query_string)
|
432
490
|
set_header(RACK_REQUEST_QUERY_HASH, query_hash)
|
433
491
|
end
|
@@ -438,27 +496,46 @@ module Rack
|
|
438
496
|
# This method support both application/x-www-form-urlencoded and
|
439
497
|
# multipart/form-data.
|
440
498
|
def POST
|
441
|
-
if get_header(
|
442
|
-
raise
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
#
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
set_header RACK_REQUEST_FORM_HASH, parse_query(form_vars, '&')
|
455
|
-
|
456
|
-
get_header(RACK_INPUT).rewind
|
499
|
+
if error = get_header(RACK_REQUEST_FORM_ERROR)
|
500
|
+
raise error.class, error.message, cause: error.cause
|
501
|
+
end
|
502
|
+
|
503
|
+
begin
|
504
|
+
rack_input = get_header(RACK_INPUT)
|
505
|
+
|
506
|
+
# If the form hash was already memoized:
|
507
|
+
if form_hash = get_header(RACK_REQUEST_FORM_HASH)
|
508
|
+
# And it was memoized from the same input:
|
509
|
+
if get_header(RACK_REQUEST_FORM_INPUT).equal?(rack_input)
|
510
|
+
return form_hash
|
511
|
+
end
|
457
512
|
end
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
513
|
+
|
514
|
+
# Otherwise, figure out how to parse the input:
|
515
|
+
if rack_input.nil?
|
516
|
+
set_header RACK_REQUEST_FORM_INPUT, nil
|
517
|
+
set_header(RACK_REQUEST_FORM_HASH, {})
|
518
|
+
elsif form_data? || parseable_data?
|
519
|
+
unless set_header(RACK_REQUEST_FORM_HASH, parse_multipart)
|
520
|
+
form_vars = get_header(RACK_INPUT).read
|
521
|
+
|
522
|
+
# Fix for Safari Ajax postings that always append \0
|
523
|
+
# form_vars.sub!(/\0\z/, '') # performance replacement:
|
524
|
+
form_vars.slice!(-1) if form_vars.end_with?("\0")
|
525
|
+
|
526
|
+
set_header RACK_REQUEST_FORM_VARS, form_vars
|
527
|
+
set_header RACK_REQUEST_FORM_HASH, parse_query(form_vars, '&')
|
528
|
+
end
|
529
|
+
|
530
|
+
set_header RACK_REQUEST_FORM_INPUT, get_header(RACK_INPUT)
|
531
|
+
get_header RACK_REQUEST_FORM_HASH
|
532
|
+
else
|
533
|
+
set_header RACK_REQUEST_FORM_INPUT, get_header(RACK_INPUT)
|
534
|
+
set_header(RACK_REQUEST_FORM_HASH, {})
|
535
|
+
end
|
536
|
+
rescue => error
|
537
|
+
set_header(RACK_REQUEST_FORM_ERROR, error)
|
538
|
+
raise
|
462
539
|
end
|
463
540
|
end
|
464
541
|
|
@@ -530,9 +607,7 @@ module Rack
|
|
530
607
|
|
531
608
|
# shortcut for <tt>request.params[key]</tt>
|
532
609
|
def [](key)
|
533
|
-
|
534
|
-
warn("Request#[] is deprecated and will be removed in a future version of Rack. Please use request.params[] instead")
|
535
|
-
end
|
610
|
+
warn("Request#[] is deprecated and will be removed in a future version of Rack. Please use request.params[] instead", uplevel: 1)
|
536
611
|
|
537
612
|
params[key.to_s]
|
538
613
|
end
|
@@ -541,9 +616,7 @@ module Rack
|
|
541
616
|
#
|
542
617
|
# Note that modifications will not be persisted in the env. Use update_param or delete_param if you want to destructively modify params.
|
543
618
|
def []=(key, value)
|
544
|
-
|
545
|
-
warn("Request#[]= is deprecated and will be removed in a future version of Rack. Please use request.params[]= instead")
|
546
|
-
end
|
619
|
+
warn("Request#[]= is deprecated and will be removed in a future version of Rack. Please use request.params[]= instead", uplevel: 1)
|
547
620
|
|
548
621
|
params[key.to_s] = value
|
549
622
|
end
|
@@ -582,6 +655,11 @@ module Rack
|
|
582
655
|
end
|
583
656
|
end
|
584
657
|
|
658
|
+
# Get an array of values set in the RFC 7239 `Forwarded` request header.
|
659
|
+
def get_http_forwarded(token)
|
660
|
+
Utils.forwarded_values(get_header(HTTP_FORWARDED))&.[](token)
|
661
|
+
end
|
662
|
+
|
585
663
|
def query_parser
|
586
664
|
Utils.default_query_parser
|
587
665
|
end
|
@@ -598,58 +676,94 @@ module Rack
|
|
598
676
|
value ? value.strip.split(/[,\s]+/) : []
|
599
677
|
end
|
600
678
|
|
601
|
-
|
602
|
-
|
679
|
+
# ipv6 extracted from resolv stdlib, simplified
|
680
|
+
# to remove numbered match group creation.
|
681
|
+
ipv6 = Regexp.union(
|
682
|
+
/(?:[0-9A-Fa-f]{1,4}:){7}
|
683
|
+
[0-9A-Fa-f]{1,4}/x,
|
684
|
+
/(?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)? ::
|
685
|
+
(?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?/x,
|
686
|
+
/(?:[0-9A-Fa-f]{1,4}:){6,6}
|
687
|
+
\d+\.\d+\.\d+\.\d+/x,
|
688
|
+
/(?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)? ::
|
689
|
+
(?:[0-9A-Fa-f]{1,4}:)*
|
690
|
+
\d+\.\d+\.\d+\.\d+/x,
|
691
|
+
/[Ff][Ee]80
|
692
|
+
(?::[0-9A-Fa-f]{1,4}){7}
|
693
|
+
%[-0-9A-Za-z._~]+/x,
|
694
|
+
/[Ff][Ee]80:
|
695
|
+
(?:
|
696
|
+
(?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)? ::
|
697
|
+
(?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?
|
698
|
+
|
|
699
|
+
:(?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?
|
700
|
+
)?
|
701
|
+
:[0-9A-Fa-f]{1,4}%[-0-9A-Za-z._~]+/x)
|
702
|
+
|
703
|
+
AUTHORITY = /
|
704
|
+
\A
|
603
705
|
(?<host>
|
604
|
-
#
|
605
|
-
|
606
|
-
|
|
607
|
-
# An IPv4 address:
|
608
|
-
(?<ip4>[\d\.]+)
|
706
|
+
# Match IPv6 as a string of hex digits and colons in square brackets
|
707
|
+
\[(?<address>#{ipv6})\]
|
609
708
|
|
|
610
|
-
#
|
611
|
-
(?<
|
709
|
+
# Match any other printable string (except square brackets) as a hostname
|
710
|
+
(?<address>[[[:graph:]&&[^\[\]]]]*?)
|
612
711
|
)
|
613
|
-
# The optional port:
|
614
712
|
(:(?<port>\d+))?
|
615
|
-
|
713
|
+
\z
|
714
|
+
/x
|
616
715
|
|
617
716
|
private_constant :AUTHORITY
|
618
717
|
|
619
718
|
def split_authority(authority)
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
else
|
624
|
-
return match[:host], match[:host], match[:port]&.to_i
|
625
|
-
end
|
626
|
-
end
|
627
|
-
|
628
|
-
# Give up!
|
629
|
-
return authority, authority, nil
|
719
|
+
return [] if authority.nil?
|
720
|
+
return [] unless match = AUTHORITY.match(authority)
|
721
|
+
return match[:host], match[:address], match[:port]&.to_i
|
630
722
|
end
|
631
723
|
|
632
724
|
def reject_trusted_ip_addresses(ip_addresses)
|
633
725
|
ip_addresses.reject { |ip| trusted_proxy?(ip) }
|
634
726
|
end
|
635
727
|
|
728
|
+
FORWARDED_SCHEME_HEADERS = {
|
729
|
+
proto: HTTP_X_FORWARDED_PROTO,
|
730
|
+
scheme: HTTP_X_FORWARDED_SCHEME
|
731
|
+
}.freeze
|
732
|
+
private_constant :FORWARDED_SCHEME_HEADERS
|
636
733
|
def forwarded_scheme
|
637
|
-
|
638
|
-
|
734
|
+
forwarded_priority.each do |type|
|
735
|
+
case type
|
736
|
+
when :forwarded
|
737
|
+
if (forwarded_proto = get_http_forwarded(:proto)) &&
|
738
|
+
(scheme = allowed_scheme(forwarded_proto.last))
|
739
|
+
return scheme
|
740
|
+
end
|
741
|
+
when :x_forwarded
|
742
|
+
x_forwarded_proto_priority.each do |x_type|
|
743
|
+
if header = FORWARDED_SCHEME_HEADERS[x_type]
|
744
|
+
split_header(get_header(header)).reverse_each do |scheme|
|
745
|
+
if allowed_scheme(scheme)
|
746
|
+
return scheme
|
747
|
+
end
|
748
|
+
end
|
749
|
+
end
|
750
|
+
end
|
751
|
+
end
|
752
|
+
end
|
753
|
+
|
754
|
+
nil
|
639
755
|
end
|
640
756
|
|
641
757
|
def allowed_scheme(header)
|
642
758
|
header if ALLOWED_SCHEMES.include?(header)
|
643
759
|
end
|
644
760
|
|
645
|
-
def
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
end
|
652
|
-
end
|
761
|
+
def forwarded_priority
|
762
|
+
Request.forwarded_priority
|
763
|
+
end
|
764
|
+
|
765
|
+
def x_forwarded_proto_priority
|
766
|
+
Request.x_forwarded_proto_priority
|
653
767
|
end
|
654
768
|
end
|
655
769
|
|
@@ -657,3 +771,7 @@ module Rack
|
|
657
771
|
include Helpers
|
658
772
|
end
|
659
773
|
end
|
774
|
+
|
775
|
+
# :nocov:
|
776
|
+
require_relative 'multipart' unless defined?(Rack::Multipart)
|
777
|
+
# :nocov:
|