rack 1.6.13 → 2.0.0.alpha

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 (138) hide show
  1. checksums.yaml +5 -5
  2. data/HISTORY.md +139 -18
  3. data/README.rdoc +17 -25
  4. data/Rakefile +6 -14
  5. data/SPEC +8 -9
  6. data/contrib/rack_logo.svg +164 -111
  7. data/lib/rack.rb +70 -21
  8. data/lib/rack/auth/digest/request.rb +1 -1
  9. data/lib/rack/body_proxy.rb +14 -9
  10. data/lib/rack/builder.rb +3 -3
  11. data/lib/rack/chunked.rb +5 -5
  12. data/lib/rack/{commonlogger.rb → common_logger.rb} +2 -2
  13. data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
  14. data/lib/rack/content_length.rb +2 -2
  15. data/lib/rack/deflater.rb +4 -4
  16. data/lib/rack/directory.rb +49 -55
  17. data/lib/rack/etag.rb +2 -1
  18. data/lib/rack/events.rb +154 -0
  19. data/lib/rack/file.rb +55 -40
  20. data/lib/rack/handler.rb +2 -24
  21. data/lib/rack/handler/cgi.rb +15 -16
  22. data/lib/rack/handler/fastcgi.rb +13 -14
  23. data/lib/rack/handler/lsws.rb +11 -11
  24. data/lib/rack/handler/scgi.rb +15 -15
  25. data/lib/rack/handler/thin.rb +3 -0
  26. data/lib/rack/handler/webrick.rb +22 -24
  27. data/lib/rack/head.rb +15 -17
  28. data/lib/rack/lint.rb +38 -38
  29. data/lib/rack/lobster.rb +1 -1
  30. data/lib/rack/lock.rb +6 -10
  31. data/lib/rack/logger.rb +2 -2
  32. data/lib/rack/media_type.rb +38 -0
  33. data/lib/rack/{methodoverride.rb → method_override.rb} +4 -11
  34. data/lib/rack/mime.rb +18 -5
  35. data/lib/rack/mock.rb +35 -52
  36. data/lib/rack/multipart.rb +35 -6
  37. data/lib/rack/multipart/generator.rb +4 -4
  38. data/lib/rack/multipart/parser.rb +273 -158
  39. data/lib/rack/multipart/uploaded_file.rb +1 -2
  40. data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
  41. data/lib/rack/query_parser.rb +174 -0
  42. data/lib/rack/recursive.rb +8 -8
  43. data/lib/rack/reloader.rb +1 -2
  44. data/lib/rack/request.rb +370 -304
  45. data/lib/rack/response.rb +129 -56
  46. data/lib/rack/rewindable_input.rb +1 -12
  47. data/lib/rack/runtime.rb +10 -18
  48. data/lib/rack/sendfile.rb +5 -7
  49. data/lib/rack/server.rb +31 -25
  50. data/lib/rack/session/abstract/id.rb +93 -135
  51. data/lib/rack/session/cookie.rb +26 -28
  52. data/lib/rack/session/memcache.rb +8 -14
  53. data/lib/rack/session/pool.rb +14 -21
  54. data/lib/rack/show_exceptions.rb +386 -0
  55. data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
  56. data/lib/rack/static.rb +30 -5
  57. data/lib/rack/tempfile_reaper.rb +2 -2
  58. data/lib/rack/urlmap.rb +13 -14
  59. data/lib/rack/utils.rb +128 -221
  60. data/rack.gemspec +9 -5
  61. data/test/builder/an_underscore_app.rb +5 -0
  62. data/test/builder/options.ru +1 -1
  63. data/test/cgi/test.fcgi +1 -0
  64. data/test/cgi/test.gz +0 -0
  65. data/test/helper.rb +31 -0
  66. data/test/multipart/filename_with_encoded_words +7 -0
  67. data/test/multipart/{filename_with_null_byte → filename_with_single_quote} +1 -1
  68. data/test/multipart/quoted +15 -0
  69. data/test/multipart/rack-logo.png +0 -0
  70. data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
  71. data/test/spec_auth_basic.rb +20 -19
  72. data/test/spec_auth_digest.rb +47 -46
  73. data/test/spec_body_proxy.rb +27 -27
  74. data/test/spec_builder.rb +51 -41
  75. data/test/spec_cascade.rb +24 -22
  76. data/test/spec_cgi.rb +49 -67
  77. data/test/spec_chunked.rb +36 -34
  78. data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -21
  79. data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
  80. data/test/spec_config.rb +3 -2
  81. data/test/spec_content_length.rb +18 -17
  82. data/test/spec_content_type.rb +13 -12
  83. data/test/spec_deflater.rb +66 -40
  84. data/test/spec_directory.rb +72 -27
  85. data/test/spec_etag.rb +32 -31
  86. data/test/spec_events.rb +133 -0
  87. data/test/spec_fastcgi.rb +50 -72
  88. data/test/spec_file.rb +96 -77
  89. data/test/spec_handler.rb +19 -34
  90. data/test/spec_head.rb +15 -14
  91. data/test/spec_lint.rb +162 -197
  92. data/test/spec_lobster.rb +24 -23
  93. data/test/spec_lock.rb +69 -39
  94. data/test/spec_logger.rb +4 -3
  95. data/test/spec_media_type.rb +42 -0
  96. data/test/spec_method_override.rb +83 -0
  97. data/test/spec_mime.rb +19 -19
  98. data/test/spec_mock.rb +196 -151
  99. data/test/spec_multipart.rb +310 -202
  100. data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
  101. data/test/spec_recursive.rb +17 -14
  102. data/test/spec_request.rb +763 -607
  103. data/test/spec_response.rb +209 -156
  104. data/test/spec_rewindable_input.rb +50 -40
  105. data/test/spec_runtime.rb +11 -10
  106. data/test/spec_sendfile.rb +30 -35
  107. data/test/spec_server.rb +78 -52
  108. data/test/spec_session_abstract_id.rb +11 -33
  109. data/test/spec_session_cookie.rb +97 -65
  110. data/test/spec_session_memcache.rb +63 -101
  111. data/test/spec_session_pool.rb +48 -84
  112. data/test/spec_show_exceptions.rb +80 -0
  113. data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
  114. data/test/spec_static.rb +71 -32
  115. data/test/spec_tempfile_reaper.rb +11 -10
  116. data/test/spec_thin.rb +55 -50
  117. data/test/spec_urlmap.rb +79 -78
  118. data/test/spec_utils.rb +417 -345
  119. data/test/spec_version.rb +2 -8
  120. data/test/spec_webrick.rb +77 -67
  121. data/test/static/foo.html +1 -0
  122. data/test/testrequest.rb +1 -1
  123. data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
  124. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
  125. metadata +116 -71
  126. data/KNOWN-ISSUES +0 -44
  127. data/lib/rack/backports/uri/common_18.rb +0 -56
  128. data/lib/rack/backports/uri/common_192.rb +0 -52
  129. data/lib/rack/backports/uri/common_193.rb +0 -29
  130. data/lib/rack/handler/evented_mongrel.rb +0 -8
  131. data/lib/rack/handler/mongrel.rb +0 -106
  132. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  133. data/lib/rack/showexceptions.rb +0 -387
  134. data/lib/rack/utils/okjson.rb +0 -600
  135. data/test/spec_methodoverride.rb +0 -111
  136. data/test/spec_mongrel.rb +0 -182
  137. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  138. data/test/spec_showexceptions.rb +0 -98
