mirror of
https://github.com/apache/struts.git
synced 2026-08-05 14:47:09 +00:00
fix double evaluations
address known issues reported at https://securitylab.github.com/research/apache-struts-double-evaluation/
This commit is contained in:
+4
@@ -33,6 +33,7 @@ import com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.DefaultExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.DefaultTextProvider;
|
||||
import com.opensymphony.xwork2.DefaultUnknownHandlerManager;
|
||||
import com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.FileManager;
|
||||
import com.opensymphony.xwork2.FileManagerFactory;
|
||||
@@ -88,6 +89,7 @@ import com.opensymphony.xwork2.ognl.accessor.XWorkIteratorPropertyAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor;
|
||||
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.util.StrutsLocalizedTextProvider;
|
||||
@@ -215,6 +217,8 @@ public class XWorkConfigurationProvider implements ConfigurationProvider {
|
||||
|
||||
.factory(ExcludedPatternsChecker.class, DefaultExcludedPatternsChecker.class, Scope.PROTOTYPE)
|
||||
.factory(AcceptedPatternsChecker.class, DefaultAcceptedPatternsChecker.class, Scope.PROTOTYPE)
|
||||
.factory(NotExcludedAcceptedPatternsChecker.class, DefaultNotExcludedAcceptedPatternsChecker.class
|
||||
, Scope.SINGLETON)
|
||||
|
||||
.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON)
|
||||
;
|
||||
|
||||
@@ -23,6 +23,8 @@ import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.XWorkConstants;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.ClearableValueStack;
|
||||
import com.opensymphony.xwork2.util.Evaluated;
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
@@ -100,6 +102,9 @@ public class AliasInterceptor extends AbstractInterceptor {
|
||||
protected LocalizedTextProvider localizedTextProvider;
|
||||
protected boolean devMode = false;
|
||||
|
||||
private ExcludedPatternsChecker excludedPatterns;
|
||||
private AcceptedPatternsChecker acceptedPatterns;
|
||||
|
||||
@Inject(XWorkConstants.DEV_MODE)
|
||||
public void setDevMode(String mode) {
|
||||
this.devMode = Boolean.parseBoolean(mode);
|
||||
@@ -115,6 +120,16 @@ public class AliasInterceptor extends AbstractInterceptor {
|
||||
this.localizedTextProvider = localizedTextProvider;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setExcludedPatterns(ExcludedPatternsChecker excludedPatterns) {
|
||||
this.excludedPatterns = excludedPatterns;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setAcceptedPatterns(AcceptedPatternsChecker acceptedPatterns) {
|
||||
this.acceptedPatterns = acceptedPatterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Sets the name of the action parameter to look for the alias map.
|
||||
@@ -145,7 +160,7 @@ public class AliasInterceptor extends AbstractInterceptor {
|
||||
ValueStack stack = ac.getValueStack();
|
||||
Object obj = stack.findValue(aliasExpression);
|
||||
|
||||
if (obj != null && obj instanceof Map) {
|
||||
if (obj instanceof Map) {
|
||||
//get secure stack
|
||||
ValueStack newStack = valueStackFactory.createValueStack(stack);
|
||||
boolean clearableStack = newStack instanceof ClearableValueStack;
|
||||
@@ -167,7 +182,13 @@ public class AliasInterceptor extends AbstractInterceptor {
|
||||
for (Object o : aliases.entrySet()) {
|
||||
Map.Entry entry = (Map.Entry) o;
|
||||
String name = entry.getKey().toString();
|
||||
if (isNotAcceptableExpression(name)) {
|
||||
continue;
|
||||
}
|
||||
String alias = (String) entry.getValue();
|
||||
if (isNotAcceptableExpression(alias)) {
|
||||
continue;
|
||||
}
|
||||
Evaluated value = new Evaluated(stack.findValue(name));
|
||||
if (!value.isDefined()) {
|
||||
// workaround
|
||||
@@ -206,5 +227,65 @@ public class AliasInterceptor extends AbstractInterceptor {
|
||||
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
|
||||
protected boolean isAccepted(String paramName) {
|
||||
AcceptedPatternsChecker.IsAccepted result = acceptedPatterns.isAccepted(paramName);
|
||||
if (result.isAccepted()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG.warn("Parameter [{}] didn't match accepted pattern [{}]! See Accepted / Excluded patterns at\n" +
|
||||
"https://struts.apache.org/security/#accepted--excluded-patterns",
|
||||
paramName, result.getAcceptedPattern());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isExcluded(String paramName) {
|
||||
ExcludedPatternsChecker.IsExcluded result = excludedPatterns.isExcluded(paramName);
|
||||
if (!result.isExcluded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG.warn("Parameter [{}] matches excluded pattern [{}]! See Accepted / Excluded patterns at\n" +
|
||||
"https://struts.apache.org/security/#accepted--excluded-patterns",
|
||||
paramName, result.getExcludedPattern());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if expression contains vulnerable code
|
||||
*
|
||||
* @param expression of interceptor
|
||||
* @return true|false
|
||||
*/
|
||||
protected boolean isNotAcceptableExpression(String expression) {
|
||||
return isExcluded(expression) || !isAccepted(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a comma-delimited list of regular expressions to match
|
||||
* parameters that are allowed in the parameter map (aka whitelist).
|
||||
* <p>
|
||||
* Don't change the default unless you know what you are doing in terms
|
||||
* of security implications.
|
||||
* </p>
|
||||
*
|
||||
* @param commaDelim A comma-delimited list of regular expressions
|
||||
*/
|
||||
public void setAcceptParamNames(String commaDelim) {
|
||||
acceptedPatterns.setAcceptedPatterns(commaDelim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a comma-delimited list of regular expressions to match
|
||||
* parameters that should be removed from the parameter map.
|
||||
*
|
||||
* @param commaDelim A comma-delimited list of regular expressions
|
||||
*/
|
||||
public void setExcludeParams(String commaDelim) {
|
||||
excludedPatterns.setExcludedPatterns(commaDelim);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ public class MockResult implements Result {
|
||||
|
||||
public static final String DEFAULT_PARAM = "foo";
|
||||
|
||||
private ActionInvocation invocation;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
@@ -41,7 +43,7 @@ public class MockResult implements Result {
|
||||
}
|
||||
|
||||
public void execute(ActionInvocation invocation) throws Exception {
|
||||
// no op
|
||||
this.invocation = invocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,4 +55,7 @@ public class MockResult implements Result {
|
||||
// no op
|
||||
}
|
||||
|
||||
public ActionInvocation getInvocation() {
|
||||
return invocation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Used across different interceptors to check if given string matches one of the excluded patterns.
|
||||
* Used across different interceptors to check if given string matches one of the accepted patterns.
|
||||
*/
|
||||
public interface AcceptedPatternsChecker {
|
||||
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package com.opensymphony.xwork2.security;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class DefaultNotExcludedAcceptedPatternsChecker implements NotExcludedAcceptedPatternsChecker {
|
||||
private ExcludedPatternsChecker excludedPatterns;
|
||||
private AcceptedPatternsChecker acceptedPatterns;
|
||||
|
||||
|
||||
@Inject
|
||||
public void setExcludedPatterns(ExcludedPatternsChecker excludedPatterns) {
|
||||
this.excludedPatterns = excludedPatterns;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setAcceptedPatterns(AcceptedPatternsChecker acceptedPatterns) {
|
||||
this.acceptedPatterns = acceptedPatterns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsAllowed isAllowed(String value) {
|
||||
IsExcluded isExcluded = isExcluded(value);
|
||||
if (isExcluded.isExcluded()) {
|
||||
return IsAllowed.no(isExcluded.getExcludedPattern());
|
||||
}
|
||||
|
||||
IsAccepted isAccepted = isAccepted(value);
|
||||
if (!isAccepted.isAccepted()) {
|
||||
return IsAllowed.no(isAccepted.getAcceptedPattern());
|
||||
}
|
||||
|
||||
return IsAllowed.yes(isAccepted.getAcceptedPattern());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsAccepted isAccepted(String value) {
|
||||
return acceptedPatterns.isAccepted(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(String commaDelimitedPatterns) {
|
||||
acceptedPatterns.setAcceptedPatterns(commaDelimitedPatterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(String[] patterns) {
|
||||
acceptedPatterns.setAcceptedPatterns(patterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(Set<String> patterns) {
|
||||
acceptedPatterns.setAcceptedPatterns(patterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Pattern> getAcceptedPatterns() {
|
||||
return acceptedPatterns.getAcceptedPatterns();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsExcluded isExcluded(String value) {
|
||||
return excludedPatterns.isExcluded(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(String commaDelimitedPatterns) {
|
||||
excludedPatterns.setExcludedPatterns(commaDelimitedPatterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(String[] patterns) {
|
||||
excludedPatterns.setExcludedPatterns(patterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(Set<String> patterns) {
|
||||
excludedPatterns.setExcludedPatterns(patterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Pattern> getExcludedPatterns() {
|
||||
return excludedPatterns.getExcludedPatterns();
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package com.opensymphony.xwork2.security;
|
||||
|
||||
/**
|
||||
* Used across different places to check if given string is not excluded and is accepted
|
||||
* @see <a href="https://securitylab.github.com/research/apache-struts-double-evaluation/">here</a>
|
||||
* @since 2.5.27
|
||||
*/
|
||||
public interface NotExcludedAcceptedPatternsChecker extends ExcludedPatternsChecker, AcceptedPatternsChecker {
|
||||
|
||||
/**
|
||||
* Checks if value doesn't match excluded pattern and matches accepted pattern
|
||||
*
|
||||
* @param value to check
|
||||
* @return object containing result of matched pattern and pattern itself
|
||||
*/
|
||||
IsAllowed isAllowed(String value);
|
||||
|
||||
final class IsAllowed {
|
||||
|
||||
private final boolean allowed;
|
||||
private final String allowedPattern;
|
||||
|
||||
public static IsAllowed yes(String allowedPattern) {
|
||||
return new IsAllowed(true, allowedPattern);
|
||||
}
|
||||
|
||||
public static IsAllowed no(String allowedPattern) {
|
||||
return new IsAllowed(false, allowedPattern);
|
||||
}
|
||||
|
||||
private IsAllowed(boolean allowed, String allowedPattern) {
|
||||
this.allowed = allowed;
|
||||
this.allowedPattern = allowedPattern;
|
||||
}
|
||||
|
||||
public boolean isAllowed() {
|
||||
return allowed;
|
||||
}
|
||||
|
||||
public String getAllowedPattern() {
|
||||
return allowedPattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IsAllowed { " +
|
||||
"allowed=" + allowed +
|
||||
", allowedPattern=" + allowedPattern +
|
||||
" }";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,6 +322,7 @@ public final class StrutsConstants {
|
||||
/** Dedicated services to check if passed string is excluded/accepted */
|
||||
public static final String STRUTS_EXCLUDED_PATTERNS_CHECKER = "struts.excludedPatterns.checker";
|
||||
public static final String STRUTS_ACCEPTED_PATTERNS_CHECKER = "struts.acceptedPatterns.checker";
|
||||
public static final String STRUTS_NOT_EXCLUDED_ACCEPTED_PATTERNS_CHECKER = "struts.notExcludedAcceptedPatterns.checker";
|
||||
|
||||
/** Constant is used to override framework's default excluded patterns */
|
||||
public static final String STRUTS_OVERRIDE_EXCLUDED_PATTERNS = "struts.override.excludedPatterns";
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package org.apache.struts2.components;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
@@ -70,6 +71,8 @@ public class Component {
|
||||
protected boolean throwExceptionOnELFailure;
|
||||
private UrlHelper urlHelper;
|
||||
|
||||
private NotExcludedAcceptedPatternsChecker notExcludedAcceptedPatterns;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
@@ -112,6 +115,12 @@ public class Component {
|
||||
public void setUrlHelper(UrlHelper urlHelper) {
|
||||
this.urlHelper = urlHelper;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setNotExcludedAcceptedPatterns(NotExcludedAcceptedPatternsChecker notExcludedAcceptedPatterns) {
|
||||
this.notExcludedAcceptedPatterns = notExcludedAcceptedPatterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OGNL value stack associated with this component.
|
||||
* @return the OGNL value stack associated with this component.
|
||||
@@ -276,7 +285,7 @@ public class Component {
|
||||
}
|
||||
|
||||
/**
|
||||
* If altsyntax (%{...}) is applied, simply strip the "%{" and "}" off.
|
||||
* If altsyntax (%{...}) is applied, simply strip the "%{" and "}" off.
|
||||
* @param expr the expression (must be not null)
|
||||
* @return the stripped expression if altSyntax is enabled. Otherwise
|
||||
* the parameter expression is returned as is.
|
||||
@@ -296,7 +305,7 @@ public class Component {
|
||||
/**
|
||||
* Adds the surrounding %{ } to the expression for proper processing.
|
||||
* @param expr the expression.
|
||||
* @return the modified expression if altSyntax is enabled, or the parameter
|
||||
* @return the modified expression if altSyntax is enabled, or the parameter
|
||||
* expression otherwise.
|
||||
*/
|
||||
protected String completeExpressionIfAltSyntax(String expr) {
|
||||
@@ -382,15 +391,6 @@ public class Component {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects if altSyntax is enabled and then checks if expression contains %{...}
|
||||
* @param expr a string to examined
|
||||
* @return true if altSyntax is enabled and expr contains %{...}
|
||||
*/
|
||||
protected boolean recursion(String expr) {
|
||||
return ComponentUtils.altSyntax(stack) && ComponentUtils.containsExpression(expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an action URL by consulting the {@link org.apache.struts2.dispatcher.mapper.ActionMapper}.
|
||||
* @param action the action
|
||||
@@ -407,7 +407,7 @@ public class Component {
|
||||
* @return the action url.
|
||||
*/
|
||||
protected String determineActionURL(String action, String namespace, String method,
|
||||
HttpServletRequest req, HttpServletResponse res, Map parameters, String scheme,
|
||||
HttpServletRequest req, HttpServletResponse res, Map<String, Object> parameters, String scheme,
|
||||
boolean includeContext, boolean encodeResult, boolean forceAddSchemeHostAndPort,
|
||||
boolean escapeAmp) {
|
||||
String finalAction = findString(action);
|
||||
@@ -560,4 +560,22 @@ public class Component {
|
||||
return standardAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if expression doesn't contain vulnerable code
|
||||
*
|
||||
* @param expression of the component
|
||||
* @return true|false
|
||||
* @since 2.5.27
|
||||
*/
|
||||
protected boolean isAcceptableExpression(String expression) {
|
||||
NotExcludedAcceptedPatternsChecker.IsAllowed isAllowed = notExcludedAcceptedPatterns.isAllowed(expression);
|
||||
if (isAllowed.isAllowed()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG.warn("Expression [{}] isn't allowed by pattern [{}]! See Accepted / Excluded patterns at\n" +
|
||||
"https://struts.apache.org/security/", expression, isAllowed.getAllowedPattern());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,7 @@ public abstract class FormButton extends ClosingUIBean {
|
||||
}
|
||||
}
|
||||
addParameter("id", _tmp_id);
|
||||
addParameter("escapedId", escape(_tmp_id));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -125,23 +125,29 @@ public class Param extends Component {
|
||||
if (component instanceof UnnamedParametric) {
|
||||
((UnnamedParametric) component).addParameter(findValue(value));
|
||||
} else {
|
||||
String name = findString(this.name);
|
||||
String translatedName = findString(this.name);
|
||||
|
||||
if (name == null) {
|
||||
if (translatedName == null) {
|
||||
throw new StrutsException("No name found for following expression: " + this.name);
|
||||
}
|
||||
|
||||
Object value = findValue(this.value);
|
||||
boolean evaluated = !translatedName.equals(this.name);
|
||||
boolean reevaluate = !evaluated || isAcceptableExpression(translatedName);
|
||||
if (!reevaluate) {
|
||||
throw new StrutsException("Excluded or not accepted name found: " + translatedName);
|
||||
}
|
||||
|
||||
Object foundValue = findValue(this.value);
|
||||
if (suppressEmptyParameters) {
|
||||
if (value != null && StringUtils.isNotBlank(value.toString())) {
|
||||
component.addParameter(name, value);
|
||||
if (foundValue != null && StringUtils.isNotBlank(foundValue.toString())) {
|
||||
component.addParameter(translatedName, foundValue);
|
||||
} else {
|
||||
component.addParameter(name, null);
|
||||
component.addParameter(translatedName, null);
|
||||
}
|
||||
} else if (value == null || StringUtils.isBlank(value.toString())) {
|
||||
component.addParameter(name, "");
|
||||
} else if (foundValue == null || StringUtils.isBlank(foundValue.toString())) {
|
||||
component.addParameter(translatedName, "");
|
||||
} else {
|
||||
component.addParameter(name, value);
|
||||
component.addParameter(translatedName, foundValue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -158,7 +164,8 @@ public class Param extends Component {
|
||||
|
||||
return super.end(writer, "");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean usesBody() {
|
||||
return true;
|
||||
}
|
||||
@@ -193,7 +200,7 @@ public class Param extends Component {
|
||||
* Adds the given value as a parameter to the outer tag.
|
||||
* @param value the value
|
||||
*/
|
||||
public void addParameter(Object value);
|
||||
void addParameter(Object value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -188,7 +188,9 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
|
||||
// if the id isn't specified, use the action name
|
||||
if (formComponent.getId() == null && actionName != null) {
|
||||
formComponent.addParameter("id", formComponent.escape(actionName));
|
||||
String escapedId = formComponent.escape(actionName);
|
||||
formComponent.addParameter("id", escapedId);
|
||||
formComponent.addParameter("escapedId", escapedId);
|
||||
}
|
||||
} else if (action != null) {
|
||||
// Since we can't find an action alias in the configuration, we just
|
||||
@@ -223,7 +225,9 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
} else {
|
||||
id = result.substring(slash + 1);
|
||||
}
|
||||
formComponent.addParameter("id", formComponent.escape(id));
|
||||
String escapedId = formComponent.escape(id);
|
||||
formComponent.addParameter("id", escapedId);
|
||||
formComponent.addParameter("escapedId", escapedId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -555,16 +555,13 @@ public abstract class UIBean extends Component {
|
||||
protected abstract String getDefaultTemplate();
|
||||
|
||||
protected Template buildTemplateName(String myTemplate, String myDefaultTemplate) {
|
||||
String template = myDefaultTemplate;
|
||||
String templateName = myDefaultTemplate;
|
||||
|
||||
if (myTemplate != null) {
|
||||
template = findString(myTemplate);
|
||||
templateName = findString(myTemplate);
|
||||
}
|
||||
|
||||
String templateDir = getTemplateDir();
|
||||
String theme = getTheme();
|
||||
|
||||
return new Template(templateDir, theme, template);
|
||||
return new Template(getTemplateDir(), getTheme(), templateName);
|
||||
|
||||
}
|
||||
|
||||
@@ -581,71 +578,70 @@ public abstract class UIBean extends Component {
|
||||
}
|
||||
|
||||
public String getTemplateDir() {
|
||||
String templateDir = null;
|
||||
String result = null;
|
||||
|
||||
if (this.templateDir != null) {
|
||||
templateDir = findString(this.templateDir);
|
||||
result = findString(this.templateDir);
|
||||
}
|
||||
|
||||
// If templateDir is not explicitly given,
|
||||
// try to find attribute which states the dir set to use
|
||||
if (StringUtils.isBlank(templateDir)) {
|
||||
templateDir = stack.findString("#attr.templateDir");
|
||||
if (StringUtils.isBlank(result)) {
|
||||
result = stack.findString("#attr.templateDir");
|
||||
}
|
||||
|
||||
// Default template set
|
||||
if (StringUtils.isBlank(templateDir)) {
|
||||
templateDir = defaultTemplateDir;
|
||||
if (StringUtils.isBlank(result)) {
|
||||
result = defaultTemplateDir;
|
||||
}
|
||||
|
||||
// Defaults to 'template'
|
||||
if (StringUtils.isBlank(templateDir)) {
|
||||
templateDir = "template";
|
||||
if (StringUtils.isBlank(result)) {
|
||||
result = "template";
|
||||
}
|
||||
|
||||
return templateDir;
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getTheme() {
|
||||
String theme = null;
|
||||
String result = null;
|
||||
|
||||
if (this.theme != null) {
|
||||
theme = findString(this.theme);
|
||||
result = findString(this.theme);
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(theme)) {
|
||||
if (StringUtils.isBlank(result)) {
|
||||
Form form = (Form) findAncestor(Form.class);
|
||||
if (form != null) {
|
||||
theme = form.getTheme();
|
||||
result = form.getTheme();
|
||||
}
|
||||
}
|
||||
|
||||
// If theme set is not explicitly given,
|
||||
// try to find attribute which states the theme set to use
|
||||
if (StringUtils.isBlank(theme)) {
|
||||
theme = stack.findString("#attr.theme");
|
||||
if (StringUtils.isBlank(result)) {
|
||||
result = stack.findString("#attr.theme");
|
||||
}
|
||||
|
||||
// Default theme set
|
||||
if (StringUtils.isBlank(theme)) {
|
||||
theme = defaultUITheme;
|
||||
if (StringUtils.isBlank(result)) {
|
||||
result = defaultUITheme;
|
||||
}
|
||||
|
||||
return theme;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void evaluateParams() {
|
||||
String templateDir = getTemplateDir();
|
||||
String theme = getTheme();
|
||||
String gotTheme = getTheme();
|
||||
|
||||
addParameter("templateDir", templateDir);
|
||||
addParameter("theme", theme);
|
||||
addParameter("templateDir", getTemplateDir());
|
||||
addParameter("theme", gotTheme);
|
||||
addParameter("template", template != null ? findString(template) : getDefaultTemplate());
|
||||
addParameter("dynamicAttributes", dynamicAttributes);
|
||||
addParameter("themeExpansionToken", uiThemeExpansionToken);
|
||||
addParameter("expandTheme", uiThemeExpansionToken + theme);
|
||||
addParameter("expandTheme", uiThemeExpansionToken + gotTheme);
|
||||
|
||||
String name = null;
|
||||
String translatedName = null;
|
||||
String providedLabel = null;
|
||||
|
||||
if (this.key != null) {
|
||||
@@ -661,8 +657,8 @@ public abstract class UIBean extends Component {
|
||||
}
|
||||
|
||||
if (this.name != null) {
|
||||
name = findString(this.name);
|
||||
addParameter("name", name);
|
||||
translatedName = findString(this.name);
|
||||
addParameter("name", translatedName);
|
||||
}
|
||||
|
||||
if (label != null) {
|
||||
@@ -786,28 +782,31 @@ public abstract class UIBean extends Component {
|
||||
|
||||
|
||||
// see if the value was specified as a parameter already
|
||||
final String NAME_VALUE = "nameValue";
|
||||
if (parameters.containsKey("value")) {
|
||||
parameters.put("nameValue", parameters.get("value"));
|
||||
parameters.put(NAME_VALUE, parameters.get("value"));
|
||||
} else {
|
||||
if (evaluateNameValue()) {
|
||||
final Class valueClazz = getValueClassType();
|
||||
|
||||
if (valueClazz != null) {
|
||||
if (value != null) {
|
||||
addParameter("nameValue", findValue(value, valueClazz));
|
||||
} else if (name != null) {
|
||||
String expr = completeExpressionIfAltSyntax(name);
|
||||
if (recursion(name)) {
|
||||
addParameter("nameValue", expr);
|
||||
addParameter(NAME_VALUE, findValue(value, valueClazz));
|
||||
} else if (translatedName != null) {
|
||||
boolean evaluated = !translatedName.equals(this.name);
|
||||
boolean reevaluate = !evaluated || isAcceptableExpression(translatedName);
|
||||
if (!reevaluate) {
|
||||
addParameter(NAME_VALUE, translatedName);
|
||||
} else {
|
||||
addParameter("nameValue", findValue(expr, valueClazz));
|
||||
String expr = completeExpressionIfAltSyntax(translatedName);
|
||||
addParameter(NAME_VALUE, findValue(expr, valueClazz));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (value != null) {
|
||||
addParameter("nameValue", findValue(value));
|
||||
} else if (name != null) {
|
||||
addParameter("nameValue", findValue(name));
|
||||
addParameter(NAME_VALUE, findValue(value));
|
||||
} else if (translatedName != null) {
|
||||
addParameter(NAME_VALUE, findValue(translatedName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -821,10 +820,10 @@ public abstract class UIBean extends Component {
|
||||
if (form != null ) {
|
||||
addParameter("form", form.getParameters());
|
||||
|
||||
if ( name != null ) {
|
||||
if ( translatedName != null ) {
|
||||
// list should have been created by the form component
|
||||
List<String> tags = (List<String>) form.getParameters().get("tagNames");
|
||||
tags.add(name);
|
||||
tags.add(translatedName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -892,7 +891,7 @@ public abstract class UIBean extends Component {
|
||||
protected String escape(String name) {
|
||||
// escape any possible values that can make the ID painful to work with in JavaScript
|
||||
if (name != null) {
|
||||
return name.replaceAll("[\\/\\.\\[\\]]", "_");
|
||||
return name.replaceAll("[^a-zA-Z0-9_]", "_");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -943,14 +942,14 @@ public abstract class UIBean extends Component {
|
||||
|
||||
protected Map getTooltipConfig(UIBean component) {
|
||||
Object tooltipConfigObj = component.getParameters().get("tooltipConfig");
|
||||
Map<String, String> tooltipConfig = new LinkedHashMap<>();
|
||||
Map<String, String> result = new LinkedHashMap<>();
|
||||
|
||||
if (tooltipConfigObj instanceof Map) {
|
||||
// we get this if its configured using
|
||||
// 1] UI component's tooltipConfig attribute OR
|
||||
// 2] <param name="tooltip" value="" /> param tag value attribute
|
||||
|
||||
tooltipConfig = new LinkedHashMap<>((Map) tooltipConfigObj);
|
||||
result = new LinkedHashMap<>((Map) tooltipConfigObj);
|
||||
} else if (tooltipConfigObj instanceof String) {
|
||||
|
||||
// we get this if its configured using
|
||||
@@ -960,23 +959,23 @@ public abstract class UIBean extends Component {
|
||||
|
||||
for (String aTooltipConfigArray : tooltipConfigArray) {
|
||||
String[] configEntry = aTooltipConfigArray.trim().split("=");
|
||||
String key = configEntry[0].trim();
|
||||
String value;
|
||||
String configKey = configEntry[0].trim();
|
||||
String configValue;
|
||||
if (configEntry.length > 1) {
|
||||
value = configEntry[1].trim();
|
||||
tooltipConfig.put(key, value);
|
||||
configValue = configEntry[1].trim();
|
||||
result.put(configKey, configValue);
|
||||
} else {
|
||||
LOG.warn("component {} tooltip config param {} has no value defined, skipped", component, key);
|
||||
LOG.warn("component {} tooltip config param {} has no value defined, skipped", component, configKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (component.javascriptTooltip != null)
|
||||
tooltipConfig.put("jsTooltipEnabled", component.javascriptTooltip);
|
||||
result.put("jsTooltipEnabled", component.javascriptTooltip);
|
||||
if (component.tooltipIconPath != null)
|
||||
tooltipConfig.put("tooltipIcon", component.tooltipIconPath);
|
||||
result.put("tooltipIcon", component.tooltipIconPath);
|
||||
if (component.tooltipDelay != null)
|
||||
tooltipConfig.put("tooltipDelay", component.tooltipDelay);
|
||||
return tooltipConfig;
|
||||
result.put("tooltipDelay", component.tooltipDelay);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1257,10 +1256,10 @@ public abstract class UIBean extends Component {
|
||||
|
||||
public void setDynamicAttributes(Map<String, String> tagDynamicAttributes) {
|
||||
for (Map.Entry<String, String> entry : tagDynamicAttributes.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String entryKey = entry.getKey();
|
||||
|
||||
if (!isValidTagAttribute(key)) {
|
||||
dynamicAttributes.put(key, entry.getValue());
|
||||
if (!isValidTagAttribute(entryKey)) {
|
||||
dynamicAttributes.put(entryKey, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1275,9 +1274,9 @@ public abstract class UIBean extends Component {
|
||||
super.copyParams(params);
|
||||
for (Object o : params.entrySet()) {
|
||||
Map.Entry entry = (Map.Entry) o;
|
||||
String key = (String) entry.getKey();
|
||||
if (!isValidTagAttribute(key) && !key.equals("dynamicAttributes")) {
|
||||
dynamicAttributes.put(key, entry.getValue());
|
||||
String entryKey = (String) entry.getKey();
|
||||
if (!isValidTagAttribute(entryKey) && !entryKey.equals("dynamicAttributes")) {
|
||||
dynamicAttributes.put(entryKey, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import com.opensymphony.xwork2.factory.ResultFactory;
|
||||
import com.opensymphony.xwork2.factory.ValidatorFactory;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.inject.Scope;
|
||||
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.PatternMatcher;
|
||||
import com.opensymphony.xwork2.util.TextParser;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
@@ -424,6 +425,8 @@ public class DefaultBeanSelectionProvider extends AbstractBeanSelectionProvider
|
||||
/** Checker is used mostly in interceptors, so there be one instance of checker per interceptor with Scope.PROTOTYPE **/
|
||||
alias(ExcludedPatternsChecker.class, StrutsConstants.STRUTS_EXCLUDED_PATTERNS_CHECKER, builder, props, Scope.PROTOTYPE);
|
||||
alias(AcceptedPatternsChecker.class, StrutsConstants.STRUTS_ACCEPTED_PATTERNS_CHECKER, builder, props, Scope.PROTOTYPE);
|
||||
alias(NotExcludedAcceptedPatternsChecker.class, StrutsConstants.STRUTS_NOT_EXCLUDED_ACCEPTED_PATTERNS_CHECKER
|
||||
, builder, props, Scope.SINGLETON);
|
||||
|
||||
switchDevMode(props);
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
package org.apache.struts2.result;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -100,6 +102,8 @@ public class StreamResult extends StrutsResultSupport {
|
||||
protected int bufferSize = 1024;
|
||||
protected boolean allowCaching = true;
|
||||
|
||||
private NotExcludedAcceptedPatternsChecker notExcludedAcceptedPatterns;
|
||||
|
||||
public StreamResult() {
|
||||
super();
|
||||
}
|
||||
@@ -115,6 +119,11 @@ public class StreamResult extends StrutsResultSupport {
|
||||
return allowCaching;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setNotExcludedAcceptedPatterns(NotExcludedAcceptedPatternsChecker notExcludedAcceptedPatterns) {
|
||||
this.notExcludedAcceptedPatterns = notExcludedAcceptedPatterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set allowCaching to <tt>false</tt> to indicate that the client should be requested not to cache the data stream.
|
||||
* This is set to <tt>false</tt> by default
|
||||
@@ -219,14 +228,17 @@ public class StreamResult extends StrutsResultSupport {
|
||||
OutputStream oOutput = null;
|
||||
|
||||
try {
|
||||
if (inputStream == null) {
|
||||
String parsedInputName = conditionalParse(inputName, invocation);
|
||||
boolean evaluated = parsedInputName != null && !parsedInputName.equals(inputName);
|
||||
boolean reevaluate = !evaluated || isAcceptableExpression(parsedInputName);
|
||||
if (inputStream == null && reevaluate) {
|
||||
LOG.debug("Find the inputstream from the invocation variable stack");
|
||||
inputStream = (InputStream) invocation.getStack().findValue(conditionalParse(inputName, invocation));
|
||||
inputStream = (InputStream) invocation.getStack().findValue(parsedInputName);
|
||||
}
|
||||
|
||||
if (inputStream == null) {
|
||||
String msg = ("Can not find a java.io.InputStream with the name [" + inputName + "] in the invocation stack. " +
|
||||
"Check the <param name=\"inputName\"> tag specified for this action.");
|
||||
String msg = ("Can not find a java.io.InputStream with the name [" + parsedInputName + "] in the invocation stack. " +
|
||||
"Check the <param name=\"inputName\"> tag specified for this action is correct, not excluded and accepted.");
|
||||
LOG.error(msg);
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
@@ -243,15 +255,16 @@ public class StreamResult extends StrutsResultSupport {
|
||||
|
||||
LOG.debug("Set the content length: {}", contentLength);
|
||||
if (contentLength != null) {
|
||||
String _contentLength = conditionalParse(contentLength, invocation);
|
||||
int _contentLengthAsInt;
|
||||
String translatedContentLength = conditionalParse(contentLength, invocation);
|
||||
int contentLengthAsInt;
|
||||
try {
|
||||
_contentLengthAsInt = Integer.parseInt(_contentLength);
|
||||
if (_contentLengthAsInt >= 0) {
|
||||
oResponse.setContentLength(_contentLengthAsInt);
|
||||
contentLengthAsInt = Integer.parseInt(translatedContentLength);
|
||||
if (contentLengthAsInt >= 0) {
|
||||
oResponse.setContentLength(contentLengthAsInt);
|
||||
}
|
||||
} catch(NumberFormatException e) {
|
||||
LOG.warn("failed to recognize {} as a number, contentLength header will not be set", _contentLength, e);
|
||||
LOG.warn("failed to recognize {} as a number, contentLength header will not be set",
|
||||
translatedContentLength, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,4 +305,22 @@ public class StreamResult extends StrutsResultSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if expression doesn't contain vulnerable code
|
||||
*
|
||||
* @param expression of result
|
||||
* @return true|false
|
||||
* @since 2.5.27
|
||||
*/
|
||||
protected boolean isAcceptableExpression(String expression) {
|
||||
NotExcludedAcceptedPatternsChecker.IsAllowed isAllowed = notExcludedAcceptedPatterns.isAllowed(expression);
|
||||
if (isAllowed.isAllowed()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG.warn("Expression [{}] isn't allowed by pattern [{}]! See Accepted / Excluded patterns at\n" +
|
||||
"https://struts.apache.org/security/", expression, isAllowed.getAllowedPattern());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ public class StrutsUtil {
|
||||
return responseWrapper.getData();
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.debug("Cannot include {}", aName.toString(), e);
|
||||
LOG.debug("Cannot include {}", aName, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -125,7 +125,7 @@ public class StrutsUtil {
|
||||
}
|
||||
|
||||
public String getText(String text) {
|
||||
return (String) stack.findValue("getText('" + text + "')");
|
||||
return (String) stack.findValue("getText('" + text.replace('\'', '"') + "')");
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -202,6 +202,7 @@
|
||||
|
||||
<bean type="com.opensymphony.xwork2.security.ExcludedPatternsChecker" name="struts" class="com.opensymphony.xwork2.security.DefaultExcludedPatternsChecker" scope="prototype" />
|
||||
<bean type="com.opensymphony.xwork2.security.AcceptedPatternsChecker" name="struts" class="com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker" scope="prototype" />
|
||||
<bean type="com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker" name="struts" class="com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsChecker" scope="singleton" />
|
||||
|
||||
<bean type="com.opensymphony.xwork2.config.providers.ValueSubstitutor" class="com.opensymphony.xwork2.config.providers.EnvsValueSubstitutor" scope="singleton"/>
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
<#if parameters.validate!false == true>
|
||||
<script type="text/javascript" src="${base}/struts/css_xhtml/validation.js"></script>
|
||||
<#if parameters.onsubmit??>
|
||||
${tag.addParameter('onsubmit', "${parameters.onsubmit}; return validateForm_${parameters.id}();")}
|
||||
${tag.addParameter('onsubmit', "${parameters.onsubmit}; return validateForm_${parameters.escapedId}();")}
|
||||
<#else>
|
||||
${tag.addParameter('onsubmit', "return validateForm_${parameters.id}();")}
|
||||
${tag.addParameter('onsubmit', "return validateForm_${parameters.escapedId}();")}
|
||||
</#if>
|
||||
</#if>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<script type="text/javascript">
|
||||
function autoPopulate_${parameters.escapedId?html}(targetElement) {
|
||||
<#if parameters.headerKey?? && parameters.headerValue??>
|
||||
if (targetElement.options[targetElement.selectedIndex].value == '${parameters.headerKey?html}') {
|
||||
if (targetElement.options[targetElement.selectedIndex].value == '${parameters.headerKey?js_string}') {
|
||||
return;
|
||||
}
|
||||
</#if>
|
||||
@@ -30,7 +30,7 @@
|
||||
return;
|
||||
}
|
||||
</#if>
|
||||
targetElement.form.elements['${parameters.name?html}'].value=targetElement.options[targetElement.selectedIndex].value;
|
||||
targetElement.form.elements['${parameters.name?js_string}'].value=targetElement.options[targetElement.selectedIndex].value;
|
||||
}
|
||||
</script>
|
||||
<#include "/${parameters.templateDir}/simple/text.ftl" />
|
||||
|
||||
@@ -72,9 +72,9 @@
|
||||
</#if>
|
||||
<script type="text/javascript">
|
||||
<#assign itemCount = startCount/>
|
||||
var ${parameters.id}Group = new Array(${parameters.listSize} + ${startCount});
|
||||
for (var i = 0; i < (${parameters.listSize} + ${startCount}); i++) {
|
||||
${parameters.id}Group[i] = [];
|
||||
var ${parameters.escapedId}Group = new Array(${parameters.listSize?number?c} + ${startCount});
|
||||
for (var i = 0; i < (${parameters.listSize?number?c} + ${startCount}); i++) {
|
||||
${parameters.escapedId}Group[i] = [];
|
||||
}
|
||||
|
||||
<@s.iterator value="parameters.list">
|
||||
@@ -90,11 +90,11 @@
|
||||
</#if>
|
||||
<#assign doubleItemCount = 0/>
|
||||
<#if parameters.doubleHeaderKey?? && parameters.doubleHeaderValue??>
|
||||
${parameters.id}Group[${itemCount}][${doubleItemCount}] = new Option("${parameters.doubleHeaderValue?js_string}", "${parameters.doubleHeaderKey?js_string}");
|
||||
${parameters.escapedId}Group[${itemCount}][${doubleItemCount}] = new Option("${parameters.doubleHeaderValue?js_string}", "${parameters.doubleHeaderKey?js_string}");
|
||||
<#assign doubleItemCount = doubleItemCount + 1/>
|
||||
</#if>
|
||||
<#if parameters.doubleEmptyOption??>
|
||||
${parameters.id}Group[${itemCount}][${doubleItemCount}] = new Option("", "");
|
||||
${parameters.escapedId}Group[${itemCount}][${doubleItemCount}] = new Option("", "");
|
||||
<#assign doubleItemCount = doubleItemCount + 1/>
|
||||
</#if>
|
||||
<@s.iterator value="${parameters.doubleList}">
|
||||
@@ -130,15 +130,15 @@
|
||||
<#assign itemDoubleTitle = ''/>
|
||||
</#if>
|
||||
</#if>
|
||||
${parameters.id}Group[${itemCount}][${doubleItemCount}] = new Option("${doubleItemValue?js_string}", "${doubleItemKeyStr?js_string}");
|
||||
${parameters.escapedId}Group[${itemCount}][${doubleItemCount}] = new Option("${doubleItemValue?js_string}", "${doubleItemKeyStr?js_string}");
|
||||
<#if itemDoubleCssClass??>
|
||||
${parameters.id}Group[${itemCount}][${doubleItemCount}].setAttribute("class","${itemDoubleCssClass?html}");
|
||||
${parameters.escapedId}Group[${itemCount}][${doubleItemCount}].setAttribute("class","${itemDoubleCssClass}");
|
||||
</#if>
|
||||
<#if itemDoubleCssStyle??>
|
||||
${parameters.id}Group[${itemCount}][${doubleItemCount}].setAttribute("style","${itemDoubleCssStyle?html}");
|
||||
${parameters.escapedId}Group[${itemCount}][${doubleItemCount}].setAttribute("style","${itemDoubleCssStyle}");
|
||||
</#if>
|
||||
<#if itemDoubleTitle??>
|
||||
${parameters.id}Group[${itemCount}][${doubleItemCount}].setAttribute("title","${itemDoubleTitle?html}");
|
||||
${parameters.escapedId}Group[${itemCount}][${doubleItemCount}].setAttribute("title","${itemDoubleTitle}");
|
||||
</#if>
|
||||
|
||||
<#assign doubleItemCount = doubleItemCount + 1/>
|
||||
@@ -146,7 +146,7 @@
|
||||
<#assign itemCount = itemCount + 1/>
|
||||
</@s.iterator>
|
||||
|
||||
var ${parameters.id}Temp = document.${parameters.formName}.${parameters.doubleId};
|
||||
var ${parameters.escapedId}Temp = document.${parameters.formName}.${parameters.doubleId};
|
||||
<#assign itemCount = startCount/>
|
||||
<#assign redirectTo = 0/>
|
||||
<@s.iterator value="parameters.list">
|
||||
@@ -160,34 +160,34 @@
|
||||
</#if>
|
||||
<#assign itemCount = itemCount + 1/>
|
||||
</@s.iterator>
|
||||
${parameters.id}Redirect(${redirectTo});
|
||||
function ${parameters.id}Redirect(x) {
|
||||
${parameters.escapedId}Redirect(${redirectTo});
|
||||
function ${parameters.escapedId}Redirect(x) {
|
||||
var selected = false;
|
||||
for (var m = ${parameters.id}Temp.options.length - 1; m >= 0; m--) {
|
||||
${parameters.id}Temp.remove(m);
|
||||
for (var m = ${parameters.escapedId}Temp.options.length - 1; m >= 0; m--) {
|
||||
${parameters.escapedId}Temp.remove(m);
|
||||
}
|
||||
|
||||
for (var i = 0; i < ${parameters.id}Group[x].length; i++) {
|
||||
${parameters.id}Temp.options[i] = new Option(${parameters.id}Group[x][i].text, ${parameters.id}Group[x][i].value);
|
||||
for (var i = 0; i < ${parameters.escapedId}Group[x].length; i++) {
|
||||
${parameters.escapedId}Temp.options[i] = new Option(${parameters.escapedId}Group[x][i].text, ${parameters.escapedId}Group[x][i].value);
|
||||
<#if parameters.doubleNameValue??>
|
||||
<#if parameters.doubleMultiple??>
|
||||
for (var j = 0; j < ${parameters.doubleNameValue}.length; j++) {
|
||||
if (${parameters.id}Temp.options[i].value == ${parameters.doubleNameValue?js_string}[j]) {
|
||||
${parameters.id}Temp.options[i].selected = true;
|
||||
if (${parameters.escapedId}Temp.options[i].value == ${parameters.doubleNameValue?js_string}[j]) {
|
||||
${parameters.escapedId}Temp.options[i].selected = true;
|
||||
selected = true;
|
||||
}
|
||||
}
|
||||
<#else>
|
||||
if (${parameters.id}Temp.options[i].value == '${parameters.doubleNameValue?js_string}') {
|
||||
${parameters.id}Temp.options[i].selected = true;
|
||||
if (${parameters.escapedId}Temp.options[i].value == '${parameters.doubleNameValue?js_string}') {
|
||||
${parameters.escapedId}Temp.options[i].selected = true;
|
||||
selected = true;
|
||||
}
|
||||
</#if>
|
||||
</#if>
|
||||
}
|
||||
|
||||
if ((${parameters.id}Temp.options.length > 0) && (! selected)) {
|
||||
${parameters.id}Temp.options[0].selected = true;
|
||||
if ((${parameters.escapedId}Temp.options.length > 0) && (! selected)) {
|
||||
${parameters.escapedId}Temp.options[0].selected = true;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -27,15 +27,15 @@
|
||||
submission.
|
||||
-->
|
||||
<#if (parameters.optiontransferselectIds!?size > 0)>
|
||||
var containingForm = document.getElementById("${parameters.id}");
|
||||
var containingForm = document.getElementById("${parameters.id?js_string}");
|
||||
<#assign selectObjIds = parameters.optiontransferselectIds.keySet() />
|
||||
<#list selectObjIds as selectObjectId>
|
||||
StrutsUtils.addEventListener(containingForm, "submit",
|
||||
function(evt) {
|
||||
var selectObj = document.getElementById("${selectObjectId}");
|
||||
var selectObj = document.getElementById("${selectObjectId?js_string}");
|
||||
<#if parameters.optiontransferselectIds.get(selectObjectId)??>
|
||||
<#assign selectTagHeaderKey = parameters.optiontransferselectIds.get(selectObjectId)/>
|
||||
selectAllOptionsExceptSome(selectObj, "key", "${selectTagHeaderKey}");
|
||||
selectAllOptionsExceptSome(selectObj, "key", "${selectTagHeaderKey?js_string}");
|
||||
<#else>
|
||||
selectAllOptionsExceptSome(selectObj, "key", "");
|
||||
</#if>
|
||||
@@ -43,15 +43,15 @@
|
||||
</#list>
|
||||
</#if>
|
||||
<#if (parameters.inputtransferselectIds!?size > 0)>
|
||||
var containingForm = document.getElementById("${parameters.id}");
|
||||
var containingForm = document.getElementById("${parameters.id?js_string}");
|
||||
<#assign selectObjIds = parameters.inputtransferselectIds.keySet() />
|
||||
<#list selectObjIds as selectObjectId>
|
||||
StrutsUtils.addEventListener(containingForm, "submit",
|
||||
function(evt) {
|
||||
var selectObj = document.getElementById("${selectObjectId}");
|
||||
var selectObj = document.getElementById("${selectObjectId?js_string}");
|
||||
<#if parameters.inputtransferselectIds.get(selectObjectId)??>
|
||||
<#assign selectTagHeaderKey = parameters.inputtransferselectIds.get(selectObjectId)/>
|
||||
selectAllOptionsExceptSome(selectObj, "key", "${selectTagHeaderKey}");
|
||||
selectAllOptionsExceptSome(selectObj, "key", "${selectTagHeaderKey?js_string}");
|
||||
<#else>
|
||||
selectAllOptionsExceptSome(selectObj, "key", "");
|
||||
</#if>
|
||||
@@ -59,15 +59,15 @@
|
||||
</#list>
|
||||
</#if>
|
||||
<#if (parameters.optiontransferselectDoubleIds!?size > 0)>
|
||||
var containingForm = document.getElementById("${parameters.id}");
|
||||
var containingForm = document.getElementById("${parameters.id?js_string}");
|
||||
<#assign selectDoubleObjIds = parameters.optiontransferselectDoubleIds.keySet() />
|
||||
<#list selectDoubleObjIds as selectObjId>
|
||||
StrutsUtils.addEventListener(containingForm, "submit",
|
||||
function(evt) {
|
||||
var selectObj = document.getElementById("${selectObjId}");
|
||||
var selectObj = document.getElementById("${selectObjId?js_string}");
|
||||
<#if parameters.optiontransferselectDoubleIds.get(selectObjId)??>
|
||||
<#assign selectTagHeaderKey = parameters.optiontransferselectDoubleIds.get(selectObjId)/>
|
||||
selectAllOptionsExceptSome(selectObj, "key", "${selectTagHeaderKey}");
|
||||
selectAllOptionsExceptSome(selectObj, "key", "${selectTagHeaderKey?js_string}");
|
||||
<#else>
|
||||
selectAllOptionsExceptSome(selectObj, "key", "");
|
||||
</#if>
|
||||
@@ -81,15 +81,15 @@
|
||||
submission
|
||||
-->
|
||||
<#if (parameters.updownselectIds!?size > 0)>
|
||||
var containingForm = document.getElementById("${parameters.id}");
|
||||
var containingForm = document.getElementById("${parameters.id?js_string}");
|
||||
<#assign tmpIds = parameters.updownselectIds.keySet() />
|
||||
<#list tmpIds as tmpId>
|
||||
StrutsUtils.addEventListener(containingForm, "submit",
|
||||
function(evt) {
|
||||
var updownselectObj = document.getElementById("${tmpId}");
|
||||
var updownselectObj = document.getElementById("${tmpId?js_string}");
|
||||
<#if parameters.updownselectIds.get(tmpId)??>
|
||||
<#assign tmpHeaderKey = parameters.updownselectIds.get(tmpId) />
|
||||
selectAllOptionsExceptSome(updownselectObj, "key", "${tmpHeaderKey}");
|
||||
selectAllOptionsExceptSome(updownselectObj, "key", "${tmpHeaderKey?js_string}");
|
||||
<#else>
|
||||
selectAllOptionsExceptSome(updownselectObj, "key", "");
|
||||
</#if>
|
||||
|
||||
@@ -33,7 +33,7 @@ END SNIPPET: supported-validators
|
||||
-->
|
||||
<#if ((parameters.validate!false == true) && (parameters.performValidation!false == true))>
|
||||
<script type="text/javascript">
|
||||
function validateForm_${parameters.id?replace('[^a-zA-Z0-9_]', '_', 'r')}() {
|
||||
function validateForm_${parameters.escapedId}() {
|
||||
<#--
|
||||
In case of multiselect fields return only the first value.
|
||||
-->
|
||||
@@ -54,7 +54,7 @@ END SNIPPET: supported-validators
|
||||
}
|
||||
return field.value;
|
||||
}
|
||||
form = document.getElementById("${parameters.id}");
|
||||
form = document.getElementById("${parameters.id?js_string}");
|
||||
clearErrorMessages(form);
|
||||
clearErrorLabels(form);
|
||||
|
||||
@@ -62,10 +62,10 @@ END SNIPPET: supported-validators
|
||||
var continueValidation = true;
|
||||
<#list parameters.tagNames as tagName>
|
||||
<#list tag.getValidators("${tagName}") as aValidator>
|
||||
// field name: ${aValidator.fieldName}
|
||||
// field name: ${aValidator.fieldName?js_string}
|
||||
// validator name: ${aValidator.validatorType}
|
||||
if (form.elements['${aValidator.fieldName}']) {
|
||||
field = form.elements['${aValidator.fieldName}'];
|
||||
if (form.elements['${aValidator.fieldName?js_string}']) {
|
||||
field = form.elements['${aValidator.fieldName?js_string}'];
|
||||
<#if aValidator.validatorType = "field-visitor">
|
||||
<#assign validator = aValidator.fieldValidator >
|
||||
//visitor validator switched to: ${validator.validatorType}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<#if parameters.focusElement??>
|
||||
<script type="text/javascript">
|
||||
StrutsUtils.addOnLoad(function() {
|
||||
var element = document.getElementById("${parameters.focusElement?html}");
|
||||
var element = document.getElementById("${parameters.focusElement?js_string}");
|
||||
if(element) {
|
||||
element.focus();
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
<script type="text/javascript" src="${base}/struts/xhtml/validation.js"></script>
|
||||
<script type="text/javascript" src="${base}/struts/utils.js"></script>
|
||||
<#if parameters.onsubmit??>
|
||||
${tag.addParameter('onsubmit', "${parameters.onsubmit}; return validateForm_${parameters.id?replace('[^a-zA-Z0-9_]', '_', 'r')}();")}
|
||||
${tag.addParameter('onsubmit', "${parameters.onsubmit}; return validateForm_${parameters.escapedId}();")}
|
||||
<#else>
|
||||
${tag.addParameter('onsubmit', "return validateForm_${parameters.id?replace('[^a-zA-Z0-9_]', '_', 'r')}();")}
|
||||
${tag.addParameter('onsubmit', "return validateForm_${parameters.escapedId}();")}
|
||||
</#if>
|
||||
</#if>
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.opensymphony.xwork2;
|
||||
|
||||
import com.mockobjects.dynamic.Mock;
|
||||
import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
|
||||
import com.opensymphony.xwork2.mock.MockResult;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
@@ -83,7 +84,18 @@ public class ChainResultTest extends XWorkTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
private class NamespaceActionNameTestActionProxyFactory implements ActionProxyFactory {
|
||||
public void testNamespaceChain() throws Exception {
|
||||
ActionProxy proxy = actionProxyFactory.createActionProxy(null, "chain_with_namespace", null, null);
|
||||
((SimpleAction)proxy.getAction()).setBlah("%{foo}");
|
||||
|
||||
proxy.execute();
|
||||
|
||||
assertTrue(proxy.getInvocation().getResult() instanceof MockResult);
|
||||
MockResult result = (MockResult) proxy.getInvocation().getResult();
|
||||
assertEquals("%{foo}", result.getInvocation().getProxy().getNamespace());
|
||||
}
|
||||
|
||||
private static class NamespaceActionNameTestActionProxyFactory implements ActionProxyFactory {
|
||||
private ActionProxy returnVal;
|
||||
private String expectedActionName;
|
||||
private String expectedNamespace;
|
||||
|
||||
@@ -28,6 +28,10 @@ import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.opensymphony.xwork2.security.DefaultAcceptedPatternsCheckerTest.ACCEPT_ALL_PATTERNS_CHECKER;
|
||||
import static com.opensymphony.xwork2.security.DefaultExcludedPatternsCheckerTest.NO_EXCLUSION_PATTERNS_CHECKER;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
|
||||
/**
|
||||
* AliasInterceptorTest
|
||||
@@ -66,6 +70,92 @@ public class AliasInterceptorTest extends XWorkTestCase {
|
||||
assertNull(actionOne.getBlah()); // WW-5087
|
||||
}
|
||||
|
||||
public void testNameNotAccepted() throws Exception {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("aliasSource", "source here");
|
||||
|
||||
Map<String, String> httpParams = new HashMap<>();
|
||||
httpParams.put("name", "getAliasSource()");
|
||||
httpParams.put("value", "aliasDest");
|
||||
params.put("parameters", HttpParameters.create(httpParams).build());
|
||||
|
||||
|
||||
XmlConfigurationProvider provider = new XmlConfigurationProvider("xwork-sample.xml");
|
||||
container.inject(provider);
|
||||
loadConfigurationProviders(provider);
|
||||
ActionProxy proxy = actionProxyFactory.createActionProxy("", "dynamicAliasTest", null, params);
|
||||
SimpleAction actionOne = (SimpleAction) proxy.getAction();
|
||||
actionOne.setAliasSource("name to be copied");
|
||||
|
||||
// prevent ERROR result
|
||||
actionOne.setFoo(-1);
|
||||
actionOne.setBar(1);
|
||||
|
||||
proxy.execute();
|
||||
assertEquals("name to be copied", actionOne.getAliasSource());
|
||||
assertNotEquals(actionOne.getAliasSource(), actionOne.getAliasDest());
|
||||
|
||||
proxy = actionProxyFactory.createActionProxy("", "dynamicAliasTest", null, params);
|
||||
((AliasInterceptor)proxy.getConfig().getInterceptors().get(1).getInterceptor())
|
||||
.setExcludedPatterns(NO_EXCLUSION_PATTERNS_CHECKER);
|
||||
((AliasInterceptor)proxy.getConfig().getInterceptors().get(1).getInterceptor())
|
||||
.setAcceptedPatterns(ACCEPT_ALL_PATTERNS_CHECKER);
|
||||
|
||||
actionOne = (SimpleAction) proxy.getAction();
|
||||
actionOne.setAliasSource("name to be copied");
|
||||
|
||||
// prevent ERROR result
|
||||
actionOne.setFoo(-1);
|
||||
actionOne.setBar(1);
|
||||
|
||||
proxy.execute();
|
||||
assertEquals("name to be copied", actionOne.getAliasSource());
|
||||
assertEquals(actionOne.getAliasSource(), actionOne.getAliasDest());
|
||||
}
|
||||
|
||||
public void testValueNotAccepted() throws Exception {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("aliasSource", "source here");
|
||||
|
||||
Map<String, String> httpParams = new HashMap<>();
|
||||
httpParams.put("name", "aliasSource");
|
||||
httpParams.put("value", "[0].aliasDest");
|
||||
params.put("parameters", HttpParameters.create(httpParams).build());
|
||||
|
||||
|
||||
XmlConfigurationProvider provider = new XmlConfigurationProvider("xwork-sample.xml");
|
||||
container.inject(provider);
|
||||
loadConfigurationProviders(provider);
|
||||
ActionProxy proxy = actionProxyFactory.createActionProxy("", "dynamicAliasTest", null, params);
|
||||
SimpleAction actionOne = (SimpleAction) proxy.getAction();
|
||||
actionOne.setAliasSource("name to be copied");
|
||||
|
||||
// prevent ERROR result
|
||||
actionOne.setFoo(-1);
|
||||
actionOne.setBar(1);
|
||||
|
||||
proxy.execute();
|
||||
assertEquals("name to be copied", actionOne.getAliasSource());
|
||||
assertNotEquals(actionOne.getAliasSource(), actionOne.getAliasDest());
|
||||
|
||||
proxy = actionProxyFactory.createActionProxy("", "dynamicAliasTest", null, params);
|
||||
((AliasInterceptor) proxy.getConfig().getInterceptors().get(1).getInterceptor())
|
||||
.setExcludedPatterns(NO_EXCLUSION_PATTERNS_CHECKER);
|
||||
((AliasInterceptor) proxy.getConfig().getInterceptors().get(1).getInterceptor())
|
||||
.setAcceptedPatterns(ACCEPT_ALL_PATTERNS_CHECKER);
|
||||
|
||||
actionOne = (SimpleAction) proxy.getAction();
|
||||
actionOne.setAliasSource("name to be copied");
|
||||
|
||||
// prevent ERROR result
|
||||
actionOne.setFoo(-1);
|
||||
actionOne.setBar(1);
|
||||
|
||||
proxy.execute();
|
||||
assertEquals("name to be copied", actionOne.getAliasSource());
|
||||
assertEquals(actionOne.getAliasSource(), actionOne.getAliasDest());
|
||||
}
|
||||
|
||||
public void testNotExisting() throws Exception {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
Map<String, Object> httpParams = new HashMap<>();
|
||||
|
||||
+28
@@ -174,4 +174,32 @@ public class DefaultAcceptedPatternsCheckerTest extends XWorkTestCase {
|
||||
|
||||
assertTrue("dmi isn't accepted", accepted.isAccepted());
|
||||
}
|
||||
|
||||
|
||||
public static final AcceptedPatternsChecker ACCEPT_ALL_PATTERNS_CHECKER = new AcceptedPatternsChecker() {
|
||||
@Override
|
||||
public IsAccepted isAccepted(String value) {
|
||||
return IsAccepted.yes(".*");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(String commaDelimitedPatterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(String[] patterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(Set<String> patterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Pattern> getAcceptedPatterns() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
+29
@@ -22,6 +22,7 @@ import com.opensymphony.xwork2.XWorkTestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -218,4 +219,32 @@ public class DefaultExcludedPatternsCheckerTest extends XWorkTestCase {
|
||||
// Expected result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static final ExcludedPatternsChecker NO_EXCLUSION_PATTERNS_CHECKER = new ExcludedPatternsChecker() {
|
||||
@Override
|
||||
public IsExcluded isExcluded(String value) {
|
||||
return IsExcluded.no(new HashSet<Pattern>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(String commaDelimitedPatterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(String[] patterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(Set<String> patterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Pattern> getExcludedPatterns() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package com.opensymphony.xwork2.security;
|
||||
|
||||
import com.opensymphony.xwork2.XWorkTestCase;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class DefaultNotExcludedAcceptedPatternsCheckerTest extends XWorkTestCase {
|
||||
|
||||
public void testNoExclusionAcceptAllPatternsChecker() {
|
||||
assertTrue(NO_EXCLUSION_ACCEPT_ALL_PATTERNS_CHECKER.isAllowed("%{1+1}").isAllowed());
|
||||
}
|
||||
|
||||
public static final NotExcludedAcceptedPatternsChecker NO_EXCLUSION_ACCEPT_ALL_PATTERNS_CHECKER
|
||||
= new NotExcludedAcceptedPatternsChecker() {
|
||||
@Override
|
||||
public IsAllowed isAllowed(String value) {
|
||||
return IsAllowed.yes("*");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsAccepted isAccepted(String value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(String commaDelimitedPatterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(String[] patterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(Set<String> patterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Pattern> getAcceptedPatterns() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsExcluded isExcluded(String value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(String commaDelimitedPatterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(String[] patterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(Set<String> patterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Pattern> getExcludedPatterns() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -33,7 +33,9 @@ import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.interceptor.ParametersInterceptor;
|
||||
import com.opensymphony.xwork2.mock.MockResult;
|
||||
import com.opensymphony.xwork2.security.DefaultExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import com.opensymphony.xwork2.validator.ValidationInterceptor;
|
||||
import org.apache.struts2.result.ServletDispatcherResult;
|
||||
@@ -42,6 +44,7 @@ import org.apache.struts2.interceptor.TokenSessionStoreInterceptor;
|
||||
import org.apache.struts2.views.jsp.ui.DoubleValidationAction;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
@@ -74,7 +77,7 @@ public class TestConfigurationProvider implements ConfigurationProvider {
|
||||
*/
|
||||
public void loadPackages() {
|
||||
|
||||
HashMap successParams = new HashMap();
|
||||
Map<String, String> successParams = new HashMap<>();
|
||||
successParams.put("propertyName", "executionCount");
|
||||
successParams.put("expectedValue", "1");
|
||||
|
||||
@@ -149,9 +152,7 @@ public class TestConfigurationProvider implements ConfigurationProvider {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the ConfigurationProvider should reload its configuration
|
||||
*
|
||||
* @return
|
||||
* @return whether the ConfigurationProvider should reload its configuration
|
||||
*/
|
||||
public boolean needsReload() {
|
||||
return false;
|
||||
@@ -167,5 +168,8 @@ public class TestConfigurationProvider implements ConfigurationProvider {
|
||||
if (!builder.contains(ExcludedPatternsChecker.class)) {
|
||||
builder.factory(ExcludedPatternsChecker.class, DefaultExcludedPatternsChecker.class);
|
||||
}
|
||||
if (!builder.contains(NotExcludedAcceptedPatternsChecker.class)) {
|
||||
builder.factory(NotExcludedAcceptedPatternsChecker.class, DefaultNotExcludedAcceptedPatternsChecker.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,9 +32,11 @@ import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsCheckerTest.NO_EXCLUSION_ACCEPT_ALL_PATTERNS_CHECKER;
|
||||
|
||||
public class UIBeanTest extends StrutsInternalTestCase {
|
||||
|
||||
public void testPopulateComponentHtmlId1() throws Exception {
|
||||
public void testPopulateComponentHtmlId1() {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
@@ -50,7 +52,7 @@ public class UIBeanTest extends StrutsInternalTestCase {
|
||||
assertEquals("txtFldId", txtFld.getParameters().get("id"));
|
||||
}
|
||||
|
||||
public void testPopulateComponentHtmlIdWithOgnl() throws Exception {
|
||||
public void testPopulateComponentHtmlIdWithOgnl() {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
@@ -66,7 +68,7 @@ public class UIBeanTest extends StrutsInternalTestCase {
|
||||
assertEquals("formId_txtFldName1", txtFld.getParameters().get("id"));
|
||||
}
|
||||
|
||||
public void testPopulateComponentHtmlId2() throws Exception {
|
||||
public void testPopulateComponentHtmlId2() {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
@@ -82,7 +84,7 @@ public class UIBeanTest extends StrutsInternalTestCase {
|
||||
assertEquals("formId_txtFldName", txtFld.getParameters().get("id"));
|
||||
}
|
||||
|
||||
public void testPopulateComponentHtmlWithoutNameAndId() throws Exception {
|
||||
public void testPopulateComponentHtmlWithoutNameAndId() {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
@@ -94,10 +96,10 @@ public class UIBeanTest extends StrutsInternalTestCase {
|
||||
|
||||
txtFld.populateComponentHtmlId(form);
|
||||
|
||||
assertEquals(null, txtFld.getParameters().get("id"));
|
||||
assertNull(txtFld.getParameters().get("id"));
|
||||
}
|
||||
|
||||
public void testEscape() throws Exception {
|
||||
public void testEscape() {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
@@ -110,11 +112,11 @@ public class UIBeanTest extends StrutsInternalTestCase {
|
||||
assertEquals(bean.escape("hello[world"), "hello_world");
|
||||
assertEquals(bean.escape("hello.world"), "hello_world");
|
||||
assertEquals(bean.escape("hello]world"), "hello_world");
|
||||
assertEquals(bean.escape("hello!world"), "hello!world");
|
||||
assertEquals(bean.escape("hello!@#$%^&*()world"), "hello!@#$%^&*()world");
|
||||
assertEquals(bean.escape("hello!world"), "hello_world");
|
||||
assertEquals(bean.escape("hello!@#$%^&*()world"), "hello__________world");
|
||||
}
|
||||
|
||||
public void testEscapeId() throws Exception {
|
||||
public void testEscapeId() {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
@@ -128,7 +130,7 @@ public class UIBeanTest extends StrutsInternalTestCase {
|
||||
assertEquals("formId_foo_bar", txtFld.getParameters().get("id"));
|
||||
}
|
||||
|
||||
public void testGetThemeFromForm() throws Exception {
|
||||
public void testGetThemeFromForm() {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
@@ -140,29 +142,29 @@ public class UIBeanTest extends StrutsInternalTestCase {
|
||||
assertEquals("foo", txtFld.getTheme());
|
||||
}
|
||||
|
||||
public void testGetThemeFromContext() throws Exception {
|
||||
public void testGetThemeFromContext() {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
Map context = Collections.singletonMap("theme", "bar");
|
||||
Map<String, String> context = Collections.singletonMap("theme", "bar");
|
||||
ActionContext.getContext().put("attr", context);
|
||||
|
||||
TextField txtFld = new TextField(stack, req, res);
|
||||
assertEquals("bar", txtFld.getTheme());
|
||||
}
|
||||
|
||||
public void testGetThemeFromContextNonString() throws Exception {
|
||||
public void testGetThemeFromContextNonString() {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
Map context = Collections.singletonMap("theme", 12);
|
||||
Map<String, Integer> context = Collections.singletonMap("theme", 12);
|
||||
ActionContext.getContext().put("attr", context);
|
||||
|
||||
TextField txtFld = new TextField(stack, req, res);
|
||||
assertEquals("12", txtFld.getTheme());
|
||||
}
|
||||
|
||||
public void testMergeTemplateNullEngineException() throws Exception {
|
||||
public void testMergeTemplateNullEngineException() {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
@@ -184,7 +186,7 @@ public class UIBeanTest extends StrutsInternalTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testBuildTemplate() throws Exception {
|
||||
public void testBuildTemplate() {
|
||||
String defaultTemplateName = "default";
|
||||
String customTemplateName = "custom";
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
@@ -200,14 +202,14 @@ public class UIBeanTest extends StrutsInternalTestCase {
|
||||
assertEquals(customTemplateName, customTemplate.getName());
|
||||
}
|
||||
|
||||
public void testGetTemplateDirExplicit() throws Exception {
|
||||
public void testGetTemplateDirExplicit() {
|
||||
String explicitTemplateDir = "explicitTemplateDirectory";
|
||||
String attrTemplateDir = "attrTemplateDirectory";
|
||||
String defaultTemplateDir = "defaultTemplateDirectory";
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
Map context = Collections.singletonMap("templateDir", attrTemplateDir);
|
||||
Map<String, String> context = Collections.singletonMap("templateDir", attrTemplateDir);
|
||||
ActionContext.getContext().put("attr", context);
|
||||
|
||||
TextField txtFld = new TextField(stack, req, res);
|
||||
@@ -217,13 +219,13 @@ public class UIBeanTest extends StrutsInternalTestCase {
|
||||
assertEquals(explicitTemplateDir, txtFld.getTemplateDir());
|
||||
}
|
||||
|
||||
public void testGetTemplateDirAttr() throws Exception {
|
||||
public void testGetTemplateDirAttr() {
|
||||
String attrTemplateDir = "attrTemplateDirectory";
|
||||
String defaultTemplateDir = "defaultTemplateDirectory";
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
Map context = Collections.singletonMap("templateDir", attrTemplateDir);
|
||||
Map<String, String> context = Collections.singletonMap("templateDir", attrTemplateDir);
|
||||
ActionContext.getContext().put("attr", context);
|
||||
|
||||
TextField txtFld = new TextField(stack, req, res);
|
||||
@@ -232,7 +234,7 @@ public class UIBeanTest extends StrutsInternalTestCase {
|
||||
assertEquals(attrTemplateDir, txtFld.getTemplateDir());
|
||||
}
|
||||
|
||||
public void testGetTemplateDirDefault() throws Exception {
|
||||
public void testGetTemplateDirDefault() {
|
||||
String defaultTemplateDir = "defaultTemplateDirectory";
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
@@ -244,7 +246,7 @@ public class UIBeanTest extends StrutsInternalTestCase {
|
||||
assertEquals(defaultTemplateDir, txtFld.getTemplateDir());
|
||||
}
|
||||
|
||||
public void testGetTemplateDirNoneSet() throws Exception {
|
||||
public void testGetTemplateDirNoneSet() {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
@@ -295,10 +297,58 @@ public class UIBeanTest extends StrutsInternalTestCase {
|
||||
});
|
||||
|
||||
TextField txtFld = new TextField(stack, req, res);
|
||||
container.inject(txtFld);
|
||||
txtFld.setName("%{myValue}");
|
||||
txtFld.evaluateParams();
|
||||
|
||||
assertEquals("%{myBad}", txtFld.getParameters().get("nameValue"));
|
||||
assertEquals("%{myBad}", txtFld.getParameters().get("name"));
|
||||
}
|
||||
|
||||
public void testValueNameParameterNotAccepted() {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
|
||||
stack.push(new Object() {
|
||||
public String getMyValueName() {
|
||||
return "getMyValue()";
|
||||
}
|
||||
public String getMyValue() {
|
||||
return "value";
|
||||
}
|
||||
});
|
||||
|
||||
TextField txtFld = new TextField(stack, req, res);
|
||||
container.inject(txtFld);
|
||||
txtFld.setName("%{myValueName}");
|
||||
txtFld.evaluateParams();
|
||||
assertEquals("getMyValue()", txtFld.getParameters().get("name"));
|
||||
assertEquals("getMyValue()", txtFld.getParameters().get("nameValue"));
|
||||
|
||||
txtFld.setNotExcludedAcceptedPatterns(NO_EXCLUSION_ACCEPT_ALL_PATTERNS_CHECKER);
|
||||
txtFld.evaluateParams();
|
||||
assertEquals("getMyValue()", txtFld.getParameters().get("name"));
|
||||
assertEquals("value", txtFld.getParameters().get("nameValue"));
|
||||
}
|
||||
|
||||
public void testValueNameParameterGetterAccepted() {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
|
||||
stack.push(new Object() {
|
||||
public String getMyValue() {
|
||||
return "value";
|
||||
}
|
||||
});
|
||||
|
||||
TextField txtFld = new TextField(stack, req, res);
|
||||
container.inject(txtFld);
|
||||
txtFld.setName("getMyValue()");
|
||||
txtFld.evaluateParams();
|
||||
assertEquals("getMyValue()", txtFld.getParameters().get("name"));
|
||||
assertEquals("value", txtFld.getParameters().get("nameValue"));
|
||||
}
|
||||
|
||||
public void testSetClass() {
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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.result;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ActionProxy;
|
||||
import com.opensymphony.xwork2.Result;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapper;
|
||||
import org.easymock.IMocksControl;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import static org.easymock.EasyMock.createControl;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
|
||||
public class PostbackResultTest extends StrutsInternalTestCase {
|
||||
|
||||
public void testWithNoNamespace() throws Exception {
|
||||
|
||||
ActionContext context = ActionContext.getContext();
|
||||
ValueStack stack = context.getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
context.put(ServletActionContext.HTTP_REQUEST, req);
|
||||
context.put(ServletActionContext.HTTP_RESPONSE, res);
|
||||
|
||||
PostbackResult result = new PostbackResult();
|
||||
result.setActionName("myAction${1-1}");
|
||||
result.setPrependServletContext(false);
|
||||
|
||||
IMocksControl control = createControl();
|
||||
ActionProxy mockActionProxy = control.createMock(ActionProxy.class);
|
||||
ActionInvocation mockInvocation = control.createMock(ActionInvocation.class);
|
||||
expect(mockInvocation.getInvocationContext()).andReturn(context).anyTimes();
|
||||
expect(mockInvocation.getStack()).andReturn(stack).anyTimes();
|
||||
expect(mockInvocation.getProxy()).andReturn(mockActionProxy);
|
||||
expect(mockActionProxy.getNamespace()).andReturn("${1-1}");
|
||||
|
||||
control.replay();
|
||||
result.setActionMapper(container.getInstance(ActionMapper.class));
|
||||
result.execute(mockInvocation);
|
||||
assertEquals("<!DOCTYPE html><html><body><form action=\"${1-1}/myAction0.action\" method=\"POST\">" +
|
||||
"<script>setTimeout(function(){document.forms[0].submit();},0);</script></html>", res.getContentAsString());
|
||||
|
||||
control.verify();
|
||||
}
|
||||
|
||||
public void testWithNamespace() throws Exception {
|
||||
|
||||
ActionContext context = ActionContext.getContext();
|
||||
ValueStack stack = context.getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
context.put(ServletActionContext.HTTP_REQUEST, req);
|
||||
context.put(ServletActionContext.HTTP_RESPONSE, res);
|
||||
|
||||
PostbackResult result = new PostbackResult();
|
||||
result.setActionName("myAction${1-1}");
|
||||
result.setNamespace("myNamespace${1-1}");
|
||||
result.setPrependServletContext(false);
|
||||
|
||||
IMocksControl control = createControl();
|
||||
ActionInvocation mockInvocation = control.createMock(ActionInvocation.class);
|
||||
expect(mockInvocation.getInvocationContext()).andReturn(context).anyTimes();
|
||||
expect(mockInvocation.getStack()).andReturn(stack).anyTimes();
|
||||
|
||||
control.replay();
|
||||
result.setActionMapper(container.getInstance(ActionMapper.class));
|
||||
result.execute(mockInvocation);
|
||||
assertEquals("<!DOCTYPE html><html><body><form action=\"myNamespace0/myAction0.action\" method=\"POST\">" +
|
||||
"<script>setTimeout(function(){document.forms[0].submit();},0);</script></html>", res.getContentAsString());
|
||||
|
||||
control.verify();
|
||||
}
|
||||
|
||||
public void testExpressionNamespace() throws Exception {
|
||||
|
||||
ActionContext context = ActionContext.getContext();
|
||||
context.getContextMap().put("namespaceName", "${1-1}");
|
||||
context.getContextMap().put("actionName", "${1-1}");
|
||||
context.getContextMap().put("methodName", "${1-1}");
|
||||
ValueStack stack = context.getValueStack();
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
context.put(ServletActionContext.HTTP_REQUEST, req);
|
||||
context.put(ServletActionContext.HTTP_RESPONSE, res);
|
||||
|
||||
PostbackResult result = new PostbackResult();
|
||||
result.setNamespace("/myNamespace${#namespaceName}");
|
||||
result.setActionName("myAction${#actionName}");
|
||||
result.setMethod("myMethod${#methodName}");
|
||||
result.setPrependServletContext(false);
|
||||
|
||||
IMocksControl control = createControl();
|
||||
ActionInvocation mockInvocation = control.createMock(ActionInvocation.class);
|
||||
expect(mockInvocation.getInvocationContext()).andReturn(context).anyTimes();
|
||||
expect(mockInvocation.getStack()).andReturn(stack).anyTimes();
|
||||
|
||||
control.replay();
|
||||
result.setActionMapper(container.getInstance(ActionMapper.class));
|
||||
result.execute(mockInvocation);
|
||||
assertEquals("<!DOCTYPE html><html><body><form action=\"/myNamespace${1-1}/myAction${1-1}!myMethod${1-1}.action\" method=\"POST\">" +
|
||||
"<script>setTimeout(function(){document.forms[0].submit();},0);</script></html>", res.getContentAsString());
|
||||
|
||||
req = new MockHttpServletRequest();
|
||||
res = new MockHttpServletResponse();
|
||||
context.put(ServletActionContext.HTTP_REQUEST, req);
|
||||
context.put(ServletActionContext.HTTP_RESPONSE, res);
|
||||
result.execute(mockInvocation);
|
||||
assertEquals("<!DOCTYPE html><html><body><form action=\"/myNamespace0/myAction0!myMethod0.action\" method=\"POST\">" +
|
||||
"<script>setTimeout(function(){document.forms[0].submit();},0);</script></html>", res.getContentAsString());
|
||||
|
||||
control.verify();
|
||||
}
|
||||
}
|
||||
@@ -108,6 +108,141 @@ public class ServletActionRedirectResultTest extends StrutsInternalTestCase {
|
||||
control.verify();
|
||||
}
|
||||
|
||||
public void testExpressionParameterInResultWithConditionParseOn() throws Exception {
|
||||
|
||||
ResultConfig resultConfig = new ResultConfig.Builder("", "")
|
||||
.addParam("actionName", "someActionName")
|
||||
.addParam("namespace", "someNamespace")
|
||||
.addParam("encode", "true")
|
||||
.addParam("parse", "true")
|
||||
.addParam("location", "someLocation")
|
||||
.addParam("prependServletContext", "true")
|
||||
.addParam("method", "someMethod")
|
||||
.addParam("statusCode", "333")
|
||||
.addParam("param1", "${#value1}")
|
||||
.addParam("param2", "${#value2}")
|
||||
.addParam("param3", "${#value3}")
|
||||
.addParam("anchor", "${#fragment}")
|
||||
.build();
|
||||
|
||||
|
||||
|
||||
ActionContext context = ActionContext.getContext();
|
||||
ValueStack stack = context.getValueStack();
|
||||
context.getContextMap().put("value1", "value 1");
|
||||
context.getContextMap().put("value2", "value 2");
|
||||
context.getContextMap().put("value3", "value 3");
|
||||
context.getContextMap().put("namespaceName", "${1-1}");
|
||||
context.getContextMap().put("actionName", "${1-1}");
|
||||
context.getContextMap().put("methodName", "${1-1}");
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
context.put(ServletActionContext.HTTP_REQUEST, req);
|
||||
context.put(ServletActionContext.HTTP_RESPONSE, res);
|
||||
|
||||
|
||||
Map<String, ResultConfig> results= new HashMap<>();
|
||||
results.put("myResult", resultConfig);
|
||||
|
||||
ActionConfig actionConfig = new ActionConfig.Builder("", "", "")
|
||||
.addResultConfigs(results).build();
|
||||
|
||||
ServletActionRedirectResult result = new ServletActionRedirectResult();
|
||||
result.setNamespace("/myNamespace${#namespaceName}");
|
||||
result.setActionName("myAction${#actionName}");
|
||||
result.setMethod("myMethod${#methodName}");
|
||||
result.setParse(true);
|
||||
result.setEncode(false);
|
||||
result.setPrependServletContext(false);
|
||||
result.setAnchor("fragment");
|
||||
result.setUrlHelper(new DefaultUrlHelper());
|
||||
|
||||
IMocksControl control = createControl();
|
||||
ActionProxy mockActionProxy = control.createMock(ActionProxy.class);
|
||||
ActionInvocation mockInvocation = control.createMock(ActionInvocation.class);
|
||||
expect(mockInvocation.getProxy()).andReturn(mockActionProxy).anyTimes();
|
||||
expect(mockInvocation.getResultCode()).andReturn("myResult").anyTimes();
|
||||
expect(mockActionProxy.getConfig()).andReturn(actionConfig).anyTimes();
|
||||
expect(mockInvocation.getInvocationContext()).andReturn(context).anyTimes();
|
||||
expect(mockInvocation.getStack()).andReturn(stack).anyTimes();
|
||||
|
||||
control.replay();
|
||||
result.setActionMapper(container.getInstance(ActionMapper.class));
|
||||
result.execute(mockInvocation);
|
||||
assertEquals("/myNamespace${1-1}/myAction${1-1}!myMethod${1-1}.action?param1=value+1¶m2=value+2¶m3=value+3#fragment", res.getRedirectedUrl());
|
||||
|
||||
req = new MockHttpServletRequest();
|
||||
res = new MockHttpServletResponse();
|
||||
context.put(ServletActionContext.HTTP_REQUEST, req);
|
||||
context.put(ServletActionContext.HTTP_RESPONSE, res);
|
||||
result.execute(mockInvocation);
|
||||
assertEquals("/myNamespace0/myAction0!myMethod0.action?param1=value+1¶m2=value+2¶m3=value+3#fragment", res.getRedirectedUrl());
|
||||
|
||||
control.verify();
|
||||
}
|
||||
|
||||
public void testIncludeParameterInResultWithConditionParseOnWithNoNamespace() throws Exception {
|
||||
|
||||
ResultConfig resultConfig = new ResultConfig.Builder("", "")
|
||||
.addParam("actionName", "someActionName")
|
||||
.addParam("namespace", "someNamespace")
|
||||
.addParam("encode", "true")
|
||||
.addParam("parse", "true")
|
||||
.addParam("location", "someLocation")
|
||||
.addParam("prependServletContext", "true")
|
||||
.addParam("method", "someMethod")
|
||||
.addParam("statusCode", "333")
|
||||
.addParam("param1", "${#value1}")
|
||||
.addParam("param2", "${#value2}")
|
||||
.addParam("param3", "${#value3}")
|
||||
.addParam("anchor", "${#fragment}")
|
||||
.build();
|
||||
|
||||
|
||||
|
||||
ActionContext context = ActionContext.getContext();
|
||||
ValueStack stack = context.getValueStack();
|
||||
context.getContextMap().put("value1", "value 1");
|
||||
context.getContextMap().put("value2", "value 2");
|
||||
context.getContextMap().put("value3", "value 3");
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
context.put(ServletActionContext.HTTP_REQUEST, req);
|
||||
context.put(ServletActionContext.HTTP_RESPONSE, res);
|
||||
|
||||
|
||||
Map<String, ResultConfig> results= new HashMap<>();
|
||||
results.put("myResult", resultConfig);
|
||||
|
||||
ActionConfig actionConfig = new ActionConfig.Builder("", "", "")
|
||||
.addResultConfigs(results).build();
|
||||
|
||||
ServletActionRedirectResult result = new ServletActionRedirectResult();
|
||||
result.setActionName("myAction${1-1}");
|
||||
result.setParse(true);
|
||||
result.setEncode(false);
|
||||
result.setPrependServletContext(false);
|
||||
result.setAnchor("fragment");
|
||||
result.setUrlHelper(new DefaultUrlHelper());
|
||||
|
||||
IMocksControl control = createControl();
|
||||
ActionProxy mockActionProxy = control.createMock(ActionProxy.class);
|
||||
ActionInvocation mockInvocation = control.createMock(ActionInvocation.class);
|
||||
expect(mockInvocation.getProxy()).andReturn(mockActionProxy).times(2);
|
||||
expect(mockInvocation.getResultCode()).andReturn("myResult");
|
||||
expect(mockActionProxy.getConfig()).andReturn(actionConfig);
|
||||
expect(mockActionProxy.getNamespace()).andReturn("${1-1}");
|
||||
expect(mockInvocation.getInvocationContext()).andReturn(context);
|
||||
expect(mockInvocation.getStack()).andReturn(stack).anyTimes();
|
||||
|
||||
control.replay();
|
||||
result.setActionMapper(container.getInstance(ActionMapper.class));
|
||||
result.execute(mockInvocation);
|
||||
assertEquals("/${1-1}/myAction0.action?param1=value+1¶m2=value+2¶m3=value+3#fragment", res.getRedirectedUrl());
|
||||
|
||||
control.verify();
|
||||
}
|
||||
|
||||
public void testIncludeParameterInResult() throws Exception {
|
||||
|
||||
ResultConfig resultConfig = new ResultConfig.Builder("", "")
|
||||
|
||||
@@ -33,6 +33,8 @@ import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
import static com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsCheckerTest.NO_EXCLUSION_ACCEPT_ALL_PATTERNS_CHECKER;
|
||||
|
||||
/**
|
||||
* Unit test for {@link StreamResult}.
|
||||
*
|
||||
@@ -213,11 +215,41 @@ public class StreamResultTest extends StrutsInternalTestCase {
|
||||
assertEquals("filename=\"logo.png\"", response.getHeader("Content-disposition"));
|
||||
}
|
||||
|
||||
public void testStreamResultParseExpression() throws Exception {
|
||||
result.setParse(true);
|
||||
result.setInputName("${streamForImageAsExpression}");
|
||||
|
||||
try {
|
||||
result.doExecute("helloworld", mai);
|
||||
fail("double evaluation?!");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals("Can not find a java.io.InputStream with the name [getStreamForImage()] in the " +
|
||||
"invocation stack. Check the <param name=\"inputName\"> tag specified for this action is correct, " +
|
||||
"not excluded and accepted.", e.getMessage());
|
||||
}
|
||||
|
||||
// verify that above test has really effect
|
||||
result.setNotExcludedAcceptedPatterns(NO_EXCLUSION_ACCEPT_ALL_PATTERNS_CHECKER);
|
||||
assertNull(result.inputStream);
|
||||
result.doExecute("helloworld", mai);
|
||||
assertNotNull(result.inputStream);
|
||||
container.inject(result); // roll back pattern checkers
|
||||
}
|
||||
|
||||
public void testStreamResultParseGetter() throws Exception {
|
||||
result.setParse(true);
|
||||
result.setInputName("getStreamForImage()");
|
||||
assertNull(result.inputStream);
|
||||
result.doExecute("helloworld", mai);
|
||||
assertNotNull(result.inputStream);
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
response = new MockHttpServletResponse();
|
||||
|
||||
result = new StreamResult();
|
||||
container.inject(result);
|
||||
result.setContentLength("${contentLength}");
|
||||
stack = ActionContext.getContext().getValueStack();
|
||||
|
||||
@@ -244,7 +276,7 @@ public class StreamResultTest extends StrutsInternalTestCase {
|
||||
mai = null;
|
||||
}
|
||||
|
||||
public class MyImageAction implements Action {
|
||||
public static class MyImageAction implements Action {
|
||||
|
||||
FileInputStream streamForImage;
|
||||
long contentLength;
|
||||
@@ -257,7 +289,7 @@ public class StreamResultTest extends StrutsInternalTestCase {
|
||||
contentLength = file.length();
|
||||
}
|
||||
|
||||
public InputStream getStreamForImage() throws Exception {
|
||||
public InputStream getStreamForImage() {
|
||||
return streamForImage;
|
||||
}
|
||||
|
||||
@@ -265,7 +297,7 @@ public class StreamResultTest extends StrutsInternalTestCase {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
public long getContentLength() throws Exception {
|
||||
public long getContentLength() {
|
||||
return contentLength;
|
||||
}
|
||||
|
||||
@@ -273,6 +305,10 @@ public class StreamResultTest extends StrutsInternalTestCase {
|
||||
return "streamForImage";
|
||||
}
|
||||
|
||||
public String getStreamForImageAsExpression() {
|
||||
return "getStreamForImage()";
|
||||
}
|
||||
|
||||
public String getContentCharSetMethod() {
|
||||
return "UTF-8";
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class StrutsUtilTest extends StrutsInternalTestCase {
|
||||
assertTrue(o instanceof TestAction);
|
||||
}
|
||||
|
||||
public void testIsTrueMethod() throws Exception {
|
||||
public void testIsTrueMethod() {
|
||||
stack.push(new Object() {
|
||||
public String getMyString() {
|
||||
return "myString";
|
||||
@@ -64,7 +64,7 @@ public class StrutsUtilTest extends StrutsInternalTestCase {
|
||||
assertFalse(strutsUtil.isTrue("getMyBoolean(false)"));
|
||||
}
|
||||
|
||||
public void testFindStringMethod() throws Exception {
|
||||
public void testFindStringMethod() {
|
||||
stack.push(new Object() {
|
||||
public String getMyString() {
|
||||
return "myString";
|
||||
@@ -89,13 +89,13 @@ public class StrutsUtilTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
|
||||
public void testUrlEncodeMethod() throws Exception {
|
||||
public void testUrlEncodeMethod() {
|
||||
assertEquals(
|
||||
strutsUtil.urlEncode("http://www.opensymphony.com/action2/index.jsp?param1=value1"),
|
||||
"http%3A%2F%2Fwww.opensymphony.com%2Faction2%2Findex.jsp%3Fparam1%3Dvalue1");
|
||||
}
|
||||
|
||||
public void testBuildUrlMethod() throws Exception {
|
||||
public void testBuildUrlMethod() {
|
||||
request.setContextPath("/myContextPath");
|
||||
assertEquals(strutsUtil.buildUrl("/someUrl?param1=value1"), "/myContextPath/someUrl?param1=value1");
|
||||
}
|
||||
@@ -123,21 +123,29 @@ public class StrutsUtilTest extends StrutsInternalTestCase {
|
||||
|
||||
|
||||
|
||||
public void testGetTextMethod() throws Exception {
|
||||
public void testGetTextMethod() {
|
||||
// this should be in xwork-messages.properties (included by default
|
||||
// by LocalizedTextUtil
|
||||
assertNotNull(strutsUtil.getText("xwork.error.action.execution"));
|
||||
assertEquals(strutsUtil.getText("xwork.error.action.execution"), "Error during Action invocation");
|
||||
String expression = "xwork.error.action.execution";
|
||||
String text = strutsUtil.getText(expression);
|
||||
assertNotNull(text);
|
||||
assertEquals(text, "Error during Action invocation");
|
||||
}
|
||||
|
||||
public void testGetTextMethodWithSingleQuote() {
|
||||
String expression = "xwork.error.action.execution') + getText('xwork.error.action.execution";
|
||||
String text = strutsUtil.getText(expression);
|
||||
assertNull(text);
|
||||
}
|
||||
|
||||
|
||||
public void testGetContextMethod() throws Exception {
|
||||
public void testGetContextMethod() {
|
||||
request.setContextPath("/myContext");
|
||||
assertEquals(strutsUtil.getContext(), "/myContext");
|
||||
}
|
||||
|
||||
|
||||
public void testMakeSelectListMethod() throws Exception {
|
||||
public void testMakeSelectListMethod() {
|
||||
String[] selectedList = new String[] { "Car", "Airplane", "Bus" };
|
||||
List list = new ArrayList();
|
||||
list.add("Lorry");
|
||||
@@ -152,44 +160,43 @@ public class StrutsUtilTest extends StrutsInternalTestCase {
|
||||
assertEquals(listMade.size(), 3);
|
||||
assertEquals(((ListEntry)listMade.get(0)).getKey(), "Lorry");
|
||||
assertEquals(((ListEntry)listMade.get(0)).getValue(), "Lorry");
|
||||
assertEquals(((ListEntry)listMade.get(0)).getIsSelected(), false);
|
||||
assertFalse(((ListEntry) listMade.get(0)).getIsSelected());
|
||||
assertEquals(((ListEntry)listMade.get(1)).getKey(), "Car");
|
||||
assertEquals(((ListEntry)listMade.get(1)).getValue(), "Car");
|
||||
assertEquals(((ListEntry)listMade.get(1)).getIsSelected(), true);
|
||||
assertTrue(((ListEntry) listMade.get(1)).getIsSelected());
|
||||
assertEquals(((ListEntry)listMade.get(2)).getKey(), "Helicopter");
|
||||
assertEquals(((ListEntry)listMade.get(2)).getValue(), "Helicopter");
|
||||
assertEquals(((ListEntry)listMade.get(2)).getIsSelected(), false);
|
||||
assertFalse(((ListEntry) listMade.get(2)).getIsSelected());
|
||||
}
|
||||
|
||||
public void testToInt() throws Exception {
|
||||
assertEquals(strutsUtil.toInt(11l), 11);
|
||||
public void testToInt() {
|
||||
assertEquals(strutsUtil.toInt(11L), 11);
|
||||
}
|
||||
|
||||
|
||||
public void testToLong() throws Exception {
|
||||
assertEquals(strutsUtil.toLong(11), 11l);
|
||||
public void testToLong() {
|
||||
assertEquals(strutsUtil.toLong(11), 11L);
|
||||
}
|
||||
|
||||
|
||||
public void testToString() throws Exception {
|
||||
public void testToString() {
|
||||
assertEquals(strutsUtil.toString(1), "1");
|
||||
assertEquals(strutsUtil.toString(11l), "11");
|
||||
assertEquals(strutsUtil.toString(11L), "11");
|
||||
}
|
||||
|
||||
public void testTranslateVariables() throws Exception {
|
||||
public void testTranslateVariables() {
|
||||
stack.push(new Object() {
|
||||
public String getFoo() {
|
||||
return "bar";
|
||||
}
|
||||
});
|
||||
Object obj1 = strutsUtil.translateVariables("try: %{foo}");
|
||||
String obj1 = strutsUtil.translateVariables("try: %{foo}");
|
||||
|
||||
assertNotNull(obj1);
|
||||
assertTrue(obj1 instanceof String);
|
||||
assertEquals(obj1, "try: bar");
|
||||
}
|
||||
|
||||
public void testTranslateVariablesRecursion() throws Exception {
|
||||
public void testTranslateVariablesRecursion() {
|
||||
stack.push(new Object() {
|
||||
public String getFoo() {
|
||||
return "%{bar}";
|
||||
@@ -226,7 +233,7 @@ public class StrutsUtilTest extends StrutsInternalTestCase {
|
||||
|
||||
// === internal class to assist in testing
|
||||
|
||||
class InternalMockHttpServletRequest extends MockHttpServletRequest {
|
||||
static class InternalMockHttpServletRequest extends MockHttpServletRequest {
|
||||
InternalMockRequestDispatcher dispatcher = null;
|
||||
public RequestDispatcher getRequestDispatcher(String path) {
|
||||
dispatcher = new InternalMockRequestDispatcher(path);
|
||||
@@ -238,7 +245,7 @@ public class StrutsUtilTest extends StrutsInternalTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
class InternalMockRequestDispatcher extends MockRequestDispatcher {
|
||||
static class InternalMockRequestDispatcher extends MockRequestDispatcher {
|
||||
private String url;
|
||||
boolean included = false;
|
||||
public InternalMockRequestDispatcher(String url) {
|
||||
|
||||
+60
-5
@@ -22,9 +22,7 @@ import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.mock.MockActionInvocation;
|
||||
import com.opensymphony.xwork2.util.ClassLoaderUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.TemplateException;
|
||||
import freemarker.template.TemplateExceptionHandler;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
@@ -39,8 +37,8 @@ import javax.servlet.ServletContext;
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.struts2.views.jsp.AbstractUITagTest.normalize;
|
||||
|
||||
@@ -194,7 +192,64 @@ public class FreemarkerResultMockedTest extends StrutsInternalTestCase {
|
||||
assertEquals(expected, stringWriter.toString());
|
||||
}
|
||||
|
||||
private void init() throws MalformedURLException, URISyntaxException {
|
||||
public void testIterator() throws Exception {
|
||||
File file = new File(FreeMarkerResultTest.class.getResource("iterator.ftl").toURI());
|
||||
EasyMock.expect(servletContext.getRealPath("/tutorial/org/apache/struts2/views/freemarker/iterator.ftl")).andReturn(file.getAbsolutePath());
|
||||
|
||||
file = new File(ClassLoaderUtil.getResource("template/simple/text.ftl", getClass()).toURI());
|
||||
EasyMock.expect(servletContext.getRealPath("/template/simple/text.ftl")).andReturn(file.getAbsolutePath());
|
||||
|
||||
file = new File(ClassLoaderUtil.getResource("template/simple/css.ftl", getClass()).toURI());
|
||||
EasyMock.expect(servletContext.getRealPath("/template/simple/css.ftl")).andReturn(file.getAbsolutePath());
|
||||
EasyMock.expect(servletContext.getRealPath("/template/~~~simple/css.ftl")).andReturn(file.getAbsolutePath());
|
||||
|
||||
file = new File(ClassLoaderUtil.getResource("template/simple/scripting-events.ftl", getClass()).toURI());
|
||||
EasyMock.expect(servletContext.getRealPath("/template/simple/scripting-events.ftl")).andReturn(file.getAbsolutePath());
|
||||
EasyMock.expect(servletContext.getRealPath("/template/~~~simple/scripting-events.ftl")).andReturn(file.getAbsolutePath());
|
||||
|
||||
file = new File(ClassLoaderUtil.getResource("template/simple/common-attributes.ftl", getClass()).toURI());
|
||||
EasyMock.expect(servletContext.getRealPath("/template/simple/common-attributes.ftl")).andReturn(file.getAbsolutePath());
|
||||
EasyMock.expect(servletContext.getRealPath("/template/~~~simple/common-attributes.ftl")).andReturn(file.getAbsolutePath());
|
||||
|
||||
file = new File(ClassLoaderUtil.getResource("template/simple/dynamic-attributes.ftl", getClass()).toURI());
|
||||
EasyMock.expect(servletContext.getRealPath("/template/simple/dynamic-attributes.ftl")).andReturn(file.getAbsolutePath());
|
||||
EasyMock.expect(servletContext.getRealPath("/template/~~~simple/dynamic-attributes.ftl")).andReturn(file.getAbsolutePath());
|
||||
|
||||
EasyMock.replay(servletContext);
|
||||
|
||||
init();
|
||||
|
||||
stack.push(new Object() {
|
||||
List<Object> items = null;
|
||||
|
||||
public List<Object> getItems() {
|
||||
if (items == null) {
|
||||
items = new ArrayList<>(3);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
final int finalI = i;
|
||||
items.add(new Object() {
|
||||
public String getName() {
|
||||
return "value" + finalI;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
});
|
||||
|
||||
request.setRequestURI("/tutorial/test11.action");
|
||||
ActionMapping mapping = container.getInstance(ActionMapper.class).getMapping(request, configurationManager);
|
||||
dispatcher.serviceAction(request, response, mapping);
|
||||
String result = stringWriter.toString();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
assertTrue(result.contains("id=\"itemId" + i + "\""));
|
||||
assertTrue(result.contains("name=\"items[" + i + "].name\""));
|
||||
assertTrue(result.contains("value=\"value" + i + "\""));
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
stringWriter = new StringWriter();
|
||||
writer = new PrintWriter(stringWriter);
|
||||
response = new StrutsMockHttpServletResponse();
|
||||
|
||||
@@ -18,7 +18,14 @@
|
||||
*/
|
||||
package org.apache.struts2.views.jsp;
|
||||
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsCheckerTest.NO_EXCLUSION_ACCEPT_ALL_PATTERNS_CHECKER;
|
||||
|
||||
|
||||
/**
|
||||
@@ -47,4 +54,58 @@ public class BeanTagTest extends AbstractUITagTest {
|
||||
request.verify();
|
||||
pageContext.verify();
|
||||
}
|
||||
|
||||
public void testNotAccepted() throws Exception {
|
||||
BeanTag tag = new BeanTag();
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setName("org.apache.struts2.TestAction");
|
||||
|
||||
Map<String, String> tmp = new HashMap<>();
|
||||
tmp.put("paramName", "getArray()[0]");
|
||||
context.put("parameters", HttpParameters.create(tmp).build());
|
||||
ParamTag param1 = new ParamTag();
|
||||
param1.setPageContext(pageContext);
|
||||
param1.setName("%{#parameters['paramName']}");
|
||||
param1.setValue("'success'");
|
||||
|
||||
tag.doStartTag();
|
||||
param1.doStartTag();
|
||||
|
||||
try {
|
||||
param1.doEndTag();
|
||||
fail("an excluded or not accepted is evaluated?!");
|
||||
} catch (StrutsException e) {
|
||||
assertEquals("Excluded or not accepted name found: getArray()[0]", e.getMessage());
|
||||
assertNull(stack.findValue("result"));
|
||||
}
|
||||
|
||||
param1.component.setNotExcludedAcceptedPatterns(NO_EXCLUSION_ACCEPT_ALL_PATTERNS_CHECKER);
|
||||
tag.component.addParameter("array", "just to instantiate array to avoid null for getArray()");
|
||||
|
||||
param1.doEndTag();
|
||||
assertEquals("success", stack.findValue("array[0]"));
|
||||
|
||||
tag.doEndTag();
|
||||
}
|
||||
|
||||
public void testGetterAccepted() throws Exception {
|
||||
BeanTag tag = new BeanTag();
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setName("org.apache.struts2.TestAction");
|
||||
|
||||
ParamTag param1 = new ParamTag();
|
||||
param1.setPageContext(pageContext);
|
||||
param1.setName("getArray()[0]");
|
||||
param1.setValue("'success'");
|
||||
|
||||
tag.doStartTag();
|
||||
param1.doStartTag();
|
||||
|
||||
tag.component.addParameter("array", "just to instantiate array to avoid null for getArray()");
|
||||
|
||||
param1.doEndTag();
|
||||
assertEquals("success", stack.findValue("array[0]"));
|
||||
|
||||
tag.doEndTag();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ public class ComboBoxTest extends AbstractUITagTest {
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setLabel("mylabel");
|
||||
tag.setName("foo");
|
||||
tag.setId("cb.bc");
|
||||
tag.setId("cb['\".\"'] = bc(){};//");
|
||||
tag.setList("collection");
|
||||
|
||||
tag.doStartTag();
|
||||
|
||||
@@ -117,7 +117,7 @@ public class TextfieldTest extends AbstractUITagTest {
|
||||
testAction.setFoo("bar");
|
||||
|
||||
TextFieldModel model = new TextFieldModel(stack, request, response);
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("name", "myname");
|
||||
params.put("value", "%{foo}");
|
||||
params.put("size", "10");
|
||||
@@ -172,6 +172,7 @@ public class TextfieldTest extends AbstractUITagTest {
|
||||
tag.setName("myname");
|
||||
tag.setValue("%{foo}");
|
||||
tag.setSize("10");
|
||||
tag.setDynamicAttribute(null, "anotherAttr", "%{foo}");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
+4
-4
@@ -1,5 +1,4 @@
|
||||
<?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
|
||||
@@ -19,5 +18,6 @@
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="test" pageWidth="842" pageHeight="595" orientation="Landscape" columnWidth="802" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="e65f69ca-7c62-4b4b-abc6-2e1a8710f23e">
|
||||
</jasperReport>
|
||||
<@s.iterator value="{'a','b','c'}" status="stat">
|
||||
<@s.textfield id="itemId%{#stat.index}" name="items[%{#stat.index}].name" theme="simple"/>
|
||||
</@s.iterator>
|
||||
@@ -1,13 +1,13 @@
|
||||
<tr>
|
||||
<td class="tdLabel"><label for="cb.bc" class="label">mylabel:</label></td>
|
||||
<td class="tdLabel"><label for="cb['"."']=bc(){};//" class="label">mylabel:</label></td>
|
||||
<td class="tdInput">
|
||||
<script type="text/javascript">
|
||||
function autoPopulate_cb_bc(targetElement) {
|
||||
function autoPopulate_cb__________bc_______(targetElement) {
|
||||
targetElement.form.elements['foo'].value=targetElement.options[targetElement.selectedIndex].value;
|
||||
}
|
||||
</script>
|
||||
<input type="text" name="foo" value="hello" id="cb.bc"/><br/>
|
||||
<select onChange="autoPopulate_cb_bc(this);">
|
||||
<input type="text" name="foo" value="hello" id="cb['"."']=bc(){};//"/><br/>
|
||||
<select onChange="autoPopulate_cb__________bc_______(this);">
|
||||
<option value="foo">foo</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<tr>
|
||||
<td class="tdLabel"></td>
|
||||
<td class="tdInput">
|
||||
<input type="radio" name="myMap['name']" id="myMap_'name'_"value=""/>
|
||||
<label for="myMap_'name'_">N/A</label>
|
||||
<input type="radio" name="myMap['name']" id="myMap_'name'_Opt." value="Opt."/>
|
||||
<label for="myMap_'name'_Opt.">Opt.</label>
|
||||
<input type="radio" name="myMap['name']" id="myMap_'name'_Std." checked="checked" value="Std."/>
|
||||
<label for="myMap_'name'_Std.">Std.</label>
|
||||
<input type="radio" name="myMap['name']" id="myMap__name__"value=""/>
|
||||
<label for="myMap__name__">N/A</label>
|
||||
<input type="radio" name="myMap['name']" id="myMap__name__Opt." value="Opt."/>
|
||||
<label for="myMap__name__Opt.">Opt.</label>
|
||||
<input type="radio" name="myMap['name']" id="myMap__name__Std." checked="checked" value="Std."/>
|
||||
<label for="myMap__name__Std.">Std.</label>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<tr>
|
||||
<td class="tdLabel"><label for="myname" class="label">mylabel:</label></td>
|
||||
<td class="tdInput"><input type="text" name="myname" size="10" value="%{1+1}" id="myname"/></td>
|
||||
<td class="tdInput"><input type="text" name="myname" size="10" value="%{1+1}" id="myname" anotherAttr="%{1+1}"/></td>
|
||||
</tr>
|
||||
|
||||
@@ -80,6 +80,11 @@
|
||||
</result>
|
||||
</action>
|
||||
|
||||
<action name="test11" class="com.opensymphony.xwork2.ActionSupport">
|
||||
<result type="freemarker">
|
||||
<param name="location">org/apache/struts2/views/freemarker/iterator.ftl</param>
|
||||
</result>
|
||||
</action>
|
||||
</package>
|
||||
|
||||
<package name="sitegraph" namespace="/tutorial/sitegraph" extends="struts-default">
|
||||
|
||||
@@ -102,7 +102,14 @@
|
||||
<interceptor-ref name="alias"/>
|
||||
<result name="success" type="mock" />
|
||||
</action>
|
||||
|
||||
|
||||
<action name="dynamicAliasTest" class="com.opensymphony.xwork2.SimpleAction">
|
||||
<param name="aliases">#{ #parameters['name'] : #parameters['value'] }</param>
|
||||
<interceptor-ref name="params"/>
|
||||
<interceptor-ref name="alias"/>
|
||||
<result name="success" type="mock" />
|
||||
</action>
|
||||
|
||||
<action name="packagelessAction" class="PackagelessAction">
|
||||
</action>
|
||||
|
||||
@@ -143,6 +150,21 @@
|
||||
<action name="InfiniteRecursionChain" class="com.opensymphony.xwork2.ActionSupport">
|
||||
<result name="success" type="chain">InfiniteRecursionChain</result>
|
||||
</action>
|
||||
<action name="chain_with_namespace" class="com.opensymphony.xwork2.SimpleAction">
|
||||
<result name="error" type="chain">
|
||||
<param name="actionName">chain_without_namespace</param>
|
||||
<param name="namespace">%{blah}</param>
|
||||
</result>
|
||||
<interceptor-ref name="debugStack"/>
|
||||
<interceptor-ref name="defaultStack"/>
|
||||
</action>
|
||||
<action name="chain_without_namespace" class="com.opensymphony.xwork2.SimpleAction">
|
||||
<result name="error" type="chain">
|
||||
<param name="actionName">Foo</param>
|
||||
</result>
|
||||
<interceptor-ref name="debugStack"/>
|
||||
<interceptor-ref name="defaultStack"/>
|
||||
</action>
|
||||
|
||||
</package>
|
||||
|
||||
|
||||
+51
-8
@@ -19,6 +19,8 @@
|
||||
package org.apache.struts2.views.jasperreports;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
|
||||
import net.sf.jasperreports.engine.*;
|
||||
@@ -131,6 +133,7 @@ public class JasperReportsResult extends StrutsResultSupport implements JasperRe
|
||||
private final static Logger LOG = LogManager.getLogger(JasperReportsResult.class);
|
||||
|
||||
protected String dataSource;
|
||||
private String parsedDataSource;
|
||||
protected String format;
|
||||
protected String documentName;
|
||||
protected String contentDisposition;
|
||||
@@ -150,12 +153,16 @@ public class JasperReportsResult extends StrutsResultSupport implements JasperRe
|
||||
* additional report parameters from the action.
|
||||
*/
|
||||
protected String reportParameters;
|
||||
private String parsedReportParameters;
|
||||
|
||||
/**
|
||||
* Names an exporter parameters map stack value,
|
||||
* allowing the use of custom export parameters.
|
||||
*/
|
||||
protected String exportParameters;
|
||||
private String parsedExportParameters;
|
||||
|
||||
private NotExcludedAcceptedPatternsChecker notExcludedAcceptedPatterns;
|
||||
|
||||
/**
|
||||
* Default ctor.
|
||||
@@ -173,6 +180,11 @@ public class JasperReportsResult extends StrutsResultSupport implements JasperRe
|
||||
super(location);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setNotExcludedAcceptedPatterns(NotExcludedAcceptedPatternsChecker notExcludedAcceptedPatterns) {
|
||||
this.notExcludedAcceptedPatterns = notExcludedAcceptedPatterns;
|
||||
}
|
||||
|
||||
public String getImageServletUrl() {
|
||||
return imageServletUrl;
|
||||
}
|
||||
@@ -265,8 +277,16 @@ public class JasperReportsResult extends StrutsResultSupport implements JasperRe
|
||||
ValueStackDataSource stackDataSource = null;
|
||||
|
||||
Connection conn = (Connection) stack.findValue(connection);
|
||||
if (conn == null)
|
||||
stackDataSource = new ValueStackDataSource(stack, dataSource, wrapField);
|
||||
if (conn == null) {
|
||||
boolean evaluated = parsedDataSource != null && !parsedDataSource.equals(dataSource);
|
||||
boolean reevaluate = !evaluated || isAcceptableExpression(parsedDataSource);
|
||||
if (reevaluate) {
|
||||
stackDataSource = new ValueStackDataSource(stack, parsedDataSource, wrapField);
|
||||
} else {
|
||||
throw new ServletException(String.format("Error building dataSource for excluded or not accepted [%s]",
|
||||
parsedDataSource));
|
||||
}
|
||||
}
|
||||
|
||||
if ("https".equalsIgnoreCase(request.getScheme())) {
|
||||
// set the the HTTP Header to work around IE SSL weirdness
|
||||
@@ -297,7 +317,9 @@ public class JasperReportsResult extends StrutsResultSupport implements JasperRe
|
||||
}
|
||||
|
||||
// Add any report parameters from action to param map.
|
||||
Map reportParams = (Map) stack.findValue(reportParameters);
|
||||
boolean evaluated = parsedReportParameters != null && !parsedReportParameters.equals(reportParameters);
|
||||
boolean reevaluate = !evaluated || isAcceptableExpression(parsedReportParameters);
|
||||
Map reportParams = reevaluate ? (Map) stack.findValue(parsedReportParameters) : null;
|
||||
if (reportParams != null) {
|
||||
LOG.debug("Found report parameters; adding to parameters...");
|
||||
parameters.putAll(reportParams);
|
||||
@@ -372,7 +394,9 @@ public class JasperReportsResult extends StrutsResultSupport implements JasperRe
|
||||
throw new ServletException("Unknown report format: " + format);
|
||||
}
|
||||
|
||||
Map exportParams = (Map) stack.findValue(exportParameters);
|
||||
evaluated = parsedExportParameters != null && !parsedExportParameters.equals(exportParameters);
|
||||
reevaluate = !evaluated || isAcceptableExpression(parsedExportParameters);
|
||||
Map exportParams = reevaluate ? (Map) stack.findValue(parsedExportParameters) : null;
|
||||
if (exportParams != null) {
|
||||
LOG.debug("Found export parameters; adding to exporter parameters...");
|
||||
exporter.getParameters().putAll(exportParams);
|
||||
@@ -427,8 +451,9 @@ public class JasperReportsResult extends StrutsResultSupport implements JasperRe
|
||||
LOG.error(message);
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
if (dataSource != null)
|
||||
dataSource = conditionalParse(dataSource, invocation);
|
||||
if (dataSource != null) {
|
||||
parsedDataSource = conditionalParse(dataSource, invocation);
|
||||
}
|
||||
|
||||
format = conditionalParse(format, invocation);
|
||||
if (StringUtils.isEmpty(format)) {
|
||||
@@ -443,8 +468,8 @@ public class JasperReportsResult extends StrutsResultSupport implements JasperRe
|
||||
documentName = conditionalParse(documentName, invocation);
|
||||
}
|
||||
|
||||
reportParameters = conditionalParse(reportParameters, invocation);
|
||||
exportParameters = conditionalParse(exportParameters, invocation);
|
||||
parsedReportParameters = conditionalParse(reportParameters, invocation);
|
||||
parsedExportParameters = conditionalParse(exportParameters, invocation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -469,4 +494,22 @@ public class JasperReportsResult extends StrutsResultSupport implements JasperRe
|
||||
return baos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if expression doesn't contain vulnerable code
|
||||
*
|
||||
* @param expression of result
|
||||
* @return true|false
|
||||
* @since 2.5.27
|
||||
*/
|
||||
protected boolean isAcceptableExpression(String expression) {
|
||||
NotExcludedAcceptedPatternsChecker.IsAllowed isAllowed = notExcludedAcceptedPatterns.isAllowed(expression);
|
||||
if (isAllowed.isAllowed()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG.warn("Expression [{}] isn't allowed by pattern [{}]! See Accepted / Excluded patterns at\n" +
|
||||
"https://struts.apache.org/security/", expression, isAllowed.getAllowedPattern());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+237
-14
@@ -20,35 +20,35 @@ package org.apache.struts2.views.jasperreports;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.mock.MockActionInvocation;
|
||||
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.ClassLoaderUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import net.sf.jasperreports.engine.JasperCompileManager;
|
||||
import org.apache.struts2.StrutsStatics;
|
||||
import org.apache.struts2.StrutsTestCase;
|
||||
import org.easymock.IAnswer;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import java.net.URL;
|
||||
import java.sql.Connection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static net.sf.jasperreports.engine.JRExporterParameter.OUTPUT_STRING_BUFFER;
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.expectLastCall;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
public class JasperReportsResultTest extends StrutsTestCase {
|
||||
private MockActionInvocation invocation;
|
||||
private ValueStack stack;
|
||||
private JasperReportsResult result;
|
||||
|
||||
public void testConnClose() throws Exception {
|
||||
JasperReportsResult result = new JasperReportsResult();
|
||||
URL url = ClassLoaderUtil.getResource("org/apache/struts2/views/jasperreports/empty.jrxml", this.getClass());
|
||||
JasperCompileManager.compileReportToFile(url.getFile(), url.getFile() + ".jasper");
|
||||
result.setLocation("org/apache/struts2/views/jasperreports/empty.jrxml.jasper");
|
||||
result.setFormat(JasperReportConstants.FORMAT_XML);
|
||||
|
||||
Connection connection = createMock(Connection.class);
|
||||
final Boolean[] closed = {false};
|
||||
connection.close();
|
||||
@@ -70,20 +70,243 @@ public class JasperReportsResultTest extends StrutsTestCase {
|
||||
assertTrue(closed[0]);
|
||||
}
|
||||
|
||||
public void testDataSourceNotAccepted() throws Exception {
|
||||
stack.push(new Object() {
|
||||
public String getDatasourceName() {
|
||||
return "getDatasource()";
|
||||
}
|
||||
|
||||
public Map<String, String>[] getDatasource() {
|
||||
return JR_MAP_ARRAY_DATA_SOURCE;
|
||||
}
|
||||
});
|
||||
result.setDataSource("${datasourceName}");
|
||||
|
||||
try {
|
||||
result.execute(this.invocation);
|
||||
} catch (ServletException e) {
|
||||
assertEquals("Error building dataSource for excluded or not accepted [getDatasource()]",
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
// verify that above test has really effect
|
||||
result.setNotExcludedAcceptedPatterns(NO_EXCLUSION_ACCEPT_ALL_PATTERNS_CHECKER);
|
||||
result.execute(this.invocation);
|
||||
assertTrue(response.getContentAsString().contains("Hello Foo Bar!"));
|
||||
}
|
||||
|
||||
public void testDataSourceAccepted() throws Exception {
|
||||
stack.push(new Object() {
|
||||
public String getDatasourceName() {
|
||||
return "datasource";
|
||||
}
|
||||
|
||||
public Map<String, String>[] getDatasource() {
|
||||
return JR_MAP_ARRAY_DATA_SOURCE;
|
||||
}
|
||||
});
|
||||
result.setDataSource("${datasourceName}");
|
||||
|
||||
result.execute(this.invocation);
|
||||
assertTrue(response.getContentAsString().contains("Hello Foo Bar!"));
|
||||
}
|
||||
|
||||
public void testDataSourceExpressionAccepted() throws Exception {
|
||||
result.setDataSource("{#{'firstName':'Qux', 'lastName':'Quux'}}");
|
||||
|
||||
result.execute(this.invocation);
|
||||
assertTrue(response.getContentAsString().contains("Hello Qux Quux!"));
|
||||
}
|
||||
|
||||
public void testReportParametersNotAccepted() throws Exception {
|
||||
result.setDataSource("{#{'firstName':'ignore', 'lastName':'ignore'}}");
|
||||
|
||||
stack.push(new Object() {
|
||||
public String getReportParametersName() {
|
||||
return "getReportParameters()";
|
||||
}
|
||||
|
||||
public Map<String, String> getReportParameters() {
|
||||
return new HashMap<String, String>() {{
|
||||
put("title", "Baz");
|
||||
}};
|
||||
}
|
||||
});
|
||||
|
||||
result.setReportParameters("${reportParametersName}");
|
||||
result.execute(this.invocation);
|
||||
assertTrue(response.getContentAsString().contains("null Report"));
|
||||
|
||||
// verify that above test has really effect
|
||||
response.setCommitted(false);
|
||||
response.reset();
|
||||
result.setNotExcludedAcceptedPatterns(NO_EXCLUSION_ACCEPT_ALL_PATTERNS_CHECKER);
|
||||
result.execute(this.invocation);
|
||||
assertTrue(response.getContentAsString().contains("Baz Report"));
|
||||
}
|
||||
|
||||
public void testReportParametersAccepted() throws Exception {
|
||||
result.setDataSource("{#{'firstName':'ignore', 'lastName':'ignore'}}");
|
||||
|
||||
stack.push(new Object() {
|
||||
public String getReportParametersName() {
|
||||
return "reportParameters";
|
||||
}
|
||||
|
||||
public Map<String, String> getReportParameters() {
|
||||
return new HashMap<String, String>() {{
|
||||
put("title", "Baz");
|
||||
}};
|
||||
}
|
||||
});
|
||||
|
||||
result.setReportParameters("${reportParametersName}");
|
||||
result.execute(this.invocation);
|
||||
assertTrue(response.getContentAsString().contains("Baz Report"));
|
||||
}
|
||||
|
||||
public void testReportParametersExpressionAccepted() throws Exception {
|
||||
result.setDataSource("{#{'firstName':'ignore', 'lastName':'ignore'}}");
|
||||
|
||||
result.setReportParameters("#{'title':'Qux'}");
|
||||
result.execute(this.invocation);
|
||||
assertTrue(response.getContentAsString().contains("Qux Report"));
|
||||
}
|
||||
|
||||
public void testExportParametersNotAccepted() throws Exception {
|
||||
result.setDataSource("{#{'firstName':'ignore', 'lastName':'ignore'}}");
|
||||
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
stack.push(new Object() {
|
||||
public String getExportParametersName() {
|
||||
return "getExportParameters()";
|
||||
}
|
||||
|
||||
public Map<Object, Object> getExportParameters() {
|
||||
return new HashMap<Object, Object>() {{
|
||||
put(OUTPUT_STRING_BUFFER, sb);
|
||||
}};
|
||||
}
|
||||
});
|
||||
|
||||
result.setExportParameters("${exportParametersName}");
|
||||
result.execute(this.invocation);
|
||||
assertEquals(0, sb.length());
|
||||
|
||||
// verify that above test has really effect
|
||||
response.setCommitted(false);
|
||||
response.reset();
|
||||
result.setNotExcludedAcceptedPatterns(NO_EXCLUSION_ACCEPT_ALL_PATTERNS_CHECKER);
|
||||
result.execute(this.invocation);
|
||||
assertNotEquals(0, sb.length());
|
||||
}
|
||||
|
||||
public void testExportParametersAccepted() throws Exception {
|
||||
result.setDataSource("{#{'firstName':'Qux', 'lastName':'Quux'}}");
|
||||
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
stack.push(new Object() {
|
||||
public String getExportParametersName() {
|
||||
return "exportParameters";
|
||||
}
|
||||
|
||||
public Map<Object, Object> getExportParameters() {
|
||||
return new HashMap<Object, Object>() {{
|
||||
put(OUTPUT_STRING_BUFFER, sb);
|
||||
}};
|
||||
}
|
||||
});
|
||||
|
||||
result.setExportParameters("${exportParametersName}");
|
||||
result.execute(this.invocation);
|
||||
assertTrue(sb.toString().contains("Hello Qux Quux!"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI("http://sumeruri");
|
||||
|
||||
request.setRequestURI("http://someuri");
|
||||
ActionContext context = ActionContext.getContext();
|
||||
context.put(StrutsStatics.HTTP_RESPONSE, response);
|
||||
context.put(StrutsStatics.HTTP_REQUEST, request);
|
||||
this.stack = context.getValueStack();
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
context.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
|
||||
this.stack = context.getValueStack();
|
||||
this.invocation = new MockActionInvocation();
|
||||
this.invocation.setInvocationContext(context);
|
||||
this.invocation.setStack(this.stack);
|
||||
|
||||
result = new JasperReportsResult();
|
||||
container.inject(result);
|
||||
URL url = ClassLoaderUtil.getResource("org/apache/struts2/views/jasperreports/simple.jrxml", this.getClass());
|
||||
JasperCompileManager.compileReportToFile(url.getFile(), url.getFile() + ".jasper");
|
||||
result.setLocation("org/apache/struts2/views/jasperreports/simple.jrxml.jasper");
|
||||
result.setFormat(JasperReportConstants.FORMAT_XML);
|
||||
}
|
||||
|
||||
|
||||
private static final Map<String, String>[] JR_MAP_ARRAY_DATA_SOURCE = new Map[]{
|
||||
new HashMap<String, String>() {{
|
||||
put("firstName", "Foo");
|
||||
put("lastName", "Bar");
|
||||
}}
|
||||
};
|
||||
|
||||
private static final NotExcludedAcceptedPatternsChecker NO_EXCLUSION_ACCEPT_ALL_PATTERNS_CHECKER
|
||||
= new NotExcludedAcceptedPatternsChecker() {
|
||||
@Override
|
||||
public IsAllowed isAllowed(String value) {
|
||||
return IsAllowed.yes("*");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsAccepted isAccepted(String value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(String commaDelimitedPatterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(String[] patterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(Set<String> patterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Pattern> getAcceptedPatterns() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsExcluded isExcluded(String value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(String commaDelimitedPatterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(String[] patterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(Set<String> patterns) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Pattern> getExcludedPatterns() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<?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.
|
||||
*/
|
||||
-->
|
||||
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd"
|
||||
name="test" pageWidth="842" pageHeight="595" orientation="Landscape" columnWidth="802">
|
||||
<parameter name="title" />
|
||||
<field name="firstName" />
|
||||
<field name="lastName" />
|
||||
<title>
|
||||
<band height="16">
|
||||
<textField>
|
||||
<reportElement x="0" y="0" width="100" height="16" />
|
||||
<textFieldExpression><![CDATA[$P{title}]]> + " Report"</textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
</title>
|
||||
<detail>
|
||||
<band height="16">
|
||||
<textField>
|
||||
<reportElement x="0" y="0" width="100" height="16" />
|
||||
<textFieldExpression>"Hello " + <![CDATA[$F{firstName}]]> + " " + <![CDATA[$F{lastName}]]> + "!"</textFieldExpression>
|
||||
</textField>
|
||||
</band>
|
||||
</detail>
|
||||
</jasperReport>
|
||||
+2
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
package org.apache.struts2.views.java.simple;
|
||||
|
||||
import com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsChecker;
|
||||
import org.apache.struts2.components.Anchor;
|
||||
import org.apache.struts2.components.UIBean;
|
||||
import org.apache.struts2.components.ServletUrlRenderer;
|
||||
@@ -73,6 +74,7 @@ public class AnchorTest extends AbstractTest {
|
||||
super.setUp();
|
||||
this.tag = new Anchor(stack, request, response);
|
||||
this.tag.setUrlRenderer(new ServletUrlRenderer());
|
||||
this.tag.setNotExcludedAcceptedPatterns(new DefaultNotExcludedAcceptedPatternsChecker());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
package org.apache.struts2.views.java.simple;
|
||||
|
||||
import com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsChecker;
|
||||
import org.apache.struts2.components.Checkbox;
|
||||
import org.apache.struts2.components.UIBean;
|
||||
|
||||
@@ -68,6 +69,7 @@ public class CheckboxTest extends AbstractCommonAttributesTest {
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
tag = new Checkbox(stack, request, response);
|
||||
tag.setNotExcludedAcceptedPatterns(new DefaultNotExcludedAcceptedPatternsChecker());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -192,7 +192,9 @@ public class PortletUrlRenderer implements UrlRenderer {
|
||||
} else {
|
||||
id = action.substring(slash + 1);
|
||||
}
|
||||
formComponent.addParameter("id", formComponent.escape(id));
|
||||
String escapedId = formComponent.escape(id);
|
||||
formComponent.addParameter("id", escapedId);
|
||||
formComponent.addParameter("escapedId", escapedId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user