diff --git a/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartUtils.java b/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartUtils.java index fd13036bc3..6cc96de0cd 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartUtils.java +++ b/spring-web/src/main/java/org/springframework/http/codec/multipart/MultipartUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,8 @@ import java.io.IOException; import java.nio.channels.Channel; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; @@ -91,4 +93,12 @@ abstract class MultipartUtils { } } + public static void deleteFile(Path file) { + try { + Files.delete(file); + } + catch (IOException ignore) { + } + } + } 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 484a09c6ad..6077f719a0 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 @@ -609,6 +609,7 @@ final class PartGenerator extends BaseSubscriber { } else { MultipartUtils.closeChannel(newState.channel); + MultipartUtils.deleteFile(newState.file); this.content.forEach(DataBufferUtils::release); } } @@ -640,6 +641,8 @@ final class PartGenerator extends BaseSubscriber { private volatile boolean closeOnDispose = true; + private volatile boolean deleteOnDispose = true; + public IdleFileState(WritingFileState state) { this.headers = state.headers; @@ -654,16 +657,20 @@ final class PartGenerator extends BaseSubscriber { if (PartGenerator.this.maxDiskUsagePerPart == -1 || count <= PartGenerator.this.maxDiskUsagePerPart) { this.closeOnDispose = false; + this.deleteOnDispose = false; WritingFileState newState = new WritingFileState(this); if (changeState(this, newState)) { newState.writeBuffer(dataBuffer); } else { MultipartUtils.closeChannel(this.channel); + MultipartUtils.deleteFile(this.file); DataBufferUtils.release(dataBuffer); } } else { + MultipartUtils.closeChannel(this.channel); + MultipartUtils.deleteFile(this.file); DataBufferUtils.release(dataBuffer); emitError(new DataBufferLimitException( "Part exceeded the disk usage limit of " + PartGenerator.this.maxDiskUsagePerPart + @@ -674,6 +681,7 @@ final class PartGenerator extends BaseSubscriber { @Override public void partComplete(boolean finalPart) { MultipartUtils.closeChannel(this.channel); + this.deleteOnDispose = false; emitPart(DefaultParts.part(this.headers, this.file, PartGenerator.this.blockingOperationScheduler)); if (finalPart) { emitComplete(); @@ -685,6 +693,9 @@ final class PartGenerator extends BaseSubscriber { if (this.closeOnDispose) { MultipartUtils.closeChannel(this.channel); } + if (this.deleteOnDispose) { + MultipartUtils.deleteFile(this.file); + } } @@ -710,6 +721,8 @@ final class PartGenerator extends BaseSubscriber { private volatile boolean finalPart; + private volatile boolean disposed; + public WritingFileState(CreateFileState state, Path file, WritableByteChannel channel) { this.headers = state.headers; @@ -761,11 +774,15 @@ final class PartGenerator extends BaseSubscriber { if (this.completed) { newState.partComplete(this.finalPart); } + else if (this.disposed) { + newState.dispose(); + } else if (changeState(this, newState)) { requestToken(); } else { MultipartUtils.closeChannel(this.channel); + MultipartUtils.deleteFile(this.file); } } @@ -779,6 +796,8 @@ final class PartGenerator extends BaseSubscriber { return Mono.empty(); } catch (IOException ex) { + MultipartUtils.closeChannel(this.channel); + MultipartUtils.deleteFile(this.file); return Mono.error(ex); } finally { @@ -786,6 +805,12 @@ final class PartGenerator extends BaseSubscriber { } } + @Override + public void dispose() { + this.disposed = true; + } + + @Override public String toString() { return "WRITE-FILE";