@@ -1,3 +1,9 @@
1
+ # coding: utf-8
2
+
3
+ require 'minitest/autorun'
4
+ require 'rack'
5
+ require 'rack/multipart'
6
+ require 'rack/multipart/parser'
1
7
  require 'rack/utils'
2
8
  require 'rack/mock'
3
9
 
@@ -6,8 +12,8 @@ describe Rack::Multipart do
6
12
  file = multipart_file(name)
7
13
  data = File.open(file, 'rb') { |io| io.read }
8
14
 
9
- type = "multipart/form-data; boundary=#{boundary}"
10
- length = data.respond_to?(:bytesize) ? data.bytesize : data.size
15
+ type = %(multipart/form-data; boundary=#{boundary})
16
+ length = data.bytesize
11
17
 
12
18
  { "CONTENT_TYPE" => type,
13
19
  "CONTENT_LENGTH" => length.to_s,
@@ -18,75 +24,73 @@ describe Rack::Multipart do
18
24
  File.join(File.dirname(__FILE__), "multipart", name.to_s)
19
25
  end
20
26
 
21
- should "return nil if content type is not multipart" do
27
+ it "return nil if content type is not multipart" do
22
28
  env = Rack::MockRequest.env_for("/",
23
29
  "CONTENT_TYPE" => 'application/x-www-form-urlencoded')
24
- Rack::Multipart.parse_multipart(env).should.equal nil
30
+ Rack::Multipart.parse_multipart(env).must_equal nil
25
31
  end
26
32
 
27
- should "parse multipart content when content type present but filename is not" do
33
+ it "parse multipart content when content type present but filename is not" do
28
34
  env = Rack::MockRequest.env_for("/", multipart_fixture(:content_type_and_no_filename))
29
35
  params = Rack::Multipart.parse_multipart(env)
30
- params["text"].should.equal "contents"
36
+ params["text"].must_equal "contents"
31
37
  end
32
38
 
33
- if "<3".respond_to?(:force_encoding)
34
- should "set US_ASCII encoding based on charset" do
39
+ it "set US_ASCII encoding based on charset" do
35
40
  env = Rack::MockRequest.env_for("/", multipart_fixture(:content_type_and_no_filename))
36
41
  params = Rack::Multipart.parse_multipart(env)
37
- params["text"].encoding.should.equal Encoding::US_ASCII
42
+ params["text"].encoding.must_equal Encoding::US_ASCII
38
43
 
39
44
  # I'm not 100% sure if making the param name encoding match the
40
45
  # Content-Type charset is the right thing to do. We should revisit this.
41
46
  params.keys.each do |key|
42
- key.encoding.should.equal Encoding::US_ASCII
47
+ key.encoding.must_equal Encoding::US_ASCII
43
48
  end
44
49
  end
45
50
 
46
- should "set BINARY encoding on things without content type" do
51
+ it "set BINARY encoding on things without content type" do
47
52
  env = Rack::MockRequest.env_for("/", multipart_fixture(:none))
48
53
  params = Rack::Multipart.parse_multipart(env)
49
- params["submit-name"].encoding.should.equal Encoding::UTF_8
54
+ params["submit-name"].encoding.must_equal Encoding::UTF_8
50
55
  end
51
56
 
52
- should "set UTF8 encoding on names of things without content type" do
57
+ it "set UTF8 encoding on names of things without content type" do
53
58
  env = Rack::MockRequest.env_for("/", multipart_fixture(:none))
54
59
  params = Rack::Multipart.parse_multipart(env)
55
60
  params.keys.each do |key|
56
- key.encoding.should.equal Encoding::UTF_8
61
+ key.encoding.must_equal Encoding::UTF_8
57
62
  end
58
63
  end
59
64
 
60
- should "default text to UTF8" do
65
+ it "default text to UTF8" do
61
66
  env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
62
67
  params = Rack::Multipart.parse_multipart(env)
63
- params['submit-name'].encoding.should.equal Encoding::UTF_8
64
- params['submit-name-with-content'].encoding.should.equal Encoding::UTF_8
68
+ params['submit-name'].encoding.must_equal Encoding::UTF_8
69
+ params['submit-name-with-content'].encoding.must_equal Encoding::UTF_8
65
70
  params.keys.each do |key|
66
- key.encoding.should.equal Encoding::UTF_8
71
+ key.encoding.must_equal Encoding::UTF_8
67
72
  end
68
73
  end
69
- end
70
74
 
71
- should "raise RangeError if the key space is exhausted" do
75
+ it "raise RangeError if the key space is exhausted" do
72
76
  env = Rack::MockRequest.env_for("/", multipart_fixture(:content_type_and_no_filename))
73
77
 
74
78
  old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 1
75
79
  begin
76
- lambda { Rack::Multipart.parse_multipart(env) }.should.raise(RangeError)
80
+ lambda { Rack::Multipart.parse_multipart(env) }.must_raise(RangeError)
77
81
  ensure
78
82
  Rack::Utils.key_space_limit = old
79
83
  end
80
84
  end
81
85
 
82
- should "parse multipart form webkit style" do
86
+ it "parse multipart form webkit style" do
83
87
  env = Rack::MockRequest.env_for '/', multipart_fixture(:webkit)
84
88
  env['CONTENT_TYPE'] = "multipart/form-data; boundary=----WebKitFormBoundaryWLHCs9qmcJJoyjKR"
85
89
  params = Rack::Multipart.parse_multipart(env)
86
- params['profile']['bio'].should.include 'hello'
90
+ params['profile']['bio'].must_include 'hello'
87
91
  end
88
92
 
89
- should "reject insanely long boundaries" do
93
+ it "reject insanely long boundaries" do
90
94
  # using a pipe since a tempfile can use up too much space
91
95
  rd, wr = IO.pipe
92
96
 
@@ -131,279 +135,309 @@ describe Rack::Multipart do
131
135
  env = Rack::MockRequest.env_for '/', fixture
132
136
  lambda {
133
137
  Rack::Multipart.parse_multipart(env)
134
- }.should.raise(EOFError)
138
+ }.must_raise EOFError
135
139
  rd.close
136
140
 
137
141
  err = thr.value
138
- err.should.be.instance_of Errno::EPIPE
142
+ err.must_be_instance_of Errno::EPIPE
139
143
  wr.close
140
144
  end
141
145
 
142
- should "parse multipart upload with text file" do
146
+ it 'raises an EOF error on content-length mistmatch' do
147
+ env = Rack::MockRequest.env_for("/", multipart_fixture(:empty))
148
+ env['rack.input'] = StringIO.new
149
+ assert_raises(EOFError) do
150
+ Rack::Multipart.parse_multipart(env)
151
+ end
152
+ end
153
+
154
+ it "parse multipart upload with text file" do
143
155
  env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
144
156
  params = Rack::Multipart.parse_multipart(env)
145
- params["submit-name"].should.equal "Larry"
146
- params["submit-name-with-content"].should.equal "Berry"
147
- params["files"][:type].should.equal "text/plain"
148
- params["files"][:filename].should.equal "file1.txt"
149
- params["files"][:head].should.equal "Content-Disposition: form-data; " +
157
+ params["submit-name"].must_equal "Larry"
158
+ params["submit-name-with-content"].must_equal "Berry"
159
+ params["files"][:type].must_equal "text/plain"
160
+ params["files"][:filename].must_equal "file1.txt"
161
+ params["files"][:head].must_equal "Content-Disposition: form-data; " +
150
162
  "name=\"files\"; filename=\"file1.txt\"\r\n" +
151
163
  "Content-Type: text/plain\r\n"
152
- params["files"][:name].should.equal "files"
153
- params["files"][:tempfile].read.should.equal "contents"
164
+ params["files"][:name].must_equal "files"
165
+ params["files"][:tempfile].read.must_equal "contents"
166
+ end
167
+
168
+ it "accept the params hash class to use for multipart parsing" do
169
+ c = Class.new(Rack::QueryParser::Params) do
170
+ def initialize(*)
171
+ super
172
+ @params = Hash.new{|h,k| h[k.to_s] if k.is_a?(Symbol)}
173
+ end
174
+ end
175
+ query_parser = Rack::QueryParser.new c, 65536, 100
176
+ env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
177
+ params = Rack::Multipart.parse_multipart(env, query_parser)
178
+ params[:files][:type].must_equal "text/plain"
154
179
  end
155
180
 
156
- should "preserve extension in the created tempfile" do
181
+ it "preserve extension in the created tempfile" do
157
182
  env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
158
183
  params = Rack::Multipart.parse_multipart(env)
159
- File.extname(params["files"][:tempfile].path).should.equal ".txt"
184
+ File.extname(params["files"][:tempfile].path).must_equal ".txt"
160
185
  end
161
186
 
162
- should "parse multipart upload with text file with no name field" do
187
+ it "parse multipart upload with text file with no name field" do
163
188
  env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_and_no_name))
