rack 1.6.13 → 2.0.1
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 +5 -5
- data/COPYING +1 -1
- data/HISTORY.md +138 -8
- data/README.rdoc +17 -25
- data/Rakefile +6 -14
- data/SPEC +8 -9
- data/contrib/rack_logo.svg +164 -111
- data/example/protectedlobster.rb +1 -1
- data/example/protectedlobster.ru +1 -1
- data/lib/rack/auth/abstract/request.rb +5 -1
- data/lib/rack/auth/digest/params.rb +2 -3
- data/lib/rack/auth/digest/request.rb +1 -1
- data/lib/rack/body_proxy.rb +14 -9
- data/lib/rack/builder.rb +3 -3
- data/lib/rack/chunked.rb +5 -5
- data/lib/rack/{commonlogger.rb → common_logger.rb} +3 -3
- data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
- data/lib/rack/content_length.rb +2 -2
- data/lib/rack/deflater.rb +4 -4
- data/lib/rack/directory.rb +66 -54
- data/lib/rack/etag.rb +4 -3
- data/lib/rack/events.rb +154 -0
- data/lib/rack/file.rb +63 -39
- data/lib/rack/handler/cgi.rb +15 -16
- data/lib/rack/handler/fastcgi.rb +13 -14
- data/lib/rack/handler/lsws.rb +11 -11
- data/lib/rack/handler/scgi.rb +15 -15
- data/lib/rack/handler/thin.rb +3 -0
- data/lib/rack/handler/webrick.rb +22 -24
- data/lib/rack/handler.rb +3 -25
- data/lib/rack/head.rb +15 -17
- data/lib/rack/lint.rb +38 -38
- data/lib/rack/lobster.rb +1 -1
- data/lib/rack/lock.rb +6 -10
- data/lib/rack/logger.rb +2 -2
- data/lib/rack/media_type.rb +38 -0
- data/lib/rack/{methodoverride.rb → method_override.rb} +4 -11
- data/lib/rack/mime.rb +18 -5
- data/lib/rack/mock.rb +35 -53
- data/lib/rack/multipart/generator.rb +5 -5
- data/lib/rack/multipart/parser.rb +272 -158
- data/lib/rack/multipart/uploaded_file.rb +1 -2
- data/lib/rack/multipart.rb +35 -6
- data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
- data/lib/rack/query_parser.rb +192 -0
- data/lib/rack/recursive.rb +8 -8
- data/lib/rack/request.rb +383 -307
- data/lib/rack/response.rb +129 -56
- data/lib/rack/rewindable_input.rb +1 -12
- data/lib/rack/runtime.rb +10 -18
- data/lib/rack/sendfile.rb +5 -7
- data/lib/rack/server.rb +31 -25
- data/lib/rack/session/abstract/id.rb +95 -135
- data/lib/rack/session/cookie.rb +26 -28
- data/lib/rack/session/memcache.rb +8 -14
- data/lib/rack/session/pool.rb +14 -21
- data/lib/rack/show_exceptions.rb +386 -0
- data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
- data/lib/rack/static.rb +30 -5
- data/lib/rack/tempfile_reaper.rb +2 -2
- data/lib/rack/urlmap.rb +15 -14
- data/lib/rack/utils.rb +135 -210
- data/lib/rack.rb +70 -21
- data/rack.gemspec +7 -5
- data/test/builder/an_underscore_app.rb +5 -0
- data/test/builder/options.ru +1 -1
- data/test/cgi/test.fcgi +1 -0
- data/test/cgi/test.gz +0 -0
- data/test/helper.rb +34 -0
- data/test/multipart/filename_with_encoded_words +7 -0
- data/test/multipart/{filename_with_null_byte → filename_with_single_quote} +1 -1
- data/test/multipart/quoted +15 -0
- data/test/multipart/rack-logo.png +0 -0
- data/test/multipart/unity3d_wwwform +11 -0
- data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
- data/test/spec_auth_basic.rb +27 -19
- data/test/spec_auth_digest.rb +47 -46
- data/test/spec_body_proxy.rb +27 -27
- data/test/spec_builder.rb +51 -41
- data/test/spec_cascade.rb +24 -22
- data/test/spec_cgi.rb +49 -67
- data/test/spec_chunked.rb +36 -34
- data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -21
- data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
- data/test/spec_config.rb +3 -2
- data/test/spec_content_length.rb +18 -17
- data/test/spec_content_type.rb +13 -12
- data/test/spec_deflater.rb +66 -40
- data/test/spec_directory.rb +87 -27
- data/test/spec_etag.rb +32 -31
- data/test/spec_events.rb +133 -0
- data/test/spec_fastcgi.rb +50 -72
- data/test/spec_file.rb +107 -77
- data/test/spec_handler.rb +19 -34
- data/test/spec_head.rb +15 -14
- data/test/spec_lint.rb +162 -197
- data/test/spec_lobster.rb +24 -23
- data/test/spec_lock.rb +69 -39
- data/test/spec_logger.rb +4 -3
- data/test/spec_media_type.rb +42 -0
- data/test/spec_method_override.rb +83 -0
- data/test/spec_mime.rb +19 -19
- data/test/spec_mock.rb +196 -151
- data/test/spec_multipart.rb +317 -201
- data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
- data/test/spec_recursive.rb +17 -14
- data/test/spec_request.rb +768 -607
- data/test/spec_response.rb +214 -111
- data/test/spec_rewindable_input.rb +50 -40
- data/test/spec_runtime.rb +11 -10
- data/test/spec_sendfile.rb +30 -35
- data/test/spec_server.rb +78 -52
- data/test/spec_session_abstract_id.rb +11 -33
- data/test/spec_session_abstract_session_hash.rb +28 -0
- data/test/spec_session_cookie.rb +97 -65
- data/test/spec_session_memcache.rb +63 -101
- data/test/spec_session_pool.rb +48 -84
- data/test/spec_show_exceptions.rb +80 -0
- data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
- data/test/spec_static.rb +71 -32
- data/test/spec_tempfile_reaper.rb +11 -10
- data/test/spec_thin.rb +55 -50
- data/test/spec_urlmap.rb +79 -78
- data/test/spec_utils.rb +441 -346
- data/test/spec_version.rb +2 -8
- data/test/spec_webrick.rb +91 -67
- data/test/static/foo.html +1 -0
- data/test/testrequest.rb +1 -1
- data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
- metadata +103 -69
- data/KNOWN-ISSUES +0 -44
- data/lib/rack/backports/uri/common_18.rb +0 -56
- data/lib/rack/backports/uri/common_192.rb +0 -52
- data/lib/rack/backports/uri/common_193.rb +0 -29
- data/lib/rack/handler/evented_mongrel.rb +0 -8
- data/lib/rack/handler/mongrel.rb +0 -106
- data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
- data/lib/rack/showexceptions.rb +0 -387
- data/lib/rack/utils/okjson.rb +0 -600
- data/test/spec_methodoverride.rb +0 -111
- data/test/spec_mongrel.rb +0 -182
- data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
- data/test/spec_showexceptions.rb +0 -98
data/lib/rack/handler/scgi.rb
CHANGED
@@ -35,24 +35,24 @@ module Rack
|
|
35
35
|
env = Hash[request]
|
36
36
|
env.delete "HTTP_CONTENT_TYPE"
|
37
37
|
env.delete "HTTP_CONTENT_LENGTH"
|
38
|
-
env[
|
39
|
-
env[
|
40
|
-
env[PATH_INFO] = env[
|
41
|
-
env[
|
42
|
-
env[
|
38
|
+
env[REQUEST_PATH], env[QUERY_STRING] = env["REQUEST_URI"].split('?', 2)
|
39
|
+
env[HTTP_VERSION] ||= env[SERVER_PROTOCOL]
|
40
|
+
env[PATH_INFO] = env[REQUEST_PATH]
|
41
|
+
env[QUERY_STRING] ||= ""
|
42
|
+
env[SCRIPT_NAME] = ""
|
43
43
|
|
44
|
-
rack_input = StringIO.new(input_body)
|
45
|
-
rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
|
44
|
+
rack_input = StringIO.new(input_body, encoding: Encoding::BINARY)
|
46
45
|
|
47
|
-
env.update(
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
46
|
+
env.update(
|
47
|
+
RACK_VERSION => Rack::VERSION,
|
48
|
+
RACK_INPUT => rack_input,
|
49
|
+
RACK_ERRORS => $stderr,
|
50
|
+
RACK_MULTITHREAD => true,
|
51
|
+
RACK_MULTIPROCESS => true,
|
52
|
+
RACK_RUNONCE => false,
|
53
|
+
RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http"
|
54
|
+
)
|
53
55
|
|
54
|
-
"rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http"
|
55
|
-
})
|
56
56
|
status, headers, body = app.call(env)
|
57
57
|
begin
|
58
58
|
socket.write("Status: #{status}\r\n")
|
data/lib/rack/handler/thin.rb
CHANGED
data/lib/rack/handler/webrick.rb
CHANGED
@@ -3,7 +3,7 @@ require 'stringio'
|
|
3
3
|
require 'rack/content_length'
|
4
4
|
|
5
5
|
# This monkey patch allows for applications to perform their own chunking
|
6
|
-
# through WEBrick::HTTPResponse
|
6
|
+
# through WEBrick::HTTPResponse if rack is set to true.
|
7
7
|
class WEBrick::HTTPResponse
|
8
8
|
attr_accessor :rack
|
9
9
|
|
@@ -24,7 +24,7 @@ module Rack
|
|
24
24
|
class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet
|
25
25
|
def self.run(app, options={})
|
26
26
|
environment = ENV['RACK_ENV'] || 'development'
|
27
|
-
default_host = environment == 'development' ? 'localhost' :
|
27
|
+
default_host = environment == 'development' ? 'localhost' : nil
|
28
28
|
|
29
29
|
options[:BindAddress] = options.delete(:Host) || default_host
|
30
30
|
options[:Port] ||= 8080
|
@@ -60,36 +60,34 @@ module Rack
|
|
60
60
|
env.delete_if { |k, v| v.nil? }
|
61
61
|
|
62
62
|
rack_input = StringIO.new(req.body.to_s)
|
63
|
-
rack_input.set_encoding(Encoding::BINARY)
|
64
|
-
|
65
|
-
env.update(
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
|
63
|
+
rack_input.set_encoding(Encoding::BINARY)
|
64
|
+
|
65
|
+
env.update(
|
66
|
+
RACK_VERSION => Rack::VERSION,
|
67
|
+
RACK_INPUT => rack_input,
|
68
|
+
RACK_ERRORS => $stderr,
|
69
|
+
RACK_MULTITHREAD => true,
|
70
|
+
RACK_MULTIPROCESS => false,
|
71
|
+
RACK_RUNONCE => false,
|
72
|
+
RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http",
|
73
|
+
RACK_IS_HIJACK => true,
|
74
|
+
RACK_HIJACK => lambda { raise NotImplementedError, "only partial hijack is supported."},
|
75
|
+
RACK_HIJACK_IO => nil
|
76
|
+
)
|
77
|
+
|
78
|
+
env[HTTP_VERSION] ||= env[SERVER_PROTOCOL]
|
81
79
|
env[QUERY_STRING] ||= ""
|
82
80
|
unless env[PATH_INFO] == ""
|
83
|
-
path, n = req.request_uri.path, env[
|
81
|
+
path, n = req.request_uri.path, env[SCRIPT_NAME].length
|
84
82
|
env[PATH_INFO] = path[n, path.length-n]
|
85
83
|
end
|
86
|
-
env[
|
84
|
+
env[REQUEST_PATH] ||= [env[SCRIPT_NAME], env[PATH_INFO]].join
|
87
85
|
|
88
86
|
status, headers, body = @app.call(env)
|
89
87
|
begin
|
90
88
|
res.status = status.to_i
|
91
89
|
headers.each { |k, vs|
|
92
|
-
next if k.downcase ==
|
90
|
+
next if k.downcase == RACK_HIJACK
|
93
91
|
|
94
92
|
if k.downcase == "set-cookie"
|
95
93
|
res.cookies.concat vs.split("\n")
|
@@ -100,7 +98,7 @@ module Rack
|
|
100
98
|
end
|
101
99
|
}
|
102
100
|
|
103
|
-
io_lambda = headers[
|
101
|
+
io_lambda = headers[RACK_HIJACK]
|
104
102
|
if io_lambda
|
105
103
|
rd, wr = IO.pipe
|
106
104
|
res.body = rd
|
data/lib/rack/handler.rb
CHANGED
@@ -19,25 +19,13 @@ module Rack
|
|
19
19
|
if klass = @handlers[server]
|
20
20
|
klass.split("::").inject(Object) { |o, x| o.const_get(x) }
|
21
21
|
else
|
22
|
-
|
22
|
+
const_get(server, false)
|
23
23
|
end
|
24
24
|
|
25
25
|
rescue NameError => name_error
|
26
26
|
raise load_error || name_error
|
27
27
|
end
|
28
28
|
|
29
|
-
begin
|
30
|
-
::Object.const_get("Object", false)
|
31
|
-
def self._const_get(str, inherit = true)
|
32
|
-
const_get(str, inherit)
|
33
|
-
end
|
34
|
-
rescue
|
35
|
-
def self._const_get(str, inherit = true)
|
36
|
-
const_get(str)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
|
41
29
|
# Select first available Rack handler given an `Array` of server names.
|
42
30
|
# Raises `LoadError` if no handler was found.
|
43
31
|
#
|
@@ -55,20 +43,16 @@ module Rack
|
|
55
43
|
raise LoadError, "Couldn't find handler for: #{server_names.join(', ')}."
|
56
44
|
end
|
57
45
|
|
58
|
-
def self.default
|
46
|
+
def self.default
|
59
47
|
# Guess.
|
60
48
|
if ENV.include?("PHP_FCGI_CHILDREN")
|
61
|
-
# We already speak FastCGI
|
62
|
-
options.delete :File
|
63
|
-
options.delete :Port
|
64
|
-
|
65
49
|
Rack::Handler::FastCGI
|
66
50
|
elsif ENV.include?(REQUEST_METHOD)
|
67
51
|
Rack::Handler::CGI
|
68
52
|
elsif ENV.include?("RACK_HANDLER")
|
69
53
|
self.get(ENV["RACK_HANDLER"])
|
70
54
|
else
|
71
|
-
pick ['
|
55
|
+
pick ['puma', 'thin', 'webrick']
|
72
56
|
end
|
73
57
|
end
|
74
58
|
|
@@ -100,9 +84,6 @@ module Rack
|
|
100
84
|
|
101
85
|
autoload :CGI, "rack/handler/cgi"
|
102
86
|
autoload :FastCGI, "rack/handler/fastcgi"
|
103
|
-
autoload :Mongrel, "rack/handler/mongrel"
|
104
|
-
autoload :EventedMongrel, "rack/handler/evented_mongrel"
|
105
|
-
autoload :SwiftipliedMongrel, "rack/handler/swiftiplied_mongrel"
|
106
87
|
autoload :WEBrick, "rack/handler/webrick"
|
107
88
|
autoload :LSWS, "rack/handler/lsws"
|
108
89
|
autoload :SCGI, "rack/handler/scgi"
|
@@ -110,9 +91,6 @@ module Rack
|
|
110
91
|
|
111
92
|
register 'cgi', 'Rack::Handler::CGI'
|
112
93
|
register 'fastcgi', 'Rack::Handler::FastCGI'
|
113
|
-
register 'mongrel', 'Rack::Handler::Mongrel'
|
114
|
-
register 'emongrel', 'Rack::Handler::EventedMongrel'
|
115
|
-
register 'smongrel', 'Rack::Handler::SwiftipliedMongrel'
|
116
94
|
register 'webrick', 'Rack::Handler::WEBrick'
|
117
95
|
register 'lsws', 'Rack::Handler::LSWS'
|
118
96
|
register 'scgi', 'Rack::Handler::SCGI'
|
data/lib/rack/head.rb
CHANGED
@@ -1,27 +1,25 @@
|
|
1
1
|
require 'rack/body_proxy'
|
2
2
|
|
3
3
|
module Rack
|
4
|
-
|
5
|
-
class Head
|
6
4
|
# Rack::Head returns an empty body for all HEAD requests. It leaves
|
7
5
|
# all other requests unchanged.
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
class Head
|
7
|
+
def initialize(app)
|
8
|
+
@app = app
|
9
|
+
end
|
11
10
|
|
12
|
-
|
13
|
-
|
11
|
+
def call(env)
|
12
|
+
status, headers, body = @app.call(env)
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
14
|
+
if env[REQUEST_METHOD] == HEAD
|
15
|
+
[
|
16
|
+
status, headers, Rack::BodyProxy.new([]) do
|
17
|
+
body.close if body.respond_to? :close
|
18
|
+
end
|
19
|
+
]
|
20
|
+
else
|
21
|
+
[status, headers, body]
|
22
|
+
end
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
27
|
-
end
|
data/lib/rack/lint.rb
CHANGED
@@ -15,8 +15,8 @@ module Rack
|
|
15
15
|
|
16
16
|
class LintError < RuntimeError; end
|
17
17
|
module Assertion
|
18
|
-
def assert(message
|
19
|
-
unless
|
18
|
+
def assert(message)
|
19
|
+
unless yield
|
20
20
|
raise LintError, message
|
21
21
|
end
|
22
22
|
end
|
@@ -42,8 +42,8 @@ module Rack
|
|
42
42
|
assert("No env given") { env }
|
43
43
|
check_env env
|
44
44
|
|
45
|
-
env[
|
46
|
-
env[
|
45
|
+
env[RACK_INPUT] = InputWrapper.new(env[RACK_INPUT])
|
46
|
+
env[RACK_ERRORS] = ErrorWrapper.new(env[RACK_ERRORS])
|
47
47
|
|
48
48
|
## and returns an Array of exactly three values:
|
49
49
|
status, headers, @body = @app.call(env)
|
@@ -57,7 +57,7 @@ module Rack
|
|
57
57
|
## and the *body*.
|
58
58
|
check_content_type status, headers
|
59
59
|
check_content_length status, headers
|
60
|
-
@head_request = env[REQUEST_METHOD] ==
|
60
|
+
@head_request = env[REQUEST_METHOD] == HEAD
|
61
61
|
[status, headers, self]
|
62
62
|
end
|
63
63
|
|
@@ -95,7 +95,7 @@ module Rack
|
|
95
95
|
## empty string, if the request URL targets
|
96
96
|
## the application root and does not have a
|
97
97
|
## trailing slash. This value may be
|
98
|
-
## percent-encoded when
|
98
|
+
## percent-encoded when originating from
|
99
99
|
## a URL.
|
100
100
|
|
101
101
|
## <tt>QUERY_STRING</tt>:: The portion of the request URL that
|
@@ -177,7 +177,7 @@ module Rack
|
|
177
177
|
## <tt>rack.session</tt>:: A hash like interface for storing
|
178
178
|
## request session data.
|
179
179
|
## The store must implement:
|
180
|
-
if session = env[
|
180
|
+
if session = env[RACK_SESSION]
|
181
181
|
## store(key, value) (aliased as []=);
|
182
182
|
assert("session #{session.inspect} must respond to store and []=") {
|
183
183
|
session.respond_to?(:store) && session.respond_to?(:[]=)
|
@@ -201,7 +201,7 @@ module Rack
|
|
201
201
|
|
202
202
|
## <tt>rack.logger</tt>:: A common object interface for logging messages.
|
203
203
|
## The object must implement:
|
204
|
-
if logger = env[
|
204
|
+
if logger = env[RACK_LOGGER]
|
205
205
|
## info(message, &block)
|
206
206
|
assert("logger #{logger.inspect} must respond to info") {
|
207
207
|
logger.respond_to?(:info)
|
@@ -229,16 +229,16 @@ module Rack
|
|
229
229
|
end
|
230
230
|
|
231
231
|
## <tt>rack.multipart.buffer_size</tt>:: An Integer hint to the multipart parser as to what chunk size to use for reads and writes.
|
232
|
-
if bufsize = env[
|
232
|
+
if bufsize = env[RACK_MULTIPART_BUFFER_SIZE]
|
233
233
|
assert("rack.multipart.buffer_size must be an Integer > 0 if specified") {
|
234
234
|
bufsize.is_a?(Integer) && bufsize > 0
|
235
235
|
}
|
236
236
|
end
|
237
237
|
|
238
238
|
## <tt>rack.multipart.tempfile_factory</tt>:: An object responding to #call with two arguments, the filename and content_type given for the multipart form field, and returning an IO-like object that responds to #<< and optionally #rewind. This factory will be used to instantiate the tempfile for each multipart form file upload field, rather than the default class of Tempfile.
|
239
|
-
if tempfile_factory = env[
|
239
|
+
if tempfile_factory = env[RACK_MULTIPART_TEMPFILE_FACTORY]
|
240
240
|
assert("rack.multipart.tempfile_factory must respond to #call") { tempfile_factory.respond_to?(:call) }
|
241
|
-
env[
|
241
|
+
env[RACK_MULTIPART_TEMPFILE_FACTORY] = lambda do |filename, content_type|
|
242
242
|
io = tempfile_factory.call(filename, content_type)
|
243
243
|
assert("rack.multipart.tempfile_factory return value must respond to #<<") { io.respond_to?(:<<) }
|
244
244
|
io
|
@@ -279,37 +279,37 @@ module Rack
|
|
279
279
|
## There are the following restrictions:
|
280
280
|
|
281
281
|
## * <tt>rack.version</tt> must be an array of Integers.
|
282
|
-
assert("rack.version must be an Array, was #{env[
|
283
|
-
env[
|
282
|
+
assert("rack.version must be an Array, was #{env[RACK_VERSION].class}") {
|
283
|
+
env[RACK_VERSION].kind_of? Array
|
284
284
|
}
|
285
285
|
## * <tt>rack.url_scheme</tt> must either be +http+ or +https+.
|
286
|
-
assert("rack.url_scheme unknown: #{env[
|
287
|
-
%w[http https].include?
|
286
|
+
assert("rack.url_scheme unknown: #{env[RACK_URL_SCHEME].inspect}") {
|
287
|
+
%w[http https].include?(env[RACK_URL_SCHEME])
|
288
288
|
}
|
289
289
|
|
290
290
|
## * There must be a valid input stream in <tt>rack.input</tt>.
|
291
|
-
check_input env[
|
291
|
+
check_input env[RACK_INPUT]
|
292
292
|
## * There must be a valid error stream in <tt>rack.errors</tt>.
|
293
|
-
check_error env[
|
293
|
+
check_error env[RACK_ERRORS]
|
294
294
|
## * There may be a valid hijack stream in <tt>rack.hijack_io</tt>
|
295
295
|
check_hijack env
|
296
296
|
|
297
297
|
## * The <tt>REQUEST_METHOD</tt> must be a valid token.
|
298
298
|
assert("REQUEST_METHOD unknown: #{env[REQUEST_METHOD]}") {
|
299
|
-
env[
|
299
|
+
env[REQUEST_METHOD] =~ /\A[0-9A-Za-z!\#$%&'*+.^_`|~-]+\z/
|
300
300
|
}
|
301
301
|
|
302
302
|
## * The <tt>SCRIPT_NAME</tt>, if non-empty, must start with <tt>/</tt>
|
303
303
|
assert("SCRIPT_NAME must start with /") {
|
304
|
-
!env.include?(
|
305
|
-
env[
|
306
|
-
env[
|
304
|
+
!env.include?(SCRIPT_NAME) ||
|
305
|
+
env[SCRIPT_NAME] == "" ||
|
306
|
+
env[SCRIPT_NAME] =~ /\A\//
|
307
307
|
}
|
308
308
|
## * The <tt>PATH_INFO</tt>, if non-empty, must start with <tt>/</tt>
|
309
309
|
assert("PATH_INFO must start with /") {
|
310
|
-
!env.include?(
|
311
|
-
env[
|
312
|
-
env[
|
310
|
+
!env.include?(PATH_INFO) ||
|
311
|
+
env[PATH_INFO] == "" ||
|
312
|
+
env[PATH_INFO] =~ /\A\//
|
313
313
|
}
|
314
314
|
## * The <tt>CONTENT_LENGTH</tt>, if given, must consist of digits only.
|
315
315
|
assert("Invalid CONTENT_LENGTH: #{env["CONTENT_LENGTH"]}") {
|
@@ -320,11 +320,11 @@ module Rack
|
|
320
320
|
## set. <tt>PATH_INFO</tt> should be <tt>/</tt> if
|
321
321
|
## <tt>SCRIPT_NAME</tt> is empty.
|
322
322
|
assert("One of SCRIPT_NAME or PATH_INFO must be set (make PATH_INFO '/' if SCRIPT_NAME is empty)") {
|
323
|
-
env[
|
323
|
+
env[SCRIPT_NAME] || env[PATH_INFO]
|
324
324
|
}
|
325
325
|
## <tt>SCRIPT_NAME</tt> never should be <tt>/</tt>, but instead be empty.
|
326
326
|
assert("SCRIPT_NAME cannot be '/', make it '' and PATH_INFO '/'") {
|
327
|
-
env[
|
327
|
+
env[SCRIPT_NAME] != "/"
|
328
328
|
}
|
329
329
|
end
|
330
330
|
|
@@ -518,11 +518,11 @@ module Rack
|
|
518
518
|
#
|
519
519
|
## ==== Request (before status)
|
520
520
|
def check_hijack(env)
|
521
|
-
if env[
|
521
|
+
if env[RACK_IS_HIJACK]
|
522
522
|
## If rack.hijack? is true then rack.hijack must respond to #call.
|
523
|
-
original_hijack = env[
|
523
|
+
original_hijack = env[RACK_HIJACK]
|
524
524
|
assert("rack.hijack must respond to call") { original_hijack.respond_to?(:call) }
|
525
|
-
env[
|
525
|
+
env[RACK_HIJACK] = proc do
|
526
526
|
## rack.hijack must return the io that will also be assigned (or is
|
527
527
|
## already present, in rack.hijack_io.
|
528
528
|
io = original_hijack.call
|
@@ -548,16 +548,16 @@ module Rack
|
|
548
548
|
## hijack_io to provide additional features to users. The purpose of
|
549
549
|
## rack.hijack is for Rack to "get out of the way", as such, Rack only
|
550
550
|
## provides the minimum of specification and support.
|
551
|
-
env[
|
551
|
+
env[RACK_HIJACK_IO] = HijackWrapper.new(env[RACK_HIJACK_IO])
|
552
552
|
io
|
553
553
|
end
|
554
554
|
else
|
555
555
|
##
|
556
556
|
## If rack.hijack? is false, then rack.hijack should not be set.
|
557
|
-
assert("rack.hijack? is false, but rack.hijack is present") { env[
|
557
|
+
assert("rack.hijack? is false, but rack.hijack is present") { env[RACK_HIJACK].nil? }
|
558
558
|
##
|
559
559
|
## If rack.hijack? is false, then rack.hijack_io should not be set.
|
560
|
-
assert("rack.hijack? is false, but rack.hijack_io is present") { env[
|
560
|
+
assert("rack.hijack? is false, but rack.hijack_io is present") { env[RACK_HIJACK_IO].nil? }
|
561
561
|
end
|
562
562
|
end
|
563
563
|
|
@@ -587,12 +587,12 @@ module Rack
|
|
587
587
|
## Servers must ignore the <tt>body</tt> part of the response tuple when
|
588
588
|
## the <tt>rack.hijack</tt> response API is in use.
|
589
589
|
|
590
|
-
if env[
|
590
|
+
if env[RACK_IS_HIJACK] && headers[RACK_HIJACK]
|
591
591
|
assert('rack.hijack header must respond to #call') {
|
592
|
-
headers[
|
592
|
+
headers[RACK_HIJACK].respond_to? :call
|
593
593
|
}
|
594
|
-
original_hijack = headers[
|
595
|
-
headers[
|
594
|
+
original_hijack = headers[RACK_HIJACK]
|
595
|
+
headers[RACK_HIJACK] = proc do |io|
|
596
596
|
original_hijack.call HijackWrapper.new(io)
|
597
597
|
end
|
598
598
|
else
|
@@ -600,7 +600,7 @@ module Rack
|
|
600
600
|
## The special response header <tt>rack.hijack</tt> must only be set
|
601
601
|
## if the request env has <tt>rack.hijack?</tt> <tt>true</tt>.
|
602
602
|
assert('rack.hijack header must not be present if server does not support hijacking') {
|
603
|
-
headers[
|
603
|
+
headers[RACK_HIJACK].nil?
|
604
604
|
}
|
605
605
|
end
|
606
606
|
end
|
@@ -710,7 +710,7 @@ module Rack
|
|
710
710
|
assert("Body yielded non-string value #{part.inspect}") {
|
711
711
|
part.kind_of? String
|
712
712
|
}
|
713
|
-
bytes +=
|
713
|
+
bytes += part.bytesize
|
714
714
|
yield part
|
715
715
|
}
|
716
716
|
verify_content_length(bytes)
|
data/lib/rack/lobster.rb
CHANGED
data/lib/rack/lock.rb
CHANGED
@@ -5,22 +5,18 @@ module Rack
|
|
5
5
|
# Rack::Lock locks every request inside a mutex, so that every request
|
6
6
|
# will effectively be executed synchronously.
|
7
7
|
class Lock
|
8
|
-
FLAG = 'rack.multithread'.freeze
|
9
|
-
|
10
8
|
def initialize(app, mutex = Mutex.new)
|
11
9
|
@app, @mutex = app, mutex
|
12
10
|
end
|
13
11
|
|
14
12
|
def call(env)
|
15
|
-
old, env[FLAG] = env[FLAG], false
|
16
13
|
@mutex.lock
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
env[FLAG] = old
|
14
|
+
begin
|
15
|
+
response = @app.call(env.merge(RACK_MULTITHREAD => false))
|
16
|
+
returned = response << BodyProxy.new(response.pop) { @mutex.unlock }
|
17
|
+
ensure
|
18
|
+
@mutex.unlock unless returned
|
19
|
+
end
|
24
20
|
end
|
25
21
|
end
|
26
22
|
end
|
data/lib/rack/logger.rb
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Rack
|
2
|
+
# Rack::MediaType parse media type and parameters out of content_type string
|
3
|
+
|
4
|
+
class MediaType
|
5
|
+
SPLIT_PATTERN = %r{\s*[;,]\s*}
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# The media type (type/subtype) portion of the CONTENT_TYPE header
|
9
|
+
# without any media type parameters. e.g., when CONTENT_TYPE is
|
10
|
+
# "text/plain;charset=utf-8", the media-type is "text/plain".
|
11
|
+
#
|
12
|
+
# For more information on the use of media types in HTTP, see:
|
13
|
+
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
|
14
|
+
def type(content_type)
|
15
|
+
return nil unless content_type
|
16
|
+
content_type.split(SPLIT_PATTERN, 2).first.downcase
|
17
|
+
end
|
18
|
+
|
19
|
+
# The media type parameters provided in CONTENT_TYPE as a Hash, or
|
20
|
+
# an empty Hash if no CONTENT_TYPE or media-type parameters were
|
21
|
+
# provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8",
|
22
|
+
# this method responds with the following Hash:
|
23
|
+
# { 'charset' => 'utf-8' }
|
24
|
+
def params(content_type)
|
25
|
+
return {} if content_type.nil?
|
26
|
+
Hash[*content_type.split(SPLIT_PATTERN)[1..-1].
|
27
|
+
collect { |s| s.split('=', 2) }.
|
28
|
+
map { |k,v| [k.downcase, strip_doublequotes(v)] }.flatten]
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def strip_doublequotes(str)
|
34
|
+
(str[0] == ?" && str[-1] == ?") ? str[1..-2] : str
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module Rack
|
2
2
|
class MethodOverride
|
3
|
-
HTTP_METHODS = %w
|
3
|
+
HTTP_METHODS = %w[GET HEAD PUT POST DELETE OPTIONS PATCH LINK UNLINK]
|
4
4
|
|
5
5
|
METHOD_OVERRIDE_PARAM_KEY = "_method".freeze
|
6
6
|
HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE".freeze
|
7
|
-
ALLOWED_METHODS = [
|
7
|
+
ALLOWED_METHODS = %w[POST]
|
8
8
|
|
9
9
|
def initialize(app)
|
10
10
|
@app = app
|
@@ -14,7 +14,7 @@ module Rack
|
|
14
14
|
if allowed_methods.include?(env[REQUEST_METHOD])
|
15
15
|
method = method_override(env)
|
16
16
|
if HTTP_METHODS.include?(method)
|
17
|
-
env[
|
17
|
+
env[RACK_METHODOVERRIDE_ORIGINAL_METHOD] = env[REQUEST_METHOD]
|
18
18
|
env[REQUEST_METHOD] = method
|
19
19
|
end
|
20
20
|
end
|
@@ -26,11 +26,7 @@ module Rack
|
|
26
26
|
req = Request.new(env)
|
27
27
|
method = method_override_param(req) ||
|
28
28
|
env[HTTP_METHOD_OVERRIDE_HEADER]
|
29
|
-
|
30
|
-
method.to_s.upcase
|
31
|
-
rescue ArgumentError
|
32
|
-
env["rack.errors"].puts "Invalid string for method"
|
33
|
-
end
|
29
|
+
method.to_s.upcase
|
34
30
|
end
|
35
31
|
|
36
32
|
private
|
@@ -42,9 +38,6 @@ module Rack
|
|
42
38
|
def method_override_param(req)
|
43
39
|
req.POST[METHOD_OVERRIDE_PARAM_KEY]
|
44
40
|
rescue Utils::InvalidParameterError, Utils::ParameterTypeError
|
45
|
-
req.env["rack.errors"].puts "Invalid or incomplete POST params"
|
46
|
-
rescue EOFError
|
47
|
-
req.env["rack.errors"].puts "Bad request content body"
|
48
41
|
end
|
49
42
|
end
|
50
43
|
end
|
data/lib/rack/mime.rb
CHANGED
@@ -45,11 +45,6 @@ module Rack
|
|
45
45
|
#
|
46
46
|
# N.B. On Ubuntu the mime.types file does not include the leading period, so
|
47
47
|
# users may need to modify the data before merging into the hash.
|
48
|
-
#
|
49
|
-
# To add the list mongrel provides, use:
|
50
|
-
#
|
51
|
-
# require 'mongrel/handlers'
|
52
|
-
# Rack::Mime::MIME_TYPES.merge!(Mongrel::DirHandler::MIME_TYPES)
|
53
48
|
|
54
49
|
MIME_TYPES = {
|
55
50
|
".123" => "application/vnd.lotus-1-2-3",
|
@@ -154,8 +149,11 @@ module Rack
|
|
154
149
|
".dmg" => "application/octet-stream",
|
155
150
|
".dna" => "application/vnd.dna",
|
156
151
|
".doc" => "application/msword",
|
152
|
+
".docm" => "application/vnd.ms-word.document.macroEnabled.12",
|
157
153
|
".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
158
154
|
".dot" => "application/msword",
|
155
|
+
".dotm" => "application/vnd.ms-word.template.macroEnabled.12",
|
156
|
+
".dotx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
|
159
157
|
".dp" => "application/vnd.osgi.dp",
|
160
158
|
".dpg" => "application/vnd.dpgraph",
|
161
159
|
".dsc" => "text/prs.lines.tag",
|
@@ -444,10 +442,19 @@ module Rack
|
|
444
442
|
".pnm" => "image/x-portable-anymap",
|
445
443
|
".pntg" => "image/x-macpaint",
|
446
444
|
".portpkg" => "application/vnd.macports.portpkg",
|
445
|
+
".pot" => "application/vnd.ms-powerpoint",
|
446
|
+
".potm" => "application/vnd.ms-powerpoint.template.macroEnabled.12",
|
447
|
+
".potx" => "application/vnd.openxmlformats-officedocument.presentationml.template",
|
448
|
+
".ppa" => "application/vnd.ms-powerpoint",
|
449
|
+
".ppam" => "application/vnd.ms-powerpoint.addin.macroEnabled.12",
|
447
450
|
".ppd" => "application/vnd.cups-ppd",
|
448
451
|
".ppm" => "image/x-portable-pixmap",
|
449
452
|
".pps" => "application/vnd.ms-powerpoint",
|
453
|
+
".ppsm" => "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
|
454
|
+
".ppsx" => "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
|
450
455
|
".ppt" => "application/vnd.ms-powerpoint",
|
456
|
+
".pptm" => "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
|
457
|
+
".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
451
458
|
".prc" => "application/vnd.palm",
|
452
459
|
".pre" => "application/vnd.lotus-freelance",
|
453
460
|
".prf" => "application/pics-rules",
|
@@ -638,8 +645,14 @@ module Rack
|
|
638
645
|
".xfdl" => "application/vnd.xfdl",
|
639
646
|
".xhtml" => "application/xhtml+xml",
|
640
647
|
".xif" => "image/vnd.xiff",
|
648
|
+
".xla" => "application/vnd.ms-excel",
|
649
|
+
".xlam" => "application/vnd.ms-excel.addin.macroEnabled.12",
|
641
650
|
".xls" => "application/vnd.ms-excel",
|
651
|
+
".xlsb" => "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
|
642
652
|
".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
653
|
+
".xlsm" => "application/vnd.ms-excel.sheet.macroEnabled.12",
|
654
|
+
".xlt" => "application/vnd.ms-excel",
|
655
|
+
".xltx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
|
643
656
|
".xml" => "application/xml",
|
644
657
|
".xo" => "application/vnd.olpc-sugar",
|
645
658
|
".xop" => "application/xop+xml",
|