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.assertThrows;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  import static org.junit.jupiter.api.Assertions.fail;
24  
25  import java.io.ByteArrayOutputStream;
26  import java.io.IOException;
27  
28  import org.apache.commons.io.IOUtils;
29  import org.junit.jupiter.api.Test;
30  
31  /**
32   * Unit test for items with varying sizes.
33   *
34   * @param <AFU> The FileUpload type.
35   * @param <R>   The FileUpload request type.
36   * @param <I>   The FileItem type.
37   * @param <F>   The FileItemFactory type.
38   */
39  public abstract class AbstractSizesTest<AFU extends AbstractFileUpload<R, I, F>, R, I extends FileItem<I>, F extends FileItemFactory<I>>
40          extends AbstractTest<AFU, R, I, F> {
41  
42      /**
43       * Checks, whether limiting the file size works.
44       *
45       * @throws IOException Test failure.
46       */
47      @Test
48      public void testFileSizeLimit() throws IOException {
49          final var content = "This is the content of the file\n";
50          final var contentSize = content.getBytes().length;
51  
52          // @formatter:off
53          final var request =
54              "-----1234\r\n" +
55              "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" +
56              "Content-Type: text/whatever\r\n" +
57              "\r\n" +
58              content +
59              "\r\n" +
60              "-----1234--\r\n";
61          // @formatter:on
62  
63          var upload = newFileUpload();
64          upload.setFileSizeMax(-1);
65          var req = newMockHttpServletRequest(request, null, null);
66          var fileItems = upload.parseRequest(req);
67          assertEquals(1, fileItems.size());
68          var item = fileItems.get(0);
69          assertEquals(content, new String(item.get()));
70  
71          upload = newFileUpload();
72          upload.setFileSizeMax(40);
73          req = newMockHttpServletRequest(request, null, null);
74          fileItems = upload.parseRequest(req);
75          assertEquals(1, fileItems.size());
76          item = fileItems.get(0);
77          assertEquals(content, new String(item.get()));
78  
79          upload = newFileUpload();
80          upload.setFileSizeMax(contentSize);
81          req = newMockHttpServletRequest(request, null, null);
82          fileItems = upload.parseRequest(req);
83          assertEquals(1, fileItems.size());
84          item = fileItems.get(0);
85          assertEquals(content, new String(item.get()));
86  
87          upload = newFileUpload();
88          upload.setFileSizeMax(contentSize - 1);
89          req = newMockHttpServletRequest(request, null, null);
90          try {
91              upload.parseRequest(req);
92              fail("Expected exception.");
93          } catch (final FileUploadByteCountLimitException e) {
94              assertEquals(contentSize - 1, e.getPermitted());
95          }
96  
97          upload = newFileUpload();
98          upload.setFileSizeMax(30);
99          req = newMockHttpServletRequest(request, null, null);
100         try {
101             upload.parseRequest(req);
102             fail("Expected exception.");
103         } catch (final FileUploadByteCountLimitException e) {
104             assertEquals(30, e.getPermitted());
105         }
106     }
107 
108     /**
109      * Checks, whether a faked Content-Length header is detected.
110      *
111      * @throws IOException Test failure.
112      */
113     @Test
114     public void testFileSizeLimitWithFakedContentLength() throws IOException {
115         // @formatter:off
116         final var request =
117             "-----1234\r\n" +
118             "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" +
119             "Content-Type: text/whatever\r\n" +
120             "Content-Length: 10\r\n" +
121             "\r\n" +
122             "This is the content of the file\n" +
123             "\r\n" +
124             "-----1234--\r\n";
125         // @formatter:on
126 
127         var upload = newFileUpload();
128         upload.setFileSizeMax(-1);
129         var req = newMockHttpServletRequest(request, null, null);
130         var fileItems = upload.parseRequest(req);
131         assertEquals(1, fileItems.size());
132         var item = fileItems.get(0);
133         assertEquals("This is the content of the file\n", new String(item.get()));
134 
135         upload = newFileUpload();
136         upload.setFileSizeMax(40);
137         req = newMockHttpServletRequest(request, null, null);
138         fileItems = upload.parseRequest(req);
139         assertEquals(1, fileItems.size());
140         item = fileItems.get(0);
141         assertEquals("This is the content of the file\n", new String(item.get()));
142 
143         // provided Content-Length is larger than the FileSizeMax -> handled by ctor
144         upload = newFileUpload();
145         upload.setFileSizeMax(5);
146         req = newMockHttpServletRequest(request, null, null);
147         try {
148             upload.parseRequest(req);
149             fail("Expected exception.");
150         } catch (final FileUploadByteCountLimitException e) {
151             assertEquals(5, e.getPermitted());
152         }
153 
154         // provided Content-Length is wrong, actual content is larger -> handled by LimitedInputStream
155         upload = newFileUpload();
156         upload.setFileSizeMax(15);
157         req = newMockHttpServletRequest(request, null, null);
158         try {
159             upload.parseRequest(req);
160             fail("Expected exception.");
161         } catch (final FileUploadByteCountLimitException e) {
162             assertEquals(15, e.getPermitted());
163         }
164     }
165 
166     /**
167      * Checks whether maxSize works.
168      *
169      * @throws IOException Test failure.
170      */
171     @Test
172     public void testMaxSizeLimit() throws IOException {
173         // @formatter:off
174         final var request =
175             "-----1234\r\n" +
176             "Content-Disposition: form-data; name=\"file1\"; filename=\"foo1.tab\"\r\n" +
177             "Content-Type: text/whatever\r\n" +
178             "Content-Length: 10\r\n" +
179             "\r\n" +
180             "This is the content of the file\n" +
181             "\r\n" +
182             "-----1234\r\n" +
183             "Content-Disposition: form-data; name=\"file2\"; filename=\"foo2.tab\"\r\n" +
184             "Content-Type: text/whatever\r\n" +
185             "\r\n" +
186             "This is the content of the file\n" +
187             "\r\n" +
188             "-----1234--\r\n";
189         // @formatter:on
190 
191         final var upload = newFileUpload();
192         upload.setFileSizeMax(-1);
193         upload.setSizeMax(200);
194 
195         final var req = newMockHttpServletRequest(request, null, null);
196         try {
197             upload.parseRequest(req);
198             fail("Expected exception.");
199         } catch (final FileUploadSizeException e) {
200             assertEquals(200, e.getPermitted());
201         }
202     }
203 
204     @Test
205     public void testMaxSizeLimitUnknownContentLength() throws IOException {
206         // @formatter:off
207         final var request =
208             "-----1234\r\n" +
209             "Content-Disposition: form-data; name=\"file1\"; filename=\"foo1.tab\"\r\n" +
210             "Content-Type: text/whatever\r\n" +
211             "Content-Length: 10\r\n" +
212             "\r\n" +
213             "This is the content of the file\n" +
214             "\r\n" +
215             "-----1234\r\n" +
216             "Content-Disposition: form-data; name=\"file2\"; filename=\"foo2.tab\"\r\n" +
217             "Content-Type: text/whatever\r\n" +
218             "\r\n" +
219             "This is the content of the file\n" +
220             "\r\n" +
221             "-----1234--\r\n";
222         // @formatter:on
223 
224         final var upload = newFileUpload();
225         upload.setFileSizeMax(-1);
226         upload.setSizeMax(300);
227 
228         // the first item should be within the max size limit
229         // set the read limit to 10 to simulate a "real" stream
230         // otherwise the buffer would be immediately filled
231 
232         final var req = newMockHttpServletRequest(request, -1L, 10);
233 
234         final var it = upload.getItemIterator(req);
235         assertTrue(it.hasNext());
236 
237         final var item = it.next();
238         assertFalse(item.isFormField());
239         assertEquals("file1", item.getFieldName());
240         assertEquals("foo1.tab", item.getName());
241 
242         {
243             try (final var baos = new ByteArrayOutputStream();
244                     final var stream = item.getInputStream()) {
245                 IOUtils.copy(stream, baos);
246             }
247 
248         }
249 
250         // the second item is over the size max, thus we expect an error
251         // the header is still within size max -> this shall still succeed
252         assertTrue(it.hasNext());
253 
254         assertThrows(FileUploadException.class, () -> {
255             final var item2 = it.next();
256             try (final var baos = new ByteArrayOutputStream();
257                     final var stream = item2.getInputStream()) {
258                 IOUtils.copy(stream, baos);
259             }
260         });
261     }
262 }