20
20
21
21
import jakarta .servlet .http .HttpServletRequest ;
22
22
import org .apache .commons .fileupload2 .core .DiskFileItem ;
23
- import org .apache .commons .fileupload2 .core .DiskFileItemFactory ;
23
+ import org .apache .commons .fileupload2 .core .RequestContext ;
24
24
import org .apache .commons .fileupload2 .jakarta .servlet6 .JakartaServletDiskFileUpload ;
25
25
import org .apache .commons .lang3 .StringUtils ;
26
26
import org .apache .logging .log4j .LogManager ;
27
27
import org .apache .logging .log4j .Logger ;
28
28
29
+ import java .io .File ;
29
30
import java .io .IOException ;
30
31
import java .nio .charset .Charset ;
31
32
import java .nio .file .Path ;
@@ -41,14 +42,24 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
41
42
42
43
private static final Logger LOG = LogManager .getLogger (JakartaMultiPartRequest .class );
43
44
45
+ /**
46
+ * List to track all DiskFileItem instances for proper cleanup
47
+ */
48
+ private final List <DiskFileItem > diskFileItems = new ArrayList <>();
49
+
44
50
@ Override
45
51
protected void processUpload (HttpServletRequest request , String saveDir ) throws IOException {
46
52
Charset charset = readCharsetEncoding (request );
47
53
48
54
JakartaServletDiskFileUpload servletFileUpload =
49
55
prepareServletFileUpload (charset , Path .of (saveDir ));
50
56
51
- for (DiskFileItem item : servletFileUpload .parseRequest (request )) {
57
+ RequestContext requestContext = createRequestContext (request );
58
+
59
+ for (DiskFileItem item : servletFileUpload .parseRequest (requestContext )) {
60
+ // Track all DiskFileItem instances for cleanup
61
+ diskFileItems .add (item );
62
+
52
63
LOG .debug (() -> "Processing a form field: " + normalizeSpace (item .getFieldName ()));
53
64
if (item .isFormField ()) {
54
65
processNormalFormField (item , charset );
@@ -59,23 +70,6 @@ protected void processUpload(HttpServletRequest request, String saveDir) throws
59
70
}
60
71
}
61
72
62
- @ Override
63
- protected JakartaServletDiskFileUpload createJakartaFileUpload (Charset charset , Path saveDir ) {
64
- DiskFileItemFactory .Builder builder = DiskFileItemFactory .builder ();
65
-
66
- LOG .debug ("Using file save directory: {}" , saveDir );
67
- builder .setPath (saveDir );
68
-
69
- LOG .debug ("Sets minimal buffer size to always write file to disk" );
70
- builder .setBufferSize (1 );
71
-
72
- LOG .debug ("Using charset: {}" , charset );
73
- builder .setCharset (charset );
74
-
75
- DiskFileItemFactory factory = builder .get ();
76
- return new JakartaServletDiskFileUpload (factory );
77
- }
78
-
79
73
protected void processNormalFormField (DiskFileItem item , Charset charset ) throws IOException {
80
74
LOG .debug ("Item: {} is a normal form field" , normalizeSpace (item .getName ()));
81
75
@@ -114,7 +108,30 @@ protected void processFileField(DiskFileItem item) {
114
108
}
115
109
116
110
if (item .isInMemory ()) {
117
- LOG .warn (() -> "Storing uploaded files just in memory isn't supported currently, skipping file: %s!" .formatted (normalizeSpace (item .getName ())));
111
+ LOG .debug ("Creating temporary file representing in-memory uploaded item: {}" , normalizeSpace (item .getFieldName ()));
112
+ try {
113
+ File tempFile = File .createTempFile ("struts_upload_" , "_" + item .getName ());
114
+ tempFile .deleteOnExit (); // Ensure cleanup on JVM exit
115
+
116
+ // Write the in-memory content to the temporary file
117
+ try (java .io .FileOutputStream fos = new java .io .FileOutputStream (tempFile )) {
118
+ fos .write (item .get ());
119
+ }
120
+
121
+ UploadedFile uploadedFile = StrutsUploadedFile .Builder
122
+ .create (tempFile )
123
+ .withOriginalName (item .getName ())
124
+ .withContentType (item .getContentType ())
125
+ .withInputName (item .getFieldName ())
126
+ .build ();
127
+ values .add (uploadedFile );
128
+
129
+ LOG .debug ("Created temporary file for in-memory uploaded item: {} at {}" ,
130
+ normalizeSpace (item .getName ()), tempFile .getAbsolutePath ());
131
+ } catch (IOException e ) {
132
+ LOG .warn ("Failed to create temporary file for in-memory uploaded item: {}" ,
133
+ normalizeSpace (item .getName ()), e );
134
+ }
118
135
} else {
119
136
UploadedFile uploadedFile = StrutsUploadedFile .Builder
120
137
.create (item .getPath ().toFile ())
@@ -128,4 +145,33 @@ protected void processFileField(DiskFileItem item) {
128
145
uploadedFiles .put (item .getFieldName (), values );
129
146
}
130
147
148
+ /**
149
+ * Override cleanUp to ensure all DiskFileItem instances are properly cleaned up
150
+ */
151
+ @ Override
152
+ public void cleanUp () {
153
+ super .cleanUp ();
154
+ try {
155
+ LOG .debug ("Clean up all DiskFileItem instances (both form fields and file uploads" );
156
+ for (DiskFileItem item : diskFileItems ) {
157
+ try {
158
+ if (item .isInMemory ()) {
159
+ LOG .debug ("Cleaning up in-memory item: {}" , normalizeSpace (item .getFieldName ()));
160
+ } else {
161
+ LOG .debug ("Cleaning up disk item: {} at {}" , normalizeSpace (item .getFieldName ()), item .getPath ());
162
+ if (item .getPath () != null && item .getPath ().toFile ().exists ()) {
163
+ if (!item .getPath ().toFile ().delete ()) {
164
+ LOG .warn ("There was a problem attempting to delete temporary file: {}" , item .getPath ());
165
+ }
166
+ }
167
+ }
168
+ } catch (Exception e ) {
169
+ LOG .warn ("Error cleaning up DiskFileItem: {}" , normalizeSpace (item .getFieldName ()), e );
170
+ }
171
+ }
172
+ } finally {
173
+ diskFileItems .clear ();
174
+ }
175
+ }
176
+
131
177
}
0 commit comments