mirror of
https://github.com/apache/struts.git
synced 2026-08-09 08:36:54 +00:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4603706b40 | |||
| 556522e9b2 | |||
| 1db8a72bb5 | |||
| 31c3fc50ed | |||
| adcd1df0ca | |||
| 568b292bd4 | |||
| 02e17f5912 | |||
| 3c856c92a1 | |||
| ff249c64cd | |||
| a1de1cfdeb | |||
| 9326279769 | |||
| 9474ba41f5 | |||
| 2d8433d300 | |||
| abbb2aad2c | |||
| 21c7ecc105 | |||
| 58b0d536e8 | |||
| 442b4ea2e6 | |||
| f4d6564bbb | |||
| 0b4855ac41 | |||
| 9d5d802980 | |||
| b34665046c | |||
| 080263e93f |
@@ -52,12 +52,12 @@ jobs:
|
||||
java-version: 17
|
||||
cache: 'maven'
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3.28.5
|
||||
uses: github/codeql-action/init@v3.28.9
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3.28.5
|
||||
uses: github/codeql-action/autobuild@v3.28.9
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3.28.5
|
||||
uses: github/codeql-action/analyze@v3.28.9
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
@@ -65,6 +65,6 @@ jobs:
|
||||
retention-days: 5
|
||||
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@e7c0c9d71b7bd108fd12e06b56fc58d3d154164d # 2.22.11
|
||||
uses: github/codeql-action/upload-sarif@0a35e8f6866a39b001e5f7ad1d0daf9836786896 # 2.22.11
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-rest-showcase</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
<name>Struts 2 Rest Showcase Webapp</name>
|
||||
<description>Struts 2 Rest Showcase Example</description>
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-showcase</artifactId>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-assembly</artifactId>
|
||||
|
||||
+4
-4
@@ -25,11 +25,11 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-bom</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Struts 2 Bill of Materials</name>
|
||||
@@ -44,7 +44,7 @@
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<struts-version.version>7.0.1</struts-version.version>
|
||||
<struts-version.version>7.0.3</struts-version.version>
|
||||
<maven.site.skip>true</maven.site.skip>
|
||||
<maven.site.deploy.skip>true</maven.site.deploy.skip>
|
||||
</properties>
|
||||
@@ -160,7 +160,7 @@
|
||||
</dependencyManagement>
|
||||
|
||||
<scm>
|
||||
<tag>STRUTS_7_0_1</tag>
|
||||
<tag>STRUTS_7_0_3</tag>
|
||||
<connection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</connection>
|
||||
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</developerConnection>
|
||||
<url>https://github.com/apache/struts/</url>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
<artifactId>struts2-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -18,13 +18,12 @@
|
||||
*/
|
||||
package org.apache.struts2.components;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
import org.apache.struts2.views.annotations.StrutsTag;
|
||||
import org.apache.struts2.views.annotations.StrutsTagAttribute;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: javadoc -->
|
||||
* <p>Render an HTML input field of type text</p>
|
||||
@@ -50,17 +49,16 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
* </pre>
|
||||
*/
|
||||
@StrutsTag(
|
||||
name="textfield",
|
||||
tldTagClass="org.apache.struts2.views.jsp.ui.TextFieldTag",
|
||||
description="Render an HTML input field of type text",
|
||||
allowDynamicAttributes=true)
|
||||
name = "textfield",
|
||||
tldTagClass = "org.apache.struts2.views.jsp.ui.TextFieldTag",
|
||||
description = "Render an HTML input field of type text",
|
||||
allowDynamicAttributes = true)
|
||||
public class TextField extends UIBean {
|
||||
/**
|
||||
* The name of the default template for the TextFieldTag
|
||||
*/
|
||||
final public static String TEMPLATE = "text";
|
||||
|
||||
|
||||
protected String maxlength;
|
||||
protected String readonly;
|
||||
protected String size;
|
||||
@@ -95,27 +93,22 @@ public class TextField extends UIBean {
|
||||
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML maxlength attribute", type="Integer")
|
||||
@StrutsTagAttribute(description = "HTML maxlength attribute", type = "Integer")
|
||||
public void setMaxlength(String maxlength) {
|
||||
this.maxlength = maxlength;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="Deprecated. Use maxlength instead.", type="Integer")
|
||||
public void setMaxLength(String maxlength) {
|
||||
this.maxlength = maxlength;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="Whether the input is readonly", type="Boolean", defaultValue="false")
|
||||
@StrutsTagAttribute(description = "Whether the input is readonly", type = "Boolean", defaultValue = "false")
|
||||
public void setReadonly(String readonly) {
|
||||
this.readonly = readonly;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML size attribute", type="Integer")
|
||||
@StrutsTagAttribute(description = "HTML size attribute", type = "Integer")
|
||||
public void setSize(String size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="Specifies the html5 type element to display. e.g. text, email, url", defaultValue="text")
|
||||
@StrutsTagAttribute(description = "Specifies the html5 type element to display. e.g. text, email, url", defaultValue = "text")
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
*/
|
||||
package org.apache.struts2.dispatcher;
|
||||
|
||||
import jakarta.servlet.jsp.PageContext;
|
||||
import org.apache.struts2.StrutsStatics;
|
||||
|
||||
import jakarta.servlet.jsp.PageContext;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -86,7 +86,7 @@ public class AttributeMap extends AbstractMap<String, Object> {
|
||||
|
||||
PageContext pc = getPageContext();
|
||||
|
||||
if (pc == null) {
|
||||
if (pc == null || pc.getRequest() == null) {
|
||||
RequestMap request = (RequestMap) context.get(DispatcherConstants.REQUEST);
|
||||
SessionMap session = (SessionMap) context.get(DispatcherConstants.SESSION);
|
||||
ApplicationMap application = (ApplicationMap) context.get(DispatcherConstants.APPLICATION);
|
||||
|
||||
+2
-30
@@ -19,8 +19,6 @@
|
||||
package org.apache.struts2.dispatcher.multipart;
|
||||
|
||||
import org.apache.struts2.inject.Inject;
|
||||
import org.apache.struts2.security.DefaultExcludedPatternsChecker;
|
||||
import org.apache.struts2.security.ExcludedPatternsChecker;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.apache.commons.fileupload2.core.FileUploadByteCountLimitException;
|
||||
import org.apache.commons.fileupload2.core.FileUploadContentTypeException;
|
||||
@@ -28,6 +26,7 @@ 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.jakarta.servlet6.JakartaServletDiskFileUpload;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -54,8 +53,6 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(AbstractMultiPartRequest.class);
|
||||
|
||||
private static final String EXCLUDED_FILE_PATTERN = ".*[<>&\"'|;\\\\/?*:]+.*|.*\\.\\..*";
|
||||
|
||||
/**
|
||||
* Defines the internal buffer size used during streaming operations.
|
||||
*/
|
||||
@@ -111,14 +108,6 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
*/
|
||||
protected Map<String, List<String>> parameters = new HashMap<>();
|
||||
|
||||
|
||||
private final ExcludedPatternsChecker patternsChecker;
|
||||
|
||||
protected AbstractMultiPartRequest() {
|
||||
patternsChecker = new DefaultExcludedPatternsChecker();
|
||||
((DefaultExcludedPatternsChecker) patternsChecker).setAdditionalExcludePatterns(EXCLUDED_FILE_PATTERN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bufferSize Sets the buffer size to be used.
|
||||
*/
|
||||
@@ -296,16 +285,7 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
* @return the canonical name based on the supplied filename
|
||||
*/
|
||||
protected String getCanonicalName(final String originalFileName) {
|
||||
String fileName = originalFileName;
|
||||
|
||||
int forwardSlash = fileName.lastIndexOf('/');
|
||||
int backwardSlash = fileName.lastIndexOf('\\');
|
||||
if (forwardSlash != -1 && forwardSlash > backwardSlash) {
|
||||
fileName = fileName.substring(forwardSlash + 1);
|
||||
} else {
|
||||
fileName = fileName.substring(backwardSlash + 1);
|
||||
}
|
||||
return fileName;
|
||||
return FilenameUtils.getName(originalFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -429,12 +409,4 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileName file name to check
|
||||
* @return true if the file name is excluded
|
||||
*/
|
||||
protected boolean isExcluded(String fileName) {
|
||||
return patternsChecker.isExcluded(fileName).isExcluded();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-16
@@ -77,12 +77,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
}
|
||||
|
||||
protected void processNormalFormField(DiskFileItem item, Charset charset) throws IOException {
|
||||
LOG.debug("Item: {} is a normal form field", item.getName());
|
||||
|
||||
if (isExcluded(item.getFieldName())) {
|
||||
LOG.warn(() -> "Form field [%s] is rejected!".formatted(normalizeSpace(item.getFieldName())));
|
||||
return;
|
||||
}
|
||||
LOG.debug("Item: {} is a normal form field", normalizeSpace(item.getName()));
|
||||
|
||||
List<String> values;
|
||||
String fieldName = item.getFieldName();
|
||||
@@ -105,16 +100,6 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
}
|
||||
|
||||
protected void processFileField(DiskFileItem item) {
|
||||
if (isExcluded(item.getName())) {
|
||||
LOG.warn(() -> "File name [%s] is not accepted".formatted(normalizeSpace(item.getName())));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExcluded(item.getFieldName())) {
|
||||
LOG.warn(() -> "Field name [%s] is not accepted".formatted(normalizeSpace(item.getFieldName())));
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip file uploads that don't have a file name - meaning that no file was selected.
|
||||
if (item.getName() == null || item.getName().trim().isEmpty()) {
|
||||
LOG.debug(() -> "No file has been uploaded for the field: " + normalizeSpace(item.getFieldName()));
|
||||
|
||||
+1
-13
@@ -116,11 +116,6 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
String fieldName = fileItemInput.getFieldName();
|
||||
String fieldValue = readStream(fileItemInput.getInputStream());
|
||||
|
||||
if (isExcluded(fieldName)) {
|
||||
LOG.warn(() -> "Form field [%s] is rejected!".formatted(normalizeSpace(fieldName)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (exceedsMaxStringLength(fieldName, fieldValue)) {
|
||||
return;
|
||||
}
|
||||
@@ -198,11 +193,6 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExcluded(fileItemInput.getName())) {
|
||||
LOG.warn(() -> "File field [%s] rejected".formatted(normalizeSpace(fileItemInput.getName())));
|
||||
return;
|
||||
}
|
||||
|
||||
if (exceedsMaxFiles(fileItemInput)) {
|
||||
return;
|
||||
}
|
||||
@@ -242,9 +232,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
InputStream input = fileItemInput.getInputStream();
|
||||
try (OutputStream output = new BufferedOutputStream(Files.newOutputStream(file.toPath()), bufferSize)) {
|
||||
byte[] buffer = new byte[bufferSize];
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Streaming file: {} using buffer size: {}", normalizeSpace(fileItemInput.getName()), bufferSize);
|
||||
}
|
||||
LOG.debug("Streaming file: {} using buffer size: {}", normalizeSpace(fileItemInput.getName()), bufferSize);
|
||||
for (int length; ((length = input.read(buffer)) > 0); ) {
|
||||
output.write(buffer, 0, length);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
*/
|
||||
package org.apache.struts2.ognl;
|
||||
|
||||
import org.apache.struts2.inject.Inject;
|
||||
import org.apache.struts2.util.ProxyUtil;
|
||||
import ognl.MemberAccess;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.inject.Inject;
|
||||
import org.apache.struts2.util.ProxyUtil;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Constructor;
|
||||
@@ -38,6 +38,10 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static java.text.MessageFormat.format;
|
||||
import static java.util.Collections.emptySet;
|
||||
import static org.apache.struts2.StrutsConstants.STRUTS_ALLOWLIST_CLASSES;
|
||||
import static org.apache.struts2.StrutsConstants.STRUTS_ALLOWLIST_PACKAGE_NAMES;
|
||||
import static org.apache.struts2.util.ConfigParseUtil.toClassObjectsSet;
|
||||
import static org.apache.struts2.util.ConfigParseUtil.toClassesSet;
|
||||
import static org.apache.struts2.util.ConfigParseUtil.toNewClassesSet;
|
||||
@@ -45,10 +49,6 @@ import static org.apache.struts2.util.ConfigParseUtil.toNewPackageNamesSet;
|
||||
import static org.apache.struts2.util.ConfigParseUtil.toNewPatternsSet;
|
||||
import static org.apache.struts2.util.ConfigParseUtil.toPackageNamesSet;
|
||||
import static org.apache.struts2.util.DebugUtils.logWarningForFirstOccurrence;
|
||||
import static java.text.MessageFormat.format;
|
||||
import static java.util.Collections.emptySet;
|
||||
import static org.apache.struts2.StrutsConstants.STRUTS_ALLOWLIST_CLASSES;
|
||||
import static org.apache.struts2.StrutsConstants.STRUTS_ALLOWLIST_PACKAGE_NAMES;
|
||||
|
||||
/**
|
||||
* Allows access decisions to be made on the basis of whether a member is static or not.
|
||||
@@ -141,6 +141,9 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
public boolean isAccessible(Map context, Object target, Member member, String propertyName) {
|
||||
LOG.debug("Checking access for [target: {}, member: {}, property: {}]", target, member, propertyName);
|
||||
|
||||
if (member == null) {
|
||||
throw new IllegalArgumentException("Member cannot be null!");
|
||||
}
|
||||
if (target != null) {
|
||||
// Special case: Target is a Class object but not Class.class
|
||||
if (Class.class.equals(target.getClass()) && !Class.class.equals(target)) {
|
||||
@@ -209,7 +212,7 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!disallowProxyObjectAccess && target != null && ProxyUtil.isProxy(target)) {
|
||||
if (!disallowProxyObjectAccess && ProxyUtil.isProxy(target)) {
|
||||
// If `disallowProxyObjectAccess` is not set, allow resolving Hibernate entities to their underlying
|
||||
// classes/members. This allows the allowlist capability to continue working and offer some level of
|
||||
// protection in applications where the developer has accepted the risk of allowing OGNL access to Hibernate
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
*/
|
||||
package org.apache.struts2.util;
|
||||
|
||||
import org.apache.struts2.ognl.DefaultOgnlCacheFactory;
|
||||
import org.apache.struts2.ognl.OgnlCache;
|
||||
import org.apache.struts2.ognl.OgnlCacheFactory;
|
||||
import org.apache.commons.lang3.reflect.ConstructorUtils;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
import org.apache.commons.lang3.reflect.MethodUtils;
|
||||
import org.apache.struts2.ognl.DefaultOgnlCacheFactory;
|
||||
import org.apache.struts2.ognl.OgnlCache;
|
||||
import org.apache.struts2.ognl.OgnlCacheFactory;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
@@ -81,6 +81,7 @@ public class ProxyUtil {
|
||||
* @param object the object to check
|
||||
*/
|
||||
public static boolean isProxy(Object object) {
|
||||
if (object == null) return false;
|
||||
Class<?> clazz = object.getClass();
|
||||
Boolean flag = isProxyCache.get(clazz);
|
||||
if (flag != null) {
|
||||
@@ -121,7 +122,7 @@ public class ProxyUtil {
|
||||
*/
|
||||
public static boolean isHibernateProxy(Object object) {
|
||||
try {
|
||||
return HibernateProxy.class.isAssignableFrom(object.getClass());
|
||||
return object != null && HibernateProxy.class.isAssignableFrom(object.getClass());
|
||||
} catch (NoClassDefFoundError ignored) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -18,18 +18,6 @@
|
||||
*/
|
||||
package org.apache.struts2.dispatcher;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.StrutsStatics;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
@@ -41,6 +29,22 @@ import jakarta.servlet.ServletContext;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import jakarta.servlet.jsp.PageContext;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class AttributeMapTest {
|
||||
|
||||
@@ -361,4 +365,21 @@ public class AttributeMapTest {
|
||||
assertEquals("value", value);
|
||||
}
|
||||
|
||||
}
|
||||
@Test
|
||||
public void get_whenPageContextHasNoRequest() {
|
||||
PageContext pageContext = mock(PageContext.class);
|
||||
when(pageContext.getRequest()).thenReturn(null);
|
||||
|
||||
var req = new MockHttpServletRequest();
|
||||
req.setAttribute("attr", "reqValue");
|
||||
|
||||
var attributeMap = new AttributeMap(Map.of(
|
||||
StrutsStatics.PAGE_CONTEXT, pageContext,
|
||||
DispatcherConstants.REQUEST, new RequestMap(req)
|
||||
));
|
||||
|
||||
assertEquals("reqValue", attributeMap.get("attr"));
|
||||
verify(pageContext, never()).findAttribute(anyString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-56
@@ -19,13 +19,7 @@
|
||||
package org.apache.struts2.dispatcher.multipart;
|
||||
|
||||
import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletDiskFileUpload;
|
||||
import org.apache.struts2.config.Configuration;
|
||||
import org.apache.struts2.config.ConfigurationManager;
|
||||
import org.apache.struts2.dispatcher.Dispatcher;
|
||||
import org.apache.struts2.dispatcher.LocalizedMessage;
|
||||
import org.apache.struts2.inject.Container;
|
||||
import org.apache.struts2.util.StrutsTestCaseHelper;
|
||||
import org.apache.struts2.views.jsp.StrutsMockServletContext;
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -37,7 +31,6 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -54,7 +47,6 @@ abstract class AbstractMultiPartRequestTest {
|
||||
protected final String endline = "\r\n";
|
||||
|
||||
protected AbstractMultiPartRequest multiPart;
|
||||
protected Container container;
|
||||
|
||||
abstract protected AbstractMultiPartRequest createMultipartRequest();
|
||||
|
||||
@@ -67,13 +59,7 @@ abstract class AbstractMultiPartRequestTest {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
StrutsMockServletContext servletContext = new StrutsMockServletContext();
|
||||
Dispatcher dispatcher = StrutsTestCaseHelper.initDispatcher(servletContext, Collections.emptyMap());
|
||||
ConfigurationManager configurationManager = dispatcher.getConfigurationManager();
|
||||
Configuration configuration = configurationManager.getConfiguration();
|
||||
container = configuration.getContainer();
|
||||
|
||||
public void before() {
|
||||
mockRequest = new MockHttpServletRequest();
|
||||
mockRequest.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
mockRequest.setMethod("post");
|
||||
@@ -506,47 +492,6 @@ abstract class AbstractMultiPartRequestTest {
|
||||
.containsExactly("struts.messages.upload.error.FileUploadException");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void maliciousFields() throws IOException {
|
||||
String content = formFile("file1", "test1.csv", "1,2,3,4") +
|
||||
formField("top.param", "expression") +
|
||||
endline + "--" + boundary + "--";
|
||||
|
||||
mockRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
assertThat(JakartaServletDiskFileUpload.isMultipartContent(mockRequest)).isTrue();
|
||||
|
||||
multiPart.parse(mockRequest, tempDir);
|
||||
|
||||
assertThat(multiPart.getErrors())
|
||||
.isEmpty();
|
||||
|
||||
assertThat(multiPart.getParameterNames().asIterator()).toIterable()
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void maliciousFilename() throws IOException {
|
||||
String content = formFile("file1", "../test1.csv", "1,2,3,4") +
|
||||
formField("param", "expression") +
|
||||
endline + "--" + boundary + "--";
|
||||
|
||||
mockRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
assertThat(JakartaServletDiskFileUpload.isMultipartContent(mockRequest)).isTrue();
|
||||
|
||||
multiPart.parse(mockRequest, tempDir);
|
||||
|
||||
assertThat(multiPart.getErrors())
|
||||
.isEmpty();
|
||||
|
||||
assertThat(multiPart.getParameterNames().asIterator()).toIterable()
|
||||
.hasSize(1);
|
||||
assertThat(multiPart.getParameterNames().asIterator()).toIterable()
|
||||
.containsOnly("param");
|
||||
assertThat(multiPart.getFileNames("file1")).isEmpty();
|
||||
}
|
||||
|
||||
protected String formFile(String fieldName, String filename, String content) {
|
||||
return endline +
|
||||
"--" + boundary + endline +
|
||||
|
||||
+1
-61
@@ -514,71 +514,11 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
|
||||
assertTrue(msg.startsWith("Der Request übertraf die maximal erlaubte Größe"));
|
||||
}
|
||||
|
||||
public void testUnacceptedFieldName() 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=\"top.file\"; filename=\"deleteme.txt\"\r\n" +
|
||||
"Content-Type: text/html\r\n" +
|
||||
"\r\n" +
|
||||
"Unit test of ActionFileUploadInterceptor" +
|
||||
"\r\n" +
|
||||
"-----1234--\r\n");
|
||||
request.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(createMultipartRequestMaxSize(2000));
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertFalse(action.hasActionErrors());
|
||||
assertNull(action.getUploadFiles());
|
||||
}
|
||||
|
||||
public void testUnacceptedFileName() 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 ActionFileUploadInterceptor" +
|
||||
"\r\n" +
|
||||
"-----1234--\r\n");
|
||||
request.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(createMultipartRequestMaxSize(2000));
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertFalse(action.hasActionErrors());
|
||||
assertNull(action.getUploadFiles());
|
||||
}
|
||||
|
||||
private String encodeTextFile(String filename, String contentType, String content) {
|
||||
return endline +
|
||||
"--" + boundary +
|
||||
endline +
|
||||
"Content-Disposition: form-data; name=\"" + "file" + "\"; filename=\"" + filename + "\"" +
|
||||
"Content-Disposition: form-data; name=\"" + "file" + "\"; filename=\"" + filename +
|
||||
endline +
|
||||
"Content-Type: " + contentType +
|
||||
endline +
|
||||
|
||||
@@ -18,17 +18,26 @@
|
||||
*/
|
||||
package org.apache.struts2.ognl;
|
||||
|
||||
import ognl.OgnlException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.core.LogEvent;
|
||||
import org.apache.logging.log4j.core.Logger;
|
||||
import org.apache.logging.log4j.core.appender.AbstractAppender;
|
||||
import org.apache.struts2.SimpleAction;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.TestBean;
|
||||
import org.apache.struts2.text.TextProvider;
|
||||
import org.apache.struts2.XWorkTestCase;
|
||||
import org.apache.struts2.config.ConfigurationException;
|
||||
import org.apache.struts2.config.DefaultPropertiesProvider;
|
||||
import org.apache.struts2.conversion.impl.ConversionData;
|
||||
import org.apache.struts2.conversion.impl.XWorkConverter;
|
||||
import org.apache.struts2.inject.ContainerBuilder;
|
||||
import org.apache.struts2.ognl.accessor.RootAccessor;
|
||||
import org.apache.struts2.test.StubConfigurationProvider;
|
||||
import org.apache.struts2.test.TestBean2;
|
||||
import org.apache.struts2.text.TextProvider;
|
||||
import org.apache.struts2.util.Bar;
|
||||
import org.apache.struts2.util.BarJunior;
|
||||
import org.apache.struts2.util.Cat;
|
||||
@@ -37,15 +46,6 @@ import org.apache.struts2.util.Foo;
|
||||
import org.apache.struts2.util.ValueStackFactory;
|
||||
import org.apache.struts2.util.location.LocatableProperties;
|
||||
import org.apache.struts2.util.reflection.ReflectionContextState;
|
||||
import ognl.OgnlException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.core.LogEvent;
|
||||
import org.apache.logging.log4j.core.Logger;
|
||||
import org.apache.logging.log4j.core.appender.AbstractAppender;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.config.DefaultPropertiesProvider;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -1234,6 +1234,33 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
assertNull("accessed private field (result not null) ?", accessedValue);
|
||||
}
|
||||
|
||||
public void testFindValueWithConstructorAndProxyChecks() {
|
||||
loadButSet(Map.of(
|
||||
StrutsConstants.STRUTS_DISALLOW_PROXY_OBJECT_ACCESS, Boolean.TRUE.toString(),
|
||||
StrutsConstants.STRUTS_DISALLOW_PROXY_MEMBER_ACCESS, Boolean.TRUE.toString()));
|
||||
refreshContainerFields();
|
||||
|
||||
String value = "test";
|
||||
String ognlResult = (String) vs.findValue(
|
||||
"new org.apache.struts2.ognl.OgnlValueStackTest$ValueHolder('" + value + "').value", String.class);
|
||||
|
||||
assertEquals(value, ognlResult);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unused", "ClassCanBeRecord"})
|
||||
public static class ValueHolder {
|
||||
// See testFindValueWithConstructorAndProxyChecks
|
||||
private final String value;
|
||||
|
||||
public ValueHolder(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
static class BadJavaBean {
|
||||
private int count;
|
||||
private int count2;
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ public class DefaultExcludedPatternsCheckerTest extends XWorkTestCase {
|
||||
|
||||
public void testDefaultExcludePatterns() throws Exception {
|
||||
// given
|
||||
List<String> prefixes = Arrays.asList("#[0].%s", "[0].%s", "top.%s", "%{[0].%s}", "%{#[0].%s}", "%{top.%s}", "%{#top.%s}", "%{#%s}", "%{%s}", "#%s", "top.param", "%{top.request}", "#top.param");
|
||||
List<String> prefixes = Arrays.asList("#[0].%s", "[0].%s", "top.%s", "%{[0].%s}", "%{#[0].%s}", "%{top.%s}", "%{#top.%s}", "%{#%s}", "%{%s}", "#%s");
|
||||
List<String> inners = Arrays.asList("servletRequest", "servletResponse", "servletContext", "application", "session", "struts", "request", "response", "dojo", "parameters");
|
||||
List<String> suffixes = Arrays.asList("['test']", "[\"test\"]", ".test");
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
<artifactId>struts2-jakarta</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-jakarta</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
<artifactId>struts2-velocity-tools-jsp-jakarta</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-jakarta</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
<artifactId>struts2-velocity-tools-view-jakarta</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-async-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-cdi-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-config-browser-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-convention-plugin</artifactId>
|
||||
|
||||
+102
-105
@@ -18,26 +18,27 @@
|
||||
*/
|
||||
package org.apache.struts2.convention;
|
||||
|
||||
import org.apache.struts2.action.Action;
|
||||
import org.apache.struts2.ActionContext;
|
||||
import org.apache.struts2.config.ConfigurationException;
|
||||
import org.apache.struts2.config.entities.PackageConfig;
|
||||
import org.apache.struts2.config.entities.ResultConfig;
|
||||
import org.apache.struts2.config.entities.ResultTypeConfig;
|
||||
import org.apache.struts2.inject.Container;
|
||||
import org.apache.struts2.inject.Inject;
|
||||
import org.apache.struts2.util.finder.ClassLoaderInterface;
|
||||
import org.apache.struts2.util.finder.ClassLoaderInterfaceDelegate;
|
||||
import org.apache.struts2.util.finder.ResourceFinder;
|
||||
import org.apache.struts2.util.finder.Test;
|
||||
import jakarta.servlet.ServletContext;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ActionContext;
|
||||
import org.apache.struts2.action.Action;
|
||||
import org.apache.struts2.config.ConfigurationException;
|
||||
import org.apache.struts2.config.entities.PackageConfig;
|
||||
import org.apache.struts2.config.entities.ResultConfig;
|
||||
import org.apache.struts2.config.entities.ResultTypeConfig;
|
||||
import org.apache.struts2.convention.annotation.Result;
|
||||
import org.apache.struts2.convention.annotation.Results;
|
||||
import org.apache.struts2.inject.Container;
|
||||
import org.apache.struts2.inject.Inject;
|
||||
import org.apache.struts2.util.TextParseUtil;
|
||||
import org.apache.struts2.util.finder.ClassLoaderInterface;
|
||||
import org.apache.struts2.util.finder.ClassLoaderInterfaceDelegate;
|
||||
import org.apache.struts2.util.finder.ResourceFinder;
|
||||
import org.apache.struts2.util.finder.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
@@ -123,23 +124,24 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
/**
|
||||
* Constructs the SimpleResultMapBuilder using the given result location.
|
||||
*
|
||||
* @param servletContext The ServletContext for finding the resources of the web application.
|
||||
* @param container The Xwork container
|
||||
* @param relativeResultTypes The list of result types that can have locations that are relative
|
||||
* and the result location (which is the resultPath plus the namespace) prepended to them.
|
||||
* @param servletContext The ServletContext for finding the resources of the web application.
|
||||
* @param container The Xwork container
|
||||
* @param relativeResultTypes The list of result types that can have locations that are relative
|
||||
* and the result location (which is the resultPath plus the namespace) prepended to them.
|
||||
*/
|
||||
@Inject
|
||||
public DefaultResultMapBuilder(ServletContext servletContext, Container container,
|
||||
@Inject(ConventionConstants.CONVENTION_RELATIVE_RESULT_TYPES) String relativeResultTypes) {
|
||||
@Inject(ConventionConstants.CONVENTION_RELATIVE_RESULT_TYPES) String relativeResultTypes) {
|
||||
this.servletContext = servletContext;
|
||||
this.relativeResultTypes = Set.of(relativeResultTypes.split("\\s*[,]\\s*"));
|
||||
this.conventionsService = container.getInstance(ConventionsService.class, container.getInstance(String.class, ConventionConstants.CONVENTION_CONVENTIONS_SERVICE));
|
||||
this.relativeResultTypes = TextParseUtil.commaDelimitedStringToSet(relativeResultTypes);
|
||||
String instanceName = container.getInstance(String.class, ConventionConstants.CONVENTION_CONVENTIONS_SERVICE);
|
||||
this.conventionsService = container.getInstance(ConventionsService.class, instanceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param flatResultLayout If 'true' result resources will be expected to be in the form
|
||||
* ${namespace}/${actionName}-${result}.${extension}, otherwise in the form
|
||||
* ${namespace}/${actionName}/${result}.${extension}
|
||||
* ${namespace}/${actionName}-${result}.${extension}, otherwise in the form
|
||||
* ${namespace}/${actionName}/${result}.${extension}
|
||||
*/
|
||||
@Inject(ConventionConstants.CONVENTION_RESULT_FLAT_LAYOUT)
|
||||
public void setFlatResultLayout(String flatResultLayout) {
|
||||
@@ -150,8 +152,8 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Map<String, ResultConfig> build(Class<?> actionClass,
|
||||
org.apache.struts2.convention.annotation.Action annotation, String actionName,
|
||||
PackageConfig packageConfig) {
|
||||
org.apache.struts2.convention.annotation.Action annotation, String actionName,
|
||||
PackageConfig packageConfig) {
|
||||
|
||||
// Get the default result location from the annotation or configuration
|
||||
String defaultResultPath = conventionsService.determineResultPath(actionClass);
|
||||
@@ -164,7 +166,7 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
// Check for resources with the action name
|
||||
final String namespace = packageConfig.getNamespace();
|
||||
if (namespace != null && namespace.startsWith("/")) {
|
||||
defaultResultPath = defaultResultPath + namespace.substring(1);
|
||||
defaultResultPath = defaultResultPath + namespace.substring(1);
|
||||
} else if (namespace != null) {
|
||||
defaultResultPath = defaultResultPath + namespace;
|
||||
}
|
||||
@@ -184,7 +186,7 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
Map<String, ResultConfig> results = new HashMap<>();
|
||||
Map<String, ResultTypeConfig> resultsByExtension = conventionsService.getResultTypesByExtension(packageConfig);
|
||||
createFromResources(actionClass, results, defaultResultPath, resultPrefix, actionName,
|
||||
packageConfig, resultsByExtension);
|
||||
packageConfig, resultsByExtension);
|
||||
|
||||
//get inherited @Results and @Result (class level)
|
||||
for (Class<?> clazz : ReflectionTools.getClassHierarchy(actionClass)) {
|
||||
@@ -202,11 +204,12 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
|
||||
/**
|
||||
* Creates results from @Results and @Result annotations
|
||||
* @param actionClass class to check for annotations
|
||||
* @param packageConfig packageConfig where the action will be located
|
||||
* @param defaultResultPath default result path
|
||||
* @param results map of results
|
||||
* @param resultsByExtension map of result types keyed by extension
|
||||
*
|
||||
* @param actionClass class to check for annotations
|
||||
* @param packageConfig packageConfig where the action will be located
|
||||
* @param defaultResultPath default result path
|
||||
* @param results map of results
|
||||
* @param resultsByExtension map of result types keyed by extension
|
||||
*/
|
||||
protected void createResultsFromAnnotations(Class<?> actionClass, PackageConfig packageConfig, String defaultResultPath,
|
||||
Map<String, ResultConfig> results, Map<String, ResultTypeConfig> resultsByExtension) {
|
||||
@@ -228,24 +231,23 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
* Creates any result types from the resources available in the web application. This scans the
|
||||
* web application resources using the servlet context.
|
||||
*
|
||||
* @param actionClass The action class the results are being built for.
|
||||
* @param results The results map to put the result configs created into.
|
||||
* @param resultPath The calculated path to the resources.
|
||||
* @param resultPrefix The prefix for the result. This is usually <code>/resultPath/actionName</code>.
|
||||
* @param actionName The action name which is used only for logging in this implementation.
|
||||
* @param packageConfig The package configuration which is passed along in order to determine
|
||||
* @param resultsByExtension The map of extensions to result type configuration instances.
|
||||
* @param actionClass The action class the results are being built for.
|
||||
* @param results The results map to put the result configs created into.
|
||||
* @param resultPath The calculated path to the resources.
|
||||
* @param resultPrefix The prefix for the result. This is usually <code>/resultPath/actionName</code>.
|
||||
* @param actionName The action name which is used only for logging in this implementation.
|
||||
* @param packageConfig The package configuration which is passed along in order to determine
|
||||
* @param resultsByExtension The map of extensions to result type configuration instances.
|
||||
*/
|
||||
protected void createFromResources(Class<?> actionClass, Map<String, ResultConfig> results,
|
||||
final String resultPath, final String resultPrefix, final String actionName,
|
||||
PackageConfig packageConfig, Map<String, ResultTypeConfig> resultsByExtension) {
|
||||
final String resultPath, final String resultPrefix, final String actionName,
|
||||
PackageConfig packageConfig, Map<String, ResultTypeConfig> resultsByExtension) {
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Searching for results in the Servlet container at [{}]" +
|
||||
" with result prefix of [#1]", resultPath, resultPrefix);
|
||||
LOG.trace("Searching for results in the Servlet container at [{}] with result prefix of [{}]",
|
||||
resultPath, resultPrefix);
|
||||
}
|
||||
|
||||
// Build from web application using the ServletContext
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<String> paths = servletContext.getResourcePaths(flatResultLayout ? resultPath : resultPrefix);
|
||||
if (paths != null) {
|
||||
for (String path : paths) {
|
||||
@@ -255,13 +257,12 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
if (StringUtils.isBlank(fileName) || StringUtils.startsWith(fileName, ".")) {
|
||||
LOG.trace("Ignoring file without name [{}]", path);
|
||||
continue;
|
||||
}
|
||||
else if(fileName.lastIndexOf(".") > 0){
|
||||
String suffix = fileName.substring(fileName.lastIndexOf(".")+1);
|
||||
} else if (fileName.lastIndexOf(".") > 0) {
|
||||
String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
|
||||
|
||||
if(conventionsService.getResultTypesByExtension(packageConfig).get(suffix) == null) {
|
||||
if (conventionsService.getResultTypesByExtension(packageConfig).get(suffix) == null) {
|
||||
LOG.debug("No result type defined for file suffix : [{}]. Ignoring file {}", suffix, fileName);
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,11 +271,10 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
}
|
||||
|
||||
// Building from the classpath
|
||||
String classPathLocation = resultPath.startsWith("/") ?
|
||||
resultPath.substring(1, resultPath.length()) : resultPath;
|
||||
String classPathLocation = resultPath.startsWith("/") ? resultPath.substring(1) : resultPath;
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Searching for results in the class path at [{}]"
|
||||
+ " with a result prefix of [{}] and action name [{}]", classPathLocation, resultPrefix,
|
||||
+ " with a result prefix of [{}] and action name [{}]", classPathLocation, resultPrefix,
|
||||
actionName);
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOG.error("Unable to scan directory [{}] for results", ex, classPathLocation);
|
||||
LOG.error("Unable to scan directory [{}] for results", classPathLocation, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,30 +320,28 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
}
|
||||
|
||||
private Test<URL> getResourceTest(final String resultPath, final String actionName) {
|
||||
return new Test<URL>() {
|
||||
public boolean test(URL url) {
|
||||
String urlStr = url.toString();
|
||||
int index = urlStr.lastIndexOf(resultPath);
|
||||
String path = urlStr.substring(index + resultPath.length());
|
||||
return path.startsWith(actionName);
|
||||
}
|
||||
return url -> {
|
||||
String urlStr = url.toString();
|
||||
int index = urlStr.lastIndexOf(resultPath);
|
||||
String path = urlStr.substring(index + resultPath.length());
|
||||
return path.startsWith(actionName);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes all the results for the given path.
|
||||
*
|
||||
* @param actionClass The action class the results are being built for.
|
||||
* @param path The path to build the result for.
|
||||
* @param resultPrefix The is the result prefix which is the result location plus the action name.
|
||||
* This is used to determine if the path contains a result code or not.
|
||||
* @param results The Map to place the result(s)
|
||||
* @param packageConfig The package config the results belong to.
|
||||
* @param resultsByExtension The map of extensions to result type configuration instances.
|
||||
* @param actionClass The action class the results are being built for.
|
||||
* @param path The path to build the result for.
|
||||
* @param resultPrefix The is the result prefix which is the result location plus the action name.
|
||||
* This is used to determine if the path contains a result code or not.
|
||||
* @param results The Map to place the result(s)
|
||||
* @param packageConfig The package config the results belong to.
|
||||
* @param resultsByExtension The map of extensions to result type configuration instances.
|
||||
*/
|
||||
protected void makeResults(Class<?> actionClass, String path, String resultPrefix,
|
||||
Map<String, ResultConfig> results, PackageConfig packageConfig,
|
||||
Map<String, ResultTypeConfig> resultsByExtension) {
|
||||
Map<String, ResultConfig> results, PackageConfig packageConfig,
|
||||
Map<String, ResultTypeConfig> resultsByExtension) {
|
||||
|
||||
if (path.startsWith(resultPrefix)) {
|
||||
int indexOfDot = path.indexOf('.', resultPrefix.length());
|
||||
@@ -351,26 +349,27 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
// This case is when the path doesn't contain a result code
|
||||
if (indexOfDot == resultPrefix.length()) {
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("The result file [{}] has no result code and therefore" +
|
||||
" will be associated with success, input and error by default. This might" +
|
||||
" be overridden by another result file or an annotation.", path);
|
||||
LOG.trace("""
|
||||
The result file [{}] has no result code and therefore
|
||||
will be associated with success, input and error by default.
|
||||
This might be overridden by another result file or an annotation.
|
||||
""".stripIndent(), path);
|
||||
}
|
||||
|
||||
addResult(actionClass, path, results, packageConfig, resultsByExtension, Action.SUCCESS);
|
||||
addResult(actionClass, path, results, packageConfig, resultsByExtension, Action.INPUT);
|
||||
addResult(actionClass, path, results, packageConfig, resultsByExtension, Action.ERROR);
|
||||
|
||||
// This case is when the path contains a result code
|
||||
// This case is when the path contains a result code
|
||||
} else if (indexOfDot > resultPrefix.length()) {
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("The result file [{}] has a result code and therefore" +
|
||||
" will be associated with only that result code.", path);
|
||||
LOG.trace("The result file [{}] has a result code and therefore will be associated with only that result code.", path);
|
||||
}
|
||||
|
||||
String resultCode = path.substring(resultPrefix.length() + 1, indexOfDot);
|
||||
ResultConfig result = createResultConfig(actionClass,
|
||||
new ResultInfo(resultCode, path, packageConfig, resultsByExtension),
|
||||
packageConfig, null);
|
||||
new ResultInfo(resultCode, path, packageConfig, resultsByExtension),
|
||||
packageConfig, null);
|
||||
results.put(resultCode, result);
|
||||
}
|
||||
}
|
||||
@@ -380,16 +379,16 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
* Checks if result was already assigned, if not checks global results first and if exists, adds reference to it.
|
||||
* If not, creates package specific result.
|
||||
*
|
||||
* @param actionClass The action class the results are being built for.
|
||||
* @param path The path to build the result for.
|
||||
* @param results The Map to place the result(s)
|
||||
* @param packageConfig The package config the results belong to.
|
||||
* @param resultsByExtension The map of extensions to result type configuration instances.
|
||||
* @param resultKey The result name to use
|
||||
* @param actionClass The action class the results are being built for.
|
||||
* @param path The path to build the result for.
|
||||
* @param results The Map to place the result(s)
|
||||
* @param packageConfig The package config the results belong to.
|
||||
* @param resultsByExtension The map of extensions to result type configuration instances.
|
||||
* @param resultKey The result name to use
|
||||
*/
|
||||
protected void addResult(Class<?> actionClass, String path, Map<String, ResultConfig> results,
|
||||
PackageConfig packageConfig, Map<String, ResultTypeConfig> resultsByExtension,
|
||||
String resultKey) {
|
||||
PackageConfig packageConfig, Map<String, ResultTypeConfig> resultsByExtension,
|
||||
String resultKey) {
|
||||
|
||||
if (!results.containsKey(resultKey)) {
|
||||
Map<String, ResultConfig> globalResults = packageConfig.getAllGlobalResults();
|
||||
@@ -405,8 +404,8 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
}
|
||||
|
||||
protected void createFromAnnotations(Map<String, ResultConfig> resultConfigs,
|
||||
String resultPath, PackageConfig packageConfig, Result[] results,
|
||||
Class<?> actionClass, Map<String, ResultTypeConfig> resultsByExtension) {
|
||||
String resultPath, PackageConfig packageConfig, Result[] results,
|
||||
Class<?> actionClass, Map<String, ResultTypeConfig> resultsByExtension) {
|
||||
// Check for multiple results on the class
|
||||
for (Result result : results) {
|
||||
for (String name : result.name()) {
|
||||
@@ -425,25 +424,23 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
* information from the annotation and anything that isn't specified will be fetched from the
|
||||
* PackageConfig defaults (if they exist).
|
||||
*
|
||||
* @param actionClass The action class the results are being built for.
|
||||
* @param info The result info that is used to create the ResultConfig instance.
|
||||
* @param packageConfig The PackageConfig to use to fetch defaults for result and parameters.
|
||||
* @param result (Optional) The result annotation to pull additional information from.
|
||||
* @return The ResultConfig or null if the Result annotation is given and the annotation is
|
||||
* targeted to some other action than this one.
|
||||
* @param actionClass The action class the results are being built for.
|
||||
* @param info The result info that is used to create the ResultConfig instance.
|
||||
* @param packageConfig The PackageConfig to use to fetch defaults for result and parameters.
|
||||
* @param result (Optional) The result annotation to pull additional information from.
|
||||
* @return The ResultConfig or null if the Result annotation is given and the annotation is
|
||||
* targeted to some other action than this one.
|
||||
*/
|
||||
@SuppressWarnings(value = {"unchecked"})
|
||||
protected ResultConfig createResultConfig(Class<?> actionClass, ResultInfo info,
|
||||
PackageConfig packageConfig, Result result) {
|
||||
protected ResultConfig createResultConfig(Class<?> actionClass, ResultInfo info, PackageConfig packageConfig, Result result) {
|
||||
// Look up by the type that was determined from the annotation or by the extension in the
|
||||
// ResultInfo class
|
||||
ResultTypeConfig resultTypeConfig = packageConfig.getAllResultTypeConfigs().get(info.type);
|
||||
if (resultTypeConfig == null) {
|
||||
throw new ConfigurationException("The Result type [" + info.type + "] which is" +
|
||||
" defined in the Result annotation on the class [" + actionClass + "] or determined" +
|
||||
" by the file extension or is the default result type for the PackageConfig of the" +
|
||||
" action, could not be found as a result-type defined for the Struts/XWork package [" +
|
||||
packageConfig.getName() + "]");
|
||||
" defined in the Result annotation on the class [" + actionClass + "] or determined" +
|
||||
" by the file extension or is the default result type for the PackageConfig of the" +
|
||||
" action, could not be found as a result-type defined for the Struts/XWork package [" +
|
||||
packageConfig.getName() + "]");
|
||||
}
|
||||
|
||||
// Add the default parameters for the result type config (if any)
|
||||
@@ -474,15 +471,15 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
public final String type;
|
||||
|
||||
public ResultInfo(String name, String location, PackageConfig packageConfig,
|
||||
Map<String, ResultTypeConfig> resultsByExtension) {
|
||||
Map<String, ResultTypeConfig> resultsByExtension) {
|
||||
this.name = name;
|
||||
this.location = location;
|
||||
this.type = determineType(location, packageConfig, resultsByExtension);
|
||||
}
|
||||
|
||||
public ResultInfo(String name, Result result, PackageConfig packageConfig,
|
||||
String resultPath, Class<?> actionClass,
|
||||
Map<String, ResultTypeConfig> resultsByExtension) {
|
||||
String resultPath, Class<?> actionClass,
|
||||
Map<String, ResultTypeConfig> resultsByExtension) {
|
||||
this.name = name;
|
||||
if (StringUtils.isNotBlank(result.type())) {
|
||||
this.type = result.type();
|
||||
@@ -490,8 +487,8 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
this.type = determineType(result.location(), packageConfig, resultsByExtension);
|
||||
} else {
|
||||
throw new ConfigurationException("The action class [" + actionClass + "] contains a " +
|
||||
"result annotation that has no type parameter and no location parameter. One of " +
|
||||
"these must be defined.");
|
||||
"result annotation that has no type parameter and no location parameter. One of " +
|
||||
"these must be defined.");
|
||||
}
|
||||
|
||||
// See if we can handle relative locations or not
|
||||
@@ -507,7 +504,7 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
}
|
||||
|
||||
String determineType(String location, PackageConfig packageConfig,
|
||||
Map<String, ResultTypeConfig> resultsByExtension) {
|
||||
Map<String, ResultTypeConfig> resultsByExtension) {
|
||||
int indexOfDot = location.lastIndexOf(".");
|
||||
if (indexOfDot > 0) {
|
||||
String extension = location.substring(indexOfDot + 1);
|
||||
@@ -516,7 +513,7 @@ public class DefaultResultMapBuilder implements ResultMapBuilder {
|
||||
return resultTypeConfig.getName();
|
||||
} else
|
||||
throw new ConfigurationException("Unable to find a result type for extension [" + extension + "] " +
|
||||
"in location attribute [" + location + "].");
|
||||
"in location attribute [" + location + "].");
|
||||
} else {
|
||||
return packageConfig.getFullDefaultResultType();
|
||||
}
|
||||
|
||||
+66
-40
@@ -18,36 +18,48 @@
|
||||
*/
|
||||
package org.apache.struts2.convention;
|
||||
|
||||
import jakarta.servlet.ServletContext;
|
||||
import org.apache.struts2.config.entities.PackageConfig;
|
||||
import org.apache.struts2.config.entities.ResultConfig;
|
||||
import org.apache.struts2.config.entities.ResultTypeConfig;
|
||||
import org.apache.struts2.inject.Container;
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.struts2.convention.actions.NoAnnotationAction;
|
||||
import org.apache.struts2.convention.actions.result.*;
|
||||
import org.apache.struts2.convention.actions.result.ActionLevelResultAction;
|
||||
import org.apache.struts2.convention.actions.result.ActionLevelResultsAction;
|
||||
import org.apache.struts2.convention.actions.result.ActionLevelResultsNamesAction;
|
||||
import org.apache.struts2.convention.actions.result.ClassLevelResultAction;
|
||||
import org.apache.struts2.convention.actions.result.ClassLevelResultsAction;
|
||||
import org.apache.struts2.convention.actions.result.GlobalResultAction;
|
||||
import org.apache.struts2.convention.actions.result.GlobalResultOverrideAction;
|
||||
import org.apache.struts2.convention.actions.result.InheritedResultExtends;
|
||||
import org.apache.struts2.convention.actions.result.InheritedResultsExtends;
|
||||
import org.apache.struts2.convention.actions.result.OverrideInheritedResultExtends;
|
||||
import org.apache.struts2.convention.actions.result.OverrideResultAction;
|
||||
import org.apache.struts2.convention.actions.resultpath.ClassLevelResultPathAction;
|
||||
import org.apache.struts2.convention.annotation.Action;
|
||||
import org.apache.struts2.inject.Container;
|
||||
import org.apache.struts2.result.ServletDispatcherResult;
|
||||
import org.easymock.EasyMock;
|
||||
import org.easymock.IAnswer;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import jakarta.servlet.ServletContext;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.struts2.convention.ReflectionTools.getAnnotation;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This class tests the simple result map builder.
|
||||
* </p>
|
||||
*/
|
||||
public class DefaultResultMapBuilderTest extends TestCase {
|
||||
public class DefaultResultMapBuilderTest {
|
||||
|
||||
private Container container;
|
||||
private ConventionsService conventionsService;
|
||||
|
||||
public void testBuild() throws Exception {
|
||||
@Test
|
||||
public void testBuild() {
|
||||
ServletContext context = mockServletContext("/WEB-INF/location");
|
||||
|
||||
// Test with a slash
|
||||
@@ -66,7 +78,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
verify(context, "/WEB-INF/location", results, false);
|
||||
}
|
||||
|
||||
public void testResultOverrride() throws Exception {
|
||||
@Test
|
||||
public void testResultOverride() throws Exception {
|
||||
ServletContext context = mockServletContext("/WEB-INF/location");
|
||||
|
||||
// Test with a slash
|
||||
@@ -80,7 +93,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
assertEquals("/WEB-INF/location/namespace/error-overriden.jsp", result.getParams().get("location"));
|
||||
}
|
||||
|
||||
public void testGlobalResult() throws Exception {
|
||||
@Test
|
||||
public void testGlobalResult() {
|
||||
|
||||
ServletContext context = mockServletContext("/WEB-INF/location");
|
||||
this.conventionsService = new ConventionsServiceImpl("/WEB-INF/location");
|
||||
@@ -105,8 +119,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
assertEquals("/globalError.jsp", result.getParams().get("location"));
|
||||
}
|
||||
|
||||
public void testGlobalResultOverride() throws Exception {
|
||||
|
||||
@Test
|
||||
public void testGlobalResultOverride() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
String resultPath = "/WEB-INF/location";
|
||||
// Setup some mock jsps
|
||||
@@ -139,7 +153,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
assertEquals(resultPath + "/namespace/action-error.jsp", result.getParams().get("location"));
|
||||
}
|
||||
|
||||
public void testNull() throws Exception {
|
||||
@Test
|
||||
public void testNull() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
EasyMock.expect(context.getResourcePaths("/WEB-INF/location/namespace/")).andReturn(null);
|
||||
EasyMock.replay(context);
|
||||
@@ -153,7 +168,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
EasyMock.verify(context);
|
||||
}
|
||||
|
||||
public void testResultPath() throws Exception {
|
||||
@Test
|
||||
public void testResultPath() {
|
||||
ServletContext context = mockServletContext("/class-level");
|
||||
|
||||
// Test with a result path
|
||||
@@ -164,7 +180,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
verify(context, "/class-level", results, false);
|
||||
}
|
||||
|
||||
public void testFromServletContextWithBadNames() throws Exception {
|
||||
@Test
|
||||
public void testFromServletContextWithBadNames() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
|
||||
// Setup some mock jsps
|
||||
@@ -184,7 +201,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
|
||||
}
|
||||
|
||||
public void testFromServletContext() throws Exception {
|
||||
@Test
|
||||
public void testFromServletContext() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
|
||||
// Setup some mock jsps
|
||||
@@ -218,7 +236,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
|
||||
}
|
||||
|
||||
public void testFromServletContextNotFlat() throws Exception {
|
||||
@Test
|
||||
public void testFromServletContextNotFlat() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
|
||||
// Setup some mock jsps
|
||||
@@ -254,7 +273,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
EasyMock.verify(context);
|
||||
}
|
||||
|
||||
public void testIgnoreFilesWithoutName() throws Exception {
|
||||
@Test
|
||||
public void testIgnoreFilesWithoutName() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
|
||||
// Setup some mock jsps
|
||||
@@ -278,7 +298,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
|
||||
}
|
||||
|
||||
public void testClassLevelSingleResultAnnotation() throws Exception {
|
||||
@Test
|
||||
public void testClassLevelSingleResultAnnotation() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
|
||||
// Setup some mock jsps
|
||||
@@ -301,7 +322,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
EasyMock.verify(context);
|
||||
}
|
||||
|
||||
public void testClassLevelInheritedSingleResultAnnotation() throws Exception {
|
||||
@Test
|
||||
public void testClassLevelInheritedSingleResultAnnotation() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
|
||||
// Setup some mock jsps
|
||||
@@ -324,7 +346,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
EasyMock.verify(context);
|
||||
}
|
||||
|
||||
public void testClassLevelOverwriteInheritedSingleResultAnnotation() throws Exception {
|
||||
@Test
|
||||
public void testClassLevelOverwriteInheritedSingleResultAnnotation() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
|
||||
// Setup some mock jsps
|
||||
@@ -349,7 +372,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
EasyMock.verify(context);
|
||||
}
|
||||
|
||||
public void testClassLevelMultipleResultAnnotation() throws Exception {
|
||||
@Test
|
||||
public void testClassLevelMultipleResultAnnotation() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
|
||||
// Setup some mock jsps
|
||||
@@ -388,7 +412,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
EasyMock.verify(context);
|
||||
}
|
||||
|
||||
public void testClassLevelInheritanceMultipleResultAnnotation() throws Exception {
|
||||
@Test
|
||||
public void testClassLevelInheritanceMultipleResultAnnotation() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
|
||||
// Setup some mock jsps
|
||||
@@ -427,7 +452,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
EasyMock.verify(context);
|
||||
}
|
||||
|
||||
public void testActionLevelSingleResultAnnotation() throws Exception {
|
||||
@Test
|
||||
public void testActionLevelSingleResultAnnotation() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
|
||||
// Setup some mock jsps
|
||||
@@ -450,7 +476,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
EasyMock.verify(context);
|
||||
}
|
||||
|
||||
public void testActionLevelMultipleResultAnnotation() throws Exception {
|
||||
@Test
|
||||
public void testActionLevelMultipleResultAnnotation() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
|
||||
// Setup some mock jsps
|
||||
@@ -485,7 +512,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
EasyMock.verify(context);
|
||||
}
|
||||
|
||||
public void testActionLevelMultipleResultNamesAnnotation() throws Exception {
|
||||
@Test
|
||||
public void testActionLevelMultipleResultNamesAnnotation() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
|
||||
// Setup some mock jsps
|
||||
@@ -520,7 +548,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
EasyMock.verify(context);
|
||||
}
|
||||
|
||||
public void testActionLevelMultipleResultNamesAnnotationNoName() throws Exception {
|
||||
@Test
|
||||
public void testActionLevelMultipleResultNamesAnnotationNoName() {
|
||||
ServletContext context = EasyMock.createStrictMock(ServletContext.class);
|
||||
|
||||
// Setup some mock jsps
|
||||
@@ -543,7 +572,8 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
EasyMock.verify(context);
|
||||
}
|
||||
|
||||
public void testClassPath() throws Exception {
|
||||
@Test
|
||||
public void testClassPath() {
|
||||
ServletContext context = EasyMock.createNiceMock(ServletContext.class);
|
||||
|
||||
ResultTypeConfig resultType = new ResultTypeConfig.Builder("freemarker", "org.apache.struts2.result.ServletDispatcherResult").
|
||||
@@ -600,8 +630,7 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
return context;
|
||||
}
|
||||
|
||||
private void verify(ServletContext context, String resultPath, Map<String, ResultConfig> results,
|
||||
boolean redirect) {
|
||||
private void verify(ServletContext context, String resultPath, Map<String, ResultConfig> results, boolean redirect) {
|
||||
assertEquals(4, results.size());
|
||||
assertEquals("success", results.get("success").getName());
|
||||
assertEquals("input", results.get("input").getName());
|
||||
@@ -633,16 +662,13 @@ public class DefaultResultMapBuilderTest extends TestCase {
|
||||
EasyMock.verify(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
@Before
|
||||
public void setup() {
|
||||
this.container = EasyMock.createNiceMock(Container.class);
|
||||
EasyMock.expect(container.getInstance(String.class, ConventionConstants.CONVENTION_CONVENTIONS_SERVICE)).andReturn("convention").anyTimes();
|
||||
EasyMock.expect(container.getInstance(ConventionsService.class, "convention")).andAnswer(new IAnswer<ConventionsService>() {
|
||||
public ConventionsService answer() throws Throwable {
|
||||
return DefaultResultMapBuilderTest.this.conventionsService;
|
||||
}
|
||||
}).anyTimes();
|
||||
EasyMock.expect(container.getInstance(String.class, ConventionConstants.CONVENTION_CONVENTIONS_SERVICE))
|
||||
.andReturn("convention").anyTimes();
|
||||
EasyMock.expect(container.getInstance(ConventionsService.class, "convention"))
|
||||
.andAnswer(() -> DefaultResultMapBuilderTest.this.conventionsService).anyTimes();
|
||||
EasyMock.replay(this.container);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-jasperreports-plugin</artifactId>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-javatemplates-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-jfreechart-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-json-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-junit-plugin</artifactId>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-rest-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-spring-plugin</artifactId>
|
||||
|
||||
+88
@@ -31,6 +31,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SecurityMemberAccessProxyTest extends XWorkJUnit4TestCase {
|
||||
@@ -87,4 +88,91 @@ public class SecurityMemberAccessProxyTest extends XWorkJUnit4TestCase {
|
||||
assertTrue(sma.isAccessible(context, proxy.getAction(), proxyObjectProxyMember, ""));
|
||||
assertTrue(sma.isAccessible(context, proxy.getAction(), proxyObjectNonProxyMember, ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullTargetAndTargetAndMemberNotAllowed() {
|
||||
sma.useDisallowProxyObjectAccess(Boolean.TRUE.toString());
|
||||
sma.useDisallowProxyMemberAccess(Boolean.TRUE.toString());
|
||||
assertTrue(sma.isAccessible(context, null, proxyObjectProxyMember, ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullTargetAndTargetAllowedAndMemberNotAllowed() {
|
||||
sma.useDisallowProxyObjectAccess(Boolean.FALSE.toString());
|
||||
sma.useDisallowProxyMemberAccess(Boolean.TRUE.toString());
|
||||
assertTrue(sma.isAccessible(context, null, proxyObjectProxyMember, ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullTargetAndTargetAndMemberAllowed() {
|
||||
sma.useDisallowProxyObjectAccess(Boolean.FALSE.toString());
|
||||
sma.useDisallowProxyMemberAccess(Boolean.FALSE.toString());
|
||||
assertTrue(sma.isAccessible(context, null, proxyObjectProxyMember, ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullMemberAndTargetAndMemberNotAllowed() {
|
||||
sma.useDisallowProxyObjectAccess(Boolean.TRUE.toString());
|
||||
sma.useDisallowProxyMemberAccess(Boolean.TRUE.toString());
|
||||
Object action = proxy.getAction();
|
||||
assertThrows("Member cannot be null!", IllegalArgumentException.class,
|
||||
() -> sma.isAccessible(context, action, null, ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullMemberAndTargetAllowedAndMemberNotAllowed() {
|
||||
sma.useDisallowProxyObjectAccess(Boolean.FALSE.toString());
|
||||
sma.useDisallowProxyMemberAccess(Boolean.TRUE.toString());
|
||||
Object action = proxy.getAction();
|
||||
assertThrows("Member cannot be null!", IllegalArgumentException.class,
|
||||
() -> sma.isAccessible(context, action, null, ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullMemberAndTargetNotAllowedAndMemberAllowed() {
|
||||
sma.useDisallowProxyObjectAccess(Boolean.TRUE.toString());
|
||||
sma.useDisallowProxyMemberAccess(Boolean.FALSE.toString());
|
||||
Object action = proxy.getAction();
|
||||
assertThrows("Member cannot be null!", IllegalArgumentException.class,
|
||||
() -> sma.isAccessible(context, action, null, ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullTargetAndMemberAndTargetAndMemberNotAllowed() {
|
||||
sma.useDisallowProxyObjectAccess(Boolean.TRUE.toString());
|
||||
sma.useDisallowProxyMemberAccess(Boolean.TRUE.toString());
|
||||
assertThrows("Member cannot be null!", IllegalArgumentException.class,
|
||||
() -> sma.isAccessible(context, null, null, ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullTargetAndMemberAndTargetNotAllowedAndMemberAllowed() {
|
||||
sma.useDisallowProxyObjectAccess(Boolean.TRUE.toString());
|
||||
sma.useDisallowProxyMemberAccess(Boolean.FALSE.toString());
|
||||
assertThrows("Member cannot be null!", IllegalArgumentException.class,
|
||||
() -> sma.isAccessible(context, null, null, ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullTargetAndMemberAndTargetAllowedAndMemberNotAllowed() {
|
||||
sma.useDisallowProxyObjectAccess(Boolean.FALSE.toString());
|
||||
sma.useDisallowProxyMemberAccess(Boolean.TRUE.toString());
|
||||
assertThrows("Member cannot be null!", IllegalArgumentException.class,
|
||||
() -> sma.isAccessible(context, null, null, ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullTargetAndMemberAndTargetAndMemberAllowed() {
|
||||
sma.useDisallowProxyObjectAccess(Boolean.FALSE.toString());
|
||||
sma.useDisallowProxyMemberAccess(Boolean.FALSE.toString());
|
||||
assertThrows("Member cannot be null!", IllegalArgumentException.class,
|
||||
() -> sma.isAccessible(context, null, null, ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullPropertyName() {
|
||||
sma.useDisallowProxyMemberAccess(Boolean.FALSE.toString());
|
||||
Object action = proxy.getAction();
|
||||
assertTrue(sma.isAccessible(context, action, proxyObjectProxyMember, null));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@ import org.apache.struts2.SimpleAction;
|
||||
import org.apache.struts2.TestBean;
|
||||
import org.apache.struts2.TestSubBean;
|
||||
import org.apache.struts2.XWorkTestCase;
|
||||
import org.apache.struts2.config.StrutsXmlConfigurationProvider;
|
||||
import org.apache.struts2.config.providers.XmlConfigurationProvider;
|
||||
import org.apache.struts2.util.ProxyUtil;
|
||||
import org.apache.struts2.config.StrutsXmlConfigurationProvider;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
@@ -46,6 +46,8 @@ public class SpringProxyUtilTest extends XWorkTestCase {
|
||||
}
|
||||
|
||||
public void testIsProxy() throws Exception {
|
||||
assertFalse(ProxyUtil.isProxy(null));
|
||||
|
||||
Object simpleAction = appContext.getBean("simple-action");
|
||||
assertFalse(ProxyUtil.isProxy(simpleAction));
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-testng-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-tiles-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-velocity-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-xslt-plugin</artifactId>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<version>7.0.3</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Struts 2</name>
|
||||
<url>https://struts.apache.org/</url>
|
||||
@@ -51,7 +51,7 @@
|
||||
<connection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</connection>
|
||||
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</developerConnection>
|
||||
<url>https://github.com/apache/struts/</url>
|
||||
<tag>STRUTS_7_0_1</tag>
|
||||
<tag>STRUTS_7_0_3</tag>
|
||||
</scm>
|
||||
|
||||
<issueManagement>
|
||||
@@ -104,7 +104,7 @@
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.build.outputTimestamp>2025-02-02T07:23:42Z</project.build.outputTimestamp>
|
||||
<project.build.outputTimestamp>2025-02-17T09:39:05Z</project.build.outputTimestamp>
|
||||
<maven.compiler.release>17</maven.compiler.release>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
@@ -807,7 +807,7 @@
|
||||
<dependency>
|
||||
<groupId>org.htmlunit</groupId>
|
||||
<artifactId>htmlunit</artifactId>
|
||||
<version>4.2.0</version>
|
||||
<version>4.9.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user