rack 3.0.0 → 3.2.7
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +592 -1
- data/CONTRIBUTING.md +11 -9
- data/README.md +120 -29
- data/SPEC.rdoc +206 -288
- data/lib/rack/auth/abstract/request.rb +2 -0
- data/lib/rack/auth/basic.rb +1 -4
- data/lib/rack/bad_request.rb +8 -0
- data/lib/rack/body_proxy.rb +18 -2
- data/lib/rack/builder.rb +61 -40
- data/lib/rack/cascade.rb +0 -3
- data/lib/rack/common_logger.rb +3 -2
- data/lib/rack/conditional_get.rb +4 -3
- data/lib/rack/constants.rb +6 -1
- data/lib/rack/directory.rb +6 -3
- data/lib/rack/etag.rb +3 -0
- data/lib/rack/events.rb +21 -6
- data/lib/rack/files.rb +1 -1
- data/lib/rack/head.rb +2 -3
- data/lib/rack/headers.rb +98 -14
- data/lib/rack/lint.rb +491 -428
- data/lib/rack/media_type.rb +18 -9
- data/lib/rack/method_override.rb +2 -2
- data/lib/rack/mime.rb +6 -5
- data/lib/rack/mock_request.rb +10 -15
- data/lib/rack/mock_response.rb +50 -20
- data/lib/rack/multipart/parser.rb +279 -80
- data/lib/rack/multipart/uploaded_file.rb +42 -5
- data/lib/rack/multipart.rb +34 -1
- data/lib/rack/query_parser.rb +88 -80
- data/lib/rack/request.rb +98 -65
- data/lib/rack/response.rb +35 -20
- data/lib/rack/rewindable_input.rb +4 -1
- data/lib/rack/sendfile.rb +53 -23
- data/lib/rack/show_exceptions.rb +10 -4
- data/lib/rack/show_status.rb +0 -2
- data/lib/rack/static.rb +9 -4
- data/lib/rack/urlmap.rb +1 -1
- data/lib/rack/utils.rb +205 -133
- data/lib/rack/version.rb +3 -20
- data/lib/rack.rb +11 -17
- metadata +6 -15
- data/lib/rack/auth/digest/md5.rb +0 -1
- data/lib/rack/auth/digest/nonce.rb +0 -1
- data/lib/rack/auth/digest/params.rb +0 -1
- data/lib/rack/auth/digest/request.rb +0 -1
- data/lib/rack/auth/digest.rb +0 -256
- data/lib/rack/chunked.rb +0 -120
- data/lib/rack/file.rb +0 -9
- data/lib/rack/logger.rb +0 -22
data/lib/rack/builder.rb
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'urlmap'
|
|
4
4
|
|
|
5
|
+
module Rack; end
|
|
6
|
+
Rack::BUILDER_TOPLEVEL_BINDING = ->(builder){builder.instance_eval{binding}}
|
|
7
|
+
|
|
5
8
|
module Rack
|
|
6
9
|
# Rack::Builder provides a domain-specific language (DSL) to construct Rack
|
|
7
10
|
# applications. It is primarily used to parse +config.ru+ files which
|
|
@@ -10,26 +13,23 @@ module Rack
|
|
|
10
13
|
#
|
|
11
14
|
# Example:
|
|
12
15
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
# run Rack::Lobster.new
|
|
20
|
-
# end
|
|
21
|
-
# end
|
|
16
|
+
# app = Rack::Builder.new do
|
|
17
|
+
# use Rack::CommonLogger
|
|
18
|
+
# map "/ok" do
|
|
19
|
+
# run lambda { |env| [200, {'content-type' => 'text/plain'}, ['OK']] }
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
22
|
#
|
|
23
|
-
#
|
|
23
|
+
# run app
|
|
24
24
|
#
|
|
25
25
|
# Or
|
|
26
26
|
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
27
|
+
# app = Rack::Builder.app do
|
|
28
|
+
# use Rack::CommonLogger
|
|
29
|
+
# run lambda { |env| [200, {'content-type' => 'text/plain'}, ['OK']] }
|
|
30
|
+
# end
|
|
31
31
|
#
|
|
32
|
-
#
|
|
32
|
+
# run app
|
|
33
33
|
#
|
|
34
34
|
# +use+ adds middleware to the stack, +run+ dispatches to an application.
|
|
35
35
|
# You can use +map+ to construct a Rack::URLMap in a convenient way.
|
|
@@ -56,15 +56,15 @@ module Rack
|
|
|
56
56
|
# Rack::Builder.parse_file('app.rb')
|
|
57
57
|
# # requires app.rb, which can be anywhere in Ruby's
|
|
58
58
|
# # load path. After requiring, assumes App constant
|
|
59
|
-
# #
|
|
59
|
+
# # is a Rack application
|
|
60
60
|
#
|
|
61
61
|
# Rack::Builder.parse_file('./my_app.rb')
|
|
62
62
|
# # requires ./my_app.rb, which should be in the
|
|
63
63
|
# # process's current directory. After requiring,
|
|
64
|
-
# # assumes MyApp constant
|
|
65
|
-
def self.parse_file(path)
|
|
64
|
+
# # assumes MyApp constant is a Rack application
|
|
65
|
+
def self.parse_file(path, **options)
|
|
66
66
|
if path.end_with?('.ru')
|
|
67
|
-
return self.load_file(path)
|
|
67
|
+
return self.load_file(path, **options)
|
|
68
68
|
else
|
|
69
69
|
require path
|
|
70
70
|
return Object.const_get(::File.basename(path, '.rb').split('_').map(&:capitalize).join(''))
|
|
@@ -84,7 +84,7 @@ module Rack
|
|
|
84
84
|
# use Rack::ContentLength
|
|
85
85
|
# require './app.rb'
|
|
86
86
|
# run App
|
|
87
|
-
def self.load_file(path)
|
|
87
|
+
def self.load_file(path, **options)
|
|
88
88
|
config = ::File.read(path)
|
|
89
89
|
config.slice!(/\A#{UTF_8_BOM}/) if config.encoding == Encoding::UTF_8
|
|
90
90
|
|
|
@@ -94,16 +94,18 @@ module Rack
|
|
|
94
94
|
|
|
95
95
|
config.sub!(/^__END__\n.*\Z/m, '')
|
|
96
96
|
|
|
97
|
-
return new_from_string(config, path)
|
|
97
|
+
return new_from_string(config, path, **options)
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
# Evaluate the given +builder_script+ string in the context of
|
|
101
101
|
# a Rack::Builder block, returning a Rack application.
|
|
102
|
-
def self.new_from_string(builder_script,
|
|
102
|
+
def self.new_from_string(builder_script, path = "(rackup)", **options)
|
|
103
|
+
builder = self.new(**options)
|
|
104
|
+
|
|
103
105
|
# We want to build a variant of TOPLEVEL_BINDING with self as a Rack::Builder instance.
|
|
104
106
|
# We cannot use instance_eval(String) as that would resolve constants differently.
|
|
105
|
-
binding
|
|
106
|
-
eval
|
|
107
|
+
binding = BUILDER_TOPLEVEL_BINDING.call(builder)
|
|
108
|
+
eval(builder_script, binding, path)
|
|
107
109
|
|
|
108
110
|
return builder.to_app
|
|
109
111
|
end
|
|
@@ -111,16 +113,24 @@ module Rack
|
|
|
111
113
|
# Initialize a new Rack::Builder instance. +default_app+ specifies the
|
|
112
114
|
# default application if +run+ is not called later. If a block
|
|
113
115
|
# is given, it is evaluated in the context of the instance.
|
|
114
|
-
def initialize(default_app = nil, &block)
|
|
116
|
+
def initialize(default_app = nil, **options, &block)
|
|
115
117
|
@use = []
|
|
116
118
|
@map = nil
|
|
117
119
|
@run = default_app
|
|
118
120
|
@warmup = nil
|
|
119
121
|
@freeze_app = false
|
|
122
|
+
@options = options
|
|
120
123
|
|
|
121
124
|
instance_eval(&block) if block_given?
|
|
122
125
|
end
|
|
123
126
|
|
|
127
|
+
# Any options provided to the Rack::Builder instance at initialization.
|
|
128
|
+
# These options can be server-specific. Some general options are:
|
|
129
|
+
#
|
|
130
|
+
# * +:isolation+: One of +process+, +thread+ or +fiber+. The execution
|
|
131
|
+
# isolation model to use.
|
|
132
|
+
attr :options
|
|
133
|
+
|
|
124
134
|
# Create a new Rack::Builder instance and return the Rack application
|
|
125
135
|
# generated from it.
|
|
126
136
|
def self.app(default_app = nil, &block)
|
|
@@ -152,6 +162,8 @@ module Rack
|
|
|
152
162
|
@use << proc { |app| generate_map(app, mapping) }
|
|
153
163
|
end
|
|
154
164
|
@use << proc { |app| middleware.new(app, *args, &block) }
|
|
165
|
+
|
|
166
|
+
nil
|
|
155
167
|
end
|
|
156
168
|
# :nocov:
|
|
157
169
|
ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
|
|
@@ -180,19 +192,12 @@ module Rack
|
|
|
180
192
|
#
|
|
181
193
|
# run Heartbeat.new
|
|
182
194
|
#
|
|
183
|
-
# It could also be a module:
|
|
184
|
-
#
|
|
185
|
-
# module HelloWorld
|
|
186
|
-
# def call(env)
|
|
187
|
-
# [200, { "content-type" => "text/plain" }, ["Hello World"]]
|
|
188
|
-
# end
|
|
189
|
-
# end
|
|
190
|
-
#
|
|
191
|
-
# run HelloWorld
|
|
192
195
|
def run(app = nil, &block)
|
|
193
196
|
raise ArgumentError, "Both app and block given!" if app && block_given?
|
|
194
197
|
|
|
195
198
|
@run = app || block
|
|
199
|
+
|
|
200
|
+
nil
|
|
196
201
|
end
|
|
197
202
|
|
|
198
203
|
# Takes a lambda or block that is used to warm-up the application. This block is called
|
|
@@ -213,21 +218,35 @@ module Rack
|
|
|
213
218
|
# the Rack application specified by run inside the block. Other requests will be sent to the
|
|
214
219
|
# default application specified by run outside the block.
|
|
215
220
|
#
|
|
216
|
-
#
|
|
221
|
+
# class App
|
|
222
|
+
# def call(env)
|
|
223
|
+
# [200, {'content-type' => 'text/plain'}, ["Hello World"]]
|
|
224
|
+
# end
|
|
225
|
+
# end
|
|
226
|
+
#
|
|
227
|
+
# class Heartbeat
|
|
228
|
+
# def call(env)
|
|
229
|
+
# [200, { "content-type" => "text/plain" }, ["OK"]]
|
|
230
|
+
# end
|
|
231
|
+
# end
|
|
232
|
+
#
|
|
233
|
+
# app = Rack::Builder.app do
|
|
217
234
|
# map '/heartbeat' do
|
|
218
|
-
# run Heartbeat
|
|
235
|
+
# run Heartbeat.new
|
|
219
236
|
# end
|
|
220
|
-
# run App
|
|
237
|
+
# run App.new
|
|
221
238
|
# end
|
|
222
239
|
#
|
|
240
|
+
# run app
|
|
241
|
+
#
|
|
223
242
|
# The +use+ method can also be used inside the block to specify middleware to run under a specific path:
|
|
224
243
|
#
|
|
225
|
-
# Rack::Builder.app do
|
|
244
|
+
# app = Rack::Builder.app do
|
|
226
245
|
# map '/heartbeat' do
|
|
227
246
|
# use Middleware
|
|
228
|
-
# run Heartbeat
|
|
247
|
+
# run Heartbeat.new
|
|
229
248
|
# end
|
|
230
|
-
# run App
|
|
249
|
+
# run App.new
|
|
231
250
|
# end
|
|
232
251
|
#
|
|
233
252
|
# This example includes a piece of middleware which will run before +/heartbeat+ requests hit +Heartbeat+.
|
|
@@ -237,6 +256,8 @@ module Rack
|
|
|
237
256
|
def map(path, &block)
|
|
238
257
|
@map ||= {}
|
|
239
258
|
@map[path] = block
|
|
259
|
+
|
|
260
|
+
nil
|
|
240
261
|
end
|
|
241
262
|
|
|
242
263
|
# Freeze the app (set using run) and all middleware instances when building the application
|
data/lib/rack/cascade.rb
CHANGED
data/lib/rack/common_logger.rb
CHANGED
|
@@ -20,7 +20,7 @@ module Rack
|
|
|
20
20
|
# The actual format is slightly different than the above due to the
|
|
21
21
|
# separation of SCRIPT_NAME and PATH_INFO, and because the elapsed
|
|
22
22
|
# time in seconds is included at the end.
|
|
23
|
-
FORMAT = %{%s - %s [%s] "%s %s%s%s %s" %d %s %0.4f
|
|
23
|
+
FORMAT = %{%s - %s [%s] "%s %s%s%s %s" %d %s %0.4f }
|
|
24
24
|
|
|
25
25
|
# +logger+ can be any object that supports the +write+ or +<<+ methods,
|
|
26
26
|
# which includes the standard library Logger. These methods are called
|
|
@@ -66,7 +66,8 @@ module Rack
|
|
|
66
66
|
length,
|
|
67
67
|
Utils.clock_time - began_at)
|
|
68
68
|
|
|
69
|
-
msg.gsub!(/[^[:print:]
|
|
69
|
+
msg.gsub!(/[^[:print:]]/) { |c| sprintf("\\x%x", c.ord) }
|
|
70
|
+
msg[-1] = "\n"
|
|
70
71
|
|
|
71
72
|
logger = @logger || request.get_header(RACK_ERRORS)
|
|
72
73
|
# Standard library logger doesn't support write but it supports << which actually
|
data/lib/rack/conditional_get.rb
CHANGED
|
@@ -34,9 +34,10 @@ module Rack
|
|
|
34
34
|
response[0] = 304
|
|
35
35
|
headers.delete(CONTENT_TYPE)
|
|
36
36
|
headers.delete(CONTENT_LENGTH)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
|
|
38
|
+
# We are done with the body:
|
|
39
|
+
body.close if body.respond_to?(:close)
|
|
40
|
+
response[2] = []
|
|
40
41
|
end
|
|
41
42
|
response
|
|
42
43
|
else
|
data/lib/rack/constants.rb
CHANGED
|
@@ -14,7 +14,7 @@ module Rack
|
|
|
14
14
|
SERVER_NAME = 'SERVER_NAME'
|
|
15
15
|
SERVER_PORT = 'SERVER_PORT'
|
|
16
16
|
HTTP_COOKIE = 'HTTP_COOKIE'
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
# Response Header Keys
|
|
19
19
|
CACHE_CONTROL = 'cache-control'
|
|
20
20
|
CONTENT_LENGTH = 'content-length'
|
|
@@ -32,6 +32,7 @@ module Rack
|
|
|
32
32
|
DELETE = 'DELETE'
|
|
33
33
|
HEAD = 'HEAD'
|
|
34
34
|
OPTIONS = 'OPTIONS'
|
|
35
|
+
CONNECT = 'CONNECT'
|
|
35
36
|
LINK = 'LINK'
|
|
36
37
|
UNLINK = 'UNLINK'
|
|
37
38
|
TRACE = 'TRACE'
|
|
@@ -39,6 +40,7 @@ module Rack
|
|
|
39
40
|
# Rack environment variables
|
|
40
41
|
RACK_VERSION = 'rack.version'
|
|
41
42
|
RACK_TEMPFILES = 'rack.tempfiles'
|
|
43
|
+
RACK_EARLY_HINTS = 'rack.early_hints'
|
|
42
44
|
RACK_ERRORS = 'rack.errors'
|
|
43
45
|
RACK_LOGGER = 'rack.logger'
|
|
44
46
|
RACK_INPUT = 'rack.input'
|
|
@@ -52,9 +54,12 @@ module Rack
|
|
|
52
54
|
RACK_MULTIPART_BUFFER_SIZE = 'rack.multipart.buffer_size'
|
|
53
55
|
RACK_MULTIPART_TEMPFILE_FACTORY = 'rack.multipart.tempfile_factory'
|
|
54
56
|
RACK_RESPONSE_FINISHED = 'rack.response_finished'
|
|
57
|
+
RACK_PROTOCOL = 'rack.protocol'
|
|
55
58
|
RACK_REQUEST_FORM_INPUT = 'rack.request.form_input'
|
|
56
59
|
RACK_REQUEST_FORM_HASH = 'rack.request.form_hash'
|
|
60
|
+
RACK_REQUEST_FORM_PAIRS = 'rack.request.form_pairs'
|
|
57
61
|
RACK_REQUEST_FORM_VARS = 'rack.request.form_vars'
|
|
62
|
+
RACK_REQUEST_FORM_ERROR = 'rack.request.form_error'
|
|
58
63
|
RACK_REQUEST_COOKIE_HASH = 'rack.request.cookie_hash'
|
|
59
64
|
RACK_REQUEST_COOKIE_STRING = 'rack.request.cookie_string'
|
|
60
65
|
RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash'
|
data/lib/rack/directory.rb
CHANGED
|
@@ -17,7 +17,7 @@ module Rack
|
|
|
17
17
|
# If +app+ is not specified, a Rack::Files of the same +root+ will be used.
|
|
18
18
|
|
|
19
19
|
class Directory
|
|
20
|
-
DIR_FILE = "<tr><td class='name'><a href='
|
|
20
|
+
DIR_FILE = "<tr><td class='name'><a href='./%s'>%s</a></td><td class='size'>%s</td><td class='type'>%s</td><td class='mtime'>%s</td></tr>\n"
|
|
21
21
|
DIR_PAGE_HEADER = <<-PAGE
|
|
22
22
|
<html><head>
|
|
23
23
|
<title>%s</title>
|
|
@@ -51,7 +51,7 @@ table { width:100%%; }
|
|
|
51
51
|
class DirectoryBody < Struct.new(:root, :path, :files)
|
|
52
52
|
# Yield strings for each part of the directory entry
|
|
53
53
|
def each
|
|
54
|
-
show_path = Utils.escape_html(path.sub(
|
|
54
|
+
show_path = Utils.escape_html(path.sub(/\A#{Regexp.escape(root)}/, ''))
|
|
55
55
|
yield(DIR_PAGE_HEADER % [ show_path, show_path ])
|
|
56
56
|
|
|
57
57
|
unless path.chomp('/') == root
|
|
@@ -82,6 +82,7 @@ table { width:100%%; }
|
|
|
82
82
|
# Set the root directory and application for serving files.
|
|
83
83
|
def initialize(root, app = nil)
|
|
84
84
|
@root = ::File.expand_path(root)
|
|
85
|
+
@root_with_separator = @root.end_with?(::File::SEPARATOR) ? @root : "#{@root}#{::File::SEPARATOR}"
|
|
85
86
|
@app = app || Files.new(@root)
|
|
86
87
|
@head = Head.new(method(:get))
|
|
87
88
|
end
|
|
@@ -118,7 +119,9 @@ table { width:100%%; }
|
|
|
118
119
|
# Rack response to use for requests with paths outside the root, or nil if path is inside the root.
|
|
119
120
|
def check_forbidden(path_info)
|
|
120
121
|
return unless path_info.include? ".."
|
|
121
|
-
|
|
122
|
+
|
|
123
|
+
expanded_path = ::File.expand_path(::File.join(@root, path_info))
|
|
124
|
+
return if expanded_path == @root || expanded_path.start_with?(@root_with_separator)
|
|
122
125
|
|
|
123
126
|
body = "Forbidden\n"
|
|
124
127
|
[403, { CONTENT_TYPE => "text/plain",
|
data/lib/rack/etag.rb
CHANGED
data/lib/rack/events.rb
CHANGED
|
@@ -29,12 +29,13 @@ module Rack
|
|
|
29
29
|
#
|
|
30
30
|
# * on_send(request, response)
|
|
31
31
|
#
|
|
32
|
-
# The webserver has started iterating over the response body
|
|
33
|
-
# has started sending data over the
|
|
34
|
-
# a request object and the response
|
|
35
|
-
# constructed from the rack triple that the
|
|
36
|
-
# SHOULD NOT be made to the response object
|
|
37
|
-
# started sending data. Any mutations will
|
|
32
|
+
# The webserver has started iterating over the response body, or has called
|
|
33
|
+
# the streaming body, and presumably has started sending data over the
|
|
34
|
+
# wire. This method is always called with a request object and the response
|
|
35
|
+
# object. The response object is constructed from the rack triple that the
|
|
36
|
+
# application returned. Changes SHOULD NOT be made to the response object
|
|
37
|
+
# as the webserver has already started sending data. Any mutations will
|
|
38
|
+
# likely result in an exception.
|
|
38
39
|
#
|
|
39
40
|
# * on_finish(request, response)
|
|
40
41
|
#
|
|
@@ -90,6 +91,20 @@ module Rack
|
|
|
90
91
|
@handlers.reverse_each { |handler| handler.on_send request, response }
|
|
91
92
|
super
|
|
92
93
|
end
|
|
94
|
+
|
|
95
|
+
def call(stream)
|
|
96
|
+
@handlers.reverse_each { |handler| handler.on_send request, response }
|
|
97
|
+
super
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def respond_to?(method_name, include_all = false)
|
|
101
|
+
case method_name
|
|
102
|
+
when :each, :call
|
|
103
|
+
@body.respond_to?(method_name, include_all)
|
|
104
|
+
else
|
|
105
|
+
super
|
|
106
|
+
end
|
|
107
|
+
end
|
|
93
108
|
end
|
|
94
109
|
|
|
95
110
|
class BufferedResponse < Rack::Response::Raw # :nodoc:
|
data/lib/rack/files.rb
CHANGED
data/lib/rack/head.rb
CHANGED
|
@@ -15,9 +15,8 @@ module Rack
|
|
|
15
15
|
_, _, body = response = @app.call(env)
|
|
16
16
|
|
|
17
17
|
if env[REQUEST_METHOD] == HEAD
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
end
|
|
18
|
+
body.close if body.respond_to?(:close)
|
|
19
|
+
response[2] = []
|
|
21
20
|
end
|
|
22
21
|
|
|
23
22
|
response
|
data/lib/rack/headers.rb
CHANGED
|
@@ -1,9 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Rack
|
|
2
4
|
# Rack::Headers is a Hash subclass that downcases all keys. It's designed
|
|
3
5
|
# to be used by rack applications that don't implement the Rack 3 SPEC
|
|
4
6
|
# (by using non-lowercase response header keys), automatically handling
|
|
5
7
|
# the downcasing of keys.
|
|
6
8
|
class Headers < Hash
|
|
9
|
+
KNOWN_HEADERS = {}
|
|
10
|
+
%w(
|
|
11
|
+
Accept-CH
|
|
12
|
+
Accept-Patch
|
|
13
|
+
Accept-Ranges
|
|
14
|
+
Access-Control-Allow-Credentials
|
|
15
|
+
Access-Control-Allow-Headers
|
|
16
|
+
Access-Control-Allow-Methods
|
|
17
|
+
Access-Control-Allow-Origin
|
|
18
|
+
Access-Control-Expose-Headers
|
|
19
|
+
Access-Control-Max-Age
|
|
20
|
+
Age
|
|
21
|
+
Allow
|
|
22
|
+
Alt-Svc
|
|
23
|
+
Cache-Control
|
|
24
|
+
Connection
|
|
25
|
+
Content-Disposition
|
|
26
|
+
Content-Encoding
|
|
27
|
+
Content-Language
|
|
28
|
+
Content-Length
|
|
29
|
+
Content-Location
|
|
30
|
+
Content-MD5
|
|
31
|
+
Content-Range
|
|
32
|
+
Content-Security-Policy
|
|
33
|
+
Content-Security-Policy-Report-Only
|
|
34
|
+
Content-Type
|
|
35
|
+
Date
|
|
36
|
+
Delta-Base
|
|
37
|
+
ETag
|
|
38
|
+
Expect-CT
|
|
39
|
+
Expires
|
|
40
|
+
Feature-Policy
|
|
41
|
+
IM
|
|
42
|
+
Last-Modified
|
|
43
|
+
Link
|
|
44
|
+
Location
|
|
45
|
+
NEL
|
|
46
|
+
P3P
|
|
47
|
+
Permissions-Policy
|
|
48
|
+
Pragma
|
|
49
|
+
Preference-Applied
|
|
50
|
+
Proxy-Authenticate
|
|
51
|
+
Public-Key-Pins
|
|
52
|
+
Referrer-Policy
|
|
53
|
+
Refresh
|
|
54
|
+
Report-To
|
|
55
|
+
Retry-After
|
|
56
|
+
Server
|
|
57
|
+
Set-Cookie
|
|
58
|
+
Status
|
|
59
|
+
Strict-Transport-Security
|
|
60
|
+
Timing-Allow-Origin
|
|
61
|
+
Tk
|
|
62
|
+
Trailer
|
|
63
|
+
Transfer-Encoding
|
|
64
|
+
Upgrade
|
|
65
|
+
Vary
|
|
66
|
+
Via
|
|
67
|
+
WWW-Authenticate
|
|
68
|
+
Warning
|
|
69
|
+
X-Cascade
|
|
70
|
+
X-Content-Duration
|
|
71
|
+
X-Content-Security-Policy
|
|
72
|
+
X-Content-Type-Options
|
|
73
|
+
X-Correlation-ID
|
|
74
|
+
X-Correlation-Id
|
|
75
|
+
X-Download-Options
|
|
76
|
+
X-Frame-Options
|
|
77
|
+
X-Permitted-Cross-Domain-Policies
|
|
78
|
+
X-Powered-By
|
|
79
|
+
X-Redirect-By
|
|
80
|
+
X-Request-ID
|
|
81
|
+
X-Request-Id
|
|
82
|
+
X-Runtime
|
|
83
|
+
X-UA-Compatible
|
|
84
|
+
X-WebKit-CS
|
|
85
|
+
X-XSS-Protection
|
|
86
|
+
).each do |str|
|
|
87
|
+
downcased = str.downcase.freeze
|
|
88
|
+
KNOWN_HEADERS[str] = KNOWN_HEADERS[downcased] = downcased
|
|
89
|
+
end
|
|
90
|
+
|
|
7
91
|
def self.[](*items)
|
|
8
92
|
if items.length % 2 != 0
|
|
9
93
|
if items.length == 1 && items.first.is_a?(Hash)
|
|
@@ -28,10 +112,10 @@ module Rack
|
|
|
28
112
|
end
|
|
29
113
|
|
|
30
114
|
def []=(key, value)
|
|
31
|
-
super(key.downcase.freeze, value)
|
|
115
|
+
super(KNOWN_HEADERS[key] || key.downcase.freeze, value)
|
|
32
116
|
end
|
|
33
117
|
alias store []=
|
|
34
|
-
|
|
118
|
+
|
|
35
119
|
def assoc(key)
|
|
36
120
|
super(downcase_key(key))
|
|
37
121
|
end
|
|
@@ -43,7 +127,7 @@ module Rack
|
|
|
43
127
|
def delete(key)
|
|
44
128
|
super(downcase_key(key))
|
|
45
129
|
end
|
|
46
|
-
|
|
130
|
+
|
|
47
131
|
def dig(key, *a)
|
|
48
132
|
super(downcase_key(key), *a)
|
|
49
133
|
end
|
|
@@ -52,7 +136,7 @@ module Rack
|
|
|
52
136
|
key = downcase_key(key)
|
|
53
137
|
super
|
|
54
138
|
end
|
|
55
|
-
|
|
139
|
+
|
|
56
140
|
def fetch_values(*a)
|
|
57
141
|
super(*a.map!{|key| downcase_key(key)})
|
|
58
142
|
end
|
|
@@ -63,34 +147,34 @@ module Rack
|
|
|
63
147
|
alias include? has_key?
|
|
64
148
|
alias key? has_key?
|
|
65
149
|
alias member? has_key?
|
|
66
|
-
|
|
150
|
+
|
|
67
151
|
def invert
|
|
68
152
|
hash = self.class.new
|
|
69
153
|
each{|key, value| hash[value] = key}
|
|
70
154
|
hash
|
|
71
155
|
end
|
|
72
|
-
|
|
156
|
+
|
|
73
157
|
def merge(hash, &block)
|
|
74
158
|
dup.merge!(hash, &block)
|
|
75
159
|
end
|
|
76
|
-
|
|
160
|
+
|
|
77
161
|
def reject(&block)
|
|
78
162
|
hash = dup
|
|
79
163
|
hash.reject!(&block)
|
|
80
164
|
hash
|
|
81
165
|
end
|
|
82
|
-
|
|
166
|
+
|
|
83
167
|
def replace(hash)
|
|
84
168
|
clear
|
|
85
169
|
update(hash)
|
|
86
170
|
end
|
|
87
|
-
|
|
171
|
+
|
|
88
172
|
def select(&block)
|
|
89
173
|
hash = dup
|
|
90
174
|
hash.select!(&block)
|
|
91
175
|
hash
|
|
92
176
|
end
|
|
93
|
-
|
|
177
|
+
|
|
94
178
|
def to_proc
|
|
95
179
|
lambda{|x| self[x]}
|
|
96
180
|
end
|
|
@@ -100,10 +184,10 @@ module Rack
|
|
|
100
184
|
end
|
|
101
185
|
|
|
102
186
|
def update(hash, &block)
|
|
103
|
-
hash.each do |key, value|
|
|
187
|
+
hash.each do |key, value|
|
|
104
188
|
self[key] = if block_given? && include?(key)
|
|
105
189
|
block.call(key, self[key], value)
|
|
106
|
-
else
|
|
190
|
+
else
|
|
107
191
|
value
|
|
108
192
|
end
|
|
109
193
|
end
|
|
@@ -114,7 +198,7 @@ module Rack
|
|
|
114
198
|
def values_at(*keys)
|
|
115
199
|
keys.map{|key| self[key]}
|
|
116
200
|
end
|
|
117
|
-
|
|
201
|
+
|
|
118
202
|
# :nocov:
|
|
119
203
|
if RUBY_VERSION >= '2.5'
|
|
120
204
|
# :nocov:
|
|
@@ -148,7 +232,7 @@ module Rack
|
|
|
148
232
|
private
|
|
149
233
|
|
|
150
234
|
def downcase_key(key)
|
|
151
|
-
key.is_a?(String) ? key.downcase : key
|
|
235
|
+
key.is_a?(String) ? KNOWN_HEADERS[key] || key.downcase : key
|
|
152
236
|
end
|
|
153
237
|
end
|
|
154
238
|
end
|