You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2023/03/08 16:15:49 UTC

[struts] branch release/6.1.x created (now c3deb3923)

This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a change to branch release/6.1.x
in repository https://gitbox.apache.org/repos/asf/struts.git


      at c3deb3923 WW-5285 Uses Long and null to check if option has been defined

This branch includes the following new commits:

     new 483a0c8d0 WW-5285 Limits max number of files to upload at once Upgrades commons-fileupload to ver. 1.5 and sets default limit to 256 files
     new c3deb3923 WW-5285 Uses Long and null to check if option has been defined

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[struts] 01/02: WW-5285 Limits max number of files to upload at once Upgrades commons-fileupload to ver. 1.5 and sets default limit to 256 files

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch release/6.1.x
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 483a0c8d012924b78343dd35e56037c0d48a84cf
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sat Feb 25 10:42:21 2023 +0100

    WW-5285 Limits max number of files to upload at once
    Upgrades commons-fileupload to ver. 1.5 and sets default limit to 256 files
---
 .../java/org/apache/struts2/StrutsConstants.java   |  3 ++
 .../struts2/config/entities/ConstantConfig.java    | 10 +++++
 .../multipart/AbstractMultiPartRequest.java        | 12 ++++++
 .../multipart/JakartaMultiPartRequest.java         | 21 ++++++++---
 .../multipart/JakartaStreamMultiPartRequest.java   |  3 ++
 .../org/apache/struts2/default.properties          |  1 +
 .../org/apache/struts2/struts-messages.properties  |  1 +
 .../interceptor/FileUploadInterceptorTest.java     | 44 ++++++++++++++++++++++
 pom.xml                                            |  2 +-
 9 files changed, 91 insertions(+), 6 deletions(-)

diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java
index c75ff3d54..15eb43d87 100644
--- a/core/src/main/java/org/apache/struts2/StrutsConstants.java
+++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java
@@ -142,6 +142,9 @@ public final class StrutsConstants {
     /** The maximize size of a multipart request (file upload) */
     public static final String STRUTS_MULTIPART_MAXSIZE = "struts.multipart.maxSize";
 
+    /** The maximized number of files allowed to upload */
+    public static final String STRUTS_MULTIPART_MAXFILES = "struts.multipart.maxFiles";
+
     /** The directory to use for storing uploaded files */
     public static final String STRUTS_MULTIPART_SAVEDIR = "struts.multipart.saveDir";
 
diff --git a/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java b/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java
index 63c30ce2f..f728d9115 100644
--- a/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java
+++ b/core/src/main/java/org/apache/struts2/config/entities/ConstantConfig.java
@@ -64,6 +64,7 @@ public class ConstantConfig {
     private String uiTheme;
     private String uiThemeExpansionToken;
     private Long multipartMaxSize;
+    private Long multipartMaxFiles;
     private String multipartSaveDir;
     private Integer multipartBufferSize;
     private BeanConfig multipartParser;
@@ -195,6 +196,7 @@ public class ConstantConfig {
         map.put(StrutsConstants.STRUTS_UI_THEME, uiTheme);
         map.put(StrutsConstants.STRUTS_UI_THEME_EXPANSION_TOKEN, uiThemeExpansionToken);
         map.put(StrutsConstants.STRUTS_MULTIPART_MAXSIZE, Objects.toString(multipartMaxSize, null));
+        map.put(StrutsConstants.STRUTS_MULTIPART_MAXFILES, Objects.toString(multipartMaxFiles, null));
         map.put(StrutsConstants.STRUTS_MULTIPART_SAVEDIR, multipartSaveDir);
         map.put(StrutsConstants.STRUTS_MULTIPART_BUFFERSIZE, Objects.toString(multipartBufferSize, null));
         map.put(StrutsConstants.STRUTS_MULTIPART_PARSER, beanConfToString(multipartParser));
@@ -580,6 +582,14 @@ public class ConstantConfig {
         this.multipartMaxSize = multipartMaxSize;
     }
 
+    public Long getMultipartMaxFiles() {
+        return multipartMaxFiles;
+    }
+
+    public void setMultipartMaxFiles(Long multipartMaxFiles) {
+        this.multipartMaxFiles = multipartMaxFiles;
+    }
+
     public String getMultipartSaveDir() {
         return multipartSaveDir;
     }
diff --git a/core/src/main/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequest.java b/core/src/main/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequest.java
index 700364047..b3410e578 100644
--- a/core/src/main/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequest.java
+++ b/core/src/main/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequest.java
@@ -54,6 +54,12 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
     protected long maxSize;
     protected boolean maxSizeProvided;
 
+    /**
+     * Specifies the maximum number of files in one request.
+     */
+    protected long maxFiles;
+    protected boolean maxFilesProvided;
+
     /**
      * Specifies the buffer size to use during streaming.
      */
@@ -88,6 +94,12 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
         this.maxSize = Long.parseLong(maxSize);
     }
 
+    @Inject(StrutsConstants.STRUTS_MULTIPART_MAXFILES)
+    public void setMaxFiles(String maxFiles) {
+        this.maxFilesProvided = true;
+        this.maxFiles = Long.parseLong(maxFiles);
+    }
+
     @Inject
     public void setLocaleProviderFactory(LocaleProviderFactory localeProviderFactory) {
         defaultLocale = localeProviderFactory.createLocaleProvider().getLocale();
diff --git a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java
index c629ec043..c20b1de19 100644
--- a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java
+++ b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.struts2.dispatcher.multipart;
 
+import org.apache.commons.fileupload.FileCountLimitExceededException;
 import org.apache.commons.fileupload.FileItem;
 import org.apache.commons.fileupload.FileUploadBase;
 import org.apache.commons.fileupload.FileUploadException;
@@ -35,7 +36,13 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * Multipart form data request adapter for Jakarta Commons Fileupload package.
@@ -65,9 +72,12 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
         } catch (FileUploadException e) {
             LOG.warn("Request exceeded size limit!", e);
             LocalizedMessage errorMessage;
-            if(e instanceof FileUploadBase.SizeLimitExceededException) {
+            if (e instanceof FileUploadBase.SizeLimitExceededException) {
                 FileUploadBase.SizeLimitExceededException ex = (FileUploadBase.SizeLimitExceededException) e;
                 errorMessage = buildErrorMessage(e, new Object[]{ex.getPermittedSize(), ex.getActualSize()});
+            } else if (e instanceof FileCountLimitExceededException) {
+                FileCountLimitExceededException ex = (FileCountLimitExceededException) e;
+                errorMessage = buildErrorMessage(e, new Object[]{ex.getLimit()});
             } else {
                 errorMessage = buildErrorMessage(e, new Object[]{});
             }
@@ -151,6 +161,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
     protected ServletFileUpload createServletFileUpload(DiskFileItemFactory fac) {
         ServletFileUpload upload = new ServletFileUpload(fac);
         upload.setSizeMax(maxSize);
+        upload.setFileCountMax(maxFiles);
         return upload;
     }
 
@@ -316,14 +327,14 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
     }
 
     /* (non-Javadoc)
-    * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#cleanUp()
-    */
+     * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#cleanUp()
+     */
     public void cleanUp() {
         Set<String> names = files.keySet();
         for (String name : names) {
             List<FileItem> items = files.get(name);
             for (FileItem item : items) {
-                LOG.debug("Removing file {} {}", name, item );
+                LOG.debug("Removing file {} {}", name, item);
                 if (!item.isInMemory()) {
                     item.delete();
                 }
diff --git a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java
index 2d016f56b..f709b3416 100644
--- a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java
+++ b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java
@@ -212,6 +212,9 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
             if (maxSizeProvided) {
                 servletFileUpload.setSizeMax(maxSize);
             }
+            if (maxFilesProvided) {
+                servletFileUpload.setFileCountMax(maxFiles);
+            }
             FileItemIterator i = servletFileUpload.getItemIterator(request);
 
             // Iterate the file items
diff --git a/core/src/main/resources/org/apache/struts2/default.properties b/core/src/main/resources/org/apache/struts2/default.properties
index 5847db3be..8c4144de8 100644
--- a/core/src/main/resources/org/apache/struts2/default.properties
+++ b/core/src/main/resources/org/apache/struts2/default.properties
@@ -68,6 +68,7 @@ struts.multipart.parser=jakarta
 ### Uses javax.servlet.context.tempdir by default
 struts.multipart.saveDir=
 struts.multipart.maxSize=2097152
+struts.multipart.maxFiles=256
 
 ### Load custom property files (does not override struts.properties!)
 # struts.custom.properties=application,org/apache/struts2/extension/custom
diff --git a/core/src/main/resources/org/apache/struts2/struts-messages.properties b/core/src/main/resources/org/apache/struts2/struts-messages.properties
index aa6e842e4..bf75f05b4 100644
--- a/core/src/main/resources/org/apache/struts2/struts-messages.properties
+++ b/core/src/main/resources/org/apache/struts2/struts-messages.properties
@@ -31,6 +31,7 @@ struts.messages.error.file.extension.not.allowed=File extension not allowed: {0}
 
 # dedicated messages used to handle various problems with file upload - check {@link JakartaMultiPartRequest#parse(HttpServletRequest, String)}
 struts.messages.upload.error.SizeLimitExceededException=Request exceeded allowed size limit! Max size allowed is: {0} but request was: {1}!
+struts.messages.upload.error.FileCountLimitExceededException=Request exceeded allowed number of files! Max allowed files number is: {0}!
 struts.messages.upload.error.IOException=Error uploading: {0}!
 
 devmode.notification=Developer Notification (set struts.devMode to false to disable this message):\n{0}
diff --git a/core/src/test/java/org/apache/struts2/interceptor/FileUploadInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/FileUploadInterceptorTest.java
index b6a41010e..842a7db3a 100644
--- a/core/src/test/java/org/apache/struts2/interceptor/FileUploadInterceptorTest.java
+++ b/core/src/test/java/org/apache/struts2/interceptor/FileUploadInterceptorTest.java
@@ -370,6 +370,49 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
         assertNotNull("test1.html", fileRealFilenames[0]);
     }
 
+    public void testUnacceptedNumberOfFiles() throws Exception {
+        final String htmlContent = "<html><head></head><body>html content</body></html>";
+        final String plainContent = "plain content";
+        final String bondary = "simple boundary";
+        final String endline = "\r\n";
+
+        MockHttpServletRequest req = new MockHttpServletRequest();
+        req.setCharacterEncoding(StandardCharsets.UTF_8.name());
+        req.setMethod("POST");
+        req.addHeader("Content-type", "multipart/form-data; boundary=" + bondary);
+        StringBuilder content = new StringBuilder(128);
+        content.append(encodeTextFile(bondary, endline, "file", "test.html", "text/plain", plainContent));
+        content.append(encodeTextFile(bondary, endline, "file", "test1.html", "text/html", htmlContent));
+        content.append(encodeTextFile(bondary, endline, "file", "test2.html", "text/html", htmlContent));
+        content.append(encodeTextFile(bondary, endline, "file", "test3.html", "text/html", htmlContent));
+        content.append(endline);
+        content.append("--");
+        content.append(bondary);
+        content.append("--");
+        content.append(endline);
+        req.setContent(content.toString().getBytes());
+
+        assertTrue(ServletFileUpload.isMultipartContent(req));
+
+        MyFileupAction action = new MyFileupAction();
+        container.inject(action);
+        MockActionInvocation mai = new MockActionInvocation();
+        mai.setAction(action);
+        mai.setResultCode("success");
+        mai.setInvocationContext(ActionContext.getContext());
+        Map<String, Object> param = new HashMap<>();
+        ActionContext.getContext().setParameters(HttpParameters.create(param).build());
+        ActionContext.getContext().put(ServletActionContext.HTTP_REQUEST, createMultipartRequest(req, 2000));
+
+        interceptor.setAllowedTypes("text/html");
+        interceptor.intercept(mai);
+
+        HttpParameters parameters = mai.getInvocationContext().getParameters();
+        assertEquals(0, parameters.keySet().size());
+        assertEquals(1, action.getActionErrors().size());
+        assertEquals("Request exceeded allowed number of files! Max allowed files number is: 3!", action.getActionErrors().iterator().next());
+    }
+
     public void testMultipartRequestLocalizedError() throws Exception {
         MockHttpServletRequest req = new MockHttpServletRequest();
         req.setCharacterEncoding(StandardCharsets.UTF_8.name());
@@ -432,6 +475,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
     private MultiPartRequestWrapper createMultipartRequest(HttpServletRequest req, int maxsize) throws IOException {
         JakartaMultiPartRequest jak = new JakartaMultiPartRequest();
         jak.setMaxSize(String.valueOf(maxsize));
+        jak.setMaxFiles("3");
         return new MultiPartRequestWrapper(jak, req, tempDir.getAbsolutePath(), new DefaultLocaleProvider());
     }
 
diff --git a/pom.xml b/pom.xml
index 3453bd034..7d8d61935 100644
--- a/pom.xml
+++ b/pom.xml
@@ -908,7 +908,7 @@
             <dependency>
                 <groupId>commons-fileupload</groupId>
                 <artifactId>commons-fileupload</artifactId>
-                <version>1.4</version>
+                <version>1.5</version>
             </dependency>
             <dependency>
                 <groupId>commons-io</groupId>


[struts] 02/02: WW-5285 Uses Long and null to check if option has been defined

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch release/6.1.x
in repository https://gitbox.apache.org/repos/asf/struts.git

commit c3deb392379a408f42fd52129f11422f847e3ffc
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Tue Feb 28 07:26:05 2023 +0100

    WW-5285 Uses Long and null to check if option has been defined
---
 .../multipart/AbstractMultiPartRequest.java        | 12 +++----
 .../multipart/JakartaMultiPartRequest.java         |  8 +++--
 .../multipart/JakartaStreamMultiPartRequest.java   | 37 +++++++++++-----------
 .../dispatcher/multipart/PellMultiPartRequest.java |  6 ++--
 4 files changed, 32 insertions(+), 31 deletions(-)

diff --git a/core/src/main/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequest.java b/core/src/main/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequest.java
index b3410e578..e46cecc00 100644
--- a/core/src/main/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequest.java
+++ b/core/src/main/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequest.java
@@ -51,14 +51,12 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
     /**
      * Specifies the maximum size of the entire request.
      */
-    protected long maxSize;
-    protected boolean maxSizeProvided;
+    protected Long maxSize;
 
     /**
      * Specifies the maximum number of files in one request.
      */
-    protected long maxFiles;
-    protected boolean maxFilesProvided;
+    protected Long maxFiles;
 
     /**
      * Specifies the buffer size to use during streaming.
@@ -90,13 +88,11 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
      */
     @Inject(StrutsConstants.STRUTS_MULTIPART_MAXSIZE)
     public void setMaxSize(String maxSize) {
-        this.maxSizeProvided = true;
         this.maxSize = Long.parseLong(maxSize);
     }
 
     @Inject(StrutsConstants.STRUTS_MULTIPART_MAXFILES)
     public void setMaxFiles(String maxFiles) {
-        this.maxFilesProvided = true;
         this.maxFiles = Long.parseLong(maxFiles);
     }
 
@@ -146,9 +142,9 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
         int forwardSlash = fileName.lastIndexOf('/');
         int backwardSlash = fileName.lastIndexOf('\\');
         if (forwardSlash != -1 && forwardSlash > backwardSlash) {
-            fileName = fileName.substring(forwardSlash + 1, fileName.length());
+            fileName = fileName.substring(forwardSlash + 1);
         } else {
-            fileName = fileName.substring(backwardSlash + 1, fileName.length());
+            fileName = fileName.substring(backwardSlash + 1);
         }
         return fileName;
     }
diff --git a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java
index c20b1de19..00d922401 100644
--- a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java
+++ b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java
@@ -160,8 +160,12 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
 
     protected ServletFileUpload createServletFileUpload(DiskFileItemFactory fac) {
         ServletFileUpload upload = new ServletFileUpload(fac);
-        upload.setSizeMax(maxSize);
-        upload.setFileCountMax(maxFiles);
+        if (maxSize != null) {
+            upload.setSizeMax(maxSize);
+        }
+        if (maxFiles != null) {
+            upload.setFileCountMax(maxFiles);
+        }
         return upload;
     }
 
diff --git a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java
index f709b3416..c7311ab0a 100644
--- a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java
+++ b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java
@@ -30,15 +30,15 @@ import org.apache.struts2.dispatcher.LocalizedMessage;
 
 import javax.servlet.http.HttpServletRequest;
 import java.io.*;
+import java.nio.file.Files;
 import java.util.*;
 
 /**
  * Multi-part form data request adapter for Jakarta Commons FileUpload package that
  * leverages the streaming API rather than the traditional non-streaming API.
- *
+ * <p>
  * For more details see WW-3025
  *
- * @author Chris Cranford
  * @since 2.3.18
  */
 public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
@@ -85,7 +85,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
             types.add(fileInfo.getContentType());
         }
 
-        return types.toArray(new String[types.size()]);
+        return types.toArray(new String[0]);
     }
 
     /* (non-Javadoc)
@@ -102,7 +102,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
             files.add(new StrutsUploadedFile(fileInfo.getFile()));
         }
 
-        return files.toArray(new UploadedFile[files.size()]);
+        return files.toArray(new UploadedFile[0]);
     }
 
     /* (non-Javadoc)
@@ -119,7 +119,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
             names.add(getCanonicalName(fileInfo.getOriginalName()));
         }
 
-        return names.toArray(new String[names.size()]);
+        return names.toArray(new String[0]);
     }
 
     /* (non-Javadoc)
@@ -143,7 +143,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
             names.add(fileInfo.getFile().getName());
         }
 
-        return names.toArray(new String[names.size()]);
+        return names.toArray(new String[0]);
     }
 
     /* (non-Javadoc)
@@ -170,7 +170,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
     public String[] getParameterValues(String name) {
         List<String> values = parameters.get(name);
         if (values != null && values.size() > 0) {
-            return values.toArray(new String[values.size()]);
+            return values.toArray(new String[0]);
         }
         return null;
     }
@@ -209,10 +209,10 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
             // Interface with Commons FileUpload API
             // Using the Streaming API
             ServletFileUpload servletFileUpload = new ServletFileUpload();
-            if (maxSizeProvided) {
+            if (maxSize != null) {
                 servletFileUpload.setSizeMax(maxSize);
             }
-            if (maxFilesProvided) {
+            if (maxFiles != null) {
                 servletFileUpload.setFileCountMax(maxFiles);
             }
             FileItemIterator i = servletFileUpload.getItemIterator(request);
@@ -261,7 +261,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
         // if maxSize is specified as -1, there is no sanity check and it's
         // safe to return true for any request, delegating the failure
         // checks later in the upload process.
-        if (maxSize == -1 || request == null) {
+        if ((maxSize != null && maxSize == -1) || request == null) {
             return true;
         }
 
@@ -289,8 +289,9 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
      */
     protected void addFileSkippedError(String fileName, HttpServletRequest request) {
         String exceptionMessage = "Skipped file " + fileName + "; request size limit exceeded.";
-        FileSizeLimitExceededException exception = new FileUploadBase.FileSizeLimitExceededException(exceptionMessage, getRequestSize(request), maxSize);
-        LocalizedMessage message = buildErrorMessage(exception, new Object[]{fileName, getRequestSize(request), maxSize});
+        long allowedMaxSize = maxSize != null ? maxSize : -1;
+        FileSizeLimitExceededException exception = new FileUploadBase.FileSizeLimitExceededException(exceptionMessage, getRequestSize(request), allowedMaxSize);
+        LocalizedMessage message = buildErrorMessage(exception, new Object[]{fileName, getRequestSize(request), allowedMaxSize});
         if (!errors.contains(message)) {
             errors.add(message);
         }
@@ -389,12 +390,12 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
      * @throws IOException in case of IO errors
      */
     protected boolean streamFileToDisk(FileItemStream itemStream, File file) throws IOException {
-        boolean result = false;
+        boolean result;
         try (InputStream input = itemStream.openStream();
-                OutputStream output = new BufferedOutputStream(new FileOutputStream(file), bufferSize)) {
+                OutputStream output = new BufferedOutputStream(Files.newOutputStream(file.toPath()), bufferSize)) {
             byte[] buffer = new byte[bufferSize];
             LOG.debug("Streaming file using buffer size {}.", bufferSize);
-            for (int length = 0; ((length = input.read(buffer)) > 0); ) {
+            for (int length; ((length = input.read(buffer)) > 0); ) {
                 output.write(buffer, 0, length);
             }
             result = true;
@@ -436,9 +437,9 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
 
         private static final long serialVersionUID = 1083158552766906037L;
 
-        private File file;
-        private String contentType;
-        private String originalName;
+        private final File file;
+        private final String contentType;
+        private final String originalName;
 
         /**
          * Default constructor.
diff --git a/plugins/pell-multipart/src/main/java/org/apache/struts2/dispatcher/multipart/PellMultiPartRequest.java b/plugins/pell-multipart/src/main/java/org/apache/struts2/dispatcher/multipart/PellMultiPartRequest.java
index aaf1f8b12..4eb931231 100644
--- a/plugins/pell-multipart/src/main/java/org/apache/struts2/dispatcher/multipart/PellMultiPartRequest.java
+++ b/plugins/pell-multipart/src/main/java/org/apache/struts2/dispatcher/multipart/PellMultiPartRequest.java
@@ -51,15 +51,15 @@ public class PellMultiPartRequest extends AbstractMultiPartRequest {
         //calling the constructor.  See javadoc for MultipartRequest.setEncoding().
         synchronized (this) {
             setEncoding();
-            if (maxSizeProvided){
-                int intMaxSize = (maxSize >= Integer.MAX_VALUE ? Integer.MAX_VALUE : Long.valueOf(maxSize).intValue());
+            if (maxSize != null && maxSize > -1){
+                int intMaxSize = (maxSize >= Integer.MAX_VALUE ? Integer.MAX_VALUE : maxSize.intValue());
             	multi = new ServletMultipartRequest(servletRequest, saveDir, intMaxSize);
             }else{
             	multi = new ServletMultipartRequest(servletRequest, saveDir);
             }
         }
     }
-    
+
     public Enumeration getFileParameterNames() {
         return multi.getFileParameterNames();
     }