blob: 7b6117d27ba1f2a0b8fff2218468c84b17fd17a6 [file] [log] [blame]
/*
* 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.views.jsp;
import java.io.File;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspWriter;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.components.URL;
import org.apache.struts2.dispatcher.ApplicationMap;
import org.apache.struts2.dispatcher.Dispatcher;
import org.apache.struts2.dispatcher.HttpParameters;
import org.apache.struts2.dispatcher.RequestMap;
import org.apache.struts2.dispatcher.SessionMap;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.dispatcher.mapper.DefaultActionMapper;
import com.mockobjects.dynamic.Mock;
import com.mockobjects.servlet.MockBodyContent;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.DefaultActionInvocation;
import com.opensymphony.xwork2.DefaultActionProxyFactory;
import com.opensymphony.xwork2.inject.Container;
/**
* Unit test for {@link URLTag}.
*
*/
public class URLTagTest extends AbstractUITagTest {
private URLTag tag;
/**
* To test priority of parameter passed in to url component though
* various way
* - current request url
* - tag's value attribute
* - tag's nested param tag
*
* id1
* ===
* - found in current request url
* - found in tag's value attribute
* - found in tag's param tag
* CONCLUSION: tag's param tag takes precedence (paramId1)
*
* id2
* ===
* - found in current request url
* - found in tag's value attribute
* CONCLUSION: tag's value attribute take precedence (tagId2)
*
* urlParam1
* =========
* - found in current request url
* CONCLUSION: param in current request url will be used (urlValue1)
*
* urlParam2
* =========
* - found in current request url
* CONCLUSION: param in current request url will be used. (urlValue2)
*
* tagId
* =====
* - found in tag's value attribute
* CONCLUSION: param in tag's value attribute wil; be used. (tagValue)
*
* param1
* ======
* - found in nested param tag
* CONCLUSION: param in nested param tag will be used. (param1value)
*
* param2
* ======
* - found in nested param tag
* CONCLUSION: param in nested param tag will be used. (param2value)
*/
public void testParametersPriority() throws Exception {
request.setQueryString("id1=urlId1&id2=urlId2&urlParam1=urlValue1&urlParam2=urlValue2");
tag.setValue("testAction.action?id1=tagId1&id2=tagId2&tagId=tagValue");
ParamTag param1 = new ParamTag();
param1.setPageContext(pageContext);
param1.setName("param1");
param1.setValue("%{'param1value'}");
ParamTag param2 = new ParamTag();
param2.setPageContext(pageContext);
param2.setName("param2");
param2.setValue("%{'param2value'}");
ParamTag param3 = new ParamTag();
param3.setPageContext(pageContext);
param3.setName("id1");
param3.setValue("%{'paramId1'}");
tag.doStartTag();
param1.doStartTag();
param1.doEndTag();
param2.doStartTag();
param2.doEndTag();
param3.doStartTag();
param3.doEndTag();
URL url = (URL) tag.getComponent();
Map parameters = url.getParameters();
assertNotNull(parameters);
assertEquals(parameters.size(), 7);
assertEquals(parameters.get("id1"), "paramId1");
assertEquals(parameters.get("id2"), "tagId2");
assertEquals(parameters.get("urlParam1"), "urlValue1");
assertEquals(parameters.get("urlParam2"), "urlValue2");
assertEquals(parameters.get("tagId"), "tagValue");
assertEquals(parameters.get("param1"), "param1value");
assertEquals(parameters.get("param2"), "param2value");
}
/**
* Use Iterable values as the value of the param tags
*/
public void testIterableParameters() throws Exception {
tag.setValue("/TestAction.action?p0=z");
tag.doStartTag();
//Iterable
List<ValueHolder> list = new ArrayList<>();
list.add(new ValueHolder("a"));
list.add(new ValueHolder("b"));
tag.component.addParameter("p1", list);
//String[]
tag.component.addParameter("p2", new String[] { "d", "e" });
//ValueHolder[]
tag.component.addParameter("p3", new ValueHolder[] {
new ValueHolder("f"), new ValueHolder("g") });
tag.doEndTag();
assertEquals("/TestAction.action?p0=z&amp;p1=a&amp;p1=b&amp;p2=d&amp;p2=e&amp;p3=f&amp;p3=g", writer.toString());
}
/**
* To test priority of parameter passed in to url component though
* various way, with includeParams="NONE"
* - current request url
* - tag's value attribute
* - tag's nested param tag
*
* In this case only parameters from the tag itself is taken into account.
* Those from request will not count, only those in tag's value attribute
* and nested param tag.
*/
public void testParametersPriorityWithIncludeParamsAsNONE() throws Exception {
request.setQueryString("id1=urlId1&id2=urlId2&urlParam1=urlValue1&urlParam2=urlValue2");
tag.setValue("testAction.action?id1=tagId1&id2=tagId2&tagId=tagValue");
tag.setIncludeParams("NONE");
ParamTag param1 = new ParamTag();
param1.setPageContext(pageContext);
param1.setName("param1");
param1.setValue("%{'param1value'}");
ParamTag param2 = new ParamTag();
param2.setPageContext(pageContext);
param2.setName("param2");
param2.setValue("%{'param2value'}");
ParamTag param3 = new ParamTag();
param3.setPageContext(pageContext);
param3.setName("id1");
param3.setValue("%{'paramId1'}");
tag.doStartTag();
param1.doStartTag();
param1.doEndTag();
param2.doStartTag();
param2.doEndTag();
param3.doStartTag();
param3.doEndTag();
URL url = (URL) tag.getComponent();
Map parameters = url.getParameters();
assertEquals(parameters.size(), 5);
assertEquals(parameters.get("id1"), "paramId1");
assertEquals(parameters.get("id2"), "tagId2");
assertEquals(parameters.get("tagId"), "tagValue");
assertEquals(parameters.get("param1"), "param1value");
assertEquals(parameters.get("param2"), "param2value");
}
public void testIncludeParamsDefaultToGET() throws Exception {
request.setQueryString("one=oneVal&two=twoVal&three=threeVal");
// request parameter map should not have any effect, as includeParams
// default to GET, which get its param from request.getQueryString()
Map<String, String> tmp = new HashMap<>();
tmp.put("one", "aaa");
tmp.put("two", "bbb");
tmp.put("three", "ccc");
request.setParameterMap(tmp);
tag.setValue("TestAction.acton");
tag.doStartTag();
URL url = (URL) tag.getComponent();
Map parameters = url.getParameters();
tag.doEndTag();
assertEquals(parameters.get("one"), "oneVal");
assertEquals(parameters.get("two"), "twoVal");
assertEquals(parameters.get("three"), "threeVal");
}
public void testActionURL() throws Exception {
tag.setValue("TestAction.action");
tag.doStartTag();
tag.doEndTag();
assertEquals("TestAction.action", writer.toString());
}
public void testAddParameters() throws Exception {
request.setAttribute("struts.request_uri", "/Test.action");
request.setAttribute("struts.request_uri", "/TestAction.action");
request.setQueryString("param0=value0");
tag.doStartTag();
tag.component.addParameter("param1", "value1");
tag.component.addParameter("param2", "value2");
tag.doEndTag();
assertEquals("/TestAction.action?param0=value0&amp;param1=value1&amp;param2=value2", writer.toString());
}
public void testEvaluateValue() throws Exception {
Foo foo = new Foo();
foo.setTitle("test");
stack.push(foo);
tag.setValue("%{title}");
tag.doStartTag();
tag.doEndTag();
assertEquals("test", writer.toString());
}
public void testHttps() throws Exception {
request.setScheme("https");
request.setServerName("localhost");
request.setServerPort(443);
tag.setValue("list-members.action");
tag.doStartTag();
tag.doEndTag();
assertEquals("list-members.action", writer.toString());
}
public void testAnchor() throws Exception {
request.setScheme("https");
request.setServerName("localhost");
request.setServerPort(443);
tag.setValue("list-members.action");
tag.setAnchor("test");
tag.doStartTag();
tag.doEndTag();
assertEquals("list-members.action#test", writer.toString());
}
public void testParamPrecedence() throws Exception {
request.setRequestURI("/context/someAction.action");
request.setQueryString("id=22&name=John");
URLTag urlTag = new URLTag();
urlTag.setPageContext(pageContext);
urlTag.setIncludeParams("get");
urlTag.setEncode("%{false}");
ParamTag paramTag = new ParamTag();
paramTag.setPageContext(pageContext);
paramTag.setName("id");
paramTag.setValue("%{'33'}");
urlTag.doStartTag();
paramTag.doStartTag();
paramTag.doEndTag();
urlTag.doEndTag();
assertEquals("/context/someAction.action?id=33&amp;name=John", writer.getBuffer().toString());
}
public void testParamPrecedenceWithAnchor() throws Exception {
request.setRequestURI("/context/someAction.action");
request.setQueryString("id=22&name=John");
URLTag urlTag = new URLTag();
urlTag.setPageContext(pageContext);
urlTag.setIncludeParams("get");
urlTag.setEncode("%{false}");
urlTag.setAnchor("testAnchor");
ParamTag paramTag = new ParamTag();
paramTag.setPageContext(pageContext);
paramTag.setName("id");
paramTag.setValue("%{'33'}");
urlTag.doStartTag();
paramTag.doStartTag();
paramTag.doEndTag();
urlTag.doEndTag();
assertEquals("/context/someAction.action?id=33&amp;name=John#testAnchor", writer.getBuffer().toString());
}
public void testPutId() throws Exception {
tag.setValue("/public/about");
assertNull(stack.findString("myId")); // nothing in stack
tag.setVar("myId");
tag.doStartTag();
tag.doEndTag();
assertEquals("", writer.toString());
assertEquals("/public/about", stack.findString("myId")); // is in stack now
}
public void testUsingValueOnly() throws Exception {
tag.setValue("/public/about/team.jsp");
tag.doStartTag();
tag.doEndTag();
assertEquals("/public/about/team.jsp", writer.toString());
}
public void testRequestURIActionIncludeNone() throws Exception {
request.setRequestURI("/public/about");
request.setQueryString("section=team&company=acme inc");
tag.setAction("team");
tag.setIncludeParams("none");
tag.doStartTag();
tag.doEndTag();
assertEquals("/team.action", writer.toString());
}
public void testRequestURIActionIncludeGet() throws Exception {
request.setRequestURI("/public/about");
request.setQueryString("section=team&company=acme inc");
tag.setAction("team");
tag.setIncludeParams("get");
tag.doStartTag();
tag.doEndTag();
assertEquals("/team.action?section=team&amp;company=acme+inc", writer.toString());
}
public void testRequestURIActionIncludeGetDoNotEscapeAmp() throws Exception {
request.setRequestURI("/public/about");
request.setQueryString("section=team&company=acme inc");
tag.setAction("team");
tag.setIncludeParams("get");
tag.setEscapeAmp("false");
tag.doStartTag();
tag.doEndTag();
assertEquals("/team.action?section=team&company=acme+inc", writer.toString());
}
public void testRequestURINoActionIncludeNone() throws Exception {
request.setRequestURI("/public/about");
request.setQueryString("section=team&company=acme inc");
tag.setAction(null);
tag.setIncludeParams("none");
tag.doStartTag();
tag.doEndTag();
assertEquals("/public/about", writer.toString());
}
public void testNoActionIncludeGet() throws Exception {
request.setRequestURI("/public/about");
request.setQueryString("section=team&company=acme inc");
tag.setAction(null);
tag.setIncludeParams("get");
tag.doStartTag();
tag.doEndTag();
assertEquals("/public/about?section=team&amp;company=acme+inc", writer.toString());
}
public void testRequestURIActionIncludeAll() throws Exception {
request.setRequestURI("/public/about");
request.setQueryString("section=team&company=acme inc");
tag.setAction("team");
tag.setIncludeParams("all");
tag.doStartTag();
// include nested param tag
ParamTag paramTag = new ParamTag();
paramTag.setPageContext(pageContext);
paramTag.setName("year");
paramTag.setValue("2006");
paramTag.doStartTag();
paramTag.doEndTag();
tag.doEndTag();
assertEquals("/team.action?section=team&amp;company=acme+inc&amp;year=2006", writer.toString());
}
public void testRequestURINoActionIncludeAll() throws Exception {
request.setRequestURI("/public/about");
request.setQueryString("section=team&company=acme inc");
tag.setAction(null);
tag.setIncludeParams("all");
tag.doStartTag();
// include nested param tag
ParamTag paramTag = new ParamTag();
paramTag.setPageContext(pageContext);
paramTag.setName("year");
paramTag.setValue("2006");
paramTag.doStartTag();
paramTag.doEndTag();
tag.doEndTag();
assertEquals("/public/about?section=team&amp;company=acme+inc&amp;year=2006", writer.toString());
}
public void testUnknownIncludeParam() throws Exception {
request.setRequestURI("/public/about");
request.setQueryString("section=team");
tag.setIncludeParams("unknown"); // will log at WARN level
tag.doStartTag();
tag.doEndTag();
assertEquals("/public/about", writer.toString()); // should not add any request parameters
}
public void testRequestURIWithAnchor() throws Exception {
request.setRequestURI("/public/about");
request.setQueryString("company=acme inc#canada");
tag.setAction("company");
tag.setIncludeParams("get");
tag.doStartTag();
tag.doEndTag();
assertEquals("/company.action?company=acme+inc", writer.toString()); // will always chop anchor if using requestURI
}
public void testIncludeContext() throws Exception {
request.setupGetContext("/myapp");
tag.setIncludeContext("true");
tag.setAction("company");
tag.doStartTag();
tag.doEndTag();
assertEquals("/myapp/company.action", writer.toString());
}
public void testForceAddSchemeHostAndPort() throws Exception {
tag.setForceAddSchemeHostAndPort("true");
tag.setAction("company");
tag.doStartTag();
tag.doEndTag();
assertEquals("http://localhost/company.action", writer.toString());
}
public void testEmptyActionCustomMapper() throws Exception {
Map<String,String> props = new HashMap<>();
props.put("config", "struts-default.xml,struts-plugin.xml,struts.xml,org/apache/struts2/views/jsp/WW3090-struts.xml");
this.tearDown();
Dispatcher du = this.initDispatcher(props);
action = this.getAction();
stack = ActionContext.getContext().getValueStack();
context = stack.getContext();
stack.push(action);
request = new StrutsMockHttpServletRequest();
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
response = new StrutsMockHttpServletResponse();
request.setSession(new StrutsMockHttpSession());
request.setupGetServletPath("/");
writer = new StringWriter();
servletContext = new StrutsMockServletContext();
servletContext.setRealPath(new File("nosuchfile.properties").getAbsolutePath());
servletContext.setServletInfo("Resin");
pageContext = new StrutsMockPageContext();
pageContext.setRequest(request);
pageContext.setResponse(response);
pageContext.setServletContext(servletContext);
mockContainer = new Mock(Container.class);
session = new SessionMap<>(request);
Map<String, Object> extraContext = du.createContextMap(new RequestMap(request),
HttpParameters.create(request.getParameterMap()).build(),
session,
new ApplicationMap(pageContext.getServletContext()),
request,
response);
// let's not set the locale -- there is a test that checks if Dispatcher actually picks this up...
// ... but generally we want to just use no locale (let it stay system default)
extraContext = ActionContext.of(extraContext).withLocale(null).getContextMap();
stack.getContext().putAll(extraContext);
ActionContext actionContext = ActionContext.of(context)
.withServletRequest(request)
.withServletResponse(response)
.withServletContext(servletContext)
.bind();
// Make sure we have an action invocation available
ActionContext.getContext().withActionInvocation(new DefaultActionInvocation(null, true));
DefaultActionProxyFactory apFactory = new DefaultActionProxyFactory();
apFactory.setContainer(container);
ActionProxy ap = apFactory.createActionProxy("/", "hello", null, null);
ActionContext.getContext().getActionInvocation().init(ap);
request.setScheme("http");
request.setServerName("localhost");
request.setServerPort(80);
tag = new URLTag();
tag.setPageContext(pageContext);
JspWriter jspWriter = new StrutsMockJspWriter(writer);
pageContext.setJspWriter(jspWriter);
request.setRequestURI("/context/someAction.action");
tag.setAction(null);
tag.setValue(null);
tag.doStartTag();
tag.doEndTag();
assertEquals("/hello.action-red", writer.toString());
writer = new StringWriter();
jspWriter = new StrutsMockJspWriter(writer);
pageContext.setJspWriter(jspWriter);
tag.doStartTag();
tag.doEndTag();
assertEquals("/hello.action-blue", writer.toString());
writer = new StringWriter();
jspWriter = new StrutsMockJspWriter(writer);
pageContext.setJspWriter(jspWriter);
tag.doStartTag();
tag.doEndTag();
assertEquals("/hello.action-red", writer.toString());
}
public void testEmbeddedParamTagExpressionGetsEvaluatedCorrectly() throws Exception {
request.setRequestURI("/public/about");
request.setQueryString("section=team&company=acme inc");
tag.setAction("team");
tag.setIncludeParams("all");
tag.doStartTag();
Foo foo = new Foo("test");
stack.push(foo);
// include nested param tag
ParamTag paramTag = new ParamTag();
paramTag.setPageContext(pageContext);
paramTag.setName("title");
paramTag.setValue("%{title}");
paramTag.doStartTag();
paramTag.doEndTag();
tag.doEndTag();
assertEquals("/team.action?section=team&amp;company=acme+inc&amp;title=test", writer.toString());
}
public void testAccessToStackInternalsGetsHandledCorrectly() throws Exception {
Map<String, Object> params = new LinkedHashMap<>();
params.put("aaa", new String[] {"1${#session[\"foo\"]='true'}"});
params.put("aab", new String[]{"1${#session[\"bar\"]}"});
params.put("aac", new String[]{"1${#_memberAccess[\"allowStaticMethodAccess\"]='true'}"});
params.put("aad", new String[]{"1${#_memberAccess[\"allowStaticMethodAccess\"]}"});
request.setParameterMap(params);
request.setRequestURI("/public/about");
request.setQueryString("aae${%23session[\"bar\"]}=1%24%7B%23session%5B%22bar%22%5D%7D");
session.put("bar", "rab");
tag.setAction("team");
tag.setIncludeParams("all");
tag.doStartTag();
tag.doEndTag();
Object allowMethodAccess = stack.findValue("\u0023_memberAccess['allowStaticMethodAccess']");
assertNull(allowMethodAccess);
assertNull(session.get("foo"));
assertEquals("/team.action?aaa=1%24%7B%23session%5B%22foo%22%5D%3D%27true%27%7D" +
"&amp;" +
"aab=1%24%7B%23session%5B%22bar%22%5D%7D" +
"&amp;" +
"aac=1%24%7B%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3D%27true%27%7D" +
"&amp;" +
"aad=1%24%7B%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%7D" +
"&amp;" +
"aae%24%7B%23session%5B%22bar%22%5D%7D=1%24%7B%23session%5B%22bar%22%5D%7D"
, writer.toString()
);
}
public void testIncludeEmptyParameters() throws Exception {
request.setRequestURI("/public/about");
tag.setAction("company");
tag.setEscapeAmp("false");
tag.doStartTag();
ParamTag param1 = new ParamTag();
param1.setPageContext(pageContext);
param1.setName("paramWithSetValue");
param1.setValue("");
param1.setSuppressEmptyParameters(false);
param1.doStartTag();
param1.doEndTag();
ParamTag param2 = new ParamTag();
param2.setPageContext(pageContext);
param2.setName("paramWithSetBody");
param2.setBodyContent(new MockBodyContent() {
@Override
public String getString() {
return "";
}
});
param2.setSuppressEmptyParameters(false);
param2.doStartTag();
param2.doEndTag();
ParamTag param3 = new ParamTag();
param3.setPageContext(pageContext);
param3.setName("paramWithSetValueSuppressed");
param3.setValue("");
param3.setSuppressEmptyParameters(true);
param3.doStartTag();
param3.doEndTag();
ParamTag param4 = new ParamTag();
param4.setPageContext(pageContext);
param4.setName("paramWithSetBodySuppressed");
param4.setBodyContent(new MockBodyContent() {
@Override
public String getString() {
return "";
}
});
param4.setSuppressEmptyParameters(true);
param4.doStartTag();
param4.doEndTag();
tag.doEndTag();
assertEquals("/company.action?paramWithSetValue=&paramWithSetBody=", writer.toString());
}
protected void setUp() throws Exception {
super.setUp();
request.setScheme("http");
request.setServerName("localhost");
request.setServerPort(80);
tag = new URLTag();
tag.setPageContext(pageContext);
JspWriter jspWriter = new StrutsMockJspWriter(writer);
pageContext.setJspWriter(jspWriter);
}
public static class Foo {
private String title;
public Foo() {
}
public Foo( String title ) {
this.title = title;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public String toString() {
return "Foo is: " + title;
}
}
public static class ValueHolder {
private String value;
public ValueHolder(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
}
@SuppressWarnings("unused")
public static class RedBlueActionMapper extends DefaultActionMapper {
@Override
public String getUriFromActionMapping(ActionMapping mapping) {
String baseUri = super.getUriFromActionMapping(mapping);
HttpSession session = ServletActionContext.getRequest().getSession();
if (session.getAttribute("redBlue")==null) {
// We are red
session.setAttribute("redBlue", 0);
return baseUri + "-red";
} else {
// We are blue
session.removeAttribute("redBlue");
return baseUri + "-blue";
}
}
}
}