rack 2.2.7 → 3.1.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 +291 -78
- data/CONTRIBUTING.md +63 -55
- data/MIT-LICENSE +1 -1
- data/README.md +328 -0
- data/SPEC.rdoc +213 -136
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +3 -1
- data/lib/rack/auth/basic.rb +1 -4
- data/lib/rack/bad_request.rb +8 -0
- data/lib/rack/body_proxy.rb +21 -3
- data/lib/rack/builder.rb +102 -69
- data/lib/rack/cascade.rb +2 -3
- data/lib/rack/common_logger.rb +23 -18
- data/lib/rack/conditional_get.rb +18 -15
- data/lib/rack/constants.rb +67 -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/files.rb +15 -17
- data/lib/rack/head.rb +9 -8
- data/lib/rack/headers.rb +238 -0
- data/lib/rack/lint.rb +864 -681
- data/lib/rack/lock.rb +2 -5
- data/lib/rack/logger.rb +3 -0
- data/lib/rack/media_type.rb +9 -4
- data/lib/rack/method_override.rb +5 -1
- data/lib/rack/mime.rb +14 -5
- data/lib/rack/mock.rb +1 -271
- data/lib/rack/mock_request.rb +171 -0
- data/lib/rack/mock_response.rb +124 -0
- data/lib/rack/multipart/generator.rb +7 -5
- data/lib/rack/multipart/parser.rb +218 -91
- data/lib/rack/multipart/uploaded_file.rb +4 -0
- data/lib/rack/multipart.rb +53 -40
- data/lib/rack/null_logger.rb +9 -0
- data/lib/rack/query_parser.rb +81 -102
- data/lib/rack/recursive.rb +2 -0
- data/lib/rack/reloader.rb +0 -2
- data/lib/rack/request.rb +248 -123
- data/lib/rack/response.rb +146 -66
- 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 +21 -4
- 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 +3 -1
- data/lib/rack/utils.rb +237 -235
- data/lib/rack/version.rb +1 -9
- data/lib/rack.rb +13 -89
- metadata +15 -41
- data/README.rdoc +0 -320
- data/Rakefile +0 -130
- 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/contrib/rdoc.css +0 -412
- data/example/lobster.ru +0 -6
- data/example/protectedlobster.rb +0 -16
- data/example/protectedlobster.ru +0 -10
- data/lib/rack/auth/digest/md5.rb +0 -131
- data/lib/rack/auth/digest/nonce.rb +0 -54
- data/lib/rack/auth/digest/params.rb +0 -54
- data/lib/rack/auth/digest/request.rb +0 -43
- data/lib/rack/chunked.rb +0 -117
- data/lib/rack/core_ext/regexp.rb +0 -14
- data/lib/rack/file.rb +0 -7
- 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
- data/rack.gemspec +0 -46
data/lib/rack/builder.rb
CHANGED
@@ -1,35 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'urlmap'
|
4
|
+
|
5
|
+
module Rack; end
|
6
|
+
Rack::BUILDER_TOPLEVEL_BINDING = ->(builder){builder.instance_eval{binding}}
|
7
|
+
|
3
8
|
module Rack
|
4
|
-
# Rack::Builder
|
5
|
-
# applications.
|
9
|
+
# Rack::Builder provides a domain-specific language (DSL) to construct Rack
|
10
|
+
# applications. It is primarily used to parse +config.ru+ files which
|
11
|
+
# instantiate several middleware and a final application which are hosted
|
12
|
+
# by a Rack-compatible web server.
|
6
13
|
#
|
7
14
|
# Example:
|
8
15
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# run Rack::Lobster.new
|
16
|
-
# end
|
17
|
-
# 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
|
18
22
|
#
|
19
|
-
#
|
23
|
+
# run app
|
20
24
|
#
|
21
25
|
# Or
|
22
26
|
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
+
# app = Rack::Builder.app do
|
28
|
+
# use Rack::CommonLogger
|
29
|
+
# run lambda { |env| [200, {'content-type' => 'text/plain'}, ['OK']] }
|
30
|
+
# end
|
27
31
|
#
|
28
|
-
#
|
32
|
+
# run app
|
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
|
#
|
@@ -55,29 +56,24 @@ module Rack
|
|
55
56
|
# Rack::Builder.parse_file('app.rb')
|
56
57
|
# # requires app.rb, which can be anywhere in Ruby's
|
57
58
|
# # load path. After requiring, assumes App constant
|
58
|
-
# #
|
59
|
+
# # is a Rack application
|
59
60
|
#
|
60
61
|
# Rack::Builder.parse_file('./my_app.rb')
|
61
62
|
# # requires ./my_app.rb, which should be in the
|
62
63
|
# # process's current directory. After requiring,
|
63
|
-
# # assumes MyApp constant
|
64
|
-
def self.parse_file(
|
65
|
-
if
|
66
|
-
return self.load_file(
|
64
|
+
# # assumes MyApp constant is a Rack application
|
65
|
+
def self.parse_file(path, **options)
|
66
|
+
if path.end_with?('.ru')
|
67
|
+
return self.load_file(path, **options)
|
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,46 +81,56 @@ 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, **options)
|
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, **options)
|
108
98
|
end
|
109
99
|
|
110
100
|
# Evaluate the given +builder_script+ string in the context of
|
111
101
|
# a Rack::Builder block, returning a Rack application.
|
112
|
-
def self.new_from_string(builder_script,
|
102
|
+
def self.new_from_string(builder_script, path = "(rackup)", **options)
|
103
|
+
builder = self.new(**options)
|
104
|
+
|
113
105
|
# We want to build a variant of TOPLEVEL_BINDING with self as a Rack::Builder instance.
|
114
106
|
# We cannot use instance_eval(String) as that would resolve constants differently.
|
115
|
-
binding
|
116
|
-
eval
|
117
|
-
|
107
|
+
binding = BUILDER_TOPLEVEL_BINDING.call(builder)
|
108
|
+
eval(builder_script, binding, path)
|
109
|
+
|
110
|
+
return builder.to_app
|
118
111
|
end
|
119
112
|
|
120
113
|
# Initialize a new Rack::Builder instance. +default_app+ specifies the
|
121
114
|
# default application if +run+ is not called later. If a block
|
122
|
-
# is given, it is
|
123
|
-
def initialize(default_app = nil, &block)
|
124
|
-
@use
|
115
|
+
# is given, it is evaluated in the context of the instance.
|
116
|
+
def initialize(default_app = nil, **options, &block)
|
117
|
+
@use = []
|
118
|
+
@map = nil
|
119
|
+
@run = default_app
|
120
|
+
@warmup = nil
|
121
|
+
@freeze_app = false
|
122
|
+
@options = options
|
123
|
+
|
125
124
|
instance_eval(&block) if block_given?
|
126
125
|
end
|
127
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
|
+
|
128
134
|
# Create a new Rack::Builder instance and return the Rack application
|
129
135
|
# generated from it.
|
130
136
|
def self.app(default_app = nil, &block)
|
@@ -145,7 +151,7 @@ module Rack
|
|
145
151
|
# end
|
146
152
|
#
|
147
153
|
# use Middleware
|
148
|
-
# run lambda { |env| [200, { "
|
154
|
+
# run lambda { |env| [200, { "content-type" => "text/plain" }, ["OK"]] }
|
149
155
|
#
|
150
156
|
# All requests through to this application will first be processed by the middleware class.
|
151
157
|
# The +call+ method in this example sets an additional environment key which then can be
|
@@ -157,24 +163,37 @@ module Rack
|
|
157
163
|
end
|
158
164
|
@use << proc { |app| middleware.new(app, *args, &block) }
|
159
165
|
end
|
166
|
+
# :nocov:
|
160
167
|
ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
|
168
|
+
# :nocov:
|
161
169
|
|
162
|
-
# Takes
|
163
|
-
#
|
170
|
+
# Takes a block or argument that is an object that responds to #call and
|
171
|
+
# returns a Rack response.
|
172
|
+
#
|
173
|
+
# You can use a block:
|
174
|
+
#
|
175
|
+
# run do |env|
|
176
|
+
# [200, { "content-type" => "text/plain" }, ["Hello World!"]]
|
177
|
+
# end
|
164
178
|
#
|
165
|
-
#
|
179
|
+
# You can also provide a lambda:
|
166
180
|
#
|
167
|
-
#
|
181
|
+
# run lambda { |env| [200, { "content-type" => "text/plain" }, ["OK"]] }
|
182
|
+
#
|
183
|
+
# You can also provide a class instance:
|
168
184
|
#
|
169
185
|
# class Heartbeat
|
170
|
-
# def
|
171
|
-
# [200, { "
|
186
|
+
# def call(env)
|
187
|
+
# [200, { "content-type" => "text/plain" }, ["OK"]]
|
172
188
|
# end
|
173
189
|
# end
|
174
190
|
#
|
175
|
-
# run Heartbeat
|
176
|
-
|
177
|
-
|
191
|
+
# run Heartbeat.new
|
192
|
+
#
|
193
|
+
def run(app = nil, &block)
|
194
|
+
raise ArgumentError, "Both app and block given!" if app && block_given?
|
195
|
+
|
196
|
+
@run = app || block
|
178
197
|
end
|
179
198
|
|
180
199
|
# Takes a lambda or block that is used to warm-up the application. This block is called
|
@@ -195,21 +214,35 @@ module Rack
|
|
195
214
|
# the Rack application specified by run inside the block. Other requests will be sent to the
|
196
215
|
# default application specified by run outside the block.
|
197
216
|
#
|
198
|
-
#
|
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
|
199
230
|
# map '/heartbeat' do
|
200
|
-
# run Heartbeat
|
231
|
+
# run Heartbeat.new
|
201
232
|
# end
|
202
|
-
# run App
|
233
|
+
# run App.new
|
203
234
|
# end
|
204
235
|
#
|
236
|
+
# run app
|
237
|
+
#
|
205
238
|
# The +use+ method can also be used inside the block to specify middleware to run under a specific path:
|
206
239
|
#
|
207
|
-
# Rack::Builder.app do
|
240
|
+
# app = Rack::Builder.app do
|
208
241
|
# map '/heartbeat' do
|
209
242
|
# use Middleware
|
210
|
-
# run Heartbeat
|
243
|
+
# run Heartbeat.new
|
211
244
|
# end
|
212
|
-
# run App
|
245
|
+
# run App.new
|
213
246
|
# end
|
214
247
|
#
|
215
248
|
# This example includes a piece of middleware which will run before +/heartbeat+ requests hit +Heartbeat+.
|
data/lib/rack/cascade.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'constants'
|
4
|
+
|
3
5
|
module Rack
|
4
6
|
# Rack::Cascade tries a request on several apps, and returns the
|
5
7
|
# first response that is not 404 or 405 (or in a list of configured
|
@@ -7,9 +9,6 @@ module Rack
|
|
7
9
|
# status codes, return the last response.
|
8
10
|
|
9
11
|
class Cascade
|
10
|
-
# deprecated, no longer used
|
11
|
-
NotFound = [404, { CONTENT_TYPE => "text/plain" }, []]
|
12
|
-
|
13
12
|
# An array of applications to try in order.
|
14
13
|
attr_reader :apps
|
15
14
|
|
data/lib/rack/common_logger.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'constants'
|
4
|
+
require_relative 'utils'
|
5
|
+
require_relative 'body_proxy'
|
6
|
+
require_relative 'request'
|
7
|
+
|
3
8
|
module Rack
|
4
9
|
# Rack::CommonLogger forwards every request to the given +app+, and
|
5
10
|
# logs a line in the
|
@@ -35,35 +40,35 @@ module Rack
|
|
35
40
|
# cause the request not to be logged.
|
36
41
|
def call(env)
|
37
42
|
began_at = Utils.clock_time
|
38
|
-
status, headers, body = @app.call(env)
|
39
|
-
|
40
|
-
|
41
|
-
|
43
|
+
status, headers, body = response = @app.call(env)
|
44
|
+
|
45
|
+
response[2] = BodyProxy.new(body) { log(env, status, headers, began_at) }
|
46
|
+
response
|
42
47
|
end
|
43
48
|
|
44
49
|
private
|
45
50
|
|
46
51
|
# Log the request to the configured logger.
|
47
|
-
def log(env, status,
|
48
|
-
|
52
|
+
def log(env, status, response_headers, began_at)
|
53
|
+
request = Rack::Request.new(env)
|
54
|
+
length = extract_content_length(response_headers)
|
49
55
|
|
50
|
-
msg = FORMAT
|
51
|
-
|
52
|
-
|
56
|
+
msg = sprintf(FORMAT,
|
57
|
+
request.ip || "-",
|
58
|
+
request.get_header("REMOTE_USER") || "-",
|
53
59
|
Time.now.strftime("%d/%b/%Y:%H:%M:%S %z"),
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
60
|
+
request.request_method,
|
61
|
+
request.script_name,
|
62
|
+
request.path_info,
|
63
|
+
request.query_string.empty? ? "" : "?#{request.query_string}",
|
64
|
+
request.get_header(SERVER_PROTOCOL),
|
59
65
|
status.to_s[0..3],
|
60
66
|
length,
|
61
|
-
Utils.clock_time - began_at
|
62
|
-
|
63
|
-
msg.gsub!(/[^[:print:]\n]/) { |c| "\\x#{c.ord}" }
|
67
|
+
Utils.clock_time - began_at)
|
64
68
|
|
65
|
-
|
69
|
+
msg.gsub!(/[^[:print:]\n]/) { |c| sprintf("\\x%x", c.ord) }
|
66
70
|
|
71
|
+
logger = @logger || request.get_header(RACK_ERRORS)
|
67
72
|
# Standard library logger doesn't support write but it supports << which actually
|
68
73
|
# calls to write on the log device without formatting
|
69
74
|
if logger.respond_to?(:write)
|
data/lib/rack/conditional_get.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'constants'
|
4
|
+
require_relative 'utils'
|
5
|
+
require_relative 'body_proxy'
|
6
|
+
|
3
7
|
module Rack
|
4
8
|
|
5
|
-
# Middleware that enables conditional GET using
|
6
|
-
#
|
7
|
-
#
|
9
|
+
# Middleware that enables conditional GET using if-none-match and
|
10
|
+
# if-modified-since. The application should set either or both of the
|
11
|
+
# last-modified or etag response headers according to RFC 2616. When
|
8
12
|
# either of the conditions is met, the response body is set to be zero
|
9
13
|
# length and the response status is set to 304 Not Modified.
|
10
14
|
#
|
@@ -24,18 +28,17 @@ module Rack
|
|
24
28
|
def call(env)
|
25
29
|
case env[REQUEST_METHOD]
|
26
30
|
when "GET", "HEAD"
|
27
|
-
status, headers, body = @app.call(env)
|
28
|
-
|
31
|
+
status, headers, body = response = @app.call(env)
|
32
|
+
|
29
33
|
if status == 200 && fresh?(env, headers)
|
30
|
-
|
34
|
+
response[0] = 304
|
31
35
|
headers.delete(CONTENT_TYPE)
|
32
36
|
headers.delete(CONTENT_LENGTH)
|
33
|
-
|
34
|
-
|
35
|
-
original_body.close if original_body.respond_to?(:close)
|
37
|
+
response[2] = Rack::BodyProxy.new([]) do
|
38
|
+
body.close if body.respond_to?(:close)
|
36
39
|
end
|
37
40
|
end
|
38
|
-
|
41
|
+
response
|
39
42
|
else
|
40
43
|
@app.call(env)
|
41
44
|
end
|
@@ -46,7 +49,7 @@ module Rack
|
|
46
49
|
# Return whether the response has not been modified since the
|
47
50
|
# last request.
|
48
51
|
def fresh?(env, headers)
|
49
|
-
#
|
52
|
+
# if-none-match has priority over if-modified-since per RFC 7232
|
50
53
|
if none_match = env['HTTP_IF_NONE_MATCH']
|
51
54
|
etag_matches?(none_match, headers)
|
52
55
|
elsif (modified_since = env['HTTP_IF_MODIFIED_SINCE']) && (modified_since = to_rfc2822(modified_since))
|
@@ -54,16 +57,16 @@ module Rack
|
|
54
57
|
end
|
55
58
|
end
|
56
59
|
|
57
|
-
# Whether the
|
60
|
+
# Whether the etag response header matches the if-none-match request header.
|
58
61
|
# If so, the request has not been modified.
|
59
62
|
def etag_matches?(none_match, headers)
|
60
|
-
headers[
|
63
|
+
headers[ETAG] == none_match
|
61
64
|
end
|
62
65
|
|
63
|
-
# Whether the
|
66
|
+
# Whether the last-modified response header matches the if-modified-since
|
64
67
|
# request header. If so, the request has not been modified.
|
65
68
|
def modified_since?(modified_since, headers)
|
66
|
-
last_modified = to_rfc2822(headers['
|
69
|
+
last_modified = to_rfc2822(headers['last-modified']) and
|
67
70
|
modified_since >= last_modified
|
68
71
|
end
|
69
72
|
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
# Request env keys
|
5
|
+
HTTP_HOST = 'HTTP_HOST'
|
6
|
+
HTTP_PORT = 'HTTP_PORT'
|
7
|
+
HTTPS = 'HTTPS'
|
8
|
+
PATH_INFO = 'PATH_INFO'
|
9
|
+
REQUEST_METHOD = 'REQUEST_METHOD'
|
10
|
+
REQUEST_PATH = 'REQUEST_PATH'
|
11
|
+
SCRIPT_NAME = 'SCRIPT_NAME'
|
12
|
+
QUERY_STRING = 'QUERY_STRING'
|
13
|
+
SERVER_PROTOCOL = 'SERVER_PROTOCOL'
|
14
|
+
SERVER_NAME = 'SERVER_NAME'
|
15
|
+
SERVER_PORT = 'SERVER_PORT'
|
16
|
+
HTTP_COOKIE = 'HTTP_COOKIE'
|
17
|
+
|
18
|
+
# Response Header Keys
|
19
|
+
CACHE_CONTROL = 'cache-control'
|
20
|
+
CONTENT_LENGTH = 'content-length'
|
21
|
+
CONTENT_TYPE = 'content-type'
|
22
|
+
ETAG = 'etag'
|
23
|
+
EXPIRES = 'expires'
|
24
|
+
SET_COOKIE = 'set-cookie'
|
25
|
+
TRANSFER_ENCODING = 'transfer-encoding'
|
26
|
+
|
27
|
+
# HTTP method verbs
|
28
|
+
GET = 'GET'
|
29
|
+
POST = 'POST'
|
30
|
+
PUT = 'PUT'
|
31
|
+
PATCH = 'PATCH'
|
32
|
+
DELETE = 'DELETE'
|
33
|
+
HEAD = 'HEAD'
|
34
|
+
OPTIONS = 'OPTIONS'
|
35
|
+
CONNECT = 'CONNECT'
|
36
|
+
LINK = 'LINK'
|
37
|
+
UNLINK = 'UNLINK'
|
38
|
+
TRACE = 'TRACE'
|
39
|
+
|
40
|
+
# Rack environment variables
|
41
|
+
RACK_VERSION = 'rack.version'
|
42
|
+
RACK_TEMPFILES = 'rack.tempfiles'
|
43
|
+
RACK_EARLY_HINTS = 'rack.early_hints'
|
44
|
+
RACK_ERRORS = 'rack.errors'
|
45
|
+
RACK_LOGGER = 'rack.logger'
|
46
|
+
RACK_INPUT = 'rack.input'
|
47
|
+
RACK_SESSION = 'rack.session'
|
48
|
+
RACK_SESSION_OPTIONS = 'rack.session.options'
|
49
|
+
RACK_SHOWSTATUS_DETAIL = 'rack.showstatus.detail'
|
50
|
+
RACK_URL_SCHEME = 'rack.url_scheme'
|
51
|
+
RACK_HIJACK = 'rack.hijack'
|
52
|
+
RACK_IS_HIJACK = 'rack.hijack?'
|
53
|
+
RACK_RECURSIVE_INCLUDE = 'rack.recursive.include'
|
54
|
+
RACK_MULTIPART_BUFFER_SIZE = 'rack.multipart.buffer_size'
|
55
|
+
RACK_MULTIPART_TEMPFILE_FACTORY = 'rack.multipart.tempfile_factory'
|
56
|
+
RACK_RESPONSE_FINISHED = 'rack.response_finished'
|
57
|
+
RACK_REQUEST_FORM_INPUT = 'rack.request.form_input'
|
58
|
+
RACK_REQUEST_FORM_HASH = 'rack.request.form_hash'
|
59
|
+
RACK_REQUEST_FORM_PAIRS = 'rack.request.form_pairs'
|
60
|
+
RACK_REQUEST_FORM_VARS = 'rack.request.form_vars'
|
61
|
+
RACK_REQUEST_FORM_ERROR = 'rack.request.form_error'
|
62
|
+
RACK_REQUEST_COOKIE_HASH = 'rack.request.cookie_hash'
|
63
|
+
RACK_REQUEST_COOKIE_STRING = 'rack.request.cookie_string'
|
64
|
+
RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash'
|
65
|
+
RACK_REQUEST_QUERY_STRING = 'rack.request.query_string'
|
66
|
+
RACK_METHODOVERRIDE_ORIGINAL_METHOD = 'rack.methodoverride.original_method'
|
67
|
+
end
|
data/lib/rack/content_length.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'constants'
|
4
|
+
require_relative 'utils'
|
5
|
+
|
3
6
|
module Rack
|
4
7
|
|
5
|
-
# Sets the
|
6
|
-
# a
|
7
|
-
# does not fix responses that have an invalid
|
8
|
+
# Sets the content-length header on responses that do not specify
|
9
|
+
# a content-length or transfer-encoding header. Note that this
|
10
|
+
# does not fix responses that have an invalid content-length
|
8
11
|
# header specified.
|
9
12
|
class ContentLength
|
10
13
|
include Rack::Utils
|
@@ -14,25 +17,18 @@ module Rack
|
|
14
17
|
end
|
15
18
|
|
16
19
|
def call(env)
|
17
|
-
status, headers, body = @app.call(env)
|
18
|
-
headers = HeaderHash[headers]
|
20
|
+
status, headers, body = response = @app.call(env)
|
19
21
|
|
20
22
|
if !STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) &&
|
21
23
|
!headers[CONTENT_LENGTH] &&
|
22
|
-
!headers[TRANSFER_ENCODING]
|
23
|
-
|
24
|
-
obody = body
|
25
|
-
body, length = [], 0
|
26
|
-
obody.each { |part| body << part; length += part.bytesize }
|
27
|
-
|
28
|
-
body = BodyProxy.new(body) do
|
29
|
-
obody.close if obody.respond_to?(:close)
|
30
|
-
end
|
24
|
+
!headers[TRANSFER_ENCODING] &&
|
25
|
+
body.respond_to?(:to_ary)
|
31
26
|
|
32
|
-
|
27
|
+
response[2] = body = body.to_ary
|
28
|
+
headers[CONTENT_LENGTH] = body.sum(&:bytesize).to_s
|
33
29
|
end
|
34
30
|
|
35
|
-
|
31
|
+
response
|
36
32
|
end
|
37
33
|
end
|
38
34
|
end
|
data/lib/rack/content_type.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'constants'
|
4
|
+
require_relative 'utils'
|
5
|
+
|
3
6
|
module Rack
|
4
7
|
|
5
|
-
# Sets the
|
8
|
+
# Sets the content-type header on responses which don't have one.
|
6
9
|
#
|
7
10
|
# Builder Usage:
|
8
11
|
# use Rack::ContentType, "text/plain"
|
@@ -13,18 +16,18 @@ module Rack
|
|
13
16
|
include Rack::Utils
|
14
17
|
|
15
18
|
def initialize(app, content_type = "text/html")
|
16
|
-
@app
|
19
|
+
@app = app
|
20
|
+
@content_type = content_type
|
17
21
|
end
|
18
22
|
|
19
23
|
def call(env)
|
20
|
-
status, headers,
|
21
|
-
headers = Utils::HeaderHash[headers]
|
24
|
+
status, headers, _ = response = @app.call(env)
|
22
25
|
|
23
26
|
unless STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i)
|
24
27
|
headers[CONTENT_TYPE] ||= @content_type
|
25
28
|
end
|
26
29
|
|
27
|
-
|
30
|
+
response
|
28
31
|
end
|
29
32
|
end
|
30
33
|
end
|