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.
1717package org .springframework .http .codec .multipart ;
1818
1919import java .io .IOException ;
20+ import java .io .UncheckedIOException ;
2021import java .nio .channels .Channels ;
2122import java .nio .channels .FileChannel ;
2223import java .nio .channels .ReadableByteChannel ;
2324import java .nio .charset .Charset ;
2425import java .nio .charset .StandardCharsets ;
26+ import java .nio .file .Files ;
2527import java .nio .file .OpenOption ;
2628import java .nio .file .Path ;
2729import java .nio .file .StandardOpenOption ;
7880 */
7981public 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