mirror of
https://github.com/apache/struts.git
synced 2026-08-08 16:16:58 +00:00
Compare commits
98 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 | |||
| f6bf43ae0b | |||
| 25d0338e63 | |||
| 01af64615f | |||
| ebc4e3516d | |||
| d5b94369d1 | |||
| c5cf2f8f99 | |||
| 10d3545ac2 | |||
| 05deb7b5e7 | |||
| 358f808567 | |||
| f98b67562b | |||
| 2def24c7db | |||
| 4e80f2661e | |||
| 9ba5c095fb | |||
| 8f4fa06855 | |||
| 181f0073ff | |||
| f3997f705e | |||
| b054b51929 | |||
| e0be8270ca | |||
| 32cd5d0dcc | |||
| c2a5bfe3c9 | |||
| fa60e1ceb2 | |||
| 4279511c5b | |||
| 71bca19c13 | |||
| 30aefaa5d3 | |||
| 2c023a245d | |||
| cebdf6df82 | |||
| 6d01916f12 | |||
| 6cc4a105e6 | |||
| b5d94a1f07 | |||
| 9e93bb51db | |||
| 0931b88b11 | |||
| 8dfc157be0 | |||
| 98df24a2a0 | |||
| fd24a4a9c8 | |||
| 026300b456 | |||
| b36f7bd9cc | |||
| 93943dbb33 | |||
| 18f3a49028 | |||
| 9e2f92f7af | |||
| f97e2c29bc | |||
| bd46f587a4 | |||
| e5825de28e | |||
| 6d71674cc1 | |||
| db9684e1c1 | |||
| ac9a02c685 | |||
| 9ac86ed61b | |||
| c0a720475b | |||
| cadb7a1fb2 | |||
| 4f1556c2d7 | |||
| 80b3108c86 | |||
| 375d00aa8e | |||
| 44ff04683a | |||
| 2850315cf3 | |||
| e695ac8a4e | |||
| 0114dff50d | |||
| 7c62bfc5a4 | |||
| 3be56a4840 | |||
| a9662ee583 | |||
| 43295b1f42 | |||
| faa3e723aa | |||
| 92b2cb9ee1 | |||
| 36ca20d3dc | |||
| bbdb38dedc | |||
| 552f7eba77 | |||
| 196aa3f366 | |||
| 0792d0586f | |||
| 6b07ee83ee | |||
| 0bcb6516bf | |||
| dba7510984 | |||
| d7188c18d2 | |||
| 1655838220 | |||
| e9a12dd94f | |||
| ddf80bec29 | |||
| e81caf5cec | |||
| 9d2eb5e607 | |||
| 9aa41f18ae |
@@ -11,6 +11,8 @@ notifications:
|
||||
jira_options: link label worklog
|
||||
|
||||
github:
|
||||
description: "Apache Struts is a free, open-source, MVC framework for creating elegant, modern Java web applications"
|
||||
homepage: https://struts.apache.org/
|
||||
del_branch_on_merge: true
|
||||
protected_branches:
|
||||
main:
|
||||
@@ -21,7 +23,7 @@ github:
|
||||
# it does not work because our github teams are private/secret, see INFRA-25666
|
||||
require_code_owner_reviews: false
|
||||
required_approving_review_count: 0
|
||||
release/*:
|
||||
release/struts-6-7-x:
|
||||
# contexts are the names of checks that must pass.
|
||||
contexts:
|
||||
- build
|
||||
|
||||
@@ -8,3 +8,4 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
ignore: []
|
||||
|
||||
@@ -52,12 +52,12 @@ jobs:
|
||||
java-version: 17
|
||||
cache: 'maven'
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3.27.7
|
||||
uses: github/codeql-action/init@v3.28.9
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3.27.7
|
||||
uses: github/codeql-action/autobuild@v3.28.9
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3.27.7
|
||||
uses: github/codeql-action/analyze@v3.28.9
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
@@ -58,13 +58,13 @@ jobs:
|
||||
publish_results: true
|
||||
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # 4.4.3
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # 4.6.0
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@89757925c7adddb19b7a2f28e3e1b27da88b7304 # 2.22.11
|
||||
uses: github/codeql-action/upload-sarif@0a35e8f6866a39b001e5f7ad1d0daf9836786896 # 2.22.11
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -44,6 +44,4 @@ jobs:
|
||||
- env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONARCLOUD_TOKEN }}
|
||||
MAIN_BRANCH: ${{ github.ref || github.base_ref || github.ref || github.base_ref }}
|
||||
if: ${{ github.ref == 'main' || github.base_ref == 'main' }}
|
||||
run: ./mvnw -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.branch.name=${{ env.MAIN_BRANCH }} -Pcoverage -DskipAssembly
|
||||
run: ./mvnw -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Pcoverage -DskipAssembly
|
||||
|
||||
Vendored
+3
@@ -87,6 +87,7 @@ pipeline {
|
||||
when {
|
||||
anyOf {
|
||||
branch 'main'
|
||||
branch 'release/struts-6-7-x'
|
||||
}
|
||||
}
|
||||
steps {
|
||||
@@ -100,6 +101,7 @@ pipeline {
|
||||
when {
|
||||
anyOf {
|
||||
branch 'main'
|
||||
branch 'release/struts-6-7-x'
|
||||
}
|
||||
}
|
||||
steps {
|
||||
@@ -112,6 +114,7 @@ pipeline {
|
||||
when {
|
||||
anyOf {
|
||||
branch 'main'
|
||||
branch 'release/struts-6-7-x'
|
||||
}
|
||||
}
|
||||
steps {
|
||||
|
||||
@@ -103,8 +103,15 @@ the Struts approach.
|
||||
|
||||
## Commercial Support
|
||||
|
||||
The Apache Struts community does not offer commercial support by itself.
|
||||
The Apache Struts community does not offer commercial support by itself, but we maintain [a list of companies offering
|
||||
commercial support on our website](https://struts.apache.org/commercial-support.html).
|
||||
|
||||
Some Apache Struts maintainers are working with [Tidelift](https://tidelift.com/) to provide commercial support and
|
||||
invest paid working time in the improvement of the Apache Struts framework. For more information, visit
|
||||
the [Tidelift resources regarding Apache Struts](https://tidelift.com/subscription/pkg/maven-org-apache-struts-struts2-core?utm_source=maven-org-apache-struts-struts2-core&utm_medium=referral&utm_campaign=readme)
|
||||
|
||||
## Thank you
|
||||
|
||||
[YourKit](https://www.yourkit.com/) is kindly supporting open source projects with its full-featured Java Profiler.
|
||||
YourKit is the creator of innovative and intelligent tools for profiling Java and .NET applications.
|
||||
As an Apache committer, you can get a free license at [YourKit's open source sponsorship program](https://www.yourkit.com/java/profiler/purchase/#os_license).
|
||||
|
||||
+3
-2
@@ -7,8 +7,9 @@ and what potential vulnerability it can have:
|
||||
|
||||
| Version | Supported |
|
||||
|---------|--------------------|
|
||||
| 6.x | :white_check_mark: |
|
||||
| 2.5.x | :white_check_mark: |
|
||||
| 7.x | :white_check_mark: |
|
||||
| 6.7.x | :white_check_mark: |
|
||||
| 2.5.x | ❌ |
|
||||
|
||||
## Reporting New Security Issues with thr Apache Struts
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>7.0.0</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.0</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-rest-showcase</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>7.0.0</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.0</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-showcase</artifactId>
|
||||
@@ -123,7 +123,7 @@
|
||||
<dependency>
|
||||
<groupId>org.sitemesh</groupId>
|
||||
<artifactId>sitemesh</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<version>3.2.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -207,7 +207,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>3.5.2</version>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>it.org.apache.struts2.showcase.*Test</include>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>7.0.0</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.0</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-bom</artifactId>
|
||||
<version>7.0.0</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.0</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_0</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.0</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
<artifactId>struts2-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
*/
|
||||
package org.apache.struts2.components;
|
||||
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
import org.apache.struts2.inject.Inject;
|
||||
import org.apache.struts2.ognl.ThreadAllowlist;
|
||||
import org.apache.struts2.util.CompoundRoot;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
import org.apache.struts2.util.reflection.ReflectionProvider;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
@@ -40,6 +43,7 @@ public class Debug extends UIBean {
|
||||
|
||||
protected ReflectionProvider reflectionProvider;
|
||||
|
||||
private ThreadAllowlist threadAllowlist;
|
||||
|
||||
public Debug(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
|
||||
super(stack, request, response);
|
||||
@@ -50,6 +54,11 @@ public class Debug extends UIBean {
|
||||
this.reflectionProvider = prov;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setThreadAllowlist(ThreadAllowlist threadAllowlist) {
|
||||
this.threadAllowlist = threadAllowlist;
|
||||
}
|
||||
|
||||
protected String getDefaultTemplate() {
|
||||
return TEMPLATE;
|
||||
}
|
||||
@@ -59,16 +68,19 @@ public class Debug extends UIBean {
|
||||
|
||||
if (showDebug()) {
|
||||
ValueStack stack = getStack();
|
||||
Iterator iter = stack.getRoot().iterator();
|
||||
List stackValues = new ArrayList(stack.getRoot().size());
|
||||
allowList(stack.getRoot());
|
||||
|
||||
Iterator<Object> iter = stack.getRoot().iterator();
|
||||
List<Object> stackValues = new ArrayList<>(stack.getRoot().size());
|
||||
while (iter.hasNext()) {
|
||||
Object o = iter.next();
|
||||
Map values;
|
||||
Map<String, Object> values;
|
||||
try {
|
||||
values = reflectionProvider.getBeanMap(o);
|
||||
} catch (Exception e) {
|
||||
throw new StrutsException("Caught an exception while getting the property values of " + o, e);
|
||||
}
|
||||
allowListClass(o);
|
||||
stackValues.add(new DebugMapEntry(o.getClass().getName(), values));
|
||||
}
|
||||
|
||||
@@ -77,6 +89,16 @@ public class Debug extends UIBean {
|
||||
return result;
|
||||
}
|
||||
|
||||
private void allowList(CompoundRoot root) {
|
||||
root.forEach(this::allowListClass);
|
||||
}
|
||||
|
||||
private void allowListClass(Object o) {
|
||||
threadAllowlist.allowClass(o.getClass());
|
||||
ClassUtils.getAllSuperclasses(o.getClass()).forEach(threadAllowlist::allowClass);
|
||||
ClassUtils.getAllInterfaces(o.getClass()).forEach(threadAllowlist::allowClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean end(Writer writer, String body) {
|
||||
if (showDebug()) {
|
||||
@@ -91,17 +113,17 @@ public class Debug extends UIBean {
|
||||
return (devMode || Boolean.TRUE == PrepareOperations.getDevModeOverride());
|
||||
}
|
||||
|
||||
private static class DebugMapEntry implements Map.Entry {
|
||||
private final Object key;
|
||||
private static class DebugMapEntry implements Map.Entry<String, Object> {
|
||||
private final String key;
|
||||
private Object value;
|
||||
|
||||
DebugMapEntry(Object key, Object value) {
|
||||
DebugMapEntry(String key, Object value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getKey() {
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
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.StrutsConstants;
|
||||
@@ -35,6 +34,7 @@ import org.apache.struts2.components.template.Template;
|
||||
import org.apache.struts2.components.template.TemplateEngine;
|
||||
import org.apache.struts2.components.template.TemplateEngineManager;
|
||||
import org.apache.struts2.components.template.TemplateRenderingContext;
|
||||
import org.apache.struts2.dispatcher.AttributeMap;
|
||||
import org.apache.struts2.dispatcher.StaticContentLoader;
|
||||
import org.apache.struts2.util.ComponentUtils;
|
||||
import org.apache.struts2.util.TextProviderHelper;
|
||||
@@ -48,6 +48,10 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.struts2.dispatcher.DispatcherConstants.ATTRIBUTES;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* UIBean is the standard superclass of all Struts UI components.
|
||||
@@ -300,7 +304,7 @@ import java.util.function.Function;
|
||||
* <!-- END SNIPPET: javascriptRelatedAttributes -->
|
||||
*
|
||||
* <!-- START SNIPPET: tooltipattributes -->
|
||||
*
|
||||
* <strong>Deprecated since 7.0.1</strong
|
||||
* <table border="1" summary="">
|
||||
* <tr>
|
||||
* <td>Attribute</td>
|
||||
@@ -344,7 +348,7 @@ import java.util.function.Function;
|
||||
*
|
||||
* <!-- START SNIPPET: tooltipdescription -->
|
||||
* <p>
|
||||
* <b>tooltipConfig is deprecated, use individual tooltip configuration attributes instead </b>
|
||||
* <strong>tooltipConfig is deprecated, use individual tooltip configuration attributes instead </strong>
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
@@ -380,7 +384,7 @@ import java.util.function.Function;
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: tooltipexample -->
|
||||
*
|
||||
* <strong>Deprecated since 7.0.1</strong>
|
||||
* <!-- Example 1: -->
|
||||
* <s:form
|
||||
* tooltipDelay="500"
|
||||
@@ -440,6 +444,9 @@ public abstract class UIBean extends Component {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(UIBean.class);
|
||||
|
||||
static final String TEMPLATE_DIR = "templateDir";
|
||||
static final String THEME = "theme";
|
||||
|
||||
protected static final String ATTR_FIELD_VALUE = "fieldValue";
|
||||
protected static final String ATTR_NAME_VALUE = "nameValue";
|
||||
protected static final String ATTR_VALUE = "value";
|
||||
@@ -602,13 +609,18 @@ public abstract class UIBean extends Component {
|
||||
result = findString(this.templateDir);
|
||||
}
|
||||
|
||||
// Check Request, Session, Application scopes
|
||||
if (isBlank(result)) {
|
||||
result = (String) getAttrMap().get(TEMPLATE_DIR);
|
||||
}
|
||||
|
||||
// Default template set
|
||||
if (StringUtils.isBlank(result)) {
|
||||
if (isBlank(result)) {
|
||||
result = defaultTemplateDir;
|
||||
}
|
||||
|
||||
// Defaults to 'template'
|
||||
if (StringUtils.isBlank(result)) {
|
||||
if (isBlank(result)) {
|
||||
result = "template";
|
||||
}
|
||||
|
||||
@@ -622,26 +634,36 @@ public abstract class UIBean extends Component {
|
||||
result = findString(this.theme);
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(result)) {
|
||||
if (isBlank(result)) {
|
||||
Form form = (Form) findAncestor(Form.class);
|
||||
if (form != null) {
|
||||
result = form.getTheme();
|
||||
}
|
||||
}
|
||||
|
||||
// Check Request, Session, Application scopes
|
||||
if (isBlank(result)) {
|
||||
result = (String) getAttrMap().get(THEME);
|
||||
}
|
||||
|
||||
// Default theme set
|
||||
if (StringUtils.isBlank(result)) {
|
||||
if (isBlank(result)) {
|
||||
result = defaultUITheme;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, Object> getAttrMap() {
|
||||
AttributeMap attrMap = (AttributeMap) getStack().getContext().get(ATTRIBUTES);
|
||||
return attrMap != null ? attrMap : emptyMap();
|
||||
}
|
||||
|
||||
public void evaluateParams() {
|
||||
String gotTheme = getTheme();
|
||||
|
||||
addParameter("templateDir", getTemplateDir());
|
||||
addParameter("theme", gotTheme);
|
||||
addParameter(TEMPLATE_DIR, getTemplateDir());
|
||||
addParameter(THEME, gotTheme);
|
||||
addParameter("template", template != null ? findString(template) : getDefaultTemplate());
|
||||
addParameter("dynamicAttributes", dynamicAttributes);
|
||||
addParameter("themeExpansionToken", uiThemeExpansionToken);
|
||||
@@ -968,6 +990,7 @@ public abstract class UIBean extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated(since = "7.0.1", forRemoval = true)
|
||||
protected Map<String, String> getTooltipConfig(UIBean component) {
|
||||
Object tooltipConfigObj = component.getAttributes().get("tooltipConfig");
|
||||
Map<String, String> result = new LinkedHashMap<>();
|
||||
@@ -1237,11 +1260,13 @@ public abstract class UIBean extends Component {
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="Set the tooltip of this particular component")
|
||||
@Deprecated(since = "7.0.1", forRemoval = true)
|
||||
public void setTooltip(String tooltip) {
|
||||
this.tooltip = tooltip;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="Deprecated. Use individual tooltip configuration attributes instead.")
|
||||
@Deprecated(since = "7.0.1", forRemoval = true)
|
||||
public void setTooltipConfig(String tooltipConfig) {
|
||||
this.tooltipConfig = tooltipConfig;
|
||||
}
|
||||
@@ -1252,22 +1277,26 @@ public abstract class UIBean extends Component {
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="Use JavaScript to generate tooltips", type="Boolean", defaultValue="false")
|
||||
@Deprecated(since = "7.0.1", forRemoval = true)
|
||||
public void setJavascriptTooltip(String javascriptTooltip) {
|
||||
this.javascriptTooltip = javascriptTooltip;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="CSS class applied to JavaScrip tooltips", defaultValue="StrutsTTClassic")
|
||||
@Deprecated(since = "7.0.1", forRemoval = true)
|
||||
public void setTooltipCssClass(String tooltipCssClass) {
|
||||
this.tooltipCssClass = tooltipCssClass;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="Delay in milliseconds, before showing JavaScript tooltips ",
|
||||
defaultValue="Classic")
|
||||
@Deprecated(since = "7.0.1", forRemoval = true)
|
||||
public void setTooltipDelay(String tooltipDelay) {
|
||||
this.tooltipDelay = tooltipDelay;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="Icon path used for image that will have the tooltip")
|
||||
@Deprecated(since = "7.0.1", forRemoval = true)
|
||||
public void setTooltipIconPath(String tooltipIconPath) {
|
||||
this.tooltipIconPath = tooltipIconPath;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -111,7 +111,7 @@ public class Dispatcher {
|
||||
*/
|
||||
public static final String REQUEST_POST_METHOD = "POST";
|
||||
|
||||
public static final String MULTIPART_FORM_DATA_REGEX = "^multipart/form-data(?:\\s*;\\s*boundary=[0-9a-zA-Z'()+_,\\-./:=?]{1,70})?(?:\\s*;\\s*charset=[a-zA-Z\\-0-9]{3,14})?";
|
||||
public static final String MULTIPART_FORM_DATA_REGEX = "^multipart/form-data(?:\\s*;\\s*boundary=[0-9a-zA-Z'\"()+_,\\-./:=?]{1,70})?(?:\\s*;\\s*charset=[a-zA-Z\\-0-9]{3,14})?";
|
||||
|
||||
private static final String CONFIG_SPLIT_REGEX = "\\s*,\\s*";
|
||||
|
||||
|
||||
+6
-10
@@ -26,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;
|
||||
@@ -284,18 +285,13 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 7.0.1, use {@link StringUtils#normalizeSpace(String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
protected String sanitizeNewlines(String before) {
|
||||
return before.replaceAll("\\R", "_");
|
||||
}
|
||||
|
||||
+7
-5
@@ -32,6 +32,8 @@ import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.normalizeSpace;
|
||||
|
||||
/**
|
||||
* Multipart form data request adapter for Jakarta Commons FileUpload package.
|
||||
*/
|
||||
@@ -47,11 +49,11 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
prepareServletFileUpload(charset, Path.of(saveDir));
|
||||
|
||||
for (DiskFileItem item : servletFileUpload.parseRequest(request)) {
|
||||
LOG.debug(() -> "Processing a form field: " + sanitizeNewlines(item.getFieldName()));
|
||||
LOG.debug(() -> "Processing a form field: " + normalizeSpace(item.getFieldName()));
|
||||
if (item.isFormField()) {
|
||||
processNormalFormField(item, charset);
|
||||
} else {
|
||||
LOG.debug(() -> "Processing a file: " + sanitizeNewlines(item.getFieldName()));
|
||||
LOG.debug(() -> "Processing a file: " + normalizeSpace(item.getFieldName()));
|
||||
processFileField(item);
|
||||
}
|
||||
}
|
||||
@@ -75,7 +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());
|
||||
LOG.debug("Item: {} is a normal form field", normalizeSpace(item.getName()));
|
||||
|
||||
List<String> values;
|
||||
String fieldName = item.getFieldName();
|
||||
@@ -100,7 +102,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
protected void processFileField(DiskFileItem item) {
|
||||
// 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: " + sanitizeNewlines(item.getFieldName()));
|
||||
LOG.debug(() -> "No file has been uploaded for the field: " + normalizeSpace(item.getFieldName()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -112,7 +114,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
}
|
||||
|
||||
if (item.isInMemory()) {
|
||||
LOG.warn("Storing uploaded files just in memory isn't supported currently, skipping file: {}!", item.getName());
|
||||
LOG.warn(() -> "Storing uploaded files just in memory isn't supported currently, skipping file: %s!".formatted(normalizeSpace(item.getName())));
|
||||
} else {
|
||||
UploadedFile uploadedFile = StrutsUploadedFile.Builder
|
||||
.create(item.getPath().toFile())
|
||||
|
||||
+9
-7
@@ -42,6 +42,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.normalizeSpace;
|
||||
|
||||
/**
|
||||
* Multi-part form data request adapter for Jakarta Commons FileUpload package that
|
||||
* leverages the streaming API rather than the traditional non-streaming API.
|
||||
@@ -71,10 +73,10 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
LOG.debug("Using Jakarta Stream API to process request");
|
||||
servletFileUpload.getItemIterator(request).forEachRemaining(item -> {
|
||||
if (item.isFormField()) {
|
||||
LOG.debug(() -> "Processing a form field: " + sanitizeNewlines(item.getFieldName()));
|
||||
LOG.debug(() -> "Processing a form field: " + normalizeSpace(item.getFieldName()));
|
||||
processFileItemAsFormField(item);
|
||||
} else {
|
||||
LOG.debug(() -> "Processing a file: " + sanitizeNewlines(item.getFieldName()));
|
||||
LOG.debug(() -> "Processing a file: " + normalizeSpace(item.getFieldName()));
|
||||
processFileItemAsFileField(item, location);
|
||||
}
|
||||
});
|
||||
@@ -141,7 +143,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
if (maxFiles != null && maxFiles == uploadedFiles.size()) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Cannot accept another file: {} as it will exceed max files: {}",
|
||||
sanitizeNewlines(fileItemInput.getName()), maxFiles);
|
||||
normalizeSpace(fileItemInput.getName()), maxFiles);
|
||||
}
|
||||
LocalizedMessage errorMessage = buildErrorMessage(
|
||||
FileUploadFileCountLimitException.class,
|
||||
@@ -160,7 +162,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
private void exceedsMaxSizeOfFiles(FileItemInput fileItemInput, File file, Long currentFilesSize) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("File: {} of size: {} exceeds allowed max size: {}, actual size of already uploaded files: {}",
|
||||
sanitizeNewlines(fileItemInput.getName()), file.length(), maxSizeOfFiles, currentFilesSize
|
||||
normalizeSpace(fileItemInput.getName()), file.length(), maxSizeOfFiles, currentFilesSize
|
||||
);
|
||||
}
|
||||
LocalizedMessage errorMessage = buildErrorMessage(
|
||||
@@ -174,7 +176,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
}
|
||||
if (!file.delete() && LOG.isWarnEnabled()) {
|
||||
LOG.warn("Cannot delete file: {} which exceeds maximum size: {} of all files!",
|
||||
sanitizeNewlines(fileItemInput.getName()), maxSizeOfFiles);
|
||||
normalizeSpace(fileItemInput.getName()), maxSizeOfFiles);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +189,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
protected void processFileItemAsFileField(FileItemInput fileItemInput, Path location) throws IOException {
|
||||
// Skip file uploads that don't have a file name - meaning that no file was selected.
|
||||
if (fileItemInput.getName() == null || fileItemInput.getName().trim().isEmpty()) {
|
||||
LOG.debug(() -> "No file has been uploaded for the field: " + sanitizeNewlines(fileItemInput.getFieldName()));
|
||||
LOG.debug(() -> "No file has been uploaded for the field: " + normalizeSpace(fileItemInput.getFieldName()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -230,7 +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];
|
||||
LOG.debug("Streaming file: {} using buffer size: {}", 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);
|
||||
}
|
||||
|
||||
@@ -242,6 +242,41 @@ class ContainerImpl implements Container {
|
||||
return toArray(parameterInjectors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets parameter injectors with nulls for optional dependencies.
|
||||
*
|
||||
* @param member to which the parameters belong
|
||||
* @param annotations on the parameters
|
||||
* @param parameterTypes parameter types
|
||||
* @return injections
|
||||
*/
|
||||
<M extends AccessibleObject & Member> List<ParameterInjector<?>> getParametersInjectorsWithNulls(
|
||||
M member,
|
||||
Annotation[][] annotations,
|
||||
Class<?>[] parameterTypes,
|
||||
String defaultName
|
||||
) throws MissingDependencyException {
|
||||
final List<ParameterInjector<?>> parameterInjectors = new ArrayList<>();
|
||||
|
||||
final Iterator<Annotation[]> annotationsIterator = Arrays.asList(annotations).iterator();
|
||||
for (Class<?> parameterType : parameterTypes) {
|
||||
Inject annotation = findInject(annotationsIterator.next());
|
||||
String name = annotation == null ? defaultName : annotation.value();
|
||||
Key<?> key = Key.newInstance(parameterType, name);
|
||||
try {
|
||||
parameterInjectors.add(createParameterInjector(key, member));
|
||||
} catch (MissingDependencyException e) {
|
||||
if (annotation != null && annotation.required()) {
|
||||
throw e;
|
||||
} else {
|
||||
parameterInjectors.add(createNullParameterInjector(key, member));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parameterInjectors;
|
||||
}
|
||||
|
||||
<T> ParameterInjector<T> createParameterInjector(Key<T> key, Member member) throws MissingDependencyException {
|
||||
final InternalFactory<? extends T> factory = getFactory(key);
|
||||
if (factory == null) {
|
||||
@@ -252,6 +287,23 @@ class ContainerImpl implements Container {
|
||||
return new ParameterInjector<>(externalContext, factory);
|
||||
}
|
||||
|
||||
<T> ParameterInjector<T> createNullParameterInjector(Key<T> key, Member member) {
|
||||
final InternalFactory<? extends T> factory = new InternalFactory<>() {
|
||||
@Override
|
||||
public T create(InternalContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends T> type() {
|
||||
return key.getType();
|
||||
}
|
||||
};
|
||||
|
||||
final ExternalContext<T> externalContext = ExternalContext.newInstance(member, key, this);
|
||||
return new ParameterInjector<>(externalContext, factory);
|
||||
}
|
||||
|
||||
private ParameterInjector<?>[] toArray(List<ParameterInjector<?>> parameterInjections) {
|
||||
return parameterInjections.toArray(new ParameterInjector[0]);
|
||||
}
|
||||
@@ -339,7 +391,7 @@ class ContainerImpl implements Container {
|
||||
|
||||
MissingDependencyException exception = null;
|
||||
Inject inject = null;
|
||||
ParameterInjector<?>[] parameters = null;
|
||||
List<ParameterInjector<?>> parameters = null;
|
||||
|
||||
try {
|
||||
inject = constructor.getAnnotation(Inject.class);
|
||||
@@ -347,7 +399,7 @@ class ContainerImpl implements Container {
|
||||
} catch (MissingDependencyException e) {
|
||||
exception = e;
|
||||
}
|
||||
parameterInjectors = parameters;
|
||||
parameterInjectors = parameters != null ? container.toArray(parameters) : null;
|
||||
|
||||
if (exception != null) {
|
||||
if (inject != null && inject.required()) {
|
||||
@@ -357,11 +409,11 @@ class ContainerImpl implements Container {
|
||||
injectors = container.injectors.get(implementation);
|
||||
}
|
||||
|
||||
ParameterInjector<?>[] constructParameterInjector(
|
||||
List<ParameterInjector<?>> constructParameterInjector(
|
||||
Inject inject, ContainerImpl container, Constructor<T> constructor) throws MissingDependencyException {
|
||||
return constructor.getParameterTypes().length == 0
|
||||
? null // default constructor.
|
||||
: container.getParametersInjectors(
|
||||
: container.getParametersInjectorsWithNulls(
|
||||
constructor,
|
||||
constructor.getParameterAnnotations(),
|
||||
constructor.getParameterTypes(),
|
||||
|
||||
+55
-53
@@ -18,11 +18,14 @@
|
||||
*/
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.config.entities.ExceptionMappingConfig;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.inject.Inject;
|
||||
import org.apache.struts2.ognl.ThreadAllowlist;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -42,11 +45,11 @@ import java.util.Map;
|
||||
* you make this interceptor the first interceptor on the stack, ensuring that it has full access to catch any
|
||||
* exception, even those caused by other interceptors.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <p><u>Interceptor parameters:</u></p>
|
||||
*
|
||||
* <p>
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
*
|
||||
* <ul>
|
||||
@@ -64,11 +67,11 @@ import java.util.Map;
|
||||
* The parameters above enables us to log all thrown exceptions with stacktace in our own logfile,
|
||||
* and present a friendly webpage (with no stacktrace) to the end user.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
*
|
||||
* <p><u>Extending the interceptor:</u></p>
|
||||
*
|
||||
* <p>
|
||||
* <!-- START SNIPPET: extending -->
|
||||
* <p>
|
||||
* If you want to add custom handling for publishing the Exception, you may override
|
||||
@@ -158,11 +161,17 @@ public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ExceptionMappingInterceptor.class);
|
||||
|
||||
private transient ThreadAllowlist threadAllowlist;
|
||||
|
||||
protected Logger categoryLogger;
|
||||
protected boolean logEnabled = false;
|
||||
protected String logCategory;
|
||||
protected String logLevel;
|
||||
|
||||
@Inject
|
||||
public void setThreadAllowlist(ThreadAllowlist threadAllowlist) {
|
||||
this.threadAllowlist = threadAllowlist;
|
||||
}
|
||||
|
||||
public boolean isLogEnabled() {
|
||||
return logEnabled;
|
||||
@@ -173,20 +182,20 @@ public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
|
||||
public String getLogCategory() {
|
||||
return logCategory;
|
||||
}
|
||||
return logCategory;
|
||||
}
|
||||
|
||||
public void setLogCategory(String logCatgory) {
|
||||
this.logCategory = logCatgory;
|
||||
}
|
||||
public void setLogCategory(String logCategory) {
|
||||
this.logCategory = logCategory;
|
||||
}
|
||||
|
||||
public String getLogLevel() {
|
||||
return logLevel;
|
||||
}
|
||||
public String getLogLevel() {
|
||||
return logLevel;
|
||||
}
|
||||
|
||||
public void setLogLevel(String logLevel) {
|
||||
this.logLevel = logLevel;
|
||||
}
|
||||
public void setLogLevel(String logLevel) {
|
||||
this.logLevel = logLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
@@ -200,13 +209,16 @@ public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
List<ExceptionMappingConfig> exceptionMappings = invocation.getProxy().getConfig().getExceptionMappings();
|
||||
ExceptionMappingConfig mappingConfig = this.findMappingFromExceptions(exceptionMappings, e);
|
||||
if (mappingConfig != null && mappingConfig.getResult()!=null) {
|
||||
if (mappingConfig != null && mappingConfig.getResult() != null) {
|
||||
Map<String, String> mappingParams = mappingConfig.getParams();
|
||||
// create a mutable HashMap since some interceptors will remove parameters, and parameterMap is immutable
|
||||
HttpParameters parameters = HttpParameters.create(mappingParams).build();
|
||||
invocation.getInvocationContext().withParameters(parameters);
|
||||
result = mappingConfig.getResult();
|
||||
publishException(invocation, new ExceptionHolder(e));
|
||||
ExceptionHolder holder = new ExceptionHolder(e);
|
||||
threadAllowlist.allowClass(holder.getClass());
|
||||
threadAllowlist.allowClass(e.getClass());
|
||||
publishException(invocation, holder);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
@@ -221,55 +233,45 @@ public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
* @param e the exception to log.
|
||||
*/
|
||||
protected void handleLogging(Exception e) {
|
||||
if (logCategory != null) {
|
||||
if (categoryLogger == null) {
|
||||
// init category logger
|
||||
categoryLogger = LogManager.getLogger(logCategory);
|
||||
}
|
||||
doLog(categoryLogger, e);
|
||||
} else {
|
||||
doLog(LOG, e);
|
||||
}
|
||||
if (logCategory != null) {
|
||||
if (categoryLogger == null) {
|
||||
// init category logger
|
||||
categoryLogger = LogManager.getLogger(logCategory);
|
||||
}
|
||||
doLog(categoryLogger, e);
|
||||
} else {
|
||||
doLog(LOG, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual logging.
|
||||
*
|
||||
* @param logger the provided logger to use.
|
||||
* @param e the exception to log.
|
||||
* @param logger the provided logger to use.
|
||||
* @param e the exception to log.
|
||||
*/
|
||||
protected void doLog(Logger logger, Exception e) {
|
||||
if (logLevel == null) {
|
||||
logger.debug(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
if (logLevel == null) {
|
||||
logger.debug(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
|
||||
if ("trace".equalsIgnoreCase(logLevel)) {
|
||||
logger.trace(e.getMessage(), e);
|
||||
} else if ("debug".equalsIgnoreCase(logLevel)) {
|
||||
logger.debug(e.getMessage(), e);
|
||||
} else if ("info".equalsIgnoreCase(logLevel)) {
|
||||
logger.info(e.getMessage(), e);
|
||||
} else if ("warn".equalsIgnoreCase(logLevel)) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
} else if ("error".equalsIgnoreCase(logLevel)) {
|
||||
logger.error(e.getMessage(), e);
|
||||
} else if ("fatal".equalsIgnoreCase(logLevel)) {
|
||||
logger.fatal(e.getMessage(), e);
|
||||
} else {
|
||||
throw new IllegalArgumentException("LogLevel [" + logLevel + "] is not supported");
|
||||
}
|
||||
Level level = Level.getLevel(logLevel);
|
||||
if (level == null) {
|
||||
throw new IllegalArgumentException("LogLevel [" + logLevel + "] is not supported");
|
||||
}
|
||||
logger.log(level, e.getMessage(), e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find appropriate {@link ExceptionMappingConfig} based on provided Throwable
|
||||
*
|
||||
* @param exceptionMappings list of defined exception mappings
|
||||
* @param t caught exception
|
||||
* @param t caught exception
|
||||
* @return appropriate mapping or null
|
||||
*/
|
||||
protected ExceptionMappingConfig findMappingFromExceptions(List<ExceptionMappingConfig> exceptionMappings, Throwable t) {
|
||||
ExceptionMappingConfig config = null;
|
||||
ExceptionMappingConfig config = null;
|
||||
// Check for specific exception mappings.
|
||||
if (exceptionMappings != null) {
|
||||
int deepest = Integer.MAX_VALUE;
|
||||
@@ -288,15 +290,15 @@ public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
* Return the depth to the superclass matching. 0 means ex matches exactly. Returns -1 if there's no match.
|
||||
* Otherwise, returns depth. Lowest depth wins.
|
||||
*
|
||||
* @param exceptionMapping the mapping classname
|
||||
* @param t the cause
|
||||
* @param exceptionMapping the mapping classname
|
||||
* @param t the cause
|
||||
* @return the depth, if not found -1 is returned.
|
||||
*/
|
||||
public int getDepth(String exceptionMapping, Throwable t) {
|
||||
return getDepth(exceptionMapping, t.getClass(), 0);
|
||||
}
|
||||
|
||||
private int getDepth(String exceptionMapping, Class exceptionClass, int depth) {
|
||||
private int getDepth(String exceptionMapping, Class<?> exceptionClass, int depth) {
|
||||
if (exceptionClass.getName().contains(exceptionMapping)) {
|
||||
// Found it!
|
||||
return depth;
|
||||
@@ -312,7 +314,7 @@ public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
* Default implementation to handle ExceptionHolder publishing. Pushes given ExceptionHolder on the stack.
|
||||
* Subclasses may override this to customize publishing.
|
||||
*
|
||||
* @param invocation The invocation to publish Exception for.
|
||||
* @param invocation The invocation to publish Exception for.
|
||||
* @param exceptionHolder The exceptionHolder wrapping the Exception to publish.
|
||||
*/
|
||||
protected void publishException(ActionInvocation invocation, ExceptionHolder exceptionHolder) {
|
||||
|
||||
+34
-19
@@ -18,21 +18,23 @@
|
||||
*/
|
||||
package org.apache.struts2.interceptor.debugging;
|
||||
|
||||
import org.apache.struts2.ActionContext;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.inject.Inject;
|
||||
import org.apache.struts2.interceptor.AbstractInterceptor;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
import org.apache.struts2.util.reflection.ReflectionProvider;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ActionContext;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.DispatcherConstants;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.dispatcher.PrepareOperations;
|
||||
import org.apache.struts2.dispatcher.RequestMap;
|
||||
import org.apache.struts2.inject.Inject;
|
||||
import org.apache.struts2.interceptor.AbstractInterceptor;
|
||||
import org.apache.struts2.ognl.ThreadAllowlist;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
import org.apache.struts2.util.reflection.ReflectionProvider;
|
||||
import org.apache.struts2.views.freemarker.FreemarkerManager;
|
||||
import org.apache.struts2.views.freemarker.FreemarkerResult;
|
||||
|
||||
@@ -101,10 +103,10 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
|
||||
private final String[] ignorePrefixes = new String[]{"org.apache.struts.", "org.apache.struts2.", "xwork."};
|
||||
private final Set<String> ignoreKeys = Set.of(
|
||||
DispatcherConstants.APPLICATION,
|
||||
DispatcherConstants.SESSION,
|
||||
DispatcherConstants.PARAMETERS,
|
||||
DispatcherConstants.REQUEST
|
||||
DispatcherConstants.APPLICATION,
|
||||
DispatcherConstants.SESSION,
|
||||
DispatcherConstants.PARAMETERS,
|
||||
DispatcherConstants.REQUEST
|
||||
);
|
||||
|
||||
private final static String XML_MODE = "xml";
|
||||
@@ -126,6 +128,7 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
|
||||
private boolean consoleEnabled = false;
|
||||
private ReflectionProvider reflectionProvider;
|
||||
private transient ThreadAllowlist threadAllowlist;
|
||||
|
||||
@Inject(StrutsConstants.STRUTS_DEVMODE)
|
||||
public void setDevMode(String mode) {
|
||||
@@ -142,6 +145,11 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
this.reflectionProvider = reflectionProvider;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setThreadAllowlist(ThreadAllowlist threadAllowlist) {
|
||||
this.threadAllowlist = threadAllowlist;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
@@ -200,7 +208,7 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
res.setContentType("text/plain");
|
||||
|
||||
try (PrintWriter writer =
|
||||
ServletActionContext.getResponse().getWriter()) {
|
||||
ServletActionContext.getResponse().getWriter()) {
|
||||
writer.print(stack.findValue(cmd));
|
||||
} catch (IOException ex) {
|
||||
LOG.warn("Interceptor in: {} mode has failed!", COMMAND_MODE, ex);
|
||||
@@ -217,6 +225,7 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
String decorate = getParameter(DECORATE_PARAM);
|
||||
ValueStack stack = ctx.getValueStack();
|
||||
Object rootObject = stack.findValue(rootObjectExpression);
|
||||
allowListClass(rootObject);
|
||||
|
||||
try (StringWriter writer = new StringWriter()) {
|
||||
ObjectToHTMLWriter htmlWriter = new ObjectToHTMLWriter(writer);
|
||||
@@ -228,8 +237,9 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
|
||||
//on the first request, response can be decorated
|
||||
//but we need plain text on the other ones
|
||||
if ("false".equals(decorate))
|
||||
if ("false".equals(decorate)) {
|
||||
ServletActionContext.getRequest().setAttribute("decorator", "none");
|
||||
}
|
||||
|
||||
FreemarkerResult result = new FreemarkerResult();
|
||||
result.setFreemarkerManager(freemarkerManager);
|
||||
@@ -239,7 +249,6 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Unable to create debugging console", ex);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -262,6 +271,14 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
}
|
||||
|
||||
private void allowListClass(Object o) {
|
||||
if (o != null) {
|
||||
threadAllowlist.allowClass(o.getClass());
|
||||
ClassUtils.getAllSuperclasses(o.getClass()).forEach(threadAllowlist::allowClass);
|
||||
ClassUtils.getAllInterfaces(o.getClass()).forEach(threadAllowlist::allowClass);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a single string from the request parameters
|
||||
*
|
||||
@@ -277,12 +294,11 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
* Prints the current context to the response in XML format.
|
||||
*/
|
||||
protected void printContext() {
|
||||
HttpServletResponse res = ServletActionContext.getResponse();
|
||||
res.setContentType("text/xml");
|
||||
HttpServletResponse response = ActionContext.getContext().getServletResponse();
|
||||
response.setContentType("text/xml");
|
||||
|
||||
try {
|
||||
PrettyPrintWriter writer = new PrettyPrintWriter(
|
||||
ServletActionContext.getResponse().getWriter());
|
||||
PrettyPrintWriter writer = new PrettyPrintWriter(response.getWriter());
|
||||
printContext(writer);
|
||||
writer.close();
|
||||
} catch (IOException ex) {
|
||||
@@ -311,6 +327,7 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
}
|
||||
if (print) {
|
||||
allowListClass(ctxMap.get(key));
|
||||
serializeIt(ctxMap.get(key), key, writer, new ArrayList<>());
|
||||
}
|
||||
}
|
||||
@@ -426,5 +443,3 @@ public class DebuggingInterceptor extends AbstractInterceptor {
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,15 +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.ognl.ProviderAllowlist;
|
||||
import org.apache.struts2.ognl.ThreadAllowlist;
|
||||
import org.apache.struts2.inject.Inject;
|
||||
import org.apache.struts2.util.ProxyUtil;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Constructor;
|
||||
@@ -40,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;
|
||||
@@ -47,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.
|
||||
@@ -143,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)) {
|
||||
@@ -211,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
|
||||
|
||||
@@ -36,7 +36,8 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
|
||||
private static final Logger LOG = LogManager.getLogger(DefaultExcludedPatternsChecker.class);
|
||||
|
||||
public static final String[] EXCLUDED_PATTERNS = {
|
||||
"(^|\\%\\{)((#?)(top(\\.|\\['|\\[\")|\\[\\d\\]\\.)?)(dojo|struts|session|request|response|application|servlet(Request|Response|Context)|parameters|context|_memberAccess)(\\.|\\[).*",
|
||||
"(^|\\%\\{)(#?top\\.)[^\\s]*",
|
||||
"(^|\\%\\{)((#?)(\\[\\d\\]\\.)?)(dojo|struts|session|request|response|application|servlet(Request|Response|Context)|parameters|context|_memberAccess)(\\.|\\[).*",
|
||||
".*(^|\\.|\\[|\\'|\"|get)class(\\(\\.|\\[|\\'|\").*",
|
||||
"actionErrors|actionMessages|fieldErrors"
|
||||
};
|
||||
|
||||
@@ -38,7 +38,7 @@ public final class DebugUtils {
|
||||
}
|
||||
log.error(message);
|
||||
if (action instanceof ValidationAware validationAware) {
|
||||
validationAware.addActionError(message);
|
||||
validationAware.addActionMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ import org.apache.struts2.dispatcher.AttributeMap;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.jsp.PageContext;
|
||||
|
||||
import static org.apache.struts2.dispatcher.DispatcherConstants.ATTRIBUTES;
|
||||
|
||||
public class TagUtils {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(TagUtils.class);
|
||||
@@ -46,8 +48,8 @@ public class TagUtils {
|
||||
} else {
|
||||
LOG.trace("Adds the current PageContext to ActionContext");
|
||||
stack.getActionContext()
|
||||
.withPageContext(pageContext)
|
||||
.with("attr", new AttributeMap(stack.getContext()));
|
||||
.withPageContext(pageContext)
|
||||
.with(ATTRIBUTES, new AttributeMap(stack.getContext()));
|
||||
}
|
||||
|
||||
return stack;
|
||||
|
||||
@@ -261,10 +261,12 @@ public abstract class AbstractUITag extends ComponentTagSupport implements Dynam
|
||||
this.onchange = onchange;
|
||||
}
|
||||
|
||||
@Deprecated(since = "7.0.1", forRemoval = true)
|
||||
public void setTooltip(String tooltip) {
|
||||
this.tooltip = tooltip;
|
||||
}
|
||||
|
||||
@Deprecated(since = "7.0.1", forRemoval = true)
|
||||
public void setTooltipConfig(String tooltipConfig) {
|
||||
this.tooltipConfig = tooltipConfig;
|
||||
}
|
||||
@@ -277,18 +279,22 @@ public abstract class AbstractUITag extends ComponentTagSupport implements Dynam
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Deprecated(since = "7.0.1", forRemoval = true)
|
||||
public void setJavascriptTooltip(String javascriptTooltip) {
|
||||
this.javascriptTooltip = javascriptTooltip;
|
||||
}
|
||||
|
||||
@Deprecated(since = "7.0.1", forRemoval = true)
|
||||
public void setTooltipCssClass(String tooltipCssClass) {
|
||||
this.tooltipCssClass = tooltipCssClass;
|
||||
}
|
||||
|
||||
@Deprecated(since = "7.0.1", forRemoval = true)
|
||||
public void setTooltipDelay(String tooltipDelay) {
|
||||
this.tooltipDelay = tooltipDelay;
|
||||
}
|
||||
|
||||
@Deprecated(since = "7.0.1", forRemoval = true)
|
||||
public void setTooltipIconPath(String tooltipIconPath) {
|
||||
this.tooltipIconPath = tooltipIconPath;
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<@s.style>
|
||||
<html lang="en">
|
||||
<style>
|
||||
.debugTable {
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
@@ -50,40 +50,40 @@
|
||||
.emptyCollection {
|
||||
background-color: #EEEEEE;
|
||||
}
|
||||
</@s.style>
|
||||
</style>
|
||||
|
||||
<@s.script>
|
||||
<script>
|
||||
function expand(src, path) {
|
||||
var baseUrl = location.href;
|
||||
var i = baseUrl.indexOf("&object=");
|
||||
let baseUrl = location.href;
|
||||
const i = baseUrl.indexOf('&object=');
|
||||
baseUrl = (i > 0 ? baseUrl.substring(0, i) : baseUrl) + "&object=" + path;
|
||||
if (baseUrl.indexOf("decorate") < 0) {
|
||||
baseUrl += "&decorate=false";
|
||||
}
|
||||
|
||||
var request = new XMLHttpRequest();
|
||||
const request = new XMLHttpRequest();
|
||||
request.open('GET', baseUrl, true);
|
||||
request.onreadystatechange = function() {
|
||||
if (this.readyState === 4) {
|
||||
if (this.status >= 200 && this.status < 400) {
|
||||
var div = document.createElement("div");
|
||||
const div = document.createElement('div');
|
||||
console.log(this.responseText);
|
||||
div.innerHTML = this.responseText;
|
||||
src.parentNode.appendChild(div);
|
||||
|
||||
src.innerHTML = "Collapse";
|
||||
var oldonclick = src.onclick;
|
||||
const oldOnclick = src.onclick;
|
||||
src.onclick = function() {
|
||||
src.innerHTML = "Expand";
|
||||
src.parentNode.removeChild(div);
|
||||
src.onclick = oldonclick;
|
||||
src.onclick = oldOnclick;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
request.send();
|
||||
}
|
||||
</@s.script>
|
||||
</script>
|
||||
|
||||
<body>
|
||||
${debugHtml?no_esc}
|
||||
|
||||
@@ -23,21 +23,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="webconsole.css"/>
|
||||
<script src="webconsole.js"></script>
|
||||
<title>OGNL Console</title>
|
||||
<link rel="stylesheet" type="text/css" href="webconsole.css"/>
|
||||
<script src="webconsole.js"></script>
|
||||
<title>OGNL Console</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="shell">
|
||||
<div class="wc-results" id="wc-result">
|
||||
Welcome to the OGNL console!
|
||||
<br/>
|
||||
:->
|
||||
</div>
|
||||
<form onsubmit="return false" id="wc-form">
|
||||
<input type="hidden" name="debug" value="command"/>
|
||||
<input name="expression" onkeyup="keyEvent(event)" class="wc-command" id="wc-command" type="text"/>
|
||||
</form>
|
||||
<div class="wc-results" id="wc-result">
|
||||
Welcome to the OGNL console!
|
||||
<br/>
|
||||
:->
|
||||
</div>
|
||||
<form onsubmit="return false" id="wc-form">
|
||||
<input type="hidden" name="debug" value="command"/>
|
||||
<input name="expression" class="wc-command" id="wc-command" type="text"/>
|
||||
<script>
|
||||
const input = document.getElementById("wc-command")
|
||||
input.addEventListener("keyup", keyEvent);
|
||||
</script>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
<constant name="struts.excludedClasses"
|
||||
value="
|
||||
org.apache.struts2.ActionContext,
|
||||
java.lang.Class,
|
||||
java.lang.ClassLoader,
|
||||
java.lang.InheritableThreadLocal,
|
||||
@@ -43,7 +42,8 @@
|
||||
java.lang.System,
|
||||
java.lang.Thread,
|
||||
java.lang.ThreadGroup,
|
||||
java.lang.ThreadLocal
|
||||
java.lang.ThreadLocal,
|
||||
org.apache.struts2.ActionContext
|
||||
"/>
|
||||
|
||||
<constant name="struts.devMode.excludedClasses"
|
||||
@@ -74,15 +74,11 @@
|
||||
<constant name="struts.excludedPackageNames"
|
||||
value="
|
||||
antlr.build,
|
||||
org.apache.struts2.config,
|
||||
org.apache.struts2.inject,
|
||||
org.apache.struts2.ognl,
|
||||
org.apache.struts2.security,
|
||||
org.apache.struts2.util,
|
||||
freemarker.core,
|
||||
freemarker.ext.jsp,
|
||||
freemarker.ext.rhino,
|
||||
freemarker.template,
|
||||
jakarta,
|
||||
java.io,
|
||||
java.net,
|
||||
java.nio,
|
||||
@@ -93,6 +89,11 @@
|
||||
org.apache.commons.beanutils,
|
||||
org.apache.commons.collections,
|
||||
org.apache.jasper,
|
||||
org.apache.struts2.config,
|
||||
org.apache.struts2.inject,
|
||||
org.apache.struts2.ognl,
|
||||
org.apache.struts2.security,
|
||||
org.apache.struts2.util,
|
||||
org.apache.tomcat,
|
||||
org.apache.velocity,
|
||||
org.objectweb.asm,
|
||||
@@ -106,15 +107,11 @@
|
||||
<constant name="struts.devMode.excludedPackageNames"
|
||||
value="
|
||||
antlr.build,
|
||||
org.apache.struts2.config,
|
||||
org.apache.struts2.inject,
|
||||
org.apache.struts2.ognl,
|
||||
org.apache.struts2.security,
|
||||
org.apache.struts2.util,
|
||||
freemarker.core,
|
||||
freemarker.ext.jsp,
|
||||
freemarker.ext.rhino,
|
||||
freemarker.template,
|
||||
jakarta,
|
||||
java.io,
|
||||
java.net,
|
||||
java.nio,
|
||||
@@ -125,7 +122,11 @@
|
||||
org.apache.commons.beanutils,
|
||||
org.apache.commons.collections,
|
||||
org.apache.jasper,
|
||||
org.apache.struts2.config,
|
||||
org.apache.struts2.inject,
|
||||
org.apache.struts2.ognl,
|
||||
org.apache.struts2.security,
|
||||
org.apache.struts2.util,
|
||||
org.apache.tomcat,
|
||||
org.apache.velocity,
|
||||
org.objectweb.asm,
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
*/
|
||||
package org.apache.struts2;
|
||||
|
||||
import org.apache.struts2.ActionProxyFactory;
|
||||
import org.apache.struts2.XWorkJUnit4TestCase;
|
||||
import org.apache.struts2.dispatcher.Dispatcher;
|
||||
import org.apache.struts2.util.StrutsTestCaseHelper;
|
||||
import org.apache.struts2.views.jsp.StrutsMockServletContext;
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.components;
|
||||
|
||||
import org.apache.struts2.ActionContext;
|
||||
import org.apache.struts2.dispatcher.DispatcherConstants;
|
||||
import org.apache.struts2.views.jsp.AbstractTagTest;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.struts2.components.UIBean.TEMPLATE_DIR;
|
||||
import static org.apache.struts2.components.UIBean.THEME;
|
||||
|
||||
public class UIBeanTagTest extends AbstractTagTest {
|
||||
|
||||
private UIBean bean;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
bean = new UIBean(stack, request, response) {
|
||||
@Override
|
||||
protected String getDefaultTemplate() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void testTemplateDir_ognlExpression() {
|
||||
bean.setTemplateDir("%{testDir}");
|
||||
stack.push(new Object() {
|
||||
public String getTestDir() {
|
||||
return "testValue";
|
||||
}
|
||||
});
|
||||
|
||||
assertEquals("testValue", bean.getTemplateDir());
|
||||
}
|
||||
|
||||
public void testTemplateDir_attrMapFallback() {
|
||||
ActionContext.of(context).getApplication().put(TEMPLATE_DIR, "applicationValue");
|
||||
assertEquals("applicationValue", bean.getTemplateDir());
|
||||
|
||||
ActionContext.of(context).getSession().put(TEMPLATE_DIR, "sessionValue");
|
||||
assertEquals("sessionValue", bean.getTemplateDir());
|
||||
|
||||
((Map<String, Object>) context.get(DispatcherConstants.REQUEST)).put(TEMPLATE_DIR, "requestValue");
|
||||
assertEquals("requestValue", bean.getTemplateDir());
|
||||
}
|
||||
|
||||
public void testTheme_ognlExpression() {
|
||||
bean.setTheme("%{testTheme}");
|
||||
stack.push(new Object() {
|
||||
public String getTestTheme() {
|
||||
return "testValue";
|
||||
}
|
||||
});
|
||||
|
||||
assertEquals("testValue", bean.getTheme());
|
||||
}
|
||||
|
||||
public void testTheme_attrMapFallback() {
|
||||
ActionContext.of(context).getApplication().put(THEME, "applicationValue");
|
||||
assertEquals("applicationValue", bean.getTheme());
|
||||
|
||||
ActionContext.of(context).getSession().put(THEME, "sessionValue");
|
||||
assertEquals("sessionValue", bean.getTheme());
|
||||
|
||||
((Map<String, Object>) context.get(DispatcherConstants.REQUEST)).put(THEME, "requestValue");
|
||||
assertEquals("requestValue", bean.getTheme());
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -344,6 +344,9 @@ public class DispatcherTest extends StrutsJUnit4InternalTestCase {
|
||||
|
||||
req.setContentType("Multipart/Form-Data ; boundary=---------------------------207103069210263;charset=UTF-16LE");
|
||||
assertTrue(dispatcher.isMultipartRequest(req));
|
||||
|
||||
req.setContentType("multipart/form-data; boundary=\"----=_Part_38_1092302434.1734807780737\"");
|
||||
assertTrue(dispatcher.isMultipartRequest(req));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ public class JakartaStreamMultiPartRequestTest extends AbstractMultiPartRequestT
|
||||
|
||||
// when
|
||||
multiPart.setMaxSizeOfFiles("10");
|
||||
multiPart.parse(mockRequest, tempDir.toString());
|
||||
multiPart.parse(mockRequest, tempDir);
|
||||
|
||||
// then
|
||||
assertThat(multiPart.uploadedFiles)
|
||||
|
||||
@@ -28,7 +28,9 @@ import java.util.concurrent.Callable;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
@@ -49,6 +51,7 @@ public class ContainerImplTest {
|
||||
ContainerBuilder cb = new ContainerBuilder();
|
||||
cb.constant("methodCheck.name", "Lukasz");
|
||||
cb.constant("fieldCheck.name", "Lukasz");
|
||||
cb.constant("constructorCheck.name", "Lukasz");
|
||||
cb.factory(EarlyInitializable.class, EarlyInitializableBean.class, Scope.SINGLETON);
|
||||
cb.factory(Initializable.class, InitializableBean.class, Scope.SINGLETON);
|
||||
cb.factory(EarlyInitializable.class, "prototypeEarlyInitializable", EarlyInitializableBean.class, Scope.PROTOTYPE);
|
||||
@@ -65,15 +68,43 @@ public class ContainerImplTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fieldInjector() throws Exception {
|
||||
public void fieldInjector() {
|
||||
FieldCheck fieldCheck = new FieldCheck();
|
||||
c.inject(fieldCheck);
|
||||
assertEquals(fieldCheck.getName(), "Lukasz");
|
||||
assertEquals("Lukasz", fieldCheck.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodInjector() throws Exception {
|
||||
c.inject(new MethodCheck());
|
||||
public void methodInjector() {
|
||||
MethodCheck methodCheck = new MethodCheck();
|
||||
c.inject(methodCheck);
|
||||
assertEquals("Lukasz", methodCheck.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorInjector() {
|
||||
ConstructorCheck constructorCheck = c.inject(ConstructorCheck.class);
|
||||
assertEquals("Lukasz", constructorCheck.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void optionalConstructorInjector() {
|
||||
OptionalConstructorCheck constructorCheck = c.inject(OptionalConstructorCheck.class);
|
||||
assertNull(constructorCheck.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requiredOptionalConstructorInjector() {
|
||||
RequiredOptionalConstructorCheck constructorCheck = c.inject(RequiredOptionalConstructorCheck.class);
|
||||
assertNotNull(constructorCheck.getExistingName());
|
||||
assertNull(constructorCheck.getNonExitingName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void optionalRequiredConstructorInjector() {
|
||||
OptionalRequiredConstructorCheck constructorCheck = c.inject(OptionalRequiredConstructorCheck.class);
|
||||
assertNull(constructorCheck.getNonExitingName());
|
||||
assertNotNull(constructorCheck.getExistingName());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +123,7 @@ public class ContainerImplTest {
|
||||
* Inject values into method under SecurityManager
|
||||
*/
|
||||
@Test
|
||||
public void testMethodInjectorWithSecurityEnabled() throws Exception {
|
||||
public void testMethodInjectorWithSecurityEnabled() {
|
||||
assumeTrue(SystemUtils.isJavaVersionAtMost(JavaVersion.JAVA_20));
|
||||
System.setSecurityManager(new TestSecurityManager());
|
||||
assertThrows(DependencyException.class, () -> c.inject(new MethodCheck()));
|
||||
@@ -101,7 +132,7 @@ public class ContainerImplTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEarlyInitializable() throws Exception {
|
||||
public void testEarlyInitializable() {
|
||||
assertTrue("should being initialized already", EarlyInitializableBean.initializedEarly);
|
||||
|
||||
EarlyInitializableCheck earlyInitializableCheck = new EarlyInitializableCheck();
|
||||
@@ -148,22 +179,19 @@ public class ContainerImplTest {
|
||||
|
||||
final InitializableCheck initializableCheck3 = new InitializableCheck();
|
||||
final TestScopeStrategy testScopeStrategy = new TestScopeStrategy();
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ContainerBuilder cb2 = new ContainerBuilder();
|
||||
cb2.factory(EarlyInitializable.class, EarlyInitializableBean.class, Scope.SINGLETON);
|
||||
cb2.factory(Initializable.class, InitializableBean.class, Scope.SINGLETON);
|
||||
cb2.factory(EarlyInitializable.class, "prototypeEarlyInitializable", EarlyInitializableBean.class, Scope.PROTOTYPE);
|
||||
cb2.factory(Initializable.class, "prototypeInitializable", InitializableBean.class, Scope.PROTOTYPE);
|
||||
cb2.factory(Initializable.class, "requestInitializable", InitializableBean.class, Scope.REQUEST);
|
||||
cb2.factory(Initializable.class, "sessionInitializable", InitializableBean.class, Scope.SESSION);
|
||||
cb2.factory(Initializable.class, "threadInitializable", InitializableBean.class, Scope.THREAD);
|
||||
cb2.factory(Initializable.class, "wizardInitializable", InitializableBean.class, Scope.WIZARD);
|
||||
Container c2 = cb2.create(false);
|
||||
c2.setScopeStrategy(testScopeStrategy);
|
||||
c2.inject(initializableCheck3);
|
||||
}
|
||||
Thread thread = new Thread(() -> {
|
||||
ContainerBuilder cb2 = new ContainerBuilder();
|
||||
cb2.factory(EarlyInitializable.class, EarlyInitializableBean.class, Scope.SINGLETON);
|
||||
cb2.factory(Initializable.class, InitializableBean.class, Scope.SINGLETON);
|
||||
cb2.factory(EarlyInitializable.class, "prototypeEarlyInitializable", EarlyInitializableBean.class, Scope.PROTOTYPE);
|
||||
cb2.factory(Initializable.class, "prototypeInitializable", InitializableBean.class, Scope.PROTOTYPE);
|
||||
cb2.factory(Initializable.class, "requestInitializable", InitializableBean.class, Scope.REQUEST);
|
||||
cb2.factory(Initializable.class, "sessionInitializable", InitializableBean.class, Scope.SESSION);
|
||||
cb2.factory(Initializable.class, "threadInitializable", InitializableBean.class, Scope.THREAD);
|
||||
cb2.factory(Initializable.class, "wizardInitializable", InitializableBean.class, Scope.WIZARD);
|
||||
Container c2 = cb2.create(false);
|
||||
c2.setScopeStrategy(testScopeStrategy);
|
||||
c2.inject(initializableCheck3);
|
||||
});
|
||||
thread.run();
|
||||
thread.join();
|
||||
@@ -205,6 +233,76 @@ public class ContainerImplTest {
|
||||
|
||||
}
|
||||
|
||||
public static class ConstructorCheck {
|
||||
private String name;
|
||||
|
||||
@Inject("constructorCheck.name")
|
||||
public ConstructorCheck(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public static class OptionalConstructorCheck {
|
||||
private String name;
|
||||
|
||||
@Inject(value = "nonExistingConstant", required = false)
|
||||
public OptionalConstructorCheck(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public static class RequiredOptionalConstructorCheck {
|
||||
private final String existingName;
|
||||
private final String nonExitingName;
|
||||
|
||||
@Inject(required = false)
|
||||
public RequiredOptionalConstructorCheck(
|
||||
@Inject("constructorCheck.name") String existingName,
|
||||
@Inject(value = "nonExistingConstant", required = false) String nonExitingName
|
||||
) {
|
||||
this.existingName = existingName;
|
||||
this.nonExitingName = nonExitingName;
|
||||
}
|
||||
|
||||
public String getExistingName() {
|
||||
return existingName;
|
||||
}
|
||||
|
||||
public String getNonExitingName() {
|
||||
return nonExitingName;
|
||||
}
|
||||
}
|
||||
|
||||
public static class OptionalRequiredConstructorCheck {
|
||||
private final String existingName;
|
||||
private final String nonExitingName;
|
||||
|
||||
@Inject(required = false)
|
||||
public OptionalRequiredConstructorCheck(
|
||||
@Inject(value = "nonExistingConstant", required = false) String nonExitingName,
|
||||
@Inject("constructorCheck.name") String existingName
|
||||
) {
|
||||
this.existingName = existingName;
|
||||
this.nonExitingName = nonExitingName;
|
||||
}
|
||||
|
||||
public String getExistingName() {
|
||||
return existingName;
|
||||
}
|
||||
|
||||
public String getNonExitingName() {
|
||||
return nonExitingName;
|
||||
}
|
||||
}
|
||||
|
||||
class InitializableCheck {
|
||||
|
||||
private Initializable initializable;
|
||||
|
||||
@@ -549,6 +549,7 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
|
||||
jak.setMaxFiles(String.valueOf(maxfiles));
|
||||
jak.setMaxStringLength(String.valueOf(maxStringLength));
|
||||
jak.setDefaultEncoding(StandardCharsets.UTF_8.name());
|
||||
|
||||
return new MultiPartRequestWrapper(jak, request, tempDir.getAbsolutePath(), new DefaultLocaleProvider());
|
||||
}
|
||||
|
||||
|
||||
+31
-29
@@ -19,16 +19,17 @@
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import com.mockobjects.dynamic.Mock;
|
||||
import org.apache.struts2.action.Action;
|
||||
import org.apache.struts2.ActionContext;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.ActionProxy;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.XWorkTestCase;
|
||||
import org.apache.struts2.action.Action;
|
||||
import org.apache.struts2.config.entities.ActionConfig;
|
||||
import org.apache.struts2.config.entities.ExceptionMappingConfig;
|
||||
import org.apache.struts2.ognl.ThreadAllowlist;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
import org.apache.struts2.validator.ValidationException;
|
||||
import org.apache.struts2.StrutsException;
|
||||
|
||||
/**
|
||||
* Unit test for ExceptionMappingInterceptor.
|
||||
@@ -52,7 +53,7 @@ public class ExceptionMappingInterceptorTest extends XWorkTestCase {
|
||||
String result = interceptor.intercept(invocation);
|
||||
assertNotNull(stack.findValue("exception"));
|
||||
assertEquals(stack.findValue("exception"), exception);
|
||||
assertEquals(result, "spooky");
|
||||
assertEquals("spooky", result);
|
||||
ExceptionHolder holder = (ExceptionHolder) stack.getRoot().get(0); // is on top of the root
|
||||
assertNotNull(holder.getExceptionStack()); // to invoke the method for unit test
|
||||
}
|
||||
@@ -67,7 +68,7 @@ public class ExceptionMappingInterceptorTest extends XWorkTestCase {
|
||||
String result = interceptor.intercept(invocation);
|
||||
assertNotNull(stack.findValue("exception"));
|
||||
assertEquals(stack.findValue("exception"), exception);
|
||||
assertEquals(result, "throwable");
|
||||
assertEquals("throwable", result);
|
||||
}
|
||||
|
||||
public void testNoThrownException() throws Exception {
|
||||
@@ -77,7 +78,7 @@ public class ExceptionMappingInterceptorTest extends XWorkTestCase {
|
||||
mockInvocation.expectAndReturn("invoke", Action.SUCCESS);
|
||||
mockInvocation.matchAndReturn("getAction", action.proxy());
|
||||
String result = interceptor.intercept(invocation);
|
||||
assertEquals(result, Action.SUCCESS);
|
||||
assertEquals(Action.SUCCESS, result);
|
||||
assertNull(stack.findValue("exception"));
|
||||
}
|
||||
|
||||
@@ -106,7 +107,7 @@ public class ExceptionMappingInterceptorTest extends XWorkTestCase {
|
||||
mockInvocation.matchAndReturn("getAction", action.proxy());
|
||||
|
||||
try {
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.intercept(invocation);
|
||||
fail("Should not have reached this point.");
|
||||
} catch (Exception e) {
|
||||
@@ -123,8 +124,8 @@ public class ExceptionMappingInterceptorTest extends XWorkTestCase {
|
||||
mockInvocation.matchAndReturn("getAction", action.proxy());
|
||||
|
||||
try {
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogCategory("showcase.unhandled");
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogCategory("showcase.unhandled");
|
||||
interceptor.intercept(invocation);
|
||||
fail("Should not have reached this point.");
|
||||
} catch (Exception e) {
|
||||
@@ -141,9 +142,9 @@ public class ExceptionMappingInterceptorTest extends XWorkTestCase {
|
||||
mockInvocation.matchAndReturn("getAction", action.proxy());
|
||||
|
||||
try {
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogCategory("showcase.unhandled");
|
||||
interceptor.setLogLevel("fatal");
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogCategory("showcase.unhandled");
|
||||
interceptor.setLogLevel("fatal");
|
||||
interceptor.intercept(invocation);
|
||||
fail("Should not have reached this point.");
|
||||
} catch (Exception e) {
|
||||
@@ -164,9 +165,9 @@ public class ExceptionMappingInterceptorTest extends XWorkTestCase {
|
||||
mockInvocation.matchAndReturn("getAction", action.proxy());
|
||||
|
||||
try {
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogCategory("showcase.unhandled");
|
||||
interceptor.setLogLevel("error");
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogCategory("showcase.unhandled");
|
||||
interceptor.setLogLevel("error");
|
||||
interceptor.intercept(invocation);
|
||||
fail("Should not have reached this point.");
|
||||
} catch (Exception e) {
|
||||
@@ -183,9 +184,9 @@ public class ExceptionMappingInterceptorTest extends XWorkTestCase {
|
||||
mockInvocation.matchAndReturn("getAction", action.proxy());
|
||||
|
||||
try {
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogCategory("showcase.unhandled");
|
||||
interceptor.setLogLevel("warn");
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogCategory("showcase.unhandled");
|
||||
interceptor.setLogLevel("warn");
|
||||
interceptor.intercept(invocation);
|
||||
fail("Should not have reached this point.");
|
||||
} catch (Exception e) {
|
||||
@@ -202,9 +203,9 @@ public class ExceptionMappingInterceptorTest extends XWorkTestCase {
|
||||
mockInvocation.matchAndReturn("getAction", action.proxy());
|
||||
|
||||
try {
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogCategory("showcase.unhandled");
|
||||
interceptor.setLogLevel("info");
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogCategory("showcase.unhandled");
|
||||
interceptor.setLogLevel("info");
|
||||
interceptor.intercept(invocation);
|
||||
fail("Should not have reached this point.");
|
||||
} catch (Exception e) {
|
||||
@@ -221,9 +222,9 @@ public class ExceptionMappingInterceptorTest extends XWorkTestCase {
|
||||
mockInvocation.matchAndReturn("getAction", action.proxy());
|
||||
|
||||
try {
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogCategory("showcase.unhandled");
|
||||
interceptor.setLogLevel("debug");
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogCategory("showcase.unhandled");
|
||||
interceptor.setLogLevel("debug");
|
||||
interceptor.intercept(invocation);
|
||||
fail("Should not have reached this point.");
|
||||
} catch (Exception e) {
|
||||
@@ -240,9 +241,9 @@ public class ExceptionMappingInterceptorTest extends XWorkTestCase {
|
||||
mockInvocation.matchAndReturn("getAction", action.proxy());
|
||||
|
||||
try {
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogCategory("showcase.unhandled");
|
||||
interceptor.setLogLevel("trace");
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogCategory("showcase.unhandled");
|
||||
interceptor.setLogLevel("trace");
|
||||
interceptor.intercept(invocation);
|
||||
fail("Should not have reached this point.");
|
||||
} catch (Exception e) {
|
||||
@@ -259,12 +260,12 @@ public class ExceptionMappingInterceptorTest extends XWorkTestCase {
|
||||
mockInvocation.matchAndReturn("getAction", action.proxy());
|
||||
|
||||
try {
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogLevel("xxx");
|
||||
interceptor.setLogEnabled(true);
|
||||
interceptor.setLogLevel("xxx");
|
||||
interceptor.intercept(invocation);
|
||||
fail("Should not have reached this point.");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// success
|
||||
// success
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,6 +297,7 @@ public class ExceptionMappingInterceptorTest extends XWorkTestCase {
|
||||
mockInvocation.expectAndReturn("getStack", stack);
|
||||
mockInvocation.expectAndReturn("getInvocationContext", ActionContext.of().bind());
|
||||
interceptor = new ExceptionMappingInterceptor();
|
||||
interceptor.setThreadAllowlist(new ThreadAllowlist());
|
||||
interceptor.init();
|
||||
}
|
||||
|
||||
|
||||
+569
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.interceptor.debugging;
|
||||
|
||||
import org.apache.struts2.ActionContext;
|
||||
import org.apache.struts2.StrutsJUnit4InternalTestCase;
|
||||
import org.apache.struts2.TestAction;
|
||||
import org.apache.struts2.dispatcher.DispatcherConstants;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.RequestMap;
|
||||
import org.apache.struts2.dispatcher.SessionMap;
|
||||
import org.apache.struts2.mock.MockActionInvocation;
|
||||
import org.apache.struts2.ognl.ThreadAllowlist;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.assertj.core.util.Maps;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
|
||||
public class DebuggingInterceptorTest extends StrutsJUnit4InternalTestCase {
|
||||
|
||||
private DebuggingInterceptor interceptor;
|
||||
private MockActionInvocation invocation;
|
||||
private MockHttpServletRequest request;
|
||||
private MockHttpServletResponse response;
|
||||
private ActionContext context;
|
||||
private TestAction action;
|
||||
|
||||
@Test
|
||||
public void noDevMode() throws Exception {
|
||||
interceptor.intercept(invocation);
|
||||
assertThat(invocation.getResultCode()).isEqualTo("mock");
|
||||
assertThat(response.getContentAsString()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void debugXml() throws Exception {
|
||||
interceptor.setDevMode("true");
|
||||
context.withParameters(HttpParameters.create(Maps.newHashMap("debug", "xml")).build());
|
||||
|
||||
interceptor.intercept(invocation);
|
||||
|
||||
assertThat(response.getContentAsString()).isEqualToIgnoringWhitespace("""
|
||||
<debug>
|
||||
<parameters/>
|
||||
<context/>
|
||||
<request/>
|
||||
<session/>
|
||||
<valueStack>
|
||||
<value>
|
||||
<action>
|
||||
<actionErrors/>
|
||||
<actionMessages/>
|
||||
<class>class org.apache.struts2.TestAction</class>
|
||||
<fieldErrors/>
|
||||
<locale>
|
||||
<ISO3Country>USA</ISO3Country>
|
||||
<ISO3Language>eng</ISO3Language>
|
||||
<class>class java.util.Locale</class>
|
||||
<country>US</country>
|
||||
<displayCountry>United States</displayCountry>
|
||||
<displayLanguage>English</displayLanguage>
|
||||
<displayName>English (United States)</displayName>
|
||||
<displayScript></displayScript>
|
||||
<displayVariant></displayVariant>
|
||||
<extensionKeys/>
|
||||
<language>en</language>
|
||||
<script></script>
|
||||
<unicodeLocaleAttributes/>
|
||||
<unicodeLocaleKeys/>
|
||||
<variant></variant>
|
||||
</locale>
|
||||
<status>
|
||||
<class>class org.apache.struts2.SomeEnum</class>
|
||||
<declaringClass>class org.apache.struts2.SomeEnum</declaringClass>
|
||||
<displayName>completed</displayName>
|
||||
<name>COMPLETED</name>
|
||||
</status>
|
||||
<statusList>
|
||||
<value>
|
||||
<class>class org.apache.struts2.SomeEnum</class>
|
||||
<declaringClass>class org.apache.struts2.SomeEnum</declaringClass>
|
||||
<displayName>init</displayName>
|
||||
<name>INIT</name>
|
||||
</value>
|
||||
<value>
|
||||
<class>class org.apache.struts2.SomeEnum</class>
|
||||
<declaringClass>class org.apache.struts2.SomeEnum</declaringClass>
|
||||
<displayName>completed</displayName>
|
||||
<name>COMPLETED</name>
|
||||
</value>
|
||||
</statusList>
|
||||
<texts>
|
||||
<baseBundleName>org.apache.struts2.TestAction</baseBundleName>
|
||||
<class>class java.util.PropertyResourceBundle</class>
|
||||
<keys>
|
||||
<class>class sun.util.ResourceBundleEnumeration</class>
|
||||
</keys>
|
||||
<locale>
|
||||
<ISO3Country></ISO3Country>
|
||||
<ISO3Language></ISO3Language>
|
||||
<class>class java.util.Locale</class>
|
||||
<country></country>
|
||||
<displayCountry></displayCountry>
|
||||
<displayLanguage></displayLanguage>
|
||||
<displayName></displayName>
|
||||
<displayScript></displayScript>
|
||||
<displayVariant></displayVariant>
|
||||
<extensionKeys/>
|
||||
<language></language>
|
||||
<script></script>
|
||||
<unicodeLocaleAttributes/>
|
||||
<unicodeLocaleKeys/>
|
||||
<variant></variant>
|
||||
</locale>
|
||||
</texts>
|
||||
</action>
|
||||
<org.apache.struts2.util.OgnlValueStack.MAP_IDENTIFIER_KEY></org.apache.struts2.util.OgnlValueStack.MAP_IDENTIFIER_KEY>
|
||||
</value>
|
||||
<value>
|
||||
<class>class org.apache.struts2.text.DefaultTextProvider</class>
|
||||
</value>
|
||||
</valueStack>
|
||||
</debug>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void debugXmlWithConsole() throws Exception {
|
||||
interceptor.setDevMode("true");
|
||||
context.withParameters(HttpParameters.create(Maps.newHashMap("debug", "console")).build());
|
||||
interceptor.setEnableXmlWithConsole(true);
|
||||
|
||||
interceptor.intercept(invocation);
|
||||
|
||||
assertThat(response.getContentAsString()).isEqualToIgnoringWhitespace("""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
var baseUrl = "/static";
|
||||
window.open(baseUrl+"/webconsole.html", 'OGNL Console','width=500,height=450,status=no,toolbar=no,menubar=no');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
&lt;debug&gt;
|
||||
&lt;parameters/&gt;
|
||||
&lt;context/&gt;
|
||||
&lt;request/&gt;
|
||||
&lt;session/&gt;
|
||||
&lt;valueStack&gt;
|
||||
&lt;value&gt;
|
||||
&lt;action&gt;
|
||||
&lt;actionErrors/&gt;
|
||||
&lt;actionMessages/&gt;
|
||||
&lt;class&gt;class org.apache.struts2.TestAction&lt;/class&gt;
|
||||
&lt;fieldErrors/&gt;
|
||||
&lt;locale&gt;
|
||||
&lt;ISO3Country&gt;USA&lt;/ISO3Country&gt;
|
||||
&lt;ISO3Language&gt;eng&lt;/ISO3Language&gt;
|
||||
&lt;class&gt;class java.util.Locale&lt;/class&gt;
|
||||
&lt;country&gt;US&lt;/country&gt;
|
||||
&lt;displayCountry&gt;United States&lt;/displayCountry&gt;
|
||||
&lt;displayLanguage&gt;English&lt;/displayLanguage&gt;
|
||||
&lt;displayName&gt;English (United States)&lt;/displayName&gt;
|
||||
&lt;displayScript&gt;&lt;/displayScript&gt;
|
||||
&lt;displayVariant&gt;&lt;/displayVariant&gt;
|
||||
&lt;extensionKeys/&gt;
|
||||
&lt;language&gt;en&lt;/language&gt;
|
||||
&lt;script&gt;&lt;/script&gt;
|
||||
&lt;unicodeLocaleAttributes/&gt;
|
||||
&lt;unicodeLocaleKeys/&gt;
|
||||
&lt;variant&gt;&lt;/variant&gt;
|
||||
&lt;/locale&gt;
|
||||
&lt;status&gt;
|
||||
&lt;class&gt;class org.apache.struts2.SomeEnum&lt;/class&gt;
|
||||
&lt;declaringClass&gt;class org.apache.struts2.SomeEnum&lt;/declaringClass&gt;
|
||||
&lt;displayName&gt;completed&lt;/displayName&gt;
|
||||
&lt;name&gt;COMPLETED&lt;/name&gt;
|
||||
&lt;/status&gt;
|
||||
&lt;statusList&gt;
|
||||
&lt;value&gt;
|
||||
&lt;class&gt;class org.apache.struts2.SomeEnum&lt;/class&gt;
|
||||
&lt;declaringClass&gt;class org.apache.struts2.SomeEnum&lt;/declaringClass&gt;
|
||||
&lt;displayName&gt;init&lt;/displayName&gt;
|
||||
&lt;name&gt;INIT&lt;/name&gt;
|
||||
&lt;/value&gt;
|
||||
&lt;value&gt;
|
||||
&lt;class&gt;class org.apache.struts2.SomeEnum&lt;/class&gt;
|
||||
&lt;declaringClass&gt;class org.apache.struts2.SomeEnum&lt;/declaringClass&gt;
|
||||
&lt;displayName&gt;completed&lt;/displayName&gt;
|
||||
&lt;name&gt;COMPLETED&lt;/name&gt;
|
||||
&lt;/value&gt;
|
||||
&lt;/statusList&gt;
|
||||
&lt;texts&gt;
|
||||
&lt;baseBundleName&gt;org.apache.struts2.TestAction&lt;/baseBundleName&gt;
|
||||
&lt;class&gt;class java.util.PropertyResourceBundle&lt;/class&gt;
|
||||
&lt;keys&gt;
|
||||
&lt;class&gt;class sun.util.ResourceBundleEnumeration&lt;/class&gt;
|
||||
&lt;/keys&gt;
|
||||
&lt;locale&gt;
|
||||
&lt;ISO3Country&gt;&lt;/ISO3Country&gt;
|
||||
&lt;ISO3Language&gt;&lt;/ISO3Language&gt;
|
||||
&lt;class&gt;class java.util.Locale&lt;/class&gt;
|
||||
&lt;country&gt;&lt;/country&gt;
|
||||
&lt;displayCountry&gt;&lt;/displayCountry&gt;
|
||||
&lt;displayLanguage&gt;&lt;/displayLanguage&gt;
|
||||
&lt;displayName&gt;&lt;/displayName&gt;
|
||||
&lt;displayScript&gt;&lt;/displayScript&gt;
|
||||
&lt;displayVariant&gt;&lt;/displayVariant&gt;
|
||||
&lt;extensionKeys/&gt;
|
||||
&lt;language&gt;&lt;/language&gt;
|
||||
&lt;script&gt;&lt;/script&gt;
|
||||
&lt;unicodeLocaleAttributes/&gt;
|
||||
&lt;unicodeLocaleKeys/&gt;
|
||||
&lt;variant&gt;&lt;/variant&gt;
|
||||
&lt;/locale&gt;
|
||||
&lt;/texts&gt;
|
||||
&lt;/action&gt;
|
||||
&lt;org.apache.struts2.util.OgnlValueStack.MAP_IDENTIFIER_KEY&gt;&lt;/org.apache.struts2.util.OgnlValueStack.MAP_IDENTIFIER_KEY&gt;
|
||||
&lt;/value&gt;
|
||||
&lt;value&gt;
|
||||
&lt;class&gt;class org.apache.struts2.text.DefaultTextProvider&lt;/class&gt;
|
||||
&lt;/value&gt;
|
||||
&lt;/valueStack&gt;
|
||||
&lt;/debug&gt;
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void debugConsole() throws Exception {
|
||||
interceptor.setDevMode("true");
|
||||
context.withParameters(HttpParameters.create(Maps.newHashMap("debug", "console")).build());
|
||||
|
||||
interceptor.intercept(invocation);
|
||||
|
||||
assertThat(response.getContentAsString()).isEqualToIgnoringWhitespace("""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
var baseUrl = "/static";
|
||||
window.open(baseUrl+"/webconsole.html", 'OGNL Console','width=500,height=450,status=no,toolbar=no,menubar=no');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<pre>
|
||||
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void debugCommand() throws Exception {
|
||||
interceptor.setDevMode("true");
|
||||
Map<String, Object> params = new HashMap<>() {{
|
||||
put("debug", "command");
|
||||
put("expression", "1+1");
|
||||
}};
|
||||
context.withParameters(HttpParameters.create(params).build());
|
||||
|
||||
interceptor.intercept(invocation);
|
||||
|
||||
assertThat(response.getContentAsString()).isEqualToIgnoringWhitespace("2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void debugBrowser() throws Exception {
|
||||
interceptor.setDevMode("true");
|
||||
context.withParameters(HttpParameters.create(Maps.newHashMap("debug", "browser")).build());
|
||||
|
||||
interceptor.intercept(invocation);
|
||||
invocation.invoke();
|
||||
|
||||
assertThat(response.getContentAsString()).isEqualToIgnoringWhitespace("""
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<style>
|
||||
.debugTable {
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.debugTable td {
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.nameColumn {
|
||||
background-color:#CCDDFF;
|
||||
}
|
||||
|
||||
.valueColumn {
|
||||
background-color: #CCFFCC;
|
||||
}
|
||||
|
||||
.nullValue {
|
||||
background-color: #FF0000;
|
||||
}
|
||||
|
||||
.typeColumn {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.emptyCollection {
|
||||
background-color: #EEEEEE;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function expand(src, path) {
|
||||
let baseUrl = location.href;
|
||||
const i = baseUrl.indexOf('&object=');
|
||||
baseUrl = (i > 0 ? baseUrl.substring(0, i) : baseUrl) + "&object=" + path;
|
||||
if (baseUrl.indexOf("decorate") < 0) {
|
||||
baseUrl += "&decorate=false";
|
||||
}
|
||||
|
||||
const request = new XMLHttpRequest();
|
||||
request.open('GET', baseUrl, true);
|
||||
request.onreadystatechange = function() {
|
||||
if (this.readyState === 4) {
|
||||
if (this.status >= 200 && this.status < 400) {
|
||||
const div = document.createElement('div');
|
||||
console.log(this.responseText);
|
||||
div.innerHTML = this.responseText;
|
||||
src.parentNode.appendChild(div);
|
||||
|
||||
src.innerHTML = "Collapse";
|
||||
const oldOnclick = src.onclick;
|
||||
src.onclick = function() {
|
||||
src.innerHTML = "Expand";
|
||||
src.parentNode.removeChild(div);
|
||||
src.onclick = oldOnclick;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
request.send();
|
||||
}
|
||||
</script>
|
||||
|
||||
<body>
|
||||
<table class="debugTable">
|
||||
<tr>
|
||||
<td class="nameColumn">container</td>
|
||||
<td class="valueColumn">There is no read method for container</td>
|
||||
<td class="typeColumn">java.lang.String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">foo</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">intList</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">locale</td>
|
||||
<td class="valueColumn">
|
||||
<a onclick="expand(this, 'action["locale"]')" href="javascript://nop/">Expand</a>
|
||||
</td>
|
||||
<td class="typeColumn">java.util.Locale</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">result</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">collection2</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">someBool</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">array</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">fooInt</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">id</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">map</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">actionErrors</td>
|
||||
<td class="emptyCollection">empty</td>
|
||||
<td class="typeColumn">java.util.LinkedList</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">objectArray</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">fieldErrors</td>
|
||||
<td class="emptyCollection">empty</td>
|
||||
<td class="typeColumn">java.util.LinkedHashMap</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">collection</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">floatNumber</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">list</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">enumList</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">actionMessages</td>
|
||||
<td class="emptyCollection">empty</td>
|
||||
<td class="typeColumn">java.util.LinkedList</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">statusList</td>
|
||||
<td class="valueColumn">
|
||||
<a onclick="expand(this, 'action["statusList"]')" href="javascript://nop/">Expand</a>
|
||||
</td>
|
||||
<td class="typeColumn">java.util.Arrays$ArrayList</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">texts</td>
|
||||
<td class="valueColumn">
|
||||
<a onclick="expand(this, 'action["texts"]')" href="javascript://nop/">Expand</a>
|
||||
</td>
|
||||
<td class="typeColumn">java.util.PropertyResourceBundle</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">list3</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">list2</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">user</td>
|
||||
<td class="nullValue">null</td>
|
||||
<td class="nullValue">unknown</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="nameColumn">status</td>
|
||||
<td class="valueColumn">
|
||||
<a onclick="expand(this, 'action["status"]')" href="javascript://nop/">Expand</a>
|
||||
</td>
|
||||
<td class="typeColumn">org.apache.struts2.SomeEnum</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allowlist() throws Exception {
|
||||
interceptor.setDevMode("true");
|
||||
context.withParameters(HttpParameters.create(Maps.newHashMap("debug", "browser")).build());
|
||||
|
||||
assertThat(container.getInstance(ThreadAllowlist.class))
|
||||
.extracting(ThreadAllowlist::getAllowlist).asInstanceOf(InstanceOfAssertFactories.SET)
|
||||
.isEmpty();
|
||||
|
||||
interceptor.intercept(invocation);
|
||||
invocation.invoke();
|
||||
|
||||
assertThat(container.getInstance(ThreadAllowlist.class))
|
||||
.extracting(ThreadAllowlist::getAllowlist).asInstanceOf(InstanceOfAssertFactories.SET)
|
||||
.contains(
|
||||
org.apache.struts2.interceptor.ValidationAware.class,
|
||||
org.apache.struts2.Validateable.class,
|
||||
org.apache.struts2.action.Action.class,
|
||||
org.apache.struts2.text.TextProvider.class,
|
||||
org.apache.struts2.ActionSupport.class,
|
||||
org.apache.struts2.locale.LocaleProvider.class,
|
||||
org.apache.struts2.TestAction.class
|
||||
);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
request = new MockHttpServletRequest();
|
||||
request.setSession(new MockHttpSession());
|
||||
response = new MockHttpServletResponse();
|
||||
|
||||
ValueStack valueStack = dispatcher.getValueStackFactory().createValueStack();
|
||||
|
||||
context = valueStack.getActionContext()
|
||||
.withServletContext(servletContext)
|
||||
.withServletRequest(request)
|
||||
.withServletResponse(response)
|
||||
.withSession(new SessionMap(request))
|
||||
.with(DispatcherConstants.REQUEST, new RequestMap(request));
|
||||
|
||||
interceptor = container.inject(DebuggingInterceptor.class);
|
||||
interceptor.init();
|
||||
|
||||
invocation = new MockActionInvocation();
|
||||
invocation.setResultCode("mock");
|
||||
invocation.setInvocationContext(context);
|
||||
action = new TestAction();
|
||||
invocation.setAction(action);
|
||||
invocation.setStack(valueStack);
|
||||
|
||||
valueStack.set("action", invocation.getAction());
|
||||
|
||||
context = context.withActionInvocation(invocation).bind();
|
||||
}
|
||||
|
||||
}
|
||||
+5
-5
@@ -117,9 +117,9 @@ public class ParametersInterceptorTest extends XWorkTestCase {
|
||||
pi.applyParameters(action, vs, HttpParameters.create(params).build());
|
||||
|
||||
// then
|
||||
assertEquals(3, action.getActionErrors().size());
|
||||
assertEquals(3, action.getActionMessages().size());
|
||||
|
||||
List<String> actionErrors = new ArrayList<>(action.getActionErrors());
|
||||
List<String> actionErrors = new ArrayList<>(action.getActionMessages());
|
||||
|
||||
String msg1 = actionErrors.get(0);
|
||||
String msg2 = actionErrors.get(1);
|
||||
@@ -204,9 +204,9 @@ public class ParametersInterceptorTest extends XWorkTestCase {
|
||||
pi.applyParameters(action, vs, HttpParameters.create(params).build());
|
||||
|
||||
// then
|
||||
assertEquals(3, action.getActionErrors().size());
|
||||
assertEquals(3, action.getActionMessages().size());
|
||||
|
||||
List<String> actionErrors = new ArrayList<>(action.getActionErrors());
|
||||
List<String> actionErrors = new ArrayList<>(action.getActionMessages());
|
||||
String msg1 = actionErrors.get(0);
|
||||
String msg2 = actionErrors.get(1);
|
||||
String msg3 = actionErrors.get(2);
|
||||
@@ -586,7 +586,7 @@ public class ParametersInterceptorTest extends XWorkTestCase {
|
||||
container.inject(config.getInterceptors().get(0).getInterceptor());
|
||||
ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext.getContextMap());
|
||||
proxy.execute();
|
||||
final String actionError = "" + ((SimpleAction) proxy.getAction()).getActionErrors().toArray()[0];
|
||||
final String actionError = "" + ((SimpleAction) proxy.getAction()).getActionMessages().toArray()[0];
|
||||
assertTrue(actionError.contains("Error setting expression 'not_a_property' with value 'There is no action property named like this'"));
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -24,34 +24,60 @@ import java.util.HashMap;
|
||||
|
||||
public class WildcardHelperTest extends XWorkTestCase {
|
||||
|
||||
public void testMatch() {
|
||||
private WildcardHelper wildcardHelper;
|
||||
|
||||
WildcardHelper wild = new WildcardHelper();
|
||||
HashMap<String, String> matchedPatterns = new HashMap<>();
|
||||
int[] pattern = wild.compilePattern("wes-rules");
|
||||
assertEquals(wild.match(matchedPatterns,"wes-rules", pattern), true);
|
||||
assertEquals(wild.match(matchedPatterns, "rules-wes", pattern), false);
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
pattern = wild.compilePattern("wes-*");
|
||||
assertEquals(wild.match(matchedPatterns,"wes-rules", pattern), true);
|
||||
assertEquals("rules".equals(matchedPatterns.get("1")), true);
|
||||
assertEquals(wild.match(matchedPatterns, "rules-wes", pattern), false);
|
||||
wildcardHelper = new WildcardHelper();
|
||||
}
|
||||
|
||||
pattern = wild.compilePattern("path/**/file");
|
||||
assertEquals(wild.match(matchedPatterns, "path/to/file", pattern), true);
|
||||
assertEquals("to".equals(matchedPatterns.get("1")), true);
|
||||
assertEquals(wild.match(matchedPatterns, "path/to/another/location/of/file", pattern), true);
|
||||
assertEquals("to/another/location/of".equals(matchedPatterns.get("1")), true);
|
||||
public void testMatch() {
|
||||
HashMap<String, String> matchedPatterns = new HashMap<>();
|
||||
int[] pattern = wildcardHelper.compilePattern("wes-rules");
|
||||
assertEquals(wildcardHelper.match(matchedPatterns, "wes-rules", pattern), true);
|
||||
assertEquals(wildcardHelper.match(matchedPatterns, "rules-wes", pattern), false);
|
||||
|
||||
pattern = wild.compilePattern("path/*/file");
|
||||
assertEquals(wild.match(matchedPatterns, "path/to/file", pattern), true);
|
||||
assertEquals("to".equals(matchedPatterns.get("1")), true);
|
||||
assertEquals(wild.match(matchedPatterns, "path/to/another/location/of/file", pattern), false);
|
||||
pattern = wildcardHelper.compilePattern("wes-*");
|
||||
assertEquals(wildcardHelper.match(matchedPatterns, "wes-rules", pattern), true);
|
||||
assertEquals("rules".equals(matchedPatterns.get("1")), true);
|
||||
assertEquals(wildcardHelper.match(matchedPatterns, "rules-wes", pattern), false);
|
||||
|
||||
pattern = wild.compilePattern("path/*/another/**/file");
|
||||
assertEquals(wild.match(matchedPatterns, "path/to/another/location/of/file", pattern), true);
|
||||
assertEquals("to".equals(matchedPatterns.get("1")), true);
|
||||
assertEquals("location/of".equals(matchedPatterns.get("2")), true);
|
||||
}
|
||||
pattern = wildcardHelper.compilePattern("path/**/file");
|
||||
assertEquals(wildcardHelper.match(matchedPatterns, "path/to/file", pattern), true);
|
||||
assertEquals("to".equals(matchedPatterns.get("1")), true);
|
||||
assertEquals(wildcardHelper.match(matchedPatterns, "path/to/another/location/of/file", pattern), true);
|
||||
assertEquals("to/another/location/of".equals(matchedPatterns.get("1")), true);
|
||||
|
||||
pattern = wildcardHelper.compilePattern("path/*/file");
|
||||
assertEquals(wildcardHelper.match(matchedPatterns, "path/to/file", pattern), true);
|
||||
assertEquals("to".equals(matchedPatterns.get("1")), true);
|
||||
assertEquals(wildcardHelper.match(matchedPatterns, "path/to/another/location/of/file", pattern), false);
|
||||
|
||||
pattern = wildcardHelper.compilePattern("path/*/another/**/file");
|
||||
assertEquals(wildcardHelper.match(matchedPatterns, "path/to/another/location/of/file", pattern), true);
|
||||
assertEquals("to".equals(matchedPatterns.get("1")), true);
|
||||
assertEquals("location/of".equals(matchedPatterns.get("2")), true);
|
||||
}
|
||||
|
||||
public void testMatchStrutsPackages() {
|
||||
// given
|
||||
HashMap<String, String> matchedPatterns = new HashMap<>();
|
||||
int[] pattern = wildcardHelper.compilePattern("org.apache.struts2.*");
|
||||
|
||||
// when & then
|
||||
assertTrue(wildcardHelper.match(matchedPatterns, "org.apache.struts2.XWorkTestCase", pattern));
|
||||
assertEquals("org.apache.struts2.XWorkTestCase", matchedPatterns.get("0"));
|
||||
assertEquals("XWorkTestCase", matchedPatterns.get("1"));
|
||||
|
||||
assertTrue(wildcardHelper.match(matchedPatterns, "org.apache.struts2.core.SomeClass", pattern));
|
||||
assertEquals("org.apache.struts2.core.SomeClass", matchedPatterns.get("0"));
|
||||
assertEquals("core.SomeClass", matchedPatterns.get("1"));
|
||||
|
||||
assertTrue(wildcardHelper.match(matchedPatterns, "org.apache.struts2.", pattern));
|
||||
assertEquals("org.apache.struts2.", matchedPatterns.get("0"));
|
||||
assertEquals("", matchedPatterns.get("1"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,13 +18,12 @@
|
||||
*/
|
||||
package org.apache.struts2.views.jsp.ui;
|
||||
|
||||
import org.apache.struts2.config.ConfigurationException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.PrepareOperations;
|
||||
import org.apache.struts2.views.jsp.AbstractUITagTest;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -59,7 +58,7 @@ public class DebugTagTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
// DebugTag has no additional state, so it compares as equal with the default tag clear state as well.
|
||||
assertTrue("Tag state after doEndTag() under default tag clear state is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
@@ -82,7 +81,7 @@ public class DebugTagTest extends AbstractUITagTest {
|
||||
freshTag.setPerformClearTagStateForTagPoolingServers(true);
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
@@ -98,7 +97,7 @@ public class DebugTagTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
// DebugTag has no additional state, so it compares as equal with the default tag clear state as well.
|
||||
assertTrue("Tag state after doEndTag() under default tag clear state is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
@@ -116,7 +115,7 @@ public class DebugTagTest extends AbstractUITagTest {
|
||||
freshTag.setPerformClearTagStateForTagPoolingServers(true);
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
@@ -135,7 +134,7 @@ public class DebugTagTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
// DebugTag has no additional state, so it compares as equal with the default tag clear state as well.
|
||||
assertTrue("Tag state after doEndTag() under default tag clear state is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
|
||||
PrepareOperations.clearDevModeOverride(); // Clear DevMode override. Avoid ThreadLocal side-effects if test thread re-used.
|
||||
@@ -158,7 +157,7 @@ public class DebugTagTest extends AbstractUITagTest {
|
||||
freshTag.setPerformClearTagStateForTagPoolingServers(true);
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
|
||||
PrepareOperations.clearDevModeOverride(); // Clear DevMode override. Avoid ThreadLocal side-effects if test thread re-used.
|
||||
@@ -177,7 +176,7 @@ public class DebugTagTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
// DebugTag has no additional state, so it compares as equal with the default tag clear state as well.
|
||||
assertTrue("Tag state after doEndTag() under default tag clear state is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
|
||||
PrepareOperations.clearDevModeOverride(); // Clear DevMode override. Avoid ThreadLocal side-effects if test thread re-used.
|
||||
@@ -198,16 +197,14 @@ public class DebugTagTest extends AbstractUITagTest {
|
||||
freshTag.setPerformClearTagStateForTagPoolingServers(true);
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
|
||||
PrepareOperations.clearDevModeOverride(); // Clear DevMode override. Avoid ThreadLocal side-effects if test thread re-used.
|
||||
}
|
||||
|
||||
private void setDevMode(final boolean devMode) {
|
||||
setStrutsConstant(new HashMap<String, String>() {{
|
||||
put(StrutsConstants.STRUTS_DEVMODE, Boolean.toString(devMode));
|
||||
}});
|
||||
setStrutsConstant(Collections.singletonMap(StrutsConstants.STRUTS_DEVMODE, Boolean.toString(devMode)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>7.0.0</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.0</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.0</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.0</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.0</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.0</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.0</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.0</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.0</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.0</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.0</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.0</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.0</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.0</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.0</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.0</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.0</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.0</version>
|
||||
<version>7.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-tiles-plugin</artifactId>
|
||||
@@ -40,7 +40,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<version>3.5.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>compile</phase>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>7.0.0</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.0</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.0</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_0</tag>
|
||||
<tag>STRUTS_7_0_3</tag>
|
||||
</scm>
|
||||
|
||||
<issueManagement>
|
||||
@@ -104,18 +104,18 @@
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.build.outputTimestamp>2024-12-11T06:54:21Z</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>
|
||||
|
||||
<!-- dependency versions in alphanumeric order -->
|
||||
<asm.version>9.7.1</asm.version>
|
||||
<byte-buddy.version>1.14.11</byte-buddy.version>
|
||||
<freemarker.version>2.3.33</freemarker.version>
|
||||
<byte-buddy.version>1.16.1</byte-buddy.version>
|
||||
<freemarker.version>2.3.34</freemarker.version>
|
||||
<hibernate-validator.version>8.0.1.Final</hibernate-validator.version>
|
||||
<jackson.version>2.18.2</jackson.version>
|
||||
<log4j2.version>2.24.2</log4j2.version>
|
||||
<log4j2.version>2.24.3</log4j2.version>
|
||||
<maven-surefire-plugin.version>3.5.2</maven-surefire-plugin.version>
|
||||
<mockito.version>5.8.0</mockito.version>
|
||||
<ognl.version>3.3.5</ognl.version>
|
||||
@@ -484,7 +484,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.17.1</version>
|
||||
<version>2.18.0</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
@@ -606,42 +606,11 @@
|
||||
<version>3.1.8</version>
|
||||
</dependency>
|
||||
|
||||
<!-- override version of error_prone_annotations until caffeine updates from 2.10.0 to 2.23.0 -->
|
||||
<dependency>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_annotations</artifactId>
|
||||
<version>2.23.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>org.apache.felix.framework</artifactId>
|
||||
<version>6.0.3</version>
|
||||
<scope>provided
|
||||
</scope> <!-- felix-main provides everything in felix-framework (and more), override here to provent both JARs from being included in the build. -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>org.apache.felix.main</artifactId>
|
||||
<version>7.0.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>org.apache.felix.shell</artifactId>
|
||||
<version>1.4.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>org.apache.felix.shell.tui</artifactId>
|
||||
<version>1.4.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Velocity -->
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
<artifactId>velocity-engine-core</artifactId>
|
||||
<version>2.3</version>
|
||||
<version>2.4.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -727,40 +696,12 @@
|
||||
<version>5.0.0-M1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.web</groupId>
|
||||
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet.jsp.jstl</groupId>
|
||||
<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.el</groupId>
|
||||
<artifactId>jakarta.el-api</artifactId>
|
||||
<version>5.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-jasper</artifactId>
|
||||
<version>10.1.15</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-api</artifactId>
|
||||
<version>10.1.15</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet.jsp</groupId>
|
||||
<artifactId>jakarta.servlet.jsp-api</artifactId>
|
||||
@@ -768,19 +709,6 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>taglibs</groupId>
|
||||
<artifactId>request</artifactId>
|
||||
<version>1.0.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-juli</artifactId>
|
||||
<version>10.1.15</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Commons -->
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
@@ -800,7 +728,7 @@
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.15.1</version>
|
||||
<version>2.18.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
@@ -810,12 +738,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-text</artifactId>
|
||||
<version>1.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-el</groupId>
|
||||
<artifactId>commons-el</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.13.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
@@ -884,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>
|
||||
|
||||
@@ -921,13 +844,6 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jmock</groupId>
|
||||
<artifactId>jmock-cglib</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
@@ -983,17 +899,6 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.github.x-stream</groupId>
|
||||
<artifactId>mxparser</artifactId>
|
||||
<version>1.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.persistence</groupId>
|
||||
<artifactId>jakarta.persistence-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
@@ -1041,13 +946,6 @@
|
||||
<version>5.1.2.Final</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>xerces</groupId>
|
||||
<artifactId>xercesImpl</artifactId>
|
||||
<version>2.12.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user