001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.fileupload;
018    
019    import java.io.File;
020    import java.io.IOException;
021    import java.io.OutputStream;
022    import java.util.Arrays;
023    
024    import junit.framework.TestCase;
025    import org.apache.commons.fileupload.DefaultFileItem;
026    import org.apache.commons.fileupload.DefaultFileItemFactory;
027    
028    
029    /**
030     * Unit tests for {@link org.apache.commons.fileupload.DefaultFileItem}.
031     *
032     * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
033     */
034    public class DefaultFileItemTest extends TestCase
035     {
036    
037        /**
038         * Content type for regular form items.
039         */
040        private static final String textContentType = "text/plain";
041    
042        /**
043         * Content type for file uploads.
044         */
045        private static final String fileContentType = "application/octet-stream";
046    
047        /**
048         * Very low threshold for testing memory versus disk options.
049         */
050        private static final int threshold = 16;
051    
052        /**
053         * Standard JUnit test case constructor.
054         *
055         * @param name The name of the test case.
056         */
057        public DefaultFileItemTest(String name)
058        {
059            super(name);
060        }
061    
062        /**
063         * Test construction of a regular text field.
064         */
065        public void testTextFieldConstruction()
066        {
067            FileItemFactory factory = createFactory(null);
068            String textFieldName = "textField";
069    
070            FileItem item = factory.createItem(
071                    textFieldName,
072                    textContentType,
073                    true,
074                    null
075            );
076            assertNotNull(item);
077            assertEquals(item.getFieldName(), textFieldName);
078            assertEquals(item.getContentType(), textContentType);
079            assertTrue(item.isFormField());
080            assertNull(item.getName());
081        }
082    
083        /**
084         * Test construction of a file field.
085         */
086        public void testFileFieldConstruction()
087        {
088            FileItemFactory factory = createFactory(null);
089            String fileFieldName = "fileField";
090            String fileName = "originalFileName";
091    
092            FileItem item = factory.createItem(
093                    fileFieldName,
094                    fileContentType,
095                    false,
096                    fileName
097            );
098            assertNotNull(item);
099            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    }