rack 3.1.23 → 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 +57 -116
- data/README.md +41 -28
- data/SPEC.rdoc +199 -306
- data/lib/rack/auth/abstract/request.rb +2 -0
- data/lib/rack/builder.rb +6 -0
- data/lib/rack/conditional_get.rb +4 -3
- data/lib/rack/constants.rb +1 -0
- data/lib/rack/directory.rb +3 -6
- data/lib/rack/files.rb +1 -1
- data/lib/rack/head.rb +2 -3
- data/lib/rack/lint.rb +430 -457
- data/lib/rack/media_type.rb +6 -7
- data/lib/rack/mock_response.rb +19 -25
- data/lib/rack/multipart/parser.rb +38 -106
- data/lib/rack/multipart/uploaded_file.rb +42 -5
- data/lib/rack/query_parser.rb +41 -26
- data/lib/rack/request.rb +50 -65
- data/lib/rack/rewindable_input.rb +4 -1
- data/lib/rack/sendfile.rb +21 -51
- data/lib/rack/show_exceptions.rb +4 -2
- data/lib/rack/show_status.rb +0 -2
- data/lib/rack/static.rb +3 -7
- data/lib/rack/utils.rb +28 -129
- data/lib/rack/version.rb +4 -8
- data/lib/rack.rb +0 -1
- metadata +3 -3
- data/lib/rack/logger.rb +0 -23
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
|
|
@@ -320,10 +325,8 @@ module Rack
|
|
|
320
325
|
end
|
|
321
326
|
|
|
322
327
|
def host_with_port(authority = self.authority)
|
|
323
|
-
|
|
324
|
-
return nil if parts.empty?
|
|
328
|
+
host, _, port = split_authority(authority)
|
|
325
329
|
|
|
326
|
-
host, _, port = parts
|
|
327
330
|
if port == DEFAULT_PORTS[self.scheme]
|
|
328
331
|
host
|
|
329
332
|
else
|
|
@@ -400,8 +403,8 @@ module Rack
|
|
|
400
403
|
return forwarded.last
|
|
401
404
|
end
|
|
402
405
|
when :x_forwarded
|
|
403
|
-
if value = get_header(HTTP_X_FORWARDED_HOST)
|
|
404
|
-
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)
|
|
405
408
|
end
|
|
406
409
|
end
|
|
407
410
|
end
|
|
@@ -415,10 +418,9 @@ module Rack
|
|
|
415
418
|
|
|
416
419
|
def ip
|
|
417
420
|
remote_addresses = split_header(get_header('REMOTE_ADDR'))
|
|
418
|
-
external_addresses = reject_trusted_ip_addresses(remote_addresses)
|
|
419
421
|
|
|
420
|
-
|
|
421
|
-
return
|
|
422
|
+
remote_addresses.reverse_each do |ip|
|
|
423
|
+
return ip unless trusted_proxy?(ip)
|
|
422
424
|
end
|
|
423
425
|
|
|
424
426
|
if (forwarded_for = self.forwarded_for) && !forwarded_for.empty?
|
|
@@ -426,7 +428,10 @@ module Rack
|
|
|
426
428
|
# So we reject all the trusted addresses (proxy*) and return the
|
|
427
429
|
# last client. Or if we trust everyone, we just return the first
|
|
428
430
|
# address.
|
|
429
|
-
|
|
431
|
+
forwarded_for.reverse_each do |ip|
|
|
432
|
+
return ip unless trusted_proxy?(ip)
|
|
433
|
+
end
|
|
434
|
+
return forwarded_for.first
|
|
430
435
|
end
|
|
431
436
|
|
|
432
437
|
# If all the addresses are trusted, and we aren't forwarded, just return
|
|
@@ -484,70 +489,42 @@ module Rack
|
|
|
484
489
|
|
|
485
490
|
# Returns the data received in the query string.
|
|
486
491
|
def GET
|
|
487
|
-
|
|
488
|
-
query_string = self.query_string
|
|
489
|
-
if rr_query_string == query_string
|
|
490
|
-
get_header(RACK_REQUEST_QUERY_HASH)
|
|
491
|
-
else
|
|
492
|
-
if rr_query_string
|
|
493
|
-
warn "query string used for GET parsing different from current query string. Starting in Rack 3.2, Rack will used the cached GET value instead of parsing the current query string.", uplevel: 1
|
|
494
|
-
end
|
|
495
|
-
query_hash = parse_query(query_string, '&')
|
|
496
|
-
set_header(RACK_REQUEST_QUERY_STRING, query_string)
|
|
497
|
-
set_header(RACK_REQUEST_QUERY_HASH, query_hash)
|
|
498
|
-
end
|
|
492
|
+
get_header(RACK_REQUEST_QUERY_HASH) || set_header(RACK_REQUEST_QUERY_HASH, parse_query(query_string, '&'))
|
|
499
493
|
end
|
|
500
494
|
|
|
501
|
-
# Returns the data received in the request body.
|
|
495
|
+
# Returns the form data pairs received in the request body.
|
|
502
496
|
#
|
|
503
497
|
# This method support both application/x-www-form-urlencoded and
|
|
504
498
|
# multipart/form-data.
|
|
505
|
-
def
|
|
506
|
-
if
|
|
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)
|
|
507
503
|
raise error.class, error.message, cause: error.cause
|
|
508
504
|
end
|
|
509
505
|
|
|
510
506
|
begin
|
|
511
507
|
rack_input = get_header(RACK_INPUT)
|
|
512
508
|
|
|
513
|
-
# If the form hash was already memoized:
|
|
514
|
-
if form_hash = get_header(RACK_REQUEST_FORM_HASH)
|
|
515
|
-
form_input = get_header(RACK_REQUEST_FORM_INPUT)
|
|
516
|
-
# And it was memoized from the same input:
|
|
517
|
-
if form_input.equal?(rack_input)
|
|
518
|
-
return form_hash
|
|
519
|
-
elsif form_input
|
|
520
|
-
warn "input stream used for POST parsing different from current input stream. Starting in Rack 3.2, Rack will used the cached POST value instead of parsing the current input stream.", uplevel: 1
|
|
521
|
-
end
|
|
522
|
-
end
|
|
523
|
-
|
|
524
509
|
# Otherwise, figure out how to parse the input:
|
|
525
510
|
if rack_input.nil?
|
|
526
|
-
set_header
|
|
527
|
-
set_header(RACK_REQUEST_FORM_HASH, {})
|
|
511
|
+
set_header(RACK_REQUEST_FORM_PAIRS, [])
|
|
528
512
|
elsif form_data? || parseable_data?
|
|
529
513
|
if pairs = Rack::Multipart.parse_multipart(env, Rack::Multipart::ParamList)
|
|
530
514
|
set_header RACK_REQUEST_FORM_PAIRS, pairs
|
|
531
|
-
set_header RACK_REQUEST_FORM_HASH, expand_param_pairs(pairs)
|
|
532
515
|
else
|
|
533
|
-
|
|
534
|
-
# in case the slice! call below removes the last byte
|
|
535
|
-
# If read returns nil, use the empty string
|
|
536
|
-
form_vars = get_header(RACK_INPUT).read(query_parser.bytesize_limit + 2) || ''
|
|
516
|
+
form_vars = get_header(RACK_INPUT).read
|
|
537
517
|
|
|
538
518
|
# Fix for Safari Ajax postings that always append \0
|
|
539
519
|
# form_vars.sub!(/\0\z/, '') # performance replacement:
|
|
540
520
|
form_vars.slice!(-1) if form_vars.end_with?("\0")
|
|
541
521
|
|
|
542
522
|
set_header RACK_REQUEST_FORM_VARS, form_vars
|
|
543
|
-
|
|
523
|
+
pairs = query_parser.parse_query_pairs(form_vars, '&')
|
|
524
|
+
set_header(RACK_REQUEST_FORM_PAIRS, pairs)
|
|
544
525
|
end
|
|
545
|
-
|
|
546
|
-
set_header RACK_REQUEST_FORM_INPUT, get_header(RACK_INPUT)
|
|
547
|
-
get_header RACK_REQUEST_FORM_HASH
|
|
548
526
|
else
|
|
549
|
-
set_header
|
|
550
|
-
set_header(RACK_REQUEST_FORM_HASH, {})
|
|
527
|
+
set_header(RACK_REQUEST_FORM_PAIRS, [])
|
|
551
528
|
end
|
|
552
529
|
rescue => error
|
|
553
530
|
set_header(RACK_REQUEST_FORM_ERROR, error)
|
|
@@ -555,6 +532,21 @@ module Rack
|
|
|
555
532
|
end
|
|
556
533
|
end
|
|
557
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
|
+
|
|
558
550
|
# The union of GET and POST data.
|
|
559
551
|
#
|
|
560
552
|
# Note that modifications will not be persisted in the env. Use update_param or delete_param if you want to destructively modify params.
|
|
@@ -562,6 +554,10 @@ module Rack
|
|
|
562
554
|
self.GET.merge(self.POST)
|
|
563
555
|
end
|
|
564
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
|
+
|
|
565
561
|
# Destructively update a parameter, whether it's in GET and/or POST. Returns nil.
|
|
566
562
|
#
|
|
567
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.
|
|
@@ -593,8 +589,7 @@ module Rack
|
|
|
593
589
|
end
|
|
594
590
|
|
|
595
591
|
def base_url
|
|
596
|
-
|
|
597
|
-
"#{scheme}://#{hostport}"
|
|
592
|
+
"#{scheme}://#{host_with_port}"
|
|
598
593
|
end
|
|
599
594
|
|
|
600
595
|
# Tries to return a remake of the original request URL as a string.
|
|
@@ -622,13 +617,6 @@ module Rack
|
|
|
622
617
|
Rack::Request.ip_filter.call(ip)
|
|
623
618
|
end
|
|
624
619
|
|
|
625
|
-
# like Hash#values_at
|
|
626
|
-
def values_at(*keys)
|
|
627
|
-
warn("Request#values_at is deprecated and will be removed in a future version of Rack. Please use request.params.values_at instead", uplevel: 1)
|
|
628
|
-
|
|
629
|
-
keys.map { |key| params[key] }
|
|
630
|
-
end
|
|
631
|
-
|
|
632
620
|
private
|
|
633
621
|
|
|
634
622
|
def default_session; {}; end
|
|
@@ -676,7 +664,7 @@ module Rack
|
|
|
676
664
|
end
|
|
677
665
|
|
|
678
666
|
def query_parser
|
|
679
|
-
Utils.default_query_parser
|
|
667
|
+
@query_parser || Utils.default_query_parser
|
|
680
668
|
end
|
|
681
669
|
|
|
682
670
|
def parse_query(qs, d = '&')
|
|
@@ -684,6 +672,7 @@ module Rack
|
|
|
684
672
|
end
|
|
685
673
|
|
|
686
674
|
def parse_multipart
|
|
675
|
+
warn "Rack::Request#parse_multipart is deprecated and will be removed in a future version of Rack.", uplevel: 1
|
|
687
676
|
Rack::Multipart.extract_multipart(self, query_parser)
|
|
688
677
|
end
|
|
689
678
|
|
|
@@ -698,7 +687,7 @@ module Rack
|
|
|
698
687
|
end
|
|
699
688
|
|
|
700
689
|
def split_header(value)
|
|
701
|
-
value ? value.strip.split(/[
|
|
690
|
+
value ? value.strip.split(/[, \t]+/) : []
|
|
702
691
|
end
|
|
703
692
|
|
|
704
693
|
# ipv6 extracted from resolv stdlib, simplified
|
|
@@ -731,8 +720,8 @@ module Rack
|
|
|
731
720
|
# Match IPv6 as a string of hex digits and colons in square brackets
|
|
732
721
|
\[(?<address>#{ipv6})\]
|
|
733
722
|
|
|
|
734
|
-
# Match
|
|
735
|
-
(?<address>[
|
|
723
|
+
# Match any other printable string (except square brackets) as a hostname
|
|
724
|
+
(?<address>[[[:graph:]&&[^\[\]]]]*?)
|
|
736
725
|
)
|
|
737
726
|
(:(?<port>\d+))?
|
|
738
727
|
\z
|
|
@@ -746,10 +735,6 @@ module Rack
|
|
|
746
735
|
return match[:host], match[:address], match[:port]&.to_i
|
|
747
736
|
end
|
|
748
737
|
|
|
749
|
-
def reject_trusted_ip_addresses(ip_addresses)
|
|
750
|
-
ip_addresses.reject { |ip| trusted_proxy?(ip) }
|
|
751
|
-
end
|
|
752
|
-
|
|
753
738
|
FORWARDED_SCHEME_HEADERS = {
|
|
754
739
|
proto: HTTP_X_FORWARDED_PROTO,
|
|
755
740
|
scheme: HTTP_X_FORWARDED_SCHEME
|
data/lib/rack/sendfile.rb
CHANGED
|
@@ -16,21 +16,21 @@ module Rack
|
|
|
16
16
|
# delivery code.
|
|
17
17
|
#
|
|
18
18
|
# In order to take advantage of this middleware, the response body must
|
|
19
|
-
# respond to +to_path+ and the request must include an
|
|
19
|
+
# respond to +to_path+ and the request must include an x-sendfile-type
|
|
20
20
|
# header. Rack::Files and other components implement +to_path+ so there's
|
|
21
|
-
# rarely anything you need to do in your application. The
|
|
21
|
+
# rarely anything you need to do in your application. The x-sendfile-type
|
|
22
22
|
# header is typically set in your web servers configuration. The following
|
|
23
23
|
# sections attempt to document
|
|
24
24
|
#
|
|
25
25
|
# === Nginx
|
|
26
26
|
#
|
|
27
|
-
# Nginx supports the
|
|
27
|
+
# Nginx supports the x-accel-redirect header. This is similar to x-sendfile
|
|
28
28
|
# but requires parts of the filesystem to be mapped into a private URL
|
|
29
29
|
# hierarchy.
|
|
30
30
|
#
|
|
31
31
|
# The following example shows the Nginx configuration required to create
|
|
32
|
-
# a private "/files/" area, enable
|
|
33
|
-
#
|
|
32
|
+
# a private "/files/" area, enable x-accel-redirect, and pass the special
|
|
33
|
+
# x-sendfile-type and x-accel-mapping headers to the backend:
|
|
34
34
|
#
|
|
35
35
|
# location ~ /files/(.*) {
|
|
36
36
|
# internal;
|
|
@@ -44,29 +44,24 @@ module Rack
|
|
|
44
44
|
# proxy_set_header X-Real-IP $remote_addr;
|
|
45
45
|
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
46
46
|
#
|
|
47
|
+
# proxy_set_header x-sendfile-type x-accel-redirect;
|
|
47
48
|
# proxy_set_header x-accel-mapping /var/www/=/files/;
|
|
48
49
|
#
|
|
49
50
|
# proxy_pass http://127.0.0.1:8080/;
|
|
50
51
|
# }
|
|
51
52
|
#
|
|
52
|
-
#
|
|
53
|
+
# Note that the x-sendfile-type header must be set exactly as shown above.
|
|
54
|
+
# The x-accel-mapping header should specify the location on the file system,
|
|
53
55
|
# followed by an equals sign (=), followed name of the private URL pattern
|
|
54
|
-
# that it maps to. The middleware performs a
|
|
56
|
+
# that it maps to. The middleware performs a simple substitution on the
|
|
55
57
|
# resulting path.
|
|
56
58
|
#
|
|
57
|
-
# To enable `x-accel-redirect`, you must configure the middleware explicitly:
|
|
58
|
-
#
|
|
59
|
-
# use Rack::Sendfile, "x-accel-redirect"
|
|
60
|
-
#
|
|
61
|
-
# For security reasons, the `x-sendfile-type` header from requests is ignored.
|
|
62
|
-
# The sendfile variation must be set via the middleware constructor.
|
|
63
|
-
#
|
|
64
59
|
# See Also: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile
|
|
65
60
|
#
|
|
66
61
|
# === lighttpd
|
|
67
62
|
#
|
|
68
|
-
# Lighttpd has supported some variation of the
|
|
69
|
-
# time, although only recent version support
|
|
63
|
+
# Lighttpd has supported some variation of the x-sendfile header for some
|
|
64
|
+
# time, although only recent version support x-sendfile in a reverse proxy
|
|
70
65
|
# configuration.
|
|
71
66
|
#
|
|
72
67
|
# $HTTP["host"] == "example.com" {
|
|
@@ -88,7 +83,7 @@ module Rack
|
|
|
88
83
|
#
|
|
89
84
|
# === Apache
|
|
90
85
|
#
|
|
91
|
-
#
|
|
86
|
+
# x-sendfile is supported under Apache 2.x using a separate module:
|
|
92
87
|
#
|
|
93
88
|
# https://tn123.org/mod_xsendfile/
|
|
94
89
|
#
|
|
@@ -102,28 +97,16 @@ module Rack
|
|
|
102
97
|
# === Mapping parameter
|
|
103
98
|
#
|
|
104
99
|
# The third parameter allows for an overriding extension of the
|
|
105
|
-
#
|
|
100
|
+
# x-accel-mapping header. Mappings should be provided in tuples of internal to
|
|
106
101
|
# external. The internal values may contain regular expression syntax, they
|
|
107
102
|
# will be matched with case indifference.
|
|
108
|
-
#
|
|
109
|
-
# When `x-accel-redirect` is explicitly enabled via the variation parameter,
|
|
110
|
-
# and no application-level mappings are provided, the middleware will read
|
|
111
|
-
# the `x-accel-mapping` header from the proxy. This allows nginx to control
|
|
112
|
-
# the path mapping without requiring application-level configuration.
|
|
113
|
-
#
|
|
114
|
-
# === Security
|
|
115
|
-
#
|
|
116
|
-
# For security reasons, the `x-sendfile-type` header from HTTP requests is
|
|
117
|
-
# ignored. The sendfile variation must be explicitly configured via the
|
|
118
|
-
# middleware constructor to prevent information disclosure vulnerabilities
|
|
119
|
-
# where attackers could bypass proxy restrictions.
|
|
120
103
|
|
|
121
104
|
class Sendfile
|
|
122
105
|
def initialize(app, variation = nil, mappings = [])
|
|
123
106
|
@app = app
|
|
124
107
|
@variation = variation
|
|
125
108
|
@mappings = mappings.map do |internal, external|
|
|
126
|
-
[
|
|
109
|
+
[/^#{internal}/i, external]
|
|
127
110
|
end
|
|
128
111
|
end
|
|
129
112
|
|
|
@@ -162,35 +145,22 @@ module Rack
|
|
|
162
145
|
end
|
|
163
146
|
|
|
164
147
|
private
|
|
165
|
-
|
|
166
148
|
def variation(env)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def x_accel_mapping(env)
|
|
173
|
-
# Only allow header when:
|
|
174
|
-
# 1. `x-accel-redirect` is explicitly enabled via constructor.
|
|
175
|
-
# 2. No application-level mappings are configured.
|
|
176
|
-
return nil unless @variation =~ /x-accel-redirect/i
|
|
177
|
-
return nil if @mappings.any?
|
|
178
|
-
|
|
179
|
-
env['HTTP_X_ACCEL_MAPPING']
|
|
149
|
+
@variation ||
|
|
150
|
+
env['sendfile.type'] ||
|
|
151
|
+
env['HTTP_X_SENDFILE_TYPE']
|
|
180
152
|
end
|
|
181
153
|
|
|
182
154
|
def map_accel_path(env, path)
|
|
183
155
|
if mapping = @mappings.find { |internal, _| internal =~ path }
|
|
184
|
-
|
|
185
|
-
elsif mapping =
|
|
186
|
-
# Safe to use header: explicit config + no app mappings:
|
|
156
|
+
path.sub(*mapping)
|
|
157
|
+
elsif mapping = env['HTTP_X_ACCEL_MAPPING']
|
|
187
158
|
mapping.split(',').map(&:strip).each do |m|
|
|
188
159
|
internal, external = m.split('=', 2).map(&:strip)
|
|
189
|
-
new_path = path.sub(
|
|
160
|
+
new_path = path.sub(/^#{internal}/i, external)
|
|
190
161
|
return new_path unless path == new_path
|
|
191
162
|
end
|
|
192
|
-
|
|
193
|
-
return path
|
|
163
|
+
path
|
|
194
164
|
end
|
|
195
165
|
end
|
|
196
166
|
end
|
data/lib/rack/show_exceptions.rb
CHANGED
|
@@ -65,8 +65,12 @@ module Rack
|
|
|
65
65
|
def dump_exception(exception)
|
|
66
66
|
if exception.respond_to?(:detailed_message)
|
|
67
67
|
message = exception.detailed_message(highlight: false)
|
|
68
|
+
# :nocov:
|
|
69
|
+
# Ruby 3.2 added Exception#detailed_message, so the else
|
|
70
|
+
# branch cannot be hit on the current Ruby version.
|
|
68
71
|
else
|
|
69
72
|
message = exception.message
|
|
73
|
+
# :nocov:
|
|
70
74
|
end
|
|
71
75
|
string = "#{exception.class}: #{message}\n".dup
|
|
72
76
|
string << exception.backtrace.map { |l| "\t#{l}" }.join("\n")
|
|
@@ -401,7 +405,5 @@ module Rack
|
|
|
401
405
|
</body>
|
|
402
406
|
</html>
|
|
403
407
|
HTML
|
|
404
|
-
|
|
405
|
-
# :startdoc:
|
|
406
408
|
end
|
|
407
409
|
end
|
data/lib/rack/show_status.rb
CHANGED
data/lib/rack/static.rb
CHANGED
|
@@ -93,9 +93,6 @@ module Rack
|
|
|
93
93
|
def initialize(app, options = {})
|
|
94
94
|
@app = app
|
|
95
95
|
@urls = options[:urls] || ["/favicon.ico"]
|
|
96
|
-
if @urls.kind_of?(Array)
|
|
97
|
-
@urls = @urls.map { |url| [url, url.end_with?('/') ? url : "#{url}/".freeze].freeze }.freeze
|
|
98
|
-
end
|
|
99
96
|
@index = options[:index]
|
|
100
97
|
@gzip = options[:gzip]
|
|
101
98
|
@cascade = options[:cascade]
|
|
@@ -118,7 +115,7 @@ module Rack
|
|
|
118
115
|
end
|
|
119
116
|
|
|
120
117
|
def route_file(path)
|
|
121
|
-
@urls.kind_of?(Array) && @urls.any? { |url
|
|
118
|
+
@urls.kind_of?(Array) && @urls.any? { |url| path.index(url) == 0 }
|
|
122
119
|
end
|
|
123
120
|
|
|
124
121
|
def can_serve(path)
|
|
@@ -168,8 +165,6 @@ module Rack
|
|
|
168
165
|
|
|
169
166
|
# Convert HTTP header rules to HTTP headers
|
|
170
167
|
def applicable_rules(path)
|
|
171
|
-
path = ::Rack::Utils.clean_path_info(::Rack::Utils.unescape_path(path))
|
|
172
|
-
|
|
173
168
|
@header_rules.find_all do |rule, new_headers|
|
|
174
169
|
case rule
|
|
175
170
|
when :all
|
|
@@ -177,9 +172,10 @@ module Rack
|
|
|
177
172
|
when :fonts
|
|
178
173
|
/\.(?:ttf|otf|eot|woff2|woff|svg)\z/.match?(path)
|
|
179
174
|
when String
|
|
175
|
+
path = ::Rack::Utils.unescape(path)
|
|
180
176
|
path.start_with?(rule) || path.start_with?('/' + rule)
|
|
181
177
|
when Array
|
|
182
|
-
|
|
178
|
+
/\.(#{rule.join('|')})\z/.match?(path)
|
|
183
179
|
when Regexp
|
|
184
180
|
rule.match?(path)
|
|
185
181
|
else
|