164
189
  params = Rack::Multipart.parse_multipart(env)
165
- params["file1.txt"][:type].should.equal "text/plain"
166
- params["file1.txt"][:filename].should.equal "file1.txt"
167
- params["file1.txt"][:head].should.equal "Content-Disposition: form-data; " +
190
+ params["file1.txt"][:type].must_equal "text/plain"
191
+ params["file1.txt"][:filename].must_equal "file1.txt"
192
+ params["file1.txt"][:head].must_equal "Content-Disposition: form-data; " +
168
193
  "filename=\"file1.txt\"\r\n" +
169
194
  "Content-Type: text/plain\r\n"
170
- params["file1.txt"][:name].should.equal "file1.txt"
171
- params["file1.txt"][:tempfile].read.should.equal "contents"
195
+ params["file1.txt"][:name].must_equal "file1.txt"
196
+ params["file1.txt"][:tempfile].read.must_equal "contents"
172
197
  end
173
198
 
174
- should "parse multipart upload file using custom tempfile class" do
199
+ it "parse multipart upload file using custom tempfile class" do
175
200
  env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
176
201
  my_tempfile = ""
177
202
  env['rack.multipart.tempfile_factory'] = lambda { |filename, content_type| my_tempfile }
178
203
  params = Rack::Multipart.parse_multipart(env)
179
- params["files"][:tempfile].object_id.should.equal my_tempfile.object_id
180
- my_tempfile.should.equal "contents"
204
+ params["files"][:tempfile].object_id.must_equal my_tempfile.object_id
205
+ my_tempfile.must_equal "contents"
181
206
  end
182
207
 
183
- should "parse multipart upload with nested parameters" do
208
+ it "parse multipart upload with nested parameters" do
184
209
  env = Rack::MockRequest.env_for("/", multipart_fixture(:nested))
185
210
  params = Rack::Multipart.parse_multipart(env)
186
- params["foo"]["submit-name"].should.equal "Larry"
187
- params["foo"]["files"][:type].should.equal "text/plain"
188
- params["foo"]["files"][:filename].should.equal "file1.txt"
189
- params["foo"]["files"][:head].should.equal "Content-Disposition: form-data; " +
211
+ params["foo"]["submit-name"].must_equal "Larry"
212
+ params["foo"]["files"][:type].must_equal "text/plain"
213
+ params["foo"]["files"][:filename].must_equal "file1.txt"
214
+ params["foo"]["files"][:head].must_equal "Content-Disposition: form-data; " +
190
215
  "name=\"foo[files]\"; filename=\"file1.txt\"\r\n" +
