1
1
/*
2
- * Copyright 2002-2020 the original author or authors.
2
+ * Copyright 2002-2021 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
17
17
package org .springframework .http .codec .multipart ;
18
18
19
19
import java .io .IOException ;
20
+ import java .io .UncheckedIOException ;
20
21
import java .nio .channels .Channels ;
21
22
import java .nio .channels .FileChannel ;
22
23
import java .nio .channels .ReadableByteChannel ;
23
24
import java .nio .charset .Charset ;
24
25
import java .nio .charset .StandardCharsets ;
26
+ import java .nio .file .Files ;
25
27
import java .nio .file .OpenOption ;
26
28
import java .nio .file .Path ;
27
29
import java .nio .file .StandardOpenOption ;
78
80
*/
79
81
public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implements HttpMessageReader <Part > {
80
82
83
+ private static final String FILE_STORAGE_DIRECTORY_PREFIX = "synchronoss-file-upload-" ;
84
+
81
85
private int maxInMemorySize = 256 * 1024 ;
82
86
83
87
private long maxDiskUsagePerPart = -1 ;
84
88
85
89
private int maxParts = -1 ;
86
90
91
+ private Path fileStorageDirectory = createTempDirectory ();
92
+
87
93
88
94
/**
89
95
* Configure the maximum amount of memory that is allowed to use per part.
@@ -144,6 +150,22 @@ public int getMaxParts() {
144
150
return this .maxParts ;
145
151
}
146
152
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
+
147
169
148
170
@ Override
149
171
public List <MediaType > getReadableMediaTypes () {
@@ -167,7 +189,7 @@ public boolean canRead(ResolvableType elementType, @Nullable MediaType mediaType
167
189
168
190
@ Override
169
191
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 ))
171
193
.doOnNext (part -> {
172
194
if (!Hints .isLoggingSuppressed (hints )) {
173
195
LogFormatUtils .traceDebug (logger , traceOn -> Hints .getLogPrefix (hints ) + "Parsed " +
@@ -183,6 +205,15 @@ public Mono<Part> readMono(ResolvableType elementType, ReactiveHttpInputMessage
183
205
return Mono .error (new UnsupportedOperationException ("Cannot read multipart request body into single Part" ));
184
206
}
185
207
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
+
186
217
187
218
/**
188
219
* Subscribe to the input stream and feed the Synchronoss parser. Then listen
@@ -194,14 +225,17 @@ private class SynchronossPartGenerator extends BaseSubscriber<DataBuffer> implem
194
225
195
226
private final LimitedPartBodyStreamStorageFactory storageFactory = new LimitedPartBodyStreamStorageFactory ();
196
227
228
+ private final Path fileStorageDirectory ;
229
+
197
230
@ Nullable
198
231
private NioMultipartParserListener listener ;
199
232
200
233
@ Nullable
201
234
private NioMultipartParser parser ;
202
235
203
- public SynchronossPartGenerator (ReactiveHttpInputMessage inputMessage ) {
236
+ public SynchronossPartGenerator (ReactiveHttpInputMessage inputMessage , Path fileStorageDirectory ) {
204
237
this .inputMessage = inputMessage ;
238
+ this .fileStorageDirectory = fileStorageDirectory ;
205
239
}
206
240
207
241
@ Override
@@ -218,6 +252,7 @@ public void accept(FluxSink<Part> sink) {
218
252
219
253
this .parser = Multipart
220
254
.multipart (context )
255
+ .saveTemporaryFilesTo (this .fileStorageDirectory .toString ())
221
256
.usePartBodyStreamStorageFactory (this .storageFactory )
222
257
.forNIO (this .listener );
223
258
0 commit comments