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 */ 017package org.apache.commons.fileupload2.core; 018 019import static org.junit.jupiter.api.Assertions.assertEquals; 020import static org.junit.jupiter.api.Assertions.assertFalse; 021import static org.junit.jupiter.api.Assertions.assertThrows; 022import static org.junit.jupiter.api.Assertions.assertTrue; 023import static org.junit.jupiter.api.Assertions.fail; 024 025import java.io.ByteArrayOutputStream; 026import java.io.IOException; 027 028import org.apache.commons.io.IOUtils; 029import org.junit.jupiter.api.Test; 030 031/** 032 * Unit test for items with varying sizes. 033 * 034 * @param <AFU> The FileUpload type. 035 * @param <R> The FileUpload request type. 036 * @param <I> The FileItem type. 037 * @param <F> The FileItemFactory type. 038 */ 039public abstract class AbstractSizesTest<AFU extends AbstractFileUpload<R, I, F>, R, I extends FileItem<I>, F extends FileItemFactory<I>> 040 extends AbstractTest<AFU, R, I, F> { 041 042 /** 043 * Checks, whether limiting the file size works. 044 * 045 * @throws IOException Test failure. 046 */ 047 @Test 048 public void testFileSizeLimit() throws IOException { 049 final var content = "This is the content of the file\n"; 050 final var contentSize = content.getBytes().length; 051 052 // @formatter:off 053 final var request = 054 "-----1234\r\n" + 055 "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" + 056 "Content-Type: text/whatever\r\n" + 057 "\r\n" + 058 content + 059 "\r\n" + 060 "-----1234--\r\n"; 061 // @formatter:on 062 063 var upload = newFileUpload(); 064 upload.setFileSizeMax(-1); 065 var req = newMockHttpServletRequest(request, null, null); 066 var fileItems = upload.parseRequest(req); 067 assertEquals(1, fileItems.size()); 068 var item = fileItems.get(0); 069 assertEquals(content, new String(item.get())); 070 071 upload = newFileUpload(); 072 upload.setFileSizeMax(40); 073 req = newMockHttpServletRequest(request, null, null); 074 fileItems = upload.parseRequest(req); 075 assertEquals(1, fileItems.size()); 076 item = fileItems.get(0); 077 assertEquals(content, new String(item.get())); 078 079 upload = newFileUpload(); 080 upload.setFileSizeMax(contentSize); 081 req = newMockHttpServletRequest(request, null, null); 082 fileItems = upload.parseRequest(req); 083 assertEquals(1, fileItems.size()); 084 item = fileItems.get(0); 085 assertEquals(content, new String(item.get())); 086 087 upload = newFileUpload(); 088 upload.setFileSizeMax(contentSize - 1); 089 req = newMockHttpServletRequest(request, null, null); 090 try { 091 upload.parseRequest(req); 092 fail("Expected exception."); 093 } catch (final FileUploadByteCountLimitException e) { 094 assertEquals(contentSize - 1, e.getPermitted()); 095 } 096 097 upload = newFileUpload(); 098 upload.setFileSizeMax(30); 099 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}