191
216
  "Content-Type: text/plain\r\n"
192
- params["foo"]["files"][:name].should.equal "foo[files]"
193
- params["foo"]["files"][:tempfile].read.should.equal "contents"
217
+ params["foo"]["files"][:name].must_equal "foo[files]"
218
+ params["foo"]["files"][:tempfile].read.must_equal "contents"
194
219
  end
195
220
 
196
- should "parse multipart upload with binary file" do
221
+ it "parse multipart upload with binary file" do
197
222
  env = Rack::MockRequest.env_for("/", multipart_fixture(:binary))
198
223
  params = Rack::Multipart.parse_multipart(env)
199
- params["submit-name"].should.equal "Larry"
200
- params["files"][:type].should.equal "image/png"
201
- params["files"][:filename].should.equal "rack-logo.png"
202
- params["files"][:head].should.equal "Content-Disposition: form-data; " +
224
+ params["submit-name"].must_equal "Larry"
225
+
226
+ params["files"][:type].must_equal "image/png"
227
+ params["files"][:filename].must_equal "rack-logo.png"
228
+ params["files"][:head].must_equal "Content-Disposition: form-data; " +
203
229
  "name=\"files\"; filename=\"rack-logo.png\"\r\n" +
204
230
  "Content-Type: image/png\r\n"
205
- params["files"][:name].should.equal "files"
206
- params["files"][:tempfile].read.length.should.equal 26473
231
+ params["files"][:name].must_equal "files"
232
+ params["files"][:tempfile].read.length.must_equal 26473
207
233
  end
208
234
 
209
- should "parse multipart upload with empty file" do
235
+ it "parse multipart upload with empty file" do
210
236
  env = Rack::MockRequest.env_for("/", multipart_fixture(:empty))
211
237
  params = Rack::Multipart.parse_multipart(env)
212
- params["submit-name"].should.equal "Larry"
213
- params["files"][:type].should.equal "text/plain"
214
- params["files"][:filename].should.equal "file1.txt"
215
- params["files"][:head].should.equal "Content-Disposition: form-data; " +
238
+ params["submit-name"].must_equal "Larry"
239
+ params["files"][:type].must_equal "text/plain"
240
+ params["files"][:filename].must_equal "file1.txt"
241
+ params["files"][:head].must_equal "Content-Disposition: form-data; " +
216
242
  "name=\"files\"; filename=\"file1.txt\"\r\n" +
217
243
  "Content-Type: text/plain\r\n"
218
- params["files"][:name].should.equal "files"
219
- params["files"][:tempfile].read.should.equal ""
244
+ params["files"][:name].must_equal "files"
245
+ params["files"][:tempfile].read.must_equal ""
220
246
  end
221
247
 
222
- should "parse multipart upload with filename with semicolons" do
248
+ it "parse multipart upload with filename with semicolons" do
223
249
  env = Rack::MockRequest.env_for("/", multipart_fixture(:semicolon))
224
250
  params = Rack::Multipart.parse_multipart(env)
225
- params["files"][:type].should.equal "text/plain"
226
- params["files"][:filename].should.equal "fi;le1.txt"
227
- params["files"][:head].should.equal "Content-Disposition: form-data; " +
251
+ params["files"][:type].must_equal "text/plain"
252
+ params["files"][:filename].must_equal "fi;le1.txt"
253
+ params["files"][:head].must_equal "Content-Disposition: form-data; " +
228
254
  "name=\"files\"; filename=\"fi;le1.txt\"\r\n" +
229
255
  "Content-Type: text/plain\r\n"
230
- params["files"][:name].should.equal "files"
231
- params["files"][:tempfile].read.should.equal "contents"
256
+ params["files"][:name].must_equal "files"
257
+ params["files"][:tempfile].read.must_equal "contents"
258
+ end
259
+
260
+ it "parse multipart upload with quoted boundary" do
261
+ env = Rack::MockRequest.env_for("/", multipart_fixture(:quoted, %("AaB:03x")))
262
+ params = Rack::Multipart.parse_multipart(env)
263
+ params["submit-name"].must_equal "Larry"
264
+ params["submit-name-with-content"].must_equal "Berry"
265
+ params["files"][:type].must_equal "text/plain"
266
+ params["files"][:filename].must_equal "file1.txt"
267
+ params["files"][:head].must_equal "Content-Disposition: form-data; " +
268
+ "name=\"files\"; filename=\"file1.txt\"\r\n" +
269
+ "Content-Type: text/plain\r\n"
270
+ params["files"][:name].must_equal "files"
271
+ params["files"][:tempfile].read.must_equal "contents"
232
272
  end
233
273
 
234
- should "parse multipart upload with filename with invalid characters" do
274
+ it "parse multipart upload with filename with invalid characters" do
235
275
  env = Rack::MockRequest.env_for("/", multipart_fixture(:invalid_character))
236
276
  params = Rack::Multipart.parse_multipart(env)
237
- params["files"][:type].should.equal "text/plain"
238
- params["files"][:filename].should.match(/invalid/)
277
+ params["files"][:type].must_equal "text/plain"
278
+ params["files"][:filename].must_match(/invalid/)
239
279
  head = "Content-Disposition: form-data; " +
240
280
  "name=\"files\"; filename=\"invalid\xC3.txt\"\r\n" +
241
281
  "Content-Type: text/plain\r\n"
242
- head = head.force_encoding("ASCII-8BIT") if head.respond_to?(:force_encoding)
243
- params["files"][:head].should.equal head
244
- params["files"][:name].should.equal "files"
245
- params["files"][:tempfile].read.should.equal "contents"
282
+ head = head.force_encoding(Encoding::ASCII_8BIT)
283
+ params["files"][:head].must_equal head
284
+ params["files"][:name].must_equal "files"
285
+ params["files"][:tempfile].read.must_equal "contents"
246
286
  end
247
287
 
248
- should "not include file params if no file was selected" do
249
- env = Rack::MockRequest.env_for("/", multipart_fixture(:none))
288
+ it "parse multipart form with an encoded word filename" do
289
+ env = Rack::MockRequest.env_for '/', multipart_fixture(:filename_with_encoded_words)
250
290
  params = Rack::Multipart.parse_multipart(env)
