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.assertNull; 022import static org.junit.jupiter.api.Assertions.assertTrue; 023 024import java.io.IOException; 025import java.nio.charset.StandardCharsets; 026 027import org.junit.jupiter.api.Test; 028 029/** 030 * Common tests for implementations of {@link AbstractFileUpload}. This is a parameterized test. Tests must be valid and common to all implementations of 031 * FileUpload added as parameter in this class. 032 * 033 * @param <AFU> The {@link AbstractFileUpload} type. 034 * @param <R> The FileUpload request type. 035 * @param <I> The FileItem type. 036 * @param <F> The FileItemFactory type. 037 */ 038public abstract class AbstractFileUploadTest<AFU extends AbstractFileUpload<R, I, F>, R, I extends FileItem<I>, F extends FileItemFactory<I>> 039 extends AbstractFileUploadWrapper<AFU, R, I, F> { 040 041 protected AbstractFileUploadTest(final AFU fileUpload) { 042 super(fileUpload); 043 } 044 045 private void assertHeaders(final String[] headerNames, final String[] headerValues, final I fileItems, final int index) { 046 for (var i = 0; i < headerNames.length; i++) { 047 final var value = fileItems.getHeaders().getHeader(headerNames[i]); 048 if (i == index) { 049 assertEquals(headerValues[i], value); 050 } else { 051 assertNull(value); 052 } 053 } 054 } 055 056 /** 057 * Tests <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-239">FILEUPLOAD-239</a> 058 * 059 * @throws IOException Test failure. 060 */ 061 @Test 062 public void testContentTypeAttachment() throws IOException { 063 // @formatter:off 064 final var fileItems = parseUpload(upload, 065 "-----1234\r\n" + 066 "content-disposition: form-data; name=\"field1\"\r\n" + 067 "\r\n" + 068 "Joe Blow\r\n" + 069 "-----1234\r\n" + 070 "content-disposition: form-data; name=\"pics\"\r\n" + 071 "Content-type: multipart/mixed, boundary=---9876\r\n" + 072 "\r\n" + 073 "-----9876\r\n" + 074 "Content-disposition: attachment; filename=\"file1.txt\"\r\n" + 075 "Content-Type: text/plain\r\n" + 076 "\r\n" + 077 "... contents of file1.txt ...\r\n" + 078 "-----9876--\r\n" + 079 "-----1234--\r\n"); 080 // @formatter:on 081 assertEquals(2, fileItems.size()); 082 083 final var field = fileItems.get(0); 084 assertEquals("field1", field.getFieldName()); 085 assertTrue(field.isFormField()); 086 assertEquals("Joe Blow", field.getString()); 087 088 final var fileItem = fileItems.get(1); 089 assertEquals("pics", fileItem.getFieldName()); 090 assertFalse(fileItem.isFormField()); 091 assertEquals("... contents of file1.txt ...", fileItem.getString()); 092 assertEquals("text/plain", fileItem.getContentType()); 093 assertEquals("file1.txt", fileItem.getName()); 094 } 095 096 /** 097 * This is what the browser does if you submit the form without choosing a file. 098 * 099 * @throws FileUploadException Test failure. 100 */ 101 @Test 102 public void testEmptyFile() throws FileUploadException { 103 // @formatter:off 104 final var fileItems = parseUpload (upload, 105 "-----1234\r\n" + 106 "Content-Disposition: form-data; name=\"file\"; filename=\"\"\r\n" + 107 "\r\n" + 108 "\r\n" + 109 "-----1234--\r\n"); 110 // @formatter:on 111 assertEquals(1, fileItems.size()); 112 113 final var file = fileItems.get(0); 114 assertFalse(file.isFormField()); 115 assertEquals("", file.getString()); 116 assertEquals("", file.getName()); 117 } 118 119 @Test 120 public void testFileNameCaseSensitivity() throws IOException { 121 // @formatter:off 122 final var fileItems = parseUpload(upload, 123 "-----1234\r\n" + 124 "Content-Disposition: form-data; " 125 + "name=\"FiLe\"; filename=\"FOO.tab\"\r\n" + 126 "Content-Type: text/whatever\r\n" + 127 "\r\n" + 128 "This is the content of the file\n" + 129 "\r\n" + 130 "-----1234--\r\n"); 131 // @formatter:on 132 assertEquals(1, fileItems.size()); 133 134 final var file = fileItems.get(0); 135 assertEquals("FiLe", file.getFieldName()); 136 assertEquals("FOO.tab", file.getName()); 137 } 138 139 @Test 140 public void testFileUpload() throws IOException { 141 // @formatter:off 142 final var fileItems = parseUpload(upload, 143 "-----1234\r\n" + 144 "Content-Disposition: " 145 + "form-data; name=\"file\"; filename=\"foo.tab\"\r\n" + 146 "Content-Type: text/whatever\r\n" + 147 "\r\n" + 148 "This is the content of the file\n" + 149 "\r\n" + 150 "-----1234\r\n" + 151 "Content-Disposition: form-data; name=\"field\"\r\n" + 152 "\r\n" + 153 "fieldValue\r\n" + 154 "-----1234\r\n" + 155 "Content-Disposition: form-data; name=\"multi\"\r\n" + 156 "\r\n" + 157 "value1\r\n" + 158 "-----1234\r\n" + 159 "Content-Disposition: form-data; name=\"multi\"\r\n" + 160 "\r\n" + 161 "value2\r\n" + 162 "-----1234--\r\n"); 163 // @formatter:on 164 assertEquals(4, fileItems.size()); 165 166 final var file = fileItems.get(0); 167 assertEquals("file", file.getFieldName()); 168 assertFalse(file.isFormField()); 169 assertEquals("This is the content of the file\n", file.getString()); 170 assertEquals("text/whatever", file.getContentType()); 171 assertEquals("foo.tab", file.getName()); 172 173 final var field = fileItems.get(1); 174 assertEquals("field", field.getFieldName()); 175 assertTrue(field.isFormField()); 176 assertEquals("fieldValue", field.getString()); 177 178 final var multi0 = fileItems.get(2); 179 assertEquals("multi", multi0.getFieldName()); 180 assertTrue(multi0.isFormField()); 181 assertEquals("value1", multi0.getString()); 182 183 final var multi1 = fileItems.get(3); 184 assertEquals("multi", multi1.getFieldName()); 185 assertTrue(multi1.isFormField()); 186 assertEquals("value2", multi1.getString()); 187 } 188 189 /** 190 * Test case for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-130">FILEUPLOAD-130</a>. 191 * 192 * @throws IOException Test failure. 193 */ 194 @Test 195 public void testFileUpload130() throws IOException { 196 final String[] headerNames = { "SomeHeader", "OtherHeader", "YetAnotherHeader", "WhatAHeader" }; 197 final String[] headerValues = { "present", "Is there", "Here", "Is That" }; 198 // @formatter:off 199 final var fileItems = parseUpload(upload, 200 "-----1234\r\n" + 201 "Content-Disposition: form-data; name=\"file\"; " 202 + "filename=\"foo.tab\"\r\n" + 203 "Content-Type: text/whatever\r\n" + 204 headerNames[0] + ": " + headerValues[0] + "\r\n" + 205 "\r\n" + 206 "This is the content of the file\n" + 207 "\r\n" + 208 "-----1234\r\n" + 209 "Content-Disposition: form-data; \r\n" + 210 "\tname=\"field\"\r\n" + 211 headerNames[1] + ": " + headerValues[1] + "\r\n" + 212 "\r\n" + 213 "fieldValue\r\n" + 214 "-----1234\r\n" + 215 "Content-Disposition: form-data;\r\n" + 216 " name=\"multi\"\r\n" + 217 headerNames[2] + ": " + headerValues[2] + "\r\n" + 218 "\r\n" + 219 "value1\r\n" + 220 "-----1234\r\n" + 221 "Content-Disposition: form-data; name=\"multi\"\r\n" + 222 headerNames[3] + ": " + headerValues[3] + "\r\n" + 223 "\r\n" + 224 "value2\r\n" + 225 "-----1234--\r\n"); 226 // @formatter:on 227 assertEquals(4, fileItems.size()); 228 229 final var file = fileItems.get(0); 230 assertHeaders(headerNames, headerValues, file, 0); 231 232 final var field = fileItems.get(1); 233 assertHeaders(headerNames, headerValues, field, 1); 234 235 final var multi0 = fileItems.get(2); 236 assertHeaders(headerNames, headerValues, multi0, 2); 237 238 final var multi1 = fileItems.get(3); 239 assertHeaders(headerNames, headerValues, multi1, 3); 240 } 241 242 /** 243 * Test for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-62">FILEUPLOAD-62</a> 244 * 245 * @throws IOException Test failure. 246 */ 247 @Test 248 public void testFILEUPLOAD62() throws IOException { 249 // @formatter:off 250 final var contentType = "multipart/form-data; boundary=AaB03x"; 251 final var request = 252 "--AaB03x\r\n" + 253 "content-disposition: form-data; name=\"field1\"\r\n" + 254 "\r\n" + 255 "Joe Blow\r\n" + 256 "--AaB03x\r\n" + 257 "content-disposition: form-data; name=\"pics\"\r\n" + 258 "Content-type: multipart/mixed; boundary=BbC04y\r\n" + 259 "\r\n" + 260 "--BbC04y\r\n" + 261 "Content-disposition: attachment; filename=\"file1.txt\"\r\n" + 262 "Content-Type: text/plain\r\n" + 263 "\r\n" + 264 "... contents of file1.txt ...\r\n" + 265 "--BbC04y\r\n" + 266 "Content-disposition: attachment; filename=\"file2.gif\"\r\n" + 267 "Content-type: image/gif\r\n" + 268 "Content-Transfer-Encoding: binary\r\n" + 269 "\r\n" + 270 "...contents of file2.gif...\r\n" + 271 "--BbC04y--\r\n" + 272 "--AaB03x--"; 273 // @formatter:on 274 final var fileItems = parseUpload(upload, request.getBytes(StandardCharsets.US_ASCII), contentType); 275 assertEquals(3, fileItems.size()); 276 final var item0 = fileItems.get(0); 277 assertEquals("field1", item0.getFieldName()); 278 assertNull(item0.getName()); 279 assertEquals("Joe Blow", new String(item0.get())); 280 final var item1 = fileItems.get(1); 281 assertEquals("pics", item1.getFieldName()); 282 assertEquals("file1.txt", item1.getName()); 283 assertEquals("... contents of file1.txt ...", new String(item1.get())); 284 final var item2 = fileItems.get(2); 285 assertEquals("pics", item2.getFieldName()); 286 assertEquals("file2.gif", item2.getName()); 287 assertEquals("...contents of file2.gif...", new String(item2.get())); 288 } 289 290 /** 291 * Test for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-111">FILEUPLOAD-111</a> 292 * 293 * @throws IOException Test failure. 294 */ 295 @Test 296 public void testFoldedHeaders() throws IOException { 297 // @formatter:off 298 final var fileItems = parseUpload(upload, "-----1234\r\n" + 299 "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" + 300 "Content-Type: text/whatever\r\n" + 301 "\r\n" + 302 "This is the content of the file\n" + 303 "\r\n" + 304 "-----1234\r\n" + 305 "Content-Disposition: form-data; \r\n" + 306 "\tname=\"field\"\r\n" + 307 "\r\n" + 308 "fieldValue\r\n" + 309 "-----1234\r\n" + 310 "Content-Disposition: form-data;\r\n" + 311 " name=\"multi\"\r\n" + 312 "\r\n" + 313 "value1\r\n" + 314 "-----1234\r\n" + 315 "Content-Disposition: form-data; name=\"multi\"\r\n" + 316 "\r\n" + 317 "value2\r\n" + 318 "-----1234--\r\n"); 319 // @formatter:on 320 assertEquals(4, fileItems.size()); 321 322 final var file = fileItems.get(0); 323 assertEquals("file", file.getFieldName()); 324 assertFalse(file.isFormField()); 325 assertEquals("This is the content of the file\n", file.getString()); 326 assertEquals("text/whatever", file.getContentType()); 327 assertEquals("foo.tab", file.getName()); 328 329 final var field = fileItems.get(1); 330 assertEquals("field", field.getFieldName()); 331 assertTrue(field.isFormField()); 332 assertEquals("fieldValue", field.getString()); 333 334 final var multi0 = fileItems.get(2); 335 assertEquals("multi", multi0.getFieldName()); 336 assertTrue(multi0.isFormField()); 337 assertEquals("value1", multi0.getString()); 338 339 final var multi1 = fileItems.get(3); 340 assertEquals("multi", multi1.getFieldName()); 341 assertTrue(multi1.isFormField()); 342 assertEquals("value2", multi1.getString()); 343 } 344 345 /** 346 * Internet Explorer 5 for the Mac has a bug where the carriage return is missing on any boundary line immediately preceding an input with type=image. 347 * (type=submit does not have the bug.) 348 * 349 * @throws FileUploadException Test failure. 350 */ 351 @Test 352 public void testIE5MacBug() throws FileUploadException { 353 final var fileItems = parseUpload(upload, 354 // @formatter:off 355 "-----1234\r\n" + 356 "Content-Disposition: form-data; name=\"field1\"\r\n" + 357 "\r\n" + 358 "fieldValue\r\n" + 359 "-----1234\n" + // NOTE \r missing 360 "Content-Disposition: form-data; name=\"submitName.x\"\r\n" + 361 "\r\n" + 362 "42\r\n" + 363 "-----1234\n" + // NOTE \r missing 364 "Content-Disposition: form-data; name=\"submitName.y\"\r\n" + 365 "\r\n" + 366 "21\r\n" + 367 "-----1234\r\n" + 368 "Content-Disposition: form-data; name=\"field2\"\r\n" + 369 "\r\n" + 370 "fieldValue2\r\n" + 371 "-----1234--\r\n"); 372 //@formatter:on 373 374 assertEquals(4, fileItems.size()); 375 376 final var field1 = fileItems.get(0); 377 assertEquals("field1", field1.getFieldName()); 378 assertTrue(field1.isFormField()); 379 assertEquals("fieldValue", field1.getString()); 380 381 final var submitX = fileItems.get(1); 382 assertEquals("submitName.x", submitX.getFieldName()); 383 assertTrue(submitX.isFormField()); 384 assertEquals("42", submitX.getString()); 385 386 final var submitY = fileItems.get(2); 387 assertEquals("submitName.y", submitY.getFieldName()); 388 assertTrue(submitY.isFormField()); 389 assertEquals("21", submitY.getString()); 390 391 final var field2 = fileItems.get(3); 392 assertEquals("field2", field2.getFieldName()); 393 assertTrue(field2.isFormField()); 394 assertEquals("fieldValue2", field2.getString()); 395 } 396}