Author: markt Date: Mon Feb 1 09:20:09 2016 New Revision: 1727899 URL: http://svn.apache.org/viewvc?rev=1727899&view=rev Log: Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=58946 Ensure that the request parameter map remains immutable when processing via a RequestDispatcher.
Modified: tomcat/trunk/java/org/apache/catalina/core/ApplicationHttpRequest.java tomcat/trunk/test/org/apache/catalina/core/TestApplicationHttpRequest.java tomcat/trunk/webapps/docs/changelog.xml Modified: tomcat/trunk/java/org/apache/catalina/core/ApplicationHttpRequest.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/ApplicationHttpRequest.java?rev=1727899&r1=1727898&r2=1727899&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/core/ApplicationHttpRequest.java (original) +++ tomcat/trunk/java/org/apache/catalina/core/ApplicationHttpRequest.java Mon Feb 1 09:20:09 2016 @@ -24,7 +24,6 @@ import java.io.UnsupportedEncodingExcept import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; -import java.util.HashMap; import java.util.Map; import java.util.NoSuchElementException; @@ -40,6 +39,7 @@ import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.Manager; import org.apache.catalina.Session; +import org.apache.catalina.util.ParameterMap; import org.apache.tomcat.util.buf.B2CConverter; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.Parameters; @@ -134,7 +134,7 @@ class ApplicationHttpRequest extends Htt /** * The request parameters for this request. This is initialized from the - * wrapped request, but updates are allowed. + * wrapped request. */ protected Map<String, String[]> parameters = null; @@ -634,27 +634,6 @@ class ApplicationHttpRequest extends Htt /** - * Perform a shallow copy of the specified Map, and return the result. - * - * @param orig Origin Map to be copied - */ - Map<String, String[]> copyMap(Map<String, String[]> orig) { - - if (orig == null) { - return (new HashMap<>()); - } - HashMap<String, String[]> dest = new HashMap<>(); - - for (Map.Entry<String, String[]> entry : orig.entrySet()) { - dest.put(entry.getKey(), entry.getValue()); - } - - return (dest); - - } - - - /** * Set the context path for this request. * * @param contextPath The new context path @@ -750,9 +729,10 @@ class ApplicationHttpRequest extends Htt return; } - parameters = new HashMap<>(); - parameters = copyMap(getRequest().getParameterMap()); + parameters = new ParameterMap<>(); + parameters.putAll(getRequest().getParameterMap()); mergeParameters(); + ((ParameterMap<String,String[]>) parameters).setLocked(true); parsedParams = true; } @@ -879,8 +859,6 @@ class ApplicationHttpRequest extends Htt if ((queryParamString == null) || (queryParamString.length() < 1)) return; - HashMap<String, String[]> queryParameters = new HashMap<>(); - // Parse the query string from the dispatch target Parameters paramParser = new Parameters(); MessageBytes queryMB = MessageBytes.newInstance(); @@ -901,23 +879,18 @@ class ApplicationHttpRequest extends Htt paramParser.setQueryStringEncoding(encoding); paramParser.handleQueryParameters(); - // Copy the original parameters - queryParameters.putAll(parameters); - // Insert the additional parameters from the dispatch target Enumeration<String> dispParamNames = paramParser.getParameterNames(); while (dispParamNames.hasMoreElements()) { String dispParamName = dispParamNames.nextElement(); String[] dispParamValues = paramParser.getParameterValues(dispParamName); - String[] originalValues = queryParameters.get(dispParamName); + String[] originalValues = parameters.get(dispParamName); if (originalValues == null) { - queryParameters.put(dispParamName, dispParamValues); + parameters.put(dispParamName, dispParamValues); continue; } - queryParameters.put(dispParamName, mergeValues(dispParamValues, originalValues)); + parameters.put(dispParamName, mergeValues(dispParamValues, originalValues)); } - - parameters = queryParameters; } Modified: tomcat/trunk/test/org/apache/catalina/core/TestApplicationHttpRequest.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/core/TestApplicationHttpRequest.java?rev=1727899&r1=1727898&r2=1727899&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/catalina/core/TestApplicationHttpRequest.java (original) +++ tomcat/trunk/test/org/apache/catalina/core/TestApplicationHttpRequest.java Mon Feb 1 09:20:09 2016 @@ -33,6 +33,7 @@ import org.junit.Test; import org.apache.catalina.Context; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.TomcatBaseTest; +import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.buf.ByteChunk; public class TestApplicationHttpRequest extends TomcatBaseTest { @@ -210,6 +211,32 @@ public class TestApplicationHttpRequest } + @Test + public void testParameterImmutability() throws Exception { + Tomcat tomcat = getTomcatInstance(); + + // No file system docBase required + Context ctx = tomcat.addContext("", null); + + Tomcat.addServlet(ctx, "forward", new ForwardServlet("/modify")); + ctx.addServletMapping("/forward", "forward"); + + Tomcat.addServlet(ctx, "modify", new ModifyParameterServlet()); + ctx.addServletMapping("/modify", "modify"); + + tomcat.start(); + + ByteChunk response = new ByteChunk(); + StringBuilder target = new StringBuilder("http://localhost:"); + target.append(getPort()); + target.append("/forward"); + int rc = getUrl(target.toString(), response, null); + + Assert.assertEquals(200, rc); + Assert.assertEquals("OK", response.toString()); + } + + private static class ForwardServlet extends HttpServlet { private static final long serialVersionUID = 1L; @@ -294,4 +321,37 @@ public class TestApplicationHttpRequest } } } + + + private static class ModifyParameterServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + // Suppress warnings generated because the code is trying to put the + // wrong type of values into the Map + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + Map map = req.getParameterMap(); + + boolean insertWorks; + try { + map.put("test", new Integer[] { Integer.valueOf(0) }); + insertWorks = true; + } catch (Throwable t) { + ExceptionUtils.handleThrowable(t); + insertWorks = false; + } + + resp.setContentType("text/plain"); + resp.setCharacterEncoding("UTF-8"); + PrintWriter pw = resp.getWriter(); + if (insertWorks) { + pw.print("FAIL"); + } else { + pw.print("OK"); + } + } + } } Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1727899&r1=1727898&r2=1727899&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Mon Feb 1 09:20:09 2016 @@ -72,6 +72,10 @@ <bug>58768</bug>: Log a warning if a redirect fails because of an invalid location. (markt) </fix> + <fix> + <bug>58946</bug>: Ensure that the request parameter map remains + immutable when processing via a RequestDispatcher. (markt) + </fix> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org