diff --git a/spring-web/src/main/java/org/springframework/http/codec/multipart/SynchronossPartHttpMessageReader.java b/spring-web/src/main/java/org/springframework/http/codec/multipart/SynchronossPartHttpMessageReader.java index b914380f59..5cb374c770 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/multipart/SynchronossPartHttpMessageReader.java +++ b/spring-web/src/main/java/org/springframework/http/codec/multipart/SynchronossPartHttpMessageReader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -17,11 +17,13 @@ package org.springframework.http.codec.multipart; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.nio.file.OpenOption; import java.nio.file.Path; import java.nio.file.StandardOpenOption; @@ -78,12 +80,16 @@ import org.springframework.util.Assert; */ public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implements HttpMessageReader { + private static final String FILE_STORAGE_DIRECTORY_PREFIX = "synchronoss-file-upload-"; + private int maxInMemorySize = 256 * 1024; private long maxDiskUsagePerPart = -1; private int maxParts = -1; + private Path fileStorageDirectory = createTempDirectory(); + /** * Configure the maximum amount of memory that is allowed to use per part. @@ -144,6 +150,22 @@ public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implem return this.maxParts; } + /** + * Set the directory used to store parts larger than + * {@link #setMaxInMemorySize(int) maxInMemorySize}. By default, a new + * temporary directory is created. + * @throws IOException if an I/O error occurs, or the parent directory + * does not exist + * @since 5.3.7 + */ + public void setFileStorageDirectory(Path fileStorageDirectory) throws IOException { + Assert.notNull(fileStorageDirectory, "FileStorageDirectory must not be null"); + if (!Files.exists(fileStorageDirectory)) { + Files.createDirectory(fileStorageDirectory); + } + this.fileStorageDirectory = fileStorageDirectory; + } + @Override public List getReadableMediaTypes() { @@ -167,7 +189,7 @@ public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implem @Override public Flux read(ResolvableType elementType, ReactiveHttpInputMessage message, Map hints) { - return Flux.create(new SynchronossPartGenerator(message)) + return Flux.create(new SynchronossPartGenerator(message, this.fileStorageDirectory)) .doOnNext(part -> { if (!Hints.isLoggingSuppressed(hints)) { LogFormatUtils.traceDebug(logger, traceOn -> Hints.getLogPrefix(hints) + "Parsed " + @@ -183,6 +205,15 @@ public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implem return Mono.error(new UnsupportedOperationException("Cannot read multipart request body into single Part")); } + private static Path createTempDirectory() { + try { + return Files.createTempDirectory(FILE_STORAGE_DIRECTORY_PREFIX); + } + catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + /** * Subscribe to the input stream and feed the Synchronoss parser. Then listen @@ -194,14 +225,17 @@ public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implem private final LimitedPartBodyStreamStorageFactory storageFactory = new LimitedPartBodyStreamStorageFactory(); + private final Path fileStorageDirectory; + @Nullable private NioMultipartParserListener listener; @Nullable private NioMultipartParser parser; - public SynchronossPartGenerator(ReactiveHttpInputMessage inputMessage) { + public SynchronossPartGenerator(ReactiveHttpInputMessage inputMessage, Path fileStorageDirectory) { this.inputMessage = inputMessage; + this.fileStorageDirectory = fileStorageDirectory; } @Override @@ -218,6 +252,7 @@ public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implem this.parser = Multipart .multipart(context) + .saveTemporaryFilesTo(this.fileStorageDirectory.toString()) .usePartBodyStreamStorageFactory(this.storageFactory) .forNIO(this.listener);