Use DataBufferUtils.write in DefaultFilePart.transferTo

This commit makes sure that in DefaultMultipartMessageReader's
DefaultFilePart, the file is not closed before all bytes are written,
by using DataBufferUtils.write (see c1b6885191d6a50347aeaa14da994f0db88f26fe).

The commit also improves on the logging of the
DefaultMultipartMessageReader.

Closes gh-23130
This commit is contained in:
Arjen Poutsma
2019-06-14 10:31:17 +02:00
parent f08656c6cb
commit 30af01fd4e
2 changed files with 59 additions and 43 deletions

View File

@@ -16,6 +16,10 @@
package org.springframework.web.reactive.result.method.annotation;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
@@ -31,6 +35,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.MultipartBodyBuilder;
@@ -145,6 +150,34 @@ public class MultipartIntegrationTests extends AbstractHttpHandlerIntegrationTes
.verifyComplete();
}
@Test
public void transferTo() {
Flux<String> result = webClient
.post()
.uri("/transferTo")
.syncBody(generateBody())
.retrieve()
.bodyToFlux(String.class);
StepVerifier.create(result)
.consumeNextWith(filename -> verifyContents(Paths.get(filename), new ClassPathResource("foo.txt", MultipartHttpMessageReader.class)))
.consumeNextWith(filename -> verifyContents(Paths.get(filename), new ClassPathResource("logo.png", getClass())))
.verifyComplete();
}
private static void verifyContents(Path tempFile, Resource resource) {
try {
byte[] tempBytes = Files.readAllBytes(tempFile);
byte[] resourceBytes = Files.readAllBytes(resource.getFile().toPath());
assertThat(tempBytes).isEqualTo(resourceBytes);
}
catch (IOException ex) {
throw new AssertionError(ex);
}
}
@Test
public void modelAttribute() {
Mono<String> result = webClient
@@ -217,6 +250,21 @@ public class MultipartIntegrationTests extends AbstractHttpHandlerIntegrationTes
return partFluxDescription(Flux.from(parts));
}
@PostMapping("/transferTo")
Flux<String> transferTo(@RequestPart("fileParts") Flux<FilePart> parts) {
return parts.flatMap(filePart -> {
try {
Path tempFile = Files.createTempFile("MultipartIntegrationTests", filePart.filename());
return filePart.transferTo(tempFile)
.then(Mono.just(tempFile.toString() + "\n"));
}
catch (IOException e) {
return Mono.error(e);
}
});
}
@PostMapping("/modelAttribute")
String modelAttribute(@ModelAttribute FormBean formBean) {
return formBean.toString();