|
18 | 18 | */
|
19 | 19 | package org.apache.struts2.dispatcher.multipart;
|
20 | 20 |
|
21 |
| -import jakarta.servlet.http.HttpServletRequest; |
22 | 21 | import org.apache.commons.fileupload2.core.FileUploadByteCountLimitException;
|
23 | 22 | import org.apache.commons.fileupload2.core.FileUploadContentTypeException;
|
24 | 23 | import org.apache.commons.fileupload2.core.FileUploadException;
|
25 | 24 | import org.apache.commons.fileupload2.core.FileUploadFileCountLimitException;
|
26 | 25 | import org.apache.commons.fileupload2.core.FileUploadSizeException;
|
27 | 26 | import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletDiskFileUpload;
|
28 |
| -import org.apache.commons.lang3.BooleanUtils; |
| 27 | +import org.apache.commons.io.FilenameUtils; |
29 | 28 | import org.apache.commons.lang3.StringUtils;
|
30 | 29 | import org.apache.logging.log4j.LogManager;
|
31 | 30 | import org.apache.logging.log4j.Logger;
|
|
35 | 34 | import org.apache.struts2.security.DefaultExcludedPatternsChecker;
|
36 | 35 | import org.apache.struts2.security.ExcludedPatternsChecker;
|
37 | 36 |
|
| 37 | +import jakarta.servlet.http.HttpServletRequest; |
38 | 38 | import java.io.IOException;
|
39 | 39 | import java.nio.charset.Charset;
|
40 | 40 | import java.nio.file.Path;
|
|
45 | 45 | import java.util.List;
|
46 | 46 | import java.util.Map;
|
47 | 47 |
|
| 48 | +import static org.apache.commons.lang3.StringUtils.normalizeSpace; |
| 49 | + |
48 | 50 | /**
|
49 | 51 | * Abstract class with some helper methods, it should be used
|
50 | 52 | * when starting development of another implementation of {@link MultiPartRequest}
|
51 | 53 | */
|
52 | 54 | public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
53 | 55 |
|
54 | 56 | protected static final String STRUTS_MESSAGES_UPLOAD_ERROR_PARAMETER_TOO_LONG_KEY = "struts.messages.upload.error.parameter.too.long";
|
| 57 | + protected static final String STRUTS_MESSAGES_UPLOAD_ERROR_ILLEGAL_CHARACTERS_FIELD = "struts.messages.upload.error.illegal.characters.field"; |
| 58 | + protected static final String STRUTS_MESSAGES_UPLOAD_ERROR_ILLEGAL_CHARACTERS_NAME = "struts.messages.upload.error.illegal.characters.name"; |
55 | 59 |
|
56 | 60 | private static final Logger LOG = LogManager.getLogger(AbstractMultiPartRequest.class);
|
57 | 61 |
|
@@ -116,13 +120,14 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
116 | 120 |
|
117 | 121 | private final ExcludedPatternsChecker patternsChecker;
|
118 | 122 |
|
119 |
| - protected AbstractMultiPartRequest(String dmiValue) { |
120 |
| - patternsChecker = new DefaultExcludedPatternsChecker(); |
121 |
| - if (BooleanUtils.toBoolean(dmiValue)) { |
122 |
| - ((DefaultExcludedPatternsChecker) patternsChecker).setAdditionalExcludePatterns(EXCLUDED_FILE_PATTERN_WITH_DMI_SUPPORT); |
123 |
| - } else { |
124 |
| - ((DefaultExcludedPatternsChecker) patternsChecker).setAdditionalExcludePatterns(EXCLUDED_FILE_PATTERN); |
125 |
| - } |
| 123 | + protected AbstractMultiPartRequest() { |
| 124 | + this(false); |
| 125 | + } |
| 126 | + |
| 127 | + protected AbstractMultiPartRequest(boolean dmiValue) { |
| 128 | + var patternsChecker = new DefaultExcludedPatternsChecker(); |
| 129 | + patternsChecker.setAdditionalExcludePatterns(dmiValue ? EXCLUDED_FILE_PATTERN_WITH_DMI_SUPPORT : EXCLUDED_FILE_PATTERN); |
| 130 | + this.patternsChecker = patternsChecker; |
126 | 131 | }
|
127 | 132 |
|
128 | 133 | /**
|
@@ -302,16 +307,7 @@ protected LocalizedMessage buildErrorMessage(Class<? extends Throwable> exceptio
|
302 | 307 | * @return the canonical name based on the supplied filename
|
303 | 308 | */
|
304 | 309 | protected String getCanonicalName(final String originalFileName) {
|
305 |
| - String fileName = originalFileName; |
306 |
| - |
307 |
| - int forwardSlash = fileName.lastIndexOf('/'); |
308 |
| - int backwardSlash = fileName.lastIndexOf('\\'); |
309 |
| - if (forwardSlash != -1 && forwardSlash > backwardSlash) { |
310 |
| - fileName = fileName.substring(forwardSlash + 1); |
311 |
| - } else { |
312 |
| - fileName = fileName.substring(backwardSlash + 1); |
313 |
| - } |
314 |
| - return fileName; |
| 310 | + return FilenameUtils.getName(originalFileName); |
315 | 311 | }
|
316 | 312 |
|
317 | 313 | /**
|
@@ -443,4 +439,32 @@ protected boolean isExcluded(String fileName) {
|
443 | 439 | return patternsChecker.isExcluded(fileName).isExcluded();
|
444 | 440 | }
|
445 | 441 |
|
| 442 | + protected boolean isInvalidInput(String fieldName, String fileName) { |
| 443 | + // Skip file uploads that don't have a file name - meaning that no file was selected. |
| 444 | + if (fileName == null || fileName.isBlank()) { |
| 445 | + LOG.debug(() -> "No file has been uploaded for the field: " + normalizeSpace(fieldName)); |
| 446 | + return true; |
| 447 | + } |
| 448 | + |
| 449 | + if (isExcluded(fileName)) { |
| 450 | + var normalizedFileName = normalizeSpace(fileName); |
| 451 | + LOG.debug("File name [{}] is not accepted", normalizedFileName); |
| 452 | + errors.add(new LocalizedMessage(getClass(), STRUTS_MESSAGES_UPLOAD_ERROR_ILLEGAL_CHARACTERS_NAME, null, |
| 453 | + new String[]{normalizedFileName})); |
| 454 | + return true; |
| 455 | + } |
| 456 | + |
| 457 | + return isInvalidInput(fieldName); |
| 458 | + } |
| 459 | + |
| 460 | + protected boolean isInvalidInput(String fieldName) { |
| 461 | + if (isExcluded(fieldName)) { |
| 462 | + var normalizedFieldName = normalizeSpace(fieldName); |
| 463 | + LOG.debug("Form field [{}}] is rejected!", normalizedFieldName); |
| 464 | + errors.add(new LocalizedMessage(getClass(), STRUTS_MESSAGES_UPLOAD_ERROR_ILLEGAL_CHARACTERS_FIELD, null, |
| 465 | + new String[]{normalizedFieldName})); |
| 466 | + return true; |
| 467 | + } |
| 468 | + return false; |
| 469 | + } |
446 | 470 | }
|
0 commit comments