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.

Files changed (190) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +675 -0
  3. data/CONTRIBUTING.md +136 -0
  4. data/{COPYING → MIT-LICENSE} +4 -2
  5. data/README.rdoc +157 -163
  6. data/Rakefile +38 -32
  7. data/{SPEC → SPEC.rdoc} +41 -13
  8. data/bin/rackup +1 -0
  9. data/contrib/rack_logo.svg +164 -111
  10. data/example/lobster.ru +2 -0
  11. data/example/protectedlobster.rb +4 -2
  12. data/example/protectedlobster.ru +3 -1
  13. data/lib/rack/auth/abstract/handler.rb +3 -1
  14. data/lib/rack/auth/abstract/request.rb +6 -2
  15. data/lib/rack/auth/basic.rb +7 -4
  16. data/lib/rack/auth/digest/md5.rb +13 -11
  17. data/lib/rack/auth/digest/nonce.rb +6 -3
  18. data/lib/rack/auth/digest/params.rb +5 -4
  19. data/lib/rack/auth/digest/request.rb +6 -4
  20. data/lib/rack/body_proxy.rb +21 -15
  21. data/lib/rack/builder.rb +119 -26
  22. data/lib/rack/cascade.rb +28 -12
  23. data/lib/rack/chunked.rb +70 -22
  24. data/lib/rack/common_logger.rb +80 -0
  25. data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -16
  26. data/lib/rack/config.rb +2 -0
  27. data/lib/rack/content_length.rb +9 -8
  28. data/lib/rack/content_type.rb +5 -4
  29. data/lib/rack/core_ext/regexp.rb +14 -0
  30. data/lib/rack/deflater.rb +60 -70
  31. data/lib/rack/directory.rb +117 -85
  32. data/lib/rack/etag.rb +9 -7
  33. data/lib/rack/events.rb +153 -0
  34. data/lib/rack/file.rb +4 -149
  35. data/lib/rack/files.rb +218 -0
  36. data/lib/rack/handler/cgi.rb +17 -19
  37. data/lib/rack/handler/fastcgi.rb +17 -18
  38. data/lib/rack/handler/lsws.rb +14 -14
  39. data/lib/rack/handler/scgi.rb +22 -21
  40. data/lib/rack/handler/thin.rb +20 -11
  41. data/lib/rack/handler/webrick.rb +39 -32
  42. data/lib/rack/handler.rb +9 -26
  43. data/lib/rack/head.rb +16 -18
  44. data/lib/rack/lint.rb +110 -64
  45. data/lib/rack/lobster.rb +10 -10
  46. data/lib/rack/lock.rb +17 -11
  47. data/lib/rack/logger.rb +4 -2
  48. data/lib/rack/media_type.rb +43 -0
  49. data/lib/rack/{methodoverride.rb → method_override.rb} +10 -8
  50. data/lib/rack/mime.rb +27 -6
  51. data/lib/rack/mock.rb +124 -65
  52. data/lib/rack/multipart/generator.rb +20 -16
  53. data/lib/rack/multipart/parser.rb +273 -162
  54. data/lib/rack/multipart/uploaded_file.rb +15 -8
  55. data/lib/rack/multipart.rb +39 -8
  56. data/lib/rack/{nulllogger.rb → null_logger.rb} +3 -1
  57. data/lib/rack/query_parser.rb +217 -0
  58. data/lib/rack/recursive.rb +11 -9
  59. data/lib/rack/reloader.rb +8 -4
  60. data/lib/rack/request.rb +543 -305
  61. data/lib/rack/response.rb +244 -88
  62. data/lib/rack/rewindable_input.rb +5 -15
  63. data/lib/rack/runtime.rb +12 -18
  64. data/lib/rack/sendfile.rb +17 -15
  65. data/lib/rack/server.rb +125 -47
  66. data/lib/rack/session/abstract/id.rb +216 -93
  67. data/lib/rack/session/cookie.rb +47 -31
  68. data/lib/rack/session/memcache.rb +4 -87
  69. data/lib/rack/session/pool.rb +26 -17
  70. data/lib/rack/show_exceptions.rb +390 -0
  71. data/lib/rack/{showstatus.rb → show_status.rb} +8 -8
  72. data/lib/rack/static.rb +48 -11
  73. data/lib/rack/tempfile_reaper.rb +3 -3
  74. data/lib/rack/urlmap.rb +26 -19
  75. data/lib/rack/utils.rb +208 -294
  76. data/lib/rack/version.rb +29 -0
  77. data/lib/rack.rb +76 -33
  78. data/rack.gemspec +43 -30
  79. metadata +62 -183
  80. data/HISTORY.md +0 -375
  81. data/KNOWN-ISSUES +0 -44
  82. data/lib/rack/backports/uri/common_18.rb +0 -56
  83. data/lib/rack/backports/uri/common_192.rb +0 -52
  84. data/lib/rack/backports/uri/common_193.rb +0 -29
  85. data/lib/rack/commonlogger.rb +0 -72
  86. data/lib/rack/handler/evented_mongrel.rb +0 -8
  87. data/lib/rack/handler/mongrel.rb +0 -106
  88. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  89. data/lib/rack/showexceptions.rb +0 -387
  90. data/lib/rack/utils/okjson.rb +0 -600
  91. data/test/builder/anything.rb +0 -5
  92. data/test/builder/comment.ru +0 -4
  93. data/test/builder/end.ru +0 -5
  94. data/test/builder/line.ru +0 -1
  95. data/test/builder/options.ru +0 -2
  96. data/test/cgi/assets/folder/test.js +0 -1
  97. data/test/cgi/assets/fonts/font.eot +0 -1
  98. data/test/cgi/assets/images/image.png +0 -1
  99. data/test/cgi/assets/index.html +0 -1
  100. data/test/cgi/assets/javascripts/app.js +0 -1
  101. data/test/cgi/assets/stylesheets/app.css +0 -1
  102. data/test/cgi/lighttpd.conf +0 -26
  103. data/test/cgi/rackup_stub.rb +0 -6
  104. data/test/cgi/sample_rackup.ru +0 -5
  105. data/test/cgi/test +0 -9
  106. data/test/cgi/test+directory/test+file +0 -1
  107. data/test/cgi/test.fcgi +0 -8
  108. data/test/cgi/test.ru +0 -5
  109. data/test/gemloader.rb +0 -10
  110. data/test/multipart/bad_robots +0 -259
  111. data/test/multipart/binary +0 -0
  112. data/test/multipart/content_type_and_no_filename +0 -6
  113. data/test/multipart/empty +0 -10
  114. data/test/multipart/fail_16384_nofile +0 -814
  115. data/test/multipart/file1.txt +0 -1
  116. data/test/multipart/filename_and_modification_param +0 -7
  117. data/test/multipart/filename_and_no_name +0 -6
  118. data/test/multipart/filename_with_escaped_quotes +0 -6
  119. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  120. data/test/multipart/filename_with_null_byte +0 -7
  121. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  122. data/test/multipart/filename_with_unescaped_percentages +0 -6
  123. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  124. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  125. data/test/multipart/filename_with_unescaped_quotes +0 -6
  126. data/test/multipart/ie +0 -6
  127. data/test/multipart/invalid_character +0 -6
  128. data/test/multipart/mixed_files +0 -21
  129. data/test/multipart/nested +0 -10
  130. data/test/multipart/none +0 -9
  131. data/test/multipart/semicolon +0 -6
  132. data/test/multipart/text +0 -15
  133. data/test/multipart/three_files_three_fields +0 -31
  134. data/test/multipart/webkit +0 -32
  135. data/test/rackup/config.ru +0 -31
  136. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  137. data/test/spec_auth_basic.rb +0 -81
  138. data/test/spec_auth_digest.rb +0 -259
  139. data/test/spec_body_proxy.rb +0 -85
  140. data/test/spec_builder.rb +0 -223
  141. data/test/spec_cascade.rb +0 -61
  142. data/test/spec_cgi.rb +0 -102
  143. data/test/spec_chunked.rb +0 -101
  144. data/test/spec_commonlogger.rb +0 -93
  145. data/test/spec_conditionalget.rb +0 -102
  146. data/test/spec_config.rb +0 -22
  147. data/test/spec_content_length.rb +0 -85
  148. data/test/spec_content_type.rb +0 -45
  149. data/test/spec_deflater.rb +0 -339
  150. data/test/spec_directory.rb +0 -88
  151. data/test/spec_etag.rb +0 -107
  152. data/test/spec_fastcgi.rb +0 -107
  153. data/test/spec_file.rb +0 -221
  154. data/test/spec_handler.rb +0 -72
  155. data/test/spec_head.rb +0 -45
  156. data/test/spec_lint.rb +0 -550
  157. data/test/spec_lobster.rb +0 -58
  158. data/test/spec_lock.rb +0 -164
  159. data/test/spec_logger.rb +0 -23
  160. data/test/spec_methodoverride.rb +0 -111
  161. data/test/spec_mime.rb +0 -51
  162. data/test/spec_mock.rb +0 -297
  163. data/test/spec_mongrel.rb +0 -182
  164. data/test/spec_multipart.rb +0 -600
  165. data/test/spec_nulllogger.rb +0 -20
  166. data/test/spec_recursive.rb +0 -72
  167. data/test/spec_request.rb +0 -1232
  168. data/test/spec_response.rb +0 -407
  169. data/test/spec_rewindable_input.rb +0 -118
  170. data/test/spec_runtime.rb +0 -49
  171. data/test/spec_sendfile.rb +0 -130
  172. data/test/spec_server.rb +0 -167
  173. data/test/spec_session_abstract_id.rb +0 -53
  174. data/test/spec_session_cookie.rb +0 -410
  175. data/test/spec_session_memcache.rb +0 -321
  176. data/test/spec_session_pool.rb +0 -209
  177. data/test/spec_showexceptions.rb +0 -98
  178. data/test/spec_showstatus.rb +0 -103
  179. data/test/spec_static.rb +0 -145
  180. data/test/spec_tempfile_reaper.rb +0 -63
  181. data/test/spec_thin.rb +0 -91
  182. data/test/spec_urlmap.rb +0 -236
  183. data/test/spec_utils.rb +0 -647
  184. data/test/spec_version.rb +0 -17
  185. data/test/spec_webrick.rb +0 -184
  186. data/test/static/another/index.html +0 -1
  187. data/test/static/index.html +0 -1
  188. data/test/testrequest.rb +0 -78
  189. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  190. 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
- require 'rack'
4
- require 'rack/lint'
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
- "rack.version" => Rack::VERSION,
45
- "rack.input" => StringIO.new,
46
- "rack.errors" => StringIO.new,
47
- "rack.multithread" => true,
48
- "rack.multiprocess" => true,
49
- "rack.run_once" => false,
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
- def get(uri, opts={}) request("GET", uri, opts) end
57
- def post(uri, opts={}) request("POST", uri, opts) end
58
- def put(uri, opts={}) request("PUT", uri, opts) end
59
- def patch(uri, opts={}) request("PATCH", uri, opts) end
60
- def delete(uri, opts={}) request("DELETE", uri, opts) end
61
- def head(uri, opts={}) request("HEAD", uri, opts) end
62
- def options(uri, opts={}) request("OPTIONS", uri, opts) end
63
-
64
- def request(method="GET", uri="", opts={})
65
- env = self.class.env_for(uri, opts.merge(:method => method))
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["rack.errors"]
74
- status, headers, body = app.call(env)
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. It's easier for users
81
- # and we get support from ruby 1.8 to 2.2 using this method.
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 ||= defined?(URI::RFC2396_Parser) ? URI::RFC2396_Parser.new : URI
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
- def self.env_for(uri="", opts={})
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
- env_with_encoding(env, opts, uri)
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["rack.errors"] = FatalWarner.new
122
+ env[RACK_ERRORS] = FatalWarner.new
100
123
  else
