rack 1.6.13 → 2.0.9.3

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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/COPYING +1 -1
  3. data/HISTORY.md +153 -8
  4. data/README.rdoc +35 -31
  5. data/Rakefile +6 -14
  6. data/SPEC +10 -11
  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} +6 -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 +41 -41
  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 +283 -157
  41. data/lib/rack/multipart/uploaded_file.rb +1 -2
  42. data/lib/rack/multipart.rb +36 -8
  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 +156 -217
  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_escaped_quotes_and_modification_param +1 -1
  71. data/test/multipart/filename_with_single_quote +7 -0
  72. data/test/multipart/quoted +15 -0
  73. data/test/multipart/rack-logo.png +0 -0
  74. data/test/multipart/unity3d_wwwform +11 -0
  75. data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
  76. data/test/spec_auth_basic.rb +27 -19
  77. data/test/spec_auth_digest.rb +47 -46
  78. data/test/spec_body_proxy.rb +27 -27
  79. data/test/spec_builder.rb +51 -41
  80. data/test/spec_cascade.rb +24 -22
  81. data/test/spec_cgi.rb +49 -67
  82. data/test/spec_chunked.rb +37 -35
  83. data/test/{spec_commonlogger.rb → spec_common_logger.rb} +35 -21
  84. data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
  85. data/test/spec_config.rb +3 -2
  86. data/test/spec_content_length.rb +18 -17
  87. data/test/spec_content_type.rb +13 -12
  88. data/test/spec_deflater.rb +85 -49
  89. data/test/spec_directory.rb +87 -27
  90. data/test/spec_etag.rb +32 -31
  91. data/test/spec_events.rb +133 -0
  92. data/test/spec_fastcgi.rb +50 -72
  93. data/test/spec_file.rb +120 -77
  94. data/test/spec_handler.rb +19 -34
  95. data/test/spec_head.rb +15 -14
  96. data/test/spec_lint.rb +169 -199
  97. data/test/spec_lobster.rb +24 -23
  98. data/test/spec_lock.rb +79 -39
  99. data/test/spec_logger.rb +4 -3
  100. data/test/spec_media_type.rb +42 -0
  101. data/test/{spec_methodoverride.rb → spec_method_override.rb} +34 -35
  102. data/test/spec_mime.rb +19 -19
  103. data/test/spec_mock.rb +206 -144
  104. data/test/spec_multipart.rb +329 -208
  105. data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
  106. data/test/spec_recursive.rb +17 -14
  107. data/test/spec_request.rb +796 -605
  108. data/test/spec_response.rb +233 -112
  109. data/test/spec_rewindable_input.rb +50 -40
  110. data/test/spec_runtime.rb +11 -10
  111. data/test/spec_sendfile.rb +30 -35
  112. data/test/spec_server.rb +78 -52
  113. data/test/spec_session_abstract_id.rb +11 -33
  114. data/test/spec_session_abstract_session_hash.rb +45 -0
  115. data/test/spec_session_cookie.rb +99 -67
  116. data/test/spec_session_memcache.rb +67 -68
  117. data/test/spec_session_pool.rb +52 -51
  118. data/test/{spec_showexceptions.rb → spec_show_exceptions.rb} +23 -28
  119. data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
  120. data/test/spec_static.rb +71 -32
  121. data/test/spec_tempfile_reaper.rb +11 -10
  122. data/test/spec_thin.rb +55 -50
  123. data/test/spec_urlmap.rb +79 -78
  124. data/test/spec_utils.rb +441 -346
  125. data/test/spec_version.rb +2 -8
  126. data/test/spec_webrick.rb +93 -71
  127. data/test/static/foo.html +1 -0
  128. data/test/testrequest.rb +1 -1
  129. data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
  130. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
  131. metadata +95 -74
  132. data/KNOWN-ISSUES +0 -44
  133. data/lib/rack/backports/uri/common_18.rb +0 -56
  134. data/lib/rack/backports/uri/common_192.rb +0 -52
  135. data/lib/rack/backports/uri/common_193.rb +0 -29
  136. data/lib/rack/handler/evented_mongrel.rb +0 -8
  137. data/lib/rack/handler/mongrel.rb +0 -106
  138. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  139. data/lib/rack/showexceptions.rb +0 -387
  140. data/lib/rack/utils/okjson.rb +0 -600
  141. data/test/spec_mongrel.rb +0 -182
  142. /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,302 @@ 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"
