18
18
*/
19
19
package org .apache .struts2 .dispatcher .multipart ;
20
20
21
+ import org .apache .commons .fileupload2 .core .DiskFileItemFactory ;
22
+ import org .apache .commons .fileupload2 .core .RequestContext ;
21
23
import org .apache .struts2 .inject .Inject ;
22
24
import jakarta .servlet .http .HttpServletRequest ;
23
25
import org .apache .commons .fileupload2 .core .FileUploadByteCountLimitException ;
33
35
import org .apache .struts2 .StrutsConstants ;
34
36
import org .apache .struts2 .dispatcher .LocalizedMessage ;
35
37
38
+ import java .io .File ;
36
39
import java .io .IOException ;
37
40
import java .nio .charset .Charset ;
38
41
import java .nio .file .Path ;
42
45
import java .util .HashMap ;
43
46
import java .util .List ;
44
47
import java .util .Map ;
48
+ import java .util .UUID ;
49
+
50
+ import static org .apache .commons .lang3 .StringUtils .normalizeSpace ;
45
51
46
52
/**
47
53
* Abstract class with some helper methods, it should be used
@@ -187,7 +193,21 @@ protected Charset readCharsetEncoding(HttpServletRequest request) {
187
193
* @param charset used charset from incoming request
188
194
* @param saveDir a temporary folder to store uploaded files (not always needed)
189
195
*/
190
- protected abstract JakartaServletDiskFileUpload createJakartaFileUpload (Charset charset , Path saveDir );
196
+ protected JakartaServletDiskFileUpload createJakartaFileUpload (Charset charset , Path saveDir ) {
197
+ DiskFileItemFactory .Builder builder = DiskFileItemFactory .builder ();
198
+
199
+ LOG .debug ("Using file save directory: {}" , saveDir );
200
+ builder .setPath (saveDir );
201
+
202
+ LOG .debug ("Sets buffer size: {}" , bufferSize );
203
+ builder .setBufferSize (bufferSize );
204
+
205
+ LOG .debug ("Using charset: {}" , charset );
206
+ builder .setCharset (charset );
207
+
208
+ DiskFileItemFactory factory = builder .get ();
209
+ return new JakartaServletDiskFileUpload (factory );
210
+ }
191
211
192
212
protected JakartaServletDiskFileUpload prepareServletFileUpload (Charset charset , Path saveDir ) {
193
213
JakartaServletDiskFileUpload servletFileUpload = createJakartaFileUpload (charset , saveDir );
@@ -207,11 +227,15 @@ protected JakartaServletDiskFileUpload prepareServletFileUpload(Charset charset,
207
227
return servletFileUpload ;
208
228
}
209
229
230
+ protected RequestContext createRequestContext (HttpServletRequest request ) {
231
+ return new StrutsRequestContext (request );
232
+ }
233
+
210
234
protected boolean exceedsMaxStringLength (String fieldName , String fieldValue ) {
211
235
if (maxStringLength != null && fieldValue .length () > maxStringLength ) {
212
236
if (LOG .isDebugEnabled ()) {
213
237
LOG .debug ("Form field: {} of size: {} bytes exceeds limit of: {}." ,
214
- sanitizeNewlines (fieldName ), fieldValue .length (), maxStringLength );
238
+ normalizeSpace (fieldName ), fieldValue .length (), maxStringLength );
215
239
}
216
240
LocalizedMessage localizedMessage = new LocalizedMessage (this .getClass (),
217
241
STRUTS_MESSAGES_UPLOAD_ERROR_PARAMETER_TOO_LONG_KEY , null ,
@@ -234,7 +258,7 @@ public void parse(HttpServletRequest request, String saveDir) throws IOException
234
258
try {
235
259
processUpload (request , saveDir );
236
260
} catch (FileUploadException e ) {
237
- LOG .debug ("Error parsing the multi-part request!" , e );
261
+ LOG .warn ("Error parsing the multi-part request!" , e );
238
262
Class <? extends Throwable > exClass = FileUploadException .class ;
239
263
Object [] args = new Object []{};
240
264
@@ -257,7 +281,7 @@ public void parse(HttpServletRequest request, String saveDir) throws IOException
257
281
errors .add (errorMessage );
258
282
}
259
283
} catch (IOException e ) {
260
- LOG .debug ("Unable to parse request" , e );
284
+ LOG .warn ("Unable to parse request" , e );
261
285
LocalizedMessage errorMessage = buildErrorMessage (e .getClass (), e .getMessage (), new Object []{});
262
286
if (!errors .contains (errorMessage )) {
263
287
errors .add (errorMessage );
@@ -384,6 +408,22 @@ public String[] getParameterValues(String name) {
384
408
return values .toArray (new String [0 ]);
385
409
}
386
410
411
+ /**
412
+ * Creates a secure temporary file in the specified directory using UUID-based naming.
413
+ * This method ensures files are created in a controlled location rather than the
414
+ * system temporary directory, reducing security risks.
415
+ *
416
+ * @param fileName the original filename for logging purposes
417
+ * @param location the directory where the temporary file should be created
418
+ * @return a new temporary file in the specified location
419
+ */
420
+ protected File createTemporaryFile (String fileName , Path location ) {
421
+ String uid = UUID .randomUUID ().toString ().replace ("-" , "_" );
422
+ File file = location .resolve ("upload_" + uid + ".tmp" ).toFile ();
423
+ LOG .debug ("Creating temporary file: {} (originally: {})" , file .getName (), fileName );
424
+ return file ;
425
+ }
426
+
387
427
/* (non-Javadoc)
388
428
* @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#cleanUp()
389
429
*/
0 commit comments