This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 7.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/7.0.x by this push: new 4d571d6 https://bz.apache.org/bugzilla/show_bug.cgi?id=63275 enc getContextPath 4d571d6 is described below commit 4d571d6897131f533a3e3ac41ccaebcde3768720 Author: Mark Thomas <ma...@apache.org> AuthorDate: Thu Mar 21 14:46:14 2019 +0000 https://bz.apache.org/bugzilla/show_bug.cgi?id=63275 enc getContextPath When using a RequestDispatcher ensure that HttpServletRequest.getContextPath() returns an encoded path in the dispatched request. --- .../catalina/core/ApplicationDispatcher.java | 71 +++++++++++----------- ...TestApplicationContextGetRequestDispatcher.java | 14 ++++- webapps/docs/changelog.xml | 5 ++ 3 files changed, 51 insertions(+), 39 deletions(-) diff --git a/java/org/apache/catalina/core/ApplicationDispatcher.java b/java/org/apache/catalina/core/ApplicationDispatcher.java index 49acfd6..8e2bfac 100644 --- a/java/org/apache/catalina/core/ApplicationDispatcher.java +++ b/java/org/apache/catalina/core/ApplicationDispatcher.java @@ -5,9 +5,9 @@ * 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. @@ -70,7 +70,7 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher static { STRICT_SERVLET_COMPLIANCE = Globals.STRICT_SERVLET_COMPLIANCE; - + String wrapSameObject = System.getProperty( "org.apache.catalina.core.ApplicationDispatcher.WRAP_SAME_OBJECT"); if (wrapSameObject == null) { @@ -156,7 +156,7 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher * The outermost response that will be passed on to the invoked servlet. */ ServletResponse outerResponse = null; - + /** * The request wrapper we have created and installed (if any). */ @@ -167,7 +167,7 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher * The response wrapper we have created and installed (if any). */ ServletResponse wrapResponse = null; - + /** * Are we performing an include() instead of a forward()? */ @@ -341,7 +341,7 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher private void doForward(ServletRequest request, ServletResponse response) throws ServletException, IOException { - + // Reset any output that has been buffered, but keep headers/cookies if (response.isCommitted()) { throw new IllegalStateException @@ -382,7 +382,6 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher ApplicationHttpRequest wrequest = (ApplicationHttpRequest) wrapRequest(state); - String contextPath = context.getPath(); HttpServletRequest hrequest = state.hrequest; if (hrequest.getAttribute( RequestDispatcher.FORWARD_REQUEST_URI) == null) { @@ -397,8 +396,8 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher wrequest.setAttribute(RequestDispatcher.FORWARD_QUERY_STRING, hrequest.getQueryString()); } - - wrequest.setContextPath(contextPath); + + wrequest.setContextPath(context.getEncodedPath()); wrequest.setRequestURI(requestURI); wrequest.setServletPath(servletPath); wrequest.setPathInfo(pathInfo); @@ -424,9 +423,9 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher ((ResponseFacade) response).finish(); } else { // Servlet SRV.6.2.2. The Request/Response may have been wrapped - // and may no longer be instance of RequestFacade + // and may no longer be instance of RequestFacade if (wrapper.getLogger().isDebugEnabled()){ - wrapper.getLogger().debug( " The Response is vehiculed using a wrapper: " + wrapper.getLogger().debug( " The Response is vehiculed using a wrapper: " + response.getClass().getName() ); } @@ -450,7 +449,7 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher } - + /** * Prepare the request based on the filter configuration. * @param request The servlet request we are processing @@ -460,15 +459,15 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ - private void processRequest(ServletRequest request, + private void processRequest(ServletRequest request, ServletResponse response, State state) throws IOException, ServletException { - + DispatcherType disInt = (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR); if (disInt != null) { boolean doInvoke = true; - + if (context.getFireRequestListenersOnForwards() && !context.fireRequestInitEvent(request)) { doInvoke = false; @@ -486,15 +485,15 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher } else { invoke(state.outerRequest, response, state); } - + if (context.getFireRequestListenersOnForwards()) { context.fireRequestDestroyEvent(request); } } } } - - + + /** * Combine the servletPath and the pathInfo. If pathInfo is * <code>null</code> it is ignored. If servletPath is <code>null</code> then @@ -553,7 +552,7 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher // Check SRV.8.2 / SRV.14.2.5.1 compliance checkSameObjects(request, response); } - + // Create a wrapped response to use for this request wrapResponse(state); @@ -595,7 +594,7 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher queryString); wrequest.setQueryParams(queryString); } - + wrequest.setAttribute(Globals.DISPATCHER_TYPE_ATTR, DispatcherType.INCLUDE); wrequest.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, @@ -642,7 +641,7 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher wrequest.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR, getCombinedPath()); - wrequest.setContextPath(context.getPath()); + wrequest.setContextPath(context.getEncodedPath()); wrequest.setRequestURI(requestURI); wrequest.setServletPath(servletPath); wrequest.setPathInfo(pathInfo); @@ -699,7 +698,7 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher // Check for the servlet being marked unavailable if (wrapper.isUnavailable()) { wrapper.getLogger().warn( - sm.getString("applicationDispatcher.isUnavailable", + sm.getString("applicationDispatcher.isUnavailable", wrapper.getName())); long available = wrapper.getAvailable(); if ((available > 0L) && (available < Long.MAX_VALUE)) @@ -728,12 +727,12 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher wrapper.getName()), e); servlet = null; } - + // Get the FilterChain Here ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance(); ApplicationFilterChain filterChain = factory.createFilterChain(request, wrapper,servlet); - + // Call the service() method for the allocated servlet instance try { support.fireInstanceEvent(InstanceEvent.BEFORE_DISPATCH_EVENT, @@ -811,14 +810,14 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher // Reset the old context class loader if (oldCCL != null) Thread.currentThread().setContextClassLoader(oldCCL); - + // Unwrap request/response if needed // See Bugzilla 30949 unwrapRequest(state); unwrapResponse(state); // Recycle request if necessary (also BZ 30949) recycleRequestWrapper(state); - + // Rethrow an exception if one was thrown by the invoked servlet if (ioException != null) throw ioException; @@ -871,7 +870,7 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher } } - + /** * Unwrap the response if we have wrapped it. */ @@ -948,7 +947,7 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher if ((state.outerRequest instanceof ApplicationHttpRequest) || (state.outerRequest instanceof Request) || (state.outerRequest instanceof HttpServletRequest)) { - HttpServletRequest houterRequest = + HttpServletRequest houterRequest = (HttpServletRequest) state.outerRequest; Object contextPath = houterRequest.getAttribute( RequestDispatcher.INCLUDE_CONTEXT_PATH); @@ -1023,15 +1022,15 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher ApplicationFilterChain.getLastServicedRequest(); ServletResponse originalResponse = ApplicationFilterChain.getLastServicedResponse(); - - // Some forwards, eg from valves will not set original values + + // Some forwards, eg from valves will not set original values if (originalRequest == null || originalResponse == null) { return; } - + boolean same = false; ServletRequest dispatchedRequest = appRequest; - + //find the request that was passed into the service method while (originalRequest instanceof ServletRequestWrapper && ((ServletRequestWrapper) originalRequest).getRequest()!=null ) { @@ -1054,13 +1053,13 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher throw new ServletException(sm.getString( "applicationDispatcher.specViolation.request")); } - + same = false; ServletResponse dispatchedResponse = appResponse; - + //find the response that was passed into the service method while (originalResponse instanceof ServletResponseWrapper && - ((ServletResponseWrapper) originalResponse).getResponse() != + ((ServletResponseWrapper) originalResponse).getResponse() != null ) { originalResponse = ((ServletResponseWrapper) originalResponse).getResponse(); @@ -1070,7 +1069,7 @@ final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher if (originalResponse.equals(dispatchedResponse)) { same = true; } - + if (!same && dispatchedResponse instanceof ServletResponseWrapper) { dispatchedResponse = ((ServletResponseWrapper) dispatchedResponse).getResponse(); diff --git a/test/org/apache/catalina/core/TestApplicationContextGetRequestDispatcher.java b/test/org/apache/catalina/core/TestApplicationContextGetRequestDispatcher.java index b2177f4..c2be051 100644 --- a/test/org/apache/catalina/core/TestApplicationContextGetRequestDispatcher.java +++ b/test/org/apache/catalina/core/TestApplicationContextGetRequestDispatcher.java @@ -372,8 +372,11 @@ public class TestApplicationContextGetRequestDispatcher extends TomcatBaseTest { // Setup Tomcat instance Tomcat tomcat = getTomcatInstance(); + // Need to make sure we use UTF-8 for the URI + tomcat.getConnector().setURIEncoding("UTF-8"); + // No file system docBase required - Context ctx = tomcat.addContext("/test", null); + Context ctx = tomcat.addContext("/test\u6771\u4eac", null); ctx.setDispatchersUseEncodedPaths(useEncodedDispatchPaths); // Add a default servlet to return 404 for not found resources @@ -399,7 +402,7 @@ public class TestApplicationContextGetRequestDispatcher extends TomcatBaseTest { StringBuilder url = new StringBuilder("http://localhost:"); url.append(getPort()); - url.append("/test"); + url.append("/test%E6%9D%B1%E4%BA%AC"); url.append(startPath); if (startQueryString != null) { url.append('?'); @@ -466,7 +469,12 @@ public class TestApplicationContextGetRequestDispatcher extends TomcatBaseTest { throws ServletException, IOException { resp.setContentType("text/plain"); resp.setCharacterEncoding("UTF-8"); - resp.getWriter().print(OK); + String contextPath = req.getContextPath(); + if ("/test%E6%9D%B1%E4%BA%AC".equals(contextPath)) { + resp.getWriter().print(OK); + } else { + resp.getWriter().print("FAIL - ContextPath"); + } String qs = req.getQueryString(); if (qs != null) { resp.getWriter().print(qs); diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 387c850..79d78b3 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -115,6 +115,11 @@ Ensure that the JarScanner correctly tests whether JARs found on the class path should be skipped when running on Java 9 or later. (markt) </fix> + <fix> + <bug>63275</bug>: When using a <code>RequestDispatcher</code> ensure + that <code>HttpServletRequest.getContextPath()</code> returns an encoded + path in the dispatched request. (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