[ 
https://issues.apache.org/jira/browse/WW-5273?focusedWorklogId=836091&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-836091
 ]

ASF GitHub Bot logged work on WW-5273:
--------------------------------------

                Author: ASF GitHub Bot
            Created on: 29/Dec/22 09:45
            Start Date: 29/Dec/22 09:45
    Worklog Time Spent: 10m 
      Work Description: github-code-scanning[bot] commented on code in PR #650:
URL: https://github.com/apache/struts/pull/650#discussion_r1058848403


##########
core/src/main/java/org/apache/struts2/dispatcher/multipart/ServletMultiPartRequest.java:
##########
@@ -0,0 +1,246 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.struts2.dispatcher.multipart;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.struts2.dispatcher.LocalizedMessage;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.Part;
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Pure Servlet API 3.1 based implementation
+ */
+public class ServletMultiPartRequest extends AbstractMultiPartRequest {
+
+    private static final Logger LOG = 
LogManager.getLogger(ServletMultiPartRequest.class);
+
+    private Map<String, List<FileData>> uploadedFiles = new HashMap<>();
+    private Map<String, List<String>> parameters = new HashMap<>();
+
+    @Override
+    public void parse(HttpServletRequest request, String saveDir) throws 
IOException {
+        try {
+            if (isSizeLimitExceeded(request)) {
+                applySizeLimitExceededError(request);
+                return;
+            }
+            parseParts(request, saveDir);
+        } catch (ServletException e) {
+            LOG.warn("Error occurred during parsing of multi part request", e);
+            LocalizedMessage errorMessage = buildErrorMessage(e, new 
Object[]{e.getMessage()});
+            if (!errors.contains(errorMessage)) {
+                errors.add(errorMessage);
+            }
+        }
+    }
+
+    private void parseParts(HttpServletRequest request, String saveDir) throws 
IOException, ServletException {
+        Collection<Part> parts = request.getParts();
+        if (parts.isEmpty()) {
+            LocalizedMessage error = buildErrorMessage(new IOException(), new 
Object[]{"No boundary defined!"});
+            if (!errors.contains(error)) {
+                errors.add(error);
+            }
+            return;
+        }
+        for (Part part : parts) {
+            if (part.getSubmittedFileName() == null) { // normal field
+                LOG.debug("Ignoring a normal form field: {}", part.getName());
+            } else { // file upload
+                LOG.debug("Storing file: {} in save dir: {}", 
part.getSubmittedFileName(), saveDir);

Review Comment:
   ## Logging should not be vulnerable to injection attacks
   
   <!--SONAR_ISSUE_KEY:AYVdRXPwlHcyP0Z-M9IE-->Change this code to not log 
user-controlled data. <p>See more on <a 
href="https://sonarcloud.io/project/issues?id=apache_struts&issues=AYVdRXPwlHcyP0Z-M9IE&open=AYVdRXPwlHcyP0Z-M9IE&pullRequest=650";>SonarCloud</a></p>
   
   [Show more 
details](https://github.com/apache/struts/security/code-scanning/205)



##########
core/src/main/java/org/apache/struts2/dispatcher/multipart/ServletMultiPartRequest.java:
##########
@@ -0,0 +1,246 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.struts2.dispatcher.multipart;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.struts2.dispatcher.LocalizedMessage;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.Part;
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Pure Servlet API 3.1 based implementation
+ */
+public class ServletMultiPartRequest extends AbstractMultiPartRequest {
+
+    private static final Logger LOG = 
LogManager.getLogger(ServletMultiPartRequest.class);
+
+    private Map<String, List<FileData>> uploadedFiles = new HashMap<>();
+    private Map<String, List<String>> parameters = new HashMap<>();
+
+    @Override
+    public void parse(HttpServletRequest request, String saveDir) throws 
IOException {
+        try {
+            if (isSizeLimitExceeded(request)) {
+                applySizeLimitExceededError(request);
+                return;
+            }
+            parseParts(request, saveDir);
+        } catch (ServletException e) {
+            LOG.warn("Error occurred during parsing of multi part request", e);
+            LocalizedMessage errorMessage = buildErrorMessage(e, new 
Object[]{e.getMessage()});
+            if (!errors.contains(errorMessage)) {
+                errors.add(errorMessage);
+            }
+        }
+    }
+
+    private void parseParts(HttpServletRequest request, String saveDir) throws 
IOException, ServletException {
+        Collection<Part> parts = request.getParts();
+        if (parts.isEmpty()) {
+            LocalizedMessage error = buildErrorMessage(new IOException(), new 
Object[]{"No boundary defined!"});
+            if (!errors.contains(error)) {
+                errors.add(error);
+            }
+            return;
+        }
+        for (Part part : parts) {
+            if (part.getSubmittedFileName() == null) { // normal field
+                LOG.debug("Ignoring a normal form field: {}", part.getName());
+            } else { // file upload
+                LOG.debug("Storing file: {} in save dir: {}", 
part.getSubmittedFileName(), saveDir);
+                parseFile(part, saveDir);
+            }
+        }
+    }
+
+    private boolean isSizeLimitExceeded(HttpServletRequest request) {
+        if (request.getContentLength() > -1) {
+            return maxSizeProvided && request.getContentLength() > maxSize;
+        } else {
+            LOG.debug("Request Content Length is: {} which means the size 
overflows 2 GB!", request.getContentLength());
+            return true;
+        }
+    }
+
+    private void applySizeLimitExceededError(HttpServletRequest request) {
+        String exceptionMessage = "Request size: " + 
request.getContentLength() + " exceeded maximum size limit: " + maxSize;
+        SizeLimitExceededException exception = new 
SizeLimitExceededException(exceptionMessage);
+        LocalizedMessage message = buildErrorMessage(exception, new 
Object[]{request.getContentLength(), maxSize});
+        if (!errors.contains(message)) {
+            errors.add(message);
+        }
+    }
+
+    private void parseFile(Part part, String saveDir) throws IOException {
+        File file = extractFile(part, saveDir);
+        List<FileData> data = uploadedFiles.get(part.getName());
+        if (data == null) {
+            data = new ArrayList<>();
+        }
+        data.add(new FileData(file, part.getContentType(), 
part.getSubmittedFileName()));
+        uploadedFiles.put(part.getName(), data);
+    }
+
+    private File extractFile(Part part, String saveDir) throws IOException {
+        String name = part.getSubmittedFileName()
+            .substring(part.getSubmittedFileName().lastIndexOf('/') + 1)
+            .substring(part.getSubmittedFileName().lastIndexOf('\\') + 1);
+
+        String prefix = name;
+        String suffix = "";
+
+        if (name.contains(".")) {
+            prefix = name.substring(0, name.lastIndexOf('.'));
+            suffix = name.substring(name.lastIndexOf('.'));
+        }
+
+        if (prefix.length() < 3) {
+            prefix = UUID.randomUUID().toString();
+        }
+
+        File tempFile = File.createTempFile(prefix + "_", suffix, new 
File(saveDir));
+        LOG.debug("Stored file: {} as temporary file: {}", 
part.getSubmittedFileName(), tempFile.getName());

Review Comment:
   ## Logging should not be vulnerable to injection attacks
   
   <!--SONAR_ISSUE_KEY:AYVdRXPwlHcyP0Z-M9ID-->Change this code to not log 
user-controlled data. <p>See more on <a 
href="https://sonarcloud.io/project/issues?id=apache_struts&issues=AYVdRXPwlHcyP0Z-M9ID&open=AYVdRXPwlHcyP0Z-M9ID&pullRequest=650";>SonarCloud</a></p>
   
   [Show more 
details](https://github.com/apache/struts/security/code-scanning/206)





Issue Time Tracking
-------------------

    Worklog Id:     (was: 836091)
    Time Spent: 0.5h  (was: 20m)

> Support fileupload using native Servlet API 3.1 logic
> -----------------------------------------------------
>
>                 Key: WW-5273
>                 URL: https://issues.apache.org/jira/browse/WW-5273
>             Project: Struts 2
>          Issue Type: Improvement
>          Components: Core
>            Reporter: Lukasz Lenart
>            Priority: Major
>             Fix For: 6.2.0
>
>          Time Spent: 0.5h
>  Remaining Estimate: 0h
>
> Since Servlet API 3.1 there is no need in using Commons Fileupload as the 
> servlets support it.
> https://stackoverflow.com/questions/68820707/jetty-11-and-commons-fileupload



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to