174
+ end
175
+
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"
154
187
  end
155
188
 
156
- should "preserve extension in the created tempfile" do
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"
334
- end
335
-
336
- should "parse filename with unescaped quotes" do
337
- env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_unescaped_quotes))
338
- 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; " +
342
- "name=\"files\"; " +
343
- "filename=\"escape \"quotes\"\r\n" +
344
- "Content-Type: application/octet-stream\r\n"
345
- params["files"][:name].should.equal "files"
346
- params["files"][:tempfile].read.should.equal "contents"
380
+ params["files"][:name].must_equal "files"
381
+ params["files"][:tempfile].read.must_equal "contents"
347
382
  end
348
383
 
349
- should "parse filename with escaped quotes and modification param" do
384
+ it "parse filename with escaped quotes and modification param" do
350
385
  env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_escaped_quotes_and_modification_param))
351
386
  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" +
387
+ params["files"][:type].must_equal "image/jpeg"
388
+ params["files"][:filename].must_equal "\"human\" genome.jpeg"
389
+ params["files"][:head].must_equal "Content-Type: image/jpeg\r\n" +
355
390
  "Content-Disposition: attachment; " +
356
391
  "name=\"files\"; " +
357
- "filename=\"\"human\" genome.jpeg\"; " +
392
+ "filename=\"\\\"human\\\" genome.jpeg\"; " +
358
393
  "modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\";\r\n" +
359
394
  "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"
395
+ params["files"][:name].must_equal "files"
396
+ params["files"][:tempfile].read.must_equal "contents"
362
397
  end
363
398
 
364
- should "parse filename with unescaped percentage characters" do
399
+ it "parse filename with unescaped percentage characters" do
365
400
  env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_unescaped_percentages, "----WebKitFormBoundary2NHc7OhsgU68l3Al"))
366
401
  params = Rack::Multipart.parse_multipart(env)
367
402
  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
403
+ files[:type].must_equal "image/jpeg"
404
+ files[:filename].must_equal "100% of a photo.jpeg"
405
+ files[:head].must_equal <<-MULTIPART
371
406
  Content-Disposition: form-data; name="document[attachment]"; filename="100% of a photo.jpeg"\r
372
407
  Content-Type: image/jpeg\r
373
408
  MULTIPART
374
409
 
375
- files[:name].should.equal "document[attachment]"
376
- files[:tempfile].read.should.equal "contents"
410
+ files[:name].must_equal "document[attachment]"
411
+ files[:tempfile].read.must_equal "contents"
377
412
  end
378
413
 
379
- should "parse filename with unescaped percentage characters that look like partial hex escapes" do
414
+ it "parse filename with unescaped percentage characters that look like partial hex escapes" do
380
415
  env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_unescaped_percentages2, "----WebKitFormBoundary2NHc7OhsgU68l3Al"))
381
416
  params = Rack::Multipart.parse_multipart(env)
382
417
  files = params["document"]["attachment"]
383
- files[:type].should.equal "image/jpeg"
384
- files[:filename].should.equal "100%a"
385
- files[:head].should.equal <<-MULTIPART
418
+ files[:type].must_equal "image/jpeg"
419
+ files[:filename].must_equal "100%a"
420
+ files[:head].must_equal <<-MULTIPART
386
421
  Content-Disposition: form-data; name="document[attachment]"; filename="100%a"\r
387
422
  Content-Type: image/jpeg\r
388
423
  MULTIPART
389
424
 
390
- files[:name].should.equal "document[attachment]"
391
- files[:tempfile].read.should.equal "contents"
425
+ files[:name].must_equal "document[attachment]"
426
+ files[:tempfile].read.must_equal "contents"
392
427
  end
393
428
 
394
- should "parse filename with unescaped percentage characters that look like partial hex escapes" do
429
+ it "parse filename with unescaped percentage characters that look like partial hex escapes" do
395
430
  env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_unescaped_percentages3, "----WebKitFormBoundary2NHc7OhsgU68l3Al"))
