Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,16 @@ public static final boolean isMultipartContent(final RequestContext ctx) {
*/
private int maxPartHeaderSize = MultipartInput.DEFAULT_PART_HEADER_SIZE_MAX;

/**
* The maximum size of the all parts headers in bytes that may be uploaded in a single request. A value of -1 indicates no maximum.
*/
private long partHeaderTotalSizeMax = -1;

/**
* The size of all headers of all parts that have been read.
*/
private long partHeaderTotalReads;

/**
* The content encoding to use when reading part headers.
*/
Expand Down Expand Up @@ -342,6 +352,7 @@ public long getMaxSize() {
*/
public FileItemHeaders getParsedHeaders(final String headerPart) {
final var len = headerPart.length();
partHeaderTotalReads += len;
final var headers = newFileItemHeaders();
var start = 0;
for (;;) {
Expand Down Expand Up @@ -488,6 +499,12 @@ public List<I> parseRequest(final RequestContext requestContext) throws FileUplo
String.format("Request '%s' failed: Maximum file count %,d exceeded.", MULTIPART_FORM_DATA, Long.valueOf(maxFileCount)),
getMaxFileCount(), size);
}
if (partHeaderTotalSizeMax > -1 && partHeaderTotalReads >= partHeaderTotalSizeMax) {
// The next item will exceed total headers size of all parts
throw new FileUploadSizeException(
"The request was rejected because total header size of all parts exceeds the configured partHeaderTotalSizeMax (%s) bytes",
partHeaderTotalSizeMax, partHeaderTotalReads);
}
// Don't use getName() here to prevent an InvalidFileNameException.
// @formatter:off
final var fileItem = fileItemFactory.fileItemBuilder()
Expand Down Expand Up @@ -575,6 +592,17 @@ public void setMaxPartHeaderSize(final int partHeaderSizeMax) {
this.maxPartHeaderSize = partHeaderSizeMax;
}

/**
* Sets the total size limit for the all parts headers
*
* @param partHeaderTotalSizeMax The maximum size of the all parts headers in
* bytes that may be uploaded in a single request.
*
*/
public void setPartHeaderTotalSizeMax(long partHeaderTotalSizeMax) {
this.partHeaderTotalSizeMax = partHeaderTotalSizeMax;
}

/**
* Sets the maximum allowed size of a complete request, as opposed to {@link #setMaxFileSize(long)}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -478,4 +479,72 @@ void testMultipleRelated() throws Exception {
assertEquals("text/plain", part2.getContentType());
assertNull(part2.getName());
}


@Test
public void testExceedTotalPartHeaderSizeLimit() throws IOException {
long max = 250;
upload.setPartHeaderTotalSizeMax(max);
try {
// @formatter:off
final var fileItems = parseUpload(upload,
"-----1234\r\n" +
"Content-Disposition: "
+ "form-data; name=\"file\"; filename=\"foo.tab\"\r\n" +
"Content-Type: text/whatever\r\n" +
"\r\n" +
"This is the content of the file\n" +
"\r\n" +
"-----1234\r\n" +
"Content-Disposition: form-data; name=\"field\"\r\n" +
"\r\n" +
"fieldValue\r\n" +
"-----1234\r\n" +
"Content-Disposition: form-data; name=\"multi\"\r\n" +
"\r\n" +
"value1\r\n" +
"-----1234\r\n" +
"Content-Disposition: form-data; name=\"multi\"\r\n" +
"Content-Type: text/plain\r\n" +
"Content-ID: multi-id\r\n" +
"\r\n" +
"value2\r\n" +
"-----1234--\r\n");
// @formatter:on
fail("FileUploadSizeException expected!");
} catch (FileUploadSizeException fse) {
assertEquals(max, fse.getPermitted());
}
}

@Test
public void testPassTotalPartHeaderSizeLimit() throws IOException {
upload.setPartHeaderTotalSizeMax(1 << 10);
// @formatter:off
final var fileItems = parseUpload(upload,
"-----1234\r\n" +
"Content-Disposition: "
+ "form-data; name=\"file\"; filename=\"foo.tab\"\r\n" +
"Content-Type: text/whatever\r\n" +
"\r\n" +
"This is the content of the file\n" +
"\r\n" +
"-----1234\r\n" +
"Content-Disposition: form-data; name=\"field\"\r\n" +
"\r\n" +
"fieldValue\r\n" +
"-----1234\r\n" +
"Content-Disposition: form-data; name=\"multi\"\r\n" +
"\r\n" +
"value1\r\n" +
"-----1234\r\n" +
"Content-Disposition: form-data; name=\"multi\"\r\n" +
"Content-Type: text/plain\r\n" +
"Content-ID: multi-id\r\n" +
"\r\n" +
"value2\r\n" +
"-----1234--\r\n");
// @formatter:on
assertEquals(4, fileItems.size());
}
}