    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.fileupload;
    18
    19  import java.io.File;
    20  import java.io.IOException;
    21  import java.io.OutputStream;
    22  import java.util.Arrays;
    23
    24  import junit.framework.TestCase;
    25  import org.apache.commons.fileupload.DefaultFileItem;
    26  import org.apache.commons.fileupload.DefaultFileItemFactory;
    27
    28
    29  /**
    30   * Unit tests for {@link org.apache.commons.fileupload.DefaultFileItem}.
    31   *
    32   * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
    33   */
    34  public class DefaultFileItemTest extends TestCase
    35   {
    36
    37      /**
    38       * Content type for regular form items.
    39       */
    40      private static final String textContentType = "text/plain";
    41
    42      /**
    43       * Content type for file uploads.
    44       */
    45      private static final String fileContentType = "application/octet-stream";
    46
    47      /**
    48       * Very low threshold for testing memory versus disk options.
    49       */
    50      private static final int threshold = 16;
    51
    52      /**
    53       * Standard JUnit test case constructor.
    54       *
    55       * @param name The name of the test case.
    56       */
    57      public DefaultFileItemTest(String name)
    58      {
    59          super(name);
    60      }
    61
    62      /**
    63       * Test construction of a regular text field.
    64       */
    65      public void testTextFieldConstruction()
    66      {
    67          FileItemFactory factory = createFactory(null);
    68          String textFieldName = "textField";
    69
    70          FileItem item = factory.createItem(
    71                  textFieldName,
    72                  textContentType,
    73                  true,
    74                  null
    75          );
    76          assertNotNull(item);
    77          assertEquals(item.getFieldName(), textFieldName);
    78          assertEquals(item.getContentType(), textContentType);
    79          assertTrue(item.isFormField());
    80          assertNull(item.getName());
    81      }
    82
    83      /**
    84       * Test construction of a file field.
    85       */
    86      public void testFileFieldConstruction()
    87      {
    88          FileItemFactory factory = createFactory(null);
    89          String fileFieldName = "fileField";
    90          String fileName = "originalFileName";
    91
    92          FileItem item = factory.createItem(
    93                  fileFieldName,
    94                  fileContentType,
    95                  false,
    96                  fileName
    97          );
    98          assertNotNull(item);
    99          assertEquals(item.getFieldName(), fileFieldName);
    100         assertEquals(item.getContentType(), fileContentType);
    101         assertFalse(item.isFormField());
    102         assertEquals(item.getName(), fileName);
    103     }
    104
    105     /**
    106      * Test creation of a field for which the amount of data falls below the
    107      * configured threshold.
    108      */
    109     public void testBelowThreshold()
    110     {
    111         FileItemFactory factory = createFactory(null);
    112         String textFieldName = "textField";
    113         String textFieldValue = "0123456789";
    114         byte[] testFieldValueBytes = textFieldValue.getBytes();
    115
    116         FileItem item = factory.createItem(
    117                 textFieldName,
    118                 textContentType,
    119                 true,
    120                 null
    121         );
    122         assertNotNull(item);
    123
    124         try
    125         {
    126             OutputStream os = item.getOutputStream();
    127             os.write(testFieldValueBytes);
    128             os.close();
    129         }
    130         catch(IOException e)
    131         {
    132             fail("Unexpected IOException");
    133         }
    134         assertTrue(item.isInMemory());
    135         assertEquals(item.getSize(), testFieldValueBytes.length);
    136         assertTrue(Arrays.equals(item.get(), testFieldValueBytes));
    137         assertEquals(item.getString(), textFieldValue);
    138     }
    139
    140     /**
    141      * Test creation of a field for which the amount of data falls above the
    142      * configured threshold, where no specific repository is configured.
    143      */
    144     public void testAboveThresholdDefaultRepository()
    145     {
    146         doTestAboveThreshold(null);
    147     }
    148
    149     /**
    150      * Test creation of a field for which the amount of data falls above the
    151      * configured threshold, where a specific repository is configured.
    152      */
    153     public void testAboveThresholdSpecifiedRepository()
    154     {
    155         String tempPath = System.getProperty("java.io.tmpdir");
    156         String tempDirName = "testAboveThresholdSpecifiedRepository";
    157         File tempDir = new File(tempPath, tempDirName);
    158         tempDir.mkdir();
    159         doTestAboveThreshold(tempDir);
    160         assertTrue(tempDir.delete());
    161     }
    162
    163     /**
    164      * Common code for cases where the amount of data is above the configured
    165      * threshold, but the ultimate destination of the data has not yet been
    166      * determined.
    167      *
    168      * @param repository The directory within which temporary files will be
    169      *                   created.
    170      */
    171     public void doTestAboveThreshold(File repository)
    172     {
    173         FileItemFactory factory = createFactory(repository);
    174         String textFieldName = "textField";
    175         String textFieldValue = "01234567890123456789";
    176         byte[] testFieldValueBytes = textFieldValue.getBytes();
    177
    178         FileItem item = factory.createItem(
    179                 textFieldName,
    180                 textContentType,
    181                 true,
    182                 null
    183         );
    184         assertNotNull(item);
    185
    186         try
    187         {
    188             OutputStream os = item.getOutputStream();
    189             os.write(testFieldValueBytes);
    190             os.close();
    191         }
    192         catch(IOException e)
    193         {
    194             fail("Unexpected IOException");
    195         }
    196         assertFalse(item.isInMemory());
    197         assertEquals(item.getSize(), testFieldValueBytes.length);
    198         assertTrue(Arrays.equals(item.get(), testFieldValueBytes));
    199         assertEquals(item.getString(), textFieldValue);
    200
    201         assertTrue(item instanceof DefaultFileItem);
    202         DefaultFileItem dfi = (DefaultFileItem) item;
    203         File storeLocation = dfi.getStoreLocation();
    204         assertNotNull(storeLocation);
    205         assertTrue(storeLocation.exists());
    206         assertEquals(storeLocation.length(), testFieldValueBytes.length);
    207
    208         if (repository != null)
    209         {
    210             assertEquals(storeLocation.getParentFile(), repository);
    211         }
    212
    213         item.delete();
    214     }
    215
    216
    217     /**
    218      * Creates a new <code>FileItemFactory</code> and returns it, obscuring
    219      * from the caller the underlying implementation of this interface.
    220      *
    221      * @param repository The directory within which temporary files will be
    222      *                   created.
    223      * @return the new <code>FileItemFactory</code> instance.
    224      */
    225     protected FileItemFactory createFactory(File repository)
    226     {
    227         return new DefaultFileItemFactory(threshold, repository);
    228     }
    229
    230
    231     static final String CHARSET_ISO88591 = "ISO-8859-1";
    232     static final String CHARSET_ASCII = "US-ASCII";
    233     static final String CHARSET_UTF8 = "UTF-8";
    234     static final String CHARSET_KOI8_R = "KOI8_R";
    235     static final String CHARSET_WIN1251 = "Cp1251";
    236
    237     static final int SWISS_GERMAN_STUFF_UNICODE [] =
    238     {
    239         0x47, 0x72, 0xFC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xE4, 0x6D, 0xE4
    240     };
    241
    242     static final int SWISS_GERMAN_STUFF_ISO8859_1 [] =
    243     {
    244         0x47, 0x72, 0xFC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xE4, 0x6D, 0xE4
    245     };
    246
    247     static final int SWISS_GERMAN_STUFF_UTF8 [] =
    248     {
    249         0x47, 0x72, 0xC3, 0xBC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xC3, 0xA4,
    250         0x6D, 0xC3, 0xA4
    251     };
    252
    253     static final int RUSSIAN_STUFF_UNICODE [] =
    254     {
    255         0x412, 0x441, 0x435, 0x43C, 0x5F, 0x43F, 0x440, 0x438,
    256         0x432, 0x435, 0x442
    257     };
    258
    259     static final int RUSSIAN_STUFF_UTF8 [] =
    260     {
    261         0xD0, 0x92, 0xD1, 0x81, 0xD0, 0xB5, 0xD0, 0xBC, 0x5F,
    262         0xD0, 0xBF, 0xD1, 0x80, 0xD0, 0xB8, 0xD0, 0xB2, 0xD0,
    263         0xB5, 0xD1, 0x82
    264     };
    265
    266     static final int RUSSIAN_STUFF_KOI8R [] =
    267     {
    268         0xF7, 0xD3, 0xC5, 0xCD, 0x5F, 0xD0, 0xD2, 0xC9, 0xD7,
    269         0xC5, 0xD4
    270     };
    271
    272     static final int RUSSIAN_STUFF_WIN1251 [] =
    273     {
    274         0xC2, 0xF1, 0xE5, 0xEC, 0x5F, 0xEF, 0xF0, 0xE8, 0xE2,
    275         0xE5, 0xF2
    276     };
    277
    278
    279     private static String constructString(int[] unicodeChars)
    280     {
    281         StringBuffer buffer = new StringBuffer();
    282         if (unicodeChars != null)
    283         {
    284             for (int i = 0; i < unicodeChars.length; i++)
    285             {
    286                 buffer.append((char) unicodeChars[i]);
    287             }
    288         }
    289         return buffer.toString();
    290     }
    291
    292     /**
    293      * Test construction of content charset.
    294      */
    295     public void testContentCharSet() throws Exception
    296     {
    297         FileItemFactory factory = createFactory(null);
    298
    299         String teststr = constructString(SWISS_GERMAN_STUFF_UNICODE);
    300
    301         FileItem item =
    302             factory.createItem(
    303                 "doesnotmatter",
    304                 "text/plain; charset=" + CHARSET_ISO88591,
    305                 true,
    306                 null);
    307         OutputStream outstream = item.getOutputStream();
    308         for (int i = 0; i < SWISS_GERMAN_STUFF_ISO8859_1.length; i++)
    309         {
    310             outstream.write(SWISS_GERMAN_STUFF_ISO8859_1[i]);
    311         }
    312         outstream.close();
    313         assertEquals(teststr, teststr, item.getString());
    314
    315         item =
    316             factory.createItem(
    317                 "doesnotmatter",
    318                 "text/plain; charset=" + CHARSET_UTF8,
    319                 true,
    320                 null);
    321         outstream = item.getOutputStream();
    322         for (int i = 0; i < SWISS_GERMAN_STUFF_UTF8.length; i++)
    323         {
    324             outstream.write(SWISS_GERMAN_STUFF_UTF8[i]);
    325         }
    326         outstream.close();
    327         assertEquals(teststr, teststr, item.getString());
    328
    329         teststr = constructString(RUSSIAN_STUFF_UNICODE);
    330
    331         item =
    332             factory.createItem(
    333                 "doesnotmatter",
    334                 "text/plain; charset=" + CHARSET_KOI8_R,
    335                 true,
    336                 null);
    337         outstream = item.getOutputStream();
    338         for (int i = 0; i < RUSSIAN_STUFF_KOI8R.length; i++)
    339         {
    340             outstream.write(RUSSIAN_STUFF_KOI8R[i]);
    341         }
    342         outstream.close();
    343         assertEquals(teststr, teststr, item.getString());
    344
    345         item =
    346             factory.createItem(
    347                 "doesnotmatter",
    348                 "text/plain; charset=" + CHARSET_WIN1251,
    349                 true,
    350                 null);
    351         outstream = item.getOutputStream();
    352         for (int i = 0; i < RUSSIAN_STUFF_WIN1251.length; i++)
    353         {
    354             outstream.write(RUSSIAN_STUFF_WIN1251[i]);
    355         }
    356         outstream.close();
    357         assertEquals(teststr, teststr, item.getString());
    358
    359         item =
    360             factory.createItem(
    361                 "doesnotmatter",
    362                 "text/plain; charset=" + CHARSET_UTF8,
    363                 true,
    364                 null);
    365         outstream = item.getOutputStream();
    366         for (int i = 0; i < RUSSIAN_STUFF_UTF8.length; i++)
    367         {
    368             outstream.write(RUSSIAN_STUFF_UTF8[i]);
    369         }
    370         outstream.close();
    371         assertEquals(teststr, teststr, item.getString());
    372     }
    373 }