Skip to content

Commit cce60c4

Browse files
committed
Ensure Synchronoss temp directories do not collide
This commit makes sure that Synchronoss uses a random temporary directory to store uploaded files, so that two instances do not collide. Closes gh-26931
1 parent 1469bdb commit cce60c4

File tree

1 file changed

+38
-3
lines changed

1 file changed

+38
-3
lines changed

spring-web/src/main/java/org/springframework/http/codec/multipart/SynchronossPartHttpMessageReader.java

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,11 +17,13 @@
1717
package org.springframework.http.codec.multipart;
1818

1919
import java.io.IOException;
20+
import java.io.UncheckedIOException;
2021
import java.nio.channels.Channels;
2122
import java.nio.channels.FileChannel;
2223
import java.nio.channels.ReadableByteChannel;
2324
import java.nio.charset.Charset;
2425
import java.nio.charset.StandardCharsets;
26+
import java.nio.file.Files;
2527
import java.nio.file.OpenOption;
2628
import java.nio.file.Path;
2729
import java.nio.file.StandardOpenOption;
@@ -78,12 +80,16 @@
7880
*/
7981
public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implements HttpMessageReader<Part> {
8082

83+
private static final String FILE_STORAGE_DIRECTORY_PREFIX = "synchronoss-file-upload-";
84+
8185
private int maxInMemorySize = 256 * 1024;
8286

8387
private long maxDiskUsagePerPart = -1;
8488

8589
private int maxParts = -1;
8690

91+
private Path fileStorageDirectory = createTempDirectory();
92+
8793

8894
/**
8995
* Configure the maximum amount of memory that is allowed to use per part.
@@ -144,6 +150,22 @@ public int getMaxParts() {
144150
return this.maxParts;
145151
}
146152

153+
/**
154+
* Set the directory used to store parts larger than
155+
* {@link #setMaxInMemorySize(int) maxInMemorySize}. By default, a new
156+
* temporary directory is created.
157+
* @throws IOException if an I/O error occurs, or the parent directory
158+
* does not exist
159+
* @since 5.3.7
160+
*/
161+
public void setFileStorageDirectory(Path fileStorageDirectory) throws IOException {
162+
Assert.notNull(fileStorageDirectory, "FileStorageDirectory must not be null");
163+
if (!Files.exists(fileStorageDirectory)) {
164+
Files.createDirectory(fileStorageDirectory);
165+
}
166+
this.fileStorageDirectory = fileStorageDirectory;
167+
}
168+
147169

148170
@Override
149171
public List<MediaType> getReadableMediaTypes() {
@@ -167,7 +189,7 @@ public boolean canRead(ResolvableType elementType, @Nullable MediaType mediaType
167189

168190
@Override
169191
public Flux<Part> read(ResolvableType elementType, ReactiveHttpInputMessage message, Map<String, Object> hints) {
170-
return Flux.create(new SynchronossPartGenerator(message))
192+
return Flux.create(new SynchronossPartGenerator(message, this.fileStorageDirectory))
171193
.doOnNext(part -> {
172194
if (!Hints.isLoggingSuppressed(hints)) {
173195
LogFormatUtils.traceDebug(logger, traceOn -> Hints.getLogPrefix(hints) + "Parsed " +
@@ -183,6 +205,15 @@ public Mono<Part> readMono(ResolvableType elementType, ReactiveHttpInputMessage
183205
return Mono.error(new UnsupportedOperationException("Cannot read multipart request body into single Part"));
184206
}
185207

208+
private static Path createTempDirectory() {
209+
try {
210+
return Files.createTempDirectory(FILE_STORAGE_DIRECTORY_PREFIX);
211+
}
212+
catch (IOException ex) {
213+
throw new UncheckedIOException(ex);
214+
}
215+
}
216+
186217

187218
/**
188219
* Subscribe to the input stream and feed the Synchronoss parser. Then listen
@@ -194,14 +225,17 @@ private class SynchronossPartGenerator extends BaseSubscriber<DataBuffer> implem
194225

195226
private final LimitedPartBodyStreamStorageFactory storageFactory = new LimitedPartBodyStreamStorageFactory();
196227

228+
private final Path fileStorageDirectory;
229+
197230
@Nullable
198231
private NioMultipartParserListener listener;
199232

200233
@Nullable
201234
private NioMultipartParser parser;
202235

203-
public SynchronossPartGenerator(ReactiveHttpInputMessage inputMessage) {
236+
public SynchronossPartGenerator(ReactiveHttpInputMessage inputMessage, Path fileStorageDirectory) {
204237
this.inputMessage = inputMessage;
238+
this.fileStorageDirectory = fileStorageDirectory;
205239
}
206240

207241
@Override
@@ -218,6 +252,7 @@ public void accept(FluxSink<Part> sink) {
218252

219253
this.parser = Multipart
220254
.multipart(context)
255+
.saveTemporaryFilesTo(this.fileStorageDirectory.toString())
221256
.usePartBodyStreamStorageFactory(this.storageFactory)
222257
.forNIO(this.listener);
223258

0 commit comments

Comments
 (0)