251
- params["submit-name"].should.equal "Larry"
252
- params["files"].should.equal nil
253
- params.keys.should.not.include "files"
291
+ params["files"][:filename].must_equal "файл"
254
292
  end
255
293
 
256
- should "parse multipart/mixed" do
257
- env = Rack::MockRequest.env_for("/", multipart_fixture(:mixed_files))
258
- params = Rack::Utils::Multipart.parse_multipart(env)
259
- params["foo"].should.equal "bar"
260
- params["files"].should.be.instance_of String
261
- params["files"].size.should.equal 252
294
+ it "parse multipart form with a single quote in the filename" do
295
+ env = Rack::MockRequest.env_for '/', multipart_fixture(:filename_with_single_quote)
296
+ params = Rack::Multipart.parse_multipart(env)
297
+ params["files"][:filename].must_equal "bob's flowers.jpg"
262
298
  end
263
299
 
264
- should "parse multipart form with a null byte in the filename" do
265
- env = Rack::MockRequest.env_for '/', multipart_fixture(:filename_with_null_byte)
300
+ it "not include file params if no file was selected" do
301
+ env = Rack::MockRequest.env_for("/", multipart_fixture(:none))
266
302
  params = Rack::Multipart.parse_multipart(env)
267
- if "<3".respond_to?(:encoding)
268
- params["files"][:filename].should.equal "flowers.exe\u0000.jpg"
269
- else
270
- params["files"][:filename].should.equal "flowers.exe\000.jpg"
271
- end
303
+ params["submit-name"].must_equal "Larry"
304
+ params["files"].must_equal nil
305
+ params.keys.wont_include "files"
272
306
  end
273
307
 
274
- should "parse multipart/mixed" do
308
+ it "parse multipart/mixed" do
275
309
  env = Rack::MockRequest.env_for("/", multipart_fixture(:mixed_files))
276
- params = Rack::Utils::Multipart.parse_multipart(env)
277
- params["foo"].should.equal "bar"
278
- params["files"].should.be.instance_of String
279
- params["files"].size.should.equal 252
310
+ params = Rack::Multipart.parse_multipart(env)
311
+ params["foo"].must_equal "bar"
312
+ params["files"].must_be_instance_of String
313
+ params["files"].size.must_equal 252
280
314
  end
281
315
 
282
- should "parse IE multipart upload and clean up filename" do
316
+ it "parse IE multipart upload and clean up filename" do
283
317
  env = Rack::MockRequest.env_for("/", multipart_fixture(:ie))
284
318
  params = Rack::Multipart.parse_multipart(env)
285
- params["files"][:type].should.equal "text/plain"
286
- params["files"][:filename].should.equal "file1.txt"
287
- params["files"][:head].should.equal "Content-Disposition: form-data; " +
319
+ params["files"][:type].must_equal "text/plain"
320
+ params["files"][:filename].must_equal "file1.txt"
321
+ params["files"][:head].must_equal "Content-Disposition: form-data; " +
288
322
  "name=\"files\"; " +
289
323
  'filename="C:\Documents and Settings\Administrator\Desktop\file1.txt"' +
290
324
  "\r\nContent-Type: text/plain\r\n"
291
- params["files"][:name].should.equal "files"
292
- params["files"][:tempfile].read.should.equal "contents"
325
+ params["files"][:name].must_equal "files"
326
+ params["files"][:tempfile].read.must_equal "contents"
293
327
  end
294
328
 
295
- should "parse filename and modification param" do
329
+ it "parse filename and modification param" do
296
330
  env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_and_modification_param))
297
331
  params = Rack::Multipart.parse_multipart(env)
298
- params["files"][:type].should.equal "image/jpeg"
299
- params["files"][:filename].should.equal "genome.jpeg"
300
- params["files"][:head].should.equal "Content-Type: image/jpeg\r\n" +
332
+ params["files"][:type].must_equal "image/jpeg"
333
+ params["files"][:filename].must_equal "genome.jpeg"
334
+ params["files"][:head].must_equal "Content-Type: image/jpeg\r\n" +
301
335
  "Content-Disposition: attachment; " +
302
336
  "name=\"files\"; " +
303
337
  "filename=genome.jpeg; " +
304
338
  "modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\";\r\n" +
305
339
  "Content-Description: a complete map of the human genome\r\n"
306
- params["files"][:name].should.equal "files"
307
- params["files"][:tempfile].read.should.equal "contents"
340
+ params["files"][:name].must_equal "files"
341
+ params["files"][:tempfile].read.must_equal "contents"
308
342
  end
309
343
 
310
- should "parse filename with escaped quotes" do
344
+ it "parse filename with escaped quotes" do
311
345
  env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_escaped_quotes))
312
346
  params = Rack::Multipart.parse_multipart(env)
313
- params["files"][:type].should.equal "application/octet-stream"
314
- params["files"][:filename].should.equal "escape \"quotes"
315
- params["files"][:head].should.equal "Content-Disposition: form-data; " +
347
+ params["files"][:type].must_equal "application/octet-stream"
348
+ params["files"][:filename].must_equal "escape \"quotes"
349
+ params["files"][:head].must_equal "Content-Disposition: form-data; " +
316
350
  "name=\"files\"; " +
317
351
  "filename=\"escape \\\"quotes\"\r\n" +
318
352
  "Content-Type: application/octet-stream\r\n"
319
- params["files"][:name].should.equal "files"
320
- params["files"][:tempfile].read.should.equal "contents"
353
+ params["files"][:name].must_equal "files"
354
+ params["files"][:tempfile].read.must_equal "contents"
321
355
  end
322
356
 
323
- should "parse filename with percent escaped quotes" do
357
+ it "parse filename with percent escaped quotes" do
324
358
  env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_percent_escaped_quotes))
325
359
  params = Rack::Multipart.parse_multipart(env)
326
- params["files"][:type].should.equal "application/octet-stream"
327
- params["files"][:filename].should.equal "escape \"quotes"
328
- params["files"][:head].should.equal "Content-Disposition: form-data; " +
360
+ params["files"][:type].must_equal "application/octet-stream"
361
+ params["files"][:filename].must_equal "escape \"quotes"
362
+ params["files"][:head].must_equal "Content-Disposition: form-data; " +
329
363
  "name=\"files\"; " +
