Merge pull request #809 from apache/fix/after-rebase

Rebase struts-7-0-x branch
This commit is contained in:
Lukasz Lenart
2023-12-17 15:39:54 +01:00
committed by GitHub
19 changed files with 400 additions and 178 deletions
+1 -1
View File
@@ -14,5 +14,5 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
Vendored
+55 -56
View File
@@ -37,14 +37,9 @@ pipeline {
MAVEN_OPTS = "-Xmx1024m"
}
stages {
stage('Build') {
steps {
sh './mvnw -B clean install -DskipTests -DskipAssembly'
}
}
stage('Test') {
steps {
sh './mvnw -B test'
sh './mvnw -B -DskipAssembly verify --no-transfer-progress'
}
post {
always {
@@ -53,49 +48,6 @@ pipeline {
}
}
}
stage('Build Source & JavaDoc') {
when {
branch 'master'
}
steps {
dir("local-snapshots-dir/") {
deleteDir()
}
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly'
}
}
stage('Deploy Snapshot') {
when {
branch 'master'
}
steps {
withCredentials([file(credentialsId: 'lukaszlenart-repository-access-token', variable: 'CUSTOM_SETTINGS')]) {
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly'
}
}
}
stage('Upload nightlies') {
when {
branch 'master'
}
steps {
sh './mvnw -B package -DskipTests'
sshPublisher(publishers: [
sshPublisherDesc(
configName: 'Nightlies',
transfers: [
sshTransfer(
remoteDirectory: '/struts/snapshot',
removePrefix: 'assembly/target/assembly/out',
sourceFiles: 'assembly/target/assembly/out/struts-*.zip',
cleanRemote: true
)
],
verbose: true
)
])
}
}
}
post {
always {
@@ -115,14 +67,9 @@ pipeline {
MAVEN_OPTS = "-Xmx1024m"
}
stages {
stage('Build') {
steps {
sh './mvnw -B clean install -DskipTests -DskipAssembly'
}
}
stage('Test') {
steps {
sh './mvnw -B verify -Pcoverage -DskipAssembly'
sh './mvnw -B verify -Pcoverage -DskipAssembly --no-transfer-progress'
}
post {
always {
@@ -133,7 +80,9 @@ pipeline {
}
stage('Code Quality') {
when {
branch 'master'
anyOf {
branch 'master'; branch 'release/struts-7-0-x'
}
}
steps {
withCredentials([string(credentialsId: 'asf-struts-sonarcloud', variable: 'SONARCLOUD_TOKEN')]) {
@@ -141,6 +90,56 @@ pipeline {
}
}
}
stage('Build Source & JavaDoc') {
when {
anyOf {
branch 'master'; branch 'release/struts-7-0-x'
}
}
steps {
dir("local-snapshots-dir/") {
deleteDir()
}
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly'
}
}
stage('Deploy Snapshot') {
when {
anyOf {
branch 'master'; branch 'release/struts-7-0-x'
}
}
steps {
withCredentials([file(credentialsId: 'lukaszlenart-repository-access-token', variable: 'CUSTOM_SETTINGS')]) {
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly'
}
}
}
stage('Upload nightlies') {
when {
anyOf {
branch 'master'
branch 'release/struts-7-0-x'
}
}
steps {
sh './mvnw -B package -DskipTests'
sshPublisher(publishers: [
sshPublisherDesc(
configName: 'Nightlies',
transfers: [
sshTransfer(
remoteDirectory: '/struts/snapshot',
removePrefix: 'assembly/target/assembly/out',
sourceFiles: 'assembly/target/assembly/out/struts-*.zip',
cleanRemote: true
)
],
verbose: true
)
])
}
}
}
post {
always {
+7 -1
View File
@@ -129,6 +129,12 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
@@ -231,7 +237,7 @@
<httpConnector>
<port>8090</port>
</httpConnector>
<scanIntervalSeconds>10</scanIntervalSeconds>
<scan>10</scan>
<webAppSourceDirectory>${basedir}/src/main/webapp/</webAppSourceDirectory>
<webApp>
<extraClasspath>
@@ -19,35 +19,46 @@
package it.org.apache.struts2.showcase;
import java.io.File;
import java.io.FileWriter;
import org.htmlunit.WebClient;
import org.htmlunit.html.DomElement;
import org.htmlunit.html.HtmlFileInput;
import org.htmlunit.html.HtmlForm;
import org.htmlunit.html.HtmlInput;
import org.htmlunit.html.HtmlPage;
import org.htmlunit.html.HtmlSubmitInput;
import org.junit.Assert;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class FileUploadTest {
@Test
public void testEmptyFile() throws Exception {
public void testSimpleFileUpload() throws Exception {
try (final WebClient webClient = new WebClient()) {
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/fileupload/doUpload.action");
final HtmlForm form = page.getFormByName("doUpload");
HtmlInput captionInput = form.getInputByName("caption");
HtmlFileInput uploadInput = form.getInputByName("upload");
captionInput.type("some caption");
File tempFile = File.createTempFile("testEmptyFile", ".tmp");
File tempFile = File.createTempFile("testEmptyFile", ".txt");
tempFile.deleteOnExit();
try (FileWriter writer = new FileWriter(tempFile)) {
writer.append("Some strings");
}
uploadInput.setValue(tempFile.getAbsolutePath());
final HtmlSubmitInput button = form.getInputByValue("Submit");
final HtmlPage resultPage = button.click();
DomElement errorMessage = resultPage.getFirstByXPath("//span[@class='errorMessage']");
Assert.assertNotNull(errorMessage);
Assert.assertEquals("File cannot be empty", errorMessage.getVisibleText());
String content = resultPage.getVisibleText();
System.out.println(content);
assertThat(content).contains(
"ContentType: text/plain",
"Original FileName: " + tempFile.getName(),
"Caption:some caption"
);
}
}
@@ -0,0 +1,40 @@
/*
* 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.action;
import org.apache.struts2.dispatcher.multipart.UploadedFile;
import java.util.List;
/**
* Actions that want to be aware of all the uploaded file should implement this interface.
* The {@link org.apache.struts2.interceptor.ActionFileUploadInterceptor} will use the interface
* to notify action about the multiple uploaded files.
*/
public interface UploadedFilesAware {
/**
* Notifies action about the multiple uploaded files, when a single file is uploaded
* the list will have just one element
*
* @param uploadedFiles a list of {@link UploadedFile}, cannot be null. It can be empty.
*/
void withUploadedFiles(List<UploadedFile> uploadedFiles);
}
@@ -36,6 +36,8 @@ import java.util.Locale;
*/
public abstract class AbstractMultiPartRequest implements MultiPartRequest {
protected static final String STRUTS_MESSAGES_UPLOAD_ERROR_PARAMETER_TOO_LONG_KEY = "struts.messages.upload.error.parameter.too.long";
private static final Logger LOG = LogManager.getLogger(AbstractMultiPartRequest.class);
/**
@@ -18,6 +18,22 @@
*/
package org.apache.struts2.dispatcher.multipart;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload2.core.DiskFileItem;
import org.apache.commons.fileupload2.core.DiskFileItemFactory;
import org.apache.commons.fileupload2.core.FileItem;
import org.apache.commons.fileupload2.core.FileUploadByteCountLimitException;
import org.apache.commons.fileupload2.core.FileUploadContentTypeException;
import org.apache.commons.fileupload2.core.FileUploadException;
import org.apache.commons.fileupload2.core.FileUploadFileCountLimitException;
import org.apache.commons.fileupload2.core.FileUploadSizeException;
import org.apache.commons.fileupload2.core.RequestContext;
import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.dispatcher.LocalizedMessage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -31,22 +47,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.fileupload2.core.DiskFileItem;
import org.apache.commons.fileupload2.core.DiskFileItemFactory;
import org.apache.commons.fileupload2.core.FileItem;
import org.apache.commons.fileupload2.core.FileUploadByteCountLimitException;
import org.apache.commons.fileupload2.core.FileUploadException;
import org.apache.commons.fileupload2.core.FileUploadFileCountLimitException;
import org.apache.commons.fileupload2.core.FileUploadSizeException;
import org.apache.commons.fileupload2.core.RequestContext;
import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.dispatcher.LocalizedMessage;
import jakarta.servlet.http.HttpServletRequest;
/**
* Multipart form data request adapter for Jakarta Commons Fileupload package.
*/
@@ -77,13 +77,24 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
LocalizedMessage errorMessage;
if (e instanceof FileUploadByteCountLimitException) {
FileUploadByteCountLimitException ex = (FileUploadByteCountLimitException) e;
errorMessage = buildErrorMessage(e, new Object[]{ex.getFileName(), ex.getPermitted(), ex.getActualSize()});
errorMessage = buildErrorMessage(e, new Object[]{
ex.getFieldName(), ex.getFileName(), ex.getPermitted(), ex.getActualSize()
});
} else if (e instanceof FileUploadFileCountLimitException) {
FileUploadFileCountLimitException ex = (FileUploadFileCountLimitException) e;
errorMessage = buildErrorMessage(e, new Object[]{ex.getPermitted()});
errorMessage = buildErrorMessage(e, new Object[]{
ex.getPermitted(), ex.getActualSize()
});
} else if (e instanceof FileUploadSizeException) {
FileUploadSizeException ex = (FileUploadSizeException) e;
errorMessage = buildErrorMessage(e, new Object[]{ex.getPermitted(), ex.getActualSize()});
errorMessage = buildErrorMessage(e, new Object[]{
ex.getPermitted(), ex.getActualSize()
});
} else if (e instanceof FileUploadContentTypeException) {
FileUploadContentTypeException ex = (FileUploadContentTypeException) e;
errorMessage = buildErrorMessage(e, new Object[]{
ex.getContentType()
});
} else {
errorMessage = buildErrorMessage(e, new Object[]{});
}
@@ -149,8 +160,8 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
long size = item.getSize();
if (size > maxStringLength) {
LOG.debug("Form field {} of size {} bytes exceeds limit of {}.", sanitizeNewlines(item.getFieldName()), size, maxStringLength);
String errorKey = "struts.messages.upload.error.parameter.too.long";
LocalizedMessage localizedMessage = new LocalizedMessage(this.getClass(), errorKey, null,
LocalizedMessage localizedMessage = new LocalizedMessage(this.getClass(),
STRUTS_MESSAGES_UPLOAD_ERROR_PARAMETER_TOO_LONG_KEY, null,
new Object[]{item.getFieldName(), maxStringLength, size});
if (!errors.contains(localizedMessage)) {
errors.add(localizedMessage);
@@ -174,7 +185,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
DiskFileItemFactory fac = createDiskFileItemFactory(saveDir);
JakartaServletFileUpload upload = createServletFileUpload(fac);
return upload.parseRequest(createRequestContext(servletRequest));
}
@@ -252,9 +263,9 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
}
}
UploadedFile uploadedFile = StrutsUploadedFile.Builder.create(storeLocation)
.withContentType(fileItem.getContentType())
.withOriginalName(fileItem.getName())
.build();
.withContentType(fileItem.getContentType())
.withOriginalName(fileItem.getName())
.build();
fileList.add(uploadedFile);
}
@@ -18,17 +18,12 @@
*/
package org.apache.struts2.dispatcher.multipart;
import org.apache.commons.fileupload2.core.DiskFileItem;
import org.apache.commons.fileupload2.core.DiskFileItemFactory;
import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload;
import org.apache.commons.fileupload2.core.FileUploadSizeException;
import org.apache.commons.fileupload2.core.FileItemInputIterator;
import org.apache.commons.fileupload2.core.FileItemInput;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.dispatcher.LocalizedMessage;
@@ -223,7 +218,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
// Interface with Commons FileUpload API
// Using the Streaming API
JakartaServletFileUpload servletFileUpload = new JakartaServletFileUpload();
JakartaServletFileUpload<DiskFileItem, DiskFileItemFactory> servletFileUpload = new JakartaServletFileUpload<>();
if (maxSize != null) {
servletFileUpload.setSizeMax(maxSize);
}
@@ -447,8 +442,6 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
*/
public static class FileInfo implements Serializable {
private static final long serialVersionUID = 1083158552766906037L;
private final File file;
private final String contentType;
private final String originalName;
@@ -55,9 +55,9 @@ public class MultiPartRequestWrapper extends StrutsRequestWrapper {
protected static final Logger LOG = LogManager.getLogger(MultiPartRequestWrapper.class);
private Collection<LocalizedMessage> errors;
private MultiPartRequest multi;
private Locale defaultLocale = Locale.ENGLISH;
private final Collection<LocalizedMessage> errors;
private final MultiPartRequest multi;
private Locale defaultLocale;
/**
* Process file downloads and log any errors.
@@ -84,7 +84,7 @@ public class MultiPartRequestWrapper extends StrutsRequestWrapper {
} catch (IOException e) {
LOG.warn(e.getMessage(), e);
addError(buildErrorMessage(e, new Object[] {e.getMessage()}));
}
}
}
public MultiPartRequestWrapper(MultiPartRequest multiPartRequest, HttpServletRequest request, String saveDir, LocaleProvider provider) {
@@ -185,12 +185,12 @@ public class MultiPartRequestWrapper extends StrutsRequestWrapper {
/**
* @see jakarta.servlet.http.HttpServletRequest#getParameterMap()
*/
public Map getParameterMap() {
public Map<String, String[]> getParameterMap() {
Map<String, String[]> map = new HashMap<>();
Enumeration enumeration = getParameterNames();
Enumeration<String> enumeration = getParameterNames();
while (enumeration.hasMoreElements()) {
String name = (String) enumeration.nextElement();
String name = enumeration.nextElement();
map.put(name, this.getParameterValues(name));
}
@@ -200,7 +200,7 @@ public class MultiPartRequestWrapper extends StrutsRequestWrapper {
/**
* @see jakarta.servlet.http.HttpServletRequest#getParameterNames()
*/
public Enumeration getParameterNames() {
public Enumeration<String> getParameterNames() {
if (multi == null) {
return super.getParameterNames();
} else {
@@ -251,8 +251,8 @@ public class MultiPartRequestWrapper extends StrutsRequestWrapper {
* @param params2 the second enumeration.
* @return a single Enumeration of all elements from both Enumerations.
*/
protected Enumeration mergeParams(Enumeration params1, Enumeration params2) {
Vector temp = new Vector();
protected Enumeration<String> mergeParams(Enumeration<String> params1, Enumeration<String> params2) {
Vector<String> temp = new Vector<>();
while (params1.hasMoreElements()) {
temp.add(params1.nextElement());
@@ -21,13 +21,13 @@ package org.apache.struts2.interceptor;
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.multipart.MultiPartRequestWrapper;
import org.apache.struts2.dispatcher.multipart.UploadedFile;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
@@ -134,7 +134,7 @@ public class ActionFileUploadInterceptor extends AbstractFileUploadInterceptor {
*/
public String intercept(ActionInvocation invocation) throws Exception {
HttpServletRequest request = invocation.getInvocationContext().getServletRequest();
if (!(request instanceof MultiPartRequestWrapper)) {
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()}));
@@ -142,15 +142,12 @@ public class ActionFileUploadInterceptor extends AbstractFileUploadInterceptor {
return invocation.invoke();
}
MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) request;
if (!(invocation.getAction() instanceof UploadedFilesAware)) {
if (!(invocation.getAction() instanceof UploadedFilesAware action)) {
LOG.debug("Action: {} doesn't implement: {}, ignoring file upload",
invocation.getProxy().getActionName(),
UploadedFilesAware.class.getSimpleName());
return invocation.invoke();
}
UploadedFilesAware action = (UploadedFilesAware) invocation.getAction();
applyValidation(action, multiWrapper);
@@ -16,24 +16,62 @@
# specific language governing permissions and limitations
# under the License.
#
# WARNING! This file is the exact copy of struts-messages.properties!
# See https://issues.apache.org/jira/browse/WW-4195 for more details!
struts.messages.invalid.token=The form has already been processed or no token was supplied, please try again.
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=File {0} is too large to be uploaded. Maximum allowed size is {4} bytes!
struts.messages.upload.error.parameter.too.long=The request parameter "{0}" was too long. Max length allowed is {1}, but found {2}!
# 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 - field name
# 1 - max string length
# 2 - actual size
struts.messages.upload.error.parameter.too.long=The request parameter "{0}" was too long. Max length allowed is {1}, but found {2}!
# 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)}
struts.messages.upload.error.FileUploadSizeException=Request exceeded allowed size limit! Max size allowed is: {0}!
struts.messages.upload.error.FileUploadFileCountLimitException=Request exceeded allowed number of files! Max allowed files number is: {0}!
struts.messages.upload.error.FileUploadByteCountLimitException=File in request exceeded allowed file size limit! Max file size allowed is: {1}!
# params depend on exception being handled
# FileUploadByteCountLimitException
# 0 - field name
# 1 - file name
# 2 - permitted
# 3 - actual size
struts.messages.upload.error.FileUploadByteCountLimitException=File {1} assigned to {0} exceeded allowed size limit! Max size allowed is: {2} but file was: {3}!
# FileUploadFileCountLimitException
# 0 - limit
struts.messages.upload.error.FileUploadFileCountLimitException=Request exceeded allowed number of files! Permitted number of files is: {0}!
# FileUploadSizeException
# 1 - permitted size
# 2 - actual size
struts.messages.upload.error.FileUploadSizeException=Request exceeded allowed size limit! Max size allowed is: {0} but request was: {1}!
# FileUploadContentTypeException
# 0 - content type
struts.messages.upload.error.FileUploadContentTypeException=Request has wrong content type: {0}!
struts.messages.upload.error.FileUploadException=Error uploading: {0}!
devmode.notification=Developer Notification (set struts.devMode to false to disable this message):\n{0}
@@ -40,7 +40,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase
}
@Test
public void allowlist() throws Exception {
public void allowList() throws Exception {
loadConfigurationProviders(testXml1, testXml2);
providerAllowlist = container.getInstance(ProviderAllowlist.class);
@@ -0,0 +1,28 @@
/*
* 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 com.opensymphony.xwork2.ognl;
import java.util.HashMap;
public class MyCustomMap<K, V> extends HashMap<K, V> {
@Override
public V get(Object key) {
return (V) "System compromised";
}
}
@@ -25,7 +25,9 @@ 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 jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload2.jakarta.JakartaServletDiskFileUpload;
import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsInternalTestCase;
import org.apache.struts2.action.UploadedFilesAware;
@@ -35,7 +37,6 @@ 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;
@@ -290,13 +291,14 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
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");
String content = ("""
-----1234\r
Content-Disposition: form-data; name="file"; filename="deleteme.txt"\r
Content-Type: text/html\r
\r
Unit test of ActionFileUploadInterceptor\r
-----1234--\r
""");
req.setContent(content.getBytes(StandardCharsets.US_ASCII));
MyFileUploadAction action = new MyFileUploadAction();
@@ -340,7 +342,7 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
endline;
req.setContent(content.getBytes());
assertTrue(ServletFileUpload.isMultipartContent(req));
assertTrue(JakartaServletDiskFileUpload.isMultipartContent(req));
MyFileUploadAction action = new MyFileUploadAction();
container.inject(action);
@@ -377,7 +379,7 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
endline;
req.setContent(content.getBytes());
assertTrue(ServletFileUpload.isMultipartContent(req));
assertTrue(JakartaServletFileUpload.isMultipartContent(req));
MyFileUploadAction action = new MyFileUploadAction();
container.inject(action);
@@ -392,7 +394,10 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
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());
assertEquals(
"Request exceeded allowed number of files! Permitted number of files is: 3!",
action.getActionErrors().iterator().next()
);
}
public void testMultipartRequestMaxFileSize() throws Exception {
@@ -402,13 +407,14 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
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");
String content = ("""
-----1234\r
Content-Disposition: form-data; name="file"; filename="deleteme.txt"\r
Content-Type: text/html\r
\r
Unit test of ActionFileUploadInterceptor\r
-----1234--\r
""");
req.setContent(content.getBytes(StandardCharsets.US_ASCII));
MyFileUploadAction action = container.inject(MyFileUploadAction.class);
@@ -427,8 +433,9 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
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 in request exceeded allowed file size limit! Max file size allowed is: 10 but file deleteme.txt was: 40!",
"File deleteme.txt assigned to file exceeded allowed size limit! Max size allowed is: 10 but file was: 10!",
msg);
}
@@ -439,23 +446,22 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
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");
String content = ("""
-----1234\r
Content-Disposition: form-data; name="file"; filename="deleteme.txt"\r
Content-Type: text/html\r
\r
Unit test of ActionFileUploadInterceptor\r
-----1234\r
Content-Disposition: form-data; name="normalFormField1"\r
\r
it works\r
-----1234\r
Content-Disposition: form-data; name="normalFormField2"\r
\r
long string should not work\r
-----1234--\r
""");
req.setContent(content.getBytes(StandardCharsets.US_ASCII));
MyFileUploadAction action = container.inject(MyFileUploadAction.class);
@@ -475,7 +481,7 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
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!",
"The request parameter \"normalFormField2\" was too long. Max length allowed is 20, but found 27!",
msg);
}
@@ -486,13 +492,14 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
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");
String content = ("""
-----1234\r
Content-Disposition: form-data; name="file"; filename="deleteme.txt"\r
Content-Type: text/html\r
\r
Unit test of ActionFileUploadInterceptor\r
-----1234--\r
""");
req.setContent(content.getBytes(StandardCharsets.US_ASCII));
MyFileUploadAction action = container.inject(MyFileUploadAction.class);
@@ -424,7 +424,10 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
HttpParameters parameters = mai.getInvocationContext().getParameters();
assertEquals(0, parameters.keySet().size());
assertEquals(1, action.getActionErrors().size());
assertEquals("Request exceeded allowed number of files! Max allowed files number is: 3!", action.getActionErrors().iterator().next());
assertEquals(
"Request exceeded allowed number of files! Permitted number of files is: 3!",
action.getActionErrors().iterator().next()
);
}
public void testMultipartRequestMaxFileSize() throws Exception {
@@ -461,8 +464,9 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
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 in request exceeded allowed file size limit! Max file size allowed is: 10!",
"File deleteme.txt assigned to file exceeded allowed size limit! Max size allowed is: 10 but file was: 10!",
msg);
}
@@ -511,7 +515,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
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!",
"The request parameter \"normalFormField2\" was too long. Max length allowed is 20, but found 27!",
msg);
}
@@ -19,10 +19,10 @@
package org.apache.struts2.util;
import com.opensymphony.xwork2.ognl.SecurityMemberAccess;
import jakarta.servlet.jsp.tagext.TagSupport;
import org.apache.struts2.StrutsInternalTestCase;
import org.apache.struts2.views.jsp.ActionTag;
import jakarta.servlet.jsp.tagext.TagSupport;
import java.lang.reflect.Member;
import java.util.HashMap;
import java.util.Map;
@@ -40,9 +40,7 @@ public class SecurityMemberAccessInServletsTest extends StrutsInternalTestCase {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<Pattern>();
excluded.add(Pattern.compile("^(?!jakarta\\.servlet\\..+)(jakarta\\..+)"));
sma.useExcludedPackageNamePatterns(excluded);
sma.useExcludedPackageNamePatterns("^(?!jakarta\\.servlet\\..+)(jakarta\\..+)");
String propertyName = "value";
Member member = TagSupport.class.getMethod("doStartTag");
@@ -58,9 +56,7 @@ public class SecurityMemberAccessInServletsTest extends StrutsInternalTestCase {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^jakarta\\..+"));
sma.useExcludedPackageNamePatterns(excluded);
sma.useExcludedPackageNamePatterns("^jakarta\\..+");
String propertyName = "value";
Member member = TagSupport.class.getMethod("doStartTag");
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
* 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.
*/
-->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
"https://struts.apache.org/dtds/struts-6.0.dtd">
<struts>
<package name="allow2">
<result-types>
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult" default="true"/>
</result-types>
<interceptors>
<interceptor name="noop" class="org.apache.struts2.interceptor.NoOpInterceptor"/>
</interceptors>
<action name="WildCard" class="com.opensymphony.xwork2.ActionSupport">
<result name="*" type="chain"/>
<interceptor-ref name="noop"/>
</action>
</package>
</struts>
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
* 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.
*/
-->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
"https://struts.apache.org/dtds/struts-6.0.dtd">
<struts>
<package name="allow">
<result-types>
<result-type name="mock" class="com.opensymphony.xwork2.mock.MockResult"/>
</result-types>
<interceptors>
<interceptor name="test" class="com.opensymphony.xwork2.mock.MockInterceptor">
<param name="foo">fooDefault</param>
</interceptor>
<interceptor-stack name="defaultStack">
<interceptor-ref name="test"/>
</interceptor-stack>
</interceptors>
<action name="Foo" class="com.opensymphony.xwork2.SimpleAction">
<param name="foo">18</param>
<param name="bar">24</param>
<result name="success" type="mock"/>
<interceptor-ref name="defaultStack"/>
</action>
</package>
</struts>
@@ -21,6 +21,7 @@ package org.apache.struts2.junit;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.ActionProxyFactory;
import com.opensymphony.xwork2.XWorkTestCase;
import com.opensymphony.xwork2.config.Configuration;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.Dispatcher;