mirror of
https://github.com/apache/struts.git
synced 2026-08-07 15:46:57 +00:00
WW-5386 Delete deprecated FileUploadInterceptor
This commit is contained in:
@@ -1,273 +0,0 @@
|
||||
/*
|
||||
* 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.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ActionProxy;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.action.UploadedFilesAware;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
|
||||
import org.apache.struts2.dispatcher.multipart.UploadedFile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
* <p>
|
||||
* Interceptor that is based off of {@link MultiPartRequestWrapper}, which is automatically applied for any request that
|
||||
* includes a file. It adds the following parameters, where [File Name] is the name given to the file uploaded by the
|
||||
* HTML form:
|
||||
* </p>
|
||||
* <ul>
|
||||
*
|
||||
* <li>[File Name] : File - the actual File</li>
|
||||
*
|
||||
* <li>[File Name]ContentType : String - the content type of the file</li>
|
||||
*
|
||||
* <li>[File Name]FileName : String - the actual name of the file uploaded (not the HTML name)</li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p>You can get access to these files by merely providing setters in your action that correspond to any of the three
|
||||
* patterns above, such as setDocument(File document), setDocumentContentType(String contentType), etc.
|
||||
* <br>See the example code section.
|
||||
* </p>
|
||||
*
|
||||
* <p> This interceptor will add several field errors, assuming that the action implements {@link ValidationAware}.
|
||||
* These error messages are based on several i18n values stored in struts-messages.properties, a default i18n file
|
||||
* processed for all i18n requests. You can override the text of these messages by providing text for the following
|
||||
* keys:
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li>struts.messages.error.uploading - a general error that occurs when the file could not be uploaded</li>
|
||||
*
|
||||
* <li>struts.messages.error.file.too.large - occurs when the uploaded file is too large</li>
|
||||
*
|
||||
* <li>struts.messages.error.content.type.not.allowed - occurs when the uploaded file does not match the expected
|
||||
* content types specified</li>
|
||||
*
|
||||
* <li>struts.messages.error.file.extension.not.allowed - occurs when the uploaded file does not match the expected
|
||||
* file extensions specified</li>
|
||||
*
|
||||
* </ul>
|
||||
* <p>
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <p><u>Interceptor parameters:</u></p>
|
||||
* <p>
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li>maximumSize (optional) - the maximum size (in bytes) that the interceptor will allow a file reference to be set
|
||||
* on the action. Note, this is <b>not</b> related to the various properties found in struts.properties.
|
||||
* Default to approximately 2MB.</li>
|
||||
*
|
||||
* <li>allowedTypes (optional) - a comma separated list of content types (ie: text/html) that the interceptor will allow
|
||||
* a file reference to be set on the action. If none is specified allow all types to be uploaded.</li>
|
||||
*
|
||||
* <li>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.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* <p>
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
*
|
||||
* <p><u>Extending the interceptor:</u></p>
|
||||
* <p>
|
||||
* <p>
|
||||
* <p>
|
||||
* <!-- START SNIPPET: extending -->
|
||||
* <p>
|
||||
* You can extend this interceptor and override the acceptFile method to provide more control over which files
|
||||
* are supported and which are not.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: extending -->
|
||||
*
|
||||
* <p><u>Example code:</u></p>
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example-configuration -->
|
||||
* <action name="doUpload" class="com.example.UploadAction">
|
||||
* <interceptor-ref name="fileUpload"/>
|
||||
* <interceptor-ref name="basicStack"/>
|
||||
* <result name="success">good_result.jsp</result>
|
||||
* </action>
|
||||
* <!-- END SNIPPET: example-configuration -->
|
||||
* </pre>
|
||||
* <p>
|
||||
* <!-- START SNIPPET: multipart-note -->
|
||||
* <p>
|
||||
* You must set the encoding to <code>multipart/form-data</code> in the form where the user selects the file to upload.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: multipart-note -->
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example-form -->
|
||||
* <s:form action="doUpload" method="post" enctype="multipart/form-data">
|
||||
* <s:file name="upload" label="File"/>
|
||||
* <s:submit/>
|
||||
* </s:form>
|
||||
* <!-- END SNIPPET: example-form -->
|
||||
* </pre>
|
||||
* <p>
|
||||
* And then in your action code you'll have access to the File object if you provide setters according to the
|
||||
* naming convention documented in the start.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example-action -->
|
||||
* package com.example;
|
||||
*
|
||||
* import java.io.File;
|
||||
* import com.opensymphony.xwork2.ActionSupport;
|
||||
*
|
||||
* public UploadAction extends ActionSupport {
|
||||
* private File file;
|
||||
* private String contentType;
|
||||
* private String filename;
|
||||
*
|
||||
* public void setUpload(File file) {
|
||||
* this.file = file;
|
||||
* }
|
||||
*
|
||||
* public void setUploadContentType(String contentType) {
|
||||
* this.contentType = contentType;
|
||||
* }
|
||||
*
|
||||
* public void setUploadFileName(String filename) {
|
||||
* this.filename = filename;
|
||||
* }
|
||||
*
|
||||
* public String execute() {
|
||||
* //...
|
||||
* return SUCCESS;
|
||||
* }
|
||||
* }
|
||||
* <!-- END SNIPPET: example-action -->
|
||||
* </pre>
|
||||
*
|
||||
* @deprecated since Struts 6.4.0, use {@link ActionFileUploadInterceptor} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public class FileUploadInterceptor extends AbstractFileUploadInterceptor {
|
||||
|
||||
private static final long serialVersionUID = -4764627478894962478L;
|
||||
|
||||
protected static final Logger LOG = LogManager.getLogger(FileUploadInterceptor.class);
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.opensymphony.xwork2.interceptor.Interceptor#intercept(com.opensymphony.xwork2.ActionInvocation)
|
||||
*/
|
||||
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
ActionContext ac = invocation.getInvocationContext();
|
||||
|
||||
HttpServletRequest request = ac.getServletRequest();
|
||||
|
||||
if (!(request instanceof MultiPartRequestWrapper multiWrapper)) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
ActionProxy proxy = invocation.getProxy();
|
||||
LOG.debug(getTextMessage(STRUTS_MESSAGES_BYPASS_REQUEST_KEY,
|
||||
new String[]{proxy.getNamespace(), proxy.getActionName()})
|
||||
);
|
||||
}
|
||||
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
Object action = invocation.getAction();
|
||||
if (action instanceof UploadedFilesAware) {
|
||||
LOG.debug("Ignoring action: {} implementing: {} as it will be handled by: {}",
|
||||
invocation.getProxy().getActionName(),
|
||||
UploadedFilesAware.class.getSimpleName(),
|
||||
ActionFileUploadInterceptor.class.getSimpleName()
|
||||
);
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
applyValidation(action, multiWrapper);
|
||||
|
||||
// bind allowed Files
|
||||
Enumeration<String> fileParameterNames = multiWrapper.getFileParameterNames();
|
||||
while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {
|
||||
// get the value of this input tag
|
||||
String inputName = fileParameterNames.nextElement();
|
||||
|
||||
// get the content type
|
||||
String[] contentType = multiWrapper.getContentTypes(inputName);
|
||||
|
||||
if (isNonEmpty(contentType)) {
|
||||
// get the name of the file from the input tag
|
||||
String[] fileName = multiWrapper.getFileNames(inputName);
|
||||
|
||||
if (isNonEmpty(fileName)) {
|
||||
// get a File object for the uploaded File
|
||||
UploadedFile[] files = multiWrapper.getFiles(inputName);
|
||||
if (files != null && files.length > 0) {
|
||||
List<UploadedFile> acceptedFiles = new ArrayList<>(files.length);
|
||||
List<String> acceptedContentTypes = new ArrayList<>(files.length);
|
||||
List<String> acceptedFileNames = new ArrayList<>(files.length);
|
||||
String contentTypeName = inputName + "ContentType";
|
||||
String fileNameName = inputName + "FileName";
|
||||
|
||||
for (int index = 0; index < files.length; index++) {
|
||||
if (acceptFile(action, files[index], fileName[index], contentType[index], inputName)) {
|
||||
acceptedFiles.add(files[index]);
|
||||
acceptedContentTypes.add(contentType[index]);
|
||||
acceptedFileNames.add(fileName[index]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!acceptedFiles.isEmpty()) {
|
||||
Map<String, Parameter> newParams = new HashMap<>();
|
||||
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_KEY, new String[]{inputName}));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (LOG.isWarnEnabled()) {
|
||||
LOG.warn(getTextMessage(action, STRUTS_MESSAGES_INVALID_CONTENT_TYPE_KEY, new String[]{inputName}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// invoke action
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -57,7 +57,6 @@
|
||||
<interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor"/>
|
||||
<interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
|
||||
<interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
|
||||
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
|
||||
<interceptor name="actionFileUpload" class="org.apache.struts2.interceptor.ActionFileUploadInterceptor"/>
|
||||
<interceptor name="i18n" class="org.apache.struts2.interceptor.I18nInterceptor"/>
|
||||
<interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
|
||||
@@ -114,12 +113,6 @@
|
||||
<interceptor-ref name="workflow"/>
|
||||
</interceptor-stack>
|
||||
|
||||
<!-- Sample file upload stack -->
|
||||
<interceptor-stack name="fileUploadStack">
|
||||
<interceptor-ref name="fileUpload"/>
|
||||
<interceptor-ref name="basicStack"/>
|
||||
</interceptor-stack>
|
||||
|
||||
<!-- Action based file upload stack -->
|
||||
<interceptor-stack name="actionFileUploadStack">
|
||||
<interceptor-ref name="actionFileUpload"/>
|
||||
@@ -169,7 +162,6 @@
|
||||
<interceptor-ref name="prepare"/>
|
||||
<interceptor-ref name="chain"/>
|
||||
<interceptor-ref name="modelDriven"/>
|
||||
<interceptor-ref name="fileUpload"/>
|
||||
<interceptor-ref name="actionFileUpload"/>
|
||||
<interceptor-ref name="staticParams"/>
|
||||
<interceptor-ref name="actionMappingParams"/>
|
||||
@@ -208,7 +200,6 @@
|
||||
<interceptor-ref name="chain"/>
|
||||
<interceptor-ref name="scopedModelDriven"/>
|
||||
<interceptor-ref name="modelDriven"/>
|
||||
<interceptor-ref name="fileUpload"/>
|
||||
<interceptor-ref name="actionFileUpload"/>
|
||||
<interceptor-ref name="checkbox"/>
|
||||
<interceptor-ref name="datetime"/>
|
||||
|
||||
@@ -1,659 +0,0 @@
|
||||
/*
|
||||
* 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.fileupload2.jakarta.servlet6.JakartaServletFileUpload;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
import org.apache.struts2.action.UploadedFilesAware;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
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.assertj.core.util.Files;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test case for FileUploadInterceptor.
|
||||
*/
|
||||
public class FileUploadInterceptorTest extends StrutsInternalTestCase {
|
||||
|
||||
private 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 File getContent() {
|
||||
return Files.newTemporaryFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOriginalName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private FileUploadInterceptor interceptor;
|
||||
private File tempDir;
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
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() {
|
||||
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<String> 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", FileUploadInterceptorTest.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<String> 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 {
|
||||
MyFileupAction action = new MyFileupAction();
|
||||
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
mai.setAction(action);
|
||||
mai.setResultCode("NoMultipart");
|
||||
mai.setInvocationContext(ActionContext.getContext());
|
||||
|
||||
// if no multipart request it will bypass and execute it
|
||||
assertEquals("NoMultipart", interceptor.intercept(mai));
|
||||
}
|
||||
|
||||
public void testInvalidContentTypeMultipartRequest() throws Exception {
|
||||
request.setContentType("multipart/form-data"); // not a multipart contentype
|
||||
request.setMethod("post");
|
||||
|
||||
MyFileupAction action = container.inject(MyFileupAction.class);
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
mai.setAction(action);
|
||||
mai.setResultCode("success");
|
||||
mai.setInvocationContext(ActionContext.getContext());
|
||||
|
||||
ActionContext.getContext().withParameters(HttpParameters.create().build());
|
||||
ActionContext.getContext().withServletRequest(createMultipartRequestMaxSize(2000));
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertTrue(action.hasErrors());
|
||||
}
|
||||
|
||||
public void testNoContentMultipartRequest() throws Exception {
|
||||
request.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
request.setMethod("post");
|
||||
request.addHeader("Content-type", "multipart/form-data");
|
||||
request.setContent(null); // there is no content
|
||||
|
||||
MyFileupAction action = container.inject(MyFileupAction.class);
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
mai.setAction(action);
|
||||
mai.setResultCode("success");
|
||||
mai.setInvocationContext(ActionContext.getContext());
|
||||
|
||||
ActionContext.getContext().withParameters(HttpParameters.create().build());
|
||||
ActionContext.getContext().withServletRequest(createMultipartRequestMaxSize(2000));
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertTrue(action.hasErrors());
|
||||
}
|
||||
|
||||
public void testSuccessUploadOfATextFileMultipartRequest() throws Exception {
|
||||
request.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
request.setMethod("post");
|
||||
request.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 FileUploadInterceptor" +
|
||||
"\r\n" +
|
||||
"-----1234--\r\n");
|
||||
request.setContent(content.getBytes(StandardCharsets.US_ASCII));
|
||||
|
||||
MyFileupAction action = new MyFileupAction();
|
||||
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
mai.setAction(action);
|
||||
mai.setResultCode("success");
|
||||
mai.setInvocationContext(ActionContext.getContext());
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
ActionContext.getContext().withParameters(HttpParameters.create(param).build());
|
||||
ActionContext.getContext().withServletRequest(createMultipartRequestMaxSize(2000));
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertFalse(action.hasErrors());
|
||||
|
||||
HttpParameters parameters = mai.getInvocationContext().getParameters();
|
||||
assertEquals(3, parameters.keySet().size());
|
||||
UploadedFile[] files = (UploadedFile[]) parameters.get("file").getObject();
|
||||
String[] fileContentTypes = parameters.get("fileContentType").getMultipleValues();
|
||||
String[] fileRealFilenames = parameters.get("fileFileName").getMultipleValues();
|
||||
|
||||
assertNotNull(files);
|
||||
assertNotNull(fileContentTypes);
|
||||
assertNotNull(fileRealFilenames);
|
||||
assertEquals(1, files.length);
|
||||
assertEquals(1, fileContentTypes.length);
|
||||
assertEquals(1, fileRealFilenames.length);
|
||||
assertEquals("text/html", fileContentTypes[0]);
|
||||
assertNotNull("deleteme.txt", fileRealFilenames[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* tests whether with multiple files sent with the same name, the ones with forbiddenTypes (see
|
||||
* FileUploadInterceptor.setAllowedTypes(...) ) are sorted out.
|
||||
*/
|
||||
public void testMultipleAccept() 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";
|
||||
|
||||
request.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
request.setMethod("POST");
|
||||
request.addHeader("Content-type", "multipart/form-data; boundary=" + bondary);
|
||||
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;
|
||||
request.setContent(content.getBytes());
|
||||
|
||||
assertTrue(JakartaServletFileUpload.isMultipartContent(request));
|
||||
|
||||
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().withParameters(HttpParameters.create(param).build());
|
||||
ActionContext.getContext().withServletRequest(createMultipartRequestMaxSize(2000));
|
||||
|
||||
interceptor.setAllowedTypes("text/html");
|
||||
interceptor.intercept(mai);
|
||||
|
||||
HttpParameters parameters = mai.getInvocationContext().getParameters();
|
||||
assertEquals(3, parameters.keySet().size());
|
||||
UploadedFile[] files = (UploadedFile[]) parameters.get("file").getObject();
|
||||
String[] fileContentTypes = parameters.get("fileContentType").getMultipleValues();
|
||||
String[] fileRealFilenames = parameters.get("fileFileName").getMultipleValues();
|
||||
|
||||
assertNotNull(files);
|
||||
assertNotNull(fileContentTypes);
|
||||
assertNotNull(fileRealFilenames);
|
||||
assertEquals("files accepted ", 2, files.length);
|
||||
assertEquals(2, fileContentTypes.length);
|
||||
assertEquals(2, fileRealFilenames.length);
|
||||
assertEquals("text/html", fileContentTypes[0]);
|
||||
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 boundary = "simple boundary";
|
||||
final String endline = "\r\n";
|
||||
|
||||
request.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
request.setMethod("POST");
|
||||
request.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;
|
||||
request.setContent(content.getBytes());
|
||||
|
||||
assertTrue(JakartaServletFileUpload.isMultipartContent(request));
|
||||
|
||||
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()
|
||||
.withParameters(HttpParameters.create(param).build())
|
||||
.withServletRequest(createMultipartRequestMaxFiles());
|
||||
|
||||
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! Permitted number of files is: 3!",
|
||||
action.getActionErrors().iterator().next()
|
||||
);
|
||||
}
|
||||
|
||||
public void testMultipartRequestMaxFileSize() throws Exception {
|
||||
request.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
request.setMethod("post");
|
||||
request.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 FileUploadInterceptor" +
|
||||
"\r\n" +
|
||||
"-----1234--\r\n");
|
||||
request.setContent(content.getBytes(StandardCharsets.US_ASCII));
|
||||
|
||||
MyFileupAction action = container.inject(MyFileupAction.class);
|
||||
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
mai.setAction(action);
|
||||
mai.setResultCode("success");
|
||||
mai.setInvocationContext(ActionContext.getContext());
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
ActionContext.getContext()
|
||||
.withParameters(HttpParameters.create(param).build())
|
||||
.withServletRequest(createMultipartRequestMaxFileSize());
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertTrue(action.hasActionErrors());
|
||||
|
||||
Collection<String> errors = action.getActionErrors();
|
||||
assertEquals(1, errors.size());
|
||||
String msg = errors.iterator().next();
|
||||
// FIXME: the expected size is 40 - length of the string
|
||||
assertEquals(
|
||||
"File deleteme.txt assigned to file exceeded allowed size limit! Max size allowed is: 10 but file was: 11!",
|
||||
msg);
|
||||
}
|
||||
|
||||
public void testMultipartRequestMaxStringLength() throws Exception {
|
||||
request.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
request.setMethod("post");
|
||||
request.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 FileUploadInterceptor" +
|
||||
"\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");
|
||||
request.setContent(content.getBytes(StandardCharsets.US_ASCII));
|
||||
|
||||
MyFileupAction action = container.inject(MyFileupAction.class);
|
||||
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
mai.setAction(action);
|
||||
mai.setResultCode("success");
|
||||
mai.setInvocationContext(ActionContext.getContext());
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
ActionContext.getContext()
|
||||
.withParameters(HttpParameters.create(param).build())
|
||||
.withServletRequest(createMultipartRequestMaxStringLength());
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertTrue(action.hasActionErrors());
|
||||
|
||||
Collection<String> 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 {
|
||||
request.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
request.setMethod("post");
|
||||
request.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 FileUploadInterceptor" +
|
||||
"\r\n" +
|
||||
"-----1234--\r\n");
|
||||
request.setContent(content.getBytes(StandardCharsets.US_ASCII));
|
||||
|
||||
MyFileupAction action = container.inject(MyFileupAction.class);
|
||||
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
mai.setAction(action);
|
||||
mai.setResultCode("success");
|
||||
mai.setInvocationContext(ActionContext.getContext());
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
ActionContext.getContext()
|
||||
.withParameters(HttpParameters.create(param).build())
|
||||
.withLocale(Locale.GERMAN)
|
||||
.withServletRequest(createMultipartRequestMaxSize(10));
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertTrue(action.hasActionErrors());
|
||||
|
||||
Collection<String> 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"));
|
||||
}
|
||||
|
||||
public void testSkippingUploadedFileAware() throws Exception {
|
||||
request.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
request.setMethod("post");
|
||||
request.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 FileUploadInterceptor" +
|
||||
"\r\n" +
|
||||
"-----1234--\r\n");
|
||||
request.setContent(content.getBytes(StandardCharsets.US_ASCII));
|
||||
|
||||
MyFileUploadAction action = container.inject(MyFileUploadAction.class);
|
||||
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
mai.setInvocationContext(ActionContext.getContext());
|
||||
mai.setAction(action);
|
||||
MockActionProxy map = new MockActionProxy();
|
||||
map.setActionName("uploadedFiles");
|
||||
mai.setProxy(map);
|
||||
ActionContext.getContext()
|
||||
.withParameters(HttpParameters.create(new HashMap<String, Object>()).build())
|
||||
.withServletRequest(createMultipartRequestMaxSize(10));
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertFalse(action.hasActionErrors());
|
||||
}
|
||||
|
||||
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() {
|
||||
return createMultipartRequest(-1, 10, -1, -1);
|
||||
}
|
||||
|
||||
private MultiPartRequestWrapper createMultipartRequestMaxFiles() {
|
||||
return createMultipartRequest(-1, -1, 3, -1);
|
||||
}
|
||||
|
||||
private MultiPartRequestWrapper createMultipartRequestMaxSize(int maxsize) {
|
||||
return createMultipartRequest(maxsize, -1, -1, -1);
|
||||
}
|
||||
|
||||
private MultiPartRequestWrapper createMultipartRequestMaxStringLength() {
|
||||
return createMultipartRequest(-1, -1, -1, 20);
|
||||
}
|
||||
|
||||
private MultiPartRequestWrapper createMultipartRequest(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));
|
||||
jak.setDefaultEncoding(StandardCharsets.UTF_8.name());
|
||||
return new MultiPartRequestWrapper(jak, request, tempDir.getAbsolutePath(), new DefaultLocaleProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
request = new MockHttpServletRequest();
|
||||
interceptor = new FileUploadInterceptor();
|
||||
container.inject(interceptor);
|
||||
tempDir = File.createTempFile("struts", "fileupload");
|
||||
assertThat(tempDir.delete()).isTrue();
|
||||
assertThat(tempDir.mkdirs()).isTrue();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
interceptor.destroy();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public static class MyFileupAction extends ActionSupport {
|
||||
}
|
||||
|
||||
public static class MyFileUploadAction extends ActionSupport implements UploadedFilesAware {
|
||||
private List<UploadedFile> uploadedFiles;
|
||||
|
||||
@Override
|
||||
public void withUploadedFiles(List<UploadedFile> uploadedFiles) {
|
||||
this.uploadedFiles = uploadedFiles;
|
||||
}
|
||||
|
||||
public List<UploadedFile> getUploadFiles() {
|
||||
return this.uploadedFiles;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -47,7 +47,7 @@
|
||||
<interceptor-ref name="chain"/>
|
||||
<interceptor-ref name="scopedModelDriven"/>
|
||||
<interceptor-ref name="modelDriven"/>
|
||||
<interceptor-ref name="fileUpload"/>
|
||||
<interceptor-ref name="actionFileUpload"/>
|
||||
<interceptor-ref name="checkbox"/>
|
||||
<interceptor-ref name="datetime"/>
|
||||
<interceptor-ref name="multiselect"/>
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
<interceptor-ref name="modelDriven">
|
||||
<param name="refreshModelBeforeResult">true</param>
|
||||
</interceptor-ref>
|
||||
<interceptor-ref name="fileUpload"/>
|
||||
<interceptor-ref name="actionFileUpload"/>
|
||||
<interceptor-ref name="checkbox"/>
|
||||
<interceptor-ref name="staticParams"/>
|
||||
<interceptor-ref name="params"/>
|
||||
|
||||
Reference in New Issue
Block a user