mirror of
https://github.com/apache/struts.git
synced 2026-08-11 01:27:14 +00:00
Compare commits
133 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9c5c80d173 | |||
| a6d6d918fa | |||
| 5e8b81b382 | |||
| f8381fbdbf | |||
| 0f6d5dbb2f | |||
| db725518ee | |||
| ee38cd5b14 | |||
| 7a79576bb3 | |||
| 5cf746f538 | |||
| 689d17d274 | |||
| c7ae614824 | |||
| 273c3a1a99 | |||
| c774e23ef9 | |||
| 93c11aaf62 | |||
| 66c1ac431f | |||
| 7281d7e2ee | |||
| 6950fcb75f | |||
| dc774c484f | |||
| 19698e1fd2 | |||
| cda2a2b231 | |||
| cdc931e26f | |||
| db0bd43855 | |||
| 86aee4b0ea | |||
| 29422e47fe | |||
| e08f637be9 | |||
| ac6c88ad4b | |||
| c320181275 | |||
| f459981022 | |||
| 6648cbdb23 | |||
| ac6095d1ae | |||
| 154132d469 | |||
| 43f1197961 | |||
| 0c4e21145d | |||
| 3aa63e8cbb | |||
| 82491eff87 | |||
| d9ed77d3f8 | |||
| 8283ded5e2 | |||
| 1ddf446f78 | |||
| 94b2ee7ce5 | |||
| 43d180f362 | |||
| 93fa72ee13 | |||
| 9d2a7649c5 | |||
| c553c93fab | |||
| a84f85798b | |||
| bb3edaec06 | |||
| 1c59b45a23 | |||
| de9aacef61 | |||
| e3ca240b70 | |||
| 0a2861b8a3 | |||
| 694b97cc3c | |||
| 42e8ad1cc2 | |||
| e9eae281c3 | |||
| 07f0d1eddb | |||
| 6d6097c729 | |||
| 4aa1cbc56b | |||
| ce24675221 | |||
| 889a4180cd | |||
| 93f0a5116b | |||
| b5fca66ad0 | |||
| ace6a713c4 | |||
| 9328ae7ec1 | |||
| eb469779f7 | |||
| 372aad2c6c | |||
| b836072956 | |||
| a358db5853 | |||
| abd824fdd2 | |||
| 218e634bf1 | |||
| fd7e74867c | |||
| 27f0b56966 | |||
| 8ef55db35f | |||
| fd2cf91601 | |||
| f8a8172a3e | |||
| 71d28ed90d | |||
| 77285186df | |||
| 028fedd306 | |||
| 8087ba97ee | |||
| e299bba112 | |||
| bd783a0e19 | |||
| 5057aeac83 | |||
| 7843cd5e1c | |||
| 2513fcb292 | |||
| 644bd1f8ca | |||
| e7a13b9637 | |||
| 2de30e72a9 | |||
| 65c0427eae | |||
| 9f4b67a9a2 | |||
| cf74a4450c | |||
| ec18f0eef1 | |||
| cde86457ab | |||
| 1e56b7ce68 | |||
| 775febbdfa | |||
| a763071d21 | |||
| dd0f0b05a5 | |||
| 9a6411c8c5 | |||
| 3ec313aa0b | |||
| 3a1a89a547 | |||
| 71d77df3f3 | |||
| 790c663ddd | |||
| d5932f82fa | |||
| 5ee3811824 | |||
| b50616942b | |||
| 72f551f40b | |||
| fdd996c686 | |||
| dc96c257d4 | |||
| 728d695ce1 | |||
| e9738698a4 | |||
| d0ac76b9a4 | |||
| bdcedc55b3 | |||
| 0a94b50bcc | |||
| ceb0a9a737 | |||
| 686189c1b3 | |||
| 9b5cb2d7b5 | |||
| 3c8fff46d4 | |||
| 49b9c0c78c | |||
| d8dc720d4b | |||
| 56d8361b41 | |||
| bf7737fa07 | |||
| f106b20983 | |||
| 6df80041e3 | |||
| 770d311105 | |||
| 0a71e2c3b9 | |||
| a57c2882e7 | |||
| b2c7542265 | |||
| 4c60f39c7a | |||
| 5d79301235 | |||
| e9154b922c | |||
| 4c5f2b0266 | |||
| bf3f407b5f | |||
| 55ca7a5b34 | |||
| 4255da3ee9 | |||
| ad576f0fd5 | |||
| eca0666f0a | |||
| 96618ebbdf |
@@ -13,7 +13,13 @@ notifications:
|
||||
github:
|
||||
del_branch_on_merge: true
|
||||
protected_branches:
|
||||
master: { }
|
||||
master:
|
||||
# contexts are the names of checks that must pass.
|
||||
contexts:
|
||||
- build
|
||||
required_pull_request_reviews:
|
||||
require_code_owner_reviews: true
|
||||
required_approving_review_count: 1
|
||||
autolink_jira:
|
||||
- WW
|
||||
dependabot_alerts: true
|
||||
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
publish_results: true
|
||||
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # 4.0.0
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # 4.3.1
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
|
||||
@@ -31,6 +31,7 @@ jobs:
|
||||
sonarcloud:
|
||||
name: Scan
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
-117
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-present the original author or authors.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Properties;
|
||||
|
||||
public class MavenWrapperDownloader {
|
||||
|
||||
private static final String WRAPPER_VERSION = "0.5.6";
|
||||
/**
|
||||
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
|
||||
*/
|
||||
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
|
||||
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
|
||||
|
||||
/**
|
||||
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
|
||||
* use instead of the default one.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
|
||||
".mvn/wrapper/maven-wrapper.properties";
|
||||
|
||||
/**
|
||||
* Path where the maven-wrapper.jar will be saved to.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_JAR_PATH =
|
||||
".mvn/wrapper/maven-wrapper.jar";
|
||||
|
||||
/**
|
||||
* Name of the property which should be used to override the default download url for the wrapper.
|
||||
*/
|
||||
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("- Downloader started");
|
||||
File baseDirectory = new File(args[0]);
|
||||
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
|
||||
|
||||
// If the maven-wrapper.properties exists, read it and check if it contains a custom
|
||||
// wrapperUrl parameter.
|
||||
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
|
||||
String url = DEFAULT_DOWNLOAD_URL;
|
||||
if(mavenWrapperPropertyFile.exists()) {
|
||||
FileInputStream mavenWrapperPropertyFileInputStream = null;
|
||||
try {
|
||||
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
|
||||
Properties mavenWrapperProperties = new Properties();
|
||||
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
|
||||
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
|
||||
} finally {
|
||||
try {
|
||||
if(mavenWrapperPropertyFileInputStream != null) {
|
||||
mavenWrapperPropertyFileInputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore ...
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading from: " + url);
|
||||
|
||||
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
|
||||
if(!outputFile.getParentFile().exists()) {
|
||||
if(!outputFile.getParentFile().mkdirs()) {
|
||||
System.out.println(
|
||||
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
|
||||
try {
|
||||
downloadFileFromURL(url, outputFile);
|
||||
System.out.println("Done");
|
||||
System.exit(0);
|
||||
} catch (Throwable e) {
|
||||
System.out.println("- Error downloading");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
|
||||
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
|
||||
String username = System.getenv("MVNW_USERNAME");
|
||||
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(username, password);
|
||||
}
|
||||
});
|
||||
}
|
||||
URL website = new URL(urlString);
|
||||
ReadableByteChannel rbc;
|
||||
rbc = Channels.newChannel(website.openStream());
|
||||
FileOutputStream fos = new FileOutputStream(destination);
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
fos.close();
|
||||
rbc.close();
|
||||
}
|
||||
|
||||
}
|
||||
+4
-4
@@ -5,14 +5,14 @@
|
||||
# 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.
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
|
||||
|
||||
Vendored
+11
-51
@@ -67,14 +67,9 @@ pipeline {
|
||||
MAVEN_OPTS = "-Xmx1024m"
|
||||
}
|
||||
stages {
|
||||
stage('Build') {
|
||||
stage('Test & Coverage') {
|
||||
steps {
|
||||
sh './mvnw -B -DskipAssembly verify --no-transfer-progress'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh './mvnw -B verify -Pcoverage -DskipAssembly'
|
||||
sh './mvnw -B verify -Pcoverage -DskipAssembly --no-transfer-progress'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
@@ -91,7 +86,7 @@ pipeline {
|
||||
}
|
||||
steps {
|
||||
withCredentials([string(credentialsId: 'asf-struts-sonarcloud', variable: 'SONARCLOUD_TOKEN')]) {
|
||||
sh './mvnw -B -Pcoverage -DskipAssembly -Dsonar.login=${SONARCLOUD_TOKEN} verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar'
|
||||
sh './mvnw -B -Pcoverage -DskipAssembly -Dsonar.login=${SONARCLOUD_TOKEN} verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar --no-transfer-progress'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,7 +98,7 @@ pipeline {
|
||||
dir("local-snapshots-dir/") {
|
||||
deleteDir()
|
||||
}
|
||||
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly'
|
||||
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly --no-transfer-progress'
|
||||
}
|
||||
}
|
||||
stage('Deploy Snapshot') {
|
||||
@@ -112,7 +107,7 @@ pipeline {
|
||||
}
|
||||
steps {
|
||||
withCredentials([file(credentialsId: 'lukaszlenart-repository-access-token', variable: 'CUSTOM_SETTINGS')]) {
|
||||
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly'
|
||||
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly --no-transfer-progress'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,7 +116,7 @@ pipeline {
|
||||
branch 'release/struts-7-0-x'
|
||||
}
|
||||
steps {
|
||||
sh './mvnw -B package -DskipTests'
|
||||
sh './mvnw -B package -DskipTests --no-transfer-progress'
|
||||
sshPublisher(publishers: [
|
||||
sshPublisherDesc(
|
||||
configName: 'Nightlies',
|
||||
@@ -145,41 +140,6 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('JDK 11') {
|
||||
agent {
|
||||
label 'ubuntu'
|
||||
}
|
||||
tools {
|
||||
jdk 'jdk_11_latest'
|
||||
maven 'maven_3_latest'
|
||||
}
|
||||
environment {
|
||||
MAVEN_OPTS = "-Xmx1024m"
|
||||
}
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh './mvnw -B -DskipAssembly verify --no-transfer-progress'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh './mvnw -B test'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit(testResults: '**/surefire-reports/*.xml', allowEmptyResults: true)
|
||||
junit(testResults: '**/failsafe-reports/*.xml', allowEmptyResults: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
cleanWs deleteDirs: true, patterns: [[pattern: '**/target/**', type: 'INCLUDE']]
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('JDK 8') {
|
||||
agent {
|
||||
label 'ubuntu'
|
||||
@@ -194,12 +154,12 @@ pipeline {
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh './mvnw -B clean install -DskipTests -DskipAssembly'
|
||||
sh './mvnw -B clean install -DskipTests -DskipAssembly --no-transfer-progress'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh './mvnw -B test'
|
||||
sh './mvnw -B verify --no-transfer-progress'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
@@ -216,7 +176,7 @@ pipeline {
|
||||
dir("local-snapshots-dir/") {
|
||||
deleteDir()
|
||||
}
|
||||
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly'
|
||||
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly --no-transfer-progress'
|
||||
}
|
||||
}
|
||||
stage('Deploy Snapshot') {
|
||||
@@ -225,7 +185,7 @@ pipeline {
|
||||
}
|
||||
steps {
|
||||
withCredentials([file(credentialsId: 'lukaszlenart-repository-access-token', variable: 'CUSTOM_SETTINGS')]) {
|
||||
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly'
|
||||
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly --no-transfer-progress'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,7 +194,7 @@ pipeline {
|
||||
branch 'master'
|
||||
}
|
||||
steps {
|
||||
sh './mvnw -B package -DskipTests'
|
||||
sh './mvnw -B package -DskipTests --no-transfer-progress'
|
||||
sshPublisher(publishers: [
|
||||
sshPublisherDesc(
|
||||
configName: 'Nightlies',
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
The Apache Struts web framework
|
||||
-------------------------------
|
||||
|
||||
[](https://ci-builds.apache.org/job/Struts/job/Struts%20Core/job/master/)
|
||||
[](https://ci-builds.apache.org/job/Struts/job/Struts%20Core/job/master/)
|
||||
[](https://github.com/apache/struts/actions/workflows/maven.yml)
|
||||
[](https://maven-badges.herokuapp.com/maven-central/org.apache.struts/struts2-core/)
|
||||
[](https://javadoc.io/doc/org.apache.struts/struts2-core)
|
||||
|
||||
+6
-6
@@ -2,13 +2,13 @@
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Please vist the [Releases](https://struts.apache.org/releases.html#prior-releases) page to see full information about each version
|
||||
Please visit the [Releases](https://struts.apache.org/releases.html#prior-releases) page to see full information about each version
|
||||
and what potential vulnerability it can have:
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 6.0.0 | :white_check_mark: |
|
||||
| 2.5.30 | :white_check_mark: |
|
||||
|---------|--------------------|
|
||||
| 6.x | :white_check_mark: |
|
||||
| 2.5.x | :white_check_mark: |
|
||||
|
||||
## Reporting New Security Issues with thr Apache Struts
|
||||
|
||||
@@ -28,8 +28,8 @@ All mail sent to this address that does not relate to security problems in the A
|
||||
```
|
||||
|
||||
Note that all networked servers are subject to denial of service attacks, and we cannot promise magic
|
||||
workarounds to generic problems (such as a client streaming lots of data to your server, or re-requesting
|
||||
the same URL repeatedly). In general our philosophy is to avoid any attacks which can cause the server
|
||||
workarounds to generic problems (such as a client streaming lots of data to your server, or requesting
|
||||
the same URL repeatedly). In general, our philosophy is to avoid any attacks that can cause the server
|
||||
to consume resources in a non-linear relationship to the size of inputs.
|
||||
|
||||
The mailing address is: [security@struts.apache.org](mailto:security@struts.apache.org)
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-rest-showcase</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</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>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-showcase</artifactId>
|
||||
|
||||
@@ -24,9 +24,15 @@ import com.opensymphony.xwork2.ActionSupport;
|
||||
import com.opensymphony.xwork2.Validateable;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.interceptor.parameter.StrutsParameter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*/
|
||||
@@ -89,6 +95,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
return leftSideCartoonCharacters;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setLeftSideCartoonCharacters(List leftSideCartoonCharacters) {
|
||||
this.leftSideCartoonCharacters = leftSideCartoonCharacters;
|
||||
}
|
||||
@@ -98,6 +105,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
return rightSideCartoonCharacters;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setRightSideCartoonCharacters(List rightSideCartoonCharacters) {
|
||||
this.rightSideCartoonCharacters = rightSideCartoonCharacters;
|
||||
}
|
||||
@@ -107,6 +115,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
return favouriteVehicalType;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setFavouriteVehicalType(String favouriteVehicalType) {
|
||||
this.favouriteVehicalType = favouriteVehicalType;
|
||||
}
|
||||
@@ -115,6 +124,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
return favouriteVehicalSpecific;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setFavouriteVehicalSpecific(String favouriteVehicalSpecific) {
|
||||
this.favouriteVehicalSpecific = favouriteVehicalSpecific;
|
||||
}
|
||||
@@ -145,6 +155,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
return name;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
@@ -153,6 +164,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
return birthday;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setBirthday(Date birthday) {
|
||||
this.birthday = birthday;
|
||||
}
|
||||
@@ -161,6 +173,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
return bio;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setBio(String bio) {
|
||||
this.bio = bio;
|
||||
}
|
||||
@@ -169,6 +182,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
return favouriteColor;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setFavouriteColor(String favoriteColor) {
|
||||
this.favouriteColor = favoriteColor;
|
||||
}
|
||||
@@ -177,6 +191,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
return friends;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setFriends(List friends) {
|
||||
this.friends = friends;
|
||||
}
|
||||
@@ -193,6 +208,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
return legalAge;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setLegalAge(boolean legalAge) {
|
||||
this.legalAge = legalAge;
|
||||
}
|
||||
@@ -201,6 +217,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
return state;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
@@ -209,6 +226,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
return region;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setRegion(String region) {
|
||||
this.region = region;
|
||||
}
|
||||
@@ -229,6 +247,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
this.pictureFileName = pictureFileName;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setFavouriteLanguage(String favouriteLanguage) {
|
||||
this.favouriteLanguage = favouriteLanguage;
|
||||
}
|
||||
@@ -237,7 +256,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
return favouriteLanguage;
|
||||
}
|
||||
|
||||
|
||||
@StrutsParameter
|
||||
public void setThoughts(String thoughts) {
|
||||
this.thoughts = thoughts;
|
||||
}
|
||||
@@ -250,6 +269,7 @@ public class UITagExample extends ActionSupport implements Validateable {
|
||||
return wakeup;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setWakeup(Date wakeup) {
|
||||
this.wakeup = wakeup;
|
||||
}
|
||||
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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.showcase.action;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.parameter.StrutsParameter;
|
||||
import org.apache.struts2.showcase.model.MyDto;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.singletonMap;
|
||||
|
||||
/**
|
||||
* This class supports {@link com.atlassian.confluence.stateless.webdriver.selenium3.security.StrutsParametersTest}
|
||||
* which prevents critical security regressions. Do NOT modify without understanding the motivation behind the tests and
|
||||
* the implications of any changes.
|
||||
*/
|
||||
public class ParamsAnnotationAction extends ActionSupport {
|
||||
|
||||
@StrutsParameter
|
||||
public String varToPrint;
|
||||
|
||||
public String publicField = "no";
|
||||
|
||||
@StrutsParameter
|
||||
public String publicFieldAnnotated = "no";
|
||||
|
||||
private String privateField = "no";
|
||||
|
||||
public int[] publicArray = new int[]{0};
|
||||
|
||||
@StrutsParameter(depth = 1)
|
||||
public int[] publicArrayAnnotated = new int[]{0};
|
||||
|
||||
public List<String> publicList = new ArrayList<>(singletonList("no"));
|
||||
|
||||
@StrutsParameter(depth = 1)
|
||||
public List<String> publicListAnnotated = new ArrayList<>(singletonList("no"));
|
||||
|
||||
private List<String> privateList = new ArrayList<>(singletonList("no"));
|
||||
|
||||
public Map<String, String> publicMap = new HashMap<>(singletonMap("key", "no"));
|
||||
|
||||
@StrutsParameter(depth = 1)
|
||||
public Map<String, String> publicMapAnnotated = new HashMap<>(singletonMap("key", "no"));
|
||||
|
||||
public MyDto publicMyDto = new MyDto();
|
||||
|
||||
@StrutsParameter(depth = 2)
|
||||
public MyDto publicMyDtoAnnotated = new MyDto();
|
||||
|
||||
@StrutsParameter(depth = 1)
|
||||
public MyDto publicMyDtoAnnotatedDepthOne = new MyDto();
|
||||
|
||||
private MyDto privateMyDto = new MyDto();
|
||||
|
||||
public void setPrivateFieldMethod(String privateField) {
|
||||
this.privateField = privateField;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setPrivateFieldMethodAnnotated(String privateField) {
|
||||
this.privateField = privateField;
|
||||
}
|
||||
|
||||
public List<String> getPrivateListMethod() {
|
||||
return privateList;
|
||||
}
|
||||
|
||||
@StrutsParameter(depth = 1)
|
||||
public List<String> getPrivateListMethodAnnotated() {
|
||||
return privateList;
|
||||
}
|
||||
|
||||
public MyDto getUnsafeMethodMyDto() {
|
||||
return privateMyDto;
|
||||
}
|
||||
|
||||
@StrutsParameter(depth = 2)
|
||||
public MyDto getSafeMethodMyDto() {
|
||||
return privateMyDto;
|
||||
}
|
||||
|
||||
@StrutsParameter(depth = 1)
|
||||
public MyDto getSafeMethodMyDtoDepthOne() {
|
||||
return privateMyDto;
|
||||
}
|
||||
|
||||
public String renderVarToPrint() throws ReflectiveOperationException {
|
||||
if (varToPrint == null) {
|
||||
return "null";
|
||||
}
|
||||
Field field = this.getClass().getDeclaredField(varToPrint);
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
return String.format("%s{%s}", varToPrint,
|
||||
field.getType().isArray() ? stringifyArray(field.get(this)) : field.get(this));
|
||||
} finally {
|
||||
field.setAccessible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private String stringifyArray(Object array) {
|
||||
switch (array.getClass().getComponentType().getName()) {
|
||||
case "int":
|
||||
return Arrays.toString((int[]) array);
|
||||
default:
|
||||
return "TODO";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ package org.apache.struts2.showcase.action;
|
||||
import com.opensymphony.xwork2.Preparable;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.interceptor.parameter.StrutsParameter;
|
||||
import org.apache.struts2.showcase.dao.Dao;
|
||||
import org.apache.struts2.showcase.dao.SkillDao;
|
||||
import org.apache.struts2.showcase.model.Skill;
|
||||
@@ -71,6 +72,7 @@ public class SkillAction extends AbstractCRUDAction implements Preparable {
|
||||
return skillDao;
|
||||
}
|
||||
|
||||
@StrutsParameter(depth = 1)
|
||||
public Skill getCurrentSkill() {
|
||||
return currentSkill;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package org.apache.struts2.showcase.async;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.parameter.StrutsParameter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -34,10 +35,12 @@ public class ChatRoomAction extends ActionSupport {
|
||||
|
||||
private static final List<String> messages = new ArrayList<>();
|
||||
|
||||
@StrutsParameter
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setLastIndex(Integer lastIndex) {
|
||||
this.lastIndex = lastIndex;
|
||||
}
|
||||
|
||||
+3
-1
@@ -21,6 +21,7 @@
|
||||
package org.apache.struts2.showcase.conversion;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.parameter.StrutsParameter;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
@@ -30,7 +31,7 @@ import java.util.Set;
|
||||
*/
|
||||
public class AddressAction extends ActionSupport {
|
||||
|
||||
private Set<Address> addresses = new LinkedHashSet<Address>();
|
||||
private Set<Address> addresses = new LinkedHashSet<>();
|
||||
|
||||
public String input() throws Exception {
|
||||
return SUCCESS;
|
||||
@@ -41,6 +42,7 @@ public class AddressAction extends ActionSupport {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@StrutsParameter(depth = 2)
|
||||
public Set<Address> getAddresses() {
|
||||
return addresses;
|
||||
}
|
||||
|
||||
+2
@@ -21,6 +21,7 @@
|
||||
package org.apache.struts2.showcase.conversion;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.parameter.StrutsParameter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
@@ -47,6 +48,7 @@ public class OperationsEnumAction extends ActionSupport {
|
||||
return this.selectedOperations;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setSelectedOperations(List<OperationsEnum> selectedOperations) {
|
||||
this.selectedOperations = selectedOperations;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
package org.apache.struts2.showcase.conversion;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.parameter.StrutsParameter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -36,6 +37,7 @@ public class PersonAction extends ActionSupport {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@StrutsParameter(depth = 2)
|
||||
public List<Person> getPersons() {
|
||||
return persons;
|
||||
}
|
||||
|
||||
+2
@@ -22,6 +22,7 @@ package org.apache.struts2.showcase.filedownload;
|
||||
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.interceptor.parameter.StrutsParameter;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
@@ -38,6 +39,7 @@ public class FileDownloadAction implements Action {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setInputPath(String value) {
|
||||
inputPath = sanitizeInputPath(value);
|
||||
}
|
||||
|
||||
+2
@@ -23,6 +23,7 @@ package org.apache.struts2.showcase.fileupload;
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.action.UploadedFilesAware;
|
||||
import org.apache.struts2.dispatcher.multipart.UploadedFile;
|
||||
import org.apache.struts2.interceptor.parameter.StrutsParameter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -65,6 +66,7 @@ public class FileUploadAction extends ActionSupport implements UploadedFilesAwar
|
||||
return caption;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setCaption(String caption) {
|
||||
this.caption = caption;
|
||||
}
|
||||
|
||||
+36
-46
@@ -22,61 +22,51 @@
|
||||
package org.apache.struts2.showcase.fileupload;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.action.UploadedFilesAware;
|
||||
import org.apache.struts2.dispatcher.multipart.UploadedFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Showcase action - mutiple file upload using array.
|
||||
*
|
||||
* @version $Date$ $Id$
|
||||
*/
|
||||
public class MultipleFileUploadUsingArrayAction extends ActionSupport {
|
||||
public class MultipleFileUploadUsingArrayAction extends ActionSupport implements UploadedFilesAware {
|
||||
|
||||
private File[] uploads = new File[0];
|
||||
private String[] uploadFileNames = new String[0];
|
||||
private String[] uploadContentTypes = new String[0];
|
||||
private List<UploadedFile> uploadedFiles;
|
||||
|
||||
public String upload() throws Exception {
|
||||
System.out.println("\n\n upload2");
|
||||
System.out.println("files:");
|
||||
for (UploadedFile u : uploadedFiles) {
|
||||
System.out.println("*** " + u + "\t" + u.length());
|
||||
}
|
||||
System.out.println("filenames:");
|
||||
for (String n : getUploadFileNames()) {
|
||||
System.out.println("*** " + n);
|
||||
}
|
||||
System.out.println("content types:");
|
||||
for (String c : getUploadContentTypes()) {
|
||||
System.out.println("*** " + c);
|
||||
}
|
||||
System.out.println("\n\n");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
public String upload() throws Exception {
|
||||
System.out.println("\n\n upload2");
|
||||
System.out.println("files:");
|
||||
for (File u : uploads) {
|
||||
System.out.println("*** " + u + "\t" + u.length());
|
||||
}
|
||||
System.out.println("filenames:");
|
||||
for (String n : uploadFileNames) {
|
||||
System.out.println("*** " + n);
|
||||
}
|
||||
System.out.println("content types:");
|
||||
for (String c : uploadContentTypes) {
|
||||
System.out.println("*** " + c);
|
||||
}
|
||||
System.out.println("\n\n");
|
||||
return SUCCESS;
|
||||
}
|
||||
@Override
|
||||
public void withUploadedFiles(List<UploadedFile> uploadedFiles) {
|
||||
this.uploadedFiles = uploadedFiles;
|
||||
}
|
||||
|
||||
public File[] getUpload() {
|
||||
return this.uploads;
|
||||
}
|
||||
private String[] getUploadFileNames() {
|
||||
return this.uploadedFiles.stream()
|
||||
.map(UploadedFile::getOriginalName)
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
public void setUpload(File[] upload) {
|
||||
this.uploads = upload;
|
||||
}
|
||||
private String[] getUploadContentTypes() {
|
||||
return this.uploadedFiles.stream()
|
||||
.map(UploadedFile::getContentType)
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
public String[] getUploadFileName() {
|
||||
return this.uploadFileNames;
|
||||
}
|
||||
|
||||
public void setUploadFileName(String[] uploadFileName) {
|
||||
this.uploadFileNames = uploadFileName;
|
||||
}
|
||||
|
||||
public String[] getUploadContentType() {
|
||||
return this.uploadContentTypes;
|
||||
}
|
||||
|
||||
public void setUploadContentType(String[] uploadContentType) {
|
||||
this.uploadContentTypes = uploadContentType;
|
||||
}
|
||||
}
|
||||
// END SNIPPET: entire-file
|
||||
+40
-48
@@ -22,64 +22,56 @@
|
||||
package org.apache.struts2.showcase.fileupload;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.action.UploadedFilesAware;
|
||||
import org.apache.struts2.dispatcher.multipart.UploadedFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Showcase action - multiple file upload using List
|
||||
*
|
||||
* @version $Date$ $Id$
|
||||
*/
|
||||
public class MultipleFileUploadUsingListAction extends ActionSupport {
|
||||
public class MultipleFileUploadUsingListAction extends ActionSupport implements UploadedFilesAware {
|
||||
|
||||
private List<File> uploads = new ArrayList<>();
|
||||
private List<String> uploadFileNames = new ArrayList<>();
|
||||
private List<String> uploadContentTypes = new ArrayList<>();
|
||||
private List<UploadedFile> uploads = new ArrayList<>();
|
||||
|
||||
public List<UploadedFile> getUpload() {
|
||||
return this.uploads;
|
||||
}
|
||||
|
||||
public List<File> getUpload() {
|
||||
return this.uploads;
|
||||
}
|
||||
@Override
|
||||
public void withUploadedFiles(List<UploadedFile> uploads) {
|
||||
this.uploads = uploads;
|
||||
}
|
||||
|
||||
public void setUpload(List<File> uploads) {
|
||||
this.uploads = uploads;
|
||||
}
|
||||
private List<String> getUploadFileNames() {
|
||||
return this.uploads.stream()
|
||||
.map(UploadedFile::getOriginalName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<String> getUploadFileName() {
|
||||
return this.uploadFileNames;
|
||||
}
|
||||
private List<String> getUploadContentTypes() {
|
||||
return this.uploads.stream()
|
||||
.map(UploadedFile::getContentType)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void setUploadFileName(List<String> uploadFileNames) {
|
||||
this.uploadFileNames = uploadFileNames;
|
||||
}
|
||||
|
||||
public List<String> getUploadContentType() {
|
||||
return this.uploadContentTypes;
|
||||
}
|
||||
|
||||
public void setUploadContentType(List<String> contentTypes) {
|
||||
this.uploadContentTypes = contentTypes;
|
||||
}
|
||||
|
||||
public String upload() throws Exception {
|
||||
|
||||
System.out.println("\n\n upload1");
|
||||
System.out.println("files:");
|
||||
for (File u : uploads) {
|
||||
System.out.println("*** " + u + "\t" + u.length());
|
||||
}
|
||||
System.out.println("filenames:");
|
||||
for (String n : uploadFileNames) {
|
||||
System.out.println("*** " + n);
|
||||
}
|
||||
System.out.println("content types:");
|
||||
for (String c : uploadContentTypes) {
|
||||
System.out.println("*** " + c);
|
||||
}
|
||||
System.out.println("\n\n");
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
// END SNIPPET: entire-file
|
||||
public String upload() throws Exception {
|
||||
System.out.println("\n\n upload1");
|
||||
System.out.println("files:");
|
||||
for (UploadedFile u : uploads) {
|
||||
System.out.println("*** " + u + "\t" + u.length());
|
||||
}
|
||||
System.out.println("filenames:");
|
||||
for (String n : getUploadFileNames()) {
|
||||
System.out.println("*** " + n);
|
||||
}
|
||||
System.out.println("content types:");
|
||||
for (String c : getUploadContentTypes()) {
|
||||
System.out.println("*** " + c);
|
||||
}
|
||||
System.out.println("\n\n");
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.showcase.model;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Collections.singletonMap;
|
||||
|
||||
public class MyDto {
|
||||
|
||||
public String str = "no";
|
||||
|
||||
public Map<String, String> map = new HashMap<>(singletonMap("key", "no"));
|
||||
public int[] array = new int[]{0};
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "str=" + str + ", map=" + map + ", array=" + Arrays.toString(array);
|
||||
}
|
||||
}
|
||||
+11
@@ -20,6 +20,8 @@
|
||||
*/
|
||||
package org.apache.struts2.showcase.validation;
|
||||
|
||||
import org.apache.struts2.interceptor.parameter.StrutsParameter;
|
||||
|
||||
import java.sql.Date;
|
||||
|
||||
/**
|
||||
@@ -44,6 +46,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
|
||||
return dateValidatorField;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setDateValidatorField(Date dateValidatorField) {
|
||||
this.dateValidatorField = dateValidatorField;
|
||||
}
|
||||
@@ -52,6 +55,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
|
||||
return emailValidatorField;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setEmailValidatorField(String emailValidatorField) {
|
||||
this.emailValidatorField = emailValidatorField;
|
||||
}
|
||||
@@ -60,6 +64,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
|
||||
return integerValidatorField;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setIntegerValidatorField(Integer integerValidatorField) {
|
||||
this.integerValidatorField = integerValidatorField;
|
||||
}
|
||||
@@ -68,6 +73,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
|
||||
return regexValidatorField;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setRegexValidatorField(String regexValidatorField) {
|
||||
this.regexValidatorField = regexValidatorField;
|
||||
}
|
||||
@@ -76,6 +82,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
|
||||
return requiredStringValidatorField;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setRequiredStringValidatorField(String requiredStringValidatorField) {
|
||||
this.requiredStringValidatorField = requiredStringValidatorField;
|
||||
}
|
||||
@@ -84,6 +91,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
|
||||
return requiredValidatorField;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setRequiredValidatorField(String requiredValidatorField) {
|
||||
this.requiredValidatorField = requiredValidatorField;
|
||||
}
|
||||
@@ -92,6 +100,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
|
||||
return stringLengthValidatorField;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setStringLengthValidatorField(String stringLengthValidatorField) {
|
||||
this.stringLengthValidatorField = stringLengthValidatorField;
|
||||
}
|
||||
@@ -100,6 +109,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
|
||||
return fieldExpressionValidatorField;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setFieldExpressionValidatorField(
|
||||
String fieldExpressionValidatorField) {
|
||||
this.fieldExpressionValidatorField = fieldExpressionValidatorField;
|
||||
@@ -109,6 +119,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
|
||||
return urlValidatorField;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setUrlValidatorField(String urlValidatorField) {
|
||||
this.urlValidatorField = urlValidatorField;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
package org.apache.struts2.showcase.wait;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.parameter.StrutsParameter;
|
||||
|
||||
/**
|
||||
* Example to illustrate the <code>execAndWait</code> interceptor.
|
||||
@@ -41,6 +42,7 @@ public class LongProcessAction extends ActionSupport {
|
||||
return time;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setTime(int time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!--
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="params-annotation" extends="velocity-default" namespace="/paramsannotation">
|
||||
<action name="test" class="org.apache.struts2.showcase.action.ParamsAnnotationAction">
|
||||
<result type="velocity">/WEB-INF/paramsannotation.vm</result>
|
||||
</action>
|
||||
</package>
|
||||
</struts>
|
||||
@@ -35,17 +35,7 @@
|
||||
<constant name="struts.action.extension" value="action,," />
|
||||
|
||||
<constant name="struts.allowlist.enable" value="true" />
|
||||
<constant name="struts.allowlist.packageNames"
|
||||
value="
|
||||
org.apache.struts2.showcase.model,
|
||||
org.apache.struts2.showcase.conversion
|
||||
"/>
|
||||
<constant name="struts.allowlist.classes"
|
||||
value="
|
||||
org.apache.struts2.showcase.UITagExample$Language,
|
||||
org.apache.struts2.showcase.UITagExample$VehicalType,
|
||||
org.apache.struts2.showcase.UITagExample$VehicalSpecific
|
||||
"/>
|
||||
<constant name="struts.parameters.requireAnnotations" value="true" />
|
||||
|
||||
<constant name="struts.convention.package.locators.basePackage" value="org.apache.struts2.showcase" />
|
||||
<constant name="struts.convention.result.path" value="/WEB-INF" />
|
||||
@@ -93,6 +83,8 @@
|
||||
|
||||
<include file="struts-dispatcher.xml" />
|
||||
|
||||
<include file="struts-params-annotation.xml" />
|
||||
|
||||
<package name="default" extends="struts-default">
|
||||
<interceptors>
|
||||
<interceptor-stack name="crudStack">
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#*
|
||||
* 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.
|
||||
*#
|
||||
<div id="output">$action.renderVarToPrint()</div>
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* 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 it.org.apache.struts2.showcase;
|
||||
|
||||
import com.gargoylesoftware.htmlunit.WebClient;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class StrutsParametersTest {
|
||||
|
||||
private WebClient webClient;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
webClient = new WebClient();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
webClient.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void public_StringField_WithoutGetterSetter_FieldNotAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("publicField", "yes");
|
||||
params.put("varToPrint", "publicField");
|
||||
assertText(params, "publicField{no}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void public_StringField_WithoutGetterSetter_FieldAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("publicFieldAnnotated", "yes");
|
||||
params.put("varToPrint", "publicFieldAnnotated");
|
||||
assertText(params, "publicFieldAnnotated{yes}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void private_StringField_WithSetter_MethodNotAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("privateFieldMethod", "yes");
|
||||
params.put("varToPrint", "privateField");
|
||||
assertText(params, "privateField{no}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void private_StringField_WithSetter_MethodAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("privateFieldMethodAnnotated", "yes");
|
||||
params.put("varToPrint", "privateField");
|
||||
assertText(params, "privateField{yes}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void public_ArrayField_WithoutGetterSetter_FieldNotAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("publicArray[0]", "1");
|
||||
params.put("varToPrint", "publicArray");
|
||||
assertText(params, "publicArray{[0]}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void public_ArrayField_WithoutGetterSetter_FieldAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("publicArrayAnnotated[0]", "1");
|
||||
params.put("varToPrint", "publicArrayAnnotated");
|
||||
assertText(params, "publicArrayAnnotated{[1]}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void public_ListField_WithoutGetterSetter_FieldNotAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("publicList[0]", "yes");
|
||||
params.put("varToPrint", "publicList");
|
||||
assertText(params, "publicList{[no]}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void public_ListField_WithoutGetterSetter_FieldAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("publicListAnnotated[0]", "yes");
|
||||
params.put("varToPrint", "publicListAnnotated");
|
||||
assertText(params, "publicListAnnotated{[yes]}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void private_ListField_WithGetterNoSetter_MethodNotAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("privateListMethod[0]", "yes");
|
||||
params.put("varToPrint", "privateList");
|
||||
assertText(params, "privateList{[no]}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void private_ListField_WithGetterNoSetter_MethodAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("privateListMethodAnnotated[0]", "yes");
|
||||
params.put("varToPrint", "privateList");
|
||||
assertText(params, "privateList{[yes]}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void public_MapField_WithoutGetterSetter_FieldNotAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("publicMap['key']", "yes");
|
||||
params.put("varToPrint", "publicMap");
|
||||
assertText(params, "publicMap{{key=no}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void public_MapField_WithoutGetterSetter_FieldAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("publicMapAnnotated['key']", "yes");
|
||||
params.put("varToPrint", "publicMapAnnotated");
|
||||
assertText(params, "publicMapAnnotated{{key=yes}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void public_MapField_Insert_WithoutGetterSetter_FieldNotAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("publicMap[999]", "yes");
|
||||
params.put("varToPrint", "publicMap");
|
||||
assertText(params, "publicMap{{key=no}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void public_MapField_Insert_WithoutGetterSetter_FieldAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("publicMapAnnotated[999]", "yes");
|
||||
params.put("varToPrint", "publicMapAnnotated");
|
||||
assertText(params, "publicMapAnnotated{{999=yes, key=no}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void public_MyDtoField_WithoutGetter_FieldNotAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("publicMyDto.str", "yes");
|
||||
params.put("publicMyDto.map['key']", "yes");
|
||||
params.put("publicMyDto.array[0]", "1");
|
||||
params.put("varToPrint", "publicMyDto");
|
||||
assertText(params, "publicMyDto{str=no, map={key=no}, array=[0]}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void public_MyDtoField_WithoutGetter_FieldAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("publicMyDtoAnnotated.str", "yes");
|
||||
params.put("publicMyDtoAnnotated.map['key']", "yes");
|
||||
params.put("publicMyDtoAnnotated.array[0]", "1");
|
||||
params.put("varToPrint", "publicMyDtoAnnotated");
|
||||
assertText(params, "publicMyDtoAnnotated{str=yes, map={key=yes}, array=[1]}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void public_MyDtoField_WithoutGetter_FieldAnnotatedDepthOne() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("publicMyDtoAnnotatedDepthOne.str", "yes");
|
||||
params.put("publicMyDtoAnnotatedDepthOne.map['key']", "yes");
|
||||
params.put("publicMyDtoAnnotatedDepthOne.array[0]", "1");
|
||||
params.put("varToPrint", "publicMyDtoAnnotatedDepthOne");
|
||||
assertText(params, "publicMyDtoAnnotatedDepthOne{str=yes, map={key=no}, array=[0]}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void private_MyDtoField_WithGetter_MethodNotAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("unsafeMethodMyDto.str", "yes");
|
||||
params.put("unsafeMethodMyDto.map['key']", "yes");
|
||||
params.put("unsafeMethodMyDto.array[0]", "1");
|
||||
params.put("varToPrint", "privateMyDto");
|
||||
assertText(params, "privateMyDto{str=no, map={key=no}, array=[0]}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void private_MyDtoField_WithGetter_MethodNotAnnotated_Alternate() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("unsafeMethodMyDto['str']", "yes");
|
||||
params.put("unsafeMethodMyDto['map']['key']", "yes");
|
||||
params.put("unsafeMethodMyDto['map'][999]", "yes");
|
||||
params.put("unsafeMethodMyDto['array'][0]", "1");
|
||||
params.put("varToPrint", "privateMyDto");
|
||||
assertText(params, "privateMyDto{str=no, map={key=no}, array=[0]}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void private_MyDtoField_WithGetter_MethodAnnotated() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("safeMethodMyDto.str", "yes");
|
||||
params.put("safeMethodMyDto.map['key']", "yes");
|
||||
params.put("safeMethodMyDto.array[0]", "1");
|
||||
params.put("varToPrint", "privateMyDto");
|
||||
assertText(params, "privateMyDto{str=yes, map={key=yes}, array=[1]}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void private_MyDtoField_WithGetter_MethodAnnotatedDepthOne() throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("safeMethodMyDtoDepthOne.str", "yes");
|
||||
params.put("safeMethodMyDtoDepthOne.map['key']", "yes");
|
||||
params.put("safeMethodMyDtoDepthOne.array[0]", "1");
|
||||
params.put("varToPrint", "privateMyDto");
|
||||
assertText(params, "privateMyDto{str=yes, map={key=no}, array=[0]}");
|
||||
}
|
||||
|
||||
private void assertText(Map<String, String> params, String text) throws IOException {
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(ParameterUtils.getBaseUrl()).path("/paramsannotation/test.action");
|
||||
params.forEach(builder::queryParam);
|
||||
String url = builder.toUriString();
|
||||
HtmlPage page = webClient.getPage(url);
|
||||
String output = page.getElementById("output").asNormalizedText();
|
||||
assertEquals(text, output);
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-assembly</artifactId>
|
||||
@@ -104,7 +104,9 @@
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.6.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
<include>ognl:ognl</include>
|
||||
<include>commons-fileupload:commons-fileupload</include>
|
||||
<include>org.apache.commons:commons-io</include>
|
||||
<include>com.github.ben-manes.caffeine:caffeine</include>
|
||||
<include>org.javassist:javassist</include>
|
||||
</includes>
|
||||
</dependencySet>
|
||||
</dependencySets>
|
||||
|
||||
+4
-4
@@ -25,11 +25,11 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-bom</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Struts 2 Bill of Materials</name>
|
||||
@@ -44,7 +44,7 @@
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<struts-version.version>6.4.0-SNAPSHOT</struts-version.version>
|
||||
<struts-version.version>6.4.0</struts-version.version>
|
||||
<maven.site.skip>true</maven.site.skip>
|
||||
<maven.site.deploy.skip>true</maven.site.deploy.skip>
|
||||
</properties>
|
||||
@@ -190,7 +190,7 @@
|
||||
</dependencyManagement>
|
||||
|
||||
<scm>
|
||||
<tag>STRUTS_6_3_0_1</tag>
|
||||
<tag>STRUTS_6_4_0</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>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-admin-bundle</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-demo-bundle</artifactId>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
<artifactId>struts2-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -73,6 +73,16 @@ public abstract class XWorkTestCase extends TestCase {
|
||||
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
|
||||
}
|
||||
|
||||
protected void loadButSet(Map<String, ?> properties) {
|
||||
loadConfigurationProviders(new StubConfigurationProvider() {
|
||||
@Override
|
||||
public void register(ContainerBuilder builder,
|
||||
LocatableProperties props) throws ConfigurationException {
|
||||
properties.forEach((k, v) -> props.setProperty(k, String.valueOf(v)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected <T> void loadButAdd(final Class<T> type, final T impl) {
|
||||
loadButAdd(type, Container.DEFAULT_NAME, impl);
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ import org.apache.struts2.conversion.StrutsTypeConverterHolder;
|
||||
import org.apache.struts2.ognl.OgnlGuard;
|
||||
import org.apache.struts2.ognl.ProviderAllowlist;
|
||||
import org.apache.struts2.ognl.StrutsOgnlGuard;
|
||||
import org.apache.struts2.ognl.ThreadAllowlist;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -395,6 +396,7 @@ public class DefaultConfiguration implements Configuration {
|
||||
.factory(SecurityMemberAccess.class, Scope.PROTOTYPE)
|
||||
.factory(OgnlGuard.class, StrutsOgnlGuard.class, Scope.SINGLETON)
|
||||
.factory(ProviderAllowlist.class, Scope.SINGLETON)
|
||||
.factory(ThreadAllowlist.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON);
|
||||
}
|
||||
|
||||
+3
-1
@@ -142,7 +142,9 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
providerAllowlist.clearAllowlist(this);
|
||||
if (providerAllowlist != null) {
|
||||
providerAllowlist.clearAllowlist(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected Class<?> allowAndLoadClass(String className) throws ClassNotFoundException {
|
||||
|
||||
@@ -26,6 +26,7 @@ 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 java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -75,6 +76,7 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
)));
|
||||
|
||||
private final ProviderAllowlist providerAllowlist;
|
||||
private final ThreadAllowlist threadAllowlist;
|
||||
private boolean allowStaticFieldAccess = true;
|
||||
private Set<Pattern> excludeProperties = emptySet();
|
||||
private Set<Pattern> acceptProperties = emptySet();
|
||||
@@ -89,8 +91,9 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
private boolean disallowDefaultPackageAccess = false;
|
||||
|
||||
@Inject
|
||||
public SecurityMemberAccess(@Inject ProviderAllowlist providerAllowlist) {
|
||||
public SecurityMemberAccess(@Inject ProviderAllowlist providerAllowlist, @Inject ThreadAllowlist threadAllowlist) {
|
||||
this.providerAllowlist = providerAllowlist;
|
||||
this.threadAllowlist = threadAllowlist;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,11 +102,11 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
* - block or allow access to properties (configurable-after-construction)
|
||||
*
|
||||
* @param allowStaticFieldAccess if set to true static fields (constants) will be accessible
|
||||
* @deprecated since 6.4.0, use {@link #SecurityMemberAccess(ProviderAllowlist)} instead.
|
||||
* @deprecated since 6.4.0, use {@link #SecurityMemberAccess(ProviderAllowlist, ThreadAllowlist)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public SecurityMemberAccess(boolean allowStaticFieldAccess) {
|
||||
this(null);
|
||||
this(null, null);
|
||||
useAllowStaticFieldAccess(String.valueOf(allowStaticFieldAccess));
|
||||
}
|
||||
|
||||
@@ -223,6 +226,7 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
return allowlistClasses.contains(clazz)
|
||||
|| ALLOWLIST_REQUIRED_CLASSES.contains(clazz)
|
||||
|| (providerAllowlist != null && providerAllowlist.getProviderAllowlist().contains(clazz))
|
||||
|| (threadAllowlist != null && threadAllowlist.getAllowlist().contains(clazz))
|
||||
|| isClassBelongsToPackages(clazz, ALLOWLIST_REQUIRED_PACKAGES)
|
||||
|| isClassBelongsToPackages(clazz, allowlistPackageNames);
|
||||
}
|
||||
|
||||
+13
-5
@@ -25,12 +25,14 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(DefaultAcceptedPatternsChecker.class);
|
||||
@@ -39,6 +41,12 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
|
||||
"\\w+((\\.\\w+)|(\\[\\d+])|(\\(\\d+\\))|(\\['(\\w-?|[\\u4e00-\\u9fa5]-?)+'])|(\\('(\\w-?|[\\u4e00-\\u9fa5]-?)+'\\)))*"
|
||||
};
|
||||
|
||||
/**
|
||||
* Must match {@link #ACCEPTED_PATTERNS} RegEx. Signifies characters which result in a nested lookup via OGNL.
|
||||
*/
|
||||
public static final Set<Character> NESTING_CHARS = unmodifiableSet(new HashSet<>(asList('.', '[', '(')));
|
||||
public static final String NESTING_CHARS_STR = NESTING_CHARS.stream().map(String::valueOf).collect(joining());
|
||||
|
||||
public static final String[] DMI_AWARE_ACCEPTED_PATTERNS = {
|
||||
"\\w+([:]?\\w+)?((\\.\\w+)|(\\[\\d+])|(\\(\\d+\\))|(\\['(\\w-?|[\\u4e00-\\u9fa5]-?)+'])|(\\('(\\w-?|[\\u4e00-\\u9fa5]-?)+'\\)))*([!]?\\w+)?"
|
||||
};
|
||||
@@ -74,7 +82,7 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
|
||||
newAcceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
acceptedPatterns = Collections.unmodifiableSet(newAcceptedPatterns);
|
||||
acceptedPatterns = unmodifiableSet(newAcceptedPatterns);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +93,7 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(String[] additionalPatterns) {
|
||||
setAcceptedPatterns(new HashSet<>(Arrays.asList(additionalPatterns)));
|
||||
setAcceptedPatterns(new HashSet<>(asList(additionalPatterns)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,7 +105,7 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
|
||||
newAcceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
acceptedPatterns = Collections.unmodifiableSet(newAcceptedPatterns);
|
||||
acceptedPatterns = unmodifiableSet(newAcceptedPatterns);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -469,6 +469,9 @@ public final class StrutsConstants {
|
||||
public static final String STRUTS_ADDITIONAL_EXCLUDED_PATTERNS = "struts.additional.excludedPatterns";
|
||||
public static final String STRUTS_ADDITIONAL_ACCEPTED_PATTERNS = "struts.additional.acceptedPatterns";
|
||||
|
||||
public static final String STRUTS_PARAMETERS_REQUIRE_ANNOTATIONS = "struts.parameters.requireAnnotations";
|
||||
public static final String STRUTS_PARAMETERS_REQUIRE_ANNOTATIONS_TRANSITION = "struts.parameters.requireAnnotations.transitionMode";
|
||||
|
||||
public static final String STRUTS_CONTENT_TYPE_MATCHER = "struts.contentTypeMatcher";
|
||||
|
||||
public static final String STRUTS_SMI_METHOD_REGEX = "struts.strictMethodInvocation.methodRegex";
|
||||
|
||||
@@ -99,4 +99,10 @@ public class File extends UIBean {
|
||||
public void setSize(String size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
@StrutsTagAttribute(description="Ignored during file upload")
|
||||
public void setValue(String value) {
|
||||
// ignores provided value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
*/
|
||||
package org.apache.struts2.components;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ognl.ThreadAllowlist;
|
||||
import org.apache.struts2.util.MakeIterator;
|
||||
import org.apache.struts2.views.annotations.StrutsTag;
|
||||
import org.apache.struts2.views.annotations.StrutsTagAttribute;
|
||||
@@ -188,8 +190,8 @@ import java.util.List;
|
||||
* <!-- START SNIPPET: example6description -->
|
||||
*
|
||||
* <p>Another way to create a simple loop, similar to JSTL's
|
||||
* <c:forEach begin="..." end="..." ...> is to use some
|
||||
* OGNL magic, which provides some under-the-covers magic to
|
||||
* <c:forEach begin="..." end="..." ...> is to use some
|
||||
* OGNL magic, which provides some under-the-covers magic to
|
||||
* make 0-n loops trivial. This example also loops five times.</p>
|
||||
*
|
||||
* <!-- END SNIPPET: example6description -->
|
||||
@@ -237,11 +239,17 @@ public class IteratorComponent extends ContextBean {
|
||||
protected Integer end;
|
||||
protected String stepStr;
|
||||
protected Integer step;
|
||||
private ThreadAllowlist threadAllowlist;
|
||||
|
||||
public IteratorComponent(ValueStack stack) {
|
||||
super(stack);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setThreadAllowlist(ThreadAllowlist threadAllowlist) {
|
||||
this.threadAllowlist = threadAllowlist;
|
||||
}
|
||||
|
||||
public boolean start(Writer writer) {
|
||||
//Create an iterator status if the status attribute was set.
|
||||
if (statusAttr != null) {
|
||||
@@ -298,6 +306,7 @@ public class IteratorComponent extends ContextBean {
|
||||
if ((iterator != null) && iterator.hasNext()) {
|
||||
Object currentValue = iterator.next();
|
||||
stack.push(currentValue);
|
||||
threadAllowlist.allowClass(currentValue.getClass());
|
||||
|
||||
String var = getVar();
|
||||
|
||||
|
||||
@@ -66,10 +66,6 @@ public class Radio extends ListUIBean {
|
||||
return TEMPLATE;
|
||||
}
|
||||
|
||||
public void evaluateExtraParams() {
|
||||
super.evaluateExtraParams();
|
||||
}
|
||||
|
||||
/**
|
||||
* Radio tag requires lazy evaluation as list of tags is dynamically generated using <s:iterator/>
|
||||
*
|
||||
@@ -80,8 +76,4 @@ public class Radio extends ListUIBean {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Class<?> getValueClassType() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -151,11 +151,16 @@ public class ApplicationMap extends AbstractMap<String, Object> implements Seria
|
||||
* @param key the attribute to remove.
|
||||
* @return the entry that was just removed.
|
||||
*/
|
||||
public Object remove(final String key) {
|
||||
@Override
|
||||
public Object remove(Object key) {
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
entries = null;
|
||||
|
||||
Object value = get(key);
|
||||
context.removeAttribute(key);
|
||||
context.removeAttribute(key.toString());
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ import org.apache.struts2.dispatcher.mapper.ActionMapper;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
import org.apache.struts2.dispatcher.multipart.MultiPartRequest;
|
||||
import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
|
||||
import org.apache.struts2.ognl.ThreadAllowlist;
|
||||
import org.apache.struts2.util.ObjectFactoryDestroyable;
|
||||
import org.apache.struts2.util.fs.JBossFileManager;
|
||||
|
||||
@@ -199,6 +200,7 @@ public class Dispatcher {
|
||||
private LocaleProviderFactory localeProviderFactory;
|
||||
private StaticContentLoader staticContentLoader;
|
||||
private ActionMapper actionMapper;
|
||||
private ThreadAllowlist threadAllowlist;
|
||||
|
||||
/**
|
||||
* Provide the dispatcher instance for the current thread.
|
||||
@@ -404,6 +406,11 @@ public class Dispatcher {
|
||||
return actionMapper;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setThreadAllowlist(ThreadAllowlist threadAllowlist) {
|
||||
this.threadAllowlist = threadAllowlist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all instances bound to this dispatcher instance.
|
||||
*/
|
||||
@@ -979,10 +986,12 @@ public class Dispatcher {
|
||||
public HttpServletRequest wrapRequest(HttpServletRequest request) throws IOException {
|
||||
// don't wrap more than once
|
||||
if (request instanceof StrutsRequestWrapper) {
|
||||
LOG.debug("Request already wrapped with: {}", StrutsRequestWrapper.class.getSimpleName());
|
||||
return request;
|
||||
}
|
||||
|
||||
if (isMultipartSupportEnabled(request) && isMultipartRequest(request)) {
|
||||
LOG.debug("Wrapping multipart request with: {}", MultiPartRequestWrapper.class.getSimpleName());
|
||||
request = new MultiPartRequestWrapper(
|
||||
getMultiPartRequest(),
|
||||
request,
|
||||
@@ -991,6 +1000,7 @@ public class Dispatcher {
|
||||
disableRequestAttributeValueStackLookup
|
||||
);
|
||||
} else {
|
||||
LOG.debug("Wrapping request using: {}", StrutsRequestWrapper.class.getSimpleName());
|
||||
request = new StrutsRequestWrapper(request, disableRequestAttributeValueStackLookup);
|
||||
}
|
||||
|
||||
@@ -1005,6 +1015,7 @@ public class Dispatcher {
|
||||
* @since 2.5.11
|
||||
*/
|
||||
protected boolean isMultipartSupportEnabled(HttpServletRequest request) {
|
||||
LOG.debug("Support for multipart request is enabled: {}", multipartSupportEnabled);
|
||||
return multipartSupportEnabled;
|
||||
}
|
||||
|
||||
@@ -1019,9 +1030,12 @@ public class Dispatcher {
|
||||
String httpMethod = request.getMethod();
|
||||
String contentType = request.getContentType();
|
||||
|
||||
return REQUEST_POST_METHOD.equalsIgnoreCase(httpMethod) &&
|
||||
contentType != null &&
|
||||
multipartValidationPattern.matcher(contentType.toLowerCase(Locale.ENGLISH)).matches();
|
||||
boolean isPostRequest = REQUEST_POST_METHOD.equalsIgnoreCase(httpMethod);
|
||||
boolean isProperContentType = contentType != null && multipartValidationPattern.matcher(contentType.toLowerCase(Locale.ENGLISH)).matches();
|
||||
|
||||
LOG.debug("Validating if this is a proper Multipart request. Request is POST: {} and ContentType matches pattern ({}): {}",
|
||||
isPostRequest, multipartValidationPattern, isProperContentType);
|
||||
return isPostRequest && isProperContentType;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1042,6 +1056,7 @@ public class Dispatcher {
|
||||
*/
|
||||
public void cleanUpRequest(HttpServletRequest request) {
|
||||
ContainerHolder.clear();
|
||||
threadAllowlist.clearAllowlist();
|
||||
if (!(request instanceof MultiPartRequestWrapper)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -125,11 +125,16 @@ public class RequestMap extends AbstractMap<String, Object> implements Serializa
|
||||
* @param key the name of the attribute to remove.
|
||||
* @return the value that was removed or <tt>null</tt> if the value was not found (and hence, not removed).
|
||||
*/
|
||||
public Object remove(final String key) {
|
||||
@Override
|
||||
public Object remove(final Object key) {
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
entries = null;
|
||||
|
||||
Object value = get(key);
|
||||
request.removeAttribute(key);
|
||||
request.removeAttribute(key.toString());
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Deprecated
|
||||
public interface ApplicationAware extends org.apache.struts2.action.ApplicationAware {
|
||||
|
||||
void setApplication(Map<String, Object> application);
|
||||
|
||||
@Override
|
||||
default void withApplication(Map<String, Object> application) {
|
||||
setApplication(application);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
|
||||
@Deprecated
|
||||
public interface HttpParametersAware extends org.apache.struts2.action.ParametersAware {
|
||||
|
||||
void setParameters(HttpParameters parameters);
|
||||
|
||||
@Override
|
||||
default void withParameters(HttpParameters parameters) {
|
||||
setParameters(parameters);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
|
||||
@Deprecated
|
||||
public interface ParameterAware extends org.apache.struts2.action.ParametersAware {
|
||||
|
||||
void setParameters(Map<String, String[]> map);
|
||||
|
||||
@Override
|
||||
default void withParameters(HttpParameters parameters) {
|
||||
setParameters(parameters.entrySet().stream().collect(toMap(Map.Entry::getKey, e -> e.getValue().getMultipleValues())));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
@Deprecated
|
||||
public interface PrincipalAware extends org.apache.struts2.action.PrincipalAware {
|
||||
|
||||
void setPrincipalProxy(PrincipalProxy principalProxy);
|
||||
|
||||
@Override
|
||||
default void withPrincipalProxy(PrincipalProxy principalProxy) {
|
||||
setPrincipalProxy(principalProxy);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import org.apache.struts2.dispatcher.RequestMap;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Map;
|
||||
|
||||
@Deprecated
|
||||
public interface RequestAware extends ServletRequestAware {
|
||||
|
||||
@Override
|
||||
default void setServletRequest(HttpServletRequest httpServletRequest) {
|
||||
// default no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
default void withServletRequest(HttpServletRequest request) {
|
||||
ServletRequestAware.super.withServletRequest(request);
|
||||
setRequest(new RequestMap(request));
|
||||
}
|
||||
|
||||
void setRequest(Map<String, Object> request);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@Deprecated
|
||||
public interface ServletRequestAware extends org.apache.struts2.action.ServletRequestAware {
|
||||
|
||||
void setServletRequest(HttpServletRequest httpServletRequest);
|
||||
|
||||
@Override
|
||||
default void withServletRequest(HttpServletRequest request) {
|
||||
setServletRequest(request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@Deprecated
|
||||
public interface ServletResponseAware extends org.apache.struts2.action.ServletResponseAware {
|
||||
|
||||
void setServletResponse(HttpServletResponse httpServletResponse);
|
||||
|
||||
@Override
|
||||
default void withServletResponse(HttpServletResponse response) {
|
||||
setServletResponse(response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Deprecated
|
||||
public interface SessionAware extends org.apache.struts2.action.SessionAware {
|
||||
|
||||
void setSession(Map<String, Object> session);
|
||||
|
||||
@Override
|
||||
default void withSession(Map<String, Object> session) {
|
||||
setSession(session);
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,8 @@ public final class CspInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(CspInterceptor.class);
|
||||
|
||||
private Boolean enforcingMode;
|
||||
private boolean prependServletContext = true;
|
||||
private boolean enforcingMode;
|
||||
private String reportUri;
|
||||
|
||||
@Override
|
||||
@@ -60,18 +61,23 @@ public final class CspInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
|
||||
private void applySettings(ActionInvocation invocation, CspSettings cspSettings) {
|
||||
if (enforcingMode != null) {
|
||||
LOG.trace("Applying: {} to enforcingMode", enforcingMode);
|
||||
cspSettings.setEnforcingMode(enforcingMode);
|
||||
}
|
||||
if (reportUri != null) {
|
||||
LOG.trace("Applying: {} to reportUri", reportUri);
|
||||
cspSettings.setReportUri(reportUri);
|
||||
}
|
||||
|
||||
HttpServletRequest request = invocation.getInvocationContext().getServletRequest();
|
||||
HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
|
||||
|
||||
LOG.trace("Applying: {} to enforcingMode", enforcingMode);
|
||||
cspSettings.setEnforcingMode(enforcingMode);
|
||||
|
||||
if (reportUri != null) {
|
||||
LOG.trace("Applying: {} to reportUri", reportUri);
|
||||
String finalReportUri = reportUri;
|
||||
|
||||
if (prependServletContext && (request.getContextPath() != null) && (!request.getContextPath().isEmpty())) {
|
||||
finalReportUri = request.getContextPath() + finalReportUri;
|
||||
}
|
||||
|
||||
cspSettings.setReportUri(finalReportUri);
|
||||
}
|
||||
|
||||
invocation.addPreResultListener((actionInvocation, resultCode) -> {
|
||||
LOG.trace("Applying CSP header: {} to the request", cspSettings);
|
||||
cspSettings.addCspHeaders(request, response);
|
||||
@@ -99,8 +105,23 @@ public final class CspInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
}
|
||||
|
||||
public void setEnforcingMode(String value) {
|
||||
this.enforcingMode = Boolean.parseBoolean(value);
|
||||
/**
|
||||
* Enables enforcing mode, by default all exceptions are only reported
|
||||
*
|
||||
* @param enforcingMode {@code true} to enable enforcing mode, {@code false} to keep reporting mode.
|
||||
*/
|
||||
public void setEnforcingMode(boolean enforcingMode) {
|
||||
this.enforcingMode = enforcingMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to prepend the servlet context path to the {@link #reportUri}.
|
||||
*
|
||||
* @param prependServletContext {@code true} to prepend the location with the servlet context path,
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
public void setPrependServletContext(boolean prependServletContext) {
|
||||
this.prependServletContext = prependServletContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+201
-1
@@ -25,6 +25,7 @@ import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.ClearableValueStack;
|
||||
import com.opensymphony.xwork2.util.MemberAccessValueStack;
|
||||
@@ -33,6 +34,7 @@ import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
@@ -41,17 +43,33 @@ import org.apache.struts2.action.ParameterNameAware;
|
||||
import org.apache.struts2.action.ParameterValueAware;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.ognl.ThreadAllowlist;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker.NESTING_CHARS;
|
||||
import static com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker.NESTING_CHARS_STR;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static org.apache.commons.lang3.StringUtils.indexOfAny;
|
||||
import static org.apache.commons.lang3.StringUtils.normalizeSpace;
|
||||
|
||||
/**
|
||||
@@ -70,8 +88,11 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
private boolean dmiEnabled = false;
|
||||
|
||||
protected boolean ordered = false;
|
||||
protected boolean requireAnnotations = false;
|
||||
protected boolean requireAnnotationsTransitionMode = false;
|
||||
|
||||
private ValueStackFactory valueStackFactory;
|
||||
protected ThreadAllowlist threadAllowlist;
|
||||
private ExcludedPatternsChecker excludedPatterns;
|
||||
private AcceptedPatternsChecker acceptedPatterns;
|
||||
private Set<Pattern> excludedValuePatterns = null;
|
||||
@@ -82,11 +103,35 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
this.valueStackFactory = valueStackFactory;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setThreadAllowlist(ThreadAllowlist threadAllowlist) {
|
||||
this.threadAllowlist = threadAllowlist;
|
||||
}
|
||||
|
||||
@Inject(StrutsConstants.STRUTS_DEVMODE)
|
||||
public void setDevMode(String mode) {
|
||||
this.devMode = BooleanUtils.toBoolean(mode);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_PARAMETERS_REQUIRE_ANNOTATIONS, required = false)
|
||||
public void setRequireAnnotations(String requireAnnotations) {
|
||||
this.requireAnnotations = BooleanUtils.toBoolean(requireAnnotations);
|
||||
}
|
||||
|
||||
/**
|
||||
* When 'Transition Mode' is enabled, parameters that are not 'nested' will be accepted without annotations. What
|
||||
* this means in practice is that all public setters on an Action will be exposed for parameter injection again, and
|
||||
* only 'nested' parameters, i.e. public getters on an Action, will require annotations.
|
||||
* <p>
|
||||
* In this mode, the OGNL auto-allowlisting capability is not degraded in any way, and as such, it offers a
|
||||
* convenient option for applications to enable the OGNL allowlist capability whilst they work through the process
|
||||
* of annotating all their Action parameters.
|
||||
*/
|
||||
@Inject(value = StrutsConstants.STRUTS_PARAMETERS_REQUIRE_ANNOTATIONS_TRANSITION, required = false)
|
||||
public void setRequireAnnotationsTransitionMode(String transitionMode) {
|
||||
this.requireAnnotationsTransitionMode = BooleanUtils.toBoolean(transitionMode);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setExcludedPatterns(ExcludedPatternsChecker excludedPatterns) {
|
||||
this.excludedPatterns = excludedPatterns;
|
||||
@@ -295,13 +340,168 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
* @return true if parameter is accepted
|
||||
*/
|
||||
protected boolean isAcceptableParameter(String name, Object action) {
|
||||
return acceptableName(name) && isAcceptableParameterNameAware(name, action);
|
||||
return acceptableName(name) && isAcceptableParameterNameAware(name, action) && isParameterAnnotatedAndAllowlist(name, action);
|
||||
}
|
||||
|
||||
protected boolean isAcceptableParameterNameAware(String name, Object action) {
|
||||
return !(action instanceof ParameterNameAware) || ((ParameterNameAware) action).acceptableParameterName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the Action class member corresponding to a parameter is appropriately annotated with
|
||||
* {@link StrutsParameter} and OGNL allowlists any necessary classes.
|
||||
* <p>
|
||||
* Note that this logic relies on the use of {@link DefaultAcceptedPatternsChecker#NESTING_CHARS} and may also
|
||||
* be adversely impacted by the use of custom OGNL property accessors.
|
||||
*/
|
||||
protected boolean isParameterAnnotatedAndAllowlist(String name, Object action) {
|
||||
if (!requireAnnotations) {
|
||||
return true;
|
||||
}
|
||||
|
||||
long paramDepth = name.codePoints().mapToObj(c -> (char) c).filter(NESTING_CHARS::contains).count();
|
||||
if (requireAnnotationsTransitionMode && paramDepth == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int nestingIndex = indexOfAny(name, NESTING_CHARS_STR);
|
||||
String rootProperty = nestingIndex == -1 ? name : name.substring(0, nestingIndex);
|
||||
String normalisedRootProperty = Character.toLowerCase(rootProperty.charAt(0)) + rootProperty.substring(1);
|
||||
|
||||
return hasValidAnnotatedMember(normalisedRootProperty, action, paramDepth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that we check for a public field last or only if there is no valid, annotated property descriptor. This is
|
||||
* because this check is likely to fail more often than not, as the relative use of public fields is low - so we
|
||||
* save computation by checking this last.
|
||||
*/
|
||||
protected boolean hasValidAnnotatedMember(String rootProperty, Object action, long paramDepth) {
|
||||
BeanInfo beanInfo = getBeanInfo(action);
|
||||
if (beanInfo == null) {
|
||||
return hasValidAnnotatedField(action, rootProperty, paramDepth);
|
||||
}
|
||||
|
||||
Optional<PropertyDescriptor> propDescOpt = Arrays.stream(beanInfo.getPropertyDescriptors())
|
||||
.filter(desc -> desc.getName().equals(rootProperty)).findFirst();
|
||||
if (!propDescOpt.isPresent()) {
|
||||
return hasValidAnnotatedField(action, rootProperty, paramDepth);
|
||||
}
|
||||
|
||||
if (hasValidAnnotatedPropertyDescriptor(propDescOpt.get(), paramDepth)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return hasValidAnnotatedField(action, rootProperty, paramDepth);
|
||||
}
|
||||
|
||||
protected boolean hasValidAnnotatedPropertyDescriptor(PropertyDescriptor propDesc, long paramDepth) {
|
||||
Method relevantMethod = paramDepth == 0 ? propDesc.getWriteMethod() : propDesc.getReadMethod();
|
||||
if (relevantMethod == null) {
|
||||
return false;
|
||||
}
|
||||
if (getPermittedInjectionDepth(relevantMethod) < paramDepth) {
|
||||
LOG.debug(
|
||||
"Parameter injection for method [{}] on action [{}] rejected. Ensure it is annotated with @StrutsParameter with an appropriate 'depth'.",
|
||||
relevantMethod.getName(),
|
||||
relevantMethod.getDeclaringClass().getName());
|
||||
return false;
|
||||
}
|
||||
if (paramDepth >= 1) {
|
||||
allowlistClass(relevantMethod.getReturnType());
|
||||
}
|
||||
if (paramDepth >= 2) {
|
||||
allowlistReturnTypeIfParameterized(relevantMethod);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void allowlistReturnTypeIfParameterized(Method method) {
|
||||
allowlistParameterizedTypeArg(method.getGenericReturnType());
|
||||
}
|
||||
|
||||
protected void allowlistParameterizedTypeArg(Type genericType) {
|
||||
if (!(genericType instanceof ParameterizedType)) {
|
||||
return;
|
||||
}
|
||||
Type[] paramTypes = ((ParameterizedType) genericType).getActualTypeArguments();
|
||||
allowlistParamType(paramTypes[0]);
|
||||
if (paramTypes.length > 1) {
|
||||
// Probably useful for Map or Map-like classes
|
||||
allowlistParamType(paramTypes[1]);
|
||||
}
|
||||
}
|
||||
|
||||
protected void allowlistParamType(Type paramType) {
|
||||
if (paramType instanceof Class) {
|
||||
allowlistClass((Class<?>) paramType);
|
||||
}
|
||||
}
|
||||
|
||||
protected void allowlistClass(Class<?> clazz) {
|
||||
threadAllowlist.allowClass(clazz);
|
||||
ClassUtils.getAllSuperclasses(clazz).forEach(threadAllowlist::allowClass);
|
||||
ClassUtils.getAllInterfaces(clazz).forEach(threadAllowlist::allowClass);
|
||||
}
|
||||
|
||||
protected boolean hasValidAnnotatedField(Object action, String fieldName, long paramDepth) {
|
||||
Field field;
|
||||
try {
|
||||
field = action.getClass().getDeclaredField(fieldName);
|
||||
} catch (NoSuchFieldException e) {
|
||||
return false;
|
||||
}
|
||||
if (!Modifier.isPublic(field.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
if (getPermittedInjectionDepth(field) < paramDepth) {
|
||||
LOG.debug(
|
||||
"Parameter injection for field [{}] on action [{}] rejected. Ensure it is annotated with @StrutsParameter with an appropriate 'depth'.",
|
||||
fieldName,
|
||||
action.getClass().getName());
|
||||
return false;
|
||||
}
|
||||
if (paramDepth >= 1) {
|
||||
allowlistClass(field.getType());
|
||||
}
|
||||
if (paramDepth >= 2) {
|
||||
allowlistFieldIfParameterized(field);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void allowlistFieldIfParameterized(Field field) {
|
||||
allowlistParameterizedTypeArg(field.getGenericType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return permitted injection depth where -1 indicates not permitted
|
||||
*/
|
||||
protected int getPermittedInjectionDepth(AnnotatedElement element) {
|
||||
StrutsParameter annotation = getParameterAnnotation(element);
|
||||
if (annotation == null) {
|
||||
return -1;
|
||||
}
|
||||
return annotation.depth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotation retrieval logic. Can be overridden to support extending annotations or some other form of annotation
|
||||
* inheritance.
|
||||
*/
|
||||
protected StrutsParameter getParameterAnnotation(AnnotatedElement element) {
|
||||
return element.getAnnotation(StrutsParameter.class);
|
||||
}
|
||||
|
||||
protected BeanInfo getBeanInfo(Object action) {
|
||||
try {
|
||||
return Introspector.getBeanInfo(action.getClass());
|
||||
} catch (IntrospectionException e) {
|
||||
LOG.warn("Error introspecting Action {} for parameter injection validation", action.getClass(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if parameter value can be accepted or thrown away
|
||||
*
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.parameter;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used to annotate public getter/setter methods or fields on {@link com.opensymphony.xwork2.Action} classes that are
|
||||
* intended for parameter injection by the {@link ParametersInterceptor}.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface StrutsParameter {
|
||||
|
||||
/**
|
||||
* The depth to which parameter injection is permitted, where a depth of 0 only allows setters/fields directly on
|
||||
* the action class. Setting within a POJO on an action will require a depth of 1 or more depending on the level of
|
||||
* nesting within the POJO.
|
||||
* <p>
|
||||
* In a practical sense, the depth dictates the number of periods or brackets that can appear in the parameter name.
|
||||
*/
|
||||
int depth() default 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.ognl;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Collections.emptySet;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
|
||||
/**
|
||||
* Allows any bean to allowlist a class for use in OGNL expressions, for the current thread only. The allowlist can be
|
||||
* cleared once any desired OGNL expressions have been evaluated.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*/
|
||||
public class ThreadAllowlist {
|
||||
|
||||
private final ThreadLocal<Set<Class<?>>> allowlist = new ThreadLocal<>();
|
||||
|
||||
public void allowClass(Class<?> clazz) {
|
||||
if (allowlist.get() == null) {
|
||||
allowlist.set(new HashSet<>());
|
||||
}
|
||||
allowlist.get().add(clazz);
|
||||
}
|
||||
|
||||
public void clearAllowlist() {
|
||||
allowlist.remove();
|
||||
}
|
||||
|
||||
public Set<Class<?>> getAllowlist() {
|
||||
return allowlist.get() != null ? unmodifiableSet(allowlist.get()) : emptySet();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
@Deprecated
|
||||
public interface ServletContextAware extends org.apache.struts2.action.ServletContextAware {
|
||||
|
||||
void setServletContext(ServletContext context);
|
||||
|
||||
@Override
|
||||
default void withServletContext(ServletContext context) {
|
||||
setServletContext(context);
|
||||
}
|
||||
}
|
||||
@@ -18,16 +18,14 @@
|
||||
*/
|
||||
package org.apache.struts2.views.jsp;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.struts2.components.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.jsp.JspException;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import org.apache.struts2.components.Component;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
|
||||
/**
|
||||
*/
|
||||
public abstract class ComponentTagSupport extends StrutsBodyTagSupport {
|
||||
@@ -39,8 +37,7 @@ public abstract class ComponentTagSupport extends StrutsBodyTagSupport {
|
||||
public int doEndTag() throws JspException {
|
||||
component.end(pageContext.getOut(), getBody());
|
||||
component = null; // Always clear component reference (since clearTagStateForTagPoolingServers() is conditional).
|
||||
clearTagStateForTagPoolingServers();
|
||||
return EVAL_PAGE;
|
||||
return super.doEndTag();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -49,7 +46,7 @@ public abstract class ComponentTagSupport extends StrutsBodyTagSupport {
|
||||
component = getBean(stack, (HttpServletRequest) pageContext.getRequest(), (HttpServletResponse) pageContext.getResponse());
|
||||
Container container = stack.getActionContext().getContainer();
|
||||
container.inject(component);
|
||||
|
||||
|
||||
populateParams();
|
||||
boolean evalBody = component.start(pageContext.getOut());
|
||||
|
||||
@@ -62,7 +59,7 @@ public abstract class ComponentTagSupport extends StrutsBodyTagSupport {
|
||||
|
||||
/**
|
||||
* Define method to populate component state based on the Tag parameters.
|
||||
*
|
||||
* <p>
|
||||
* Descendants should override this method for custom behaviour, but should <em>always</em> call the ancestor method when doing so.
|
||||
*/
|
||||
protected void populateParams() {
|
||||
@@ -71,7 +68,7 @@ public abstract class ComponentTagSupport extends StrutsBodyTagSupport {
|
||||
|
||||
/**
|
||||
* Specialized method to populate the performClearTagStateForTagPoolingServers state of the Component to match the value set in the Tag.
|
||||
*
|
||||
* <p>
|
||||
* Generally only unit tests would call this method directly, to avoid calling the whole populateParams() chain again after doStartTag()
|
||||
* has been called. Doing that can break tag / component state behaviour, but unit tests still need a way to set the
|
||||
* performClearTagStateForTagPoolingServers state for the component (which only comes into being after doStartTag() is called).
|
||||
|
||||
@@ -26,23 +26,29 @@ package org.apache.struts2.views.jsp;
|
||||
* <li>count: iterations so far, starts on 1. count is always index + 1</li>
|
||||
* <li>first: true if index == 0</li>
|
||||
* <li>even: true if (index + 1) % 2 == 0</li>
|
||||
* <li>last: true if current iteration is the last iteration</li>
|
||||
* <li>last: true if current iteration is the last iteration</li>
|
||||
* <li>odd: true if (index + 1) % 2 == 1</li>
|
||||
* </ul>
|
||||
* <p>Example</p>
|
||||
* <pre>
|
||||
* <s:iterator status="status" value='{0, 1}'>
|
||||
* Index: <s:property value="%{#status.index}" /> <br />
|
||||
* Count: <s:property value="%{#status.count}" /> <br />
|
||||
* Index Str: <s:property value="%{#status.indexStr}" /> <br />
|
||||
* Count: <s:property value="%{#status.count}" /> <br />
|
||||
* Count Str: <s:property value="%{#status.countStr}" /> <br />
|
||||
* </s:iterator>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <p>will print</p>
|
||||
* <pre>
|
||||
* Index: 0
|
||||
* Index Str: 0
|
||||
* Count: 1
|
||||
* Count Str: 1
|
||||
* Index: 1
|
||||
* Index Str: 1
|
||||
* Count: 2
|
||||
* Count Str: 2
|
||||
* </pre>
|
||||
*/
|
||||
public class IteratorStatus {
|
||||
@@ -56,6 +62,10 @@ public class IteratorStatus {
|
||||
return state.index + 1;
|
||||
}
|
||||
|
||||
public String getCountStr() {
|
||||
return String.valueOf(state.index + 1);
|
||||
}
|
||||
|
||||
public boolean isEven() {
|
||||
return ((state.index + 1) % 2) == 0;
|
||||
}
|
||||
@@ -68,6 +78,10 @@ public class IteratorStatus {
|
||||
return state.index;
|
||||
}
|
||||
|
||||
public String getIndexStr() {
|
||||
return String.valueOf(state.index);
|
||||
}
|
||||
|
||||
public boolean isLast() {
|
||||
return state.last;
|
||||
}
|
||||
|
||||
@@ -170,6 +170,7 @@
|
||||
<bean type="org.apache.struts2.ognl.OgnlGuard" name="struts"
|
||||
class="org.apache.struts2.ognl.StrutsOgnlGuard"/>
|
||||
<bean class="org.apache.struts2.ognl.ProviderAllowlist"/>
|
||||
<bean class="org.apache.struts2.ognl.ThreadAllowlist"/>
|
||||
|
||||
<bean type="com.opensymphony.xwork2.util.TextParser" name="struts"
|
||||
class="com.opensymphony.xwork2.util.OgnlTextParser" scope="singleton"/>
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
<#if parameters.href??>
|
||||
href="${parameters.href?no_esc}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.disabled!false>
|
||||
disabled="disabled"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.tabindex??>
|
||||
tabindex="${parameters.tabindex}"<#rt/>
|
||||
</#if>
|
||||
|
||||
@@ -371,6 +371,6 @@
|
||||
<td class="tag-attribute"></td>
|
||||
<td class="tag-attribute">false</td>
|
||||
<td class="tag-attribute">String</td>
|
||||
<td class="tag-attribute">Preset the value of input element.</td>
|
||||
<td class="tag-attribute">Ignored during file upload</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -90,43 +90,27 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
refreshContainerFields();
|
||||
}
|
||||
|
||||
protected void refreshContainerFields() {
|
||||
ognlUtil = container.getInstance(OgnlUtil.class);
|
||||
vs = createValueStack(true);
|
||||
}
|
||||
|
||||
private OgnlValueStack createValueStack(boolean allowStaticFieldAccess) {
|
||||
OgnlValueStack stack = new OgnlValueStack(
|
||||
container.getInstance(XWorkConverter.class),
|
||||
(CompoundRootAccessor) container.getInstance(RootAccessor.class),
|
||||
container.getInstance(TextProvider.class, "system"), allowStaticFieldAccess);
|
||||
container.inject(stack);
|
||||
return stack;
|
||||
vs = (OgnlValueStack) container.getInstance(ValueStackFactory.class).createValueStack();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return current OgnlValueStackFactory instance from current container
|
||||
*/
|
||||
private OgnlValueStackFactory getValueStackFactory() {
|
||||
return (OgnlValueStackFactory) container.getInstance(ValueStackFactory.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads container and gets a new OgnlValueStackFactory with specified new configuration.
|
||||
* Reloads container and sets a new OgnlValueStackFactory with specified new configuration.
|
||||
* Intended for testing OgnlValueStack instance(s) that are minimally configured.
|
||||
* This should help ensure no underlying configuration/injection side-effects are responsible
|
||||
* for the behaviour of fundamental access control flags).
|
||||
*
|
||||
* @param allowStaticField new allowStaticField configuration
|
||||
* @return a new OgnlValueStackFactory with specified new configuration
|
||||
*/
|
||||
private OgnlValueStackFactory reloadValueStackFactory(boolean allowStaticField) {
|
||||
try {
|
||||
reloadTestContainerConfiguration(allowStaticField);
|
||||
} catch (Exception ex) {
|
||||
fail("Unable to reload container configuration and configure ognlValueStackFactory - exception: " + ex);
|
||||
}
|
||||
|
||||
return getValueStackFactory();
|
||||
private void reloadContainer(boolean allowStaticField) {
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, Boolean.toString(allowStaticField));
|
||||
loadButSet(properties);
|
||||
refreshContainerFields();
|
||||
}
|
||||
|
||||
public void testExpOverridesCanStackExpUp() throws Exception {
|
||||
@@ -1159,31 +1143,29 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
* when a default configuration is used.
|
||||
*/
|
||||
public void testOgnlValueStackFromOgnlValueStackFactoryDefaultConfig() throws IllegalAccessException {
|
||||
OgnlValueStackFactory ognlValueStackFactory = getValueStackFactory();
|
||||
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
|
||||
Object accessedValue;
|
||||
|
||||
assertTrue("OgnlValueStackFactory staticFieldAccess (default flags) not true?",
|
||||
reflectField(ognlValueStack.securityMemberAccess, "allowStaticFieldAccess"));
|
||||
reflectField(vs.securityMemberAccess, "allowStaticFieldAccess"));
|
||||
// An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
|
||||
// but prevent non-public field access. It should also deny static method access.
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
|
||||
assertNull("able to access static method (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
|
||||
assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
|
||||
assertEquals("accessed static public field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
|
||||
assertNull("accessed final package field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
|
||||
assertNull("accessed package field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
|
||||
assertNull("accessed final protected field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
|
||||
assertNull("accessed protected field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
|
||||
assertNull("accessed final private field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
|
||||
assertNull("accessed private field (result not null) ?", accessedValue);
|
||||
}
|
||||
|
||||
@@ -1192,31 +1174,30 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
* when static access flag is set to false.
|
||||
*/
|
||||
public void testOgnlValueStackFromOgnlValueStackFactoryNoStaticAccess() throws IllegalAccessException {
|
||||
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(false);
|
||||
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
|
||||
reloadContainer(false);
|
||||
Object accessedValue;
|
||||
|
||||
assertFalse("OgnlValueStackFactory staticFieldAccess (set false) not false?",
|
||||
reflectField(ognlValueStack.securityMemberAccess, "allowStaticFieldAccess"));
|
||||
reflectField(vs.securityMemberAccess, "allowStaticFieldAccess"));
|
||||
// An OgnlValueStack created from the above OgnlValueStackFactory should prevent public field access,
|
||||
// and prevent non-public field access. It should also deny static method access.
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
|
||||
assertNull("able to access static method (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
|
||||
assertNull("able to access static final public field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
|
||||
assertNull("able to access static public field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
|
||||
assertNull("accessed final package field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
|
||||
assertNull("accessed package field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
|
||||
assertNull("accessed final protected field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
|
||||
assertNull("accessed protected field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
|
||||
assertNull("accessed final private field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
|
||||
assertNull("accessed private field (result not null) ?", accessedValue);
|
||||
}
|
||||
|
||||
@@ -1225,45 +1206,33 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
* when static access flag is set to true.
|
||||
*/
|
||||
public void testOgnlValueStackFromOgnlValueStackFactoryAllStaticAccess() throws IllegalAccessException {
|
||||
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(true);
|
||||
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
|
||||
reloadContainer(true);
|
||||
Object accessedValue;
|
||||
|
||||
assertTrue("OgnlValueStackFactory staticFieldAccess (set true) not true?",
|
||||
reflectField(ognlValueStack.securityMemberAccess, "allowStaticFieldAccess"));
|
||||
reflectField(vs.securityMemberAccess, "allowStaticFieldAccess"));
|
||||
// An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
|
||||
// but prevent non-public field access. It should also allow static method access.
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
|
||||
assertNull("able to access static method (result non-null)!!!", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
|
||||
assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
|
||||
assertEquals("accessed static public field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
|
||||
assertNull("accessed final package field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
|
||||
assertNull("accessed package field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
|
||||
assertNull("accessed final protected field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
|
||||
assertNull("accessed protected field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
|
||||
assertNull("accessed final private field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
|
||||
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
|
||||
assertNull("accessed private field (result not null) ?", accessedValue);
|
||||
}
|
||||
|
||||
private void reloadTestContainerConfiguration(boolean allowStaticField) throws Exception {
|
||||
loadConfigurationProviders(new StubConfigurationProvider() {
|
||||
@Override
|
||||
public void register(ContainerBuilder builder,
|
||||
LocatableProperties props) throws ConfigurationException {
|
||||
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, String.valueOf(allowStaticField));
|
||||
}
|
||||
});
|
||||
ognlUtil = container.getInstance(OgnlUtil.class);
|
||||
}
|
||||
|
||||
static class BadJavaBean {
|
||||
private int count;
|
||||
private int count2;
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.opensymphony.xwork2.util.Foo;
|
||||
import ognl.MemberAccess;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
import org.apache.struts2.ognl.ProviderAllowlist;
|
||||
import org.apache.struts2.ognl.ThreadAllowlist;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -54,18 +55,21 @@ public class SecurityMemberAccessTest {
|
||||
private FooBar target;
|
||||
protected SecurityMemberAccess sma;
|
||||
private ProviderAllowlist mockedProviderAllowlist;
|
||||
private ThreadAllowlist mockedThreadAllowlist;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
context = new HashMap<>();
|
||||
target = new FooBar();
|
||||
mockedProviderAllowlist = mock(ProviderAllowlist.class);
|
||||
mockedThreadAllowlist = mock(ThreadAllowlist.class);
|
||||
assignNewSma(true);
|
||||
}
|
||||
|
||||
protected void assignNewSma(boolean allowStaticFieldAccess) {
|
||||
when(mockedProviderAllowlist.getProviderAllowlist()).thenReturn(new HashSet<>());
|
||||
sma = new SecurityMemberAccess(mockedProviderAllowlist);
|
||||
when(mockedThreadAllowlist.getAllowlist()).thenReturn(new HashSet<>());
|
||||
sma = new SecurityMemberAccess(mockedProviderAllowlist, mockedThreadAllowlist);
|
||||
sma.useAllowStaticFieldAccess(String.valueOf(allowStaticFieldAccess));
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,12 @@ public class User implements UserMarker {
|
||||
private String email2;
|
||||
private String name;
|
||||
|
||||
public User() {
|
||||
}
|
||||
|
||||
public User(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setCollection(Collection collection) {
|
||||
this.collection = collection;
|
||||
|
||||
@@ -45,6 +45,7 @@ public class TestAction extends ActionSupport {
|
||||
private String result;
|
||||
private User user;
|
||||
private String[] array;
|
||||
private Object[] objectArray;
|
||||
private String[][] list;
|
||||
private List list2;
|
||||
private List list3;
|
||||
@@ -53,6 +54,7 @@ public class TestAction extends ActionSupport {
|
||||
private Long id;
|
||||
private List<SomeEnum> enumList;
|
||||
private List<Integer> intList;
|
||||
private Boolean someBool;
|
||||
|
||||
private final Map<String, String> texts = new HashMap<>();
|
||||
|
||||
@@ -134,6 +136,14 @@ public class TestAction extends ActionSupport {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
public Object[] getObjectArray() {
|
||||
return objectArray;
|
||||
}
|
||||
|
||||
public void setObjectArray(Object[] arrayObject) {
|
||||
this.objectArray = arrayObject;
|
||||
}
|
||||
|
||||
public String[][] getList() {
|
||||
return list;
|
||||
}
|
||||
@@ -254,4 +264,12 @@ public class TestAction extends ActionSupport {
|
||||
public void setIntList(List<Integer> intList) {
|
||||
this.intList = intList;
|
||||
}
|
||||
|
||||
public Boolean getSomeBool() {
|
||||
return someBool;
|
||||
}
|
||||
|
||||
public void setSomeBool(Boolean someBool) {
|
||||
this.someBool = someBool;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,23 +19,38 @@
|
||||
package org.apache.struts2.components;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.test.User;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
import org.apache.struts2.ognl.ThreadAllowlist;
|
||||
import org.apache.struts2.TestAction;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class IteratorComponentTest extends StrutsInternalTestCase {
|
||||
|
||||
private ValueStack stack;
|
||||
private IteratorComponent ic;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
stack = ActionContext.getContext().getValueStack();
|
||||
ic = new IteratorComponent(stack);
|
||||
ThreadAllowlist threadAllowlist = new ThreadAllowlist();
|
||||
ic.setThreadAllowlist(threadAllowlist);
|
||||
}
|
||||
|
||||
public void testIterator() throws Exception {
|
||||
// given
|
||||
final ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
stack.push(new FooAction());
|
||||
|
||||
StringWriter out = new StringWriter();
|
||||
|
||||
IteratorComponent ic = new IteratorComponent(stack);
|
||||
ic.setValue("items");
|
||||
ic.setVar("val");
|
||||
|
||||
@@ -62,14 +77,53 @@ public class IteratorComponentTest extends StrutsInternalTestCase {
|
||||
assertEquals("item1 item2 item3 item4 ", out.getBuffer().toString());
|
||||
}
|
||||
|
||||
public void testIteratorWithBegin() throws Exception {
|
||||
public void testSimpleIterator() {
|
||||
// given
|
||||
stack.push(new FooAction());
|
||||
|
||||
StringWriter out = new StringWriter();
|
||||
|
||||
ic.setBegin("1");
|
||||
ic.setEnd("8");
|
||||
ic.setStep("2");
|
||||
ic.setStatus("status");
|
||||
|
||||
Property prop = new Property(stack);
|
||||
Property status = new Property(stack);
|
||||
status.setValue("#status.index");
|
||||
|
||||
ic.getComponentStack().push(prop);
|
||||
ic.getComponentStack().push(status);
|
||||
ic.getComponentStack().push(prop);
|
||||
ic.getComponentStack().push(status);
|
||||
ic.getComponentStack().push(prop);
|
||||
ic.getComponentStack().push(status);
|
||||
ic.getComponentStack().push(prop);
|
||||
ic.getComponentStack().push(status);
|
||||
|
||||
String body = " ";
|
||||
|
||||
// when
|
||||
assertTrue(ic.start(out));
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
status.start(out);
|
||||
status.end(out, body);
|
||||
prop.start(out);
|
||||
prop.end(out, body);
|
||||
ic.end(out, null);
|
||||
}
|
||||
|
||||
// then
|
||||
assertEquals("0 1 1 3 2 5 3 7 ", out.getBuffer().toString());
|
||||
}
|
||||
|
||||
public void testIteratorWithBegin() {
|
||||
// given
|
||||
final ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
stack.push(new FooAction());
|
||||
|
||||
StringWriter out = new StringWriter();
|
||||
|
||||
IteratorComponent ic = new IteratorComponent(stack);
|
||||
ic.setValue("items");
|
||||
ic.setVar("val");
|
||||
ic.setBegin("1");
|
||||
@@ -94,20 +148,18 @@ public class IteratorComponentTest extends StrutsInternalTestCase {
|
||||
assertEquals("item2 item3 item4 ", out.getBuffer().toString());
|
||||
}
|
||||
|
||||
public void testIteratorWithNulls() throws Exception {
|
||||
public void testIteratorWithNulls() {
|
||||
// given
|
||||
final ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
stack.push(new FooAction() {
|
||||
private List items = Arrays.asList("1", "2", null, "4");
|
||||
private final List<String> items = Arrays.asList("1", "2", null, "4");
|
||||
|
||||
public List getItems() {
|
||||
public List<String> getItems() {
|
||||
return items;
|
||||
}
|
||||
});
|
||||
|
||||
StringWriter out = new StringWriter();
|
||||
|
||||
IteratorComponent ic = new IteratorComponent(stack);
|
||||
ic.setValue("items");
|
||||
ic.setVar("val");
|
||||
Property prop = new Property(stack);
|
||||
@@ -132,15 +184,147 @@ public class IteratorComponentTest extends StrutsInternalTestCase {
|
||||
assertEquals("1, 2, , 4, ", out.getBuffer().toString());
|
||||
}
|
||||
|
||||
public void testIteratorWithDifferentLocale() {
|
||||
// given
|
||||
ActionContext.getContext().withLocale(new Locale("fa_IR"));
|
||||
stack.push(new FooAction());
|
||||
|
||||
StringWriter out = new StringWriter();
|
||||
|
||||
ic.setBegin("1");
|
||||
ic.setEnd("3");
|
||||
ic.setStatus("status");
|
||||
|
||||
Property prop = new Property(stack);
|
||||
Property status = new Property(stack);
|
||||
status.setValue("#status.count");
|
||||
|
||||
ic.getComponentStack().push(prop);
|
||||
ic.getComponentStack().push(status);
|
||||
ic.getComponentStack().push(prop);
|
||||
ic.getComponentStack().push(status);
|
||||
ic.getComponentStack().push(prop);
|
||||
ic.getComponentStack().push(status);
|
||||
|
||||
String body = ",";
|
||||
|
||||
// when
|
||||
assertTrue(ic.start(out));
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
status.start(out);
|
||||
status.end(out, body);
|
||||
|
||||
prop.start(out);
|
||||
prop.end(out, body);
|
||||
ic.end(out, null);
|
||||
}
|
||||
|
||||
// then
|
||||
assertEquals("1,1,2,2,3,3,", out.getBuffer().toString());
|
||||
}
|
||||
|
||||
public void testListOfBeansIterator() {
|
||||
// given
|
||||
TestAction action = new TestAction();
|
||||
action.setList2(new ArrayList<User>() {{
|
||||
add(new User("Anton"));
|
||||
add(new User("Tym"));
|
||||
add(new User("Luk"));
|
||||
}});
|
||||
stack.push(action);
|
||||
|
||||
StringWriter out = new StringWriter();
|
||||
|
||||
ic.setValue("list2");
|
||||
ic.setStatus("status");
|
||||
|
||||
Property prop = new Property(stack);
|
||||
prop.setValue("name");
|
||||
Property status = new Property(stack);
|
||||
status.setValue("#status.indexStr");
|
||||
|
||||
ic.getComponentStack().push(status);
|
||||
ic.getComponentStack().push(prop);
|
||||
ic.getComponentStack().push(status);
|
||||
ic.getComponentStack().push(prop);
|
||||
ic.getComponentStack().push(status);
|
||||
ic.getComponentStack().push(prop);
|
||||
|
||||
String body = ",";
|
||||
|
||||
// when
|
||||
assertTrue(ic.start(out));
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
status.start(out);
|
||||
status.end(out, body);
|
||||
|
||||
prop.start(out);
|
||||
prop.end(out, body);
|
||||
|
||||
ic.end(out, null);
|
||||
}
|
||||
|
||||
// then
|
||||
assertEquals("0,Anton,1,Tym,2,Luk,", out.getBuffer().toString());
|
||||
}
|
||||
|
||||
public void testArrayOfBeansIterator() {
|
||||
// given
|
||||
TestAction action = new TestAction();
|
||||
action.setObjectArray(new ArrayList<User>() {{
|
||||
add(new User("Anton"));
|
||||
add(new User("Tym"));
|
||||
add(new User("Luk"));
|
||||
}}.toArray());
|
||||
stack.push(action);
|
||||
|
||||
StringWriter out = new StringWriter();
|
||||
|
||||
ic.setValue("objectArray");
|
||||
ic.setStatus("status");
|
||||
|
||||
Property prop = new Property(stack);
|
||||
prop.setValue("name");
|
||||
Property status = new Property(stack);
|
||||
status.setValue("#status.countStr");
|
||||
|
||||
ic.getComponentStack().push(status);
|
||||
ic.getComponentStack().push(prop);
|
||||
ic.getComponentStack().push(status);
|
||||
ic.getComponentStack().push(prop);
|
||||
ic.getComponentStack().push(status);
|
||||
ic.getComponentStack().push(prop);
|
||||
|
||||
String body = " ";
|
||||
|
||||
// when
|
||||
assertTrue(ic.start(out));
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
status.start(out);
|
||||
status.end(out, body);
|
||||
|
||||
prop.start(out);
|
||||
prop.end(out, body);
|
||||
|
||||
ic.end(out, null);
|
||||
}
|
||||
|
||||
// then
|
||||
assertEquals("1 Anton 2 Tym 3 Luk ", out.getBuffer().toString());
|
||||
}
|
||||
|
||||
static class FooAction {
|
||||
|
||||
private List items;
|
||||
private final List<String> items;
|
||||
|
||||
public FooAction() {
|
||||
items = Arrays.asList("item1", "item2", "item3", "item4");
|
||||
}
|
||||
|
||||
public List getItems() {
|
||||
public List<String> getItems() {
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.mock.MockActionInvocation;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
import org.apache.struts2.TestAction;
|
||||
import org.apache.struts2.action.CspSettingsAware;
|
||||
import org.apache.struts2.dispatcher.SessionMap;
|
||||
import org.apache.struts2.interceptor.csp.CspInterceptor;
|
||||
@@ -45,7 +46,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
|
||||
public void test_whenRequestReceived_thenNonceIsSetInSession_andCspHeaderContainsIt() throws Exception {
|
||||
String reportUri = "/barfoo";
|
||||
String reporting = "false";
|
||||
boolean reporting = false;
|
||||
interceptor.setReportUri(reportUri);
|
||||
interceptor.setEnforcingMode(reporting);
|
||||
|
||||
@@ -58,7 +59,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
|
||||
public void test_whenNonceAlreadySetInSession_andRequestReceived_thenNewNonceIsSet() throws Exception {
|
||||
String reportUri = "https://www.google.com/";
|
||||
String enforcingMode = "true";
|
||||
boolean enforcingMode = true;
|
||||
interceptor.setReportUri(reportUri);
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
session.setAttribute("nonce", "foo");
|
||||
@@ -73,7 +74,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
|
||||
public void testEnforcingCspHeadersSet() throws Exception {
|
||||
String reportUri = "/csp-reports";
|
||||
String enforcingMode = "true";
|
||||
boolean enforcingMode = true;
|
||||
interceptor.setReportUri(reportUri);
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
session.setAttribute("nonce", "foo");
|
||||
@@ -88,7 +89,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
|
||||
public void testReportingCspHeadersSet() throws Exception {
|
||||
String reportUri = "/csp-reports";
|
||||
String enforcingMode = "false";
|
||||
boolean enforcingMode = false;
|
||||
interceptor.setReportUri(reportUri);
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
session.setAttribute("nonce", "foo");
|
||||
@@ -101,7 +102,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
public void test_uriSetOnlyWhenSetIsCalled() throws Exception {
|
||||
String enforcingMode = "false";
|
||||
boolean enforcingMode = false;
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
|
||||
interceptor.intercept(mai);
|
||||
@@ -115,7 +116,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
public void testCannotParseUri() {
|
||||
String enforcingMode = "false";
|
||||
boolean enforcingMode = false;
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
|
||||
try {
|
||||
@@ -127,7 +128,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
public void testCannotParseRelativeUri() {
|
||||
String enforcingMode = "false";
|
||||
boolean enforcingMode = false;
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
|
||||
try {
|
||||
@@ -139,13 +140,41 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
public void testCustomPreResultListener() throws Exception {
|
||||
boolean enforcingMode = false;
|
||||
mai.setAction(new CustomerCspAction("/report-uri"));
|
||||
interceptor.setEnforcingMode("false");
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
interceptor.intercept(mai);
|
||||
checkHeader("/report-uri", "false");
|
||||
checkHeader("/report-uri", enforcingMode);
|
||||
}
|
||||
|
||||
public void checkHeader(String reportUri, String enforcingMode) {
|
||||
public void testPrependContext() throws Exception {
|
||||
boolean enforcingMode = true;
|
||||
mai.setAction(new TestAction());
|
||||
request.setContextPath("/app");
|
||||
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
interceptor.setReportUri("/report-uri");
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
checkHeader("/app/report-uri", enforcingMode);
|
||||
}
|
||||
|
||||
public void testNoPrependContext() throws Exception {
|
||||
boolean enforcingMode = true;
|
||||
mai.setAction(new TestAction());
|
||||
request.setContextPath("/app");
|
||||
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
interceptor.setReportUri("/report-uri");
|
||||
interceptor.setPrependServletContext(false);
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
checkHeader("/report-uri", enforcingMode);
|
||||
}
|
||||
|
||||
public void checkHeader(String reportUri, boolean enforcingMode) {
|
||||
String expectedCspHeader;
|
||||
if (Strings.isEmpty(reportUri)) {
|
||||
expectedCspHeader = String.format("%s '%s'; %s 'nonce-%s' '%s' %s %s; %s '%s'; ",
|
||||
@@ -163,7 +192,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
String header;
|
||||
if (enforcingMode.equals("true")) {
|
||||
if (enforcingMode) {
|
||||
header = response.getHeader(CspSettings.CSP_ENFORCE_HEADER);
|
||||
} else {
|
||||
header = response.getHeader(CspSettings.CSP_REPORT_HEADER);
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ public class StrutsBackgroundProcessTest extends StrutsInternalTestCase {
|
||||
executor.execute(bp);
|
||||
}
|
||||
|
||||
Thread.sleep(500);
|
||||
Thread.sleep(800);
|
||||
|
||||
for (BackgroundProcess bp : bps) {
|
||||
assertTrue("Process is still active: " + bp, bp.isDone());
|
||||
|
||||
+348
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* 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.parameter;
|
||||
|
||||
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.ognl.ThreadAllowlist;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class StrutsParameterAnnotationTest {
|
||||
|
||||
private ParametersInterceptor parametersInterceptor;
|
||||
|
||||
private ThreadAllowlist threadAllowlist;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
parametersInterceptor = new ParametersInterceptor();
|
||||
parametersInterceptor.setRequireAnnotations(Boolean.TRUE.toString());
|
||||
|
||||
threadAllowlist = new ThreadAllowlist();
|
||||
parametersInterceptor.setThreadAllowlist(threadAllowlist);
|
||||
|
||||
NotExcludedAcceptedPatternsChecker checker = mock(NotExcludedAcceptedPatternsChecker.class);
|
||||
when(checker.isAccepted(anyString())).thenReturn(AcceptedPatternsChecker.IsAccepted.yes(""));
|
||||
when(checker.isExcluded(anyString())).thenReturn(NotExcludedAcceptedPatternsChecker.IsExcluded.no(new HashSet<>()));
|
||||
parametersInterceptor.setAcceptedPatterns(checker);
|
||||
parametersInterceptor.setExcludedPatterns(checker);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
threadAllowlist.clearAllowlist();
|
||||
}
|
||||
|
||||
private void testParameter(Object action, String paramName, boolean shouldContain) {
|
||||
Map<String, String[]> requestParamMap = new HashMap<>();
|
||||
requestParamMap.put(paramName, new String[]{"value"});
|
||||
HttpParameters httpParameters = HttpParameters.create(requestParamMap).build();
|
||||
|
||||
Map<String, Parameter> acceptedParameters = parametersInterceptor.toAcceptableParameters(httpParameters, action);
|
||||
|
||||
if (shouldContain) {
|
||||
assertThat(acceptedParameters).containsOnlyKeys(paramName);
|
||||
} else {
|
||||
assertThat(acceptedParameters).isEmpty();
|
||||
assertThat(threadAllowlist.getAllowlist()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private Set<Class<?>> getParentClasses(Class<?> ...clazzes) {
|
||||
Set<Class<?>> set = new HashSet<>();
|
||||
for (Class<?> clazz : clazzes) {
|
||||
set.add(clazz);
|
||||
set.addAll(ClassUtils.getAllSuperclasses(clazz));
|
||||
set.addAll(ClassUtils.getAllInterfaces(clazz));
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void privateStrAnnotated() {
|
||||
testParameter(new FieldAction(), "privateStr", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicStrAnnotated() {
|
||||
testParameter(new FieldAction(), "publicStr", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicStrNotAnnotated() {
|
||||
testParameter(new FieldAction(), "publicStrNotAnnotated", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void privatePojoAnnotated() {
|
||||
testParameter(new FieldAction(), "privatePojo.key", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicPojoDepthZero() {
|
||||
testParameter(new FieldAction(), "publicPojoDepthZero.key", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicPojoDepthOne() {
|
||||
testParameter(new FieldAction(), "publicPojoDepthOne.key", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicPojoDepthOne_sqrBracket() {
|
||||
testParameter(new FieldAction(), "publicPojoDepthOne['key']", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicPojoDepthOne_bracket() {
|
||||
testParameter(new FieldAction(), "publicPojoDepthOne('key')", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicNestedPojoDepthOne() {
|
||||
testParameter(new FieldAction(), "publicPojoDepthOne.key.key", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicPojoDepthTwo() {
|
||||
testParameter(new FieldAction(), "publicPojoDepthTwo.key", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicNestedPojoDepthTwo() {
|
||||
testParameter(new FieldAction(), "publicPojoDepthTwo.key.key", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicNestedPojoDepthTwo_sqrBracket() {
|
||||
testParameter(new FieldAction(), "publicPojoDepthTwo['key']['key']", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicNestedPojoDepthTwo_bracket() {
|
||||
testParameter(new FieldAction(), "publicPojoDepthTwo('key')('key')", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void privateStrAnnotatedMethod() {
|
||||
testParameter(new MethodAction(), "privateStr", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicStrAnnotatedMethod() {
|
||||
testParameter(new MethodAction(), "publicStr", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicStrNotAnnotatedMethod() {
|
||||
testParameter(new MethodAction(), "publicStrNotAnnotated", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void privatePojoAnnotatedMethod() {
|
||||
testParameter(new MethodAction(), "privatePojo.key", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicPojoDepthZeroMethod() {
|
||||
testParameter(new MethodAction(), "publicPojoDepthZero.key", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicPojoDepthOneMethod() {
|
||||
testParameter(new MethodAction(), "publicPojoDepthOne.key", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicNestedPojoDepthOneMethod() {
|
||||
testParameter(new MethodAction(), "publicPojoDepthOne.key.key", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicPojoDepthTwoMethod() {
|
||||
testParameter(new MethodAction(), "publicPojoDepthTwo.key", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicNestedPojoDepthTwoMethod() {
|
||||
testParameter(new MethodAction(), "publicPojoDepthTwo.key.key", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicPojoListDepthOne() {
|
||||
testParameter(new FieldAction(), "publicPojoListDepthOne[0].key", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicPojoListDepthTwo() {
|
||||
testParameter(new FieldAction(), "publicPojoListDepthTwo[0].key", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(List.class, Pojo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicPojoMapDepthTwo() {
|
||||
testParameter(new FieldAction(), "publicPojoMapDepthTwo['a'].key", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Map.class, String.class, Pojo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicPojoListDepthOneMethod() {
|
||||
testParameter(new MethodAction(), "publicPojoListDepthOne[0].key", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicPojoListDepthTwoMethod() {
|
||||
testParameter(new MethodAction(), "publicPojoListDepthTwo[0].key", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(List.class, Pojo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicPojoMapDepthTwoMethod() {
|
||||
testParameter(new MethodAction(), "publicPojoMapDepthTwo['a'].key", true);
|
||||
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Map.class, String.class, Pojo.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicStrNotAnnotated_transitionMode() {
|
||||
parametersInterceptor.setRequireAnnotationsTransitionMode(Boolean.TRUE.toString());
|
||||
testParameter(new FieldAction(), "publicStrNotAnnotated", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicStrNotAnnotatedMethod_transitionMode() {
|
||||
parametersInterceptor.setRequireAnnotationsTransitionMode(Boolean.TRUE.toString());
|
||||
testParameter(new MethodAction(), "publicStrNotAnnotated", true);
|
||||
}
|
||||
|
||||
|
||||
class FieldAction {
|
||||
@StrutsParameter
|
||||
private String privateStr;
|
||||
|
||||
@StrutsParameter
|
||||
public String publicStr;
|
||||
|
||||
public String publicStrNotAnnotated;
|
||||
|
||||
@StrutsParameter(depth = 1)
|
||||
private Pojo privatePojo;
|
||||
|
||||
@StrutsParameter
|
||||
public Pojo publicPojoDepthZero;
|
||||
|
||||
@StrutsParameter(depth = 1)
|
||||
public Pojo publicPojoDepthOne ;
|
||||
|
||||
@StrutsParameter(depth = 2)
|
||||
public Pojo publicPojoDepthTwo;
|
||||
|
||||
@StrutsParameter(depth = 1)
|
||||
public List<Pojo> publicPojoListDepthOne;
|
||||
|
||||
@StrutsParameter(depth = 2)
|
||||
public List<Pojo> publicPojoListDepthTwo;
|
||||
|
||||
@StrutsParameter(depth = 2)
|
||||
public Map<String, Pojo> publicPojoMapDepthTwo;
|
||||
}
|
||||
|
||||
class MethodAction {
|
||||
|
||||
@StrutsParameter
|
||||
private void setPrivateStr(String str) {
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setPublicStr(String str) {
|
||||
}
|
||||
|
||||
public void setPublicStrNotAnnotated(String str) {
|
||||
}
|
||||
|
||||
@StrutsParameter(depth = 1)
|
||||
private Pojo getPrivatePojo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public Pojo getPublicPojoDepthZero() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@StrutsParameter
|
||||
public void setPublicPojoDepthZero() {
|
||||
}
|
||||
|
||||
@StrutsParameter(depth = 1)
|
||||
public Pojo getPublicPojoDepthOne() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@StrutsParameter(depth = 2)
|
||||
public Pojo getPublicPojoDepthTwo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@StrutsParameter(depth = 1)
|
||||
public List<Pojo> getPublicPojoListDepthOne() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@StrutsParameter(depth = 2)
|
||||
public List<Pojo> getPublicPojoListDepthTwo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@StrutsParameter(depth = 2)
|
||||
public Map<String, Pojo> getPublicPojoMapDepthTwo() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class Pojo {
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ package org.apache.struts2.views.jsp;
|
||||
|
||||
import com.mockobjects.servlet.MockBodyContent;
|
||||
import com.mockobjects.servlet.MockJspWriter;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import org.apache.commons.collections.ListUtils;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
@@ -29,20 +30,15 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Test Case for Iterator Tag
|
||||
*
|
||||
*/
|
||||
public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
IteratorTag tag;
|
||||
|
||||
private IteratorTag tag;
|
||||
|
||||
public void testIteratingWithIdSpecified() throws Exception {
|
||||
List list = new ArrayList();
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add("one");
|
||||
list.add("two");
|
||||
list.add("three");
|
||||
@@ -104,12 +100,12 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
IteratorTag freshTag = new IteratorTag();
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal 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));
|
||||
}
|
||||
|
||||
public void testIteratingWithIdSpecified_clearTagStateSet() throws Exception {
|
||||
List list = new ArrayList();
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add("one");
|
||||
list.add("two");
|
||||
list.add("three");
|
||||
@@ -174,12 +170,12 @@ public class IteratorTagTest 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));
|
||||
}
|
||||
|
||||
public void testIteratingWithIdSpecifiedAndNullElementOnCollection() throws Exception {
|
||||
List list = new ArrayList();
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add("one");
|
||||
list.add(null);
|
||||
list.add("three");
|
||||
@@ -224,12 +220,12 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
IteratorTag freshTag = new IteratorTag();
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal 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));
|
||||
}
|
||||
|
||||
public void testIteratingWithIdSpecifiedAndNullElementOnCollection_clearTagStateSet() throws Exception {
|
||||
List list = new ArrayList();
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add("one");
|
||||
list.add(null);
|
||||
list.add("three");
|
||||
@@ -277,7 +273,7 @@ public class IteratorTagTest 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));
|
||||
}
|
||||
|
||||
@@ -294,7 +290,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
public void testCollectionIterator() {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add("test1");
|
||||
list.add("test2");
|
||||
list.add("test3");
|
||||
@@ -314,7 +310,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
public void testMapIterator() {
|
||||
Foo foo = new Foo();
|
||||
HashMap map = new HashMap();
|
||||
HashMap<String, String> map = new HashMap<>();
|
||||
map.put("test1", "123");
|
||||
map.put("test2", "456");
|
||||
map.put("test3", "789");
|
||||
@@ -329,8 +325,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doStartTag();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_INCLUDE, result);
|
||||
@@ -340,8 +335,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doAfterBody();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
|
||||
@@ -351,8 +345,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doAfterBody();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
|
||||
@@ -362,8 +355,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doAfterBody();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.SKIP_BODY, result);
|
||||
@@ -372,8 +364,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doEndTag();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_PAGE, result);
|
||||
@@ -382,13 +373,13 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
IteratorTag freshTag = new IteratorTag();
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal 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));
|
||||
}
|
||||
|
||||
public void testMapIterator_clearTagStateSet() {
|
||||
Foo foo = new Foo();
|
||||
HashMap map = new HashMap();
|
||||
HashMap<String, String> map = new HashMap<>();
|
||||
map.put("test1", "123");
|
||||
map.put("test2", "456");
|
||||
map.put("test3", "789");
|
||||
@@ -405,8 +396,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
result = tag.doStartTag();
|
||||
setComponentTagClearTagState(tag, true); // Ensure component tag state clearing is set true (to match tag).
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_INCLUDE, result);
|
||||
@@ -416,8 +406,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doAfterBody();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
|
||||
@@ -427,8 +416,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doAfterBody();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
|
||||
@@ -438,8 +426,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doAfterBody();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.SKIP_BODY, result);
|
||||
@@ -448,8 +435,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doEndTag();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_PAGE, result);
|
||||
@@ -459,7 +445,7 @@ public class IteratorTagTest 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));
|
||||
}
|
||||
|
||||
@@ -477,8 +463,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doStartTag();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_INCLUDE, result);
|
||||
@@ -490,15 +475,16 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
assertFalse(status.isLast());
|
||||
assertTrue(status.isFirst());
|
||||
assertEquals(0, status.getIndex());
|
||||
assertEquals("0", status.getIndexStr());
|
||||
assertEquals(1, status.getCount());
|
||||
assertEquals("1", status.getCountStr());
|
||||
assertTrue(status.isOdd());
|
||||
assertFalse(status.isEven());
|
||||
|
||||
try {
|
||||
result = tag.doAfterBody();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
|
||||
@@ -517,8 +503,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doAfterBody();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
|
||||
@@ -537,8 +522,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doEndTag();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_PAGE, result);
|
||||
@@ -547,7 +531,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
IteratorTag freshTag = new IteratorTag();
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal 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));
|
||||
}
|
||||
|
||||
@@ -567,8 +551,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
result = tag.doStartTag();
|
||||
setComponentTagClearTagState(tag, true); // Ensure component tag state clearing is set true (to match tag).
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_INCLUDE, result);
|
||||
@@ -587,8 +570,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doAfterBody();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
|
||||
@@ -607,8 +589,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doAfterBody();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
|
||||
@@ -627,8 +608,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doEndTag();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_PAGE, result);
|
||||
@@ -638,7 +618,7 @@ public class IteratorTagTest 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));
|
||||
}
|
||||
|
||||
@@ -666,7 +646,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
public void testEmptyCollection() {
|
||||
Foo foo = new Foo();
|
||||
foo.setList(new ArrayList());
|
||||
foo.setList(new ArrayList<>());
|
||||
|
||||
stack.push(foo);
|
||||
|
||||
@@ -692,17 +672,41 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
validateCounter(new Integer[]{0, 1, 2, 3, 4, 5});
|
||||
}
|
||||
|
||||
public void testCounterWithStackValues() throws JspException {
|
||||
public void testCounterWithDifferentLocale() throws JspException {
|
||||
stack.getActionContext().withLocale(new Locale("fa_IR"));
|
||||
tag.setVar("it");
|
||||
tag.setBegin("0");
|
||||
tag.setEnd("5");
|
||||
List<String> expectedValues = Arrays.asList("0", "1", "2", "3", "4", "5");
|
||||
|
||||
ArrayList<String> values = new ArrayList<>();
|
||||
try {
|
||||
int result = tag.doStartTag();
|
||||
assertEquals(TagSupport.EVAL_BODY_INCLUDE, result);
|
||||
values.add((String) stack.findValue("it", String.class));
|
||||
} catch (JspException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
while (tag.doAfterBody() == TagSupport.EVAL_BODY_AGAIN) {
|
||||
values.add((String) stack.findValue("top", String.class));
|
||||
}
|
||||
|
||||
assertEquals(expectedValues.size(), values.size());
|
||||
assertEquals(expectedValues, values);
|
||||
}
|
||||
|
||||
public void testCounterWithStackValues() throws JspException {
|
||||
stack.getContext().put("begin", 0);
|
||||
stack.getContext().put("end", 5);
|
||||
tag.setBegin("%{#begin}");
|
||||
tag.setEnd("%{#end}");
|
||||
tag.setBegin("begin");
|
||||
tag.setEnd("end");
|
||||
validateCounter(new Integer[]{0, 1, 2, 3, 4, 5});
|
||||
}
|
||||
|
||||
public void testCounterWithList() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
@@ -720,7 +724,6 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
public void testCounterWithArray() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
foo.setArray(new String[]{"a", "b", "c", "d"});
|
||||
|
||||
stack.push(foo);
|
||||
@@ -735,7 +738,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
public void testCounterWithListNoEnd() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
@@ -752,7 +755,6 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
public void testCounterWithArrayNoEnd() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
foo.setArray(new String[]{"a", "b", "c", "d"});
|
||||
|
||||
stack.push(foo);
|
||||
@@ -765,7 +767,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
public void testCounterWithList2() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
@@ -783,7 +785,6 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
public void testCounterWithArray2() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
foo.setArray(new String[]{"a", "b", "c", "d"});
|
||||
|
||||
stack.push(foo);
|
||||
@@ -797,7 +798,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
public void testCounterWithListNoEnd2() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
@@ -812,9 +813,8 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
validateCounter(new String[]{"c", "d"});
|
||||
}
|
||||
|
||||
public void testCounterWithArrayNoEnd2() throws JspException {
|
||||
public void testCounterWithArrayNoEnd2() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
foo.setArray(new String[]{"a", "b", "c", "d"});
|
||||
|
||||
stack.push(foo);
|
||||
@@ -838,9 +838,9 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
validateCounter(new Integer[]{0, 2, 4});
|
||||
}
|
||||
|
||||
public void testCounterWithListAndStep() throws JspException {
|
||||
public void testCounterWithListAndStep() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
@@ -858,9 +858,8 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
validateCounter(new String[]{"a", "c"});
|
||||
}
|
||||
|
||||
public void testCounterWithArrayAndStep() throws JspException {
|
||||
public void testCounterWithArrayAndStep() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
foo.setArray(new String[]{"a", "b", "c", "d"});
|
||||
|
||||
stack.push(foo);
|
||||
@@ -876,7 +875,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
public void testCounterWithListAndStepNoEnd() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
@@ -895,7 +894,6 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
public void testCounterWithArrayAndStepNoEnd() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
foo.setArray(new String[]{"a", "b", "c", "d"});
|
||||
|
||||
stack.push(foo);
|
||||
@@ -917,7 +915,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
public void testCounterWithListAndNegativeStep() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
@@ -937,7 +935,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
public void testCounterWithListAndNegativeStepNoEnd() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
@@ -954,9 +952,9 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
validateCounter(new String[]{"d", "c", "b", "a"});
|
||||
}
|
||||
|
||||
public void testCounterWithArrayAndNegativeStep() throws JspException {
|
||||
public void testCounterWithArrayAndNegativeStep() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
@@ -976,7 +974,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
|
||||
public void testCounterWithArrayAndNegativeStepNoEnd() throws JspException {
|
||||
Foo foo = new Foo();
|
||||
ArrayList list = new ArrayList();
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add("a");
|
||||
list.add("b");
|
||||
list.add("c");
|
||||
@@ -994,14 +992,13 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
}
|
||||
|
||||
protected void validateCounter(Object[] expectedValues) throws JspException {
|
||||
List values = new ArrayList();
|
||||
ArrayList<Object> values = new ArrayList<>();
|
||||
try {
|
||||
int result = tag.doStartTag();
|
||||
assertEquals(TagSupport.EVAL_BODY_INCLUDE, result);
|
||||
values.add(stack.getRoot().peek());
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
while (tag.doAfterBody() == TagSupport.EVAL_BODY_AGAIN) {
|
||||
@@ -1009,7 +1006,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
}
|
||||
|
||||
assertEquals(expectedValues.length, values.size());
|
||||
ListUtils.isEqualList(Arrays.asList(expectedValues), values);
|
||||
assertTrue(ListUtils.isEqualList(Arrays.asList(expectedValues), values));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1033,8 +1030,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doStartTag();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_INCLUDE, result);
|
||||
@@ -1044,8 +1040,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doAfterBody();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
|
||||
@@ -1055,8 +1050,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doAfterBody();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
|
||||
@@ -1066,8 +1060,7 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doAfterBody();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.SKIP_BODY, result);
|
||||
@@ -1080,16 +1073,14 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
try {
|
||||
result = tag.doStartTag();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.SKIP_BODY, result);
|
||||
try {
|
||||
result = tag.doEndTag();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertEquals(TagSupport.EVAL_PAGE, result);
|
||||
@@ -1098,13 +1089,13 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
IteratorTag freshTag = new IteratorTag();
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal 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));
|
||||
}
|
||||
|
||||
class Foo {
|
||||
private Collection list;
|
||||
private Map map;
|
||||
static class Foo {
|
||||
private Collection<String> list;
|
||||
private Map<String, String> map;
|
||||
private String[] array;
|
||||
|
||||
public void setArray(String[] array) {
|
||||
@@ -1115,24 +1106,24 @@ public class IteratorTagTest extends AbstractUITagTest {
|
||||
return array;
|
||||
}
|
||||
|
||||
public void setList(Collection list) {
|
||||
public void setList(Collection<String> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public Collection getList() {
|
||||
public Collection<String> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
public void setMap(Map map) {
|
||||
public void setMap(Map<String, String> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public Map getMap() {
|
||||
public Map<String, String> getMap() {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
class TestMockBodyContent extends MockBodyContent {
|
||||
static class TestMockBodyContent extends MockBodyContent {
|
||||
public String getString() {
|
||||
return ".-.";
|
||||
}
|
||||
|
||||
@@ -276,6 +276,23 @@ public class AnchorTest extends AbstractUITagTest {
|
||||
verifyResource("href-5.txt");
|
||||
}
|
||||
|
||||
public void testSimpleDisabled() throws Exception {
|
||||
createAction();
|
||||
|
||||
AnchorTag tag = createTag();
|
||||
tag.setHref("a");
|
||||
tag.setDisabled("true");
|
||||
|
||||
StrutsBodyContent body = new StrutsBodyContent(null);
|
||||
body.print("should have disabled attribute");
|
||||
tag.setBodyContent(body);
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
verifyResource("href-6.txt");
|
||||
}
|
||||
|
||||
public void testInjectEscapeHtmlBodyFlag() throws Exception {
|
||||
// given
|
||||
initDispatcherWithConfigs("struts-default.xml, struts-escape-body.xml");
|
||||
|
||||
@@ -64,6 +64,37 @@ public class RadioTest extends AbstractUITagTest {
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapWithBooleanAsKeyWithoutForceValue() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
Map<Boolean, String> map = new LinkedHashMap<>();
|
||||
map.put(Boolean.TRUE, "male");
|
||||
map.put(Boolean.FALSE, "female");
|
||||
testAction.setMap(map);
|
||||
|
||||
testAction.setSomeBool(false);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setLabel("mylabel");
|
||||
tag.setName("myname");
|
||||
tag.setValue("someBool");
|
||||
tag.setList("map");
|
||||
tag.setTheme("simple");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-11.txt"));
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapWithBooleanAsKey_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
@@ -165,12 +196,13 @@ public class RadioTest extends AbstractUITagTest {
|
||||
|
||||
List<SomeEnum> enumList = new ArrayList<>(Arrays.asList(SomeEnum.values()));
|
||||
testAction.setEnumList(enumList);
|
||||
testAction.setStatus(SomeEnum.INIT);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setTheme("simple");
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setName("status");
|
||||
tag.setValue("INIT");
|
||||
tag.setValue("status");
|
||||
tag.setList("enumList");
|
||||
|
||||
tag.doStartTag();
|
||||
@@ -191,13 +223,14 @@ public class RadioTest extends AbstractUITagTest {
|
||||
|
||||
List<SomeEnum> enumList = new ArrayList<>(Arrays.asList(SomeEnum.values()));
|
||||
testAction.setEnumList(enumList);
|
||||
testAction.setStatus(SomeEnum.INIT);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
|
||||
tag.setTheme("simple");
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setName("status");
|
||||
tag.setValue("INIT");
|
||||
tag.setValue("status");
|
||||
tag.setList("enumList");
|
||||
|
||||
tag.doStartTag();
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<input type="radio" name="myname" id="mynametrue" value="true"/>
|
||||
<label for="mynametrue">male</label>
|
||||
<input type="radio" name="myname" id="mynamefalse" checked="checked" value="false"/>
|
||||
<label for="mynamefalse">female</label>
|
||||
@@ -0,0 +1 @@
|
||||
<a id="mylink" href="a" disabled="disabled">should have disabled attribute</a>
|
||||
@@ -19,7 +19,7 @@
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven Start Up Batch script
|
||||
# Apache Maven Wrapper startup batch script, version 3.2.0
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
@@ -27,7 +27,6 @@
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@@ -54,7 +53,7 @@ fi
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
case "$(uname)" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
@@ -62,9 +61,9 @@ case "`uname`" in
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||
JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
|
||||
else
|
||||
export JAVA_HOME="/Library/Java/Home"
|
||||
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
@@ -72,68 +71,38 @@ esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
JAVA_HOME=$(java-config --jre-home)
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
javaExecutable="$(which javac)"
|
||||
if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
readLink=$(which readlink)
|
||||
if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
javaHome="$(dirname "\"$javaExecutable\"")"
|
||||
javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
javaExecutable="$(readlink -f "\"$javaExecutable\"")"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
javaHome="$(dirname "\"$javaExecutable\"")"
|
||||
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
@@ -149,7 +118,7 @@ if [ -z "$JAVACMD" ] ; then
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`\\unset -f command; \\command -v java`"
|
||||
JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -163,12 +132,9 @@ if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
@@ -184,96 +150,99 @@ find_maven_basedir() {
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=`cd "$wdir/.."; pwd`
|
||||
wdir=$(cd "$wdir/.." || exit 1; pwd)
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
echo "${basedir}"
|
||||
printf '%s' "$(cd "$basedir" || exit 1; pwd)"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
# Remove \r in case we run on Windows within Git Bash
|
||||
# and check out the repository with auto CRLF management
|
||||
# enabled. Otherwise, we may read lines that are delimited with
|
||||
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
|
||||
# splitting rules.
|
||||
tr -s '\r\n' ' ' < "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||
log() {
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
printf '%s\n' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
|
||||
log "$MAVEN_PROJECTBASEDIR"
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||
fi
|
||||
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if [ -r "$wrapperJarPath" ]; then
|
||||
log "Found $wrapperJarPath"
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||
fi
|
||||
log "Couldn't find $wrapperJarPath, downloading it ..."
|
||||
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
|
||||
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
else
|
||||
jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
|
||||
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
fi
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||
while IFS="=" read -r key value; do
|
||||
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
|
||||
safeValue=$(echo "$value" | tr -d '\r')
|
||||
case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
|
||||
esac
|
||||
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Downloading from: $jarUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
log "Downloading from: $wrapperUrl"
|
||||
|
||||
if $cygwin; then
|
||||
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
|
||||
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
fi
|
||||
log "Found wget ... using wget"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
else
|
||||
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
fi
|
||||
log "Found curl ... using curl"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl -o "$wrapperJarPath" "$jarUrl" -f
|
||||
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
else
|
||||
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
|
||||
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
log "Falling back to using Java to download"
|
||||
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaClass=`cygpath --path --windows "$javaClass"`
|
||||
javaSource=$(cygpath --path --windows "$javaSource")
|
||||
javaClass=$(cygpath --path --windows "$javaClass")
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
# Compiling the Java class
|
||||
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||
if [ -e "$javaSource" ]; then
|
||||
if [ ! -e "$javaClass" ]; then
|
||||
log " - Compiling MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/javac" "$javaSource")
|
||||
fi
|
||||
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
# Running the downloader
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Running MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||
if [ -e "$javaClass" ]; then
|
||||
log " - Running MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -282,35 +251,58 @@ fi
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo $MAVEN_PROJECTBASEDIR
|
||||
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
|
||||
wrapperSha256Sum=""
|
||||
while IFS="=" read -r key value; do
|
||||
case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
|
||||
esac
|
||||
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ -n "$wrapperSha256Sum" ]; then
|
||||
wrapperSha256Result=false
|
||||
if command -v sha256sum > /dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
|
||||
wrapperSha256Result=true
|
||||
fi
|
||||
elif command -v shasum > /dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
|
||||
wrapperSha256Result=true
|
||||
fi
|
||||
else
|
||||
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
|
||||
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
|
||||
exit 1
|
||||
fi
|
||||
if [ $wrapperSha256Result = false ]; then
|
||||
echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
|
||||
echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
|
||||
echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
# shellcheck disable=SC2086 # safe args
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
$MAVEN_DEBUG_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" \
|
||||
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
||||
|
||||
@@ -18,13 +18,12 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven Start Up Batch script
|
||||
@REM Apache Maven Wrapper startup batch script, version 3.2.0
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@@ -120,10 +119,10 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
|
||||
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
|
||||
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||
IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@@ -134,11 +133,11 @@ if exist %WRAPPER_JAR% (
|
||||
)
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
|
||||
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
echo Downloading from: %WRAPPER_URL%
|
||||
)
|
||||
|
||||
powershell -Command "&{"^
|
||||
@@ -146,7 +145,7 @@ if exist %WRAPPER_JAR% (
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
@@ -154,6 +153,24 @@ if exist %WRAPPER_JAR% (
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
|
||||
SET WRAPPER_SHA_256_SUM=""
|
||||
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
|
||||
)
|
||||
IF NOT %WRAPPER_SHA_256_SUM%=="" (
|
||||
powershell -Command "&{"^
|
||||
"$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
|
||||
"If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
|
||||
" Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
|
||||
" Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
|
||||
" Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
|
||||
" exit 1;"^
|
||||
"}"^
|
||||
"}"
|
||||
if ERRORLEVEL 1 goto error
|
||||
)
|
||||
|
||||
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||
@REM work with both Windows and non-Windows executions.
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-async-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-cdi-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-config-browser-plugin</artifactId>
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ import org.apache.struts2.dispatcher.mapper.ActionMapper;
|
||||
import org.apache.struts2.dispatcher.multipart.MultiPartRequest;
|
||||
import org.apache.struts2.views.freemarker.FreemarkerManager;
|
||||
import org.apache.struts2.views.velocity.VelocityConstants;
|
||||
import org.apache.struts2.views.velocity.VelocityManager;
|
||||
import org.apache.struts2.views.velocity.VelocityManagerInterface;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -56,7 +56,7 @@ public class ShowBeansAction extends ActionNamesAction {
|
||||
bindings.put(ActionMapper.class.getName(), addBindings(container, ActionMapper.class, StrutsConstants.STRUTS_MAPPER_CLASS));
|
||||
bindings.put(MultiPartRequest.class.getName(), addBindings(container, MultiPartRequest.class, StrutsConstants.STRUTS_MULTIPART_PARSER));
|
||||
bindings.put(FreemarkerManager.class.getName(), addBindings(container, FreemarkerManager.class, StrutsConstants.STRUTS_FREEMARKER_MANAGER_CLASSNAME));
|
||||
bindings.put(VelocityManager.class.getName(), addBindings(container, VelocityManager.class, VelocityConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME));
|
||||
bindings.put(VelocityManagerInterface.class.getName(), addBindings(container, VelocityManagerInterface.class, VelocityConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME));
|
||||
bindings.put(UrlRenderer.class.getName(), addBindings(container, UrlRenderer.class, StrutsConstants.STRUTS_URL_RENDERER));
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-convention-plugin</artifactId>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-dwr-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-embeddedjsp-plugin</artifactId>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-gxp-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-jasperreports-plugin</artifactId>
|
||||
@@ -35,7 +35,7 @@
|
||||
<dependency>
|
||||
<groupId>net.sf.jasperreports</groupId>
|
||||
<artifactId>jasperreports</artifactId>
|
||||
<version>6.20.6</version>
|
||||
<version>6.21.0</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<!-- not necessary to compile and it force dependency convergence issues -->
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-javatemplates-plugin</artifactId>
|
||||
|
||||
-1
@@ -33,7 +33,6 @@ public class FileHandler extends AbstractTagHandler implements TagGenerator {
|
||||
a.addDefaultToEmpty("name", params.get("name"))
|
||||
.add("type", "file")
|
||||
.addIfExists("size", params.get("size"))
|
||||
.addIfExists("value", params.get("nameValue"))
|
||||
.addIfTrue("disabled", params.get("disabled"))
|
||||
.addIfExists("accept", params.get("accept"))
|
||||
.addIfExists("tabindex", params.get("tabindex"))
|
||||
|
||||
+1
-2
@@ -28,7 +28,6 @@ public class FileTest extends AbstractCommonAttributesTest {
|
||||
|
||||
public void testRenderTextField() {
|
||||
tag.setName("name");
|
||||
tag.setValue("val1");
|
||||
tag.setSize("10");
|
||||
tag.setDisabled("true");
|
||||
tag.setAccept("accept_");
|
||||
@@ -43,7 +42,7 @@ public class FileTest extends AbstractCommonAttributesTest {
|
||||
map.putAll(tag.getParameters());
|
||||
theme.renderTag(getTagName(), context);
|
||||
String output = writer.getBuffer().toString();
|
||||
String expected = s("<input name='name' type='file' size='10' value='val1' disabled='disabled' accept='accept_' tabindex='1' id='id1' class='class1' style='style1' title='title'></input>");
|
||||
String expected = s("<input name='name' type='file' size='10' disabled='disabled' accept='accept_' tabindex='1' id='id1' class='class1' style='style1' title='title'></input>");
|
||||
assertEquals(expected, output);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-jfreechart-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-json-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-junit-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-plugin</artifactId>
|
||||
|
||||
@@ -24,15 +24,15 @@ import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.PackageProvider;
|
||||
import com.opensymphony.xwork2.config.entities.PackageConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.finder.ClassLoaderInterface;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.osgi.host.OsgiHost;
|
||||
import org.apache.struts2.osgi.loaders.VelocityBundleResourceLoader;
|
||||
import org.apache.struts2.views.velocity.VelocityManager;
|
||||
import org.apache.struts2.views.velocity.VelocityManagerInterface;
|
||||
import org.apache.velocity.app.Velocity;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleContext;
|
||||
@@ -40,7 +40,6 @@ import org.osgi.framework.BundleEvent;
|
||||
import org.osgi.framework.BundleListener;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
@@ -255,9 +254,12 @@ public class OsgiConfigurationProvider implements PackageProvider, BundleListene
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setVelocityManager(VelocityManager vm) {
|
||||
LOG.trace("OSGi ConfigurationProvider - setVelocityManager() called - VelocityManager: [{}]", vm);
|
||||
|
||||
public void setVelocityManager(VelocityManagerInterface vmi) {
|
||||
LOG.trace("OSGi ConfigurationProvider - setVelocityManager() called - VelocityManager: [{}]", vmi);
|
||||
if (!(vmi instanceof VelocityManager)) {
|
||||
return;
|
||||
}
|
||||
VelocityManager vm = (VelocityManager) vmi;
|
||||
Properties props = new Properties();
|
||||
props.setProperty("osgi.resource.loader.description", "OSGI bundle loader");
|
||||
props.setProperty("osgi.resource.loader.class", VelocityBundleResourceLoader.class.getName());
|
||||
@@ -265,6 +267,14 @@ public class OsgiConfigurationProvider implements PackageProvider, BundleListene
|
||||
vm.setVelocityProperties(props);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0
|
||||
*/
|
||||
@Deprecated
|
||||
public void setVelocityManager(VelocityManager mgr) {
|
||||
setVelocityManager((VelocityManagerInterface) mgr);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
LOG.trace("OSGi ConfigurationProvider - setServletContext() called - ServletContext: [{}]", servletContext);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-oval-plugin</artifactId>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user