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 }