diff --git a/spring-web/src/main/java/org/springframework/http/codec/multipart/PartGenerator.java b/spring-web/src/main/java/org/springframework/http/codec/multipart/PartGenerator.java index fa6074616b9..d3bc65d9232 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/multipart/PartGenerator.java +++ b/spring-web/src/main/java/org/springframework/http/codec/multipart/PartGenerator.java @@ -56,6 +56,7 @@ import org.springframework.util.FastByteArrayOutputStream; * of {@link Part} objects. * * @author Arjen Poutsma + * @author Seonghun Lee * @since 5.3 */ @SuppressWarnings("NullAway") // Dataflow analysis limitation @@ -380,6 +381,15 @@ final class PartGenerator extends BaseSubscriber { } private void switchToFile(DataBuffer current, long byteCount) { + if (PartGenerator.this.maxDiskUsagePerPart != -1 && byteCount > PartGenerator.this.maxDiskUsagePerPart) { + DataBufferUtils.release(current); + this.dispose(); + emitError(new DataBufferLimitException( + "Part exceeded the disk usage limit of " + PartGenerator.this.maxDiskUsagePerPart + + " bytes")); + return; + } + List content = new ArrayList<>(this.content); content.add(current); this.releaseOnDispose = false; diff --git a/spring-web/src/test/java/org/springframework/http/codec/multipart/DefaultPartHttpMessageReaderTests.java b/spring-web/src/test/java/org/springframework/http/codec/multipart/DefaultPartHttpMessageReaderTests.java index 372f1481b00..81e78543b3e 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/multipart/DefaultPartHttpMessageReaderTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/multipart/DefaultPartHttpMessageReaderTests.java @@ -63,6 +63,7 @@ import static org.springframework.core.io.buffer.DataBufferUtils.release; * * @author Arjen Poutsma * @author Brian Clozel + * @author Seonghun Lee */ class DefaultPartHttpMessageReaderTests extends AbstractLeakCheckingTests { @@ -313,6 +314,20 @@ class DefaultPartHttpMessageReaderTests extends AbstractLeakCheckingTests { .verify(); } + @Test // gh-35099 + void exceedDiskUsageOnSpillOver() { + MockServerHttpRequest request = createRequest("files.multipart", "\"----WebKitFormBoundaryG8fJ50opQOML0oGD\""); + + DefaultPartHttpMessageReader reader = new DefaultPartHttpMessageReader(); + reader.setMaxInMemorySize(90); + reader.setMaxDiskUsagePerPart(99); + Flux result = reader.read(forClass(Part.class), request, emptyMap()); + + StepVerifier.create(result) + .expectError(DataBufferLimitException.class) + .verify(); + } + @ParameterizedDefaultPartHttpMessageReaderTest void emptyLastPart(DefaultPartHttpMessageReader reader) throws InterruptedException { MockServerHttpRequest request = createRequest(