rack 1.6.11 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack might be problematic. Click here for more details.

Files changed (190) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +675 -0
  3. data/CONTRIBUTING.md +136 -0
  4. data/{COPYING → MIT-LICENSE} +4 -2
  5. data/README.rdoc +157 -163
  6. data/Rakefile +38 -32
  7. data/{SPEC → SPEC.rdoc} +41 -13
  8. data/bin/rackup +1 -0
  9. data/contrib/rack_logo.svg +164 -111
  10. data/example/lobster.ru +2 -0
  11. data/example/protectedlobster.rb +4 -2
  12. data/example/protectedlobster.ru +3 -1
  13. data/lib/rack/auth/abstract/handler.rb +3 -1
  14. data/lib/rack/auth/abstract/request.rb +6 -2
  15. data/lib/rack/auth/basic.rb +7 -4
  16. data/lib/rack/auth/digest/md5.rb +13 -11
  17. data/lib/rack/auth/digest/nonce.rb +6 -3
  18. data/lib/rack/auth/digest/params.rb +5 -4
  19. data/lib/rack/auth/digest/request.rb +6 -4
  20. data/lib/rack/body_proxy.rb +21 -15
  21. data/lib/rack/builder.rb +119 -26
  22. data/lib/rack/cascade.rb +28 -12
  23. data/lib/rack/chunked.rb +70 -22
  24. data/lib/rack/common_logger.rb +80 -0
  25. data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -16
  26. data/lib/rack/config.rb +2 -0
  27. data/lib/rack/content_length.rb +9 -8
  28. data/lib/rack/content_type.rb +5 -4
  29. data/lib/rack/core_ext/regexp.rb +14 -0
  30. data/lib/rack/deflater.rb +60 -70
  31. data/lib/rack/directory.rb +117 -85
  32. data/lib/rack/etag.rb +9 -7
  33. data/lib/rack/events.rb +153 -0
  34. data/lib/rack/file.rb +4 -149
  35. data/lib/rack/files.rb +218 -0
  36. data/lib/rack/handler/cgi.rb +17 -19
  37. data/lib/rack/handler/fastcgi.rb +17 -18
  38. data/lib/rack/handler/lsws.rb +14 -14
  39. data/lib/rack/handler/scgi.rb +22 -21
  40. data/lib/rack/handler/thin.rb +20 -11
  41. data/lib/rack/handler/webrick.rb +39 -32
  42. data/lib/rack/handler.rb +9 -26
  43. data/lib/rack/head.rb +16 -18
  44. data/lib/rack/lint.rb +110 -64
  45. data/lib/rack/lobster.rb +10 -10
  46. data/lib/rack/lock.rb +17 -11
  47. data/lib/rack/logger.rb +4 -2
  48. data/lib/rack/media_type.rb +43 -0
  49. data/lib/rack/{methodoverride.rb → method_override.rb} +10 -8
  50. data/lib/rack/mime.rb +27 -6
  51. data/lib/rack/mock.rb +124 -65
  52. data/lib/rack/multipart/generator.rb +20 -16
  53. data/lib/rack/multipart/parser.rb +273 -162
  54. data/lib/rack/multipart/uploaded_file.rb +15 -8
  55. data/lib/rack/multipart.rb +39 -8
  56. data/lib/rack/{nulllogger.rb → null_logger.rb} +3 -1
  57. data/lib/rack/query_parser.rb +217 -0
  58. data/lib/rack/recursive.rb +11 -9
  59. data/lib/rack/reloader.rb +8 -4
  60. data/lib/rack/request.rb +543 -305
  61. data/lib/rack/response.rb +244 -88
  62. data/lib/rack/rewindable_input.rb +5 -15
  63. data/lib/rack/runtime.rb +12 -18
  64. data/lib/rack/sendfile.rb +17 -15
  65. data/lib/rack/server.rb +125 -47
  66. data/lib/rack/session/abstract/id.rb +216 -93
  67. data/lib/rack/session/cookie.rb +47 -31
  68. data/lib/rack/session/memcache.rb +4 -87
  69. data/lib/rack/session/pool.rb +26 -17
  70. data/lib/rack/show_exceptions.rb +390 -0
  71. data/lib/rack/{showstatus.rb → show_status.rb} +8 -8
  72. data/lib/rack/static.rb +48 -11
  73. data/lib/rack/tempfile_reaper.rb +3 -3
  74. data/lib/rack/urlmap.rb +26 -19
  75. data/lib/rack/utils.rb +208 -294
  76. data/lib/rack/version.rb +29 -0
  77. data/lib/rack.rb +76 -33
  78. data/rack.gemspec +43 -30
  79. metadata +62 -183
  80. data/HISTORY.md +0 -375
  81. data/KNOWN-ISSUES +0 -44
  82. data/lib/rack/backports/uri/common_18.rb +0 -56
  83. data/lib/rack/backports/uri/common_192.rb +0 -52
  84. data/lib/rack/backports/uri/common_193.rb +0 -29
  85. data/lib/rack/commonlogger.rb +0 -72
  86. data/lib/rack/handler/evented_mongrel.rb +0 -8
  87. data/lib/rack/handler/mongrel.rb +0 -106
  88. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  89. data/lib/rack/showexceptions.rb +0 -387
  90. data/lib/rack/utils/okjson.rb +0 -600
  91. data/test/builder/anything.rb +0 -5
  92. data/test/builder/comment.ru +0 -4
  93. data/test/builder/end.ru +0 -5
  94. data/test/builder/line.ru +0 -1
  95. data/test/builder/options.ru +0 -2
  96. data/test/cgi/assets/folder/test.js +0 -1
  97. data/test/cgi/assets/fonts/font.eot +0 -1
  98. data/test/cgi/assets/images/image.png +0 -1
  99. data/test/cgi/assets/index.html +0 -1
  100. data/test/cgi/assets/javascripts/app.js +0 -1
  101. data/test/cgi/assets/stylesheets/app.css +0 -1
  102. data/test/cgi/lighttpd.conf +0 -26
  103. data/test/cgi/rackup_stub.rb +0 -6
  104. data/test/cgi/sample_rackup.ru +0 -5
  105. data/test/cgi/test +0 -9
  106. data/test/cgi/test+directory/test+file +0 -1
  107. data/test/cgi/test.fcgi +0 -8
  108. data/test/cgi/test.ru +0 -5
  109. data/test/gemloader.rb +0 -10
  110. data/test/multipart/bad_robots +0 -259
  111. data/test/multipart/binary +0 -0
  112. data/test/multipart/content_type_and_no_filename +0 -6
  113. data/test/multipart/empty +0 -10
  114. data/test/multipart/fail_16384_nofile +0 -814
  115. data/test/multipart/file1.txt +0 -1
  116. data/test/multipart/filename_and_modification_param +0 -7
  117. data/test/multipart/filename_and_no_name +0 -6
  118. data/test/multipart/filename_with_escaped_quotes +0 -6
  119. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  120. data/test/multipart/filename_with_null_byte +0 -7
  121. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  122. data/test/multipart/filename_with_unescaped_percentages +0 -6
  123. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  124. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  125. data/test/multipart/filename_with_unescaped_quotes +0 -6
  126. data/test/multipart/ie +0 -6
  127. data/test/multipart/invalid_character +0 -6
  128. data/test/multipart/mixed_files +0 -21
  129. data/test/multipart/nested +0 -10
  130. data/test/multipart/none +0 -9
  131. data/test/multipart/semicolon +0 -6
  132. data/test/multipart/text +0 -15
  133. data/test/multipart/three_files_three_fields +0 -31
  134. data/test/multipart/webkit +0 -32
  135. data/test/rackup/config.ru +0 -31
  136. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  137. data/test/spec_auth_basic.rb +0 -81
  138. data/test/spec_auth_digest.rb +0 -259
  139. data/test/spec_body_proxy.rb +0 -85
  140. data/test/spec_builder.rb +0 -223
  141. data/test/spec_cascade.rb +0 -61
  142. data/test/spec_cgi.rb +0 -102
  143. data/test/spec_chunked.rb +0 -101
  144. data/test/spec_commonlogger.rb +0 -93
  145. data/test/spec_conditionalget.rb +0 -102
  146. data/test/spec_config.rb +0 -22
  147. data/test/spec_content_length.rb +0 -85
  148. data/test/spec_content_type.rb +0 -45
  149. data/test/spec_deflater.rb +0 -339
  150. data/test/spec_directory.rb +0 -88
  151. data/test/spec_etag.rb +0 -107
  152. data/test/spec_fastcgi.rb +0 -107
  153. data/test/spec_file.rb +0 -221
  154. data/test/spec_handler.rb +0 -72
  155. data/test/spec_head.rb +0 -45
  156. data/test/spec_lint.rb +0 -550
  157. data/test/spec_lobster.rb +0 -58
  158. data/test/spec_lock.rb +0 -164
  159. data/test/spec_logger.rb +0 -23
  160. data/test/spec_methodoverride.rb +0 -111
  161. data/test/spec_mime.rb +0 -51
  162. data/test/spec_mock.rb +0 -297
  163. data/test/spec_mongrel.rb +0 -182
  164. data/test/spec_multipart.rb +0 -600
  165. data/test/spec_nulllogger.rb +0 -20
  166. data/test/spec_recursive.rb +0 -72
  167. data/test/spec_request.rb +0 -1232
  168. data/test/spec_response.rb +0 -407
  169. data/test/spec_rewindable_input.rb +0 -118
  170. data/test/spec_runtime.rb +0 -49
  171. data/test/spec_sendfile.rb +0 -130
  172. data/test/spec_server.rb +0 -167
  173. data/test/spec_session_abstract_id.rb +0 -53
  174. data/test/spec_session_cookie.rb +0 -410
  175. data/test/spec_session_memcache.rb +0 -321
  176. data/test/spec_session_pool.rb +0 -209
  177. data/test/spec_showexceptions.rb +0 -98
  178. data/test/spec_showstatus.rb +0 -103
  179. data/test/spec_static.rb +0 -145
  180. data/test/spec_tempfile_reaper.rb +0 -63
  181. data/test/spec_thin.rb +0 -91
  182. data/test/spec_urlmap.rb +0 -236
  183. data/test/spec_utils.rb +0 -647
  184. data/test/spec_version.rb +0 -17
  185. data/test/spec_webrick.rb +0 -184
  186. data/test/static/another/index.html +0 -1
  187. data/test/static/index.html +0 -1
  188. data/test/testrequest.rb +0 -78
  189. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  190. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