396
431
  params = Rack::Multipart.parse_multipart(env)
397
432
  files = params["document"]["attachment"]
398
- files[:type].should.equal "image/jpeg"
399
- files[:filename].should.equal "100%"
400
- files[:head].should.equal <<-MULTIPART
433
+ files[:type].must_equal "image/jpeg"
434
+ files[:filename].must_equal "100%"
435
+ files[:head].must_equal <<-MULTIPART
401
436
  Content-Disposition: form-data; name="document[attachment]"; filename="100%"\r
402
437
  Content-Type: image/jpeg\r
403
438
  MULTIPART
404
439
 
405
- files[:name].should.equal "document[attachment]"
406
- files[:tempfile].read.should.equal "contents"
440
+ files[:name].must_equal "document[attachment]"
441
+ files[:tempfile].read.must_equal "contents"
407
442
  end
408
443
 
409
444
  it "rewinds input after parsing upload" do
@@ -411,9 +446,9 @@ Content-Type: image/jpeg\r
411
446
  input = options[:input]
412
447
  env = Rack::MockRequest.env_for("/", options)
413
448
  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
449
+ params["submit-name"].must_equal "Larry"
450
+ params["files"][:filename].must_equal "file1.txt"
451
+ input.read.length.must_equal 307
417
452
  end
418
453
 
419
454
  it "builds multipart body" do
@@ -427,9 +462,9 @@ Content-Type: image/jpeg\r
427
462
  }
428
463
  env = Rack::MockRequest.env_for("/", options)
429
464
  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"
465
+ params["submit-name"].must_equal "Larry"
466
+ params["files"][:filename].must_equal "file1.txt"
467
+ params["files"][:tempfile].read.must_equal "contents"
433
468
  end
434
469
 
435
470
  it "builds nested multipart body" do
@@ -443,9 +478,9 @@ Content-Type: image/jpeg\r
443
478
  }
444
479
  env = Rack::MockRequest.env_for("/", options)
445
480
  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"
481
+ params["people"][0]["submit-name"].must_equal "Larry"
482
+ params["people"][0]["files"][:filename].must_equal "file1.txt"
483
+ params["people"][0]["files"][:tempfile].read.must_equal "contents"
449
484
  end
450
485
 
451
486
  it "can parse fields that end at the end of the buffer" do
@@ -456,8 +491,8 @@ Content-Type: image/jpeg\r
456
491
  "CONTENT_LENGTH" => input.size,
457
492
  :input => input)
458
493
 
459
- req.POST['file.path'].should.equal "/var/tmp/uploads/4/0001728414"
460
- req.POST['addresses'].should.not.equal nil
494
+ req.POST['file.path'].must_equal "/var/tmp/uploads/4/0001728414"
495
+ req.POST['addresses'].wont_equal nil
461
496
  end
462
497
 
463
498
  it "builds complete params with the chunk size of 16384 slicing exactly on boundary" do
@@ -474,54 +509,66 @@ Content-Type: image/jpeg\r
474
509
  env = Rack::MockRequest.env_for("/", options)
475
510
  params = Rack::Multipart.parse_multipart(env)
476
511
 
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"
512
+ params.wont_equal nil
513
+ params.keys.must_include "AAAAAAAAAAAAAAAAAAA"
514
+ params["AAAAAAAAAAAAAAAAAAA"].keys.must_include "PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"
515
+ params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"].keys.must_include "new"
516
+ params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"].keys.must_include "-2"
517
+ params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"]["-2"].keys.must_include "ba_unit_id"
518
+ params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"]["-2"]["ba_unit_id"].must_equal "1017"
484
519
  ensure
485
520
  Rack::Utils.multipart_part_limit = previous_limit
486
521
  end
487
522
  end
488
523
 
489
- should "not reach a multi-part limit" do
524
+ it "not reach a multi-part limit" do
490
525
  begin
491
526
  previous_limit = Rack::Utils.multipart_part_limit
492
527
  Rack::Utils.multipart_part_limit = 4
493
528
 
494
529
  env = Rack::MockRequest.env_for '/', multipart_fixture(:three_files_three_fields)
495
530
  params = Rack::Multipart.parse_multipart(env)
