mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-10-04 05:59:12 +00:00
Enforce disk usage limit when spilling part to disk
Previously, PartGenerator only enforced maxDiskUsagePerPart for body buffers that arrived after a part had switched to file storage. The content accumulated in memory that triggered the switch was written to disk without any check against maxDiskUsagePerPart. As a result, a part whose last body buffer caused the in-memory overflow was accepted in full, even when its total size exceeded the configured disk usage limit. This commit checks the accumulated byte count against maxDiskUsagePerPart before switching to file storage, and emits a DataBufferLimitException, consistent with the existing check for subsequent buffers. Closes gh-35099 Signed-off-by: seonghun lee <harrisleesh@gmail.com>
This commit is contained in:
committed by
Brian Clozel
parent
bb7ea37f1b
commit
94afeedad6
@@ -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,16 @@ final class PartGenerator extends BaseSubscriber<MultipartParser.Token> {
|
||||
}
|
||||
|
||||
private void switchToFile(DataBuffer current, long byteCount) {
|
||||
if (PartGenerator.this.maxDiskUsagePerPart != -1 && byteCount > PartGenerator.this.maxDiskUsagePerPart) {
|
||||
DataBufferUtils.release(current);
|
||||
this.content.forEach(DataBufferUtils::release);
|
||||
this.content.clear();
|
||||
emitError(new DataBufferLimitException(
|
||||
"Part exceeded the disk usage limit of " + PartGenerator.this.maxDiskUsagePerPart +
|
||||
" bytes"));
|
||||
return;
|
||||
}
|
||||
|
||||
List<DataBuffer> content = new ArrayList<>(this.content);
|
||||
content.add(current);
|
||||
this.releaseOnDispose = false;
|
||||
|
||||
+15
@@ -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 {
|
||||
|
||||
@@ -314,6 +315,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<Part> 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(
|
||||
|
||||
Reference in New Issue
Block a user