rack 2.0.9.3 → 2.2.8
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 +740 -0
- data/CONTRIBUTING.md +136 -0
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +151 -147
- data/Rakefile +37 -23
- data/{SPEC → SPEC.rdoc} +44 -15
- 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 +1 -1
- data/lib/rack/auth/basic.rb +7 -4
- data/lib/rack/auth/digest/md5.rb +13 -11
- 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 +5 -3
- data/lib/rack/body_proxy.rb +15 -14
- data/lib/rack/builder.rb +116 -23
- data/lib/rack/cascade.rb +28 -12
- data/lib/rack/chunked.rb +68 -20
- data/lib/rack/common_logger.rb +33 -25
- data/lib/rack/conditional_get.rb +20 -16
- data/lib/rack/config.rb +2 -0
- data/lib/rack/content_length.rb +8 -7
- data/lib/rack/content_type.rb +5 -4
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +59 -34
- data/lib/rack/directory.rb +84 -64
- data/lib/rack/etag.rb +7 -4
- data/lib/rack/events.rb +19 -20
- data/lib/rack/file.rb +4 -173
- data/lib/rack/files.rb +218 -0
- data/lib/rack/handler/cgi.rb +2 -3
- data/lib/rack/handler/fastcgi.rb +4 -4
- data/lib/rack/handler/lsws.rb +3 -3
- data/lib/rack/handler/scgi.rb +9 -8
- data/lib/rack/handler/thin.rb +3 -3
- data/lib/rack/handler/webrick.rb +15 -6
- data/lib/rack/handler.rb +7 -2
- data/lib/rack/head.rb +1 -1
- data/lib/rack/lint.rb +219 -184
- data/lib/rack/lobster.rb +10 -10
- data/lib/rack/lock.rb +2 -1
- data/lib/rack/logger.rb +2 -0
- data/lib/rack/media_type.rb +10 -5
- data/lib/rack/method_override.rb +5 -3
- data/lib/rack/mime.rb +9 -1
- data/lib/rack/mock.rb +97 -20
- data/lib/rack/multipart/generator.rb +17 -13
- data/lib/rack/multipart/parser.rb +55 -56
- data/lib/rack/multipart/uploaded_file.rb +15 -7
- data/lib/rack/multipart.rb +4 -2
- data/lib/rack/null_logger.rb +2 -0
- data/lib/rack/query_parser.rb +59 -30
- data/lib/rack/recursive.rb +7 -5
- data/lib/rack/reloader.rb +8 -4
- data/lib/rack/request.rb +222 -63
- data/lib/rack/response.rb +127 -44
- data/lib/rack/rewindable_input.rb +4 -3
- data/lib/rack/runtime.rb +6 -4
- data/lib/rack/sendfile.rb +13 -9
- data/lib/rack/server.rb +95 -24
- data/lib/rack/session/abstract/id.rb +34 -21
- data/lib/rack/session/cookie.rb +12 -12
- data/lib/rack/session/memcache.rb +4 -93
- data/lib/rack/session/pool.rb +5 -3
- data/lib/rack/show_exceptions.rb +21 -17
- data/lib/rack/show_status.rb +9 -9
- data/lib/rack/static.rb +23 -11
- data/lib/rack/tempfile_reaper.rb +1 -1
- data/lib/rack/urlmap.rb +13 -7
- data/lib/rack/utils.rb +105 -111
- data/lib/rack/version.rb +29 -0
- data/lib/rack.rb +67 -73
- data/rack.gemspec +40 -28
- metadata +36 -179
- 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/utils.rb
CHANGED
@@ -1,22 +1,30 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
require 'uri'
|
3
5
|
require 'fileutils'
|
4
6
|
require 'set'
|
5
7
|
require 'tempfile'
|
6
|
-
require 'rack/query_parser'
|
7
8
|
require 'time'
|
8
9
|
|
10
|
+
require_relative 'query_parser'
|
11
|
+
|
9
12
|
module Rack
|
10
13
|
# Rack::Utils contains a grab-bag of useful methods for writing web
|
11
14
|
# applications adopted from all kinds of Ruby libraries.
|
12
15
|
|
13
16
|
module Utils
|
17
|
+
(require_relative 'core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4'
|
18
|
+
|
14
19
|
ParameterTypeError = QueryParser::ParameterTypeError
|
15
20
|
InvalidParameterError = QueryParser::InvalidParameterError
|
16
21
|
DEFAULT_SEP = QueryParser::DEFAULT_SEP
|
17
22
|
COMMON_SEP = QueryParser::COMMON_SEP
|
18
23
|
KeySpaceConstrainedParams = QueryParser::Params
|
19
24
|
|
25
|
+
RFC2822_DAY_NAME = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]
|
26
|
+
RFC2822_MONTH_NAME = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
|
27
|
+
|
20
28
|
class << self
|
21
29
|
attr_accessor :default_query_parser
|
22
30
|
end
|
@@ -24,33 +32,30 @@ module Rack
|
|
24
32
|
# This helps prevent a rogue client from flooding a Request.
|
25
33
|
self.default_query_parser = QueryParser.make_default(65536, 100)
|
26
34
|
|
35
|
+
module_function
|
36
|
+
|
27
37
|
# URI escapes. (CGI style space to +)
|
28
38
|
def escape(s)
|
29
39
|
URI.encode_www_form_component(s)
|
30
40
|
end
|
31
|
-
module_function :escape
|
32
41
|
|
33
42
|
# Like URI escaping, but with %20 instead of +. Strictly speaking this is
|
34
43
|
# true URI escaping.
|
35
44
|
def escape_path(s)
|
36
45
|
::URI::DEFAULT_PARSER.escape s
|
37
46
|
end
|
38
|
-
module_function :escape_path
|
39
47
|
|
40
48
|
# Unescapes the **path** component of a URI. See Rack::Utils.unescape for
|
41
49
|
# unescaping query parameters or form components.
|
42
50
|
def unescape_path(s)
|
43
51
|
::URI::DEFAULT_PARSER.unescape s
|
44
52
|
end
|
45
|
-
module_function :unescape_path
|
46
|
-
|
47
53
|
|
48
54
|
# Unescapes a URI escaped string with +encoding+. +encoding+ will be the
|
49
55
|
# target encoding of the string returned, and it defaults to UTF-8
|
50
56
|
def unescape(s, encoding = Encoding::UTF_8)
|
51
57
|
URI.decode_www_form_component(s, encoding)
|
52
58
|
end
|
53
|
-
module_function :unescape
|
54
59
|
|
55
60
|
class << self
|
56
61
|
attr_accessor :multipart_total_part_limit
|
@@ -93,21 +98,20 @@ module Rack
|
|
93
98
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
94
99
|
end
|
95
100
|
else
|
101
|
+
# :nocov:
|
96
102
|
def clock_time
|
97
103
|
Time.now.to_f
|
98
104
|
end
|
105
|
+
# :nocov:
|
99
106
|
end
|
100
|
-
module_function :clock_time
|
101
107
|
|
102
108
|
def parse_query(qs, d = nil, &unescaper)
|
103
109
|
Rack::Utils.default_query_parser.parse_query(qs, d, &unescaper)
|
104
110
|
end
|
105
|
-
module_function :parse_query
|
106
111
|
|
107
112
|
def parse_nested_query(qs, d = nil)
|
108
113
|
Rack::Utils.default_query_parser.parse_nested_query(qs, d)
|
109
114
|
end
|
110
|
-
module_function :parse_nested_query
|
111
115
|
|
112
116
|
def build_query(params)
|
113
117
|
params.map { |k, v|
|
@@ -118,7 +122,6 @@ module Rack
|
|
118
122
|
end
|
119
123
|
}.join("&")
|
120
124
|
end
|
121
|
-
module_function :build_query
|
122
125
|
|
123
126
|
def build_nested_query(value, prefix = nil)
|
124
127
|
case value
|
@@ -129,7 +132,7 @@ module Rack
|
|
129
132
|
when Hash
|
130
133
|
value.map { |k, v|
|
131
134
|
build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
|
132
|
-
}.
|
135
|
+
}.delete_if(&:empty?).join('&')
|
133
136
|
when nil
|
134
137
|
prefix
|
135
138
|
else
|
@@ -137,20 +140,22 @@ module Rack
|
|
137
140
|
"#{prefix}=#{escape(value)}"
|
138
141
|
end
|
139
142
|
end
|
140
|
-
module_function :build_nested_query
|
141
143
|
|
142
144
|
def q_values(q_value_header)
|
143
145
|
q_value_header.to_s.split(/\s*,\s*/).map do |part|
|
144
146
|
value, parameters = part.split(/\s*;\s*/, 2)
|
145
147
|
quality = 1.0
|
146
|
-
if md = /\Aq=([\d.]+)/.match(parameters)
|
148
|
+
if parameters && (md = /\Aq=([\d.]+)/.match(parameters))
|
147
149
|
quality = md[1].to_f
|
148
150
|
end
|
149
151
|
[value, quality]
|
150
152
|
end
|
151
153
|
end
|
152
|
-
module_function :q_values
|
153
154
|
|
155
|
+
# Return best accept value to use, based on the algorithm
|
156
|
+
# in RFC 2616 Section 14. If there are multiple best
|
157
|
+
# matches (same specificity and quality), the value returned
|
158
|
+
# is arbitrary.
|
154
159
|
def best_q_match(q_value_header, available_mimes)
|
155
160
|
values = q_values(q_value_header)
|
156
161
|
|
@@ -163,7 +168,6 @@ module Rack
|
|
163
168
|
end.last
|
164
169
|
matches && matches.first
|
165
170
|
end
|
166
|
-
module_function :best_q_match
|
167
171
|
|
168
172
|
ESCAPE_HTML = {
|
169
173
|
"&" => "&",
|
@@ -180,51 +184,55 @@ module Rack
|
|
180
184
|
def escape_html(string)
|
181
185
|
string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] }
|
182
186
|
end
|
183
|
-
module_function :escape_html
|
184
187
|
|
185
188
|
def select_best_encoding(available_encodings, accept_encoding)
|
186
189
|
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
187
190
|
|
188
|
-
expanded_accept_encoding =
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
191
|
+
expanded_accept_encoding = []
|
192
|
+
|
193
|
+
accept_encoding.each do |m, q|
|
194
|
+
preference = available_encodings.index(m) || available_encodings.size
|
195
|
+
|
196
|
+
if m == "*"
|
197
|
+
(available_encodings - accept_encoding.map(&:first)).each do |m2|
|
198
|
+
expanded_accept_encoding << [m2, q, preference]
|
194
199
|
end
|
195
|
-
|
196
|
-
|
197
|
-
|
200
|
+
else
|
201
|
+
expanded_accept_encoding << [m, q, preference]
|
202
|
+
end
|
203
|
+
end
|
198
204
|
|
199
|
-
encoding_candidates = expanded_accept_encoding
|
205
|
+
encoding_candidates = expanded_accept_encoding
|
206
|
+
.sort_by { |_, q, p| [-q, p] }
|
207
|
+
.map!(&:first)
|
200
208
|
|
201
209
|
unless encoding_candidates.include?("identity")
|
202
210
|
encoding_candidates.push("identity")
|
203
211
|
end
|
204
212
|
|
205
|
-
expanded_accept_encoding.each
|
213
|
+
expanded_accept_encoding.each do |m, q|
|
206
214
|
encoding_candidates.delete(m) if q == 0.0
|
207
|
-
|
215
|
+
end
|
208
216
|
|
209
|
-
|
217
|
+
(encoding_candidates & available_encodings)[0]
|
210
218
|
end
|
211
|
-
module_function :select_best_encoding
|
212
219
|
|
213
220
|
def parse_cookies(env)
|
214
221
|
parse_cookies_header env[HTTP_COOKIE]
|
215
222
|
end
|
216
|
-
module_function :parse_cookies
|
217
223
|
|
218
224
|
def parse_cookies_header(header)
|
219
|
-
# According to RFC
|
220
|
-
#
|
221
|
-
#
|
222
|
-
#
|
223
|
-
|
224
|
-
|
225
|
-
|
225
|
+
# According to RFC 6265:
|
226
|
+
# The syntax for cookie headers only supports semicolons
|
227
|
+
# User Agent -> Server ==
|
228
|
+
# Cookie: SID=31d4d96e407aad42; lang=en-US
|
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
|
-
module_function :parse_cookies_header
|
228
236
|
|
229
237
|
def add_cookie_to_header(header, key, value)
|
230
238
|
case value
|
@@ -232,31 +240,7 @@ module Rack
|
|
232
240
|
domain = "; domain=#{value[:domain]}" if value[:domain]
|
233
241
|
path = "; path=#{value[:path]}" if value[:path]
|
234
242
|
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]
|
243
|
+
expires = "; expires=#{value[:expires].httpdate}" if value[:expires]
|
260
244
|
secure = "; secure" if value[:secure]
|
261
245
|
httponly = "; HttpOnly" if (value.key?(:httponly) ? value[:httponly] : value[:http_only])
|
262
246
|
same_site =
|
@@ -264,11 +248,11 @@ module Rack
|
|
264
248
|
when false, nil
|
265
249
|
nil
|
266
250
|
when :none, 'None', :None
|
267
|
-
'; SameSite=None'
|
251
|
+
'; SameSite=None'
|
268
252
|
when :lax, 'Lax', :Lax
|
269
|
-
'; SameSite=Lax'
|
253
|
+
'; SameSite=Lax'
|
270
254
|
when true, :strict, 'Strict', :Strict
|
271
|
-
'; SameSite=Strict'
|
255
|
+
'; SameSite=Strict'
|
272
256
|
else
|
273
257
|
raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}"
|
274
258
|
end
|
@@ -290,13 +274,11 @@ module Rack
|
|
290
274
|
raise ArgumentError, "Unrecognized cookie header value. Expected String, Array, or nil, got #{header.inspect}"
|
291
275
|
end
|
292
276
|
end
|
293
|
-
module_function :add_cookie_to_header
|
294
277
|
|
295
278
|
def set_cookie_header!(header, key, value)
|
296
279
|
header[SET_COOKIE] = add_cookie_to_header(header[SET_COOKIE], key, value)
|
297
280
|
nil
|
298
281
|
end
|
299
|
-
module_function :set_cookie_header!
|
300
282
|
|
301
283
|
def make_delete_cookie_header(header, key, value)
|
302
284
|
case header
|
@@ -308,25 +290,30 @@ module Rack
|
|
308
290
|
cookies = header
|
309
291
|
end
|
310
292
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
293
|
+
key = escape(key)
|
294
|
+
domain = value[:domain]
|
295
|
+
path = value[:path]
|
296
|
+
regexp = if domain
|
297
|
+
if path
|
298
|
+
/\A#{key}=.*(?:domain=#{domain}(?:;|$).*path=#{path}(?:;|$)|path=#{path}(?:;|$).*domain=#{domain}(?:;|$))/
|
299
|
+
else
|
300
|
+
/\A#{key}=.*domain=#{domain}(?:;|$)/
|
301
|
+
end
|
302
|
+
elsif path
|
303
|
+
/\A#{key}=.*path=#{path}(?:;|$)/
|
304
|
+
else
|
305
|
+
/\A#{key}=/
|
306
|
+
end
|
307
|
+
|
308
|
+
cookies.reject! { |cookie| regexp.match? cookie }
|
320
309
|
|
321
310
|
cookies.join("\n")
|
322
311
|
end
|
323
|
-
module_function :make_delete_cookie_header
|
324
312
|
|
325
313
|
def delete_cookie_header!(header, key, value = {})
|
326
314
|
header[SET_COOKIE] = add_remove_cookie_to_header(header[SET_COOKIE], key, value)
|
327
315
|
nil
|
328
316
|
end
|
329
|
-
module_function :delete_cookie_header!
|
330
317
|
|
331
318
|
# Adds a cookie that will *remove* a cookie from the client. Hence the
|
332
319
|
# strange method name.
|
@@ -334,17 +321,15 @@ module Rack
|
|
334
321
|
new_header = make_delete_cookie_header(header, key, value)
|
335
322
|
|
336
323
|
add_cookie_to_header(new_header, key,
|
337
|
-
{:
|
338
|
-
:
|
339
|
-
:
|
324
|
+
{ value: '', path: nil, domain: nil,
|
325
|
+
max_age: '0',
|
326
|
+
expires: Time.at(0) }.merge(value))
|
340
327
|
|
341
328
|
end
|
342
|
-
module_function :add_remove_cookie_to_header
|
343
329
|
|
344
330
|
def rfc2822(time)
|
345
331
|
time.rfc2822
|
346
332
|
end
|
347
|
-
module_function :rfc2822
|
348
333
|
|
349
334
|
# Modified version of stdlib time.rb Time#rfc2822 to use '%d-%b-%Y' instead
|
350
335
|
# of '% %b %Y'.
|
@@ -356,11 +341,10 @@ module Rack
|
|
356
341
|
# weekday and month.
|
357
342
|
#
|
358
343
|
def rfc2109(time)
|
359
|
-
wday =
|
360
|
-
mon =
|
344
|
+
wday = RFC2822_DAY_NAME[time.wday]
|
345
|
+
mon = RFC2822_MONTH_NAME[time.mon - 1]
|
361
346
|
time.strftime("#{wday}, %d-#{mon}-%Y %H:%M:%S GMT")
|
362
347
|
end
|
363
|
-
module_function :rfc2109
|
364
348
|
|
365
349
|
# Parses the "Range:" header, if present, into an array of Range objects.
|
366
350
|
# Returns nil if the header is missing or syntactically invalid.
|
@@ -369,7 +353,6 @@ module Rack
|
|
369
353
|
warn "`byte_ranges` is deprecated, please use `get_byte_ranges`" if $VERBOSE
|
370
354
|
get_byte_ranges env['HTTP_RANGE'], size
|
371
355
|
end
|
372
|
-
module_function :byte_ranges
|
373
356
|
|
374
357
|
def get_byte_ranges(http_range, size)
|
375
358
|
# See <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35>
|
@@ -392,14 +375,13 @@ module Rack
|
|
392
375
|
else
|
393
376
|
r1 = r1.to_i
|
394
377
|
return nil if r1 < r0 # backwards range is syntactically invalid
|
395
|
-
r1 = size-1 if r1 >= size
|
378
|
+
r1 = size - 1 if r1 >= size
|
396
379
|
end
|
397
380
|
end
|
398
381
|
ranges << (r0..r1) if r0 <= r1
|
399
382
|
end
|
400
383
|
ranges
|
401
384
|
end
|
402
|
-
module_function :get_byte_ranges
|
403
385
|
|
404
386
|
# Constant time string comparison.
|
405
387
|
#
|
@@ -413,10 +395,9 @@ module Rack
|
|
413
395
|
l = a.unpack("C*")
|
414
396
|
|
415
397
|
r, i = 0, -1
|
416
|
-
b.each_byte { |v| r |= v ^ l[i+=1] }
|
398
|
+
b.each_byte { |v| r |= v ^ l[i += 1] }
|
417
399
|
r == 0
|
418
400
|
end
|
419
|
-
module_function :secure_compare
|
420
401
|
|
421
402
|
# Context allows the use of a compatible middleware at different points
|
422
403
|
# in a request handling stack. A compatible middleware must define
|
@@ -439,19 +420,25 @@ module Rack
|
|
439
420
|
self.class.new(@for, app)
|
440
421
|
end
|
441
422
|
|
442
|
-
def context(env, app
|
423
|
+
def context(env, app = @app)
|
443
424
|
recontext(app).call(env)
|
444
425
|
end
|
445
426
|
end
|
446
427
|
|
447
428
|
# A case-insensitive Hash that preserves the original case of a
|
448
429
|
# header when set.
|
449
|
-
|
450
|
-
|
451
|
-
|
430
|
+
#
|
431
|
+
# @api private
|
432
|
+
class HeaderHash < Hash # :nodoc:
|
433
|
+
def self.[](headers)
|
434
|
+
if headers.is_a?(HeaderHash) && !headers.frozen?
|
435
|
+
return headers
|
436
|
+
else
|
437
|
+
return self.new(headers)
|
438
|
+
end
|
452
439
|
end
|
453
440
|
|
454
|
-
def initialize(hash={})
|
441
|
+
def initialize(hash = {})
|
455
442
|
super()
|
456
443
|
@names = {}
|
457
444
|
hash.each { |k, v| self[k] = v }
|
@@ -463,6 +450,12 @@ module Rack
|
|
463
450
|
@names = other.names.dup
|
464
451
|
end
|
465
452
|
|
453
|
+
# on clear, we need to clear @names hash
|
454
|
+
def clear
|
455
|
+
super
|
456
|
+
@names.clear
|
457
|
+
end
|
458
|
+
|
466
459
|
def each
|
467
460
|
super do |k, v|
|
468
461
|
yield(k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v)
|
@@ -471,7 +464,7 @@ module Rack
|
|
471
464
|
|
472
465
|
def to_hash
|
473
466
|
hash = {}
|
474
|
-
each { |k,v| hash[k] = v }
|
467
|
+
each { |k, v| hash[k] = v }
|
475
468
|
hash
|
476
469
|
end
|
477
470
|
|
@@ -524,13 +517,14 @@ module Rack
|
|
524
517
|
|
525
518
|
# Every standard HTTP code mapped to the appropriate message.
|
526
519
|
# Generated with:
|
527
|
-
#
|
528
|
-
#
|
529
|
-
#
|
520
|
+
# curl -s https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv | \
|
521
|
+
# ruby -ne 'm = /^(\d{3}),(?!Unassigned|\(Unused\))([^,]+)/.match($_) and \
|
522
|
+
# puts "#{m[1]} => \x27#{m[2].strip}\x27,"'
|
530
523
|
HTTP_STATUS_CODES = {
|
531
524
|
100 => 'Continue',
|
532
525
|
101 => 'Switching Protocols',
|
533
526
|
102 => 'Processing',
|
527
|
+
103 => 'Early Hints',
|
534
528
|
200 => 'OK',
|
535
529
|
201 => 'Created',
|
536
530
|
202 => 'Accepted',
|
@@ -547,6 +541,7 @@ module Rack
|
|
547
541
|
303 => 'See Other',
|
548
542
|
304 => 'Not Modified',
|
549
543
|
305 => 'Use Proxy',
|
544
|
+
306 => '(Unused)',
|
550
545
|
307 => 'Temporary Redirect',
|
551
546
|
308 => 'Permanent Redirect',
|
552
547
|
400 => 'Bad Request',
|
@@ -571,6 +566,7 @@ module Rack
|
|
571
566
|
422 => 'Unprocessable Entity',
|
572
567
|
423 => 'Locked',
|
573
568
|
424 => 'Failed Dependency',
|
569
|
+
425 => 'Too Early',
|
574
570
|
426 => 'Upgrade Required',
|
575
571
|
428 => 'Precondition Required',
|
576
572
|
429 => 'Too Many Requests',
|
@@ -585,12 +581,13 @@ module Rack
|
|
585
581
|
506 => 'Variant Also Negotiates',
|
586
582
|
507 => 'Insufficient Storage',
|
587
583
|
508 => 'Loop Detected',
|
584
|
+
509 => 'Bandwidth Limit Exceeded',
|
588
585
|
510 => 'Not Extended',
|
589
586
|
511 => 'Network Authentication Required'
|
590
587
|
}
|
591
588
|
|
592
589
|
# Responses with HTTP status codes that should not have an entity body
|
593
|
-
STATUS_WITH_NO_ENTITY_BODY =
|
590
|
+
STATUS_WITH_NO_ENTITY_BODY = Hash[((100..199).to_a << 204 << 304).product([true])]
|
594
591
|
|
595
592
|
SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message|
|
596
593
|
[message.downcase.gsub(/\s|-|'/, '_').to_sym, code]
|
@@ -598,12 +595,11 @@ module Rack
|
|
598
595
|
|
599
596
|
def status_code(status)
|
600
597
|
if status.is_a?(Symbol)
|
601
|
-
SYMBOL_TO_STATUS_CODE
|
598
|
+
SYMBOL_TO_STATUS_CODE.fetch(status) { raise ArgumentError, "Unrecognized status code #{status.inspect}" }
|
602
599
|
else
|
603
600
|
status.to_i
|
604
601
|
end
|
605
602
|
end
|
606
|
-
module_function :status_code
|
607
603
|
|
608
604
|
PATH_SEPS = Regexp.union(*[::File::SEPARATOR, ::File::ALT_SEPARATOR].compact)
|
609
605
|
|
@@ -617,18 +613,16 @@ module Rack
|
|
617
613
|
part == '..' ? clean.pop : clean << part
|
618
614
|
end
|
619
615
|
|
620
|
-
|
621
|
-
|
622
|
-
|
616
|
+
clean_path = clean.join(::File::SEPARATOR)
|
617
|
+
clean_path.prepend("/") if parts.empty? || parts.first.empty?
|
618
|
+
clean_path
|
623
619
|
end
|
624
|
-
module_function :clean_path_info
|
625
620
|
|
626
|
-
NULL_BYTE = "\0"
|
621
|
+
NULL_BYTE = "\0"
|
627
622
|
|
628
623
|
def valid_path?(path)
|
629
624
|
path.valid_encoding? && !path.include?(NULL_BYTE)
|
630
625
|
end
|
631
|
-
module_function :valid_path?
|
632
626
|
|
633
627
|
end
|
634
628
|
end
|
data/lib/rack/version.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2007-2019 Leah Neukirchen <http://leahneukirchen.org/infopage.html>
|
4
|
+
#
|
5
|
+
# Rack is freely distributable under the terms of an MIT-style license.
|
6
|
+
# See MIT-LICENSE or https://opensource.org/licenses/MIT.
|
7
|
+
|
8
|
+
# The Rack main module, serving as a namespace for all core Rack
|
9
|
+
# modules and classes.
|
10
|
+
#
|
11
|
+
# All modules meant for use in your application are <tt>autoload</tt>ed here,
|
12
|
+
# so it should be enough just to <tt>require 'rack'</tt> in your code.
|
13
|
+
|
14
|
+
module Rack
|
15
|
+
# The Rack protocol version number implemented.
|
16
|
+
VERSION = [1, 3]
|
17
|
+
|
18
|
+
# Return the Rack protocol version as a dotted string.
|
19
|
+
def self.version
|
20
|
+
VERSION.join(".")
|
21
|
+
end
|
22
|
+
|
23
|
+
RELEASE = "2.2.8"
|
24
|
+
|
25
|
+
# Return the Rack release as a dotted string.
|
26
|
+
def self.release
|
27
|
+
RELEASE
|
28
|
+
end
|
29
|
+
end
|