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.fileupload;
    18
    19  import static org.junit.Assert.assertEquals;
    20  import static org.junit.Assert.assertFalse;
    21  import static org.junit.Assert.assertTrue;
    22  import static org.junit.Assert.fail;
    23  import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
    24  import static org.junit.jupiter.api.Assertions.assertThrows;
    25
    26  import java.io.ByteArrayOutputStream;
    27  import java.io.IOException;
    28  import java.io.InputStream;
    29  import java.util.Iterator;
    30  import java.util.List;
    31
    32  import javax.servlet.http.HttpServletRequest;
    33
    34  import org.apache.commons.fileupload.FileUploadBase.FileUploadIOException;
    35  import org.apache.commons.fileupload.MultipartStream.MalformedStreamException;
    36  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    37  import org.apache.commons.fileupload.servlet.ServletFileUpload;
    38  import org.apache.commons.fileupload.util.Streams;
    39  import org.junit.Test;
    40
    41  /**
    42   * Unit test for items with varying sizes.
    43   */
    44  public class SizesTest {
    45
    46      /** Checks, whether limiting the file size works.
    47       */
    48      @Test
    49      public void testFileSizeLimit()
    50              throws IOException, FileUploadException {
    51          final String request =
    52              "-----1234\r\n" +
    53              "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" +
    54              "Content-Type: text/whatever\r\n" +
    55              "\r\n" +
    56              "This is the content of the file\n" +
    57              "\r\n" +
    58              "-----1234--\r\n";
    59
    60          ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
    61          upload.setFileSizeMax(-1);
    62          HttpServletRequest req = new MockHttpServletRequest(
    63                  request.getBytes("US-ASCII"), Constants.CONTENT_TYPE);
    64          List<FileItem> fileItems = upload.parseRequest(req);
    65          assertEquals(1, fileItems.size());
    66          FileItem item = fileItems.get(0);
    67          assertEquals("This is the content of the file\n", new String(item.get()));
    68
    69          upload = new ServletFileUpload(new DiskFileItemFactory());
    70          upload.setFileSizeMax(40);
    71          req = new MockHttpServletRequest(request.getBytes("US-ASCII"), Constants.CONTENT_TYPE);
    72          fileItems = upload.parseRequest(req);
    73          assertEquals(1, fileItems.size());
    74          item = fileItems.get(0);
    75          assertEquals("This is the content of the file\n", new String(item.get()));
    76
    77          upload = new ServletFileUpload(new DiskFileItemFactory());
    78          upload.setFileSizeMax(30);
    79          req = new MockHttpServletRequest(request.getBytes("US-ASCII"), Constants.CONTENT_TYPE);
    80          try {
    81              upload.parseRequest(req);
    82              fail("Expected exception.");
    83          } catch (final FileUploadBase.FileSizeLimitExceededException e) {
    84              assertEquals(30, e.getPermittedSize());
    85          }
    86      }
    87
    88      /** Checks, whether a faked Content-Length header is detected.
    89       */
    90      @Test
    91      public void testFileSizeLimitWithFakedContentLength()
    92              throws IOException, FileUploadException {
    93          final String request =
    94              "-----1234\r\n" +
    95              "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" +
    96              "Content-Type: text/whatever\r\n" +
    97              "Content-Length: 10\r\n" +
    98              "\r\n" +
    99              "This is the content of the file\n" +
    100             "\r\n" +
    101             "-----1234--\r\n";
    102
    103         ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
    104         upload.setFileSizeMax(-1);
    105         HttpServletRequest req = new MockHttpServletRequest(
    106                 request.getBytes("US-ASCII"), Constants.CONTENT_TYPE);
    107         List<FileItem> fileItems = upload.parseRequest(req);
    108         assertEquals(1, fileItems.size());
    109         FileItem item = fileItems.get(0);
    110         assertEquals("This is the content of the file\n", new String(item.get()));
    111
    112         upload = new ServletFileUpload(new DiskFileItemFactory());
    113         upload.setFileSizeMax(40);
    114         req = new MockHttpServletRequest(request.getBytes("US-ASCII"), Constants.CONTENT_TYPE);
    115         fileItems = upload.parseRequest(req);
    116         assertEquals(1, fileItems.size());
    117         item = fileItems.get(0);
    118         assertEquals("This is the content of the file\n", new String(item.get()));
    119
    120         // provided Content-Length is larger than the FileSizeMax -> handled by ctor
    121         upload = new ServletFileUpload(new DiskFileItemFactory());
    122         upload.setFileSizeMax(5);
    123         req = new MockHttpServletRequest(request.getBytes("US-ASCII"), Constants.CONTENT_TYPE);
    124         try {
    125             upload.parseRequest(req);
    126             fail("Expected exception.");
    127         } catch (final FileUploadBase.FileSizeLimitExceededException e) {
    128             assertEquals(5, e.getPermittedSize());
    129         }
    130
    131         // provided Content-Length is wrong, actual content is larger -> handled by LimitedInputStream
    132         upload = new ServletFileUpload(new DiskFileItemFactory());
    133         upload.setFileSizeMax(15);
    134         req = new MockHttpServletRequest(request.getBytes("US-ASCII"), Constants.CONTENT_TYPE);
    135         try {
    136             upload.parseRequest(req);
    137             fail("Expected exception.");
    138         } catch (final FileUploadBase.FileSizeLimitExceededException e) {
    139             assertEquals(15, e.getPermittedSize());
    140         }
    141     }
    142
    143     /**
    144      * Runs a test with varying file sizes.
    145      */
    146     @Test
    147     public void testFileUpload()
    148             throws IOException, FileUploadException {
    149         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    150         int add = 16;
    151         int num = 0;
    152         for (int i = 0;  i < 16384;  i += add) {
    153             if (++add == 32) {
    154                 add = 16;
    155             }
    156             final String header = "-----1234\r\n"
    157                 + "Content-Disposition: form-data; name=\"field" + num++ + "\"\r\n"
    158                 + "\r\n";
    159             baos.write(header.getBytes("US-ASCII"));
    160             for (int j = 0;  j < i;  j++) {
    161                 baos.write((byte) j);
    162             }
    163             baos.write("\r\n".getBytes("US-ASCII"));
    164         }
    165         baos.write("-----1234--\r\n".getBytes("US-ASCII"));
    166
    167         final List<FileItem> fileItems =
    168                 Util.parseUpload(new ServletFileUpload(new DiskFileItemFactory()), baos.toByteArray());
    169         final Iterator<FileItem> fileIter = fileItems.iterator();
    170         add = 16;
    171         num = 0;
    172         for (int i = 0;  i < 16384;  i += add) {
    173             if (++add == 32) {
    174                 add = 16;
    175             }
    176             final FileItem item = fileIter.next();
    177             assertEquals("field" + num++, item.getFieldName());
    178             final byte[] bytes = item.get();
    179             assertEquals(i, bytes.length);
    180             for (int j = 0;  j < i;  j++) {
    181                 assertEquals((byte) j, bytes[j]);
    182             }
    183         }
    184         assertTrue(!fileIter.hasNext());
    185     }
    186
    187     /** Checks, whether the maxSize works.
    188      */
    189     @Test
    190     public void testMaxSizeLimit()
    191             throws IOException, FileUploadException {
    192         final String request =
    193             "-----1234\r\n" +
    194             "Content-Disposition: form-data; name=\"file1\"; filename=\"foo1.tab\"\r\n" +
    195             "Content-Type: text/whatever\r\n" +
    196             "Content-Length: 10\r\n" +
    197             "\r\n" +
    198             "This is the content of the file\n" +
    199             "\r\n" +
    200             "-----1234\r\n" +
    201             "Content-Disposition: form-data; name=\"file2\"; filename=\"foo2.tab\"\r\n" +
    202             "Content-Type: text/whatever\r\n" +
    203             "\r\n" +
    204             "This is the content of the file\n" +
    205             "\r\n" +
    206             "-----1234--\r\n";
    207
    208         final ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
    209         upload.setFileSizeMax(-1);
    210         upload.setSizeMax(200);
    211
    212         final MockHttpServletRequest req = new MockHttpServletRequest(request.getBytes("US-ASCII"), Constants.CONTENT_TYPE);
    213         assertEquals(200, assertThrows(FileUploadBase.SizeLimitExceededException.class, () -> upload.parseRequest(req)).getPermittedSize());
    214     }
    215
    216     @Test
    217     public void testMaxSizeLimitUnknownContentLength()
    218             throws IOException, FileUploadException {
    219         final String request =
    220             "-----1234\r\n" +
    221             "Content-Disposition: form-data; name=\"file1\"; filename=\"foo1.tab\"\r\n" +
    222             "Content-Type: text/whatever\r\n" +
    223             "Content-Length: 10\r\n" +
    224             "\r\n" +
    225             "This is the content of the file\n" +
    226             "\r\n" +
    227             "-----1234\r\n" +
    228             "Content-Disposition: form-data; name=\"file2\"; filename=\"foo2.tab\"\r\n" +
    229             "Content-Type: text/whatever\r\n" +
    230             "\r\n" +
    231             "This is the content of the file\n" +
    232             "\r\n" +
    233             "-----1234--\r\n";
    234
    235         final ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
    236         upload.setFileSizeMax(-1);
    237         upload.setSizeMax(300);
    238
    239         // the first item should be within the max size limit
    240         // set the read limit to 10 to simulate a "real" stream
    241         // otherwise the buffer would be immediately filled
    242
    243         final MockHttpServletRequest req = new MockHttpServletRequest(
    244                 request.getBytes("US-ASCII"), Constants.CONTENT_TYPE);
    245         req.setContentLength(-1);
    246         req.setReadLimit(10);
    247
    248         final FileItemIterator it = upload.getItemIterator(req);
    249         assertTrue(it.hasNext());
    250
    251         FileItemStream item = it.next();
    252         assertFalse(item.isFormField());
    253         assertEquals("file1", item.getFieldName());
    254         assertEquals("foo1.tab", item.getName());
    255
    256         try (InputStream stream = item.openStream()) {
    257             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    258             Streams.copy(stream, baos, true);
    259         }
    260
    261         // the second item is over the size max, thus we expect an error
    262         // the header is still within size max -> this shall still succeed
    263         assertDoesNotThrow(it::hasNext);
    264
    265         item = it.next();
    266
    267         try (InputStream stream = item.openStream()) {
    268             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    269             assertThrows(FileUploadIOException.class, () -> Streams.copy(stream, baos, true));
    270             assertThrows(MalformedStreamException.class, stream::close);
    271         } catch (final MalformedStreamException e) {
    272             // expected as close() throws again.
    273         }
    274     }
    275
    276     /** Checks, whether the maxSize works.
    277      */
    278     @Test
    279     public void testPartHeaderSizeMaxLimit()
    280             throws IOException, FileUploadException {
    281         final String request =
    282             "-----1234\r\n" +
    283             "Content-Disposition: form-data; name=\"file1\"; filename=\"foo1.tab\"\r\n" +
    284             "Content-Type: text/whatever\r\n" +
    285             "Content-Length: 10\r\n" +
    286             "\r\n" +
    287             "This is the content of the file\n" +
    288             "\r\n" +
    289             "-----1234\r\n" +
    290             "Content-Disposition: form-data; name=\"file2\"; filename=\"foo2.tab\"\r\n" +
    291             "Content-Type: text/whatever\r\n" +
    292             "\r\n" +
    293             "This is the content of the file\n" +
    294             "\r\n" +
    295             "-----1234--\r\n";
    296
    297         final ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
    298         upload.setFileSizeMax(-1);
    299         upload.setSizeMax(-1);
    300         upload.setPartHeaderSizeMax(100);
    301
    302         final MockHttpServletRequest req = new MockHttpServletRequest(request.getBytes("US-ASCII"), Constants.CONTENT_TYPE);
    303         assertEquals(100, assertThrows(FileUploadBase.SizeLimitExceededException.class, () -> upload.parseRequest(req)).getPermittedSize());
    304     }
    305 }