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