Delete file on multipart cancel
This commit makes sure that the temporary file used for multipart storage is deleted when the source stream is malformed or cancelled. Closes gh-28740
This commit is contained in:
@@ -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) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -609,6 +609,7 @@ final class PartGenerator extends BaseSubscriber<MultipartParser.Token> {
|
||||
}
|
||||
else {
|
||||
MultipartUtils.closeChannel(newState.channel);
|
||||
MultipartUtils.deleteFile(newState.file);
|
||||
this.content.forEach(DataBufferUtils::release);
|
||||
}
|
||||
}
|
||||
@@ -640,6 +641,8 @@ final class PartGenerator extends BaseSubscriber<MultipartParser.Token> {
|
||||
|
||||
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<MultipartParser.Token> {
|
||||
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<MultipartParser.Token> {
|
||||
@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<MultipartParser.Token> {
|
||||
if (this.closeOnDispose) {
|
||||
MultipartUtils.closeChannel(this.channel);
|
||||
}
|
||||
if (this.deleteOnDispose) {
|
||||
MultipartUtils.deleteFile(this.file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -710,6 +721,8 @@ final class PartGenerator extends BaseSubscriber<MultipartParser.Token> {
|
||||
|
||||
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<MultipartParser.Token> {
|
||||
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<MultipartParser.Token> {
|
||||
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<MultipartParser.Token> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
this.disposed = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WRITE-FILE";
|
||||
|
||||
Reference in New Issue
Block a user