496
- params['reply'].should.equal 'yes'
497
- params['to'].should.equal 'people'
498
- params['from'].should.equal 'others'
531
+ params['reply'].must_equal 'yes'
532
+ params['to'].must_equal 'people'
533
+ params['from'].must_equal 'others'
499
534
  ensure
500
535
  Rack::Utils.multipart_part_limit = previous_limit
501
536
  end
502
537
  end
503
538
 
504
- should "reach a multipart limit" do
539
+ it "reach a multipart limit" do
505
540
  begin
506
541
  previous_limit = Rack::Utils.multipart_part_limit
507
542
  Rack::Utils.multipart_part_limit = 3
508
543
 
509
544
  env = Rack::MockRequest.env_for '/', multipart_fixture(:three_files_three_fields)
510
- lambda { Rack::Multipart.parse_multipart(env) }.should.raise(Rack::Multipart::MultipartPartLimitError)
545
+ lambda { Rack::Multipart.parse_multipart(env) }.must_raise Rack::Multipart::MultipartPartLimitError
511
546
  ensure
512
547
  Rack::Utils.multipart_part_limit = previous_limit
513
548
  end
514
549
  end
515
550
 
516
- should "return nil if no UploadedFiles were used" do
551
+ it "reach a multipart total limit" do
552
+ begin
553
+ previous_limit = Rack::Utils.multipart_total_part_limit
554
+ Rack::Utils.multipart_total_part_limit = 5
555
+
556
+ env = Rack::MockRequest.env_for '/', multipart_fixture(:three_files_three_fields)
557
+ lambda { Rack::Multipart.parse_multipart(env) }.must_raise Rack::Multipart::MultipartTotalPartLimitError
558
+ ensure
559
+ Rack::Utils.multipart_total_part_limit = previous_limit
560
+ end
561
+ end
562
+
563
+ it "return nil if no UploadedFiles were used" do
517
564
  data = Rack::Multipart.build_multipart("people" => [{"submit-name" => "Larry", "files" => "contents"}])
518
- data.should.equal nil
565
+ data.must_be_nil
519
566
  end
520
567
 
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"
568
+ it "raise ArgumentError if params is not a Hash" do
569
+ lambda {
570
+ Rack::Multipart.build_multipart("foo=bar")
571
+ }.must_raise(ArgumentError).message.must_equal "value must be a Hash"
525
572
  end
526
573
 
527
574
  it "can parse fields with a content type" do
@@ -539,20 +586,20 @@ EOF
539
586
  :input => StringIO.new(data)
540
587
  }
541
588
  env = Rack::MockRequest.env_for("/", options)
542
- params = Rack::Utils::Multipart.parse_multipart(env)
589
+ params = Rack::Multipart.parse_multipart(env)
543
590
 
544
- params.should.equal({"description"=>"Very very blue"})
591
+ params.must_equal "description"=>"Very very blue"
545
592
  end
546
593
 
547
- should "parse multipart upload with no content-length header" do
594
+ it "parse multipart upload with no content-length header" do
548
595
  env = Rack::MockRequest.env_for '/', multipart_fixture(:webkit)
549
596
  env['CONTENT_TYPE'] = "multipart/form-data; boundary=----WebKitFormBoundaryWLHCs9qmcJJoyjKR"
550
597
  env.delete 'CONTENT_LENGTH'
551
598
  params = Rack::Multipart.parse_multipart(env)
552
- params['profile']['bio'].should.include 'hello'
599
+ params['profile']['bio'].must_include 'hello'
553
600
  end
554
601
 
555
- should "parse very long unquoted multipart file names" do
602
+ it "parse very long unquoted multipart file names" do
556
603
  data = <<-EOF
557
604
  --AaB03x\r
558
605
  Content-Type: text/plain\r
@@ -568,17 +615,57 @@ contents\r
568
615
  :input => StringIO.new(data)
569
616
  }
570
617
  env = Rack::MockRequest.env_for("/", options)
