From aa17d06e76f9a5f47e41258d2a8b91f255c4b774 Mon Sep 17 00:00:00 2001 From: James Holmes Date: Tue, 24 Jul 2007 18:15:13 +0000 Subject: [PATCH] WW-1938 Bug with multiple s:param tags inside s:url tag git-svn-id: https://svn.apache.org/repos/asf/struts/struts2/branches/STRUTS_2_0_X@559146 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/struts2/components/Component.java | 5 ++-- .../org/apache/struts2/components/URL.java | 30 ++++++++++++++----- .../org/apache/struts2/views/jsp/URLTag.java | 8 +++++ .../apache/struts2/views/util/UrlHelper.java | 10 ++++++- core/src/site/resources/tags/url.html | 8 +++++ .../apache/struts2/views/jsp/URLTagTest.java | 13 ++++++++ .../struts2/views/util/UrlHelperTest.java | 16 ++++++++++ 7 files changed, 80 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/components/Component.java b/core/src/main/java/org/apache/struts2/components/Component.java index fb0f2bd66..66769638b 100644 --- a/core/src/main/java/org/apache/struts2/components/Component.java +++ b/core/src/main/java/org/apache/struts2/components/Component.java @@ -338,12 +338,13 @@ public class Component { */ protected String determineActionURL(String action, String namespace, String method, HttpServletRequest req, HttpServletResponse res, Map parameters, String scheme, - boolean includeContext, boolean encodeResult) { + boolean includeContext, boolean encodeResult, boolean forceAddSchemeHostAndPort, + boolean escapeAmp) { String finalAction = findString(action); String finalNamespace = determineNamespace(namespace, getStack(), req); ActionMapping mapping = new ActionMapping(finalAction, finalNamespace, method, parameters); String uri = actionMapper.getUriFromActionMapping(mapping); - return UrlHelper.buildUrl(uri, req, res, parameters, scheme, includeContext, encodeResult); + return UrlHelper.buildUrl(uri, req, res, parameters, scheme, includeContext, encodeResult, forceAddSchemeHostAndPort, escapeAmp); } /** diff --git a/core/src/main/java/org/apache/struts2/components/URL.java b/core/src/main/java/org/apache/struts2/components/URL.java index 204469062..a210d3645 100644 --- a/core/src/main/java/org/apache/struts2/components/URL.java +++ b/core/src/main/java/org/apache/struts2/components/URL.java @@ -53,6 +53,12 @@ import com.opensymphony.xwork2.util.ValueStack; * additional request parameters.

* * NOTE: + *

By default request parameters will be separated using escaped ampersands (i.e., &amp;). + * This is necessary for XHTML compliance, however, when using the URL generated by this tag + * with the <s:property> tag, the escapeAmp attribute should be used to disable + * ampersand escaping.

+ * + * NOTE: *

When includeParams is 'all' or 'get', the parameter defined in param tag will take * precedence and will not be overriden if they exists in the parameter submitted. For * example, in Example 3 below, if there is a id parameter in the url where the page this @@ -68,16 +74,20 @@ import com.opensymphony.xwork2.util.ValueStack; *