@@ -1,600 +0,0 @@
1
- require 'rack/utils'
2
- require 'rack/mock'
3
-
4
- describe Rack::Multipart do
5
- def multipart_fixture(name, boundary = "AaB03x")
6
- file = multipart_file(name)
7
- data = File.open(file, 'rb') { |io| io.read }
8
-
9
- type = "multipart/form-data; boundary=#{boundary}"
10
- length = data.respond_to?(:bytesize) ? data.bytesize : data.size
11
-
12
- { "CONTENT_TYPE" => type,
13
- "CONTENT_LENGTH" => length.to_s,
14
- :input => StringIO.new(data) }
15
- end
16
-
17
- def multipart_file(name)
18
- File.join(File.dirname(__FILE__), "multipart", name.to_s)
19
- end
20
-
21
- should "return nil if content type is not multipart" do
22
- env = Rack::MockRequest.env_for("/",
23
- "CONTENT_TYPE" => 'application/x-www-form-urlencoded')
24
- Rack::Multipart.parse_multipart(env).should.equal nil
25
- end
26
-
27
- should "parse multipart content when content type present but filename is not" do
28
- env = Rack::MockRequest.env_for("/", multipart_fixture(:content_type_and_no_filename))
29
- params = Rack::Multipart.parse_multipart(env)
30
- params["text"].should.equal "contents"
31
- end
32
-
33
- if "<3".respond_to?(:force_encoding)
34
- should "set US_ASCII encoding based on charset" do
35
- env = Rack::MockRequest.env_for("/", multipart_fixture(:content_type_and_no_filename))
36
- params = Rack::Multipart.parse_multipart(env)
37
- params["text"].encoding.should.equal Encoding::US_ASCII
38
-
39
- # I'm not 100% sure if making the param name encoding match the
40
- # Content-Type charset is the right thing to do. We should revisit this.
41
- params.keys.each do |key|
42
- key.encoding.should.equal Encoding::US_ASCII
43
- end
44
- end
45
-
46
- should "set BINARY encoding on things without content type" do
47
- env = Rack::MockRequest.env_for("/", multipart_fixture(:none))
48
- params = Rack::Multipart.parse_multipart(env)
49
- params["submit-name"].encoding.should.equal Encoding::UTF_8
50
- end
51
-
52
- should "set UTF8 encoding on names of things without content type" do
53
- env = Rack::MockRequest.env_for("/", multipart_fixture(:none))
54
- params = Rack::Multipart.parse_multipart(env)
55
- params.keys.each do |key|
56
- key.encoding.should.equal Encoding::UTF_8
57
- end
58
- end
59
-
60
- should "default text to UTF8" do
61
- env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
62
- 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
65
- params.keys.each do |key|
66
- key.encoding.should.equal Encoding::UTF_8
67
- end
68
- end
69
- end
70
-
71
- should "raise RangeError if the key space is exhausted" do
72
- env = Rack::MockRequest.env_for("/", multipart_fixture(:content_type_and_no_filename))
73
-
74
- old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 1
75
- begin
76
- lambda { Rack::Multipart.parse_multipart(env) }.should.raise(RangeError)
77
- ensure
78
- Rack::Utils.key_space_limit = old
79
- end
80
- end
81
-
82
- should "parse multipart form webkit style" do
83
- env = Rack::MockRequest.env_for '/', multipart_fixture(:webkit)
84
- env['CONTENT_TYPE'] = "multipart/form-data; boundary=----WebKitFormBoundaryWLHCs9qmcJJoyjKR"
85
- params = Rack::Multipart.parse_multipart(env)
86
- params['profile']['bio'].should.include 'hello'
87
- end
88
-
89
- should "reject insanely long boundaries" do
90
- # using a pipe since a tempfile can use up too much space
91
- rd, wr = IO.pipe
92
-
93
- # we only call rewind once at start, so make sure it succeeds
94
- # and doesn't hit ESPIPE
95
- def rd.rewind; end
96
- wr.sync = true
97
-
98
- # mock out length to make this pipe look like a Tempfile
99
- def rd.length
100
- 1024 * 1024 * 8
101
- end
102
-
103
- # write to a pipe in a background thread, this will write a lot
104
- # unless Rack (properly) shuts down the read end
105
- thr = Thread.new do
106
- begin
107
- wr.write("--AaB03x")
108
-
109
- # make the initial boundary a few gigs long
110
- longer = "0123456789" * 1024 * 1024
111
- (1024 * 1024).times { wr.write(longer) }
112
-
113
- wr.write("\r\n")
114
- wr.write('Content-Disposition: form-data; name="a"; filename="a.txt"')
115
- wr.write("\r\n")
116
- wr.write("Content-Type: text/plain\r\n")
117
- wr.write("\r\na")
118
- wr.write("--AaB03x--\r\n")
119
- wr.close
120
- rescue => err # this is EPIPE if Rack shuts us down
121
- err
122
- end
123
- end
124
-
125
- fixture = {
126
- "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
127
- "CONTENT_LENGTH" => rd.length.to_s,
128
- :input => rd,
129
- }
130
-
131
- env = Rack::MockRequest.env_for '/', fixture
132
- lambda {
133
- Rack::Multipart.parse_multipart(env)
134
- }.should.raise(EOFError)
135
- rd.close
136
-
137
- err = thr.value
138
- err.should.be.instance_of Errno::EPIPE
139
- wr.close
140
- end
141
-
142
- should "parse multipart upload with text file" do
143
- env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
144
- 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; " +
150
- "name=\"files\"; filename=\"file1.txt\"\r\n" +
151
- "Content-Type: text/plain\r\n"
152
- params["files"][:name].should.equal "files"
153
- params["files"][:tempfile].read.should.equal "contents"
154
- end
155
-
156
- should "preserve extension in the created tempfile" do
157
- env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
158
- params = Rack::Multipart.parse_multipart(env)
159
- File.extname(params["files"][:tempfile].path).should.equal ".txt"
160
- end
161
-
162
- should "parse multipart upload with text file with no name field" do
163
- env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_and_no_name))
164
- 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; " +
168
- "filename=\"file1.txt\"\r\n" +
169
- "Content-Type: text/plain\r\n"
170
- params["file1.txt"][:name].should.equal "file1.txt"
171
- params["file1.txt"][:tempfile].read.should.equal "contents"
172
- end
173
-
174
- should "parse multipart upload file using custom tempfile class" do
175
- env = Rack::MockRequest.env_for("/", multipart_fixture(:text))
176
- my_tempfile = ""
177
- env['rack.multipart.tempfile_factory'] = lambda { |filename, content_type| my_tempfile }
178
- params = Rack::Multipart.parse_multipart(env)
179
- params["files"][:tempfile].object_id.should.equal my_tempfile.object_id
180
- my_tempfile.should.equal "contents"
181
- end
182
-
183
- should "parse multipart upload with nested parameters" do
184
- env = Rack::MockRequest.env_for("/", multipart_fixture(:nested))
185
- 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; " +
190
- "name=\"foo[files]\"; filename=\"file1.txt\"\r\n" +
191
- "Content-Type: text/plain\r\n"
192
- params["foo"]["files"][:name].should.equal "foo[files]"
193
- params["foo"]["files"][:tempfile].read.should.equal "contents"
194
- end
195
-
196
- should "parse multipart upload with binary file" do
197
- env = Rack::MockRequest.env_for("/", multipart_fixture(:binary))
198
- 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; " +
203
- "name=\"files\"; filename=\"rack-logo.png\"\r\n" +
204
- "Content-Type: image/png\r\n"
205
- params["files"][:name].should.equal "files"
206
- params["files"][:tempfile].read.length.should.equal 26473
207
- end
208
-
209
- should "parse multipart upload with empty file" do
210
- env = Rack::MockRequest.env_for("/", multipart_fixture(:empty))
211
- 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; " +
216
- "name=\"files\"; filename=\"file1.txt\"\r\n" +
217
- "Content-Type: text/plain\r\n"
218
- params["files"][:name].should.equal "files"
219
- params["files"][:tempfile].read.should.equal ""
220
- end
221
-
222
- should "parse multipart upload with filename with semicolons" do
223
- env = Rack::MockRequest.env_for("/", multipart_fixture(:semicolon))
224
- 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; " +
228
- "name=\"files\"; filename=\"fi;le1.txt\"\r\n" +
229
- "Content-Type: text/plain\r\n"
230
- params["files"][:name].should.equal "files"
231
- params["files"][:tempfile].read.should.equal "contents"
232
- end
233
-
234
- should "parse multipart upload with filename with invalid characters" do
235
- env = Rack::MockRequest.env_for("/", multipart_fixture(:invalid_character))
236
- params = Rack::Multipart.parse_multipart(env)
237
- params["files"][:type].should.equal "text/plain"
238
- params["files"][:filename].should.match(/invalid/)
239
- head = "Content-Disposition: form-data; " +
240
- "name=\"files\"; filename=\"invalid\xC3.txt\"\r\n" +
241
- "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"
246
- end
247
-
248
- should "not include file params if no file was selected" do
249
- env = Rack::MockRequest.env_for("/", multipart_fixture(:none))
250
- 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"
254
- end
255
-
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
262
- end
263
-
264
- should "parse multipart form with a null byte in the filename" do
265
- env = Rack::MockRequest.env_for '/', multipart_fixture(:filename_with_null_byte)
266
- 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
272
- end
273
-
274
- should "parse multipart/mixed" do
275
- 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
280
- end
281
-
282
- should "parse IE multipart upload and clean up filename" do
283
- env = Rack::MockRequest.env_for("/", multipart_fixture(:ie))
284
- 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; " +
288
- "name=\"files\"; " +
289
- 'filename="C:\Documents and Settings\Administrator\Desktop\file1.txt"' +
290
- "\r\nContent-Type: text/plain\r\n"
291
- params["files"][:name].should.equal "files"
292
- params["files"][:tempfile].read.should.equal "contents"
293
- end
294
-
295
- should "parse filename and modification param" do
296
- env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_and_modification_param))
297
- 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" +
301
- "Content-Disposition: attachment; " +
302
- "name=\"files\"; " +
303
- "filename=genome.jpeg; " +
304
- "modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\";\r\n" +
305
- "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"
308
- end
309
-
310
- should "parse filename with escaped quotes" do
311
- env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_escaped_quotes))
312
- 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; " +
316
- "name=\"files\"; " +
317
- "filename=\"escape \\\"quotes\"\r\n" +
318
- "Content-Type: application/octet-stream\r\n"
319
- params["files"][:name].should.equal "files"
320
- params["files"][:tempfile].read.should.equal "contents"
321
- end
322
-
323
- should "parse filename with percent escaped quotes" do
324
- env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_percent_escaped_quotes))
325
- 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; " +
329
- "name=\"files\"; " +
330
- "filename=\"escape %22quotes\"\r\n" +
331
- "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"
347
- end
348
-
349
- should "parse filename with escaped quotes and modification param" do
350
- env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_escaped_quotes_and_modification_param))
351
- 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" +
355
- "Content-Disposition: attachment; " +
356
- "name=\"files\"; " +
357
- "filename=\"\"human\" genome.jpeg\"; " +
358
- "modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\";\r\n" +
359
- "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"
362
- end
363
-
364
- should "parse filename with unescaped percentage characters" do
365
- env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_unescaped_percentages, "----WebKitFormBoundary2NHc7OhsgU68l3Al"))
366
- params = Rack::Multipart.parse_multipart(env)
367
- 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
371
- Content-Disposition: form-data; name="document[attachment]"; filename="100% of a photo.jpeg"\r
372
- Content-Type: image/jpeg\r
373
- MULTIPART
374
-
375
- files[:name].should.equal "document[attachment]"
376
- files[:tempfile].read.should.equal "contents"
377
- end
378
-
379
- should "parse filename with unescaped percentage characters that look like partial hex escapes" do
380
- env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_unescaped_percentages2, "----WebKitFormBoundary2NHc7OhsgU68l3Al"))
381
- params = Rack::Multipart.parse_multipart(env)
382
- files = params["document"]["attachment"]
383
- files[:type].should.equal "image/jpeg"
384
- files[:filename].should.equal "100%a"
385
- files[:head].should.equal <<-MULTIPART
386
- Content-Disposition: form-data; name="document[attachment]"; filename="100%a"\r
387
- Content-Type: image/jpeg\r
388
- MULTIPART
389
-
390
- files[:name].should.equal "document[attachment]"
391
- files[:tempfile].read.should.equal "contents"
392
- end
393
-
394
- should "parse filename with unescaped percentage characters that look like partial hex escapes" do
395
- env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_with_unescaped_percentages3, "----WebKitFormBoundary2NHc7OhsgU68l3Al"))
396
- params = Rack::Multipart.parse_multipart(env)
397
- files = params["document"]["attachment"]
398
- files[:type].should.equal "image/jpeg"
399
- files[:filename].should.equal "100%"
400
- files[:head].should.equal <<-MULTIPART
401
- Content-Disposition: form-data; name="document[attachment]"; filename="100%"\r
402
- Content-Type: image/jpeg\r
403
- MULTIPART
404
-
405
- files[:name].should.equal "document[attachment]"
406
- files[:tempfile].read.should.equal "contents"
407
- end
408
-
409
- it "rewinds input after parsing upload" do
410
- options = multipart_fixture(:text)
411
- input = options[:input]
412
- env = Rack::MockRequest.env_for("/", options)
413
- 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
417
- end
418
-
419
- it "builds multipart body" do
420
- files = Rack::Multipart::UploadedFile.new(multipart_file("file1.txt"))
421
- data = Rack::Multipart.build_multipart("submit-name" => "Larry", "files" => files)
422
-
423
- options = {
424
- "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
425
- "CONTENT_LENGTH" => data.length.to_s,
426
- :input => StringIO.new(data)
427
- }
428
- env = Rack::MockRequest.env_for("/", options)
429
- 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"
433
- end
434
-
435
- it "builds nested multipart body" do
436
- files = Rack::Multipart::UploadedFile.new(multipart_file("file1.txt"))
437
- data = Rack::Multipart.build_multipart("people" => [{"submit-name" => "Larry", "files" => files}])
438
-
439
- options = {
440
- "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
441
- "CONTENT_LENGTH" => data.length.to_s,
442
- :input => StringIO.new(data)
443
- }
444
- env = Rack::MockRequest.env_for("/", options)
445
- 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"
449
- end
450
-
451
- it "can parse fields that end at the end of the buffer" do
452
- input = File.read(multipart_file("bad_robots"))
453
-
454
- req = Rack::Request.new Rack::MockRequest.env_for("/",
455
- "CONTENT_TYPE" => "multipart/form-data, boundary=1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon",
456
- "CONTENT_LENGTH" => input.size,
457
- :input => input)
458
-
459
- req.POST['file.path'].should.equal "/var/tmp/uploads/4/0001728414"
460
- req.POST['addresses'].should.not.equal nil
461
- end
462
-
463
- it "builds complete params with the chunk size of 16384 slicing exactly on boundary" do
464
- begin
465
- previous_limit = Rack::Utils.multipart_part_limit
466
- Rack::Utils.multipart_part_limit = 256
467
-
468
- data = File.open(multipart_file("fail_16384_nofile"), 'rb') { |f| f.read }.gsub(/\n/, "\r\n")
469
- options = {
470
- "CONTENT_TYPE" => "multipart/form-data; boundary=----WebKitFormBoundaryWsY0GnpbI5U7ztzo",
471
- "CONTENT_LENGTH" => data.length.to_s,
472
- :input => StringIO.new(data)
473
- }
474
- env = Rack::MockRequest.env_for("/", options)
475
- params = Rack::Multipart.parse_multipart(env)
476
-
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"
484
- ensure
485
- Rack::Utils.multipart_part_limit = previous_limit
486
- end
487
- end
488
-
489
- should "not reach a multi-part limit" do
490
- begin
491
- previous_limit = Rack::Utils.multipart_part_limit
492
- Rack::Utils.multipart_part_limit = 4
493
-
494
- env = Rack::MockRequest.env_for '/', multipart_fixture(:three_files_three_fields)
495
- params = Rack::Multipart.parse_multipart(env)
496
- params['reply'].should.equal 'yes'
497
- params['to'].should.equal 'people'
498
- params['from'].should.equal 'others'
499
- ensure
500
- Rack::Utils.multipart_part_limit = previous_limit
501
- end
502
- end
503
-
504
- should "reach a multipart limit" do
505
- begin
506
- previous_limit = Rack::Utils.multipart_part_limit
507
- Rack::Utils.multipart_part_limit = 3
508
-
509
- env = Rack::MockRequest.env_for '/', multipart_fixture(:three_files_three_fields)
510
- lambda { Rack::Multipart.parse_multipart(env) }.should.raise(Rack::Multipart::MultipartPartLimitError)
511
- ensure
512
- Rack::Utils.multipart_part_limit = previous_limit
513
- end
514
- end
515
-
516
- should "return nil if no UploadedFiles were used" do
517
- data = Rack::Multipart.build_multipart("people" => [{"submit-name" => "Larry", "files" => "contents"}])
518
- data.should.equal nil
519
- end
520
-
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"
525
- end
526
-
527
- it "can parse fields with a content type" do
528
- data = <<-EOF
529
- --1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon\r
530
- Content-Disposition: form-data; name="description"\r
531
- Content-Type: text/plain"\r
532
- \r
533
- Very very blue\r
534
- --1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon--\r
535
- EOF
536
- options = {
537
- "CONTENT_TYPE" => "multipart/form-data; boundary=1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon",
538
- "CONTENT_LENGTH" => data.length.to_s,
539
- :input => StringIO.new(data)
540
- }
541
- env = Rack::MockRequest.env_for("/", options)
542
- params = Rack::Utils::Multipart.parse_multipart(env)
543
-
544
- params.should.equal({"description"=>"Very very blue"})
545
- end
546
-
547
- should "parse multipart upload with no content-length header" do
548
- env = Rack::MockRequest.env_for '/', multipart_fixture(:webkit)
549
- env['CONTENT_TYPE'] = "multipart/form-data; boundary=----WebKitFormBoundaryWLHCs9qmcJJoyjKR"
550
- env.delete 'CONTENT_LENGTH'
551
- params = Rack::Multipart.parse_multipart(env)
552
- params['profile']['bio'].should.include 'hello'
553
- end
554
-
555
- should "parse very long unquoted multipart file names" do
556
- data = <<-EOF
557
- --AaB03x\r
558
- Content-Type: text/plain\r
559
- Content-Disposition: attachment; name=file; filename=#{'long' * 100}\r
560
- \r
561
- contents\r
562
- --AaB03x--\r
563
- EOF
564
-
565
- options = {
566
- "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
567
- "CONTENT_LENGTH" => data.length.to_s,
568
- :input => StringIO.new(data)
569
- }
570
- env = Rack::MockRequest.env_for("/", options)
571
- params = Rack::Utils::Multipart.parse_multipart(env)
572
-
573
- params["file"][:filename].should.equal('long' * 100)
574
- end
575
-
576
- should "support mixed case metadata" do
577
- file = multipart_file(:text)
578
- data = File.open(file, 'rb') { |io| io.read }
579
-
580
- type = "Multipart/Form-Data; Boundary=AaB03x"
581
- length = data.respond_to?(:bytesize) ? data.bytesize : data.size
582
-
583
- e = { "CONTENT_TYPE" => type,
584
- "CONTENT_LENGTH" => length.to_s,
585
- :input => StringIO.new(data) }
586
-
587
- env = Rack::MockRequest.env_for("/", e)
588
- 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; " +
594
- "name=\"files\"; filename=\"file1.txt\"\r\n" +
595
- "Content-Type: text/plain\r\n"
596
- params["files"][:name].should.equal "files"
597
- params["files"][:tempfile].read.should.equal "contents"
598
- end
599
-
600
- end
@@ -1,20 +0,0 @@
1
- require 'rack/lint'
2
- require 'rack/mock'
3
- require 'rack/nulllogger'
4
-
5
- describe Rack::NullLogger do
6
- should "act as a noop logger" do
7
- app = lambda { |env|
8
- env['rack.logger'].warn "b00m"
9
- [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]]
10
- }
11
-
12
- logger = Rack::Lint.new(Rack::NullLogger.new(app))
13
-
14
- res = logger.call(Rack::MockRequest.env_for)
15
- res[0..1].should.equal [
16
- 200, {'Content-Type' => 'text/plain'}
17
- ]
18
- res[2].to_enum.to_a.should.equal ["Hello, World!"]
19
- end
20
- end