571
- params = Rack::Utils::Multipart.parse_multipart(env)
618
+ params = Rack::Multipart.parse_multipart(env)
619
+
620
+ params["file"][:filename].must_equal 'long' * 100
621
+ end
622
+
623
+ it "parse unquoted parameter values at end of line" do
624
+ data = <<-EOF
625
+ --AaB03x\r
626
+ Content-Type: text/plain\r
627
+ Content-Disposition: attachment; name=inline\r
628
+ \r
629
+ true\r
630
+ --AaB03x--\r
631
+ EOF
632
+
633
+ options = {
634
+ "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
635
+ "CONTENT_LENGTH" => data.length.to_s,
636
+ :input => StringIO.new(data)
637
+ }
638
+ env = Rack::MockRequest.env_for("/", options)
639
+ params = Rack::Multipart.parse_multipart(env)
640
+ params["inline"].must_equal 'true'
641
+ end
642
+
643
+ it "parse quoted chars in name parameter" do
644
+ data = <<-EOF
645
+ --AaB03x\r
646
+ Content-Type: text/plain\r
647
+ Content-Disposition: attachment; name="quoted\\\\chars\\"in\rname"\r
648
+ \r
649
+ true\r
650
+ --AaB03x--\r
651
+ EOF
572
652
 
573
- params["file"][:filename].should.equal('long' * 100)
653
+ options = {
654
+ "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
655
+ "CONTENT_LENGTH" => data.length.to_s,
656
+ :input => StringIO.new(data)
657
+ }
658
+ env = Rack::MockRequest.env_for("/", options)
659
+ params = Rack::Multipart.parse_multipart(env)
660
+ params["quoted\\chars\"in\rname"].must_equal 'true'
574
661
  end
575
662
 
576
- should "support mixed case metadata" do
663
+ it "support mixed case metadata" do
577
664
  file = multipart_file(:text)
578
665
  data = File.open(file, 'rb') { |io| io.read }
579
666
 
580
667
  type = "Multipart/Form-Data; Boundary=AaB03x"
581
- length = data.respond_to?(:bytesize) ? data.bytesize : data.size
668
+ length = data.bytesize
582
669
 
583
670
  e = { "CONTENT_TYPE" => type,
584
671
  "CONTENT_LENGTH" => length.to_s,
@@ -586,15 +673,49 @@ contents\r
586
673
 
587
674
  env = Rack::MockRequest.env_for("/", e)
588
675
  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; " +
676
+ params["submit-name"].must_equal "Larry"
677
+ params["submit-name-with-content"].must_equal "Berry"
678
+ params["files"][:type].must_equal "text/plain"
679
+ params["files"][:filename].must_equal "file1.txt"
680
+ params["files"][:head].must_equal "Content-Disposition: form-data; " +
594
681
  "name=\"files\"; filename=\"file1.txt\"\r\n" +
595
682
  "Content-Type: text/plain\r\n"
596
- params["files"][:name].should.equal "files"
597
- params["files"][:tempfile].read.should.equal "contents"
683
+ params["files"][:name].must_equal "files"
684
+ params["files"][:tempfile].read.must_equal "contents"
598
685
  end
599
686
 
687
+ it "fallback to content-type for name" do
688
+ rack_logo = File.read(multipart_file("rack-logo.png"))
689
+
690
+ data = <<-EOF
691
+ --AaB03x\r
692
+ Content-Type: text/plain\r
693
+ \r
694
+ some text\r
695
+ --AaB03x\r
696
+ \r
697
+ \r
698
+ some more text (I didn't specify Content-Type)\r
699
+ --AaB03x\r
700
+ Content-Type: image/png\r
701
+ \r
702
+ #{rack_logo}\r
703
+ --AaB03x--\r
704
+ EOF
705
+
706
+ options = {
707
+ "CONTENT_TYPE" => "multipart/related; boundary=AaB03x",
708
+ "CONTENT_LENGTH" => data.bytesize.to_s,
709
+ :input => StringIO.new(data)
710
+ }
711
+ env = Rack::MockRequest.env_for("/", options)
712
+ params = Rack::Multipart.parse_multipart(env)
713
+
714
+ params["text/plain"].must_equal ["some text", "some more text (I didn't specify Content-Type)"]
715
+ params["image/png"].length.must_equal 1
716
+
717
+ f = Tempfile.new("rack-logo")
718
+ f.write(params["image/png"][0])
719
+ f.length.must_equal 26473
720
+ end
600
721
  end