rack 1.6.13 → 2.0.9

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