330
364
  "filename=\"escape %22quotes\"\r\n" +
331
365
  "Content-Type: application/octet-stream\r\n"
332
- params["files"][:name].should.equal "files"
333
- params["files"][:tempfile].read.should.equal "contents"
366
+ params["files"][:name].must_equal "files"
367
+ params["files"][:tempfile].read.must_equal "contents"
334
368
  end
335
369
 
336
- should "parse filename with unescaped quotes" do
370
+ it "parse filename with unescaped quotes" do
337
371
  env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_unescaped_quotes))
338
372
  params = Rack::Multipart.parse_multipart(env)
339
- params["files"][:type].should.equal "application/octet-stream"
340
- params["files"][:filename].should.equal "escape \"quotes"
341
- params["files"][:head].should.equal "Content-Disposition: form-data; " +
373
+ params["files"][:type].must_equal "application/octet-stream"
374
+ params["files"][:filename].must_equal "escape \"quotes"
375
+ params["files"][:head].must_equal "Content-Disposition: form-data; " +
342
376
  "name=\"files\"; " +
343
377
  "filename=\"escape \"quotes\"\r\n" +
344
378
  "Content-Type: application/octet-stream\r\n"
345
- params["files"][:name].should.equal "files"
346
- params["files"][:tempfile].read.should.equal "contents"
379
+ params["files"][:name].must_equal "files"
380
+ params["files"][:tempfile].read.must_equal "contents"
347
381
  end
348
382
 
349
- should "parse filename with escaped quotes and modification param" do
383
+ it "parse filename with escaped quotes and modification param" do
350
384
  env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_escaped_quotes_and_modification_param))
351
385
  params = Rack::Multipart.parse_multipart(env)
352
- params["files"][:type].should.equal "image/jpeg"
353
- params["files"][:filename].should.equal "\"human\" genome.jpeg"
354
- params["files"][:head].should.equal "Content-Type: image/jpeg\r\n" +
386
+ params["files"][:type].must_equal "image/jpeg"
387
+ params["files"][:filename].must_equal "\"human\" genome.jpeg"
388
+ params["files"][:head].must_equal "Content-Type: image/jpeg\r\n" +
355
389
  "Content-Disposition: attachment; " +
356
390
  "name=\"files\"; " +
357
391
  "filename=\"\"human\" genome.jpeg\"; " +
358
392
  "modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\";\r\n" +
359
393
  "Content-Description: a complete map of the human genome\r\n"
360
- params["files"][:name].should.equal "files"
361
- params["files"][:tempfile].read.should.equal "contents"
394
+ params["files"][:name].must_equal "files"
395
+ params["files"][:tempfile].read.must_equal "contents"
362
396
  end
363
397
 
364
- should "parse filename with unescaped percentage characters" do
398
+ it "parse filename with unescaped percentage characters" do
365
399
  env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_unescaped_percentages, "----WebKitFormBoundary2NHc7OhsgU68l3Al"))
366
400
  params = Rack::Multipart.parse_multipart(env)
367
401
  files = params["document"]["attachment"]
368
- files[:type].should.equal "image/jpeg"
369
- files[:filename].should.equal "100% of a photo.jpeg"
370
- files[:head].should.equal <<-MULTIPART
402
+ files[:type].must_equal "image/jpeg"
403
+ files[:filename].must_equal "100% of a photo.jpeg"
404
+ files[:head].must_equal <<-MULTIPART
371
405
  Content-Disposition: form-data; name="document[attachment]"; filename="100% of a photo.jpeg"\r
372
406
  Content-Type: image/jpeg\r
373
407
  MULTIPART
374
408
 
375
- files[:name].should.equal "document[attachment]"
376
- files[:tempfile].read.should.equal "contents"
409
+ files[:name].must_equal "document[attachment]"
410
+ files[:tempfile].read.must_equal "contents"
377
411
  end
378
412
 
379
- should "parse filename with unescaped percentage characters that look like partial hex escapes" do
413
+ it "parse filename with unescaped percentage characters that look like partial hex escapes" do
380
414
  env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_unescaped_percentages2, "----WebKitFormBoundary2NHc7OhsgU68l3Al"))
381
415
  params = Rack::Multipart.parse_multipart(env)
382
416
  files = params["document"]["attachment"]
383
- files[:type].should.equal "image/jpeg"
384
- files[:filename].should.equal "100%a"
385
- files[:head].should.equal <<-MULTIPART
417
+ files[:type].must_equal "image/jpeg"
418
+ files[:filename].must_equal "100%a"
419
+ files[:head].must_equal <<-MULTIPART
386
420
  Content-Disposition: form-data; name="document[attachment]"; filename="100%a"\r
387
421
  Content-Type: image/jpeg\r
388
422
  MULTIPART
389
423
 
390
- files[:name].should.equal "document[attachment]"
391
- files[:tempfile].read.should.equal "contents"
424
+ files[:name].must_equal "document[attachment]"
425
+ files[:tempfile].read.must_equal "contents"
392
426
  end
393
427
 
394
- should "parse filename with unescaped percentage characters that look like partial hex escapes" do
428
+ it "parse filename with unescaped percentage characters that look like partial hex escapes" do
395
429
  env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_unescaped_percentages3, "----WebKitFormBoundary2NHc7OhsgU68l3Al"))
396
430
  params = Rack::Multipart.parse_multipart(env)
397
431
  files = params["document"]["attachment"]
398
- files[:type].should.equal "image/jpeg"
399
- files[:filename].should.equal "100%"
400
- files[:head].should.equal <<-MULTIPART
432
+ files[:type].must_equal "image/jpeg"
433
+ files[:filename].must_equal "100%"
434
+ files[:head].must_equal <<-MULTIPART
401
435
  Content-Disposition: form-data; name="document[attachment]"; filename="100%"\r
402
436
  Content-Type: image/jpeg\r
403
437
  MULTIPART
404
438
 
405
- files[:name].should.equal "document[attachment]"
406
- files[:tempfile].read.should.equal "contents"
439
+ files[:name].must_equal "document[attachment]"
440
+ files[:tempfile].read.must_equal "contents"
407
441
  end
408
442
 
409
443
  it "rewinds input after parsing upload" do
@@ -411,9 +445,9 @@ Content-Type: image/jpeg\r
411
445
  input = options[:input]