101
- env["rack.errors"] = StringIO.new
124
+ env[RACK_ERRORS] = StringIO.new
102
125
  end
103
126
 
104
127
  if params = opts[:params]
105
- if env[REQUEST_METHOD] == "GET"
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 = Utils::Multipart.build_multipart(params)
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=#{Utils::Multipart::MULTIPART_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) if rack_input.respond_to?(:set_encoding)
135
- env['rack.input'] = rack_input
156
+ rack_input.set_encoding(Encoding::BINARY)
157
+ env[RACK_INPUT] = rack_input
136
158
 
137
- env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s
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
- @body_string = nil
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
- super.join
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, 205, 304].include? status
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 if !@first
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, "rb") do |f|
19
- f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding)
20
- content_for_tempfile(f, file, name)
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 + "--#{MULTIPART_BOUNDARY}--\r"
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.each(&query)
39
+ value.any?(&query)
36
40
  when Hash
37
- value.values.each(&query)
41
+ value.values.any?(&query)
38
42
  when Rack::Multipart::UploadedFile
39
- multipart = true
43
+ true
40
44
  end
41
45
  }
42
- @params.values.each(&query)
43
46
 
44
- multipart
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}"; filename="#{Utils.escape(file.original_filename)}"\r
80
+ Content-Disposition: form-data; name="#{name}"#{filename}\r
76
81
  Content-Type: #{file.content_type}\r
77
- Content-Length: #{::File.stat(file.path).size}\r
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