rack 2.1.4.3 → 2.2.0
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 +4 -4
- data/CHANGELOG.md +598 -15
- data/CONTRIBUTING.md +136 -0
- data/README.rdoc +84 -54
- data/Rakefile +14 -7
- data/{SPEC → SPEC.rdoc} +35 -6
- data/lib/rack/auth/abstract/request.rb +0 -2
- data/lib/rack/auth/basic.rb +3 -3
- data/lib/rack/auth/digest/md5.rb +4 -4
- data/lib/rack/auth/digest/request.rb +3 -3
- data/lib/rack/body_proxy.rb +13 -9
- data/lib/rack/builder.rb +77 -8
- data/lib/rack/cascade.rb +23 -8
- data/lib/rack/chunked.rb +48 -23
- data/lib/rack/common_logger.rb +25 -21
- data/lib/rack/conditional_get.rb +18 -16
- data/lib/rack/content_length.rb +6 -7
- data/lib/rack/content_type.rb +3 -4
- data/lib/rack/deflater.rb +45 -35
- data/lib/rack/directory.rb +77 -60
- data/lib/rack/etag.rb +2 -3
- data/lib/rack/events.rb +15 -18
- data/lib/rack/file.rb +1 -1
- data/lib/rack/files.rb +96 -56
- data/lib/rack/handler/cgi.rb +1 -4
- data/lib/rack/handler/fastcgi.rb +1 -3
- data/lib/rack/handler/lsws.rb +1 -3
- data/lib/rack/handler/scgi.rb +1 -3
- data/lib/rack/handler/thin.rb +15 -11
- data/lib/rack/handler/webrick.rb +12 -5
- data/lib/rack/head.rb +0 -2
- data/lib/rack/lint.rb +58 -15
- data/lib/rack/lobster.rb +3 -5
- data/lib/rack/lock.rb +0 -1
- data/lib/rack/mock.rb +22 -4
- data/lib/rack/multipart/generator.rb +11 -6
- data/lib/rack/multipart/parser.rb +12 -32
- data/lib/rack/multipart/uploaded_file.rb +13 -7
- data/lib/rack/multipart.rb +5 -4
- data/lib/rack/query_parser.rb +7 -8
- data/lib/rack/recursive.rb +1 -1
- data/lib/rack/reloader.rb +1 -3
- data/lib/rack/request.rb +172 -76
- data/lib/rack/response.rb +62 -19
- data/lib/rack/rewindable_input.rb +0 -1
- data/lib/rack/runtime.rb +3 -3
- data/lib/rack/sendfile.rb +0 -3
- data/lib/rack/server.rb +9 -8
- data/lib/rack/session/abstract/id.rb +20 -18
- data/lib/rack/session/cookie.rb +2 -3
- data/lib/rack/session/pool.rb +1 -1
- data/lib/rack/show_exceptions.rb +2 -4
- data/lib/rack/show_status.rb +1 -3
- data/lib/rack/static.rb +13 -6
- data/lib/rack/tempfile_reaper.rb +0 -2
- data/lib/rack/urlmap.rb +1 -4
- data/lib/rack/utils.rb +68 -80
- data/lib/rack/version.rb +29 -0
- data/lib/rack.rb +7 -16
- data/rack.gemspec +31 -29
- metadata +14 -15
data/lib/rack/response.rb
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'rack/request'
|
4
|
-
require 'rack/utils'
|
5
|
-
require 'rack/body_proxy'
|
6
|
-
require 'rack/media_type'
|
7
3
|
require 'time'
|
8
4
|
|
9
5
|
module Rack
|
@@ -19,34 +15,51 @@ module Rack
|
|
19
15
|
# +write+ are synchronous with the Rack response.
|
20
16
|
#
|
21
17
|
# Your application's +call+ should end returning Response#finish.
|
22
|
-
|
23
18
|
class Response
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
def self.[](status, headers, body)
|
20
|
+
self.new(body, status, headers)
|
21
|
+
end
|
27
22
|
|
28
23
|
CHUNKED = 'chunked'
|
29
24
|
STATUS_WITH_NO_ENTITY_BODY = Utils::STATUS_WITH_NO_ENTITY_BODY
|
30
25
|
|
31
|
-
|
26
|
+
attr_accessor :length, :status, :body
|
27
|
+
attr_reader :headers
|
28
|
+
|
29
|
+
# @deprecated Use {#headers} instead.
|
30
|
+
alias header headers
|
31
|
+
|
32
|
+
# Initialize the response object with the specified body, status
|
33
|
+
# and headers.
|
34
|
+
#
|
35
|
+
# @param body [nil, #each, #to_str] the response body.
|
36
|
+
# @param status [Integer] the integer status as defined by the
|
37
|
+
# HTTP protocol RFCs.
|
38
|
+
# @param headers [#each] a list of key-value header pairs which
|
39
|
+
# conform to the HTTP protocol RFCs.
|
40
|
+
#
|
41
|
+
# Providing a body which responds to #to_str is legacy behaviour.
|
42
|
+
def initialize(body = nil, status = 200, headers = {})
|
32
43
|
@status = status.to_i
|
33
|
-
@
|
44
|
+
@headers = Utils::HeaderHash[headers]
|
34
45
|
|
35
46
|
@writer = self.method(:append)
|
36
47
|
|
37
48
|
@block = nil
|
38
|
-
@length = 0
|
39
49
|
|
40
50
|
# Keep track of whether we have expanded the user supplied body.
|
41
51
|
if body.nil?
|
42
52
|
@body = []
|
43
53
|
@buffered = true
|
54
|
+
@length = 0
|
44
55
|
elsif body.respond_to?(:to_str)
|
45
56
|
@body = [body]
|
46
57
|
@buffered = true
|
58
|
+
@length = body.to_str.bytesize
|
47
59
|
else
|
48
60
|
@body = body
|
49
61
|
@buffered = false
|
62
|
+
@length = 0
|
50
63
|
end
|
51
64
|
|
52
65
|
yield self if block_given?
|
@@ -61,18 +74,21 @@ module Rack
|
|
61
74
|
CHUNKED == get_header(TRANSFER_ENCODING)
|
62
75
|
end
|
63
76
|
|
77
|
+
# Generate a response array consistent with the requirements of the SPEC.
|
78
|
+
# @return [Array] a 3-tuple suitable of `[status, headers, body]`
|
79
|
+
# which is suitable to be returned from the middleware `#call(env)` method.
|
64
80
|
def finish(&block)
|
65
81
|
if STATUS_WITH_NO_ENTITY_BODY[status.to_i]
|
66
82
|
delete_header CONTENT_TYPE
|
67
83
|
delete_header CONTENT_LENGTH
|
68
84
|
close
|
69
|
-
[status
|
85
|
+
return [@status, @headers, []]
|
70
86
|
else
|
71
87
|
if block_given?
|
72
88
|
@block = block
|
73
|
-
[status
|
89
|
+
return [@status, @headers, self]
|
74
90
|
else
|
75
|
-
[status
|
91
|
+
return [@status, @headers, @body]
|
76
92
|
end
|
77
93
|
end
|
78
94
|
end
|
@@ -152,7 +168,7 @@ module Rack
|
|
152
168
|
# assert_equal 'Accept-Encoding,Cookie', response.get_header('Vary')
|
153
169
|
#
|
154
170
|
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
|
155
|
-
def add_header
|
171
|
+
def add_header(key, v)
|
156
172
|
if v.nil?
|
157
173
|
get_header key
|
158
174
|
elsif has_header? key
|
@@ -162,10 +178,16 @@ module Rack
|
|
162
178
|
end
|
163
179
|
end
|
164
180
|
|
181
|
+
# Get the content type of the response.
|
165
182
|
def content_type
|
166
183
|
get_header CONTENT_TYPE
|
167
184
|
end
|
168
185
|
|
186
|
+
# Set the content type of the response.
|
187
|
+
def content_type=(content_type)
|
188
|
+
set_header CONTENT_TYPE, content_type
|
189
|
+
end
|
190
|
+
|
169
191
|
def media_type
|
170
192
|
MediaType.type(content_type)
|
171
193
|
end
|
@@ -200,7 +222,7 @@ module Rack
|
|
200
222
|
get_header SET_COOKIE
|
201
223
|
end
|
202
224
|
|
203
|
-
def set_cookie_header=
|
225
|
+
def set_cookie_header=(v)
|
204
226
|
set_header SET_COOKIE, v
|
205
227
|
end
|
206
228
|
|
@@ -208,15 +230,31 @@ module Rack
|
|
208
230
|
get_header CACHE_CONTROL
|
209
231
|
end
|
210
232
|
|
211
|
-
def cache_control=
|
233
|
+
def cache_control=(v)
|
212
234
|
set_header CACHE_CONTROL, v
|
213
235
|
end
|
214
236
|
|
237
|
+
# Specifies that the content shouldn't be cached. Overrides `cache!` if already called.
|
238
|
+
def do_not_cache!
|
239
|
+
set_header CACHE_CONTROL, "no-cache, must-revalidate"
|
240
|
+
set_header EXPIRES, Time.now.httpdate
|
241
|
+
end
|
242
|
+
|
243
|
+
# Specify that the content should be cached.
|
244
|
+
# @param duration [Integer] The number of seconds until the cache expires.
|
245
|
+
# @option directive [String] The cache control directive, one of "public", "private", "no-cache" or "no-store".
|
246
|
+
def cache!(duration = 3600, directive: "public")
|
247
|
+
unless headers[CACHE_CONTROL] =~ /no-cache/
|
248
|
+
set_header CACHE_CONTROL, "#{directive}, max-age=#{duration}"
|
249
|
+
set_header EXPIRES, (Time.now + duration).httpdate
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
215
253
|
def etag
|
216
254
|
get_header ETAG
|
217
255
|
end
|
218
256
|
|
219
|
-
def etag=
|
257
|
+
def etag=(v)
|
220
258
|
set_header ETAG, v
|
221
259
|
end
|
222
260
|
|
@@ -228,6 +266,9 @@ module Rack
|
|
228
266
|
if @body.is_a?(Array)
|
229
267
|
# The user supplied body was an array:
|
230
268
|
@body = @body.compact
|
269
|
+
@body.each do |part|
|
270
|
+
@length += part.to_s.bytesize
|
271
|
+
end
|
231
272
|
else
|
232
273
|
# Turn the user supplied body into a buffered array:
|
233
274
|
body = @body
|
@@ -236,6 +277,8 @@ module Rack
|
|
236
277
|
body.each do |part|
|
237
278
|
@writer.call(part.to_s)
|
238
279
|
end
|
280
|
+
|
281
|
+
body.close if body.respond_to?(:close)
|
239
282
|
end
|
240
283
|
|
241
284
|
@buffered = true
|
@@ -261,7 +304,7 @@ module Rack
|
|
261
304
|
attr_reader :headers
|
262
305
|
attr_accessor :status
|
263
306
|
|
264
|
-
def initialize
|
307
|
+
def initialize(status, headers)
|
265
308
|
@status = status
|
266
309
|
@headers = headers
|
267
310
|
end
|
data/lib/rack/runtime.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'rack/utils'
|
4
|
-
|
5
3
|
module Rack
|
6
4
|
# Sets an "X-Runtime" response header, indicating the response
|
7
5
|
# time of the request, in seconds
|
@@ -22,9 +20,11 @@ module Rack
|
|
22
20
|
def call(env)
|
23
21
|
start_time = Utils.clock_time
|
24
22
|
status, headers, body = @app.call(env)
|
23
|
+
headers = Utils::HeaderHash[headers]
|
24
|
+
|
25
25
|
request_time = Utils.clock_time - start_time
|
26
26
|
|
27
|
-
unless headers.
|
27
|
+
unless headers.key?(@header_name)
|
28
28
|
headers[@header_name] = FORMAT_STRING % request_time
|
29
29
|
end
|
30
30
|
|
data/lib/rack/sendfile.rb
CHANGED
data/lib/rack/server.rb
CHANGED
@@ -3,12 +3,10 @@
|
|
3
3
|
require 'optparse'
|
4
4
|
require 'fileutils'
|
5
5
|
|
6
|
-
require_relative 'core_ext/regexp'
|
7
|
-
|
8
6
|
module Rack
|
9
7
|
|
10
8
|
class Server
|
11
|
-
using ::Rack::RegexpExtensions
|
9
|
+
(require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4'
|
12
10
|
|
13
11
|
class Options
|
14
12
|
def parse!(args)
|
@@ -42,7 +40,7 @@ module Rack
|
|
42
40
|
|
43
41
|
opts.on("-r", "--require LIBRARY",
|
44
42
|
"require the library, before executing your script") { |library|
|
45
|
-
options[:require]
|
43
|
+
(options[:require] ||= []) << library
|
46
44
|
}
|
47
45
|
|
48
46
|
opts.separator ""
|
@@ -143,7 +141,7 @@ module Rack
|
|
143
141
|
return "" if !has_options
|
144
142
|
end
|
145
143
|
info.join("\n")
|
146
|
-
rescue NameError
|
144
|
+
rescue NameError, LoadError
|
147
145
|
return "Warning: Could not find handler specified (#{options[:server] || 'default'}) to determine handler-specific options"
|
148
146
|
end
|
149
147
|
end
|
@@ -285,7 +283,7 @@ module Rack
|
|
285
283
|
self.class.middleware
|
286
284
|
end
|
287
285
|
|
288
|
-
def start
|
286
|
+
def start(&block)
|
289
287
|
if options[:warn]
|
290
288
|
$-w = true
|
291
289
|
end
|
@@ -294,7 +292,7 @@ module Rack
|
|
294
292
|
$LOAD_PATH.unshift(*includes)
|
295
293
|
end
|
296
294
|
|
297
|
-
|
295
|
+
Array(options[:require]).each do |library|
|
298
296
|
require library
|
299
297
|
end
|
300
298
|
|
@@ -326,7 +324,7 @@ module Rack
|
|
326
324
|
end
|
327
325
|
end
|
328
326
|
|
329
|
-
server.run
|
327
|
+
server.run(wrapped_app, **options, &block)
|
330
328
|
end
|
331
329
|
|
332
330
|
def server
|
@@ -425,7 +423,10 @@ module Rack
|
|
425
423
|
end
|
426
424
|
|
427
425
|
def daemonize_app
|
426
|
+
# Cannot be covered as it forks
|
427
|
+
# :nocov:
|
428
428
|
Process.daemon
|
429
|
+
# :nocov:
|
429
430
|
end
|
430
431
|
|
431
432
|
def write_pid
|
@@ -3,10 +3,8 @@
|
|
3
3
|
# AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net
|
4
4
|
# bugrep: Andreas Zehnder
|
5
5
|
|
6
|
-
|
6
|
+
require_relative '../../../rack'
|
7
7
|
require 'time'
|
8
|
-
require 'rack/request'
|
9
|
-
require 'rack/response'
|
10
8
|
require 'securerandom'
|
11
9
|
require 'digest/sha2'
|
12
10
|
|
@@ -44,18 +42,6 @@ module Rack
|
|
44
42
|
# SessionHash is responsible to lazily load the session from store.
|
45
43
|
|
46
44
|
class SessionHash
|
47
|
-
using Module.new {
|
48
|
-
refine Hash do
|
49
|
-
def transform_keys(&block)
|
50
|
-
hash = {}
|
51
|
-
each do |key, value|
|
52
|
-
hash[block.call(key)] = value
|
53
|
-
end
|
54
|
-
hash
|
55
|
-
end
|
56
|
-
end
|
57
|
-
} unless {}.respond_to?(:transform_keys)
|
58
|
-
|
59
45
|
include Enumerable
|
60
46
|
attr_writer :id
|
61
47
|
|
@@ -98,6 +84,11 @@ module Rack
|
|
98
84
|
@data[key.to_s]
|
99
85
|
end
|
100
86
|
|
87
|
+
def dig(key, *keys)
|
88
|
+
load_for_read!
|
89
|
+
@data.dig(key.to_s, *keys)
|
90
|
+
end
|
91
|
+
|
101
92
|
def fetch(key, default = Unspecified, &block)
|
102
93
|
load_for_read!
|
103
94
|
if default == Unspecified
|
@@ -201,14 +192,19 @@ module Rack
|
|
201
192
|
end
|
202
193
|
|
203
194
|
def stringify_keys(other)
|
204
|
-
|
195
|
+
# Use transform_keys after dropping Ruby 2.4 support
|
196
|
+
hash = {}
|
197
|
+
other.to_hash.each do |key, value|
|
198
|
+
hash[key.to_s] = value
|
199
|
+
end
|
200
|
+
hash
|
205
201
|
end
|
206
202
|
end
|
207
203
|
|
208
204
|
# ID sets up a basic framework for implementing an id based sessioning
|
209
205
|
# service. Cookies sent to the client for maintaining sessions will only
|
210
|
-
# contain an id reference. Only #find_session
|
211
|
-
# required to be overwritten.
|
206
|
+
# contain an id reference. Only #find_session, #write_session and
|
207
|
+
# #delete_session are required to be overwritten.
|
212
208
|
#
|
213
209
|
# All parameters are optional.
|
214
210
|
# * :key determines the name of the cookie, by default it is
|
@@ -397,6 +393,12 @@ module Rack
|
|
397
393
|
cookie[:value] = cookie_value(data)
|
398
394
|
cookie[:expires] = Time.now + options[:expire_after] if options[:expire_after]
|
399
395
|
cookie[:expires] = Time.now + options[:max_age] if options[:max_age]
|
396
|
+
|
397
|
+
if @same_site.respond_to? :call
|
398
|
+
cookie[:same_site] = @same_site.call(req, res)
|
399
|
+
else
|
400
|
+
cookie[:same_site] = @same_site
|
401
|
+
end
|
400
402
|
set_cookie(req, res, cookie.merge!(options))
|
401
403
|
end
|
402
404
|
end
|
data/lib/rack/session/cookie.rb
CHANGED
@@ -2,9 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'openssl'
|
4
4
|
require 'zlib'
|
5
|
-
|
6
|
-
require 'rack/response'
|
7
|
-
require 'rack/session/abstract/id'
|
5
|
+
require_relative 'abstract/id'
|
8
6
|
require 'json'
|
9
7
|
require 'base64'
|
10
8
|
|
@@ -120,6 +118,7 @@ module Rack
|
|
120
118
|
Called from: #{caller[0]}.
|
121
119
|
MSG
|
122
120
|
@coder = options[:coder] ||= Base64::Marshal.new
|
121
|
+
@same_site = options.delete :same_site
|
123
122
|
super(app, options.merge!(cookie_only: true))
|
124
123
|
end
|
125
124
|
|
data/lib/rack/session/pool.rb
CHANGED
data/lib/rack/show_exceptions.rb
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'ostruct'
|
4
4
|
require 'erb'
|
5
|
-
require 'rack/request'
|
6
|
-
require 'rack/utils'
|
7
5
|
|
8
6
|
module Rack
|
9
7
|
# Rack::ShowExceptions catches all exceptions raised from the app it
|
@@ -313,7 +311,7 @@ module Rack
|
|
313
311
|
<% end %>
|
314
312
|
|
315
313
|
<h3 id="post-info">POST</h3>
|
316
|
-
<% if req.POST and not req.POST.empty? %>
|
314
|
+
<% if ((req.POST and not req.POST.empty?) rescue (no_post_data = "Invalid POST data"; nil)) %>
|
317
315
|
<table class="req">
|
318
316
|
<thead>
|
319
317
|
<tr>
|
@@ -331,7 +329,7 @@ module Rack
|
|
331
329
|
</tbody>
|
332
330
|
</table>
|
333
331
|
<% else %>
|
334
|
-
<p
|
332
|
+
<p><%= no_post_data || "No POST data" %>.</p>
|
335
333
|
<% end %>
|
336
334
|
|
337
335
|
|
data/lib/rack/show_status.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'erb'
|
4
|
-
require 'rack/request'
|
5
|
-
require 'rack/utils'
|
6
4
|
|
7
5
|
module Rack
|
8
6
|
# Rack::ShowStatus catches all empty responses and replaces them
|
@@ -20,7 +18,7 @@ module Rack
|
|
20
18
|
|
21
19
|
def call(env)
|
22
20
|
status, headers, body = @app.call(env)
|
23
|
-
headers = Utils::HeaderHash
|
21
|
+
headers = Utils::HeaderHash[headers]
|
24
22
|
empty = headers[CONTENT_LENGTH].to_i <= 0
|
25
23
|
|
26
24
|
# client or server error, or explicit message
|
data/lib/rack/static.rb
CHANGED
@@ -1,10 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "rack/files"
|
4
|
-
require "rack/utils"
|
5
|
-
|
6
|
-
require_relative 'core_ext/regexp'
|
7
|
-
|
8
3
|
module Rack
|
9
4
|
|
10
5
|
# The Rack::Static middleware intercepts requests for static files
|
@@ -19,6 +14,11 @@ module Rack
|
|
19
14
|
#
|
20
15
|
# use Rack::Static, :urls => ["/media"]
|
21
16
|
#
|
17
|
+
# Same as previous, but instead of returning 404 for missing files under
|
18
|
+
# /media, call the next middleware:
|
19
|
+
#
|
20
|
+
# use Rack::Static, :urls => ["/media"], :cascade => true
|
21
|
+
#
|
22
22
|
# Serve all requests beginning with /css or /images from the folder "public"
|
23
23
|
# in the current directory (ie public/css/* and public/images/*):
|
24
24
|
#
|
@@ -86,13 +86,14 @@ module Rack
|
|
86
86
|
# ]
|
87
87
|
#
|
88
88
|
class Static
|
89
|
-
using ::Rack::RegexpExtensions
|
89
|
+
(require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4'
|
90
90
|
|
91
91
|
def initialize(app, options = {})
|
92
92
|
@app = app
|
93
93
|
@urls = options[:urls] || ["/favicon.ico"]
|
94
94
|
@index = options[:index]
|
95
95
|
@gzip = options[:gzip]
|
96
|
+
@cascade = options[:cascade]
|
96
97
|
root = options[:root] || Dir.pwd
|
97
98
|
|
98
99
|
# HTTP Headers
|
@@ -133,6 +134,8 @@ module Rack
|
|
133
134
|
|
134
135
|
if response[0] == 404
|
135
136
|
response = nil
|
137
|
+
elsif response[0] == 304
|
138
|
+
# Do nothing, leave headers as is
|
136
139
|
else
|
137
140
|
if mime_type = Mime.mime_type(::File.extname(path), 'text/plain')
|
138
141
|
response[1][CONTENT_TYPE] = mime_type
|
@@ -144,6 +147,10 @@ module Rack
|
|
144
147
|
path = env[PATH_INFO]
|
145
148
|
response ||= @file_server.call(env)
|
146
149
|
|
150
|
+
if @cascade && response[0] == 404
|
151
|
+
return @app.call(env)
|
152
|
+
end
|
153
|
+
|
147
154
|
headers = response[1]
|
148
155
|
applicable_rules(path).each do |rule, new_headers|
|
149
156
|
new_headers.each { |field, content| headers[field] = content }
|
data/lib/rack/tempfile_reaper.rb
CHANGED
data/lib/rack/urlmap.rb
CHANGED
@@ -16,9 +16,6 @@ module Rack
|
|
16
16
|
# first, since they are most specific.
|
17
17
|
|
18
18
|
class URLMap
|
19
|
-
NEGATIVE_INFINITY = -1.0 / 0.0
|
20
|
-
INFINITY = 1.0 / 0.0
|
21
|
-
|
22
19
|
def initialize(map = {})
|
23
20
|
remap(map)
|
24
21
|
end
|
@@ -42,7 +39,7 @@ module Rack
|
|
42
39
|
|
43
40
|
[host, location, match, app]
|
44
41
|
}.sort_by do |(host, location, _, _)|
|
45
|
-
[host ? -host.size : INFINITY, -location.size]
|
42
|
+
[host ? -host.size : Float::INFINITY, -location.size]
|
46
43
|
end
|
47
44
|
end
|
48
45
|
|