rack 1.6.11 → 2.2.0
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 +675 -0
- data/CONTRIBUTING.md +136 -0
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +157 -163
- data/Rakefile +38 -32
- data/{SPEC → SPEC.rdoc} +41 -13
- data/bin/rackup +1 -0
- data/contrib/rack_logo.svg +164 -111
- data/example/lobster.ru +2 -0
- data/example/protectedlobster.rb +4 -2
- data/example/protectedlobster.ru +3 -1
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +6 -2
- 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 +5 -4
- data/lib/rack/auth/digest/request.rb +6 -4
- data/lib/rack/body_proxy.rb +21 -15
- data/lib/rack/builder.rb +119 -26
- data/lib/rack/cascade.rb +28 -12
- data/lib/rack/chunked.rb +70 -22
- data/lib/rack/common_logger.rb +80 -0
- data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -16
- data/lib/rack/config.rb +2 -0
- data/lib/rack/content_length.rb +9 -8
- data/lib/rack/content_type.rb +5 -4
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +60 -70
- data/lib/rack/directory.rb +117 -85
- data/lib/rack/etag.rb +9 -7
- data/lib/rack/events.rb +153 -0
- data/lib/rack/file.rb +4 -149
- data/lib/rack/files.rb +218 -0
- data/lib/rack/handler/cgi.rb +17 -19
- data/lib/rack/handler/fastcgi.rb +17 -18
- data/lib/rack/handler/lsws.rb +14 -14
- data/lib/rack/handler/scgi.rb +22 -21
- data/lib/rack/handler/thin.rb +20 -11
- data/lib/rack/handler/webrick.rb +39 -32
- data/lib/rack/handler.rb +9 -26
- data/lib/rack/head.rb +16 -18
- data/lib/rack/lint.rb +110 -64
- data/lib/rack/lobster.rb +10 -10
- data/lib/rack/lock.rb +17 -11
- data/lib/rack/logger.rb +4 -2
- data/lib/rack/media_type.rb +43 -0
- data/lib/rack/{methodoverride.rb → method_override.rb} +10 -8
- data/lib/rack/mime.rb +27 -6
- data/lib/rack/mock.rb +124 -65
- data/lib/rack/multipart/generator.rb +20 -16
- data/lib/rack/multipart/parser.rb +273 -162
- data/lib/rack/multipart/uploaded_file.rb +15 -8
- data/lib/rack/multipart.rb +39 -8
- data/lib/rack/{nulllogger.rb → null_logger.rb} +3 -1
- data/lib/rack/query_parser.rb +217 -0
- data/lib/rack/recursive.rb +11 -9
- data/lib/rack/reloader.rb +8 -4
- data/lib/rack/request.rb +543 -305
- data/lib/rack/response.rb +244 -88
- data/lib/rack/rewindable_input.rb +5 -15
- data/lib/rack/runtime.rb +12 -18
- data/lib/rack/sendfile.rb +17 -15
- data/lib/rack/server.rb +125 -47
- data/lib/rack/session/abstract/id.rb +216 -93
- data/lib/rack/session/cookie.rb +47 -31
- data/lib/rack/session/memcache.rb +4 -87
- data/lib/rack/session/pool.rb +26 -17
- data/lib/rack/show_exceptions.rb +390 -0
- data/lib/rack/{showstatus.rb → show_status.rb} +8 -8
- data/lib/rack/static.rb +48 -11
- data/lib/rack/tempfile_reaper.rb +3 -3
- data/lib/rack/urlmap.rb +26 -19
- data/lib/rack/utils.rb +208 -294
- data/lib/rack/version.rb +29 -0
- data/lib/rack.rb +76 -33
- data/rack.gemspec +43 -30
- metadata +62 -183
- data/HISTORY.md +0 -375
- 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/commonlogger.rb +0 -72
- 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/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 -8
- data/test/cgi/test.ru +0 -5
- data/test/gemloader.rb +0 -10
- 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_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_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/semicolon +0 -6
- data/test/multipart/text +0 -15
- data/test/multipart/three_files_three_fields +0 -31
- 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 -81
- data/test/spec_auth_digest.rb +0 -259
- data/test/spec_body_proxy.rb +0 -85
- data/test/spec_builder.rb +0 -223
- data/test/spec_cascade.rb +0 -61
- data/test/spec_cgi.rb +0 -102
- data/test/spec_chunked.rb +0 -101
- data/test/spec_commonlogger.rb +0 -93
- data/test/spec_conditionalget.rb +0 -102
- data/test/spec_config.rb +0 -22
- data/test/spec_content_length.rb +0 -85
- data/test/spec_content_type.rb +0 -45
- data/test/spec_deflater.rb +0 -339
- data/test/spec_directory.rb +0 -88
- data/test/spec_etag.rb +0 -107
- data/test/spec_fastcgi.rb +0 -107
- data/test/spec_file.rb +0 -221
- data/test/spec_handler.rb +0 -72
- data/test/spec_head.rb +0 -45
- data/test/spec_lint.rb +0 -550
- data/test/spec_lobster.rb +0 -58
- data/test/spec_lock.rb +0 -164
- data/test/spec_logger.rb +0 -23
- data/test/spec_methodoverride.rb +0 -111
- data/test/spec_mime.rb +0 -51
- data/test/spec_mock.rb +0 -297
- data/test/spec_mongrel.rb +0 -182
- data/test/spec_multipart.rb +0 -600
- data/test/spec_nulllogger.rb +0 -20
- data/test/spec_recursive.rb +0 -72
- data/test/spec_request.rb +0 -1232
- data/test/spec_response.rb +0 -407
- data/test/spec_rewindable_input.rb +0 -118
- data/test/spec_runtime.rb +0 -49
- data/test/spec_sendfile.rb +0 -130
- data/test/spec_server.rb +0 -167
- data/test/spec_session_abstract_id.rb +0 -53
- data/test/spec_session_cookie.rb +0 -410
- data/test/spec_session_memcache.rb +0 -321
- data/test/spec_session_pool.rb +0 -209
- data/test/spec_showexceptions.rb +0 -98
- data/test/spec_showstatus.rb +0 -103
- data/test/spec_static.rb +0 -145
- data/test/spec_tempfile_reaper.rb +0 -63
- data/test/spec_thin.rb +0 -91
- data/test/spec_urlmap.rb +0 -236
- data/test/spec_utils.rb +0 -647
- data/test/spec_version.rb +0 -17
- data/test/spec_webrick.rb +0 -184
- data/test/static/another/index.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/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
|
@@ -45,11 +47,6 @@ module Rack
|
|
45
47
|
#
|
46
48
|
# N.B. On Ubuntu the mime.types file does not include the leading period, so
|
47
49
|
# 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
50
|
|
54
51
|
MIME_TYPES = {
|
55
52
|
".123" => "application/vnd.lotus-1-2-3",
|
@@ -154,8 +151,11 @@ module Rack
|
|
154
151
|
".dmg" => "application/octet-stream",
|
155
152
|
".dna" => "application/vnd.dna",
|
156
153
|
".doc" => "application/msword",
|
154
|
+
".docm" => "application/vnd.ms-word.document.macroEnabled.12",
|
157
155
|
".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
158
156
|
".dot" => "application/msword",
|
157
|
+
".dotm" => "application/vnd.ms-word.template.macroEnabled.12",
|
158
|
+
".dotx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
|
159
159
|
".dp" => "application/vnd.osgi.dp",
|
160
160
|
".dpg" => "application/vnd.dpgraph",
|
161
161
|
".dsc" => "text/prs.lines.tag",
|
@@ -308,6 +308,7 @@ module Rack
|
|
308
308
|
".lvp" => "audio/vnd.lucent.voice",
|
309
309
|
".lwp" => "application/vnd.lotus-wordpro",
|
310
310
|
".m3u" => "audio/x-mpegurl",
|
311
|
+
".m3u8" => "application/x-mpegurl",
|
311
312
|
".m4a" => "audio/mp4a-latm",
|
312
313
|
".m4v" => "video/mp4",
|
313
314
|
".ma" => "application/mathematica",
|
@@ -345,6 +346,7 @@ module Rack
|
|
345
346
|
".mp4s" => "application/mp4",
|
346
347
|
".mp4v" => "video/mp4",
|
347
348
|
".mpc" => "application/vnd.mophun.certificate",
|
349
|
+
".mpd" => "application/dash+xml",
|
348
350
|
".mpeg" => "video/mpeg",
|
349
351
|
".mpg" => "video/mpeg",
|
350
352
|
".mpga" => "audio/mpeg",
|
@@ -444,10 +446,19 @@ module Rack
|
|
444
446
|
".pnm" => "image/x-portable-anymap",
|
445
447
|
".pntg" => "image/x-macpaint",
|
446
448
|
".portpkg" => "application/vnd.macports.portpkg",
|
449
|
+
".pot" => "application/vnd.ms-powerpoint",
|
450
|
+
".potm" => "application/vnd.ms-powerpoint.template.macroEnabled.12",
|
451
|
+
".potx" => "application/vnd.openxmlformats-officedocument.presentationml.template",
|
452
|
+
".ppa" => "application/vnd.ms-powerpoint",
|
453
|
+
".ppam" => "application/vnd.ms-powerpoint.addin.macroEnabled.12",
|
447
454
|
".ppd" => "application/vnd.cups-ppd",
|
448
455
|
".ppm" => "image/x-portable-pixmap",
|
449
456
|
".pps" => "application/vnd.ms-powerpoint",
|
457
|
+
".ppsm" => "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
|
458
|
+
".ppsx" => "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
|
450
459
|
".ppt" => "application/vnd.ms-powerpoint",
|
460
|
+
".pptm" => "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
|
461
|
+
".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
451
462
|
".prc" => "application/vnd.palm",
|
452
463
|
".pre" => "application/vnd.lotus-freelance",
|
453
464
|
".prf" => "application/pics-rules",
|
@@ -535,6 +546,7 @@ module Rack
|
|
535
546
|
".spp" => "application/scvp-vp-response",
|
536
547
|
".spq" => "application/scvp-vp-request",
|
537
548
|
".src" => "application/x-wais-source",
|
549
|
+
".srt" => "text/srt",
|
538
550
|
".srx" => "application/sparql-results+xml",
|
539
551
|
".sse" => "application/vnd.kodak-descriptor",
|
540
552
|
".ssf" => "application/vnd.epson.ssf",
|
@@ -569,6 +581,7 @@ module Rack
|
|
569
581
|
".tr" => "text/troff",
|
570
582
|
".tra" => "application/vnd.trueapp",
|
571
583
|
".trm" => "application/x-msterminal",
|
584
|
+
".ts" => "video/mp2t",
|
572
585
|
".tsv" => "text/tab-separated-values",
|
573
586
|
".ttf" => "application/octet-stream",
|
574
587
|
".twd" => "application/vnd.simtech-mindmapper",
|
@@ -593,9 +606,11 @@ module Rack
|
|
593
606
|
".vrml" => "model/vrml",
|
594
607
|
".vsd" => "application/vnd.visio",
|
595
608
|
".vsf" => "application/vnd.vsf",
|
609
|
+
".vtt" => "text/vtt",
|
596
610
|
".vtu" => "model/vnd.vtu",
|
597
611
|
".vxml" => "application/voicexml+xml",
|
598
612
|
".war" => "application/java-archive",
|
613
|
+
".wasm" => "application/wasm",
|
599
614
|
".wav" => "audio/x-wav",
|
600
615
|
".wax" => "audio/x-ms-wax",
|
601
616
|
".wbmp" => "image/vnd.wap.wbmp",
|
@@ -638,8 +653,14 @@ module Rack
|
|
638
653
|
".xfdl" => "application/vnd.xfdl",
|
639
654
|
".xhtml" => "application/xhtml+xml",
|
640
655
|
".xif" => "image/vnd.xiff",
|
656
|
+
".xla" => "application/vnd.ms-excel",
|
657
|
+
".xlam" => "application/vnd.ms-excel.addin.macroEnabled.12",
|
641
658
|
".xls" => "application/vnd.ms-excel",
|
659
|
+
".xlsb" => "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
|
642
660
|
".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
661
|
+
".xlsm" => "application/vnd.ms-excel.sheet.macroEnabled.12",
|
662
|
+
".xlt" => "application/vnd.ms-excel",
|
663
|
+
".xltx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
|
643
664
|
".xml" => "application/xml",
|
644
665
|
".xo" => "application/vnd.olpc-sugar",
|
645
666
|
".xop" => "application/xop+xml",
|
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
|
@@ -41,28 +41,38 @@ module Rack
|
|
41
41
|
end
|
42
42
|
|
43
43
|
DEFAULT_ENV = {
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
}
|
44
|
+
RACK_VERSION => Rack::VERSION,
|
45
|
+
RACK_INPUT => StringIO.new,
|
46
|
+
RACK_ERRORS => StringIO.new,
|
47
|
+
RACK_MULTITHREAD => true,
|
48
|
+
RACK_MULTIPROCESS => true,
|
49
|
+
RACK_RUNONCE => false,
|
50
|
+
}.freeze
|
51
51
|
|
52
52
|
def initialize(app)
|
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)
|
@@ -70,49 +80,62 @@ module Rack
|
|
70
80
|
app = @app
|
71
81
|
end
|
72
82
|
|
73
|
-
errors = env[
|
74
|
-
status, headers, body
|
83
|
+
errors = env[RACK_ERRORS]
|
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)
|
78
88
|
end
|
79
89
|
|
80
|
-
# For historical reasons, we're pinning to RFC 2396.
|
81
|
-
#
|
90
|
+
# For historical reasons, we're pinning to RFC 2396.
|
91
|
+
# URI::Parser = URI::RFC2396_Parser
|
82
92
|
def self.parse_uri_rfc2396(uri)
|
83
|
-
@parser ||=
|
93
|
+
@parser ||= URI::Parser.new
|
84
94
|
@parser.parse(uri)
|
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
|
|
92
109
|
env = DEFAULT_ENV.dup
|
93
110
|
|
94
|
-
|
111
|
+
env[REQUEST_METHOD] = (opts[:method] ? opts[:method].to_s.upcase : GET).b
|
112
|
+
env[SERVER_NAME] = (uri.host || "example.org").b
|
113
|
+
env[SERVER_PORT] = (uri.port ? uri.port.to_s : "80").b
|
114
|
+
env[QUERY_STRING] = (uri.query.to_s).b
|
115
|
+
env[PATH_INFO] = ((!uri.path || uri.path.empty?) ? "/" : uri.path).b
|
116
|
+
env[RACK_URL_SCHEME] = (uri.scheme || "http").b
|
117
|
+
env[HTTPS] = (env[RACK_URL_SCHEME] == "https" ? "on" : "off").b
|
95
118
|
|
96
119
|
env[SCRIPT_NAME] = opts[:script_name] || ""
|
97
120
|
|
98
121
|
if opts[:fatal]
|
99
|
-
env[
|
122
|
+
env[RACK_ERRORS] = FatalWarner.new
|
100
123
|
else
|
101
|
-
env[
|
124
|
+
env[RACK_ERRORS] = StringIO.new
|
102
125
|
end
|
103
126
|
|
104
127
|
if params = opts[:params]
|
105
|
-
if env[REQUEST_METHOD] ==
|
128
|
+
if env[REQUEST_METHOD] == GET
|
106
129
|
params = Utils.parse_nested_query(params) if params.is_a?(String)
|
107
130
|
params.update(Utils.parse_nested_query(env[QUERY_STRING]))
|
108
131
|
env[QUERY_STRING] = Utils.build_nested_query(params)
|
109
132
|
elsif !opts.has_key?(:input)
|
110
133
|
opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
|
111
134
|
if params.is_a?(Hash)
|
112
|
-
if data =
|
135
|
+
if data = Rack::Multipart.build_multipart(params)
|
113
136
|
opts[:input] = data
|
114
137
|
opts["CONTENT_LENGTH"] ||= data.length.to_s
|
115
|
-
opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{
|
138
|
+
opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Rack::Multipart::MULTIPART_BOUNDARY}"
|
116
139
|
else
|
117
140
|
opts[:input] = Utils.build_nested_query(params)
|
118
141
|
end
|
@@ -122,8 +145,7 @@ module Rack
|
|
122
145
|
end
|
123
146
|
end
|
124
147
|
|
125
|
-
empty_str =
|
126
|
-
empty_str.force_encoding("ASCII-8BIT") if empty_str.respond_to? :force_encoding
|
148
|
+
empty_str = String.new
|
127
149
|
opts[:input] ||= empty_str
|
128
150
|
if String === opts[:input]
|
129
151
|
rack_input = StringIO.new(opts[:input])
|
@@ -131,10 +153,10 @@ module Rack
|
|
131
153
|
rack_input = opts[:input]
|
132
154
|
end
|
133
155
|
|
134
|
-
rack_input.set_encoding(Encoding::BINARY)
|
135
|
-
env[
|
156
|
+
rack_input.set_encoding(Encoding::BINARY)
|
157
|
+
env[RACK_INPUT] = rack_input
|
136
158
|
|
137
|
-
env["CONTENT_LENGTH"] ||= env[
|
159
|
+
env["CONTENT_LENGTH"] ||= env[RACK_INPUT].size.to_s if env[RACK_INPUT].respond_to?(:size)
|
138
160
|
|
139
161
|
opts.each { |field, value|
|
140
162
|
env[field] = value if String === field
|
@@ -142,28 +164,6 @@ module Rack
|
|
142
164
|
|
143
165
|
env
|
144
166
|
end
|
145
|
-
|
146
|
-
if "<3".respond_to? :b
|
147
|
-
def self.env_with_encoding(env, opts, uri)
|
148
|
-
env[REQUEST_METHOD] = (opts[:method] ? opts[:method].to_s.upcase : "GET").b
|
149
|
-
env["SERVER_NAME"] = (uri.host || "example.org").b
|
150
|
-
env["SERVER_PORT"] = (uri.port ? uri.port.to_s : "80").b
|
151
|
-
env[QUERY_STRING] = (uri.query.to_s).b
|
152
|
-
env[PATH_INFO] = ((!uri.path || uri.path.empty?) ? "/" : uri.path).b
|
153
|
-
env["rack.url_scheme"] = (uri.scheme || "http").b
|
154
|
-
env["HTTPS"] = (env["rack.url_scheme"] == "https" ? "on" : "off").b
|
155
|
-
end
|
156
|
-
else
|
157
|
-
def self.env_with_encoding(env, opts, uri)
|
158
|
-
env[REQUEST_METHOD] = opts[:method] ? opts[:method].to_s.upcase : "GET"
|
159
|
-
env["SERVER_NAME"] = uri.host || "example.org"
|
160
|
-
env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80"
|
161
|
-
env[QUERY_STRING] = uri.query.to_s
|
162
|
-
env[PATH_INFO] = (!uri.path || uri.path.empty?) ? "/" : uri.path
|
163
|
-
env["rack.url_scheme"] = uri.scheme || "http"
|
164
|
-
env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off"
|
165
|
-
end
|
166
|
-
end
|
167
167
|
end
|
168
168
|
|
169
169
|
# Rack::MockResponse provides useful helpers for testing your apps.
|
@@ -171,18 +171,24 @@ module Rack
|
|
171
171
|
# MockRequest.
|
172
172
|
|
173
173
|
class MockResponse < Rack::Response
|
174
|
+
class << self
|
175
|
+
alias [] new
|
176
|
+
end
|
177
|
+
|
174
178
|
# Headers
|
175
|
-
attr_reader :original_headers
|
179
|
+
attr_reader :original_headers, :cookies
|
176
180
|
|
177
181
|
# Errors
|
178
182
|
attr_accessor :errors
|
179
183
|
|
180
|
-
def initialize(status, headers, body, errors=StringIO.new(""))
|
184
|
+
def initialize(status, headers, body, errors = StringIO.new(""))
|
181
185
|
@original_headers = headers
|
182
186
|
@errors = errors.string if errors.respond_to?(:string)
|
183
|
-
@
|
187
|
+
@cookies = parse_cookies_from_header
|
184
188
|
|
185
189
|
super(body, status, headers)
|
190
|
+
|
191
|
+
buffered_body!
|
186
192
|
end
|
187
193
|
|
188
194
|
def =~(other)
|
@@ -204,11 +210,64 @@ module Rack
|
|
204
210
|
# ...
|
205
211
|
# res.body.should == "foo!"
|
206
212
|
# end
|
207
|
-
|
213
|
+
buffer = String.new
|
214
|
+
|
215
|
+
super.each do |chunk|
|
216
|
+
buffer << chunk
|
217
|
+
end
|
218
|
+
|
219
|
+
return buffer
|
208
220
|
end
|
209
221
|
|
210
222
|
def empty?
|
211
|
-
[201, 204,
|
223
|
+
[201, 204, 304].include? status
|
212
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
|
+
|
213
272
|
end
|
214
273
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rack
|
2
4
|
module Multipart
|
3
5
|
class Generator
|
@@ -11,37 +13,38 @@ module Rack
|
|
11
13
|
|
12
14
|
def dump
|
13
15
|
return nil if @first && !multipart?
|
14
|
-
return flattened_params
|
16
|
+
return flattened_params unless @first
|
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)
|
24
30
|
end
|
25
|
-
end.join
|
31
|
+
end.join << "--#{MULTIPART_BOUNDARY}--\r"
|
26
32
|
end
|
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
|
@@ -90,4 +94,4 @@ EOF
|
|
90
94
|
end
|
91
95
|
end
|
92
96
|
end
|
93
|
-
end
|
97
|
+
end
|