* * @@ -135,6 +145,7 @@ public class URL extends Component { protected String method; protected boolean encode = true; protected boolean includeContext = true; + protected boolean escapeAmp = true; protected String portletMode; protected String windowState; protected String portletUrlType; @@ -240,7 +251,7 @@ public class URL extends Component { result = PortletUrlHelper.buildUrl(action, namespace, parameters, portletUrlType, portletMode, windowState); } else { - result = determineActionURL(action, namespace, method, req, res, parameters, scheme, includeContext, encode); + result = determineActionURL(action, namespace, method, req, res, parameters, scheme, includeContext, encode, false, escapeAmp); } } else { if(Dispatcher.getInstance().isPortletSupportActive() && PortletActionContext.isPortletRequest()) { @@ -254,7 +265,7 @@ public class URL extends Component { if (_value != null && _value.indexOf("?") > 0) { _value = _value.substring(0, _value.indexOf("?")); } - result = UrlHelper.buildUrl(_value, req, res, parameters, scheme, includeContext, encode); + result = UrlHelper.buildUrl(_value, req, res, parameters, scheme, includeContext, encode, false, escapeAmp); } } if ( anchor != null && anchor.length() > 0 ) { @@ -338,6 +349,11 @@ public class URL extends Component { this.anchor = anchor; } + @StrutsTagAttribute(description="Specifies whether to escape ampersand (&) to (&amp;) or not", type="Boolean", defaultValue="true") + public void setEscapeAmp(boolean escapeAmp) { + this.escapeAmp = escapeAmp; + } + /** * Merge request parameters into current parameters. If a parameter is diff --git a/core/src/main/java/org/apache/struts2/views/jsp/URLTag.java b/core/src/main/java/org/apache/struts2/views/jsp/URLTag.java index f8fbb5381..6ec2c338f 100644 --- a/core/src/main/java/org/apache/struts2/views/jsp/URLTag.java +++ b/core/src/main/java/org/apache/struts2/views/jsp/URLTag.java @@ -44,6 +44,7 @@ public class URLTag extends ComponentTagSupport { protected String method; protected String encode; protected String includeContext; + protected String escapeAmp; protected String portletMode; protected String windowState; protected String portletUrlType; @@ -74,6 +75,9 @@ public class URLTag extends ComponentTagSupport { if (includeContext != null) { url.setIncludeContext(Boolean.valueOf(includeContext).booleanValue()); } + if (escapeAmp != null) { + url.setEscapeAmp(Boolean.valueOf(escapeAmp).booleanValue()); + } } public void setEncode(String encode) { @@ -84,6 +88,10 @@ public class URLTag extends ComponentTagSupport { this.includeContext = includeContext; } + public void setEscapeAmp(String escapeAmp) { + this.escapeAmp = escapeAmp; + } + public void setIncludeParams(String name) { includeParams = name; } diff --git a/core/src/main/java/org/apache/struts2/views/util/UrlHelper.java b/core/src/main/java/org/apache/struts2/views/util/UrlHelper.java index a9aacd7c9..1070e98ad 100644 --- a/core/src/main/java/org/apache/struts2/views/util/UrlHelper.java +++ b/core/src/main/java/org/apache/struts2/views/util/UrlHelper.java @@ -91,6 +91,10 @@ public class UrlHelper { } public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params, String scheme, boolean includeContext, boolean encodeResult, boolean forceAddSchemeHostAndPort) { + return buildUrl(action, request, response, params, scheme, includeContext, encodeResult, forceAddSchemeHostAndPort, true); + } + + public static String buildUrl(String action, HttpServletRequest request, HttpServletResponse response, Map params, String scheme, boolean includeContext, boolean encodeResult, boolean forceAddSchemeHostAndPort, boolean escapeAmp) { StringBuffer link = new StringBuffer(); boolean changedScheme = false; @@ -169,7 +173,11 @@ public class UrlHelper { } //if the action was not explicitly set grab the params from the request - buildParametersString(params, link); + if (escapeAmp) { + buildParametersString(params, link); + } else { + buildParametersString(params, link, "&"); + } String result; diff --git a/core/src/site/resources/tags/url.html b/core/src/site/resources/tags/url.html index f26eca008..ab7fdb46f 100644 --- a/core/src/site/resources/tags/url.html +++ b/core/src/site/resources/tags/url.html @@ -51,6 +51,14 @@ Please do not edit it directly. Boolean Whether to encode parameters + + escapeAmp + false + true + true + Boolean + Specifies whether to escape ampersand (&) to (&amp;) or not + id false diff --git a/core/src/test/java/org/apache/struts2/views/jsp/URLTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/URLTagTest.java index ac7992dcd..abc0b1aa0 100644 --- a/core/src/test/java/org/apache/struts2/views/jsp/URLTagTest.java +++ b/core/src/test/java/org/apache/struts2/views/jsp/URLTagTest.java @@ -348,6 +348,19 @@ public class URLTagTest extends AbstractUITagTest { assertEquals("/team.action?section=team&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"); diff --git a/core/src/test/java/org/apache/struts2/views/util/UrlHelperTest.java b/core/src/test/java/org/apache/struts2/views/util/UrlHelperTest.java index 5d2cc5453..5062ebef3 100644 --- a/core/src/test/java/org/apache/struts2/views/util/UrlHelperTest.java +++ b/core/src/test/java/org/apache/struts2/views/util/UrlHelperTest.java @@ -144,6 +144,22 @@ public class UrlHelperTest extends StrutsTestCase { assertEquals(expectedString, urlString); } + public void testBuildUrlCorrectlyAddsDoNotEscapeAmp() { + String expectedString = "my.actionName?foo=bar&hello=world"; + Mock mockHttpServletRequest = new Mock(HttpServletRequest.class); + mockHttpServletRequest.expectAndReturn("getScheme", "http"); + Mock mockHttpServletResponse = new Mock(HttpServletResponse.class); + mockHttpServletResponse.expectAndReturn("encodeURL", expectedString, expectedString); + + String actionName = "my.actionName"; + TreeMap params = new TreeMap(); + params.put("hello", "world"); + params.put("foo", "bar"); + + String urlString = UrlHelper.buildUrl(actionName, (HttpServletRequest) mockHttpServletRequest.proxy(), (HttpServletResponse) mockHttpServletResponse.proxy(), params, null, true, true, false, false); + assertEquals(expectedString, urlString); + } + public void testBuildUrlWithStringArray() { String expectedString = "my.actionName?foo=bar&hello=earth&hello=mars"; Mock mockHttpServletRequest = new Mock(HttpServletRequest.class);