rack 2.2.10 → 3.0.0.beta1
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 +138 -105
- data/CONTRIBUTING.md +53 -47
- data/MIT-LICENSE +1 -1
- data/README.md +287 -0
- data/Rakefile +40 -7
- data/SPEC.rdoc +166 -125
- data/contrib/LICENSE.md +7 -0
- data/contrib/logo.webp +0 -0
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +3 -1
- data/lib/rack/auth/basic.rb +2 -1
- data/lib/rack/auth/digest/md5.rb +1 -131
- data/lib/rack/auth/digest/nonce.rb +1 -53
- data/lib/rack/auth/digest/params.rb +1 -54
- data/lib/rack/auth/digest/request.rb +1 -43
- data/lib/rack/auth/digest.rb +256 -0
- data/lib/rack/body_proxy.rb +3 -1
- data/lib/rack/builder.rb +60 -42
- data/lib/rack/cascade.rb +2 -0
- data/lib/rack/chunked.rb +16 -13
- data/lib/rack/common_logger.rb +23 -18
- data/lib/rack/conditional_get.rb +18 -15
- data/lib/rack/constants.rb +62 -0
- data/lib/rack/content_length.rb +12 -16
- data/lib/rack/content_type.rb +8 -5
- data/lib/rack/deflater.rb +40 -26
- data/lib/rack/directory.rb +9 -3
- data/lib/rack/etag.rb +14 -23
- data/lib/rack/events.rb +4 -0
- data/lib/rack/file.rb +2 -0
- data/lib/rack/files.rb +15 -17
- data/lib/rack/head.rb +9 -8
- data/lib/rack/headers.rb +154 -0
- data/lib/rack/lint.rb +740 -649
- data/lib/rack/lock.rb +2 -5
- data/lib/rack/logger.rb +2 -0
- data/lib/rack/media_type.rb +4 -9
- data/lib/rack/method_override.rb +5 -1
- data/lib/rack/mime.rb +8 -0
- data/lib/rack/mock.rb +1 -271
- data/lib/rack/mock_request.rb +166 -0
- data/lib/rack/mock_response.rb +124 -0
- data/lib/rack/multipart/generator.rb +7 -5
- data/lib/rack/multipart/parser.rb +123 -85
- data/lib/rack/multipart/uploaded_file.rb +4 -0
- data/lib/rack/multipart.rb +20 -40
- data/lib/rack/null_logger.rb +9 -0
- data/lib/rack/query_parser.rb +76 -44
- data/lib/rack/recursive.rb +2 -0
- data/lib/rack/reloader.rb +0 -2
- data/lib/rack/request.rb +189 -91
- data/lib/rack/response.rb +131 -61
- data/lib/rack/rewindable_input.rb +24 -5
- data/lib/rack/runtime.rb +7 -6
- data/lib/rack/sendfile.rb +30 -25
- data/lib/rack/show_exceptions.rb +15 -2
- data/lib/rack/show_status.rb +17 -7
- data/lib/rack/static.rb +8 -8
- data/lib/rack/tempfile_reaper.rb +15 -4
- data/lib/rack/urlmap.rb +4 -2
- data/lib/rack/utils.rb +212 -202
- data/lib/rack/version.rb +9 -4
- data/lib/rack.rb +5 -76
- data/rack.gemspec +6 -6
- metadata +19 -31
- data/README.rdoc +0 -320
- data/bin/rackup +0 -5
- data/contrib/rack.png +0 -0
- data/contrib/rack.svg +0 -150
- data/contrib/rack_logo.svg +0 -164
- data/lib/rack/core_ext/regexp.rb +0 -14
- data/lib/rack/handler/cgi.rb +0 -59
- data/lib/rack/handler/fastcgi.rb +0 -100
- data/lib/rack/handler/lsws.rb +0 -61
- data/lib/rack/handler/scgi.rb +0 -71
- data/lib/rack/handler/thin.rb +0 -36
- data/lib/rack/handler/webrick.rb +0 -129
- data/lib/rack/handler.rb +0 -104
- data/lib/rack/lobster.rb +0 -70
- data/lib/rack/server.rb +0 -466
- data/lib/rack/session/abstract/id.rb +0 -523
- data/lib/rack/session/cookie.rb +0 -203
- data/lib/rack/session/memcache.rb +0 -10
- data/lib/rack/session/pool.rb +0 -85
@@ -1,54 +1 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module Rack
|
4
|
-
module Auth
|
5
|
-
module Digest
|
6
|
-
class Params < Hash
|
7
|
-
|
8
|
-
def self.parse(str)
|
9
|
-
Params[*split_header_value(str).map do |param|
|
10
|
-
k, v = param.split('=', 2)
|
11
|
-
[k, dequote(v)]
|
12
|
-
end.flatten]
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.dequote(str) # From WEBrick::HTTPUtils
|
16
|
-
ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
|
17
|
-
ret.gsub!(/\\(.)/, "\\1")
|
18
|
-
ret
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.split_header_value(str)
|
22
|
-
str.scan(/\w+\=(?:"[^\"]+"|[^,]+)/n)
|
23
|
-
end
|
24
|
-
|
25
|
-
def initialize
|
26
|
-
super()
|
27
|
-
|
28
|
-
yield self if block_given?
|
29
|
-
end
|
30
|
-
|
31
|
-
def [](k)
|
32
|
-
super k.to_s
|
33
|
-
end
|
34
|
-
|
35
|
-
def []=(k, v)
|
36
|
-
super k.to_s, v.to_s
|
37
|
-
end
|
38
|
-
|
39
|
-
UNQUOTED = ['nc', 'stale']
|
40
|
-
|
41
|
-
def to_s
|
42
|
-
map do |k, v|
|
43
|
-
"#{k}=#{(UNQUOTED.include?(k) ? v.to_s : quote(v))}"
|
44
|
-
end.join(', ')
|
45
|
-
end
|
46
|
-
|
47
|
-
def quote(str) # From WEBrick::HTTPUtils
|
48
|
-
'"' + str.gsub(/[\\\"]/o, "\\\1") + '"'
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
1
|
+
require_relative '../digest'
|
@@ -1,43 +1 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require_relative '../abstract/request'
|
4
|
-
require_relative 'params'
|
5
|
-
require_relative 'nonce'
|
6
|
-
|
7
|
-
module Rack
|
8
|
-
module Auth
|
9
|
-
module Digest
|
10
|
-
class Request < Auth::AbstractRequest
|
11
|
-
def method
|
12
|
-
@env[RACK_METHODOVERRIDE_ORIGINAL_METHOD] || @env[REQUEST_METHOD]
|
13
|
-
end
|
14
|
-
|
15
|
-
def digest?
|
16
|
-
"digest" == scheme
|
17
|
-
end
|
18
|
-
|
19
|
-
def correct_uri?
|
20
|
-
request.fullpath == uri
|
21
|
-
end
|
22
|
-
|
23
|
-
def nonce
|
24
|
-
@nonce ||= Nonce.parse(params['nonce'])
|
25
|
-
end
|
26
|
-
|
27
|
-
def params
|
28
|
-
@params ||= Params.parse(parts.last)
|
29
|
-
end
|
30
|
-
|
31
|
-
def respond_to?(sym, *)
|
32
|
-
super or params.has_key? sym.to_s
|
33
|
-
end
|
34
|
-
|
35
|
-
def method_missing(sym, *args)
|
36
|
-
return super unless params.has_key?(key = sym.to_s)
|
37
|
-
return params[key] if args.size == 0
|
38
|
-
raise ArgumentError, "wrong number of arguments (#{args.size} for 0)"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
1
|
+
require_relative '../digest'
|
@@ -0,0 +1,256 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'abstract/handler'
|
4
|
+
require_relative 'abstract/request'
|
5
|
+
require 'digest/md5'
|
6
|
+
require 'base64'
|
7
|
+
|
8
|
+
module Rack
|
9
|
+
warn "Rack::Auth::Digest is deprecated and will be removed in Rack 3.1", uplevel: 1
|
10
|
+
|
11
|
+
module Auth
|
12
|
+
module Digest
|
13
|
+
# Rack::Auth::Digest::Nonce is the default nonce generator for the
|
14
|
+
# Rack::Auth::Digest::MD5 authentication handler.
|
15
|
+
#
|
16
|
+
# +private_key+ needs to set to a constant string.
|
17
|
+
#
|
18
|
+
# +time_limit+ can be optionally set to an integer (number of seconds),
|
19
|
+
# to limit the validity of the generated nonces.
|
20
|
+
|
21
|
+
class Nonce
|
22
|
+
|
23
|
+
class << self
|
24
|
+
attr_accessor :private_key, :time_limit
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.parse(string)
|
28
|
+
new(*Base64.decode64(string).split(' ', 2))
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(timestamp = Time.now, given_digest = nil)
|
32
|
+
@timestamp, @given_digest = timestamp.to_i, given_digest
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
Base64.encode64("#{@timestamp} #{digest}").strip
|
37
|
+
end
|
38
|
+
|
39
|
+
def digest
|
40
|
+
::Digest::MD5.hexdigest("#{@timestamp}:#{self.class.private_key}")
|
41
|
+
end
|
42
|
+
|
43
|
+
def valid?
|
44
|
+
digest == @given_digest
|
45
|
+
end
|
46
|
+
|
47
|
+
def stale?
|
48
|
+
!self.class.time_limit.nil? && (Time.now.to_i - @timestamp) > self.class.time_limit
|
49
|
+
end
|
50
|
+
|
51
|
+
def fresh?
|
52
|
+
!stale?
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
class Params < Hash
|
58
|
+
|
59
|
+
def self.parse(str)
|
60
|
+
Params[*split_header_value(str).map do |param|
|
61
|
+
k, v = param.split('=', 2)
|
62
|
+
[k, dequote(v)]
|
63
|
+
end.flatten]
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.dequote(str) # From WEBrick::HTTPUtils
|
67
|
+
ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
|
68
|
+
ret.gsub!(/\\(.)/, "\\1")
|
69
|
+
ret
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.split_header_value(str)
|
73
|
+
str.scan(/\w+\=(?:"[^\"]+"|[^,]+)/n)
|
74
|
+
end
|
75
|
+
|
76
|
+
def initialize
|
77
|
+
super()
|
78
|
+
|
79
|
+
yield self if block_given?
|
80
|
+
end
|
81
|
+
|
82
|
+
def [](k)
|
83
|
+
super k.to_s
|
84
|
+
end
|
85
|
+
|
86
|
+
def []=(k, v)
|
87
|
+
super k.to_s, v.to_s
|
88
|
+
end
|
89
|
+
|
90
|
+
UNQUOTED = ['nc', 'stale']
|
91
|
+
|
92
|
+
def to_s
|
93
|
+
map do |k, v|
|
94
|
+
"#{k}=#{(UNQUOTED.include?(k) ? v.to_s : quote(v))}"
|
95
|
+
end.join(', ')
|
96
|
+
end
|
97
|
+
|
98
|
+
def quote(str) # From WEBrick::HTTPUtils
|
99
|
+
'"' + str.gsub(/[\\\"]/o, "\\\1") + '"'
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
class Request < Auth::AbstractRequest
|
105
|
+
def method
|
106
|
+
@env[RACK_METHODOVERRIDE_ORIGINAL_METHOD] || @env[REQUEST_METHOD]
|
107
|
+
end
|
108
|
+
|
109
|
+
def digest?
|
110
|
+
"digest" == scheme
|
111
|
+
end
|
112
|
+
|
113
|
+
def correct_uri?
|
114
|
+
request.fullpath == uri
|
115
|
+
end
|
116
|
+
|
117
|
+
def nonce
|
118
|
+
@nonce ||= Nonce.parse(params['nonce'])
|
119
|
+
end
|
120
|
+
|
121
|
+
def params
|
122
|
+
@params ||= Params.parse(parts.last)
|
123
|
+
end
|
124
|
+
|
125
|
+
def respond_to?(sym, *)
|
126
|
+
super or params.has_key? sym.to_s
|
127
|
+
end
|
128
|
+
|
129
|
+
def method_missing(sym, *args)
|
130
|
+
return super unless params.has_key?(key = sym.to_s)
|
131
|
+
return params[key] if args.size == 0
|
132
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for 0)"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Rack::Auth::Digest::MD5 implements the MD5 algorithm version of
|
137
|
+
# HTTP Digest Authentication, as per RFC 2617.
|
138
|
+
#
|
139
|
+
# Initialize with the [Rack] application that you want protecting,
|
140
|
+
# and a block that looks up a plaintext password for a given username.
|
141
|
+
#
|
142
|
+
# +opaque+ needs to be set to a constant base64/hexadecimal string.
|
143
|
+
#
|
144
|
+
class MD5 < AbstractHandler
|
145
|
+
|
146
|
+
attr_accessor :opaque
|
147
|
+
|
148
|
+
attr_writer :passwords_hashed
|
149
|
+
|
150
|
+
def initialize(app, realm = nil, opaque = nil, &authenticator)
|
151
|
+
@passwords_hashed = nil
|
152
|
+
if opaque.nil? and realm.respond_to? :values_at
|
153
|
+
realm, opaque, @passwords_hashed = realm.values_at :realm, :opaque, :passwords_hashed
|
154
|
+
end
|
155
|
+
super(app, realm, &authenticator)
|
156
|
+
@opaque = opaque
|
157
|
+
end
|
158
|
+
|
159
|
+
def passwords_hashed?
|
160
|
+
!!@passwords_hashed
|
161
|
+
end
|
162
|
+
|
163
|
+
def call(env)
|
164
|
+
auth = Request.new(env)
|
165
|
+
|
166
|
+
unless auth.provided?
|
167
|
+
return unauthorized
|
168
|
+
end
|
169
|
+
|
170
|
+
if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth)
|
171
|
+
return bad_request
|
172
|
+
end
|
173
|
+
|
174
|
+
if valid?(auth)
|
175
|
+
if auth.nonce.stale?
|
176
|
+
return unauthorized(challenge(stale: true))
|
177
|
+
else
|
178
|
+
env['REMOTE_USER'] = auth.username
|
179
|
+
|
180
|
+
return @app.call(env)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
unauthorized
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
private
|
189
|
+
|
190
|
+
QOP = 'auth'
|
191
|
+
|
192
|
+
def params(hash = {})
|
193
|
+
Params.new do |params|
|
194
|
+
params['realm'] = realm
|
195
|
+
params['nonce'] = Nonce.new.to_s
|
196
|
+
params['opaque'] = H(opaque)
|
197
|
+
params['qop'] = QOP
|
198
|
+
|
199
|
+
hash.each { |k, v| params[k] = v }
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def challenge(hash = {})
|
204
|
+
"Digest #{params(hash)}"
|
205
|
+
end
|
206
|
+
|
207
|
+
def valid?(auth)
|
208
|
+
valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth)
|
209
|
+
end
|
210
|
+
|
211
|
+
def valid_qop?(auth)
|
212
|
+
QOP == auth.qop
|
213
|
+
end
|
214
|
+
|
215
|
+
def valid_opaque?(auth)
|
216
|
+
H(opaque) == auth.opaque
|
217
|
+
end
|
218
|
+
|
219
|
+
def valid_nonce?(auth)
|
220
|
+
auth.nonce.valid?
|
221
|
+
end
|
222
|
+
|
223
|
+
def valid_digest?(auth)
|
224
|
+
pw = @authenticator.call(auth.username)
|
225
|
+
pw && Rack::Utils.secure_compare(digest(auth, pw), auth.response)
|
226
|
+
end
|
227
|
+
|
228
|
+
def md5(data)
|
229
|
+
::Digest::MD5.hexdigest(data)
|
230
|
+
end
|
231
|
+
|
232
|
+
alias :H :md5
|
233
|
+
|
234
|
+
def KD(secret, data)
|
235
|
+
H "#{secret}:#{data}"
|
236
|
+
end
|
237
|
+
|
238
|
+
def A1(auth, password)
|
239
|
+
"#{auth.username}:#{auth.realm}:#{password}"
|
240
|
+
end
|
241
|
+
|
242
|
+
def A2(auth)
|
243
|
+
"#{auth.method}:#{auth.uri}"
|
244
|
+
end
|
245
|
+
|
246
|
+
def digest(auth, password)
|
247
|
+
password_hash = passwords_hashed? ? password : H(A1(auth, password))
|
248
|
+
|
249
|
+
KD password_hash, "#{auth.nonce}:#{auth.nc}:#{auth.cnonce}:#{QOP}:#{H A2(auth)}"
|
250
|
+
end
|
251
|
+
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
data/lib/rack/body_proxy.rb
CHANGED
@@ -24,7 +24,7 @@ module Rack
|
|
24
24
|
return if @closed
|
25
25
|
@closed = true
|
26
26
|
begin
|
27
|
-
@body.close if @body.respond_to?
|
27
|
+
@body.close if @body.respond_to?(:close)
|
28
28
|
ensure
|
29
29
|
@block.call
|
30
30
|
end
|
@@ -40,6 +40,8 @@ module Rack
|
|
40
40
|
def method_missing(method_name, *args, &block)
|
41
41
|
@body.__send__(method_name, *args, &block)
|
42
42
|
end
|
43
|
+
# :nocov:
|
43
44
|
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
45
|
+
# :nocov:
|
44
46
|
end
|
45
47
|
end
|
data/lib/rack/builder.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'urlmap'
|
4
|
+
|
3
5
|
module Rack
|
4
|
-
# Rack::Builder
|
5
|
-
# applications.
|
6
|
+
# Rack::Builder provides a domain-specific language (DSL) to construct Rack
|
7
|
+
# applications. It is primarily used to parse +config.ru+ files which
|
8
|
+
# instantiate several middleware and a final application which are hosted
|
9
|
+
# by a Rack-compatible web server.
|
6
10
|
#
|
7
11
|
# Example:
|
8
12
|
#
|
@@ -29,7 +33,6 @@ module Rack
|
|
29
33
|
#
|
30
34
|
# +use+ adds middleware to the stack, +run+ dispatches to an application.
|
31
35
|
# You can use +map+ to construct a Rack::URLMap in a convenient way.
|
32
|
-
|
33
36
|
class Builder
|
34
37
|
|
35
38
|
# https://stackoverflow.com/questions/2223882/whats-the-difference-between-utf-8-and-utf-8-without-bom
|
@@ -39,13 +42,11 @@ module Rack
|
|
39
42
|
#
|
40
43
|
# If the config file ends in +.ru+, it is treated as a
|
41
44
|
# rackup file and the contents will be treated as if
|
42
|
-
# specified inside a Rack::Builder block
|
43
|
-
# options.
|
45
|
+
# specified inside a Rack::Builder block.
|
44
46
|
#
|
45
47
|
# If the config file does not end in +.ru+, it is
|
46
48
|
# required and Rack will use the basename of the file
|
47
49
|
# to guess which constant will be the Rack application to run.
|
48
|
-
# The options given will be ignored in this case.
|
49
50
|
#
|
50
51
|
# Examples:
|
51
52
|
#
|
@@ -61,23 +62,18 @@ module Rack
|
|
61
62
|
# # requires ./my_app.rb, which should be in the
|
62
63
|
# # process's current directory. After requiring,
|
63
64
|
# # assumes MyApp constant contains Rack application
|
64
|
-
def self.parse_file(
|
65
|
-
if
|
66
|
-
return self.load_file(
|
65
|
+
def self.parse_file(path)
|
66
|
+
if path.end_with?('.ru')
|
67
|
+
return self.load_file(path)
|
67
68
|
else
|
68
|
-
require
|
69
|
-
|
70
|
-
return app, {}
|
69
|
+
require path
|
70
|
+
return Object.const_get(::File.basename(path, '.rb').split('_').map(&:capitalize).join(''))
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
74
|
# Load the given file as a rackup file, treating the
|
75
75
|
# contents as if specified inside a Rack::Builder block.
|
76
76
|
#
|
77
|
-
# Treats the first comment at the beginning of a line
|
78
|
-
# that starts with a backslash as options similar to
|
79
|
-
# options passed on a rackup command line.
|
80
|
-
#
|
81
77
|
# Ignores content in the file after +__END__+, so that
|
82
78
|
# use of +__END__+ will not result in a syntax error.
|
83
79
|
#
|
@@ -85,26 +81,20 @@ module Rack
|
|
85
81
|
#
|
86
82
|
# $ cat config.ru
|
87
83
|
#
|
88
|
-
# #\ -p 9393
|
89
|
-
#
|
90
84
|
# use Rack::ContentLength
|
91
85
|
# require './app.rb'
|
92
86
|
# run App
|
93
|
-
def self.load_file(path
|
94
|
-
|
95
|
-
|
96
|
-
cfgfile = ::File.read(path)
|
97
|
-
cfgfile.slice!(/\A#{UTF_8_BOM}/) if cfgfile.encoding == Encoding::UTF_8
|
87
|
+
def self.load_file(path)
|
88
|
+
config = ::File.read(path)
|
89
|
+
config.slice!(/\A#{UTF_8_BOM}/) if config.encoding == Encoding::UTF_8
|
98
90
|
|
99
|
-
if
|
100
|
-
|
101
|
-
options = opts.parse! $1.split(/\s+/)
|
91
|
+
if config[/^#\\(.*)/]
|
92
|
+
fail "Parsing options from the first comment line is no longer supported: #{path}"
|
102
93
|
end
|
103
94
|
|
104
|
-
|
105
|
-
app = new_from_string cfgfile, path
|
95
|
+
config.sub!(/^__END__\n.*\Z/m, '')
|
106
96
|
|
107
|
-
return
|
97
|
+
return new_from_string(config, path)
|
108
98
|
end
|
109
99
|
|
110
100
|
# Evaluate the given +builder_script+ string in the context of
|
@@ -114,14 +104,20 @@ module Rack
|
|
114
104
|
# We cannot use instance_eval(String) as that would resolve constants differently.
|
115
105
|
binding, builder = TOPLEVEL_BINDING.eval('Rack::Builder.new.instance_eval { [binding, self] }')
|
116
106
|
eval builder_script, binding, file
|
117
|
-
|
107
|
+
|
108
|
+
return builder.to_app
|
118
109
|
end
|
119
110
|
|
120
111
|
# Initialize a new Rack::Builder instance. +default_app+ specifies the
|
121
112
|
# default application if +run+ is not called later. If a block
|
122
|
-
# is given, it is
|
113
|
+
# is given, it is evaluated in the context of the instance.
|
123
114
|
def initialize(default_app = nil, &block)
|
124
|
-
@use
|
115
|
+
@use = []
|
116
|
+
@map = nil
|
117
|
+
@run = default_app
|
118
|
+
@warmup = nil
|
119
|
+
@freeze_app = false
|
120
|
+
|
125
121
|
instance_eval(&block) if block_given?
|
126
122
|
end
|
127
123
|
|
@@ -145,7 +141,7 @@ module Rack
|
|
145
141
|
# end
|
146
142
|
#
|
147
143
|
# use Middleware
|
148
|
-
# run lambda { |env| [200, { "
|
144
|
+
# run lambda { |env| [200, { "content-type" => "text/plain" }, ["OK"]] }
|
149
145
|
#
|
150
146
|
# All requests through to this application will first be processed by the middleware class.
|
151
147
|
# The +call+ method in this example sets an additional environment key which then can be
|
@@ -157,24 +153,46 @@ module Rack
|
|
157
153
|
end
|
158
154
|
@use << proc { |app| middleware.new(app, *args, &block) }
|
159
155
|
end
|
156
|
+
# :nocov:
|
160
157
|
ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
|
158
|
+
# :nocov:
|
161
159
|
|
162
|
-
# Takes
|
163
|
-
#
|
160
|
+
# Takes a block or argument that is an object that responds to #call and
|
161
|
+
# returns a Rack response.
|
162
|
+
#
|
163
|
+
# You can use a block:
|
164
|
+
#
|
165
|
+
# run do |env|
|
166
|
+
# [200, { "content-type" => "text/plain" }, ["Hello World!"]]
|
167
|
+
# end
|
164
168
|
#
|
165
|
-
#
|
169
|
+
# You can also provide a lambda:
|
166
170
|
#
|
167
|
-
#
|
171
|
+
# run lambda { |env| [200, { "content-type" => "text/plain" }, ["OK"]] }
|
172
|
+
#
|
173
|
+
# You can also provide a class instance:
|
168
174
|
#
|
169
175
|
# class Heartbeat
|
170
|
-
# def
|
171
|
-
# [200, { "
|
176
|
+
# def call(env)
|
177
|
+
# [200, { "content-type" => "text/plain" }, ["OK"]]
|
172
178
|
# end
|
173
179
|
# end
|
174
180
|
#
|
175
|
-
# run Heartbeat
|
176
|
-
|
177
|
-
|
181
|
+
# run Heartbeat.new
|
182
|
+
#
|
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
|
+
def run(app = nil, &block)
|
193
|
+
raise ArgumentError, "Both app and block given!" if app && block_given?
|
194
|
+
|
195
|
+
@run = app || block
|
178
196
|
end
|
179
197
|
|
180
198
|
# Takes a lambda or block that is used to warm-up the application. This block is called
|
data/lib/rack/cascade.rb
CHANGED
data/lib/rack/chunked.rb
CHANGED
@@ -1,22 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'constants'
|
4
|
+
require_relative 'utils'
|
5
|
+
|
3
6
|
module Rack
|
7
|
+
warn "Rack::Chunked is deprecated and will be removed in Rack 3.1", uplevel: 1
|
4
8
|
|
5
9
|
# Middleware that applies chunked transfer encoding to response bodies
|
6
|
-
# when the response does not include a
|
10
|
+
# when the response does not include a content-length header.
|
7
11
|
#
|
8
|
-
# This supports the
|
12
|
+
# This supports the trailer response header to allow the use of trailing
|
9
13
|
# headers in the chunked encoding. However, using this requires you manually
|
10
14
|
# specify a response body that supports a +trailers+ method. Example:
|
11
15
|
#
|
12
|
-
# [200, { '
|
16
|
+
# [200, { 'trailer' => 'expires'}, ["Hello", "World"]]
|
13
17
|
# # error raised
|
14
18
|
#
|
15
19
|
# body = ["Hello", "World"]
|
16
20
|
# def body.trailers
|
17
|
-
# { '
|
21
|
+
# { 'expires' => Time.now.to_s }
|
18
22
|
# end
|
19
|
-
# [200, { '
|
23
|
+
# [200, { 'trailer' => 'expires'}, body]
|
20
24
|
# # No exception raised
|
21
25
|
class Chunked
|
22
26
|
include Rack::Utils
|
@@ -92,11 +96,10 @@ module Rack
|
|
92
96
|
end
|
93
97
|
|
94
98
|
# If the rack app returns a response that should have a body,
|
95
|
-
# but does not have
|
96
|
-
# modify the response to use chunked
|
99
|
+
# but does not have content-length or transfer-encoding headers,
|
100
|
+
# modify the response to use chunked transfer-encoding.
|
97
101
|
def call(env)
|
98
|
-
status, headers, body = @app.call(env)
|
99
|
-
headers = HeaderHash[headers]
|
102
|
+
status, headers, body = response = @app.call(env)
|
100
103
|
|
101
104
|
if chunkable_version?(env[SERVER_PROTOCOL]) &&
|
102
105
|
!STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) &&
|
@@ -104,14 +107,14 @@ module Rack
|
|
104
107
|
!headers[TRANSFER_ENCODING]
|
105
108
|
|
106
109
|
headers[TRANSFER_ENCODING] = 'chunked'
|
107
|
-
if headers['
|
108
|
-
|
110
|
+
if headers['trailer']
|
111
|
+
response[2] = TrailerBody.new(body)
|
109
112
|
else
|
110
|
-
|
113
|
+
response[2] = Body.new(body)
|
111
114
|
end
|
112
115
|
end
|
113
116
|
|
114
|
-
|
117
|
+
response
|
115
118
|
end
|
116
119
|
end
|
117
120
|
end
|