412
446
  env = Rack::MockRequest.env_for("/", options)
413
447
  params = Rack::Multipart.parse_multipart(env)
414
- params["submit-name"].should.equal "Larry"
415
- params["files"][:filename].should.equal "file1.txt"
416
- input.read.length.should.equal 307
448
+ params["submit-name"].must_equal "Larry"
449
+ params["files"][:filename].must_equal "file1.txt"
450
+ input.read.length.must_equal 307
417
451
  end
418
452
 
419
453
  it "builds multipart body" do
@@ -427,9 +461,9 @@ Content-Type: image/jpeg\r
427
461
  }
428
462
  env = Rack::MockRequest.env_for("/", options)
429
463
  params = Rack::Multipart.parse_multipart(env)
430
- params["submit-name"].should.equal "Larry"
431
- params["files"][:filename].should.equal "file1.txt"
432
- params["files"][:tempfile].read.should.equal "contents"
464
+ params["submit-name"].must_equal "Larry"
465
+ params["files"][:filename].must_equal "file1.txt"
466
+ params["files"][:tempfile].read.must_equal "contents"
433
467
  end
434
468
 
435
469
  it "builds nested multipart body" do
@@ -443,9 +477,9 @@ Content-Type: image/jpeg\r
443
477
  }
444
478
  env = Rack::MockRequest.env_for("/", options)
445
479
  params = Rack::Multipart.parse_multipart(env)
446
- params["people"][0]["submit-name"].should.equal "Larry"
447
- params["people"][0]["files"][:filename].should.equal "file1.txt"
448
- params["people"][0]["files"][:tempfile].read.should.equal "contents"
480
+ params["people"][0]["submit-name"].must_equal "Larry"
481
+ params["people"][0]["files"][:filename].must_equal "file1.txt"
482
+ params["people"][0]["files"][:tempfile].read.must_equal "contents"
449
483
  end
450
484
 
451
485
  it "can parse fields that end at the end of the buffer" do
@@ -456,8 +490,8 @@ Content-Type: image/jpeg\r
456
490
  "CONTENT_LENGTH" => input.size,
457
491
  :input => input)
458
492
 
459
- req.POST['file.path'].should.equal "/var/tmp/uploads/4/0001728414"
460
- req.POST['addresses'].should.not.equal nil
493
+ req.POST['file.path'].must_equal "/var/tmp/uploads/4/0001728414"
494
+ req.POST['addresses'].wont_equal nil
461
495
  end
462
496
 
463
497
  it "builds complete params with the chunk size of 16384 slicing exactly on boundary" do
@@ -474,54 +508,54 @@ Content-Type: image/jpeg\r
474
508
  env = Rack::MockRequest.env_for("/", options)
475
509
  params = Rack::Multipart.parse_multipart(env)
476
510
 
477
- params.should.not.equal nil
478
- params.keys.should.include "AAAAAAAAAAAAAAAAAAA"
479
- params["AAAAAAAAAAAAAAAAAAA"].keys.should.include "PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"
480
- params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"].keys.should.include "new"
481
- params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"].keys.should.include "-2"
482
- params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"]["-2"].keys.should.include "ba_unit_id"
483
- params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"]["-2"]["ba_unit_id"].should.equal "1017"
511
+ params.wont_equal nil
512
+ params.keys.must_include "AAAAAAAAAAAAAAAAAAA"
513
+ params["AAAAAAAAAAAAAAAAAAA"].keys.must_include "PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"
514
+ params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"].keys.must_include "new"
515
+ params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"].keys.must_include "-2"
516
+ params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"]["-2"].keys.must_include "ba_unit_id"
517
+ params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"]["-2"]["ba_unit_id"].must_equal "1017"
484
518
  ensure
485
519
  Rack::Utils.multipart_part_limit = previous_limit
486
520
  end
487
521
  end
488
522
 
489
- should "not reach a multi-part limit" do
523
+ it "not reach a multi-part limit" do
490
524
  begin
491
525
  previous_limit = Rack::Utils.multipart_part_limit
492
526
  Rack::Utils.multipart_part_limit = 4
493
527
 
494
528
  env = Rack::MockRequest.env_for '/', multipart_fixture(:three_files_three_fields)
495
529
  params = Rack::Multipart.parse_multipart(env)
496
- params['reply'].should.equal 'yes'
497
- params['to'].should.equal 'people'
498
- params['from'].should.equal 'others'
530
+ params['reply'].must_equal 'yes'
531
+ params['to'].must_equal 'people'
532
+ params['from'].must_equal 'others'
499
533
  ensure
500
534
  Rack::Utils.multipart_part_limit = previous_limit
501
535
  end
502
536
  end
503
537
 
504
- should "reach a multipart limit" do
538
+ it "reach a multipart limit" do
505
539
  begin
506
540
  previous_limit = Rack::Utils.multipart_part_limit
507
541
  Rack::Utils.multipart_part_limit = 3
508
542
 
509
543
  env = Rack::MockRequest.env_for '/', multipart_fixture(:three_files_three_fields)
510
- lambda { Rack::Multipart.parse_multipart(env) }.should.raise(Rack::Multipart::MultipartPartLimitError)
544
+ lambda { Rack::Multipart.parse_multipart(env) }.must_raise Rack::Multipart::MultipartPartLimitError
511
545
  ensure
512
546
  Rack::Utils.multipart_part_limit = previous_limit
513
547
  end
514
548
  end
515
549
 
516
- should "return nil if no UploadedFiles were used" do
550
+ it "return nil if no UploadedFiles were used" do
517
551
  data = Rack::Multipart.build_multipart("people" => [{"submit-name" => "Larry", "files" => "contents"}])
518
- data.should.equal nil
552
+ data.must_equal nil
519
553
  end
520
554
 
521
- should "raise ArgumentError if params is not a Hash" do
522
- lambda { Rack::Multipart.build_multipart("foo=bar") }.
523
- should.raise(ArgumentError).
524
- message.should.equal "value must be a Hash"
555
+ it "raise ArgumentError if params is not a Hash" do
556
+ lambda {
557
+ Rack::Multipart.build_multipart("foo=bar")
558
+ }.must_raise(ArgumentError).message.must_equal "value must be a Hash"
525
559
  end
526
560
 
527
561
  it "can parse fields with a content type" do
