rack 1.4.7 → 2.1.4
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/CHANGELOG.md +77 -0
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +122 -456
- data/Rakefile +32 -31
- data/SPEC +119 -29
- 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 +7 -5
- data/lib/rack/auth/abstract/request.rb +8 -6
- data/lib/rack/auth/basic.rb +5 -2
- data/lib/rack/auth/digest/md5.rb +10 -8
- 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 +4 -2
- data/lib/rack/body_proxy.rb +11 -9
- data/lib/rack/builder.rb +63 -20
- data/lib/rack/cascade.rb +10 -9
- data/lib/rack/chunked.rb +45 -11
- data/lib/rack/{commonlogger.rb → common_logger.rb} +24 -15
- data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -6
- data/lib/rack/config.rb +7 -0
- data/lib/rack/content_length.rb +12 -6
- data/lib/rack/content_type.rb +4 -2
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +73 -42
- data/lib/rack/directory.rb +77 -56
- data/lib/rack/etag.rb +25 -13
- data/lib/rack/events.rb +156 -0
- data/lib/rack/file.rb +4 -143
- data/lib/rack/files.rb +178 -0
- data/lib/rack/handler/cgi.rb +18 -17
- data/lib/rack/handler/fastcgi.rb +21 -17
- data/lib/rack/handler/lsws.rb +14 -12
- data/lib/rack/handler/scgi.rb +27 -21
- data/lib/rack/handler/thin.rb +19 -5
- data/lib/rack/handler/webrick.rb +66 -24
- data/lib/rack/handler.rb +29 -19
- data/lib/rack/head.rb +21 -14
- data/lib/rack/lint.rb +259 -65
- data/lib/rack/lobster.rb +17 -10
- data/lib/rack/lock.rb +19 -10
- data/lib/rack/logger.rb +4 -2
- data/lib/rack/media_type.rb +43 -0
- data/lib/rack/method_override.rb +52 -0
- data/lib/rack/mime.rb +43 -6
- data/lib/rack/mock.rb +109 -44
- data/lib/rack/multipart/generator.rb +11 -12
- data/lib/rack/multipart/parser.rb +302 -115
- data/lib/rack/multipart/uploaded_file.rb +4 -3
- data/lib/rack/multipart.rb +40 -9
- data/lib/rack/null_logger.rb +39 -0
- data/lib/rack/query_parser.rb +218 -0
- data/lib/rack/recursive.rb +14 -11
- data/lib/rack/reloader.rb +12 -5
- data/lib/rack/request.rb +484 -270
- data/lib/rack/response.rb +196 -77
- data/lib/rack/rewindable_input.rb +5 -14
- data/lib/rack/runtime.rb +13 -6
- data/lib/rack/sendfile.rb +44 -20
- data/lib/rack/server.rb +175 -61
- data/lib/rack/session/abstract/id.rb +276 -133
- data/lib/rack/session/cookie.rb +75 -40
- data/lib/rack/session/memcache.rb +4 -87
- data/lib/rack/session/pool.rb +24 -18
- data/lib/rack/show_exceptions.rb +392 -0
- data/lib/rack/{showstatus.rb → show_status.rb} +11 -9
- data/lib/rack/static.rb +65 -38
- data/lib/rack/tempfile_reaper.rb +24 -0
- data/lib/rack/urlmap.rb +40 -15
- data/lib/rack/utils.rb +316 -285
- data/lib/rack.rb +78 -23
- data/rack.gemspec +26 -19
- metadata +44 -209
- data/KNOWN-ISSUES +0 -30
- 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 -100
- data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
- data/lib/rack/methodoverride.rb +0 -33
- data/lib/rack/nulllogger.rb +0 -18
- data/lib/rack/showexceptions.rb +0 -378
- 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/lighttpd.errors +0 -1
- 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_with_escaped_quotes +0 -6
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +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/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.rb +0 -57
- data/test/spec_auth_basic.rb +0 -81
- data/test/spec_auth_digest.rb +0 -259
- data/test/spec_body_proxy.rb +0 -69
- data/test/spec_builder.rb +0 -207
- data/test/spec_cascade.rb +0 -61
- data/test/spec_cgi.rb +0 -102
- data/test/spec_chunked.rb +0 -87
- data/test/spec_commonlogger.rb +0 -57
- data/test/spec_conditionalget.rb +0 -102
- data/test/spec_config.rb +0 -22
- data/test/spec_content_length.rb +0 -86
- data/test/spec_content_type.rb +0 -45
- data/test/spec_deflater.rb +0 -187
- data/test/spec_directory.rb +0 -88
- data/test/spec_etag.rb +0 -98
- data/test/spec_fastcgi.rb +0 -107
- data/test/spec_file.rb +0 -200
- data/test/spec_handler.rb +0 -59
- data/test/spec_head.rb +0 -48
- data/test/spec_lint.rb +0 -515
- data/test/spec_lobster.rb +0 -58
- data/test/spec_lock.rb +0 -167
- data/test/spec_logger.rb +0 -23
- data/test/spec_methodoverride.rb +0 -72
- data/test/spec_mock.rb +0 -269
- data/test/spec_mongrel.rb +0 -182
- data/test/spec_multipart.rb +0 -479
- data/test/spec_nulllogger.rb +0 -23
- data/test/spec_recursive.rb +0 -72
- data/test/spec_request.rb +0 -955
- data/test/spec_response.rb +0 -313
- data/test/spec_rewindable_input.rb +0 -118
- data/test/spec_runtime.rb +0 -49
- data/test/spec_sendfile.rb +0 -90
- data/test/spec_server.rb +0 -121
- data/test/spec_session_abstract_id.rb +0 -43
- data/test/spec_session_cookie.rb +0 -361
- data/test/spec_session_memcache.rb +0 -321
- data/test/spec_session_pool.rb +0 -209
- data/test/spec_showexceptions.rb +0 -92
- data/test/spec_showstatus.rb +0 -84
- data/test/spec_static.rb +0 -145
- data/test/spec_thin.rb +0 -86
- data/test/spec_urlmap.rb +0 -213
- data/test/spec_utils.rb +0 -554
- data/test/spec_webrick.rb +0 -143
- 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
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class MethodOverride
|
5
|
+
HTTP_METHODS = %w[GET HEAD PUT POST DELETE OPTIONS PATCH LINK UNLINK]
|
6
|
+
|
7
|
+
METHOD_OVERRIDE_PARAM_KEY = "_method"
|
8
|
+
HTTP_METHOD_OVERRIDE_HEADER = "HTTP_X_HTTP_METHOD_OVERRIDE"
|
9
|
+
ALLOWED_METHODS = %w[POST]
|
10
|
+
|
11
|
+
def initialize(app)
|
12
|
+
@app = app
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
if allowed_methods.include?(env[REQUEST_METHOD])
|
17
|
+
method = method_override(env)
|
18
|
+
if HTTP_METHODS.include?(method)
|
19
|
+
env[RACK_METHODOVERRIDE_ORIGINAL_METHOD] = env[REQUEST_METHOD]
|
20
|
+
env[REQUEST_METHOD] = method
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
@app.call(env)
|
25
|
+
end
|
26
|
+
|
27
|
+
def method_override(env)
|
28
|
+
req = Request.new(env)
|
29
|
+
method = method_override_param(req) ||
|
30
|
+
env[HTTP_METHOD_OVERRIDE_HEADER]
|
31
|
+
begin
|
32
|
+
method.to_s.upcase
|
33
|
+
rescue ArgumentError
|
34
|
+
env[RACK_ERRORS].puts "Invalid string for method"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def allowed_methods
|
41
|
+
ALLOWED_METHODS
|
42
|
+
end
|
43
|
+
|
44
|
+
def method_override_param(req)
|
45
|
+
req.POST[METHOD_OVERRIDE_PARAM_KEY]
|
46
|
+
rescue Utils::InvalidParameterError, Utils::ParameterTypeError
|
47
|
+
req.get_header(RACK_ERRORS).puts "Invalid or incomplete POST params"
|
48
|
+
rescue EOFError
|
49
|
+
req.get_header(RACK_ERRORS).puts "Bad request content body"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
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,11 +15,26 @@ 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
|
20
22
|
|
23
|
+
# Returns true if the given value is a mime match for the given mime match
|
24
|
+
# specification, false otherwise.
|
25
|
+
#
|
26
|
+
# Rack::Mime.match?('text/html', 'text/*') => true
|
27
|
+
# Rack::Mime.match?('text/plain', '*') => true
|
28
|
+
# Rack::Mime.match?('text/html', 'application/json') => false
|
29
|
+
|
30
|
+
def match?(value, matcher)
|
31
|
+
v1, v2 = value.split('/', 2)
|
32
|
+
m1, m2 = matcher.split('/', 2)
|
33
|
+
|
34
|
+
(m1 == '*' || v1 == m1) && (m2.nil? || m2 == '*' || m2 == v2)
|
35
|
+
end
|
36
|
+
module_function :match?
|
37
|
+
|
21
38
|
# List of most common mime-types, selected various sources
|
22
39
|
# according to their usefulness in a webserving scope for Ruby
|
23
40
|
# users.
|
@@ -30,11 +47,6 @@ module Rack
|
|
30
47
|
#
|
31
48
|
# N.B. On Ubuntu the mime.types file does not include the leading period, so
|
32
49
|
# users may need to modify the data before merging into the hash.
|
33
|
-
#
|
34
|
-
# To add the list mongrel provides, use:
|
35
|
-
#
|
36
|
-
# require 'mongrel/handlers'
|
37
|
-
# Rack::Mime::MIME_TYPES.merge!(Mongrel::DirHandler::MIME_TYPES)
|
38
50
|
|
39
51
|
MIME_TYPES = {
|
40
52
|
".123" => "application/vnd.lotus-1-2-3",
|
@@ -139,8 +151,11 @@ module Rack
|
|
139
151
|
".dmg" => "application/octet-stream",
|
140
152
|
".dna" => "application/vnd.dna",
|
141
153
|
".doc" => "application/msword",
|
154
|
+
".docm" => "application/vnd.ms-word.document.macroEnabled.12",
|
142
155
|
".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
143
156
|
".dot" => "application/msword",
|
157
|
+
".dotm" => "application/vnd.ms-word.template.macroEnabled.12",
|
158
|
+
".dotx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
|
144
159
|
".dp" => "application/vnd.osgi.dp",
|
145
160
|
".dpg" => "application/vnd.dpgraph",
|
146
161
|
".dsc" => "text/prs.lines.tag",
|
@@ -293,6 +308,7 @@ module Rack
|
|
293
308
|
".lvp" => "audio/vnd.lucent.voice",
|
294
309
|
".lwp" => "application/vnd.lotus-wordpro",
|
295
310
|
".m3u" => "audio/x-mpegurl",
|
311
|
+
".m3u8" => "application/x-mpegurl",
|
296
312
|
".m4a" => "audio/mp4a-latm",
|
297
313
|
".m4v" => "video/mp4",
|
298
314
|
".ma" => "application/mathematica",
|
@@ -330,6 +346,7 @@ module Rack
|
|
330
346
|
".mp4s" => "application/mp4",
|
331
347
|
".mp4v" => "video/mp4",
|
332
348
|
".mpc" => "application/vnd.mophun.certificate",
|
349
|
+
".mpd" => "application/dash+xml",
|
333
350
|
".mpeg" => "video/mpeg",
|
334
351
|
".mpg" => "video/mpeg",
|
335
352
|
".mpga" => "audio/mpeg",
|
@@ -429,10 +446,19 @@ module Rack
|
|
429
446
|
".pnm" => "image/x-portable-anymap",
|
430
447
|
".pntg" => "image/x-macpaint",
|
431
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",
|
432
454
|
".ppd" => "application/vnd.cups-ppd",
|
433
455
|
".ppm" => "image/x-portable-pixmap",
|
434
456
|
".pps" => "application/vnd.ms-powerpoint",
|
457
|
+
".ppsm" => "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
|
458
|
+
".ppsx" => "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
|
435
459
|
".ppt" => "application/vnd.ms-powerpoint",
|
460
|
+
".pptm" => "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
|
461
|
+
".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
436
462
|
".prc" => "application/vnd.palm",
|
437
463
|
".pre" => "application/vnd.lotus-freelance",
|
438
464
|
".prf" => "application/pics-rules",
|
@@ -520,6 +546,7 @@ module Rack
|
|
520
546
|
".spp" => "application/scvp-vp-response",
|
521
547
|
".spq" => "application/scvp-vp-request",
|
522
548
|
".src" => "application/x-wais-source",
|
549
|
+
".srt" => "text/srt",
|
523
550
|
".srx" => "application/sparql-results+xml",
|
524
551
|
".sse" => "application/vnd.kodak-descriptor",
|
525
552
|
".ssf" => "application/vnd.epson.ssf",
|
@@ -554,6 +581,7 @@ module Rack
|
|
554
581
|
".tr" => "text/troff",
|
555
582
|
".tra" => "application/vnd.trueapp",
|
556
583
|
".trm" => "application/x-msterminal",
|
584
|
+
".ts" => "video/mp2t",
|
557
585
|
".tsv" => "text/tab-separated-values",
|
558
586
|
".ttf" => "application/octet-stream",
|
559
587
|
".twd" => "application/vnd.simtech-mindmapper",
|
@@ -578,9 +606,11 @@ module Rack
|
|
578
606
|
".vrml" => "model/vrml",
|
579
607
|
".vsd" => "application/vnd.visio",
|
580
608
|
".vsf" => "application/vnd.vsf",
|
609
|
+
".vtt" => "text/vtt",
|
581
610
|
".vtu" => "model/vnd.vtu",
|
582
611
|
".vxml" => "application/voicexml+xml",
|
583
612
|
".war" => "application/java-archive",
|
613
|
+
".wasm" => "application/wasm",
|
584
614
|
".wav" => "audio/x-wav",
|
585
615
|
".wax" => "audio/x-ms-wax",
|
586
616
|
".wbmp" => "image/vnd.wap.wbmp",
|
@@ -599,6 +629,7 @@ module Rack
|
|
599
629
|
".wmx" => "video/x-ms-wmx",
|
600
630
|
".wmz" => "application/x-ms-wmz",
|
601
631
|
".woff" => "application/font-woff",
|
632
|
+
".woff2" => "application/font-woff2",
|
602
633
|
".wpd" => "application/vnd.wordperfect",
|
603
634
|
".wpl" => "application/vnd.ms-wpl",
|
604
635
|
".wps" => "application/vnd.ms-works",
|
@@ -622,8 +653,14 @@ module Rack
|
|
622
653
|
".xfdl" => "application/vnd.xfdl",
|
623
654
|
".xhtml" => "application/xhtml+xml",
|
624
655
|
".xif" => "image/vnd.xiff",
|
656
|
+
".xla" => "application/vnd.ms-excel",
|
657
|
+
".xlam" => "application/vnd.ms-excel.addin.macroEnabled.12",
|
625
658
|
".xls" => "application/vnd.ms-excel",
|
659
|
+
".xlsb" => "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
|
626
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",
|
627
664
|
".xml" => "application/xml",
|
628
665
|
".xo" => "application/vnd.olpc-sugar",
|
629
666
|
".xop" => "application/xop+xml",
|
data/lib/rack/mock.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
require 'stringio'
|
3
5
|
require 'rack'
|
4
6
|
require 'rack/lint'
|
5
7
|
require 'rack/utils'
|
6
8
|
require 'rack/response'
|
9
|
+
require 'cgi/cookie'
|
7
10
|
|
8
11
|
module Rack
|
9
12
|
# Rack::MockRequest helps testing your Rack application without
|
@@ -41,27 +44,28 @@ module Rack
|
|
41
44
|
end
|
42
45
|
|
43
46
|
DEFAULT_ENV = {
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
}
|
47
|
+
RACK_VERSION => Rack::VERSION,
|
48
|
+
RACK_INPUT => StringIO.new,
|
49
|
+
RACK_ERRORS => StringIO.new,
|
50
|
+
RACK_MULTITHREAD => true,
|
51
|
+
RACK_MULTIPROCESS => true,
|
52
|
+
RACK_RUNONCE => false,
|
53
|
+
}.freeze
|
51
54
|
|
52
55
|
def initialize(app)
|
53
56
|
@app = app
|
54
57
|
end
|
55
58
|
|
56
|
-
def get(uri, opts={})
|
57
|
-
def post(uri, opts={})
|
58
|
-
def put(uri, opts={})
|
59
|
-
def patch(uri, opts={})
|
60
|
-
def delete(uri, opts={})
|
61
|
-
def head(uri, opts={})
|
59
|
+
def get(uri, opts = {}) request(GET, uri, opts) end
|
60
|
+
def post(uri, opts = {}) request(POST, uri, opts) end
|
61
|
+
def put(uri, opts = {}) request(PUT, uri, opts) end
|
62
|
+
def patch(uri, opts = {}) request(PATCH, uri, opts) end
|
63
|
+
def delete(uri, opts = {}) request(DELETE, uri, opts) end
|
64
|
+
def head(uri, opts = {}) request(HEAD, uri, opts) end
|
65
|
+
def options(uri, opts = {}) request(OPTIONS, uri, opts) end
|
62
66
|
|
63
|
-
def request(method=
|
64
|
-
env = self.class.env_for(uri, opts.merge(:
|
67
|
+
def request(method = GET, uri = "", opts = {})
|
68
|
+
env = self.class.env_for(uri, opts.merge(method: method))
|
65
69
|
|
66
70
|
if opts[:lint]
|
67
71
|
app = Rack::Lint.new(@app)
|
@@ -69,48 +73,55 @@ module Rack
|
|
69
73
|
app = @app
|
70
74
|
end
|
71
75
|
|
72
|
-
errors = env[
|
73
|
-
status, headers, body
|
76
|
+
errors = env[RACK_ERRORS]
|
77
|
+
status, headers, body = app.call(env)
|
74
78
|
MockResponse.new(status, headers, body, errors)
|
75
79
|
ensure
|
76
80
|
body.close if body.respond_to?(:close)
|
77
81
|
end
|
78
82
|
|
83
|
+
# For historical reasons, we're pinning to RFC 2396.
|
84
|
+
# URI::Parser = URI::RFC2396_Parser
|
85
|
+
def self.parse_uri_rfc2396(uri)
|
86
|
+
@parser ||= URI::Parser.new
|
87
|
+
@parser.parse(uri)
|
88
|
+
end
|
89
|
+
|
79
90
|
# Return the Rack environment used for a request to +uri+.
|
80
|
-
def self.env_for(uri="", opts={})
|
81
|
-
uri =
|
91
|
+
def self.env_for(uri = "", opts = {})
|
92
|
+
uri = parse_uri_rfc2396(uri)
|
82
93
|
uri.path = "/#{uri.path}" unless uri.path[0] == ?/
|
83
94
|
|
84
95
|
env = DEFAULT_ENV.dup
|
85
96
|
|
86
|
-
env[
|
87
|
-
env[
|
88
|
-
env[
|
89
|
-
env[
|
90
|
-
env[
|
91
|
-
env[
|
92
|
-
env[
|
97
|
+
env[REQUEST_METHOD] = (opts[:method] ? opts[:method].to_s.upcase : GET).b
|
98
|
+
env[SERVER_NAME] = (uri.host || "example.org").b
|
99
|
+
env[SERVER_PORT] = (uri.port ? uri.port.to_s : "80").b
|
100
|
+
env[QUERY_STRING] = (uri.query.to_s).b
|
101
|
+
env[PATH_INFO] = ((!uri.path || uri.path.empty?) ? "/" : uri.path).b
|
102
|
+
env[RACK_URL_SCHEME] = (uri.scheme || "http").b
|
103
|
+
env[HTTPS] = (env[RACK_URL_SCHEME] == "https" ? "on" : "off").b
|
93
104
|
|
94
|
-
env[
|
105
|
+
env[SCRIPT_NAME] = opts[:script_name] || ""
|
95
106
|
|
96
107
|
if opts[:fatal]
|
97
|
-
env[
|
108
|
+
env[RACK_ERRORS] = FatalWarner.new
|
98
109
|
else
|
99
|
-
env[
|
110
|
+
env[RACK_ERRORS] = StringIO.new
|
100
111
|
end
|
101
112
|
|
102
113
|
if params = opts[:params]
|
103
|
-
if env[
|
114
|
+
if env[REQUEST_METHOD] == GET
|
104
115
|
params = Utils.parse_nested_query(params) if params.is_a?(String)
|
105
|
-
params.update(Utils.parse_nested_query(env[
|
106
|
-
env[
|
116
|
+
params.update(Utils.parse_nested_query(env[QUERY_STRING]))
|
117
|
+
env[QUERY_STRING] = Utils.build_nested_query(params)
|
107
118
|
elsif !opts.has_key?(:input)
|
108
119
|
opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
|
109
120
|
if params.is_a?(Hash)
|
110
|
-
if data =
|
121
|
+
if data = Rack::Multipart.build_multipart(params)
|
111
122
|
opts[:input] = data
|
112
123
|
opts["CONTENT_LENGTH"] ||= data.length.to_s
|
113
|
-
opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{
|
124
|
+
opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Rack::Multipart::MULTIPART_BOUNDARY}"
|
114
125
|
else
|
115
126
|
opts[:input] = Utils.build_nested_query(params)
|
116
127
|
end
|
@@ -120,8 +131,7 @@ module Rack
|
|
120
131
|
end
|
121
132
|
end
|
122
133
|
|
123
|
-
empty_str =
|
124
|
-
empty_str.force_encoding("ASCII-8BIT") if empty_str.respond_to? :force_encoding
|
134
|
+
empty_str = String.new
|
125
135
|
opts[:input] ||= empty_str
|
126
136
|
if String === opts[:input]
|
127
137
|
rack_input = StringIO.new(opts[:input])
|
@@ -129,10 +139,10 @@ module Rack
|
|
129
139
|
rack_input = opts[:input]
|
130
140
|
end
|
131
141
|
|
132
|
-
rack_input.set_encoding(Encoding::BINARY)
|
133
|
-
env[
|
142
|
+
rack_input.set_encoding(Encoding::BINARY)
|
143
|
+
env[RACK_INPUT] = rack_input
|
134
144
|
|
135
|
-
env["CONTENT_LENGTH"] ||= env[
|
145
|
+
env["CONTENT_LENGTH"] ||= env[RACK_INPUT].size.to_s if env[RACK_INPUT].respond_to?(:size)
|
136
146
|
|
137
147
|
opts.each { |field, value|
|
138
148
|
env[field] = value if String === field
|
@@ -148,17 +158,19 @@ module Rack
|
|
148
158
|
|
149
159
|
class MockResponse < Rack::Response
|
150
160
|
# Headers
|
151
|
-
attr_reader :original_headers
|
161
|
+
attr_reader :original_headers, :cookies
|
152
162
|
|
153
163
|
# Errors
|
154
164
|
attr_accessor :errors
|
155
165
|
|
156
|
-
def initialize(status, headers, body, errors=StringIO.new(""))
|
166
|
+
def initialize(status, headers, body, errors = StringIO.new(""))
|
157
167
|
@original_headers = headers
|
158
168
|
@errors = errors.string if errors.respond_to?(:string)
|
159
|
-
@
|
169
|
+
@cookies = parse_cookies_from_header
|
160
170
|
|
161
171
|
super(body, status, headers)
|
172
|
+
|
173
|
+
buffered_body!
|
162
174
|
end
|
163
175
|
|
164
176
|
def =~(other)
|
@@ -180,11 +192,64 @@ module Rack
|
|
180
192
|
# ...
|
181
193
|
# res.body.should == "foo!"
|
182
194
|
# end
|
183
|
-
|
195
|
+
buffer = String.new
|
196
|
+
|
197
|
+
super.each do |chunk|
|
198
|
+
buffer << chunk
|
199
|
+
end
|
200
|
+
|
201
|
+
return buffer
|
184
202
|
end
|
185
203
|
|
186
204
|
def empty?
|
187
|
-
[201, 204,
|
205
|
+
[201, 204, 304].include? status
|
206
|
+
end
|
207
|
+
|
208
|
+
def cookie(name)
|
209
|
+
cookies.fetch(name, nil)
|
210
|
+
end
|
211
|
+
|
212
|
+
private
|
213
|
+
|
214
|
+
def parse_cookies_from_header
|
215
|
+
cookies = Hash.new
|
216
|
+
if original_headers.has_key? 'Set-Cookie'
|
217
|
+
set_cookie_header = original_headers.fetch('Set-Cookie')
|
218
|
+
set_cookie_header.split("\n").each do |cookie|
|
219
|
+
cookie_name, cookie_filling = cookie.split('=', 2)
|
220
|
+
cookie_attributes = identify_cookie_attributes cookie_filling
|
221
|
+
parsed_cookie = CGI::Cookie.new(
|
222
|
+
'name' => cookie_name.strip,
|
223
|
+
'value' => cookie_attributes.fetch('value'),
|
224
|
+
'path' => cookie_attributes.fetch('path', nil),
|
225
|
+
'domain' => cookie_attributes.fetch('domain', nil),
|
226
|
+
'expires' => cookie_attributes.fetch('expires', nil),
|
227
|
+
'secure' => cookie_attributes.fetch('secure', false)
|
228
|
+
)
|
229
|
+
cookies.store(cookie_name, parsed_cookie)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
cookies
|
233
|
+
end
|
234
|
+
|
235
|
+
def identify_cookie_attributes(cookie_filling)
|
236
|
+
cookie_bits = cookie_filling.split(';')
|
237
|
+
cookie_attributes = Hash.new
|
238
|
+
cookie_attributes.store('value', cookie_bits[0].strip)
|
239
|
+
cookie_bits.each do |bit|
|
240
|
+
if bit.include? '='
|
241
|
+
cookie_attribute, attribute_value = bit.split('=')
|
242
|
+
cookie_attributes.store(cookie_attribute.strip, attribute_value.strip)
|
243
|
+
if cookie_attribute.include? 'max-age'
|
244
|
+
cookie_attributes.store('expires', Time.now + attribute_value.strip.to_i)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
if bit.include? 'secure'
|
248
|
+
cookie_attributes.store('secure', true)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
cookie_attributes
|
188
252
|
end
|
253
|
+
|
189
254
|
end
|
190
255
|
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,34 @@ 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
|
-
::File.open(file.path,
|
19
|
-
f.set_encoding(Encoding::BINARY)
|
20
|
+
::File.open(file.path, 'rb') do |f|
|
21
|
+
f.set_encoding(Encoding::BINARY)
|
20
22
|
content_for_tempfile(f, file, name)
|
21
23
|
end
|
22
24
|
else
|
23
25
|
content_for_other(file, name)
|
24
26
|
end
|
25
|
-
end.join
|
27
|
+
end.join << "--#{MULTIPART_BOUNDARY}--\r"
|
26
28
|
end
|
27
29
|
|
28
30
|
private
|
29
31
|
def multipart?
|
30
|
-
multipart = false
|
31
|
-
|
32
32
|
query = lambda { |value|
|
33
33
|
case value
|
34
34
|
when Array
|
35
|
-
value.
|
35
|
+
value.any?(&query)
|
36
36
|
when Hash
|
37
|
-
value.values.
|
37
|
+
value.values.any?(&query)
|
38
38
|
when Rack::Multipart::UploadedFile
|
39
|
-
|
39
|
+
true
|
40
40
|
end
|
41
41
|
}
|
42
|
-
@params.values.each(&query)
|
43
42
|
|
44
|
-
|
43
|
+
@params.values.any?(&query)
|
45
44
|
end
|
46
45
|
|
47
46
|
def flattened_params
|
@@ -90,4 +89,4 @@ EOF
|
|
90
89
|
end
|
91
90
|
end
|
92
91
|
end
|
93
|
-
end
|
92
|
+
end
|