rack 2.0.9.3 → 2.2.8
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 +740 -0
- data/CONTRIBUTING.md +136 -0
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +151 -147
- data/Rakefile +37 -23
- data/{SPEC → SPEC.rdoc} +44 -15
- data/bin/rackup +1 -0
- data/example/lobster.ru +2 -0
- data/example/protectedlobster.rb +3 -1
- data/example/protectedlobster.ru +2 -0
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +1 -1
- data/lib/rack/auth/basic.rb +7 -4
- data/lib/rack/auth/digest/md5.rb +13 -11
- data/lib/rack/auth/digest/nonce.rb +6 -3
- data/lib/rack/auth/digest/params.rb +4 -2
- data/lib/rack/auth/digest/request.rb +5 -3
- data/lib/rack/body_proxy.rb +15 -14
- data/lib/rack/builder.rb +116 -23
- data/lib/rack/cascade.rb +28 -12
- data/lib/rack/chunked.rb +68 -20
- data/lib/rack/common_logger.rb +33 -25
- data/lib/rack/conditional_get.rb +20 -16
- data/lib/rack/config.rb +2 -0
- data/lib/rack/content_length.rb +8 -7
- data/lib/rack/content_type.rb +5 -4
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +59 -34
- data/lib/rack/directory.rb +84 -64
- data/lib/rack/etag.rb +7 -4
- data/lib/rack/events.rb +19 -20
- data/lib/rack/file.rb +4 -173
- data/lib/rack/files.rb +218 -0
- data/lib/rack/handler/cgi.rb +2 -3
- data/lib/rack/handler/fastcgi.rb +4 -4
- data/lib/rack/handler/lsws.rb +3 -3
- data/lib/rack/handler/scgi.rb +9 -8
- data/lib/rack/handler/thin.rb +3 -3
- data/lib/rack/handler/webrick.rb +15 -6
- data/lib/rack/handler.rb +7 -2
- data/lib/rack/head.rb +1 -1
- data/lib/rack/lint.rb +219 -184
- data/lib/rack/lobster.rb +10 -10
- data/lib/rack/lock.rb +2 -1
- data/lib/rack/logger.rb +2 -0
- data/lib/rack/media_type.rb +10 -5
- data/lib/rack/method_override.rb +5 -3
- data/lib/rack/mime.rb +9 -1
- data/lib/rack/mock.rb +97 -20
- data/lib/rack/multipart/generator.rb +17 -13
- data/lib/rack/multipart/parser.rb +55 -56
- data/lib/rack/multipart/uploaded_file.rb +15 -7
- data/lib/rack/multipart.rb +4 -2
- data/lib/rack/null_logger.rb +2 -0
- data/lib/rack/query_parser.rb +59 -30
- data/lib/rack/recursive.rb +7 -5
- data/lib/rack/reloader.rb +8 -4
- data/lib/rack/request.rb +222 -63
- data/lib/rack/response.rb +127 -44
- data/lib/rack/rewindable_input.rb +4 -3
- data/lib/rack/runtime.rb +6 -4
- data/lib/rack/sendfile.rb +13 -9
- data/lib/rack/server.rb +95 -24
- data/lib/rack/session/abstract/id.rb +34 -21
- data/lib/rack/session/cookie.rb +12 -12
- data/lib/rack/session/memcache.rb +4 -93
- data/lib/rack/session/pool.rb +5 -3
- data/lib/rack/show_exceptions.rb +21 -17
- data/lib/rack/show_status.rb +9 -9
- data/lib/rack/static.rb +23 -11
- data/lib/rack/tempfile_reaper.rb +1 -1
- data/lib/rack/urlmap.rb +13 -7
- data/lib/rack/utils.rb +105 -111
- data/lib/rack/version.rb +29 -0
- data/lib/rack.rb +67 -73
- data/rack.gemspec +40 -28
- metadata +36 -179
- data/HISTORY.md +0 -520
- data/test/builder/an_underscore_app.rb +0 -5
- data/test/builder/anything.rb +0 -5
- data/test/builder/comment.ru +0 -4
- data/test/builder/end.ru +0 -5
- data/test/builder/line.ru +0 -1
- data/test/builder/options.ru +0 -2
- data/test/cgi/assets/folder/test.js +0 -1
- data/test/cgi/assets/fonts/font.eot +0 -1
- data/test/cgi/assets/images/image.png +0 -1
- data/test/cgi/assets/index.html +0 -1
- data/test/cgi/assets/javascripts/app.js +0 -1
- data/test/cgi/assets/stylesheets/app.css +0 -1
- data/test/cgi/lighttpd.conf +0 -26
- data/test/cgi/rackup_stub.rb +0 -6
- data/test/cgi/sample_rackup.ru +0 -5
- data/test/cgi/test +0 -9
- data/test/cgi/test+directory/test+file +0 -1
- data/test/cgi/test.fcgi +0 -9
- data/test/cgi/test.gz +0 -0
- data/test/cgi/test.ru +0 -5
- data/test/gemloader.rb +0 -10
- data/test/helper.rb +0 -34
- data/test/multipart/bad_robots +0 -259
- data/test/multipart/binary +0 -0
- data/test/multipart/content_type_and_no_filename +0 -6
- data/test/multipart/empty +0 -10
- data/test/multipart/fail_16384_nofile +0 -814
- data/test/multipart/file1.txt +0 -1
- data/test/multipart/filename_and_modification_param +0 -7
- data/test/multipart/filename_and_no_name +0 -6
- data/test/multipart/filename_with_encoded_words +0 -7
- data/test/multipart/filename_with_escaped_quotes +0 -6
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
- data/test/multipart/filename_with_null_byte +0 -7
- data/test/multipart/filename_with_percent_escaped_quotes +0 -6
- data/test/multipart/filename_with_single_quote +0 -7
- data/test/multipart/filename_with_unescaped_percentages +0 -6
- data/test/multipart/filename_with_unescaped_percentages2 +0 -6
- data/test/multipart/filename_with_unescaped_percentages3 +0 -6
- data/test/multipart/filename_with_unescaped_quotes +0 -6
- data/test/multipart/ie +0 -6
- data/test/multipart/invalid_character +0 -6
- data/test/multipart/mixed_files +0 -21
- data/test/multipart/nested +0 -10
- data/test/multipart/none +0 -9
- data/test/multipart/quoted +0 -15
- data/test/multipart/rack-logo.png +0 -0
- data/test/multipart/semicolon +0 -6
- data/test/multipart/text +0 -15
- data/test/multipart/three_files_three_fields +0 -31
- data/test/multipart/unity3d_wwwform +0 -11
- data/test/multipart/webkit +0 -32
- data/test/rackup/config.ru +0 -31
- data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
- data/test/spec_auth_basic.rb +0 -89
- data/test/spec_auth_digest.rb +0 -260
- data/test/spec_body_proxy.rb +0 -85
- data/test/spec_builder.rb +0 -233
- data/test/spec_cascade.rb +0 -63
- data/test/spec_cgi.rb +0 -84
- data/test/spec_chunked.rb +0 -103
- data/test/spec_common_logger.rb +0 -107
- data/test/spec_conditional_get.rb +0 -103
- data/test/spec_config.rb +0 -23
- data/test/spec_content_length.rb +0 -86
- data/test/spec_content_type.rb +0 -46
- data/test/spec_deflater.rb +0 -375
- data/test/spec_directory.rb +0 -148
- data/test/spec_etag.rb +0 -108
- data/test/spec_events.rb +0 -133
- data/test/spec_fastcgi.rb +0 -85
- data/test/spec_file.rb +0 -264
- data/test/spec_handler.rb +0 -57
- data/test/spec_head.rb +0 -46
- data/test/spec_lint.rb +0 -520
- data/test/spec_lobster.rb +0 -59
- data/test/spec_lock.rb +0 -204
- data/test/spec_logger.rb +0 -24
- data/test/spec_media_type.rb +0 -42
- data/test/spec_method_override.rb +0 -110
- data/test/spec_mime.rb +0 -51
- data/test/spec_mock.rb +0 -359
- data/test/spec_multipart.rb +0 -721
- data/test/spec_null_logger.rb +0 -21
- data/test/spec_recursive.rb +0 -75
- data/test/spec_request.rb +0 -1423
- data/test/spec_response.rb +0 -528
- data/test/spec_rewindable_input.rb +0 -128
- data/test/spec_runtime.rb +0 -50
- data/test/spec_sendfile.rb +0 -125
- data/test/spec_server.rb +0 -193
- data/test/spec_session_abstract_id.rb +0 -31
- data/test/spec_session_abstract_session_hash.rb +0 -45
- data/test/spec_session_cookie.rb +0 -442
- data/test/spec_session_memcache.rb +0 -357
- data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
- data/test/spec_session_pool.rb +0 -247
- data/test/spec_show_exceptions.rb +0 -93
- data/test/spec_show_status.rb +0 -104
- data/test/spec_static.rb +0 -184
- data/test/spec_tempfile_reaper.rb +0 -64
- data/test/spec_thin.rb +0 -96
- data/test/spec_urlmap.rb +0 -237
- data/test/spec_utils.rb +0 -742
- data/test/spec_version.rb +0 -11
- data/test/spec_webrick.rb +0 -206
- data/test/static/another/index.html +0 -1
- data/test/static/foo.html +0 -1
- data/test/static/index.html +0 -1
- data/test/testrequest.rb +0 -78
- data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/lib/rack/lobster.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require '
|
|
4
|
-
require 'rack/response'
|
|
3
|
+
require 'zlib'
|
|
5
4
|
|
|
6
5
|
module Rack
|
|
7
6
|
# Paste has a Pony, Rack has a Lobster!
|
|
@@ -25,8 +24,8 @@ module Rack
|
|
|
25
24
|
content = ["<title>Lobstericious!</title>",
|
|
26
25
|
"<pre>", lobster, "</pre>",
|
|
27
26
|
"<a href='#{href}'>flip!</a>"]
|
|
28
|
-
length = content.inject(0) { |a,e| a+e.size }.to_s
|
|
29
|
-
[200, {CONTENT_TYPE => "text/html", CONTENT_LENGTH => length}, content]
|
|
27
|
+
length = content.inject(0) { |a, e| a + e.size }.to_s
|
|
28
|
+
[200, { CONTENT_TYPE => "text/html", CONTENT_LENGTH => length }, content]
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
def call(env)
|
|
@@ -37,8 +36,8 @@ module Rack
|
|
|
37
36
|
gsub('\\', 'TEMP').
|
|
38
37
|
gsub('/', '\\').
|
|
39
38
|
gsub('TEMP', '/').
|
|
40
|
-
gsub('{','}').
|
|
41
|
-
gsub('(',')')
|
|
39
|
+
gsub('{', '}').
|
|
40
|
+
gsub('(', ')')
|
|
42
41
|
end.join("\n")
|
|
43
42
|
href = "?flip=right"
|
|
44
43
|
elsif req.GET["flip"] == "crash"
|
|
@@ -62,9 +61,10 @@ module Rack
|
|
|
62
61
|
end
|
|
63
62
|
|
|
64
63
|
if $0 == __FILE__
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
# :nocov:
|
|
65
|
+
require_relative '../rack'
|
|
67
66
|
Rack::Server.start(
|
|
68
|
-
:
|
|
67
|
+
app: Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)), Port: 9292
|
|
69
68
|
)
|
|
69
|
+
# :nocov:
|
|
70
70
|
end
|
data/lib/rack/lock.rb
CHANGED
data/lib/rack/logger.rb
CHANGED
data/lib/rack/media_type.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Rack
|
|
2
4
|
# Rack::MediaType parse media type and parameters out of content_type string
|
|
3
5
|
|
|
@@ -13,7 +15,7 @@ module Rack
|
|
|
13
15
|
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
|
|
14
16
|
def type(content_type)
|
|
15
17
|
return nil unless content_type
|
|
16
|
-
content_type.split(SPLIT_PATTERN, 2).first.downcase
|
|
18
|
+
content_type.split(SPLIT_PATTERN, 2).first.tap &:downcase!
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
# The media type parameters provided in CONTENT_TYPE as a Hash, or
|
|
@@ -23,15 +25,18 @@ module Rack
|
|
|
23
25
|
# { 'charset' => 'utf-8' }
|
|
24
26
|
def params(content_type)
|
|
25
27
|
return {} if content_type.nil?
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
content_type.split(SPLIT_PATTERN)[1..-1].each_with_object({}) do |s, hsh|
|
|
30
|
+
k, v = s.split('=', 2)
|
|
31
|
+
|
|
32
|
+
hsh[k.tap(&:downcase!)] = strip_doublequotes(v)
|
|
33
|
+
end
|
|
29
34
|
end
|
|
30
35
|
|
|
31
36
|
private
|
|
32
37
|
|
|
33
38
|
def strip_doublequotes(str)
|
|
34
|
-
(str
|
|
39
|
+
(str.start_with?('"') && str.end_with?('"')) ? str[1..-2] : str
|
|
35
40
|
end
|
|
36
41
|
end
|
|
37
42
|
end
|
data/lib/rack/method_override.rb
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Rack
|
|
2
4
|
class MethodOverride
|
|
3
5
|
HTTP_METHODS = %w[GET HEAD PUT POST DELETE OPTIONS PATCH LINK UNLINK]
|
|
4
6
|
|
|
5
|
-
METHOD_OVERRIDE_PARAM_KEY = "_method"
|
|
6
|
-
HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE"
|
|
7
|
+
METHOD_OVERRIDE_PARAM_KEY = "_method"
|
|
8
|
+
HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE"
|
|
7
9
|
ALLOWED_METHODS = %w[POST]
|
|
8
10
|
|
|
9
11
|
def initialize(app)
|
|
@@ -41,7 +43,7 @@ module Rack
|
|
|
41
43
|
|
|
42
44
|
def method_override_param(req)
|
|
43
45
|
req.POST[METHOD_OVERRIDE_PARAM_KEY]
|
|
44
|
-
rescue Utils::InvalidParameterError, Utils::ParameterTypeError
|
|
46
|
+
rescue Utils::InvalidParameterError, Utils::ParameterTypeError, QueryParser::ParamsTooDeepError
|
|
45
47
|
req.get_header(RACK_ERRORS).puts "Invalid or incomplete POST params"
|
|
46
48
|
rescue EOFError
|
|
47
49
|
req.get_header(RACK_ERRORS).puts "Bad request content body"
|
data/lib/rack/mime.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Rack
|
|
2
4
|
module Mime
|
|
3
5
|
# Returns String with mime type if found, otherwise use +fallback+.
|
|
@@ -13,7 +15,7 @@ module Rack
|
|
|
13
15
|
# This is a shortcut for:
|
|
14
16
|
# Rack::Mime::MIME_TYPES.fetch('.foo', 'application/octet-stream')
|
|
15
17
|
|
|
16
|
-
def mime_type(ext, fallback='application/octet-stream')
|
|
18
|
+
def mime_type(ext, fallback = 'application/octet-stream')
|
|
17
19
|
MIME_TYPES.fetch(ext.to_s.downcase, fallback)
|
|
18
20
|
end
|
|
19
21
|
module_function :mime_type
|
|
@@ -306,6 +308,7 @@ module Rack
|
|
|
306
308
|
".lvp" => "audio/vnd.lucent.voice",
|
|
307
309
|
".lwp" => "application/vnd.lotus-wordpro",
|
|
308
310
|
".m3u" => "audio/x-mpegurl",
|
|
311
|
+
".m3u8" => "application/x-mpegurl",
|
|
309
312
|
".m4a" => "audio/mp4a-latm",
|
|
310
313
|
".m4v" => "video/mp4",
|
|
311
314
|
".ma" => "application/mathematica",
|
|
@@ -343,6 +346,7 @@ module Rack
|
|
|
343
346
|
".mp4s" => "application/mp4",
|
|
344
347
|
".mp4v" => "video/mp4",
|
|
345
348
|
".mpc" => "application/vnd.mophun.certificate",
|
|
349
|
+
".mpd" => "application/dash+xml",
|
|
346
350
|
".mpeg" => "video/mpeg",
|
|
347
351
|
".mpg" => "video/mpeg",
|
|
348
352
|
".mpga" => "audio/mpeg",
|
|
@@ -542,6 +546,7 @@ module Rack
|
|
|
542
546
|
".spp" => "application/scvp-vp-response",
|
|
543
547
|
".spq" => "application/scvp-vp-request",
|
|
544
548
|
".src" => "application/x-wais-source",
|
|
549
|
+
".srt" => "text/srt",
|
|
545
550
|
".srx" => "application/sparql-results+xml",
|
|
546
551
|
".sse" => "application/vnd.kodak-descriptor",
|
|
547
552
|
".ssf" => "application/vnd.epson.ssf",
|
|
@@ -576,6 +581,7 @@ module Rack
|
|
|
576
581
|
".tr" => "text/troff",
|
|
577
582
|
".tra" => "application/vnd.trueapp",
|
|
578
583
|
".trm" => "application/x-msterminal",
|
|
584
|
+
".ts" => "video/mp2t",
|
|
579
585
|
".tsv" => "text/tab-separated-values",
|
|
580
586
|
".ttf" => "application/octet-stream",
|
|
581
587
|
".twd" => "application/vnd.simtech-mindmapper",
|
|
@@ -600,9 +606,11 @@ module Rack
|
|
|
600
606
|
".vrml" => "model/vrml",
|
|
601
607
|
".vsd" => "application/vnd.visio",
|
|
602
608
|
".vsf" => "application/vnd.vsf",
|
|
609
|
+
".vtt" => "text/vtt",
|
|
603
610
|
".vtu" => "model/vnd.vtu",
|
|
604
611
|
".vxml" => "application/voicexml+xml",
|
|
605
612
|
".war" => "application/java-archive",
|
|
613
|
+
".wasm" => "application/wasm",
|
|
606
614
|
".wav" => "audio/x-wav",
|
|
607
615
|
".wax" => "audio/x-ms-wax",
|
|
608
616
|
".wbmp" => "image/vnd.wap.wbmp",
|
data/lib/rack/mock.rb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'uri'
|
|
2
4
|
require 'stringio'
|
|
3
|
-
|
|
4
|
-
require '
|
|
5
|
-
require 'rack/utils'
|
|
6
|
-
require 'rack/response'
|
|
5
|
+
require_relative '../rack'
|
|
6
|
+
require 'cgi/cookie'
|
|
7
7
|
|
|
8
8
|
module Rack
|
|
9
9
|
# Rack::MockRequest helps testing your Rack application without
|
|
@@ -53,16 +53,26 @@ module Rack
|
|
|
53
53
|
@app = app
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
def
|
|
58
|
-
|
|
59
|
-
def
|
|
60
|
-
|
|
61
|
-
def
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
# Make a GET request and return a MockResponse. See #request.
|
|
57
|
+
def get(uri, opts = {}) request(GET, uri, opts) end
|
|
58
|
+
# Make a POST request and return a MockResponse. See #request.
|
|
59
|
+
def post(uri, opts = {}) request(POST, uri, opts) end
|
|
60
|
+
# Make a PUT request and return a MockResponse. See #request.
|
|
61
|
+
def put(uri, opts = {}) request(PUT, uri, opts) end
|
|
62
|
+
# Make a PATCH request and return a MockResponse. See #request.
|
|
63
|
+
def patch(uri, opts = {}) request(PATCH, uri, opts) end
|
|
64
|
+
# Make a DELETE request and return a MockResponse. See #request.
|
|
65
|
+
def delete(uri, opts = {}) request(DELETE, uri, opts) end
|
|
66
|
+
# Make a HEAD request and return a MockResponse. See #request.
|
|
67
|
+
def head(uri, opts = {}) request(HEAD, uri, opts) end
|
|
68
|
+
# Make an OPTIONS request and return a MockResponse. See #request.
|
|
69
|
+
def options(uri, opts = {}) request(OPTIONS, uri, opts) end
|
|
70
|
+
|
|
71
|
+
# Make a request using the given request method for the given
|
|
72
|
+
# uri to the rack application and return a MockResponse.
|
|
73
|
+
# Options given are passed to MockRequest.env_for.
|
|
74
|
+
def request(method = GET, uri = "", opts = {})
|
|
75
|
+
env = self.class.env_for(uri, opts.merge(method: method))
|
|
66
76
|
|
|
67
77
|
if opts[:lint]
|
|
68
78
|
app = Rack::Lint.new(@app)
|
|
@@ -71,7 +81,7 @@ module Rack
|
|
|
71
81
|
end
|
|
72
82
|
|
|
73
83
|
errors = env[RACK_ERRORS]
|
|
74
|
-
status, headers, body
|
|
84
|
+
status, headers, body = app.call(env)
|
|
75
85
|
MockResponse.new(status, headers, body, errors)
|
|
76
86
|
ensure
|
|
77
87
|
body.close if body.respond_to?(:close)
|
|
@@ -85,7 +95,14 @@ module Rack
|
|
|
85
95
|
end
|
|
86
96
|
|
|
87
97
|
# Return the Rack environment used for a request to +uri+.
|
|
88
|
-
|
|
98
|
+
# All options that are strings are added to the returned environment.
|
|
99
|
+
# Options:
|
|
100
|
+
# :fatal :: Whether to raise an exception if request outputs to rack.errors
|
|
101
|
+
# :input :: The rack.input to set
|
|
102
|
+
# :method :: The HTTP request method to use
|
|
103
|
+
# :params :: The params to use
|
|
104
|
+
# :script_name :: The SCRIPT_NAME to set
|
|
105
|
+
def self.env_for(uri = "", opts = {})
|
|
89
106
|
uri = parse_uri_rfc2396(uri)
|
|
90
107
|
uri.path = "/#{uri.path}" unless uri.path[0] == ?/
|
|
91
108
|
|
|
@@ -139,7 +156,7 @@ module Rack
|
|
|
139
156
|
rack_input.set_encoding(Encoding::BINARY)
|
|
140
157
|
env[RACK_INPUT] = rack_input
|
|
141
158
|
|
|
142
|
-
env["CONTENT_LENGTH"] ||= env[RACK_INPUT].
|
|
159
|
+
env["CONTENT_LENGTH"] ||= env[RACK_INPUT].size.to_s if env[RACK_INPUT].respond_to?(:size)
|
|
143
160
|
|
|
144
161
|
opts.each { |field, value|
|
|
145
162
|
env[field] = value if String === field
|
|
@@ -154,17 +171,24 @@ module Rack
|
|
|
154
171
|
# MockRequest.
|
|
155
172
|
|
|
156
173
|
class MockResponse < Rack::Response
|
|
174
|
+
class << self
|
|
175
|
+
alias [] new
|
|
176
|
+
end
|
|
177
|
+
|
|
157
178
|
# Headers
|
|
158
|
-
attr_reader :original_headers
|
|
179
|
+
attr_reader :original_headers, :cookies
|
|
159
180
|
|
|
160
181
|
# Errors
|
|
161
182
|
attr_accessor :errors
|
|
162
183
|
|
|
163
|
-
def initialize(status, headers, body, errors=StringIO.new(""))
|
|
184
|
+
def initialize(status, headers, body, errors = StringIO.new(""))
|
|
164
185
|
@original_headers = headers
|
|
165
186
|
@errors = errors.string if errors.respond_to?(:string)
|
|
187
|
+
@cookies = parse_cookies_from_header
|
|
166
188
|
|
|
167
189
|
super(body, status, headers)
|
|
190
|
+
|
|
191
|
+
buffered_body!
|
|
168
192
|
end
|
|
169
193
|
|
|
170
194
|
def =~(other)
|
|
@@ -186,11 +210,64 @@ module Rack
|
|
|
186
210
|
# ...
|
|
187
211
|
# res.body.should == "foo!"
|
|
188
212
|
# end
|
|
189
|
-
|
|
213
|
+
buffer = String.new
|
|
214
|
+
|
|
215
|
+
super.each do |chunk|
|
|
216
|
+
buffer << chunk
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
return buffer
|
|
190
220
|
end
|
|
191
221
|
|
|
192
222
|
def empty?
|
|
193
223
|
[201, 204, 304].include? status
|
|
194
224
|
end
|
|
225
|
+
|
|
226
|
+
def cookie(name)
|
|
227
|
+
cookies.fetch(name, nil)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
private
|
|
231
|
+
|
|
232
|
+
def parse_cookies_from_header
|
|
233
|
+
cookies = Hash.new
|
|
234
|
+
if original_headers.has_key? 'Set-Cookie'
|
|
235
|
+
set_cookie_header = original_headers.fetch('Set-Cookie')
|
|
236
|
+
set_cookie_header.split("\n").each do |cookie|
|
|
237
|
+
cookie_name, cookie_filling = cookie.split('=', 2)
|
|
238
|
+
cookie_attributes = identify_cookie_attributes cookie_filling
|
|
239
|
+
parsed_cookie = CGI::Cookie.new(
|
|
240
|
+
'name' => cookie_name.strip,
|
|
241
|
+
'value' => cookie_attributes.fetch('value'),
|
|
242
|
+
'path' => cookie_attributes.fetch('path', nil),
|
|
243
|
+
'domain' => cookie_attributes.fetch('domain', nil),
|
|
244
|
+
'expires' => cookie_attributes.fetch('expires', nil),
|
|
245
|
+
'secure' => cookie_attributes.fetch('secure', false)
|
|
246
|
+
)
|
|
247
|
+
cookies.store(cookie_name, parsed_cookie)
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
cookies
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def identify_cookie_attributes(cookie_filling)
|
|
254
|
+
cookie_bits = cookie_filling.split(';')
|
|
255
|
+
cookie_attributes = Hash.new
|
|
256
|
+
cookie_attributes.store('value', cookie_bits[0].strip)
|
|
257
|
+
cookie_bits.each do |bit|
|
|
258
|
+
if bit.include? '='
|
|
259
|
+
cookie_attribute, attribute_value = bit.split('=')
|
|
260
|
+
cookie_attributes.store(cookie_attribute.strip, attribute_value.strip)
|
|
261
|
+
if cookie_attribute.include? 'max-age'
|
|
262
|
+
cookie_attributes.store('expires', Time.now + attribute_value.strip.to_i)
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
if bit.include? 'secure'
|
|
266
|
+
cookie_attributes.store('secure', true)
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
cookie_attributes
|
|
270
|
+
end
|
|
271
|
+
|
|
195
272
|
end
|
|
196
273
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Rack
|
|
2
4
|
module Multipart
|
|
3
5
|
class Generator
|
|
@@ -15,9 +17,13 @@ module Rack
|
|
|
15
17
|
|
|
16
18
|
flattened_params.map do |name, file|
|
|
17
19
|
if file.respond_to?(:original_filename)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
if file.path
|
|
21
|
+
::File.open(file.path, 'rb') do |f|
|
|
22
|
+
f.set_encoding(Encoding::BINARY)
|
|
23
|
+
content_for_tempfile(f, file, name)
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
content_for_tempfile(file, file, name)
|
|
21
27
|
end
|
|
22
28
|
else
|
|
23
29
|
content_for_other(file, name)
|
|
@@ -27,21 +33,18 @@ module Rack
|
|
|
27
33
|
|
|
28
34
|
private
|
|
29
35
|
def multipart?
|
|
30
|
-
multipart = false
|
|
31
|
-
|
|
32
36
|
query = lambda { |value|
|
|
33
37
|
case value
|
|
34
38
|
when Array
|
|
35
|
-
value.
|
|
39
|
+
value.any?(&query)
|
|
36
40
|
when Hash
|
|
37
|
-
value.values.
|
|
41
|
+
value.values.any?(&query)
|
|
38
42
|
when Rack::Multipart::UploadedFile
|
|
39
|
-
|
|
43
|
+
true
|
|
40
44
|
end
|
|
41
45
|
}
|
|
42
|
-
@params.values.each(&query)
|
|
43
46
|
|
|
44
|
-
|
|
47
|
+
@params.values.any?(&query)
|
|
45
48
|
end
|
|
46
49
|
|
|
47
50
|
def flattened_params
|
|
@@ -70,12 +73,13 @@ module Rack
|
|
|
70
73
|
end
|
|
71
74
|
|
|
72
75
|
def content_for_tempfile(io, file, name)
|
|
76
|
+
length = ::File.stat(file.path).size if file.path
|
|
77
|
+
filename = "; filename=\"#{Utils.escape(file.original_filename)}\"" if file.original_filename
|
|
73
78
|
<<-EOF
|
|
74
79
|
--#{MULTIPART_BOUNDARY}\r
|
|
75
|
-
Content-Disposition: form-data; name="#{name}"
|
|
80
|
+
Content-Disposition: form-data; name="#{name}"#{filename}\r
|
|
76
81
|
Content-Type: #{file.content_type}\r
|
|
77
|
-
Content-Length: #{
|
|
78
|
-
\r
|
|
82
|
+
#{"Content-Length: #{length}\r\n" if length}\r
|
|
79
83
|
#{io.read}\r
|
|
80
84
|
EOF
|
|
81
85
|
end
|