rack 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +125 -2
- data/CONTRIBUTING.md +11 -9
- data/README.md +55 -20
- data/SPEC.rdoc +38 -13
- 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 +55 -40
- data/lib/rack/cascade.rb +0 -3
- data/lib/rack/constants.rb +5 -2
- data/lib/rack/content_length.rb +0 -1
- data/lib/rack/headers.rb +98 -14
- data/lib/rack/lint.rb +126 -38
- data/lib/rack/logger.rb +2 -1
- data/lib/rack/media_type.rb +9 -4
- data/lib/rack/method_override.rb +2 -2
- data/lib/rack/mime.rb +6 -5
- data/lib/rack/mock_request.rb +19 -14
- data/lib/rack/mock_response.rb +12 -14
- data/lib/rack/multipart/parser.rb +147 -66
- data/lib/rack/multipart.rb +34 -1
- data/lib/rack/query_parser.rb +19 -72
- data/lib/rack/request.rb +65 -38
- data/lib/rack/response.rb +27 -22
- data/lib/rack/sendfile.rb +1 -1
- data/lib/rack/show_exceptions.rb +6 -2
- data/lib/rack/urlmap.rb +1 -1
- data/lib/rack/utils.rb +91 -114
- data/lib/rack/version.rb +1 -14
- data/lib/rack.rb +11 -16
- metadata +4 -10
- 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/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)
|
|
@@ -180,15 +190,6 @@ module Rack
|
|
|
180
190
|
#
|
|
181
191
|
# run Heartbeat.new
|
|
182
192
|
#
|
|
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
193
|
def run(app = nil, &block)
|
|
193
194
|
raise ArgumentError, "Both app and block given!" if app && block_given?
|
|
194
195
|
|
|
@@ -213,21 +214,35 @@ module Rack
|
|
|
213
214
|
# the Rack application specified by run inside the block. Other requests will be sent to the
|
|
214
215
|
# default application specified by run outside the block.
|
|
215
216
|
#
|
|
216
|
-
#
|
|
217
|
+
# class App
|
|
218
|
+
# def call(env)
|
|
219
|
+
# [200, {'content-type' => 'text/plain'}, ["Hello World"]]
|
|
220
|
+
# end
|
|
221
|
+
# end
|
|
222
|
+
#
|
|
223
|
+
# class Heartbeat
|
|
224
|
+
# def call(env)
|
|
225
|
+
# [200, { "content-type" => "text/plain" }, ["OK"]]
|
|
226
|
+
# end
|
|
227
|
+
# end
|
|
228
|
+
#
|
|
229
|
+
# app = Rack::Builder.app do
|
|
217
230
|
# map '/heartbeat' do
|
|
218
|
-
# run Heartbeat
|
|
231
|
+
# run Heartbeat.new
|
|
219
232
|
# end
|
|
220
|
-
# run App
|
|
233
|
+
# run App.new
|
|
221
234
|
# end
|
|
222
235
|
#
|
|
236
|
+
# run app
|
|
237
|
+
#
|
|
223
238
|
# The +use+ method can also be used inside the block to specify middleware to run under a specific path:
|
|
224
239
|
#
|
|
225
|
-
# Rack::Builder.app do
|
|
240
|
+
# app = Rack::Builder.app do
|
|
226
241
|
# map '/heartbeat' do
|
|
227
242
|
# use Middleware
|
|
228
|
-
# run Heartbeat
|
|
243
|
+
# run Heartbeat.new
|
|
229
244
|
# end
|
|
230
|
-
# run App
|
|
245
|
+
# run App.new
|
|
231
246
|
# end
|
|
232
247
|
#
|
|
233
248
|
# This example includes a piece of middleware which will run before +/heartbeat+ requests hit +Heartbeat+.
|
data/lib/rack/cascade.rb
CHANGED
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'
|
|
@@ -22,7 +22,6 @@ module Rack
|
|
|
22
22
|
ETAG = 'etag'
|
|
23
23
|
EXPIRES = 'expires'
|
|
24
24
|
SET_COOKIE = 'set-cookie'
|
|
25
|
-
TRANSFER_ENCODING = 'transfer-encoding'
|
|
26
25
|
|
|
27
26
|
# HTTP method verbs
|
|
28
27
|
GET = 'GET'
|
|
@@ -32,6 +31,7 @@ module Rack
|
|
|
32
31
|
DELETE = 'DELETE'
|
|
33
32
|
HEAD = 'HEAD'
|
|
34
33
|
OPTIONS = 'OPTIONS'
|
|
34
|
+
CONNECT = 'CONNECT'
|
|
35
35
|
LINK = 'LINK'
|
|
36
36
|
UNLINK = 'UNLINK'
|
|
37
37
|
TRACE = 'TRACE'
|
|
@@ -39,6 +39,7 @@ module Rack
|
|
|
39
39
|
# Rack environment variables
|
|
40
40
|
RACK_VERSION = 'rack.version'
|
|
41
41
|
RACK_TEMPFILES = 'rack.tempfiles'
|
|
42
|
+
RACK_EARLY_HINTS = 'rack.early_hints'
|
|
42
43
|
RACK_ERRORS = 'rack.errors'
|
|
43
44
|
RACK_LOGGER = 'rack.logger'
|
|
44
45
|
RACK_INPUT = 'rack.input'
|
|
@@ -54,7 +55,9 @@ module Rack
|
|
|
54
55
|
RACK_RESPONSE_FINISHED = 'rack.response_finished'
|
|
55
56
|
RACK_REQUEST_FORM_INPUT = 'rack.request.form_input'
|
|
56
57
|
RACK_REQUEST_FORM_HASH = 'rack.request.form_hash'
|
|
58
|
+
RACK_REQUEST_FORM_PAIRS = 'rack.request.form_pairs'
|
|
57
59
|
RACK_REQUEST_FORM_VARS = 'rack.request.form_vars'
|
|
60
|
+
RACK_REQUEST_FORM_ERROR = 'rack.request.form_error'
|
|
58
61
|
RACK_REQUEST_COOKIE_HASH = 'rack.request.cookie_hash'
|
|
59
62
|
RACK_REQUEST_COOKIE_STRING = 'rack.request.cookie_string'
|
|
60
63
|
RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash'
|
data/lib/rack/content_length.rb
CHANGED
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
|