diff --git a/portal/web/src/main/java/org/gatein/portal/page/Decoder.java b/portal/web/src/main/java/org/gatein/portal/page/Decoder.java index 9efadf2f0..6a4cece60 100644 --- a/portal/web/src/main/java/org/gatein/portal/page/Decoder.java +++ b/portal/web/src/main/java/org/gatein/portal/page/Decoder.java @@ -18,6 +18,8 @@ */ package org.gatein.portal.page; +import juzu.impl.common.PercentCodec; + import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -157,8 +159,8 @@ private void put(String rawName, String rawValue) { if (parameters == null) { parameters = new HashMap(); } - String name = Encoder.NAME_CODEC.decode(rawName); - String value = Encoder.VALUE_CODEC.decode(rawValue); + String name = Encoder.PORTLET_RENDER_PARAM_CODEC.decode(rawName); + String value = Encoder.PORTLET_RENDER_PARAM_CODEC.decode(rawValue); String[] parameter = parameters.get(rawName); if (parameter != null) { parameter = Tools.appendTo(parameter, value); diff --git a/portal/web/src/main/java/org/gatein/portal/page/Encoder.java b/portal/web/src/main/java/org/gatein/portal/page/Encoder.java index a03cbb737..3f4072213 100644 --- a/portal/web/src/main/java/org/gatein/portal/page/Encoder.java +++ b/portal/web/src/main/java/org/gatein/portal/page/Encoder.java @@ -18,24 +18,20 @@ */ package org.gatein.portal.page; +import juzu.impl.common.PercentCodec; + import java.io.IOException; import java.lang.reflect.UndeclaredThrowableException; -import java.math.BigInteger; import java.util.Iterator; import java.util.Map; -import juzu.impl.common.PercentCodec; - /** * @author Julien Viet */ public class Encoder { /** . */ - static final PercentCodec NAME_CODEC = PercentCodec.RFC3986_QUERY_PARAM_NAME; - - /** . */ - static final PercentCodec VALUE_CODEC = PercentCodec.create( + static final PercentCodec PORTLET_RENDER_PARAM_CODEC = PercentCodec.create( PercentCodec.RFC3986_QUERY_PARAM_VALUE. clearBit(':'). clearBit(',') @@ -78,9 +74,9 @@ public void encode(Appendable appendable) throws IOException { } else { first = false; } - NAME_CODEC.encode(parameter.getKey(), appendable); + PORTLET_RENDER_PARAM_CODEC.encode(parameter.getKey(), appendable); appendable.append(':'); - VALUE_CODEC.encode(s, appendable); + PORTLET_RENDER_PARAM_CODEC.encode(s, appendable); } } } diff --git a/portal/web/src/test/java/org/gatein/portal/page/EncoderTestCase.java b/portal/web/src/test/java/org/gatein/portal/page/EncoderTestCase.java index 7105a1147..73af6ce1a 100644 --- a/portal/web/src/test/java/org/gatein/portal/page/EncoderTestCase.java +++ b/portal/web/src/test/java/org/gatein/portal/page/EncoderTestCase.java @@ -49,11 +49,17 @@ public void testPairs() { public void testEscapeKey() { Encoder encoder = new Encoder(Collections.singletonMap(" ", new String[]{"value"})); Assert.assertEquals("%20:value", encoder.encode()); + + encoder = new Encoder(Collections.singletonMap("&", new String[]{"value"})); + Assert.assertEquals("%26:value", encoder.encode()); } @Test public void testEscapeValue() { Encoder encoder = new Encoder(Collections.singletonMap("key", new String[]{" "})); Assert.assertEquals("key:%20", encoder.encode()); + + encoder = new Encoder(Collections.singletonMap("key", new String[]{"&"})); + Assert.assertEquals("key:%26", encoder.encode()); } } diff --git a/portal/web/src/test/java/org/gatein/portal/page/PortletParameterEncodingTestCase.java b/portal/web/src/test/java/org/gatein/portal/page/PortletParameterEncodingTestCase.java new file mode 100644 index 000000000..d75941ae5 --- /dev/null +++ b/portal/web/src/test/java/org/gatein/portal/page/PortletParameterEncodingTestCase.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2012 eXo Platform SAS. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.gatein.portal.page; + +import org.gatein.portal.AbstractPortalTestCase; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.drone.api.annotation.Drone; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.arquillian.test.api.ArquillianResource; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.URL; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.portlet.ActionRequest; +import javax.portlet.ActionResponse; +import javax.portlet.GenericPortlet; +import javax.portlet.PortletException; +import javax.portlet.PortletURL; +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; + +/** + * @author Trong Tran + * @version $Revision$ + */ +@RunWith(Arquillian.class) +public class PortletParameterEncodingTestCase extends AbstractPortalTestCase { + + @Deployment(testable = false) + public static WebArchive createPortal() { + WebArchive portal = AbstractPortalTestCase.createPortal(); + portal.addAsWebInfResource(new StringAsset(descriptor(Portlet1.class).exportAsString()), "portlet.xml"); + return portal; + } + + @ArquillianResource + URL deploymentURL; + + @Drone + WebDriver driver; + + static HashMap result = new HashMap(); + + @Test + public void testParameterEncoding() throws Exception { + + driver.get(deploymentURL.toString() + "page1"); + driver.findElements(By.name("_name")).get(0).sendKeys("a%a"); + driver.findElements(By.name("_value")).get(0).sendKeys("b%b"); + driver.findElements(By.tagName("button")).get(0).click(); + + String[] values = result.get("a%a"); + System.out.println(result.keySet()); + Assert.assertEquals(1, result.keySet().size()); + Assert.assertNotNull(values); + Assert.assertEquals("b%b", values[0]); + + driver.get(deploymentURL.toString() + "page1"); + driver.findElements(By.name("_name")).get(0).sendKeys("a&a"); + driver.findElements(By.name("_value")).get(0).sendKeys("b&b"); + driver.findElements(By.tagName("button")).get(0).click(); + + Assert.assertTrue(result.keySet().size() == 1); + values = result.get("a&a"); + Assert.assertNotNull(values); + Assert.assertEquals("b&b", values[0]); + + driver.findElements(By.name("_name")).get(0).sendKeys("c"); + driver.findElements(By.name("_value")).get(0).sendKeys("d"); + driver.findElements(By.tagName("button")).get(0).click(); + + Assert.assertTrue(result.keySet().size() == 2); + values = result.get("a&a"); + Assert.assertNotNull(values); + Assert.assertEquals("b&b", values[0]); + values = result.get("c"); + Assert.assertNotNull(values); + Assert.assertEquals("d", values[0]); + } + + public static class Portlet1 extends GenericPortlet { + @Override + public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException { + HashMap p = new HashMap(request.getParameterMap()); + for (Iterator i = p.keySet().iterator();i.hasNext();) { + String s = i.next(); + if (s.startsWith("_")) { + i.remove(); + } + } + + String name = request.getParameter("_name"); + String value = request.getParameter("_value"); + if (name != null && value != null) { + String[] values = p.get(name); + if (values == null) { + values = new String[] { value }; + } else { + values = Arrays.copyOf(values, values.length + 1); + values[values.length - 1] = value; + } + p.put(name, values); + } else { + throw new PortletException("Invalid request"); + } + + for (Map.Entry parameter : p.entrySet()) { + response.setRenderParameter(parameter.getKey(), parameter.getValue()); + } + } + + @Override + public void render(RenderRequest request, RenderResponse response) throws PortletException, IOException { + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + result = new HashMap(request.getParameterMap()); + + PortletURL addURL = response.createActionURL(); + addURL.setParameters(request.getPrivateParameterMap()); + out.append("
\n"); + out.append("\n"); + out.append("\n"); + out.append("\n"); + out.append("
"); + + // + out.close(); + } + } +} \ No newline at end of file