@@ -539,20 +573,20 @@ EOF
539
573
  :input => StringIO.new(data)
540
574
  }
541
575
  env = Rack::MockRequest.env_for("/", options)
542
- params = Rack::Utils::Multipart.parse_multipart(env)
576
+ params = Rack::Multipart.parse_multipart(env)
543
577
 
544
- params.should.equal({"description"=>"Very very blue"})
578
+ params.must_equal "description"=>"Very very blue"
545
579
  end
546
580
 
547
- should "parse multipart upload with no content-length header" do
581
+ it "parse multipart upload with no content-length header" do
548
582
  env = Rack::MockRequest.env_for '/', multipart_fixture(:webkit)
549
583
  env['CONTENT_TYPE'] = "multipart/form-data; boundary=----WebKitFormBoundaryWLHCs9qmcJJoyjKR"
550
584
  env.delete 'CONTENT_LENGTH'
551
585
  params = Rack::Multipart.parse_multipart(env)
552
- params['profile']['bio'].should.include 'hello'
586
+ params['profile']['bio'].must_include 'hello'
553
587
  end
554
588
 
555
- should "parse very long unquoted multipart file names" do
589
+ it "parse very long unquoted multipart file names" do
556
590
  data = <<-EOF
557
591
  --AaB03x\r
558
592
  Content-Type: text/plain\r
@@ -568,17 +602,57 @@ contents\r
568
602
  :input => StringIO.new(data)
569
603
  }
570
604
  env = Rack::MockRequest.env_for("/", options)
571
- params = Rack::Utils::Multipart.parse_multipart(env)
605
+ params = Rack::Multipart.parse_multipart(env)
606
+
607
+ params["file"][:filename].must_equal 'long' * 100
608
+ end
609
+
610
+ it "parse unquoted parameter values at end of line" do
611
+ data = <<-EOF
612
+ --AaB03x\r
613
+ Content-Type: text/plain\r
614
+ Content-Disposition: attachment; name=inline\r
615
+ \r
616
+ true\r
617
+ --AaB03x--\r
618
+ EOF
619
+
620
+ options = {
621
+ "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
622
+ "CONTENT_LENGTH" => data.length.to_s,
623
+ :input => StringIO.new(data)
624
+ }
625
+ env = Rack::MockRequest.env_for("/", options)
626
+ params = Rack::Multipart.parse_multipart(env)
627
+ params["inline"].must_equal 'true'
628
+ end
629
+
630
+ it "parse quoted chars in name parameter" do
631
+ data = <<-EOF
632
+ --AaB03x\r
633
+ Content-Type: text/plain\r
634
+ Content-Disposition: attachment; name="quoted\\\\chars\\"in\rname"\r
635
+ \r
636
+ true\r
637
+ --AaB03x--\r
638
+ EOF
572
639
 
573
- params["file"][:filename].should.equal('long' * 100)
640
+ options = {
641
+ "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
642
+ "CONTENT_LENGTH" => data.length.to_s,
643
+ :input => StringIO.new(data)
644
+ }
645
+ env = Rack::MockRequest.env_for("/", options)
646
+ params = Rack::Multipart.parse_multipart(env)
647
+ params["quoted\\chars\"in\rname"].must_equal 'true'
574
648
  end
575
649
 
576
- should "support mixed case metadata" do
650
+ it "support mixed case metadata" do
577
651
  file = multipart_file(:text)
578
652
  data = File.open(file, 'rb') { |io| io.read }
579
653
 
580
654
  type = "Multipart/Form-Data; Boundary=AaB03x"
581
- length = data.respond_to?(:bytesize) ? data.bytesize : data.size
655
+ length = data.bytesize
582
656
 
583
657
  e = { "CONTENT_TYPE" => type,
584
658
  "CONTENT_LENGTH" => length.to_s,
@@ -586,15 +660,49 @@ contents\r
586
660
 
587
661
  env = Rack::MockRequest.env_for("/", e)
588
662
  params = Rack::Multipart.parse_multipart(env)
589
- params["submit-name"].should.equal "Larry"
590
- params["submit-name-with-content"].should.equal "Berry"
591
- params["files"][:type].should.equal "text/plain"
592
- params["files"][:filename].should.equal "file1.txt"
593
- params["files"][:head].should.equal "Content-Disposition: form-data; " +
663
+ params["submit-name"].must_equal "Larry"
664
+ params["submit-name-with-content"].must_equal "Berry"
665
+ params["files"][:type].must_equal "text/plain"
666
+ params["files"][:filename].must_equal "file1.txt"
667
+ params["files"][:head].must_equal "Content-Disposition: form-data; " +
594
668
  "name=\"files\"; filename=\"file1.txt\"\r\n" +
595
669
  "Content-Type: text/plain\r\n"
596
- params["files"][:name].should.equal "files"
597
- params["files"][:tempfile].read.should.equal "contents"
670
+ params["files"][:name].must_equal "files"
671
+ params["files"][:tempfile].read.must_equal "contents"
598
672
  end
599
673
 
674
+ it "fallback to content-type for name" do
675
+ rack_logo = File.read(multipart_file("rack-logo.png"))
676
+
677
+ data = <<-EOF
678
+ --AaB03x\r
679
+ Content-Type: text/plain\r
680
+ \r
681
+ some text\r
682
+ --AaB03x\r
683
+ \r
684
+ \r
685
+ some more text (I didn't specify Content-Type)\r
686
+ --AaB03x\r
687
+ Content-Type: image/png\r
688
+ \r
689
+ #{rack_logo}\r
690
+ --AaB03x--\r
691
+ EOF
692
+
693
+ options = {
694
+ "CONTENT_TYPE" => "multipart/related; boundary=AaB03x",
695
+ "CONTENT_LENGTH" => data.bytesize.to_s,
696
+ :input => StringIO.new(data)
697
+ }
698
+ env = Rack::MockRequest.env_for("/", options)
699
+ params = Rack::Multipart.parse_multipart(env)
700
+
701
+ params["text/plain"].must_equal ["some text", "some more text (I didn't specify Content-Type)"]
702
+ params["image/png"].length.must_equal 1
703
+
704
+ f = Tempfile.new("rack-logo")
705
+ f.write(params["image/png"][0])
706
+ f.length.must_equal 26473
707
+ end
600
708
  end