acceptedFiles = new ArrayList<>();
+
+ while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {
+ // get the value of this input tag
+ String inputName = fileParameterNames.nextElement();
+ UploadedFile[] uploadedFiles = multiWrapper.getFiles(inputName);
+
+ if (uploadedFiles == null || uploadedFiles.length == 0) {
+ if (LOG.isWarnEnabled()) {
+ LOG.warn(getTextMessage(action, STRUTS_MESSAGES_INVALID_FILE_KEY, new String[]{inputName}));
+ }
+ } else {
+ for (UploadedFile uploadedFile : uploadedFiles) {
+ if (acceptFile(action, uploadedFile, uploadedFile.getOriginalName(), uploadedFile.getContentType(), inputName)) {
+ acceptedFiles.add(uploadedFile);
+ }
+ }
+ }
+ }
+
+ if (acceptedFiles.isEmpty()) {
+ LOG.debug("No files have been uploaded/accepted");
+ } else {
+ LOG.debug("Passing: {} uploaded file(s) to action", acceptedFiles.size());
+ action.withUploadedFiles(acceptedFiles);
+ }
+
+ // invoke action
+ return invocation.invoke();
+ }
+
+}
+
diff --git a/core/src/main/java/org/apache/struts2/interceptor/FileUploadInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/FileUploadInterceptor.java
index bb77ea093..86f8a64be 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/FileUploadInterceptor.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/FileUploadInterceptor.java
@@ -18,23 +18,22 @@
*/
package org.apache.struts2.interceptor;
-import com.opensymphony.xwork2.*;
-import com.opensymphony.xwork2.inject.Container;
-import com.opensymphony.xwork2.inject.Inject;
-import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.interceptor.ValidationAware;
-import com.opensymphony.xwork2.util.TextParseUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import org.apache.struts2.dispatcher.LocalizedMessage;
import org.apache.struts2.dispatcher.Parameter;
import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
import org.apache.struts2.dispatcher.multipart.UploadedFile;
-import org.apache.struts2.util.ContentTypeMatcher;
import javax.servlet.http.HttpServletRequest;
-import java.text.NumberFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
/**
*
@@ -77,11 +76,11 @@ import java.util.*;
* file extensions specified
*
*
- *
+ *
*
*
*
Interceptor parameters:
- *
+ *
*
*
*
@@ -96,14 +95,14 @@ import java.util.*;
* - allowedExtensions (optional) - a comma separated list of file extensions (ie: .html) that the interceptor will allow
* a file reference to be set on the action. If none is specified allow all extensions to be uploaded.
*
- *
- *
+ *
+ *
*
*
*
Extending the interceptor:
- *
- *
- *
+ *
+ *
+ *
*
*
* You can extend this interceptor and override the acceptFile method to provide more control over which files
@@ -122,7 +121,7 @@ import java.util.*;
* </action>
*
*
- *
+ *
*
*
* You must set the encoding to multipart/form-data in the form where the user selects the file to upload.
@@ -173,57 +172,16 @@ import java.util.*;
* }
*
*
+ *
+ * @deprecated since Struts 6.4.0, use {@link ActionFileUploadInterceptor} instead
*/
-public class FileUploadInterceptor extends AbstractInterceptor {
+@Deprecated
+public class FileUploadInterceptor extends AbstractFileUploadInterceptor {
private static final long serialVersionUID = -4764627478894962478L;
protected static final Logger LOG = LogManager.getLogger(FileUploadInterceptor.class);
- protected Long maximumSize;
- protected Set allowedTypesSet = Collections.emptySet();
- protected Set allowedExtensionsSet = Collections.emptySet();
-
- private ContentTypeMatcher matcher;
- private Container container;
-
- @Inject
- public void setMatcher(ContentTypeMatcher matcher) {
- this.matcher = matcher;
- }
-
- @Inject
- public void setContainer(Container container) {
- this.container = container;
- }
-
- /**
- * Sets the allowed extensions
- *
- * @param allowedExtensions A comma-delimited list of extensions
- */
- public void setAllowedExtensions(String allowedExtensions) {
- allowedExtensionsSet = TextParseUtil.commaDelimitedStringToSet(allowedExtensions);
- }
-
- /**
- * Sets the allowed mimetypes
- *
- * @param allowedTypes A comma-delimited list of types
- */
- public void setAllowedTypes(String allowedTypes) {
- allowedTypesSet = TextParseUtil.commaDelimitedStringToSet(allowedTypes);
- }
-
- /**
- * Sets the maximum size of an uploaded file
- *
- * @param maximumSize The maximum size in bytes
- */
- public void setMaximumSize(Long maximumSize) {
- this.maximumSize = maximumSize;
- }
-
/* (non-Javadoc)
* @see com.opensymphony.xwork2.interceptor.Interceptor#intercept(com.opensymphony.xwork2.ActionInvocation)
*/
@@ -236,40 +194,22 @@ public class FileUploadInterceptor extends AbstractInterceptor {
if (!(request instanceof MultiPartRequestWrapper)) {
if (LOG.isDebugEnabled()) {
ActionProxy proxy = invocation.getProxy();
- LOG.debug(getTextMessage("struts.messages.bypass.request", new String[]{proxy.getNamespace(), proxy.getActionName()}));
+ LOG.debug(getTextMessage(STRUTS_MESSAGES_BYPASS_REQUEST_KEY, new String[]{proxy.getNamespace(), proxy.getActionName()}));
}
return invocation.invoke();
}
- ValidationAware validation = null;
-
Object action = invocation.getAction();
-
- if (action instanceof ValidationAware) {
- validation = (ValidationAware) action;
- }
-
MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) request;
- if (multiWrapper.hasErrors() && validation != null) {
- TextProvider textProvider = getTextProvider(action);
- for (LocalizedMessage error : multiWrapper.getErrors()) {
- String errorMessage;
- if (textProvider.hasKey(error.getTextKey())) {
- errorMessage = textProvider.getText(error.getTextKey(), Arrays.asList(error.getArgs()));
- } else {
- errorMessage = textProvider.getText("struts.messages.error.uploading", error.getDefaultMessage());
- }
- validation.addActionError(errorMessage);
- }
- }
+ applyValidation(action, multiWrapper);
// bind allowed Files
- Enumeration fileParameterNames = multiWrapper.getFileParameterNames();
+ Enumeration fileParameterNames = multiWrapper.getFileParameterNames();
while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {
// get the value of this input tag
- String inputName = (String) fileParameterNames.nextElement();
+ String inputName = fileParameterNames.nextElement();
// get the content type
String[] contentType = multiWrapper.getContentTypes(inputName);
@@ -289,7 +229,7 @@ public class FileUploadInterceptor extends AbstractInterceptor {
String fileNameName = inputName + "FileName";
for (int index = 0; index < files.length; index++) {
- if (acceptFile(action, files[index], fileName[index], contentType[index], inputName, validation)) {
+ if (acceptFile(action, files[index], fileName[index], contentType[index], inputName)) {
acceptedFiles.add(files[index]);
acceptedContentTypes.add(contentType[index]);
acceptedFileNames.add(fileName[index]);
@@ -298,20 +238,20 @@ public class FileUploadInterceptor extends AbstractInterceptor {
if (!acceptedFiles.isEmpty()) {
Map newParams = new HashMap<>();
- newParams.put(inputName, new Parameter.File(inputName, acceptedFiles.toArray(new UploadedFile[acceptedFiles.size()])));
- newParams.put(contentTypeName, new Parameter.File(contentTypeName, acceptedContentTypes.toArray(new String[acceptedContentTypes.size()])));
- newParams.put(fileNameName, new Parameter.File(fileNameName, acceptedFileNames.toArray(new String[acceptedFileNames.size()])));
+ newParams.put(inputName, new Parameter.File(inputName, acceptedFiles.toArray(new UploadedFile[0])));
+ newParams.put(contentTypeName, new Parameter.File(contentTypeName, acceptedContentTypes.toArray(new String[0])));
+ newParams.put(fileNameName, new Parameter.File(fileNameName, acceptedFileNames.toArray(new String[0])));
ac.getParameters().appendAll(newParams);
}
}
} else {
if (LOG.isWarnEnabled()) {
- LOG.warn(getTextMessage(action, "struts.messages.invalid.file", new String[]{inputName}));
+ LOG.warn(getTextMessage(action, STRUTS_MESSAGES_INVALID_FILE_KEY, new String[]{inputName}));
}
}
} else {
if (LOG.isWarnEnabled()) {
- LOG.warn(getTextMessage(action, "struts.messages.invalid.content.type", new String[]{inputName}));
+ LOG.warn(getTextMessage(action, STRUTS_MESSAGES_INVALID_CONTENT_TYPE_KEY, new String[]{inputName}));
}
}
}
@@ -320,149 +260,4 @@ public class FileUploadInterceptor extends AbstractInterceptor {
return invocation.invoke();
}
- /**
- * Override for added functionality. Checks if the proposed file is acceptable based on contentType and size.
- *
- * @param action - uploading action for message retrieval.
- * @param file - proposed upload file.
- * @param filename - name of the file.
- * @param contentType - contentType of the file.
- * @param inputName - inputName of the file.
- * @param validation - Non-null ValidationAware if the action implements ValidationAware, allowing for better
- * logging.
- * @return true if the proposed file is acceptable by contentType and size.
- */
- protected boolean acceptFile(Object action, UploadedFile file, String filename, String contentType, String inputName, ValidationAware validation) {
- boolean fileIsAcceptable = false;
-
- // If it's null the upload failed
- if (file == null) {
- String errMsg = getTextMessage(action, "struts.messages.error.uploading", new String[]{inputName});
- if (validation != null) {
- validation.addFieldError(inputName, errMsg);
- }
-
- if (LOG.isWarnEnabled()) {
- LOG.warn(errMsg);
- }
- } else if (file.getContent() == null) {
- String errMsg = getTextMessage(action, "struts.messages.error.uploading", new String[]{filename});
- if (validation != null) {
- validation.addFieldError(inputName, errMsg);
- }
- if (LOG.isWarnEnabled()) {
- LOG.warn(errMsg);
- }
- } else if (maximumSize != null && maximumSize < file.length()) {
- String errMsg = getTextMessage(action, "struts.messages.error.file.too.large", new String[]{inputName, filename, file.getName(), "" + file.length(), getMaximumSizeStr(action)});
- if (validation != null) {
- validation.addFieldError(inputName, errMsg);
- }
-
- if (LOG.isWarnEnabled()) {
- LOG.warn(errMsg);
- }
- } else if ((!allowedTypesSet.isEmpty()) && (!containsItem(allowedTypesSet, contentType))) {
- String errMsg = getTextMessage(action, "struts.messages.error.content.type.not.allowed", new String[]{inputName, filename, file.getName(), contentType});
- if (validation != null) {
- validation.addFieldError(inputName, errMsg);
- }
-
- if (LOG.isWarnEnabled()) {
- LOG.warn(errMsg);
- }
- } else if ((!allowedExtensionsSet.isEmpty()) && (!hasAllowedExtension(allowedExtensionsSet, filename))) {
- String errMsg = getTextMessage(action, "struts.messages.error.file.extension.not.allowed", new String[]{inputName, filename, file.getName(), contentType});
- if (validation != null) {
- validation.addFieldError(inputName, errMsg);
- }
-
- if (LOG.isWarnEnabled()) {
- LOG.warn(errMsg);
- }
- } else {
- fileIsAcceptable = true;
- }
-
- return fileIsAcceptable;
- }
-
- private String getMaximumSizeStr(Object action) {
- return NumberFormat.getNumberInstance(getLocaleProvider(action).getLocale()).format(maximumSize);
- }
-
- /**
- * @param extensionCollection - Collection of extensions (all lowercase).
- * @param filename - filename to check.
- * @return true if the filename has an allowed extension, false otherwise.
- */
- private boolean hasAllowedExtension(Collection extensionCollection, String filename) {
- if (filename == null) {
- return false;
- }
-
- String lowercaseFilename = filename.toLowerCase();
- for (String extension : extensionCollection) {
- if (lowercaseFilename.endsWith(extension)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * @param itemCollection - Collection of string items (all lowercase).
- * @param item - Item to search for.
- * @return true if itemCollection contains the item, false otherwise.
- */
- private boolean containsItem(Collection itemCollection, String item) {
- for (String pattern : itemCollection)
- if (matchesWildcard(pattern, item))
- return true;
- return false;
- }
-
- private boolean matchesWildcard(String pattern, String text) {
- Object o = matcher.compilePattern(pattern);
- return matcher.match(new HashMap(), text, o);
- }
-
- private boolean isNonEmpty(Object[] objArray) {
- boolean result = false;
- for (int index = 0; index < objArray.length && !result; index++) {
- if (objArray[index] != null) {
- result = true;
- }
- }
- return result;
- }
-
- protected String getTextMessage(String messageKey, String[] args) {
- return getTextMessage(this, messageKey, args);
- }
-
- protected String getTextMessage(Object action, String messageKey, String[] args) {
- if (action instanceof TextProvider) {
- return ((TextProvider) action).getText(messageKey, args);
- }
- return getTextProvider(action).getText(messageKey, args);
- }
-
- private TextProvider getTextProvider(Object action) {
- TextProviderFactory tpf = container.getInstance(TextProviderFactory.class);
- return tpf.createInstance(action.getClass());
- }
-
- private LocaleProvider getLocaleProvider(Object action) {
- LocaleProvider localeProvider;
- if (action instanceof LocaleProvider) {
- localeProvider = (LocaleProvider) action;
- } else {
- LocaleProviderFactory localeProviderFactory = container.getInstance(LocaleProviderFactory.class);
- localeProvider = localeProviderFactory.createLocaleProvider();
- }
- return localeProvider;
- }
-
}
diff --git a/core/src/main/resources/org/apache/struts2/struts-messages_en.properties b/core/src/main/resources/org/apache/struts2/struts-messages_en.properties
index 155e13c39..d70fe0119 100644
--- a/core/src/main/resources/org/apache/struts2/struts-messages_en.properties
+++ b/core/src/main/resources/org/apache/struts2/struts-messages_en.properties
@@ -25,15 +25,40 @@ struts.internal.invalid.token=Form token {0} does not match the session token {1
struts.messages.bypass.request=Bypassing {0}/{1}
struts.messages.current.file=File {0} {1} {2} {3}
+# 0 - input name
struts.messages.invalid.file=Could not find a Filename for {0}. Verify that a valid file was submitted.
+# 0 - original filename
struts.messages.invalid.content.type=Could not find a Content-Type for {0}. Verify that a valid file was submitted.
struts.messages.removing.file=Removing file {0} {1}
struts.messages.error.uploading=Error uploading: {0}
-struts.messages.error.file.too.large=The file is too large to be uploaded: {0} "{1}" "{2}" {3}
+# 0 - input name
+# 1 - original filename
+# 2 - file name after uploading the file
+# 3 - size of the uploaded files
+# 4 - maximum allowed size
+struts.messages.error.file.too.large=The file is too large to be uploaded: {0} "{1}" "{2}" has size {3} and allowed mx size is {4}
+# 0 - input name
+# 1 - original filename
+# 2 - file name after uploading the file
+# 3 - content type of the file
struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3}
+# 0 - input name
+# 1 - original filename
+# 2 - file name after uploading the file
+# 3 - content type of the file
struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}
# dedicated messages used to handle various problems with file upload - check {@link JakartaMultiPartRequest#parse(HttpServletRequest, String)}
+# params depend on exception being handled
+# FileUploadBase.SizeLimitExceededException:
+# 0 - permitted size
+# 1 - actual size
+# FileUploadBase.FileSizeLimitExceededException
+# 0 - file name
+# 1 - permitted size
+# 2 - actual size
+# FileCountLimitExceededException
+# 0 - limit
struts.messages.upload.error.SizeLimitExceededException=Request exceeded allowed size limit! Max size allowed is: {0} but request was: {1}!
struts.messages.upload.error.IOException=Error uploading: {0}!
diff --git a/core/src/main/resources/struts-default.xml b/core/src/main/resources/struts-default.xml
index 0fdcc2b37..326477bc4 100644
--- a/core/src/main/resources/struts-default.xml
+++ b/core/src/main/resources/struts-default.xml
@@ -58,6 +58,7 @@
+
@@ -121,6 +122,12 @@
+
+
+
+
+
+
@@ -165,6 +172,7 @@
+
@@ -203,6 +211,7 @@
+
diff --git a/core/src/test/java/org/apache/struts2/conversion/UploadedFileConverterTest.java b/core/src/test/java/org/apache/struts2/conversion/UploadedFileConverterTest.java
index b88d2b36b..3832a514f 100644
--- a/core/src/test/java/org/apache/struts2/conversion/UploadedFileConverterTest.java
+++ b/core/src/test/java/org/apache/struts2/conversion/UploadedFileConverterTest.java
@@ -34,10 +34,12 @@ import static org.assertj.core.api.Assertions.assertThat;
public class UploadedFileConverterTest {
private Map context;
- private Class target;
+ private Class> target;
private Member member;
private String propertyName;
private File tempFile;
+ private String contentType;
+ private String originalName;
@Before
public void setUp() throws Exception {
@@ -46,6 +48,8 @@ public class UploadedFileConverterTest {
member = File.class.getMethod("length");
propertyName = "ignore";
tempFile = File.createTempFile("struts", "test");
+ contentType = "text/plain";
+ originalName = tempFile.getName();
}
@After
@@ -54,10 +58,10 @@ public class UploadedFileConverterTest {
}
@Test
- public void convertUploadedFileToFile() throws Exception {
+ public void convertUploadedFileToFile() {
// given
UploadedFileConverter ufc = new UploadedFileConverter();
- UploadedFile uploadedFile = new StrutsUploadedFile(tempFile);
+ UploadedFile uploadedFile = StrutsUploadedFile.Builder.create(tempFile).withContentType(this.contentType).withOriginalName(this.originalName).build();
// when
Object result = ufc.convertValue(context, target, member, propertyName, uploadedFile, File.class);
@@ -70,10 +74,15 @@ public class UploadedFileConverterTest {
}
@Test
- public void convertUploadedFileArrayToFile() throws Exception {
+ public void convertUploadedFileArrayToFile() {
// given
UploadedFileConverter ufc = new UploadedFileConverter();
- UploadedFile[] uploadedFile = new UploadedFile[] { new StrutsUploadedFile(tempFile) };
+ UploadedFile[] uploadedFile = new UploadedFile[]{
+ StrutsUploadedFile.Builder.create(tempFile)
+ .withContentType(this.contentType)
+ .withOriginalName(this.originalName)
+ .build()
+ };
// when
Object result = ufc.convertValue(context, target, member, propertyName, uploadedFile, File.class);
diff --git a/core/src/test/java/org/apache/struts2/interceptor/ActionFileUploadInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/ActionFileUploadInterceptorTest.java
new file mode 100644
index 000000000..51747b147
--- /dev/null
+++ b/core/src/test/java/org/apache/struts2/interceptor/ActionFileUploadInterceptorTest.java
@@ -0,0 +1,591 @@
+/*
+ * 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.interceptor;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionSupport;
+import com.opensymphony.xwork2.DefaultLocaleProvider;
+import com.opensymphony.xwork2.ValidationAwareSupport;
+import com.opensymphony.xwork2.mock.MockActionInvocation;
+import com.opensymphony.xwork2.mock.MockActionProxy;
+import com.opensymphony.xwork2.util.ClassLoaderUtil;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.struts2.ServletActionContext;
+import org.apache.struts2.StrutsInternalTestCase;
+import org.apache.struts2.action.UploadedFilesAware;
+import org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest;
+import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
+import org.apache.struts2.dispatcher.multipart.StrutsUploadedFile;
+import org.apache.struts2.dispatcher.multipart.UploadedFile;
+import org.springframework.mock.web.MockHttpServletRequest;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.net.URI;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Test case for {@link ActionFileUploadInterceptor}.
+ */
+public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
+
+ public static final UploadedFile EMPTY_FILE = new UploadedFile() {
+ @Override
+ public Long length() {
+ return 0L;
+ }
+
+ @Override
+ public String getName() {
+ return "";
+ }
+
+ @Override
+ public boolean isFile() {
+ return false;
+ }
+
+ @Override
+ public boolean delete() {
+ return false;
+ }
+
+ @Override
+ public String getAbsolutePath() {
+ return null;
+ }
+
+ @Override
+ public byte[] getContent() {
+ return new byte[0];
+ }
+
+ @Override
+ public String getOriginalName() {
+ return null;
+ }
+
+ @Override
+ public String getContentType() {
+ return null;
+ }
+ };
+
+ private ActionFileUploadInterceptor interceptor;
+ private File tempDir;
+
+ private final String htmlContent = "html content";
+ private final String plainContent = "plain content";
+ private final String boundary = "simple boundary";
+ private final String endline = "\r\n";
+
+ public void testAcceptFileWithEmptyAllowedTypesAndExtensions() {
+ // when allowed type is empty
+ ValidationAwareSupport validation = new ValidationAwareSupport();
+ boolean ok = interceptor.acceptFile(validation, EMPTY_FILE, "filename", "text/plain", "inputName");
+
+ assertTrue(ok);
+ assertTrue(validation.getFieldErrors().isEmpty());
+ assertFalse(validation.hasErrors());
+ }
+
+ public void testAcceptFileWithoutEmptyTypes() {
+ interceptor.setAllowedTypes("text/plain");
+
+ // when file is of allowed types
+ ValidationAwareSupport validation = new ValidationAwareSupport();
+ boolean ok = interceptor.acceptFile(validation, EMPTY_FILE, "filename.txt", "text/plain", "inputName");
+
+ assertTrue(ok);
+ assertTrue(validation.getFieldErrors().isEmpty());
+ assertFalse(validation.hasErrors());
+
+ // when file is not of allowed types
+ validation = new ValidationAwareSupport();
+ boolean notOk = interceptor.acceptFile(validation, EMPTY_FILE, "filename.html", "text/html", "inputName");
+
+ assertFalse(notOk);
+ assertFalse(validation.getFieldErrors().isEmpty());
+ assertTrue(validation.hasErrors());
+ }
+
+
+ public void testAcceptFileWithWildcardContent() {
+ interceptor.setAllowedTypes("text/*");
+
+ ValidationAwareSupport validation = new ValidationAwareSupport();
+ boolean ok = interceptor.acceptFile(validation, EMPTY_FILE, "filename.txt", "text/plain", "inputName");
+
+ assertTrue(ok);
+ assertTrue(validation.getFieldErrors().isEmpty());
+ assertFalse(validation.hasErrors());
+
+ interceptor.setAllowedTypes("text/h*");
+ validation = new ValidationAwareSupport();
+ boolean notOk = interceptor.acceptFile(validation, EMPTY_FILE, "filename.html", "text/plain", "inputName");
+
+ assertFalse(notOk);
+ assertFalse(validation.getFieldErrors().isEmpty());
+ assertTrue(validation.hasErrors());
+ }
+
+ public void testAcceptFileWithoutEmptyExtensions() {
+ interceptor.setAllowedExtensions(".txt");
+
+ // when file is of allowed extensions
+ ValidationAwareSupport validation = new ValidationAwareSupport();
+ boolean ok = interceptor.acceptFile(validation, EMPTY_FILE, "filename.txt", "text/plain", "inputName");
+
+ assertTrue(ok);
+ assertTrue(validation.getFieldErrors().isEmpty());
+ assertFalse(validation.hasErrors());
+
+ // when file is not of allowed extensions
+ validation = new ValidationAwareSupport();
+ boolean notOk = interceptor.acceptFile(validation, EMPTY_FILE, "filename.html", "text/html", "inputName");
+
+ assertFalse(notOk);
+ assertFalse(validation.getFieldErrors().isEmpty());
+ assertTrue(validation.hasErrors());
+
+ //test with multiple extensions
+ interceptor.setAllowedExtensions(".txt,.lol");
+ validation = new ValidationAwareSupport();
+ ok = interceptor.acceptFile(validation, EMPTY_FILE, "filename.lol", "text/plain", "inputName");
+
+ assertTrue(ok);
+ assertTrue(validation.getFieldErrors().isEmpty());
+ assertFalse(validation.hasErrors());
+ }
+
+ public void testAcceptFileWithNoFile() {
+ ActionFileUploadInterceptor interceptor = new ActionFileUploadInterceptor();
+ interceptor.setContainer(container);
+
+ interceptor.setAllowedTypes("text/plain");
+
+ // when file is not of allowed types
+ ValidationAwareSupport validation = new ValidationAwareSupport();
+ boolean notOk = interceptor.acceptFile(validation, null, "filename.html", "text/html", "inputName");
+
+ assertFalse(notOk);
+ assertFalse(validation.getFieldErrors().isEmpty());
+ assertTrue(validation.hasErrors());
+ List errors = validation.getFieldErrors().get("inputName");
+ assertEquals(1, errors.size());
+ String msg = errors.get(0);
+ assertTrue(msg.startsWith("Error uploading:"));
+ assertTrue(msg.indexOf("inputName") > 0);
+ }
+
+ public void testAcceptFileWithMaxSize() throws Exception {
+ interceptor.setMaximumSize(10L);
+
+ // when file is not of allowed types
+ ValidationAwareSupport validation = new ValidationAwareSupport();
+
+ URL url = ClassLoaderUtil.getResource("log4j2.xml", ActionFileUploadInterceptorTest.class);
+ File file = new File(new URI(url.toString()));
+ assertTrue("log4j2.xml should be in src/test folder", file.exists());
+ UploadedFile uploadedFile = StrutsUploadedFile.Builder.create(file).withContentType("text/html").withOriginalName("filename").build();
+ boolean notOk = interceptor.acceptFile(validation, uploadedFile, "filename", "text/html", "inputName");
+
+ assertFalse(notOk);
+ assertFalse(validation.getFieldErrors().isEmpty());
+ assertTrue(validation.hasErrors());
+ List errors = validation.getFieldErrors().get("inputName");
+ assertEquals(1, errors.size());
+ String msg = errors.get(0);
+ // the error message should contain at least this test
+ assertThat(msg).contains(
+ "The file is too large to be uploaded",
+ "inputName",
+ "log4j2.xml",
+ "allowed mx size is 10"
+ );
+ }
+
+ public void testNoMultipartRequest() throws Exception {
+ MyFileUploadAction action = new MyFileUploadAction();
+
+ MockActionInvocation mai = new MockActionInvocation();
+ mai.setAction(action);
+ mai.setResultCode("NoMultipart");
+ MockActionProxy proxy = new MockActionProxy();
+ proxy.setNamespace("/test");
+ proxy.setActionName("myFileUpload");
+ mai.setProxy(proxy);
+ mai.setInvocationContext(ActionContext.getContext());
+
+ // if no multipart request it will bypass and execute it
+ assertEquals("NoMultipart", interceptor.intercept(mai));
+ }
+
+ public void testInvalidContentTypeMultipartRequest() throws Exception {
+ MockHttpServletRequest req = new MockHttpServletRequest();
+
+ req.setContentType("multipart/form-data"); // not a multipart contentype
+ req.setMethod("post");
+
+ MyFileUploadAction action = container.inject(MyFileUploadAction.class);
+ MockActionInvocation mai = new MockActionInvocation();
+ mai.setAction(action);
+ mai.setResultCode("success");
+ mai.setInvocationContext(ActionContext.getContext());
+
+ ActionContext.getContext().put(ServletActionContext.HTTP_REQUEST, createMultipartRequestMaxSize(req, 2000));
+
+ interceptor.intercept(mai);
+
+ assertTrue(action.hasErrors());
+ }
+
+ public void testNoContentMultipartRequest() throws Exception {
+ MockHttpServletRequest req = new MockHttpServletRequest();
+
+ req.setCharacterEncoding(StandardCharsets.UTF_8.name());
+ req.setMethod("post");
+ req.addHeader("Content-type", "multipart/form-data");
+ req.setContent(null); // there is no content
+
+ MyFileUploadAction action = container.inject(MyFileUploadAction.class);
+ MockActionInvocation mai = new MockActionInvocation();
+ mai.setAction(action);
+ mai.setResultCode("success");
+ mai.setInvocationContext(ActionContext.getContext());
+
+ ActionContext.getContext().put(ServletActionContext.HTTP_REQUEST, createMultipartRequestMaxSize(req, 2000));
+
+ interceptor.intercept(mai);
+
+ assertTrue(action.hasErrors());
+ }
+
+ public void testSuccessUploadOfATextFileMultipartRequest() throws Exception {
+ MockHttpServletRequest req = new MockHttpServletRequest();
+ req.setCharacterEncoding(StandardCharsets.UTF_8.name());
+ req.setMethod("post");
+ req.addHeader("Content-type", "multipart/form-data; boundary=---1234");
+
+ // inspired by the unit tests for jakarta commons fileupload
+ String content = ("-----1234\r\n" +
+ "Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" +
+ "Content-Type: text/html\r\n" +
+ "\r\n" +
+ "Unit test of ActionFileUploadInterceptor" +
+ "\r\n" +
+ "-----1234--\r\n");
+ req.setContent(content.getBytes(StandardCharsets.US_ASCII));
+
+ MyFileUploadAction action = new MyFileUploadAction();
+
+ MockActionInvocation mai = new MockActionInvocation();
+ mai.setAction(action);
+ mai.setResultCode("success");
+ mai.setInvocationContext(ActionContext.getContext());
+ ActionContext.getContext().put(ServletActionContext.HTTP_REQUEST, createMultipartRequestMaxSize(req, 2000));
+
+ interceptor.intercept(mai);
+
+ assertFalse(action.hasErrors());
+
+ List files = action.getUploadFiles();
+
+ assertNotNull(files);
+ assertEquals(1, files.size());
+ assertEquals("text/html", files.get(0).getContentType());
+ assertNotNull("deleteme.txt", files.get(0).getOriginalName());
+ }
+
+ /**
+ * tests whether with multiple files sent with the same name, the ones with forbiddenTypes (see
+ * ActionFileUploadInterceptor.setAllowedTypes(...) ) are sorted out.
+ */
+ public void testMultipleAccept() throws Exception {
+ MockHttpServletRequest req = new MockHttpServletRequest();
+ req.setCharacterEncoding(StandardCharsets.UTF_8.name());
+ req.setMethod("POST");
+ req.addHeader("Content-type", "multipart/form-data; boundary=" + boundary);
+ String content = encodeTextFile("test.html", "text/plain", plainContent) +
+ encodeTextFile("test1.html", "text/html", htmlContent) +
+ encodeTextFile("test2.html", "text/html", htmlContent) +
+ endline +
+ endline +
+ endline +
+ "--" +
+ boundary +
+ "--" +
+ endline;
+ req.setContent(content.getBytes());
+
+ assertTrue(ServletFileUpload.isMultipartContent(req));
+
+ MyFileUploadAction action = new MyFileUploadAction();
+ container.inject(action);
+ MockActionInvocation mai = new MockActionInvocation();
+ mai.setAction(action);
+ mai.setResultCode("success");
+ mai.setInvocationContext(ActionContext.getContext());
+ ActionContext.getContext().put(ServletActionContext.HTTP_REQUEST, createMultipartRequestMaxSize(req, 2000));
+
+ interceptor.setAllowedTypes("text/html");
+ interceptor.intercept(mai);
+
+ List files = action.getUploadFiles();
+
+ assertNotNull(files);
+ assertEquals("files accepted ", 2, files.size());
+ assertEquals("text/html", files.get(0).getContentType());
+ assertNotNull("test1.html", files.get(0).getOriginalName());
+ }
+
+ public void testUnacceptedNumberOfFiles() throws Exception {
+ MockHttpServletRequest req = new MockHttpServletRequest();
+ req.setCharacterEncoding(StandardCharsets.UTF_8.name());
+ req.setMethod("POST");
+ req.addHeader("Content-type", "multipart/form-data; boundary=" + boundary);
+ String content = encodeTextFile("test.html", "text/plain", plainContent) +
+ encodeTextFile("test1.html", "text/html", htmlContent) +
+ encodeTextFile("test2.html", "text/html", htmlContent) +
+ encodeTextFile("test3.html", "text/html", htmlContent) +
+ endline +
+ "--" +
+ boundary +
+ "--" +
+ endline;
+ req.setContent(content.getBytes());
+
+ assertTrue(ServletFileUpload.isMultipartContent(req));
+
+ MyFileUploadAction action = new MyFileUploadAction();
+ container.inject(action);
+ MockActionInvocation mai = new MockActionInvocation();
+ mai.setAction(action);
+ mai.setResultCode("success");
+ mai.setInvocationContext(ActionContext.getContext());
+ ActionContext.getContext().withServletRequest(createMultipartRequestMaxFiles(req));
+
+ interceptor.setAllowedTypes("text/html");
+ interceptor.intercept(mai);
+
+ assertNull(action.getUploadFiles());
+ assertEquals(1, action.getActionErrors().size());
+ assertEquals("Request exceeded allowed number of files! Max allowed files number is: 3!", action.getActionErrors().iterator().next());
+ }
+
+ public void testMultipartRequestMaxFileSize() throws Exception {
+ MockHttpServletRequest req = new MockHttpServletRequest();
+ req.setCharacterEncoding(StandardCharsets.UTF_8.name());
+ req.setMethod("post");
+ req.addHeader("Content-type", "multipart/form-data; boundary=---1234");
+
+ // inspired by the unit tests for jakarta commons fileupload
+ String content = ("-----1234\r\n" +
+ "Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" +
+ "Content-Type: text/html\r\n" +
+ "\r\n" +
+ "Unit test of ActionFileUploadInterceptor" +
+ "\r\n" +
+ "-----1234--\r\n");
+ req.setContent(content.getBytes(StandardCharsets.US_ASCII));
+
+ MyFileUploadAction action = container.inject(MyFileUploadAction.class);
+
+ MockActionInvocation mai = new MockActionInvocation();
+ mai.setAction(action);
+ mai.setResultCode("success");
+ mai.setInvocationContext(ActionContext.getContext());
+ ActionContext.getContext()
+ .withServletRequest(createMultipartRequestMaxFileSize(req));
+
+ interceptor.intercept(mai);
+
+ assertTrue(action.hasActionErrors());
+
+ Collection errors = action.getActionErrors();
+ assertEquals(1, errors.size());
+ String msg = errors.iterator().next();
+ assertEquals(
+ "File in request exceeded allowed file size limit! Max file size allowed is: 10 but file deleteme.txt was: 40!",
+ msg);
+ }
+
+ public void testMultipartRequestMaxStringLength() throws Exception {
+ MockHttpServletRequest req = new MockHttpServletRequest();
+ req.setCharacterEncoding(StandardCharsets.UTF_8.name());
+ req.setMethod("post");
+ req.addHeader("Content-type", "multipart/form-data; boundary=---1234");
+
+ // inspired by the unit tests for jakarta commons fileupload
+ String content = ("-----1234\r\n" +
+ "Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" +
+ "Content-Type: text/html\r\n" +
+ "\r\n" +
+ "Unit test of ActionFileUploadInterceptor" +
+ "\r\n" +
+ "-----1234\r\n" +
+ "Content-Disposition: form-data; name=\"normalFormField1\"\r\n" +
+ "\r\n" +
+ "it works" +
+ "\r\n" +
+ "-----1234\r\n" +
+ "Content-Disposition: form-data; name=\"normalFormField2\"\r\n" +
+ "\r\n" +
+ "long string should not work" +
+ "\r\n" +
+ "-----1234--\r\n");
+ req.setContent(content.getBytes(StandardCharsets.US_ASCII));
+
+ MyFileUploadAction action = container.inject(MyFileUploadAction.class);
+
+ MockActionInvocation mai = new MockActionInvocation();
+ mai.setAction(action);
+ mai.setResultCode("success");
+ mai.setInvocationContext(ActionContext.getContext());
+ ActionContext.getContext()
+ .withServletRequest(createMultipartRequestMaxStringLength(req));
+
+ interceptor.intercept(mai);
+
+ assertTrue(action.hasActionErrors());
+
+ Collection errors = action.getActionErrors();
+ assertEquals(1, errors.size());
+ String msg = errors.iterator().next();
+ assertEquals(
+ "The request parameter \"normalFormField2\" was too long. Max length allowed is 20, but found 27!",
+ msg);
+ }
+
+ public void testMultipartRequestLocalizedError() throws Exception {
+ MockHttpServletRequest req = new MockHttpServletRequest();
+ req.setCharacterEncoding(StandardCharsets.UTF_8.name());
+ req.setMethod("post");
+ req.addHeader("Content-type", "multipart/form-data; boundary=---1234");
+
+ // inspired by the unit tests for jakarta commons fileupload
+ String content = ("-----1234\r\n" +
+ "Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" +
+ "Content-Type: text/html\r\n" +
+ "\r\n" +
+ "Unit test of ActionFileUploadInterceptor" +
+ "\r\n" +
+ "-----1234--\r\n");
+ req.setContent(content.getBytes(StandardCharsets.US_ASCII));
+
+ MyFileUploadAction action = container.inject(MyFileUploadAction.class);
+
+ MockActionInvocation mai = new MockActionInvocation();
+ mai.setAction(action);
+ mai.setResultCode("success");
+ mai.setInvocationContext(ActionContext.getContext());
+ ActionContext.getContext()
+ .withLocale(Locale.GERMAN)
+ .withServletRequest(createMultipartRequestMaxSize(req, 10));
+
+ interceptor.intercept(mai);
+
+ assertTrue(action.hasActionErrors());
+
+ Collection errors = action.getActionErrors();
+ assertEquals(1, errors.size());
+ String msg = errors.iterator().next();
+ // the error message should contain at least this test
+ assertTrue(msg.startsWith("Der Request übertraf die maximal erlaubte Größe"));
+ }
+
+ private String encodeTextFile(String filename, String contentType, String content) {
+ return "\r\n" +
+ "--" +
+ "simple boundary" +
+ "\r\n" +
+ "Content-Disposition: form-data; name=\"" +
+ "file" +
+ "\"; filename=\"" +
+ filename +
+ "\r\n" +
+ "Content-Type: " +
+ contentType +
+ "\r\n" +
+ "\r\n" +
+ content;
+ }
+
+ private MultiPartRequestWrapper createMultipartRequestMaxFileSize(HttpServletRequest req) {
+ return createMultipartRequest(req, -1, 10, -1, -1);
+ }
+
+ private MultiPartRequestWrapper createMultipartRequestMaxFiles(HttpServletRequest req) {
+ return createMultipartRequest(req, -1, -1, 3, -1);
+ }
+
+ private MultiPartRequestWrapper createMultipartRequestMaxSize(HttpServletRequest req, int maxsize) {
+ return createMultipartRequest(req, maxsize, -1, -1, -1);
+ }
+
+ private MultiPartRequestWrapper createMultipartRequestMaxStringLength(HttpServletRequest req) {
+ return createMultipartRequest(req, -1, -1, -1, 20);
+ }
+
+ private MultiPartRequestWrapper createMultipartRequest(HttpServletRequest req, int maxsize, int maxfilesize, int maxfiles, int maxStringLength) {
+
+ JakartaMultiPartRequest jak = new JakartaMultiPartRequest();
+ jak.setMaxSize(String.valueOf(maxsize));
+ jak.setMaxFileSize(String.valueOf(maxfilesize));
+ jak.setMaxFiles(String.valueOf(maxfiles));
+ jak.setMaxStringLength(String.valueOf(maxStringLength));
+ return new MultiPartRequestWrapper(jak, req, tempDir.getAbsolutePath(), new DefaultLocaleProvider());
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ interceptor = new ActionFileUploadInterceptor();
+ container.inject(interceptor);
+ tempDir = File.createTempFile("struts", "fileupload");
+ tempDir.delete();
+ tempDir.mkdirs();
+ }
+
+ protected void tearDown() throws Exception {
+ tempDir.delete();
+ interceptor.destroy();
+ super.tearDown();
+ }
+
+ public static class MyFileUploadAction extends ActionSupport implements UploadedFilesAware {
+ private List uploadedFiles;
+
+ @Override
+ public void withUploadedFiles(List uploadedFiles) {
+ this.uploadedFiles = uploadedFiles;
+ }
+
+ public List getUploadFiles() {
+ return this.uploadedFiles;
+ }
+ }
+
+}
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 b9bab88d4..14bb23c36 100644
--- a/core/src/test/java/org/apache/struts2/interceptor/FileUploadInterceptorTest.java
+++ b/core/src/test/java/org/apache/struts2/interceptor/FileUploadInterceptorTest.java
@@ -47,6 +47,8 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
+import static org.assertj.core.api.Assertions.assertThat;
+
/**
* Test case for FileUploadInterceptor.
@@ -83,28 +85,37 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
public byte[] getContent() {
return new byte[0];
}
+
+ @Override
+ public String getOriginalName() {
+ return null;
+ }
+
+ @Override
+ public String getContentType() {
+ return null;
+ }
};
private FileUploadInterceptor interceptor;
private File tempDir;
- private TestAction action;
- public void testAcceptFileWithEmptyAllowedTypesAndExtensions() throws Exception {
+ public void testAcceptFileWithEmptyAllowedTypesAndExtensions() {
// when allowed type is empty
ValidationAwareSupport validation = new ValidationAwareSupport();
- boolean ok = interceptor.acceptFile(action, EMPTY_FILE, "filename", "text/plain", "inputName", validation);
+ boolean ok = interceptor.acceptFile(validation, EMPTY_FILE, "filename", "text/plain", "inputName");
assertTrue(ok);
assertTrue(validation.getFieldErrors().isEmpty());
assertFalse(validation.hasErrors());
}
- public void testAcceptFileWithoutEmptyTypes() throws Exception {
+ public void testAcceptFileWithoutEmptyTypes() {
interceptor.setAllowedTypes("text/plain");
// when file is of allowed types
ValidationAwareSupport validation = new ValidationAwareSupport();
- boolean ok = interceptor.acceptFile(action, EMPTY_FILE, "filename.txt", "text/plain", "inputName", validation);
+ boolean ok = interceptor.acceptFile(validation, EMPTY_FILE, "filename.txt", "text/plain", "inputName");
assertTrue(ok);
assertTrue(validation.getFieldErrors().isEmpty());
@@ -112,7 +123,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
// when file is not of allowed types
validation = new ValidationAwareSupport();
- boolean notOk = interceptor.acceptFile(action, EMPTY_FILE, "filename.html", "text/html", "inputName", validation);
+ boolean notOk = interceptor.acceptFile(validation, EMPTY_FILE, "filename.html", "text/html", "inputName");
assertFalse(notOk);
assertFalse(validation.getFieldErrors().isEmpty());
@@ -120,11 +131,11 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
}
- public void testAcceptFileWithWildcardContent() throws Exception {
+ public void testAcceptFileWithWildcardContent() {
interceptor.setAllowedTypes("text/*");
ValidationAwareSupport validation = new ValidationAwareSupport();
- boolean ok = interceptor.acceptFile(action, EMPTY_FILE, "filename.txt", "text/plain", "inputName", validation);
+ boolean ok = interceptor.acceptFile(validation, EMPTY_FILE, "filename.txt", "text/plain", "inputName");
assertTrue(ok);
assertTrue(validation.getFieldErrors().isEmpty());
@@ -132,19 +143,19 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
interceptor.setAllowedTypes("text/h*");
validation = new ValidationAwareSupport();
- boolean notOk = interceptor.acceptFile(action, EMPTY_FILE, "filename.html", "text/plain", "inputName", validation);
+ boolean notOk = interceptor.acceptFile(validation, EMPTY_FILE, "filename.html", "text/plain", "inputName");
assertFalse(notOk);
assertFalse(validation.getFieldErrors().isEmpty());
assertTrue(validation.hasErrors());
}
- public void testAcceptFileWithoutEmptyExtensions() throws Exception {
+ public void testAcceptFileWithoutEmptyExtensions() {
interceptor.setAllowedExtensions(".txt");
// when file is of allowed extensions
ValidationAwareSupport validation = new ValidationAwareSupport();
- boolean ok = interceptor.acceptFile(action, EMPTY_FILE, "filename.txt", "text/plain", "inputName", validation);
+ boolean ok = interceptor.acceptFile(validation, EMPTY_FILE, "filename.txt", "text/plain", "inputName");
assertTrue(ok);
assertTrue(validation.getFieldErrors().isEmpty());
@@ -152,7 +163,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
// when file is not of allowed extensions
validation = new ValidationAwareSupport();
- boolean notOk = interceptor.acceptFile(action, EMPTY_FILE, "filename.html", "text/html", "inputName", validation);
+ boolean notOk = interceptor.acceptFile(validation, EMPTY_FILE, "filename.html", "text/html", "inputName");
assertFalse(notOk);
assertFalse(validation.getFieldErrors().isEmpty());
@@ -161,34 +172,35 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
//test with multiple extensions
interceptor.setAllowedExtensions(".txt,.lol");
validation = new ValidationAwareSupport();
- ok = interceptor.acceptFile(action, EMPTY_FILE, "filename.lol", "text/plain", "inputName", validation);
+ ok = interceptor.acceptFile(validation, EMPTY_FILE, "filename.lol", "text/plain", "inputName");
assertTrue(ok);
assertTrue(validation.getFieldErrors().isEmpty());
assertFalse(validation.hasErrors());
}
- public void testAcceptFileWithNoFile() throws Exception {
+ public void testAcceptFileWithNoFile() {
FileUploadInterceptor interceptor = new FileUploadInterceptor();
+ interceptor.setContainer(container);
+
interceptor.setAllowedTypes("text/plain");
// when file is not of allowed types
ValidationAwareSupport validation = new ValidationAwareSupport();
- boolean notOk = interceptor.acceptFile(action, null, "filename.html", "text/html", "inputName", validation);
+ boolean notOk = interceptor.acceptFile(validation, null, "filename.html", "text/html", "inputName");
assertFalse(notOk);
assertFalse(validation.getFieldErrors().isEmpty());
assertTrue(validation.hasErrors());
- List errors = (List) validation.getFieldErrors().get("inputName");
+ List errors = validation.getFieldErrors().get("inputName");
assertEquals(1, errors.size());
- String msg = (String) errors.get(0);
+ String msg = errors.get(0);
assertTrue(msg.startsWith("Error uploading:"));
assertTrue(msg.indexOf("inputName") > 0);
}
public void testAcceptFileWithMaxSize() throws Exception {
- interceptor.setAllowedTypes("text/plain");
- interceptor.setMaximumSize(new Long(10));
+ interceptor.setMaximumSize(10L);
// when file is not of allowed types
ValidationAwareSupport validation = new ValidationAwareSupport();
@@ -196,18 +208,22 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
URL url = ClassLoaderUtil.getResource("log4j2.xml", FileUploadInterceptorTest.class);
File file = new File(new URI(url.toString()));
assertTrue("log4j2.xml should be in src/test folder", file.exists());
- boolean notOk = interceptor.acceptFile(action, new StrutsUploadedFile(file), "filename", "text/html", "inputName", validation);
+ UploadedFile uploadedFile = StrutsUploadedFile.Builder.create(file).withContentType("text/html").withOriginalName("filename").build();
+ boolean notOk = interceptor.acceptFile(validation, uploadedFile, "filename", "text/html", "inputName");
assertFalse(notOk);
assertFalse(validation.getFieldErrors().isEmpty());
assertTrue(validation.hasErrors());
List errors = validation.getFieldErrors().get("inputName");
assertEquals(1, errors.size());
- String msg = (String) errors.get(0);
+ String msg = errors.get(0);
// the error message should contain at least this test
- assertTrue(msg.startsWith("The file is too large to be uploaded"));
- assertTrue(msg.indexOf("inputName") > 0);
- assertTrue(msg.indexOf("log4j2.xml") > 0);
+ assertThat(msg).contains(
+ "The file is too large to be uploaded",
+ "inputName",
+ "log4j2.xml",
+ "allowed mx size is 10"
+ );
}
public void testNoMultipartRequest() throws Exception {
@@ -278,7 +294,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
"Unit test of FileUploadInterceptor" +
"\r\n" +
"-----1234--\r\n");
- req.setContent(content.getBytes("US-ASCII"));
+ req.setContent(content.getBytes(StandardCharsets.US_ASCII));
MyFileupAction action = new MyFileupAction();
@@ -292,10 +308,10 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
interceptor.intercept(mai);
- assertTrue(!action.hasErrors());
+ assertFalse(action.hasErrors());
HttpParameters parameters = mai.getInvocationContext().getParameters();
- assertTrue(parameters.keySet().size() == 3);
+ assertEquals(3, parameters.keySet().size());
UploadedFile[] files = (UploadedFile[]) parameters.get("file").getObject();
String[] fileContentTypes = parameters.get("fileContentType").getMultipleValues();
String[] fileRealFilenames = parameters.get("fileFileName").getMultipleValues();
@@ -303,9 +319,9 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
assertNotNull(files);
assertNotNull(fileContentTypes);
assertNotNull(fileRealFilenames);
- assertTrue(files.length == 1);
- assertTrue(fileContentTypes.length == 1);
- assertTrue(fileRealFilenames.length == 1);
+ assertEquals(1, files.length);
+ assertEquals(1, fileContentTypes.length);
+ assertEquals(1, fileRealFilenames.length);
assertEquals("text/html", fileContentTypes[0]);
assertNotNull("deleteme.txt", fileRealFilenames[0]);
}
@@ -313,8 +329,6 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
/**
* tests whether with multiple files sent with the same name, the ones with forbiddenTypes (see
* FileUploadInterceptor.setAllowedTypes(...) ) are sorted out.
- *
- * @throws Exception
*/
public void testMultipleAccept() throws Exception {
final String htmlContent = "html content";
@@ -326,18 +340,17 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
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(endline);
- content.append(endline);
- content.append(endline);
- content.append("--");
- content.append(bondary);
- content.append("--");
- content.append(endline);
- req.setContent(content.toString().getBytes());
+ String content = encodeTextFile("test.html", "text/plain", plainContent) +
+ encodeTextFile("test1.html", "text/html", htmlContent) +
+ encodeTextFile("test2.html", "text/html", htmlContent) +
+ endline +
+ endline +
+ endline +
+ "--" +
+ bondary +
+ "--" +
+ endline;
+ req.setContent(content.getBytes());
assertTrue(ServletFileUpload.isMultipartContent(req));
@@ -347,7 +360,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
mai.setAction(action);
mai.setResultCode("success");
mai.setInvocationContext(ActionContext.getContext());
- Map param = new HashMap();
+ Map param = new HashMap<>();
ActionContext.getContext().withParameters(HttpParameters.create(param).build());
ActionContext.getContext().put(ServletActionContext.HTTP_REQUEST, createMultipartRequestMaxSize(req, 2000));
@@ -380,17 +393,16 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
req.setCharacterEncoding(StandardCharsets.UTF_8.name());
req.setMethod("POST");
req.addHeader("Content-type", "multipart/form-data; boundary=" + boundary);
- StringBuilder content = new StringBuilder(128);
- content.append(encodeTextFile(boundary, endline, "file", "test.html", "text/plain", plainContent));
- content.append(encodeTextFile(boundary, endline, "file", "test1.html", "text/html", htmlContent));
- content.append(encodeTextFile(boundary, endline, "file", "test2.html", "text/html", htmlContent));
- content.append(encodeTextFile(boundary, endline, "file", "test3.html", "text/html", htmlContent));
- content.append(endline);
- content.append("--");
- content.append(boundary);
- content.append("--");
- content.append(endline);
- req.setContent(content.toString().getBytes());
+ String content = encodeTextFile("test.html", "text/plain", plainContent) +
+ encodeTextFile("test1.html", "text/html", htmlContent) +
+ encodeTextFile("test2.html", "text/html", htmlContent) +
+ encodeTextFile("test3.html", "text/html", htmlContent) +
+ endline +
+ "--" +
+ boundary +
+ "--" +
+ endline;
+ req.setContent(content.getBytes());
assertTrue(ServletFileUpload.isMultipartContent(req));
@@ -402,7 +414,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
mai.setInvocationContext(ActionContext.getContext());
Map param = new HashMap<>();
ActionContext.getContext().withParameters(HttpParameters.create(param).build());
- ActionContext.getContext().put(ServletActionContext.HTTP_REQUEST, createMultipartRequestMaxFiles(req, 3));
+ ActionContext.getContext().put(ServletActionContext.HTTP_REQUEST, createMultipartRequestMaxFiles(req));
interceptor.setAllowedTypes("text/html");
interceptor.intercept(mai);
@@ -438,7 +450,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
Map param = new HashMap<>();
ActionContext.getContext()
.withParameters(HttpParameters.create(param).build())
- .withServletRequest(createMultipartRequestMaxFileSize(req, 10));
+ .withServletRequest(createMultipartRequestMaxFileSize(req));
interceptor.intercept(mai);
@@ -487,7 +499,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
Map param = new HashMap<>();
ActionContext.getContext()
.withParameters(HttpParameters.create(param).build())
- .withServletRequest(createMultipartRequestMaxStringLength(req, 20));
+ .withServletRequest(createMultipartRequestMaxStringLength(req));
interceptor.intercept(mai);
@@ -540,44 +552,40 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
assertTrue(msg.startsWith("Der Request übertraf die maximal erlaubte Größe"));
}
- private String encodeTextFile(String bondary, String endline, String name, String filename, String contentType, String content) {
- final StringBuilder sb = new StringBuilder(64);
- sb.append(endline);
- sb.append("--");
- sb.append(bondary);
- sb.append(endline);
- sb.append("Content-Disposition: form-data; name=\"");
- sb.append(name);
- sb.append("\"; filename=\"");
- sb.append(filename);
- sb.append(endline);
- sb.append("Content-Type: ");
- sb.append(contentType);
- sb.append(endline);
- sb.append(endline);
- sb.append(content);
-
- return sb.toString();
+ private String encodeTextFile(String filename, String contentType, String content) {
+ return "\r\n" +
+ "--" +
+ "simple boundary" +
+ "\r\n" +
+ "Content-Disposition: form-data; name=\"" +
+ "file" +
+ "\"; filename=\"" +
+ filename +
+ "\r\n" +
+ "Content-Type: " +
+ contentType +
+ "\r\n" +
+ "\r\n" +
+ content;
}
- private MultiPartRequestWrapper createMultipartRequestMaxFileSize(HttpServletRequest req, int maxfilesize) throws IOException {
- return createMultipartRequest(req, -1, maxfilesize, -1, -1);
+ private MultiPartRequestWrapper createMultipartRequestMaxFileSize(HttpServletRequest req) {
+ return createMultipartRequest(req, -1, 10, -1, -1);
}
- private MultiPartRequestWrapper createMultipartRequestMaxFiles(HttpServletRequest req, int maxfiles) throws IOException {
- return createMultipartRequest(req, -1, -1, maxfiles, -1);
+ private MultiPartRequestWrapper createMultipartRequestMaxFiles(HttpServletRequest req) {
+ return createMultipartRequest(req, -1, -1, 3, -1);
}
- private MultiPartRequestWrapper createMultipartRequestMaxSize(HttpServletRequest req, int maxsize) throws IOException {
+ private MultiPartRequestWrapper createMultipartRequestMaxSize(HttpServletRequest req, int maxsize) {
return createMultipartRequest(req, maxsize, -1, -1, -1);
}
- private MultiPartRequestWrapper createMultipartRequestMaxStringLength(HttpServletRequest req, int maxStringLength) throws IOException {
- return createMultipartRequest(req, -1, -1, -1, maxStringLength);
+ private MultiPartRequestWrapper createMultipartRequestMaxStringLength(HttpServletRequest req) {
+ return createMultipartRequest(req, -1, -1, -1, 20);
}
- private MultiPartRequestWrapper createMultipartRequest(HttpServletRequest req, int maxsize, int maxfilesize,
- int maxfiles, int maxStringLength) throws IOException {
+ private MultiPartRequestWrapper createMultipartRequest(HttpServletRequest req, int maxsize, int maxfilesize, int maxfiles, int maxStringLength) {
JakartaMultiPartRequest jak = new JakartaMultiPartRequest();
jak.setMaxSize(String.valueOf(maxsize));
@@ -589,8 +597,6 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
protected void setUp() throws Exception {
super.setUp();
- action = new TestAction();
- container.inject(action);
interceptor = new FileUploadInterceptor();
container.inject(interceptor);
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 9688be65e..d2db975d4 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
@@ -31,7 +31,6 @@ import java.util.List;
/**
* Multipart form data request adapter for Jason Pell's multipart utils package.
- *
*/
public class PellMultiPartRequest extends AbstractMultiPartRequest {
@@ -69,7 +68,11 @@ public class PellMultiPartRequest extends AbstractMultiPartRequest {
}
public UploadedFile[] getFile(String fieldName) {
- return new UploadedFile[]{ new StrutsUploadedFile(multi.getFile(fieldName)) };
+ return new UploadedFile[]{StrutsUploadedFile.Builder.create(multi.getFile(fieldName))
+ .withContentType(multi.getContentType(fieldName))
+ .withOriginalName(multi.getFileSystemName(fieldName))
+ .build()
+ };
}
public String[] getFileNames(String fieldName) {
@@ -132,7 +135,7 @@ public class PellMultiPartRequest extends AbstractMultiPartRequest {
}
} catch (IllegalArgumentException e) {
if (LOG.isInfoEnabled()) {
- LOG.info("Could not get encoding property 'struts.i18n.encoding' for file upload. Using system default");
+ LOG.info("Could not get encoding property 'struts.i18n.encoding' for file upload. Using system default");
}
} catch (UnsupportedEncodingException e) {
LOG.error("Encoding " + encoding + " is not a valid encoding. Please check your struts.properties file.");
@@ -140,8 +143,8 @@ public class PellMultiPartRequest extends AbstractMultiPartRequest {
}
/* (non-Javadoc)
- * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#cleanUp()
- */
+ * @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#cleanUp()
+ */
public void cleanUp() {
Enumeration fileParameterNames = multi.getFileParameterNames();
while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {