View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.fileupload2.core;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertNull;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  
24  import java.io.IOException;
25  import java.nio.charset.StandardCharsets;
26  
27  import org.junit.jupiter.api.Test;
28  
29  /**
30   * Common tests for implementations of {@link AbstractFileUpload}. This is a parameterized test. Tests must be valid and common to all implementations of
31   * FileUpload added as parameter in this class.
32   *
33   * @param <AFU> The {@link AbstractFileUpload} type.
34   * @param <R>   The FileUpload request type.
35   * @param <I>   The FileItem type.
36   * @param <F>   The FileItemFactory type.
37   */
38  public abstract class AbstractFileUploadTest<AFU extends AbstractFileUpload<R, I, F>, R, I extends FileItem<I>, F extends FileItemFactory<I>>
39          extends AbstractFileUploadWrapper<AFU, R, I, F> {
40  
41      protected AbstractFileUploadTest(final AFU fileUpload) {
42          super(fileUpload);
43      }
44  
45      private void assertHeaders(final String[] headerNames, final String[] headerValues, final I fileItems, final int index) {
46          for (var i = 0; i < headerNames.length; i++) {
47              final var value = fileItems.getHeaders().getHeader(headerNames[i]);
48              if (i == index) {
49                  assertEquals(headerValues[i], value);
50              } else {
51                  assertNull(value);
52              }
53          }
54      }
55  
56      /**
57       * Tests <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-239">FILEUPLOAD-239</a>
58       *
59       * @throws IOException Test failure.
60       */
61      @Test
62      public void testContentTypeAttachment() throws IOException {
63          // @formatter:off
64          final var fileItems = parseUpload(upload,
65                  "-----1234\r\n" +
66                  "content-disposition: form-data; name=\"field1\"\r\n" +
67                  "\r\n" +
68                  "Joe Blow\r\n" +
69                  "-----1234\r\n" +
70                  "content-disposition: form-data; name=\"pics\"\r\n" +
71                  "Content-type: multipart/mixed, boundary=---9876\r\n" +
72                  "\r\n" +
73                  "-----9876\r\n" +
74                  "Content-disposition: attachment; filename=\"file1.txt\"\r\n" +
75                  "Content-Type: text/plain\r\n" +
76                  "\r\n" +
77                  "... contents of file1.txt ...\r\n" +
78                  "-----9876--\r\n" +
79                  "-----1234--\r\n");
80          // @formatter:on
81          assertEquals(2, fileItems.size());
82  
83          final var field = fileItems.get(0);
84          assertEquals("field1", field.getFieldName());
85          assertTrue(field.isFormField());
86          assertEquals("Joe Blow", field.getString());
87  
88          final var fileItem = fileItems.get(1);
89          assertEquals("pics", fileItem.getFieldName());
90          assertFalse(fileItem.isFormField());
91          assertEquals("... contents of file1.txt ...", fileItem.getString());
92          assertEquals("text/plain", fileItem.getContentType());
93          assertEquals("file1.txt", fileItem.getName());
94      }
95  
96      /**
97       * This is what the browser does if you submit the form without choosing a file.
98       *
99       * @throws FileUploadException Test failure.
100      */
101     @Test
102     public void testEmptyFile() throws FileUploadException {
103         // @formatter:off
104         final var fileItems = parseUpload (upload,
105                                                 "-----1234\r\n" +
106                                                 "Content-Disposition: form-data; name=\"file\"; filename=\"\"\r\n" +
107                                                 "\r\n" +
108                                                 "\r\n" +
109                                                 "-----1234--\r\n");
110         // @formatter:on
111         assertEquals(1, fileItems.size());
112 
113         final var file = fileItems.get(0);
114         assertFalse(file.isFormField());
115         assertEquals("", file.getString());
116         assertEquals("", file.getName());
117     }
118 
119     @Test
120     public void testFileNameCaseSensitivity() throws IOException {
121         // @formatter:off
122         final var fileItems = parseUpload(upload,
123                                                "-----1234\r\n" +
124                                                "Content-Disposition: form-data; "
125                                              + "name=\"FiLe\"; filename=\"FOO.tab\"\r\n" +
126                                                "Content-Type: text/whatever\r\n" +
127                                                "\r\n" +
128                                                "This is the content of the file\n" +
129                                                "\r\n" +
130                                                "-----1234--\r\n");
131         // @formatter:on
132         assertEquals(1, fileItems.size());
133 
134         final var file = fileItems.get(0);
135         assertEquals("FiLe", file.getFieldName());
136         assertEquals("FOO.tab", file.getName());
137     }
138 
139     @Test
140     public void testFileUpload() throws IOException {
141         // @formatter:off
142         final var fileItems = parseUpload(upload,
143                                                "-----1234\r\n" +
144                                                "Content-Disposition: "
145                                                + "form-data; name=\"file\"; filename=\"foo.tab\"\r\n" +
146                                                "Content-Type: text/whatever\r\n" +
147                                                "\r\n" +
148                                                "This is the content of the file\n" +
149                                                "\r\n" +
150                                                "-----1234\r\n" +
151                                                "Content-Disposition: form-data; name=\"field\"\r\n" +
152                                                "\r\n" +
153                                                "fieldValue\r\n" +
154                                                "-----1234\r\n" +
155                                                "Content-Disposition: form-data; name=\"multi\"\r\n" +
156                                                "\r\n" +
157                                                "value1\r\n" +
158                                                "-----1234\r\n" +
159                                                "Content-Disposition: form-data; name=\"multi\"\r\n" +
160                                                "\r\n" +
161                                                "value2\r\n" +
162                                                "-----1234--\r\n");
163         // @formatter:on
164         assertEquals(4, fileItems.size());
165 
166         final var file = fileItems.get(0);
167         assertEquals("file", file.getFieldName());
168         assertFalse(file.isFormField());
169         assertEquals("This is the content of the file\n", file.getString());
170         assertEquals("text/whatever", file.getContentType());
171         assertEquals("foo.tab", file.getName());
172 
173         final var field = fileItems.get(1);
174         assertEquals("field", field.getFieldName());
175         assertTrue(field.isFormField());
176         assertEquals("fieldValue", field.getString());
177 
178         final var multi0 = fileItems.get(2);
179         assertEquals("multi", multi0.getFieldName());
180         assertTrue(multi0.isFormField());
181         assertEquals("value1", multi0.getString());
182 
183         final var multi1 = fileItems.get(3);
184         assertEquals("multi", multi1.getFieldName());
185         assertTrue(multi1.isFormField());
186         assertEquals("value2", multi1.getString());
187     }
188 
189     /**
190      * Test case for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-130">FILEUPLOAD-130</a>.
191      *
192      * @throws IOException Test failure.
193      */
194     @Test
195     public void testFileUpload130() throws IOException {
196         final String[] headerNames = { "SomeHeader", "OtherHeader", "YetAnotherHeader", "WhatAHeader" };
197         final String[] headerValues = { "present", "Is there", "Here", "Is That" };
198         // @formatter:off
199         final var fileItems = parseUpload(upload,
200                                                "-----1234\r\n" +
201                                                "Content-Disposition: form-data; name=\"file\"; "
202                                              + "filename=\"foo.tab\"\r\n" +
203                                                "Content-Type: text/whatever\r\n" +
204                                                headerNames[0] + ": " + headerValues[0] + "\r\n" +
205                                                "\r\n" +
206                                                "This is the content of the file\n" +
207                                                "\r\n" +
208                                                "-----1234\r\n" +
209                                                "Content-Disposition: form-data; \r\n" +
210                                                "\tname=\"field\"\r\n" +
211                                                headerNames[1] + ": " + headerValues[1] + "\r\n" +
212                                                "\r\n" +
213                                                "fieldValue\r\n" +
214                                                "-----1234\r\n" +
215                                                "Content-Disposition: form-data;\r\n" +
216                                                "     name=\"multi\"\r\n" +
217                                                headerNames[2] + ": " + headerValues[2] + "\r\n" +
218                                                "\r\n" +
219                                                "value1\r\n" +
220                                                "-----1234\r\n" +
221                                                "Content-Disposition: form-data; name=\"multi\"\r\n" +
222                                                headerNames[3] + ": " + headerValues[3] + "\r\n" +
223                                                "\r\n" +
224                                                "value2\r\n" +
225                                                "-----1234--\r\n");
226         // @formatter:on
227         assertEquals(4, fileItems.size());
228 
229         final var file = fileItems.get(0);
230         assertHeaders(headerNames, headerValues, file, 0);
231 
232         final var field = fileItems.get(1);
233         assertHeaders(headerNames, headerValues, field, 1);
234 
235         final var multi0 = fileItems.get(2);
236         assertHeaders(headerNames, headerValues, multi0, 2);
237 
238         final var multi1 = fileItems.get(3);
239         assertHeaders(headerNames, headerValues, multi1, 3);
240     }
241 
242     /**
243      * Test for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-62">FILEUPLOAD-62</a>
244      *
245      * @throws IOException Test failure.
246      */
247     @Test
248     public void testFILEUPLOAD62() throws IOException {
249         // @formatter:off
250         final var contentType = "multipart/form-data; boundary=AaB03x";
251         final var request =
252             "--AaB03x\r\n" +
253             "content-disposition: form-data; name=\"field1\"\r\n" +
254             "\r\n" +
255             "Joe Blow\r\n" +
256             "--AaB03x\r\n" +
257             "content-disposition: form-data; name=\"pics\"\r\n" +
258             "Content-type: multipart/mixed; boundary=BbC04y\r\n" +
259             "\r\n" +
260             "--BbC04y\r\n" +
261             "Content-disposition: attachment; filename=\"file1.txt\"\r\n" +
262             "Content-Type: text/plain\r\n" +
263             "\r\n" +
264             "... contents of file1.txt ...\r\n" +
265             "--BbC04y\r\n" +
266             "Content-disposition: attachment; filename=\"file2.gif\"\r\n" +
267             "Content-type: image/gif\r\n" +
268             "Content-Transfer-Encoding: binary\r\n" +
269             "\r\n" +
270             "...contents of file2.gif...\r\n" +
271             "--BbC04y--\r\n" +
272             "--AaB03x--";
273         // @formatter:on
274         final var fileItems = parseUpload(upload, request.getBytes(StandardCharsets.US_ASCII), contentType);
275         assertEquals(3, fileItems.size());
276         final var item0 = fileItems.get(0);
277         assertEquals("field1", item0.getFieldName());
278         assertNull(item0.getName());
279         assertEquals("Joe Blow", new String(item0.get()));
280         final var item1 = fileItems.get(1);
281         assertEquals("pics", item1.getFieldName());
282         assertEquals("file1.txt", item1.getName());
283         assertEquals("... contents of file1.txt ...", new String(item1.get()));
284         final var item2 = fileItems.get(2);
285         assertEquals("pics", item2.getFieldName());
286         assertEquals("file2.gif", item2.getName());
287         assertEquals("...contents of file2.gif...", new String(item2.get()));
288     }
289 
290     /**
291      * Test for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-111">FILEUPLOAD-111</a>
292      *
293      * @throws IOException Test failure.
294      */
295     @Test
296     public void testFoldedHeaders() throws IOException {
297         // @formatter:off
298         final var fileItems = parseUpload(upload, "-----1234\r\n" +
299                 "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" +
300                 "Content-Type: text/whatever\r\n" +
301                 "\r\n" +
302                 "This is the content of the file\n" +
303                 "\r\n" +
304                 "-----1234\r\n" +
305                 "Content-Disposition: form-data; \r\n" +
306                 "\tname=\"field\"\r\n" +
307                 "\r\n" +
308                 "fieldValue\r\n" +
309                 "-----1234\r\n" +
310                 "Content-Disposition: form-data;\r\n" +
311                 "     name=\"multi\"\r\n" +
312                 "\r\n" +
313                 "value1\r\n" +
314                 "-----1234\r\n" +
315                 "Content-Disposition: form-data; name=\"multi\"\r\n" +
316                 "\r\n" +
317                 "value2\r\n" +
318                 "-----1234--\r\n");
319         // @formatter:on
320         assertEquals(4, fileItems.size());
321 
322         final var file = fileItems.get(0);
323         assertEquals("file", file.getFieldName());
324         assertFalse(file.isFormField());
325         assertEquals("This is the content of the file\n", file.getString());
326         assertEquals("text/whatever", file.getContentType());
327         assertEquals("foo.tab", file.getName());
328 
329         final var field = fileItems.get(1);
330         assertEquals("field", field.getFieldName());
331         assertTrue(field.isFormField());
332         assertEquals("fieldValue", field.getString());
333 
334         final var multi0 = fileItems.get(2);
335         assertEquals("multi", multi0.getFieldName());
336         assertTrue(multi0.isFormField());
337         assertEquals("value1", multi0.getString());
338 
339         final var multi1 = fileItems.get(3);
340         assertEquals("multi", multi1.getFieldName());
341         assertTrue(multi1.isFormField());
342         assertEquals("value2", multi1.getString());
343     }
344 
345     /**
346      * Internet Explorer 5 for the Mac has a bug where the carriage return is missing on any boundary line immediately preceding an input with type=image.
347      * (type=submit does not have the bug.)
348      *
349      * @throws FileUploadException Test failure.
350      */
351     @Test
352     public void testIE5MacBug() throws FileUploadException {
353         final var fileItems = parseUpload(upload,
354         // @formatter:off
355                 "-----1234\r\n" +
356                 "Content-Disposition: form-data; name=\"field1\"\r\n" +
357                 "\r\n" +
358                 "fieldValue\r\n" +
359                 "-----1234\n" + // NOTE \r missing
360                 "Content-Disposition: form-data; name=\"submitName.x\"\r\n" +
361                 "\r\n" +
362                 "42\r\n" +
363                 "-----1234\n" + // NOTE \r missing
364                 "Content-Disposition: form-data; name=\"submitName.y\"\r\n" +
365                 "\r\n" +
366                 "21\r\n" +
367                 "-----1234\r\n" +
368                 "Content-Disposition: form-data; name=\"field2\"\r\n" +
369                 "\r\n" +
370                 "fieldValue2\r\n" +
371                 "-----1234--\r\n");
372         //@formatter:on
373 
374         assertEquals(4, fileItems.size());
375 
376         final var field1 = fileItems.get(0);
377         assertEquals("field1", field1.getFieldName());
378         assertTrue(field1.isFormField());
379         assertEquals("fieldValue", field1.getString());
380 
381         final var submitX = fileItems.get(1);
382         assertEquals("submitName.x", submitX.getFieldName());
383         assertTrue(submitX.isFormField());
384         assertEquals("42", submitX.getString());
385 
386         final var submitY = fileItems.get(2);
387         assertEquals("submitName.y", submitY.getFieldName());
388         assertTrue(submitY.isFormField());
389         assertEquals("21", submitY.getString());
390 
391         final var field2 = fileItems.get(3);
392         assertEquals("field2", field2.getFieldName());
393         assertTrue(field2.isFormField());
394         assertEquals("fieldValue2", field2.getString());
395     }
396 }