rack 2.0.9.3 → 2.1.4.3
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 +92 -0
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +76 -116
- data/Rakefile +25 -18
- data/SPEC +9 -9
- data/bin/rackup +1 -0
- data/example/lobster.ru +2 -0
- data/example/protectedlobster.rb +3 -1
- data/example/protectedlobster.ru +2 -0
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +2 -0
- data/lib/rack/auth/basic.rb +4 -1
- data/lib/rack/auth/digest/md5.rb +9 -7
- data/lib/rack/auth/digest/nonce.rb +6 -3
- data/lib/rack/auth/digest/params.rb +4 -2
- data/lib/rack/auth/digest/request.rb +2 -0
- data/lib/rack/body_proxy.rb +3 -6
- data/lib/rack/builder.rb +39 -15
- data/lib/rack/cascade.rb +6 -5
- data/lib/rack/chunked.rb +29 -6
- data/lib/rack/common_logger.rb +9 -8
- data/lib/rack/conditional_get.rb +3 -1
- data/lib/rack/config.rb +2 -0
- data/lib/rack/content_length.rb +3 -1
- data/lib/rack/content_type.rb +3 -1
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +32 -17
- data/lib/rack/directory.rb +19 -16
- data/lib/rack/etag.rb +3 -1
- data/lib/rack/events.rb +5 -3
- data/lib/rack/file.rb +4 -173
- data/lib/rack/files.rb +178 -0
- data/lib/rack/handler/cgi.rb +3 -1
- data/lib/rack/handler/fastcgi.rb +4 -2
- data/lib/rack/handler/lsws.rb +3 -1
- data/lib/rack/handler/scgi.rb +9 -6
- data/lib/rack/handler/thin.rb +3 -1
- data/lib/rack/handler/webrick.rb +4 -2
- data/lib/rack/handler.rb +7 -2
- data/lib/rack/head.rb +2 -0
- data/lib/rack/lint.rb +14 -11
- data/lib/rack/lobster.rb +7 -5
- data/lib/rack/lock.rb +2 -0
- data/lib/rack/logger.rb +2 -0
- data/lib/rack/media_type.rb +10 -5
- data/lib/rack/method_override.rb +4 -2
- data/lib/rack/mime.rb +9 -1
- data/lib/rack/mock.rb +74 -15
- data/lib/rack/multipart/generator.rb +6 -7
- data/lib/rack/multipart/parser.rb +50 -45
- data/lib/rack/multipart/uploaded_file.rb +2 -0
- data/lib/rack/multipart.rb +3 -1
- data/lib/rack/null_logger.rb +2 -0
- data/lib/rack/query_parser.rb +51 -25
- data/lib/rack/recursive.rb +7 -5
- data/lib/rack/reloader.rb +10 -4
- data/lib/rack/request.rb +79 -26
- data/lib/rack/response.rb +71 -31
- data/lib/rack/rewindable_input.rb +4 -2
- data/lib/rack/runtime.rb +4 -2
- data/lib/rack/sendfile.rb +15 -8
- data/lib/rack/server.rb +88 -18
- data/lib/rack/session/abstract/id.rb +30 -20
- data/lib/rack/session/cookie.rb +10 -9
- data/lib/rack/session/memcache.rb +4 -93
- data/lib/rack/session/pool.rb +4 -2
- data/lib/rack/show_exceptions.rb +15 -9
- data/lib/rack/show_status.rb +4 -2
- data/lib/rack/static.rb +15 -10
- data/lib/rack/tempfile_reaper.rb +2 -0
- data/lib/rack/urlmap.rb +11 -2
- data/lib/rack/utils.rb +58 -71
- data/lib/rack.rb +63 -60
- data/rack.gemspec +17 -7
- metadata +28 -170
- data/HISTORY.md +0 -520
- data/test/builder/an_underscore_app.rb +0 -5
- data/test/builder/anything.rb +0 -5
- data/test/builder/comment.ru +0 -4
- data/test/builder/end.ru +0 -5
- data/test/builder/line.ru +0 -1
- data/test/builder/options.ru +0 -2
- data/test/cgi/assets/folder/test.js +0 -1
- data/test/cgi/assets/fonts/font.eot +0 -1
- data/test/cgi/assets/images/image.png +0 -1
- data/test/cgi/assets/index.html +0 -1
- data/test/cgi/assets/javascripts/app.js +0 -1
- data/test/cgi/assets/stylesheets/app.css +0 -1
- data/test/cgi/lighttpd.conf +0 -26
- data/test/cgi/rackup_stub.rb +0 -6
- data/test/cgi/sample_rackup.ru +0 -5
- data/test/cgi/test +0 -9
- data/test/cgi/test+directory/test+file +0 -1
- data/test/cgi/test.fcgi +0 -9
- data/test/cgi/test.gz +0 -0
- data/test/cgi/test.ru +0 -5
- data/test/gemloader.rb +0 -10
- data/test/helper.rb +0 -34
- data/test/multipart/bad_robots +0 -259
- data/test/multipart/binary +0 -0
- data/test/multipart/content_type_and_no_filename +0 -6
- data/test/multipart/empty +0 -10
- data/test/multipart/fail_16384_nofile +0 -814
- data/test/multipart/file1.txt +0 -1
- data/test/multipart/filename_and_modification_param +0 -7
- data/test/multipart/filename_and_no_name +0 -6
- data/test/multipart/filename_with_encoded_words +0 -7
- data/test/multipart/filename_with_escaped_quotes +0 -6
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
- data/test/multipart/filename_with_null_byte +0 -7
- data/test/multipart/filename_with_percent_escaped_quotes +0 -6
- data/test/multipart/filename_with_single_quote +0 -7
- data/test/multipart/filename_with_unescaped_percentages +0 -6
- data/test/multipart/filename_with_unescaped_percentages2 +0 -6
- data/test/multipart/filename_with_unescaped_percentages3 +0 -6
- data/test/multipart/filename_with_unescaped_quotes +0 -6
- data/test/multipart/ie +0 -6
- data/test/multipart/invalid_character +0 -6
- data/test/multipart/mixed_files +0 -21
- data/test/multipart/nested +0 -10
- data/test/multipart/none +0 -9
- data/test/multipart/quoted +0 -15
- data/test/multipart/rack-logo.png +0 -0
- data/test/multipart/semicolon +0 -6
- data/test/multipart/text +0 -15
- data/test/multipart/three_files_three_fields +0 -31
- data/test/multipart/unity3d_wwwform +0 -11
- data/test/multipart/webkit +0 -32
- data/test/rackup/config.ru +0 -31
- data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
- data/test/spec_auth_basic.rb +0 -89
- data/test/spec_auth_digest.rb +0 -260
- data/test/spec_body_proxy.rb +0 -85
- data/test/spec_builder.rb +0 -233
- data/test/spec_cascade.rb +0 -63
- data/test/spec_cgi.rb +0 -84
- data/test/spec_chunked.rb +0 -103
- data/test/spec_common_logger.rb +0 -107
- data/test/spec_conditional_get.rb +0 -103
- data/test/spec_config.rb +0 -23
- data/test/spec_content_length.rb +0 -86
- data/test/spec_content_type.rb +0 -46
- data/test/spec_deflater.rb +0 -375
- data/test/spec_directory.rb +0 -148
- data/test/spec_etag.rb +0 -108
- data/test/spec_events.rb +0 -133
- data/test/spec_fastcgi.rb +0 -85
- data/test/spec_file.rb +0 -264
- data/test/spec_handler.rb +0 -57
- data/test/spec_head.rb +0 -46
- data/test/spec_lint.rb +0 -520
- data/test/spec_lobster.rb +0 -59
- data/test/spec_lock.rb +0 -204
- data/test/spec_logger.rb +0 -24
- data/test/spec_media_type.rb +0 -42
- data/test/spec_method_override.rb +0 -110
- data/test/spec_mime.rb +0 -51
- data/test/spec_mock.rb +0 -359
- data/test/spec_multipart.rb +0 -721
- data/test/spec_null_logger.rb +0 -21
- data/test/spec_recursive.rb +0 -75
- data/test/spec_request.rb +0 -1423
- data/test/spec_response.rb +0 -528
- data/test/spec_rewindable_input.rb +0 -128
- data/test/spec_runtime.rb +0 -50
- data/test/spec_sendfile.rb +0 -125
- data/test/spec_server.rb +0 -193
- data/test/spec_session_abstract_id.rb +0 -31
- data/test/spec_session_abstract_session_hash.rb +0 -45
- data/test/spec_session_cookie.rb +0 -442
- data/test/spec_session_memcache.rb +0 -357
- data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
- data/test/spec_session_pool.rb +0 -247
- data/test/spec_show_exceptions.rb +0 -93
- data/test/spec_show_status.rb +0 -104
- data/test/spec_static.rb +0 -184
- data/test/spec_tempfile_reaper.rb +0 -64
- data/test/spec_thin.rb +0 -96
- data/test/spec_urlmap.rb +0 -237
- data/test/spec_utils.rb +0 -742
- data/test/spec_version.rb +0 -11
- data/test/spec_webrick.rb +0 -206
- data/test/static/another/index.html +0 -1
- data/test/static/foo.html +0 -1
- data/test/static/index.html +0 -1
- data/test/testrequest.rb +0 -78
- data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/lib/rack/static.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rack/files"
|
2
4
|
require "rack/utils"
|
3
5
|
|
6
|
+
require_relative 'core_ext/regexp'
|
7
|
+
|
4
8
|
module Rack
|
5
9
|
|
6
10
|
# The Rack::Static middleware intercepts requests for static files
|
7
11
|
# (javascript files, images, stylesheets, etc) based on the url prefixes or
|
8
|
-
# route mappings passed in the options, and serves them using a Rack::
|
12
|
+
# route mappings passed in the options, and serves them using a Rack::Files
|
9
13
|
# object. This allows a Rack stack to serve both static and dynamic content.
|
10
14
|
#
|
11
15
|
# Examples:
|
@@ -82,8 +86,9 @@ module Rack
|
|
82
86
|
# ]
|
83
87
|
#
|
84
88
|
class Static
|
89
|
+
using ::Rack::RegexpExtensions
|
85
90
|
|
86
|
-
def initialize(app, options={})
|
91
|
+
def initialize(app, options = {})
|
87
92
|
@app = app
|
88
93
|
@urls = options[:urls] || ["/favicon.ico"]
|
89
94
|
@index = options[:index]
|
@@ -93,13 +98,13 @@ module Rack
|
|
93
98
|
# HTTP Headers
|
94
99
|
@header_rules = options[:header_rules] || []
|
95
100
|
# Allow for legacy :cache_control option while prioritizing global header_rules setting
|
96
|
-
@header_rules.unshift([:all, {CACHE_CONTROL => options[:cache_control]}]) if options[:cache_control]
|
101
|
+
@header_rules.unshift([:all, { CACHE_CONTROL => options[:cache_control] }]) if options[:cache_control]
|
97
102
|
|
98
|
-
@file_server = Rack::
|
103
|
+
@file_server = Rack::Files.new(root)
|
99
104
|
end
|
100
105
|
|
101
106
|
def add_index_root?(path)
|
102
|
-
@index && path
|
107
|
+
@index && route_file(path) && path.end_with?('/')
|
103
108
|
end
|
104
109
|
|
105
110
|
def overwrite_file_path(path)
|
@@ -120,7 +125,7 @@ module Rack
|
|
120
125
|
if can_serve(path)
|
121
126
|
if overwrite_file_path(path)
|
122
127
|
env[PATH_INFO] = (add_index_root?(path) ? path + @index : @urls[path])
|
123
|
-
elsif @gzip && env['HTTP_ACCEPT_ENCODING']
|
128
|
+
elsif @gzip && env['HTTP_ACCEPT_ENCODING'] && /\bgzip\b/.match?(env['HTTP_ACCEPT_ENCODING'])
|
124
129
|
path = env[PATH_INFO]
|
125
130
|
env[PATH_INFO] += '.gz'
|
126
131
|
response = @file_server.call(env)
|
@@ -157,14 +162,14 @@ module Rack
|
|
157
162
|
when :all
|
158
163
|
true
|
159
164
|
when :fonts
|
160
|
-
|
165
|
+
/\.(?:ttf|otf|eot|woff2|woff|svg)\z/.match?(path)
|
161
166
|
when String
|
162
167
|
path = ::Rack::Utils.unescape(path)
|
163
168
|
path.start_with?(rule) || path.start_with?('/' + rule)
|
164
169
|
when Array
|
165
|
-
|
170
|
+
/\.(#{rule.join('|')})\z/.match?(path)
|
166
171
|
when Regexp
|
167
|
-
path
|
172
|
+
rule.match?(path)
|
168
173
|
else
|
169
174
|
false
|
170
175
|
end
|
data/lib/rack/tempfile_reaper.rb
CHANGED
data/lib/rack/urlmap.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
1
5
|
module Rack
|
2
6
|
# Rack::URLMap takes a hash mapping urls or paths to apps, and
|
3
7
|
# dispatches accordingly. Support for HTTP/1.1 host names exists if
|
@@ -20,9 +24,11 @@ module Rack
|
|
20
24
|
end
|
21
25
|
|
22
26
|
def remap(map)
|
27
|
+
@known_hosts = Set[]
|
23
28
|
@mapping = map.map { |location, app|
|
24
29
|
if location =~ %r{\Ahttps?://(.*?)(/.*)}
|
25
30
|
host, location = $1, $2
|
31
|
+
@known_hosts << host
|
26
32
|
else
|
27
33
|
host = nil
|
28
34
|
end
|
@@ -50,10 +56,13 @@ module Rack
|
|
50
56
|
is_same_server = casecmp?(http_host, server_name) ||
|
51
57
|
casecmp?(http_host, "#{server_name}:#{server_port}")
|
52
58
|
|
59
|
+
is_host_known = @known_hosts.include? http_host
|
60
|
+
|
53
61
|
@mapping.each do |host, location, match, app|
|
54
62
|
unless casecmp?(http_host, host) \
|
55
63
|
|| casecmp?(server_name, host) \
|
56
|
-
|| (!host && is_same_server)
|
64
|
+
|| (!host && is_same_server) \
|
65
|
+
|| (!host && !is_host_known) # If we don't have a matching host, default to the first without a specified host
|
57
66
|
next
|
58
67
|
end
|
59
68
|
|
@@ -68,7 +77,7 @@ module Rack
|
|
68
77
|
return app.call(env)
|
69
78
|
end
|
70
79
|
|
71
|
-
[404, {CONTENT_TYPE => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]]
|
80
|
+
[404, { CONTENT_TYPE => "text/plain", "X-Cascade" => "pass" }, ["Not Found: #{path}"]]
|
72
81
|
|
73
82
|
ensure
|
74
83
|
env[PATH_INFO] = path
|
data/lib/rack/utils.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
require 'uri'
|
3
5
|
require 'fileutils'
|
4
6
|
require 'set'
|
@@ -6,11 +8,15 @@ require 'tempfile'
|
|
6
8
|
require 'rack/query_parser'
|
7
9
|
require 'time'
|
8
10
|
|
11
|
+
require_relative 'core_ext/regexp'
|
12
|
+
|
9
13
|
module Rack
|
10
14
|
# Rack::Utils contains a grab-bag of useful methods for writing web
|
11
15
|
# applications adopted from all kinds of Ruby libraries.
|
12
16
|
|
13
17
|
module Utils
|
18
|
+
using ::Rack::RegexpExtensions
|
19
|
+
|
14
20
|
ParameterTypeError = QueryParser::ParameterTypeError
|
15
21
|
InvalidParameterError = QueryParser::InvalidParameterError
|
16
22
|
DEFAULT_SEP = QueryParser::DEFAULT_SEP
|
@@ -129,7 +135,7 @@ module Rack
|
|
129
135
|
when Hash
|
130
136
|
value.map { |k, v|
|
131
137
|
build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
|
132
|
-
}.
|
138
|
+
}.delete_if(&:empty?).join('&')
|
133
139
|
when nil
|
134
140
|
prefix
|
135
141
|
else
|
@@ -143,7 +149,7 @@ module Rack
|
|
143
149
|
q_value_header.to_s.split(/\s*,\s*/).map do |part|
|
144
150
|
value, parameters = part.split(/\s*;\s*/, 2)
|
145
151
|
quality = 1.0
|
146
|
-
if md = /\Aq=([\d.]+)/.match(parameters)
|
152
|
+
if parameters && (md = /\Aq=([\d.]+)/.match(parameters))
|
147
153
|
quality = md[1].to_f
|
148
154
|
end
|
149
155
|
[value, quality]
|
@@ -186,27 +192,26 @@ module Rack
|
|
186
192
|
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
187
193
|
|
188
194
|
expanded_accept_encoding =
|
189
|
-
accept_encoding.
|
195
|
+
accept_encoding.each_with_object([]) do |(m, q), list|
|
190
196
|
if m == "*"
|
191
|
-
(available_encodings - accept_encoding.map
|
197
|
+
(available_encodings - accept_encoding.map(&:first))
|
198
|
+
.each { |m2| list << [m2, q] }
|
192
199
|
else
|
193
|
-
[
|
200
|
+
list << [m, q]
|
194
201
|
end
|
195
|
-
|
196
|
-
mem + list
|
197
|
-
}
|
202
|
+
end
|
198
203
|
|
199
|
-
encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map
|
204
|
+
encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map!(&:first)
|
200
205
|
|
201
206
|
unless encoding_candidates.include?("identity")
|
202
207
|
encoding_candidates.push("identity")
|
203
208
|
end
|
204
209
|
|
205
|
-
expanded_accept_encoding.each
|
210
|
+
expanded_accept_encoding.each do |m, q|
|
206
211
|
encoding_candidates.delete(m) if q == 0.0
|
207
|
-
|
212
|
+
end
|
208
213
|
|
209
|
-
|
214
|
+
(encoding_candidates & available_encodings)[0]
|
210
215
|
end
|
211
216
|
module_function :select_best_encoding
|
212
217
|
|
@@ -221,8 +226,12 @@ module Rack
|
|
221
226
|
# the Cookie header such that those with more specific Path attributes
|
222
227
|
# precede those with less specific. Ordering with respect to other
|
223
228
|
# attributes (e.g., Domain) is unspecified.
|
224
|
-
|
225
|
-
|
229
|
+
return {} unless header
|
230
|
+
header.split(/[;,] */n).each_with_object({}) do |cookie, cookies|
|
231
|
+
next if cookie.empty?
|
232
|
+
key, value = cookie.split('=', 2)
|
233
|
+
cookies[key] = (unescape(value) rescue value) unless cookies.key?(key)
|
234
|
+
end
|
226
235
|
end
|
227
236
|
module_function :parse_cookies_header
|
228
237
|
|
@@ -232,31 +241,7 @@ module Rack
|
|
232
241
|
domain = "; domain=#{value[:domain]}" if value[:domain]
|
233
242
|
path = "; path=#{value[:path]}" if value[:path]
|
234
243
|
max_age = "; max-age=#{value[:max_age]}" if value[:max_age]
|
235
|
-
|
236
|
-
# only are there contradicting RFCs and examples within RFC text, but
|
237
|
-
# there are also numerous conflicting names of fields and partially
|
238
|
-
# cross-applicable specifications.
|
239
|
-
#
|
240
|
-
# These are best described in RFC 2616 3.3.1. This RFC text also
|
241
|
-
# specifies that RFC 822 as updated by RFC 1123 is preferred. That is a
|
242
|
-
# fixed length format with space-date delimited fields.
|
243
|
-
#
|
244
|
-
# See also RFC 1123 section 5.2.14.
|
245
|
-
#
|
246
|
-
# RFC 6265 also specifies "sane-cookie-date" as RFC 1123 date, defined
|
247
|
-
# in RFC 2616 3.3.1. RFC 6265 also gives examples that clearly denote
|
248
|
-
# the space delimited format. These formats are compliant with RFC 2822.
|
249
|
-
#
|
250
|
-
# For reference, all involved RFCs are:
|
251
|
-
# RFC 822
|
252
|
-
# RFC 1123
|
253
|
-
# RFC 2109
|
254
|
-
# RFC 2616
|
255
|
-
# RFC 2822
|
256
|
-
# RFC 2965
|
257
|
-
# RFC 6265
|
258
|
-
expires = "; expires=" +
|
259
|
-
rfc2822(value[:expires].clone.gmtime) if value[:expires]
|
244
|
+
expires = "; expires=#{value[:expires].httpdate}" if value[:expires]
|
260
245
|
secure = "; secure" if value[:secure]
|
261
246
|
httponly = "; HttpOnly" if (value.key?(:httponly) ? value[:httponly] : value[:http_only])
|
262
247
|
same_site =
|
@@ -264,11 +249,11 @@ module Rack
|
|
264
249
|
when false, nil
|
265
250
|
nil
|
266
251
|
when :none, 'None', :None
|
267
|
-
'; SameSite=None'
|
252
|
+
'; SameSite=None'
|
268
253
|
when :lax, 'Lax', :Lax
|
269
|
-
'; SameSite=Lax'
|
254
|
+
'; SameSite=Lax'
|
270
255
|
when true, :strict, 'Strict', :Strict
|
271
|
-
'; SameSite=Strict'
|
256
|
+
'; SameSite=Strict'
|
272
257
|
else
|
273
258
|
raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}"
|
274
259
|
end
|
@@ -308,15 +293,15 @@ module Rack
|
|
308
293
|
cookies = header
|
309
294
|
end
|
310
295
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
}
|
296
|
+
regexp = if value[:domain]
|
297
|
+
/\A#{escape(key)}=.*domain=#{value[:domain]}/
|
298
|
+
elsif value[:path]
|
299
|
+
/\A#{escape(key)}=.*path=#{value[:path]}/
|
300
|
+
else
|
301
|
+
/\A#{escape(key)}=/
|
302
|
+
end
|
303
|
+
|
304
|
+
cookies.reject! { |cookie| regexp.match? cookie }
|
320
305
|
|
321
306
|
cookies.join("\n")
|
322
307
|
end
|
@@ -334,9 +319,9 @@ module Rack
|
|
334
319
|
new_header = make_delete_cookie_header(header, key, value)
|
335
320
|
|
336
321
|
add_cookie_to_header(new_header, key,
|
337
|
-
{:
|
338
|
-
:
|
339
|
-
:
|
322
|
+
{ value: '', path: nil, domain: nil,
|
323
|
+
max_age: '0',
|
324
|
+
expires: Time.at(0) }.merge(value))
|
340
325
|
|
341
326
|
end
|
342
327
|
module_function :add_remove_cookie_to_header
|
@@ -392,7 +377,7 @@ module Rack
|
|
392
377
|
else
|
393
378
|
r1 = r1.to_i
|
394
379
|
return nil if r1 < r0 # backwards range is syntactically invalid
|
395
|
-
r1 = size-1 if r1 >= size
|
380
|
+
r1 = size - 1 if r1 >= size
|
396
381
|
end
|
397
382
|
end
|
398
383
|
ranges << (r0..r1) if r0 <= r1
|
@@ -413,7 +398,7 @@ module Rack
|
|
413
398
|
l = a.unpack("C*")
|
414
399
|
|
415
400
|
r, i = 0, -1
|
416
|
-
b.each_byte { |v| r |= v ^ l[i+=1] }
|
401
|
+
b.each_byte { |v| r |= v ^ l[i += 1] }
|
417
402
|
r == 0
|
418
403
|
end
|
419
404
|
module_function :secure_compare
|
@@ -439,19 +424,17 @@ module Rack
|
|
439
424
|
self.class.new(@for, app)
|
440
425
|
end
|
441
426
|
|
442
|
-
def context(env, app
|
427
|
+
def context(env, app = @app)
|
443
428
|
recontext(app).call(env)
|
444
429
|
end
|
445
430
|
end
|
446
431
|
|
447
432
|
# A case-insensitive Hash that preserves the original case of a
|
448
433
|
# header when set.
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
def initialize(hash={})
|
434
|
+
#
|
435
|
+
# @api private
|
436
|
+
class HeaderHash < Hash # :nodoc:
|
437
|
+
def initialize(hash = {})
|
455
438
|
super()
|
456
439
|
@names = {}
|
457
440
|
hash.each { |k, v| self[k] = v }
|
@@ -471,7 +454,7 @@ module Rack
|
|
471
454
|
|
472
455
|
def to_hash
|
473
456
|
hash = {}
|
474
|
-
each { |k,v| hash[k] = v }
|
457
|
+
each { |k, v| hash[k] = v }
|
475
458
|
hash
|
476
459
|
end
|
477
460
|
|
@@ -524,13 +507,14 @@ module Rack
|
|
524
507
|
|
525
508
|
# Every standard HTTP code mapped to the appropriate message.
|
526
509
|
# Generated with:
|
527
|
-
#
|
528
|
-
#
|
529
|
-
#
|
510
|
+
# curl -s https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv | \
|
511
|
+
# ruby -ne 'm = /^(\d{3}),(?!Unassigned|\(Unused\))([^,]+)/.match($_) and \
|
512
|
+
# puts "#{m[1]} => \x27#{m[2].strip}\x27,"'
|
530
513
|
HTTP_STATUS_CODES = {
|
531
514
|
100 => 'Continue',
|
532
515
|
101 => 'Switching Protocols',
|
533
516
|
102 => 'Processing',
|
517
|
+
103 => 'Early Hints',
|
534
518
|
200 => 'OK',
|
535
519
|
201 => 'Created',
|
536
520
|
202 => 'Accepted',
|
@@ -547,6 +531,7 @@ module Rack
|
|
547
531
|
303 => 'See Other',
|
548
532
|
304 => 'Not Modified',
|
549
533
|
305 => 'Use Proxy',
|
534
|
+
306 => '(Unused)',
|
550
535
|
307 => 'Temporary Redirect',
|
551
536
|
308 => 'Permanent Redirect',
|
552
537
|
400 => 'Bad Request',
|
@@ -571,6 +556,7 @@ module Rack
|
|
571
556
|
422 => 'Unprocessable Entity',
|
572
557
|
423 => 'Locked',
|
573
558
|
424 => 'Failed Dependency',
|
559
|
+
425 => 'Too Early',
|
574
560
|
426 => 'Upgrade Required',
|
575
561
|
428 => 'Precondition Required',
|
576
562
|
429 => 'Too Many Requests',
|
@@ -585,12 +571,13 @@ module Rack
|
|
585
571
|
506 => 'Variant Also Negotiates',
|
586
572
|
507 => 'Insufficient Storage',
|
587
573
|
508 => 'Loop Detected',
|
574
|
+
509 => 'Bandwidth Limit Exceeded',
|
588
575
|
510 => 'Not Extended',
|
589
576
|
511 => 'Network Authentication Required'
|
590
577
|
}
|
591
578
|
|
592
579
|
# Responses with HTTP status codes that should not have an entity body
|
593
|
-
STATUS_WITH_NO_ENTITY_BODY =
|
580
|
+
STATUS_WITH_NO_ENTITY_BODY = Hash[((100..199).to_a << 204 << 304).product([true])]
|
594
581
|
|
595
582
|
SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message|
|
596
583
|
[message.downcase.gsub(/\s|-|'/, '_').to_sym, code]
|
@@ -598,7 +585,7 @@ module Rack
|
|
598
585
|
|
599
586
|
def status_code(status)
|
600
587
|
if status.is_a?(Symbol)
|
601
|
-
SYMBOL_TO_STATUS_CODE
|
588
|
+
SYMBOL_TO_STATUS_CODE.fetch(status) { raise ArgumentError, "Unrecognized status code #{status.inspect}" }
|
602
589
|
else
|
603
590
|
status.to_i
|
604
591
|
end
|
@@ -619,11 +606,11 @@ module Rack
|
|
619
606
|
|
620
607
|
clean.unshift '/' if parts.empty? || parts.first.empty?
|
621
608
|
|
622
|
-
::File.join
|
609
|
+
::File.join clean
|
623
610
|
end
|
624
611
|
module_function :clean_path_info
|
625
612
|
|
626
|
-
NULL_BYTE = "\0"
|
613
|
+
NULL_BYTE = "\0"
|
627
614
|
|
628
615
|
def valid_path?(path)
|
629
616
|
path.valid_encoding? && !path.include?(NULL_BYTE)
|
data/lib/rack.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2007-2019 Leah Neukirchen <http://leahneukirchen.org/infopage.html>
|
2
4
|
#
|
3
5
|
# Rack is freely distributable under the terms of an MIT-style license.
|
4
|
-
# See
|
6
|
+
# See MIT-LICENSE or https://opensource.org/licenses/MIT.
|
5
7
|
|
6
8
|
# The Rack main module, serving as a namespace for all core Rack
|
7
9
|
# modules and classes.
|
@@ -11,80 +13,80 @@
|
|
11
13
|
|
12
14
|
module Rack
|
13
15
|
# The Rack protocol version number implemented.
|
14
|
-
VERSION = [1,3]
|
16
|
+
VERSION = [1, 3]
|
15
17
|
|
16
18
|
# Return the Rack protocol version as a dotted string.
|
17
19
|
def self.version
|
18
20
|
VERSION.join(".")
|
19
21
|
end
|
20
22
|
|
21
|
-
RELEASE = "2.
|
23
|
+
RELEASE = "2.1.4.3"
|
22
24
|
|
23
25
|
# Return the Rack release as a dotted string.
|
24
26
|
def self.release
|
25
27
|
RELEASE
|
26
28
|
end
|
27
29
|
|
28
|
-
HTTP_HOST = 'HTTP_HOST'
|
29
|
-
HTTP_VERSION = 'HTTP_VERSION'
|
30
|
-
HTTPS = 'HTTPS'
|
31
|
-
PATH_INFO = 'PATH_INFO'
|
32
|
-
REQUEST_METHOD = 'REQUEST_METHOD'
|
33
|
-
REQUEST_PATH = 'REQUEST_PATH'
|
34
|
-
SCRIPT_NAME = 'SCRIPT_NAME'
|
35
|
-
QUERY_STRING = 'QUERY_STRING'
|
36
|
-
SERVER_PROTOCOL = 'SERVER_PROTOCOL'
|
37
|
-
SERVER_NAME = 'SERVER_NAME'
|
38
|
-
SERVER_ADDR = 'SERVER_ADDR'
|
39
|
-
SERVER_PORT = 'SERVER_PORT'
|
40
|
-
CACHE_CONTROL = 'Cache-Control'
|
41
|
-
CONTENT_LENGTH = 'Content-Length'
|
42
|
-
CONTENT_TYPE = 'Content-Type'
|
43
|
-
SET_COOKIE = 'Set-Cookie'
|
44
|
-
TRANSFER_ENCODING = 'Transfer-Encoding'
|
45
|
-
HTTP_COOKIE = 'HTTP_COOKIE'
|
46
|
-
ETAG = 'ETag'
|
30
|
+
HTTP_HOST = 'HTTP_HOST'
|
31
|
+
HTTP_VERSION = 'HTTP_VERSION'
|
32
|
+
HTTPS = 'HTTPS'
|
33
|
+
PATH_INFO = 'PATH_INFO'
|
34
|
+
REQUEST_METHOD = 'REQUEST_METHOD'
|
35
|
+
REQUEST_PATH = 'REQUEST_PATH'
|
36
|
+
SCRIPT_NAME = 'SCRIPT_NAME'
|
37
|
+
QUERY_STRING = 'QUERY_STRING'
|
38
|
+
SERVER_PROTOCOL = 'SERVER_PROTOCOL'
|
39
|
+
SERVER_NAME = 'SERVER_NAME'
|
40
|
+
SERVER_ADDR = 'SERVER_ADDR'
|
41
|
+
SERVER_PORT = 'SERVER_PORT'
|
42
|
+
CACHE_CONTROL = 'Cache-Control'
|
43
|
+
CONTENT_LENGTH = 'Content-Length'
|
44
|
+
CONTENT_TYPE = 'Content-Type'
|
45
|
+
SET_COOKIE = 'Set-Cookie'
|
46
|
+
TRANSFER_ENCODING = 'Transfer-Encoding'
|
47
|
+
HTTP_COOKIE = 'HTTP_COOKIE'
|
48
|
+
ETAG = 'ETag'
|
47
49
|
|
48
50
|
# HTTP method verbs
|
49
|
-
GET = 'GET'
|
50
|
-
POST = 'POST'
|
51
|
-
PUT = 'PUT'
|
52
|
-
PATCH = 'PATCH'
|
53
|
-
DELETE = 'DELETE'
|
54
|
-
HEAD = 'HEAD'
|
55
|
-
OPTIONS = 'OPTIONS'
|
56
|
-
LINK = 'LINK'
|
57
|
-
UNLINK = 'UNLINK'
|
58
|
-
TRACE = 'TRACE'
|
51
|
+
GET = 'GET'
|
52
|
+
POST = 'POST'
|
53
|
+
PUT = 'PUT'
|
54
|
+
PATCH = 'PATCH'
|
55
|
+
DELETE = 'DELETE'
|
56
|
+
HEAD = 'HEAD'
|
57
|
+
OPTIONS = 'OPTIONS'
|
58
|
+
LINK = 'LINK'
|
59
|
+
UNLINK = 'UNLINK'
|
60
|
+
TRACE = 'TRACE'
|
59
61
|
|
60
62
|
# Rack environment variables
|
61
|
-
RACK_VERSION = 'rack.version'
|
62
|
-
RACK_TEMPFILES = 'rack.tempfiles'
|
63
|
-
RACK_ERRORS = 'rack.errors'
|
64
|
-
RACK_LOGGER = 'rack.logger'
|
65
|
-
RACK_INPUT = 'rack.input'
|
66
|
-
RACK_SESSION = 'rack.session'
|
67
|
-
RACK_SESSION_OPTIONS = 'rack.session.options'
|
68
|
-
RACK_SHOWSTATUS_DETAIL = 'rack.showstatus.detail'
|
69
|
-
RACK_MULTITHREAD = 'rack.multithread'
|
70
|
-
RACK_MULTIPROCESS = 'rack.multiprocess'
|
71
|
-
RACK_RUNONCE = 'rack.run_once'
|
72
|
-
RACK_URL_SCHEME = 'rack.url_scheme'
|
73
|
-
RACK_HIJACK = 'rack.hijack'
|
74
|
-
RACK_IS_HIJACK = 'rack.hijack?'
|
75
|
-
RACK_HIJACK_IO = 'rack.hijack_io'
|
76
|
-
RACK_RECURSIVE_INCLUDE = 'rack.recursive.include'
|
77
|
-
RACK_MULTIPART_BUFFER_SIZE = 'rack.multipart.buffer_size'
|
78
|
-
RACK_MULTIPART_TEMPFILE_FACTORY = 'rack.multipart.tempfile_factory'
|
79
|
-
RACK_REQUEST_FORM_INPUT = 'rack.request.form_input'
|
80
|
-
RACK_REQUEST_FORM_HASH = 'rack.request.form_hash'
|
81
|
-
RACK_REQUEST_FORM_VARS = 'rack.request.form_vars'
|
82
|
-
RACK_REQUEST_COOKIE_HASH = 'rack.request.cookie_hash'
|
83
|
-
RACK_REQUEST_COOKIE_STRING = 'rack.request.cookie_string'
|
84
|
-
RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash'
|
85
|
-
RACK_REQUEST_QUERY_STRING = 'rack.request.query_string'
|
86
|
-
RACK_METHODOVERRIDE_ORIGINAL_METHOD = 'rack.methodoverride.original_method'
|
87
|
-
RACK_SESSION_UNPACKED_COOKIE_DATA = 'rack.session.unpacked_cookie_data'
|
63
|
+
RACK_VERSION = 'rack.version'
|
64
|
+
RACK_TEMPFILES = 'rack.tempfiles'
|
65
|
+
RACK_ERRORS = 'rack.errors'
|
66
|
+
RACK_LOGGER = 'rack.logger'
|
67
|
+
RACK_INPUT = 'rack.input'
|
68
|
+
RACK_SESSION = 'rack.session'
|
69
|
+
RACK_SESSION_OPTIONS = 'rack.session.options'
|
70
|
+
RACK_SHOWSTATUS_DETAIL = 'rack.showstatus.detail'
|
71
|
+
RACK_MULTITHREAD = 'rack.multithread'
|
72
|
+
RACK_MULTIPROCESS = 'rack.multiprocess'
|
73
|
+
RACK_RUNONCE = 'rack.run_once'
|
74
|
+
RACK_URL_SCHEME = 'rack.url_scheme'
|
75
|
+
RACK_HIJACK = 'rack.hijack'
|
76
|
+
RACK_IS_HIJACK = 'rack.hijack?'
|
77
|
+
RACK_HIJACK_IO = 'rack.hijack_io'
|
78
|
+
RACK_RECURSIVE_INCLUDE = 'rack.recursive.include'
|
79
|
+
RACK_MULTIPART_BUFFER_SIZE = 'rack.multipart.buffer_size'
|
80
|
+
RACK_MULTIPART_TEMPFILE_FACTORY = 'rack.multipart.tempfile_factory'
|
81
|
+
RACK_REQUEST_FORM_INPUT = 'rack.request.form_input'
|
82
|
+
RACK_REQUEST_FORM_HASH = 'rack.request.form_hash'
|
83
|
+
RACK_REQUEST_FORM_VARS = 'rack.request.form_vars'
|
84
|
+
RACK_REQUEST_COOKIE_HASH = 'rack.request.cookie_hash'
|
85
|
+
RACK_REQUEST_COOKIE_STRING = 'rack.request.cookie_string'
|
86
|
+
RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash'
|
87
|
+
RACK_REQUEST_QUERY_STRING = 'rack.request.query_string'
|
88
|
+
RACK_METHODOVERRIDE_ORIGINAL_METHOD = 'rack.methodoverride.original_method'
|
89
|
+
RACK_SESSION_UNPACKED_COOKIE_DATA = 'rack.session.unpacked_cookie_data'
|
88
90
|
|
89
91
|
autoload :Builder, "rack/builder"
|
90
92
|
autoload :BodyProxy, "rack/body_proxy"
|
@@ -97,6 +99,7 @@ module Rack
|
|
97
99
|
autoload :ContentType, "rack/content_type"
|
98
100
|
autoload :ETag, "rack/etag"
|
99
101
|
autoload :File, "rack/file"
|
102
|
+
autoload :Files, "rack/files"
|
100
103
|
autoload :Deflater, "rack/deflater"
|
101
104
|
autoload :Directory, "rack/directory"
|
102
105
|
autoload :ForwardRequest, "rack/recursive"
|
data/rack.gemspec
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Gem::Specification.new do |s|
|
2
|
-
s.name
|
4
|
+
s.name = "rack"
|
3
5
|
s.version = File.read('lib/rack.rb')[/RELEASE += +([\"\'])([\d][\w\.]+)\1/, 2]
|
4
6
|
s.platform = Gem::Platform::RUBY
|
5
7
|
s.summary = "a modular Ruby webserver interface"
|
@@ -15,20 +17,28 @@ middleware) into a single method call.
|
|
15
17
|
Also see https://rack.github.io/.
|
16
18
|
EOF
|
17
19
|
|
18
|
-
s.files = Dir['{bin/*,contrib/*,example/*,lib
|
19
|
-
%w(
|
20
|
+
s.files = Dir['{bin/*,contrib/*,example/*,lib/**/*}'] +
|
21
|
+
%w(MIT-LICENSE rack.gemspec Rakefile README.rdoc SPEC)
|
20
22
|
s.bindir = 'bin'
|
21
|
-
s.executables
|
22
|
-
s.require_path
|
23
|
-
s.extra_rdoc_files = ['README.rdoc', '
|
24
|
-
s.test_files = Dir['test/spec_*.rb']
|
23
|
+
s.executables << 'rackup'
|
24
|
+
s.require_path = 'lib'
|
25
|
+
s.extra_rdoc_files = ['README.rdoc', 'CHANGELOG.md']
|
25
26
|
|
26
27
|
s.author = 'Leah Neukirchen'
|
27
28
|
s.email = 'leah@vuxu.org'
|
28
29
|
s.homepage = 'https://rack.github.io/'
|
29
30
|
s.required_ruby_version = '>= 2.2.2'
|
31
|
+
s.metadata = {
|
32
|
+
"bug_tracker_uri" => "https://github.com/rack/rack/issues",
|
33
|
+
"changelog_uri" => "https://github.com/rack/rack/blob/master/CHANGELOG.md",
|
34
|
+
"documentation_uri" => "https://rubydoc.info/github/rack/rack",
|
35
|
+
"homepage_uri" => "https://rack.github.io",
|
36
|
+
"mailing_list_uri" => "https://groups.google.com/forum/#!forum/rack-devel",
|
37
|
+
"source_code_uri" => "https://github.com/rack/rack"
|
38
|
+
}
|
30
39
|
|
31
40
|
s.add_development_dependency 'minitest', "~> 5.0"
|
32
41
|
s.add_development_dependency 'minitest-sprint'
|
42
|
+
s.add_development_dependency 'minitest-global_expectations'
|
33
43
|
s.add_development_dependency 'rake'
|
34
44
|
end
|