[
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)