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  
18  package org.apache.commons.fileupload;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertNotNull;
23  import static org.junit.Assert.assertNull;
24  import static org.junit.Assert.assertTrue;
25  
26  import java.io.File;
27  import java.io.IOException;
28  import java.io.OutputStream;
29  import java.nio.charset.StandardCharsets;
30  import java.util.Arrays;
31  
32  import org.apache.commons.io.FileUtils;
33  import org.junit.Test;
34  
35  /**
36   * Tests for {@link org.apache.commons.fileupload.DefaultFileItem}.
37   */
38  @SuppressWarnings({ "deprecation" }) // unit tests for deprecated class
39  public class DefaultFileItemTest {
40  
41      /**
42       * Content type for regular form items.
43       */
44      private static final String CONTENT_TYPE_TEXT = "text/plain";
45  
46      /**
47       * Content type for file uploads.
48       */
49      private static final String CONTENT_TYPE_FILE = "application/octet-stream";
50  
51      /**
52       * Very low threshold for testing memory versus disk options.
53       */
54      private static final int THRESHOLD = 16;
55  
56      /** Charset name. */
57      static final String CHARSET_ISO_8859_1 = StandardCharsets.ISO_8859_1.name();
58  
59      /** Charset name. */
60      static final String CHARSET_US_ASCII = StandardCharsets.US_ASCII.name();
61  
62      /** Charset name. */
63      static final String CHARSET_UTF8 = StandardCharsets.UTF_8.name();
64  
65      /** Charset name. */
66      static final String CHARSET_KOI8_R = "KOI8_R";
67  
68      /** Charset name. */
69      static final String CHARSET_WIN1251 = "Cp1251";
70  
71      /** Test fixture. */
72      static final int[] SWISS_GERMAN_STUFF_UNICODE = { 0x47, 0x72, 0xFC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xE4, 0x6D, 0xE4 };
73  
74      /** Test fixture. */
75      static final int[] SWISS_GERMAN_STUFF_ISO8859_1 = { 0x47, 0x72, 0xFC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xE4, 0x6D, 0xE4 };
76  
77      /** Test fixture. */
78      static final int[] SWISS_GERMAN_STUFF_UTF8 = { 0x47, 0x72, 0xC3, 0xBC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xC3, 0xA4, 0x6D, 0xC3, 0xA4 };
79  
80      /** Test fixture. */
81      static final int[] RUSSIAN_STUFF_UNICODE = { 0x412, 0x441, 0x435, 0x43C, 0x5F, 0x43F, 0x440, 0x438, 0x432, 0x435, 0x442 };
82  
83      /** Test fixture. */
84      static final int[] RUSSIAN_STUFF_UTF8 = { 0xD0, 0x92, 0xD1, 0x81, 0xD0, 0xB5, 0xD0, 0xBC, 0x5F, 0xD0, 0xBF, 0xD1, 0x80, 0xD0, 0xB8, 0xD0, 0xB2, 0xD0, 0xB5,
85              0xD1, 0x82 };
86  
87      /** Test fixture. */
88      static final int[] RUSSIAN_STUFF_KOI8R = { 0xF7, 0xD3, 0xC5, 0xCD, 0x5F, 0xD0, 0xD2, 0xC9, 0xD7, 0xC5, 0xD4 };
89  
90      /** Test fixture. */
91      static final int[] RUSSIAN_STUFF_WIN1251 = { 0xC2, 0xF1, 0xE5, 0xEC, 0x5F, 0xEF, 0xF0, 0xE8, 0xE2, 0xE5, 0xF2 };
92  
93      private static String constructString(final int[] unicodeChars) {
94          final StringBuilder buffer = new StringBuilder();
95          if (unicodeChars != null) {
96              for (final int unicodeChar : unicodeChars) {
97                  buffer.append((char) unicodeChar);
98              }
99          }
100         return buffer.toString();
101     }
102 
103     /**
104      * Creates a new {@code FileItemFactory} and returns it, obscuring from the caller the underlying implementation of this interface.
105      *
106      * @param repository The directory within which temporary files will be created.
107      * @return the new {@code FileItemFactory} instance.
108      */
109     protected FileItemFactory createFactory(final File repository) {
110         return new DefaultFileItemFactory(THRESHOLD, repository);
111     }
112 
113     /**
114      * Common code for cases where the amount of data is above the configured threshold, but the ultimate destination of the data has not yet been determined.
115      *
116      * @param repository The directory within which temporary files will be created.
117      */
118     private void doTestAboveThreshold(final File repository) throws IOException {
119         final FileItemFactory factory = createFactory(repository);
120         final String textFieldName = "textField";
121         final String textFieldValue = "01234567890123456789";
122         final byte[] testFieldValueBytes = textFieldValue.getBytes();
123         final FileItem item = factory.createItem(textFieldName, CONTENT_TYPE_TEXT, true, null);
124         assertNotNull(item);
125         try (OutputStream os = item.getOutputStream()) {
126             os.write(testFieldValueBytes);
127         }
128         assertFalse(item.isInMemory());
129         assertEquals(item.getSize(), testFieldValueBytes.length);
130         assertTrue(Arrays.equals(item.get(), testFieldValueBytes));
131         assertEquals(item.getString(), textFieldValue);
132         assertTrue(item instanceof DefaultFileItem);
133         final DefaultFileItem dfi = (DefaultFileItem) item;
134         final File storeLocation = dfi.getStoreLocation();
135         assertNotNull(storeLocation);
136         assertTrue(storeLocation.exists());
137         assertEquals(storeLocation.length(), testFieldValueBytes.length);
138         if (repository != null) {
139             assertEquals(storeLocation.getParentFile(), repository);
140         }
141         item.delete();
142     }
143 
144     /**
145      * Test creation of a field for which the amount of data falls above the configured threshold, where no specific repository is configured.
146      */
147     @Test
148     public void testAboveThresholdDefaultRepository() throws IOException {
149         doTestAboveThreshold(null);
150     }
151 
152     /**
153      * Test creation of a field for which the amount of data falls above the configured threshold, where a specific repository is configured.
154      */
155     @Test
156     public void testAboveThresholdSpecifiedRepository() throws IOException {
157         final String tempPath = System.getProperty("java.io.tmpdir");
158         final String tempDirName = "testAboveThresholdSpecifiedRepository";
159         final File tempDir = new File(tempPath, tempDirName);
160         FileUtils.forceMkdir(tempDir);
161         doTestAboveThreshold(tempDir);
162         assertTrue(tempDir.delete());
163     }
164 
165     /**
166      * Test creation of a field for which the amount of data falls below the configured threshold.
167      */
168     @Test
169     public void testBelowThreshold() throws IOException {
170         final FileItemFactory factory = createFactory(null);
171         final String textFieldName = "textField";
172         final String textFieldValue = "0123456789";
173         final byte[] testFieldValueBytes = textFieldValue.getBytes();
174         final FileItem item = factory.createItem(textFieldName, CONTENT_TYPE_TEXT, true, null);
175         assertNotNull(item);
176         try (OutputStream os = item.getOutputStream()) {
177             os.write(testFieldValueBytes);
178         }
179         assertTrue(item.isInMemory());
180         assertEquals(item.getSize(), testFieldValueBytes.length);
181         assertTrue(Arrays.equals(item.get(), testFieldValueBytes));
182         assertEquals(item.getString(), textFieldValue);
183     }
184 
185     /**
186      * Test construction of content charset.
187      */
188     @Test
189     public void testContentCharSet() throws Exception {
190         final FileItemFactory factory = createFactory(null);
191         String teststr = constructString(SWISS_GERMAN_STUFF_UNICODE);
192         FileItem item = factory.createItem("doesnotmatter", "text/plain; charset=" + CHARSET_ISO_8859_1, true, null);
193         try (OutputStream out = item.getOutputStream()) {
194             for (final int element : SWISS_GERMAN_STUFF_ISO8859_1) {
195                 out.write(element);
196             }
197         }
198         assertEquals(teststr, teststr, item.getString());
199         item = factory.createItem("doesnotmatter", "text/plain; charset=" + CHARSET_UTF8, true, null);
200         try (OutputStream out = item.getOutputStream()) {
201             for (final int element : SWISS_GERMAN_STUFF_UTF8) {
202                 out.write(element);
203             }
204         }
205         assertEquals(teststr, teststr, item.getString());
206         teststr = constructString(RUSSIAN_STUFF_UNICODE);
207         item = factory.createItem("doesnotmatter", "text/plain; charset=" + CHARSET_KOI8_R, true, null);
208         try (OutputStream out = item.getOutputStream()) {
209             for (final int element : RUSSIAN_STUFF_KOI8R) {
210                 out.write(element);
211             }
212         }
213         assertEquals(teststr, teststr, item.getString());
214         item = factory.createItem("doesnotmatter", "text/plain; charset=" + CHARSET_WIN1251, true, null);
215         try (OutputStream out = item.getOutputStream()) {
216             for (final int element : RUSSIAN_STUFF_WIN1251) {
217                 out.write(element);
218             }
219         }
220         assertEquals(teststr, teststr, item.getString());
221         item = factory.createItem("doesnotmatter", "text/plain; charset=" + CHARSET_UTF8, true, null);
222         try (OutputStream out = item.getOutputStream()) {
223             for (final int element : RUSSIAN_STUFF_UTF8) {
224                 out.write(element);
225             }
226         }
227         assertEquals(teststr, teststr, item.getString());
228     }
229 
230     /**
231      * Test construction of a file field.
232      */
233     @Test
234     public void testFileFieldConstruction() {
235         final FileItemFactory factory = createFactory(null);
236         final String fileFieldName = "fileField";
237         final String fileName = "originalFileName";
238         final FileItem item = factory.createItem(fileFieldName, CONTENT_TYPE_FILE, false, fileName);
239         assertNotNull(item);
240         assertEquals(item.getFieldName(), fileFieldName);
241         assertEquals(item.getContentType(), CONTENT_TYPE_FILE);
242         assertFalse(item.isFormField());
243         assertEquals(item.getName(), fileName);
244     }
245 
246     /**
247      * Test construction of a regular text field.
248      */
249     @Test
250     public void testTextFieldConstruction() {
251         final FileItemFactory factory = createFactory(null);
252         final String textFieldName = "textField";
253         final FileItem item = factory.createItem(textFieldName, CONTENT_TYPE_TEXT, true, null);
254         assertNotNull(item);
255         assertEquals(item.getFieldName(), textFieldName);
256         assertEquals(item.getContentType(), CONTENT_TYPE_TEXT);
257         assertTrue(item.isFormField());
258         assertNull(item.getName());
259     }
260 }