This is an automated email from the ASF dual-hosted git repository.
markt-asf pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/10.1.x by this push:
new f89df03ebd Back-port new test cases and fix exposed edge case
f89df03ebd is described below
commit f89df03ebd0ecc1d92e5855431d1d7d33e79877f
Author: Mark Thomas <[email protected]>
AuthorDate: Tue Nov 3 16:15:12 2026 +0000
Back-port new test cases and fix exposed edge case
Also rename new utility method
---
java/org/apache/catalina/connector/Request.java | 2 +-
.../org/apache/catalina/core/AsyncContextImpl.java | 9 +++
java/org/apache/catalina/util/RequestUtil.java | 2 +-
.../apache/catalina/core/TestAsyncContextImpl.java | 71 ++++++++++++++++++++++
4 files changed, 82 insertions(+), 2 deletions(-)
diff --git a/java/org/apache/catalina/connector/Request.java
b/java/org/apache/catalina/connector/Request.java
index 49b8fff637..1e9e2cd8e3 100644
--- a/java/org/apache/catalina/connector/Request.java
+++ b/java/org/apache/catalina/connector/Request.java
@@ -2089,7 +2089,7 @@ public class Request implements HttpServletRequest {
@Override
public String getContextPath() {
- return RequestUtil.getContextPathUndecoded(this);
+ return RequestUtil.getContextPathEncoded(this);
}
diff --git a/java/org/apache/catalina/core/AsyncContextImpl.java
b/java/org/apache/catalina/core/AsyncContextImpl.java
index 6494c26ea2..cbe75e49d3 100644
--- a/java/org/apache/catalina/core/AsyncContextImpl.java
+++ b/java/org/apache/catalina/core/AsyncContextImpl.java
@@ -231,6 +231,15 @@ public class AsyncContextImpl implements AsyncContext,
AsyncContextCallback {
path = request.getRequestURI();
cpath = request.getContextPath();
}
+ int pos = 0;
+ if (!context.getAllowMultipleLeadingForwardSlashInPath()) {
+ do {
+ pos++;
+ } while (pos < path.length() && path.charAt(pos) == '/');
+ pos--;
+ path = path.substring(pos);
+
+ }
if (cpath.length() > 1) {
path = path.substring(cpath.length());
}
diff --git a/java/org/apache/catalina/util/RequestUtil.java
b/java/org/apache/catalina/util/RequestUtil.java
index 332e93afce..b59638f67a 100644
--- a/java/org/apache/catalina/util/RequestUtil.java
+++ b/java/org/apache/catalina/util/RequestUtil.java
@@ -208,7 +208,7 @@ public final class RequestUtil {
}
- public static String getContextPathUndecoded(Request request) {
+ public static String getContextPathEncoded(Request request) {
int lastSlash = request.getMappingData().contextSlashCount;
// Special case handling for the root context
diff --git a/test/org/apache/catalina/core/TestAsyncContextImpl.java
b/test/org/apache/catalina/core/TestAsyncContextImpl.java
index dd0ade360b..547427a1b6 100644
--- a/test/org/apache/catalina/core/TestAsyncContextImpl.java
+++ b/test/org/apache/catalina/core/TestAsyncContextImpl.java
@@ -66,11 +66,13 @@ import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
import org.apache.catalina.valves.TesterAccessLogValve;
import org.apache.catalina.valves.ValveBase;
+import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.unittest.TesterContext;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.EncodedSolidusHandling;
import org.apache.tomcat.util.collections.CaseInsensitiveKeyMap;
import org.apache.tomcat.util.descriptor.web.ErrorPage;
+import org.apache.tomcat.util.scan.StandardJarScanner;
import org.easymock.EasyMock;
public class TestAsyncContextImpl extends TomcatBaseTest {
@@ -2521,6 +2523,73 @@ public class TestAsyncContextImpl extends TomcatBaseTest
{
}
+ /*
+ * A %3b in the request URI is an encoded semi-colon that is part of the
path, not a path parameter delimiter. After
+ * AsyncContext.dispatch() the servlet should see exactly the same path
info as it saw for the original request.
+ */
+ @Test
+ public void testAsyncDispatchEncodedSemicolon() throws Exception {
+ Tomcat tomcat = getTomcatInstance();
+ Context context = tomcat.addContext("/test", null);
+ // Disable class path scanning - it slows the tests down by almost an
order of magnitude
+ ((StandardJarScanner) context.getJarScanner()).setScanClassPath(false);
+
+ Wrapper w = Tomcat.addServlet(context, "semicolon", new
AsyncDispatchPathInfoServlet());
+ w.setAsyncSupported(true);
+ context.addServletMapping("/semicolon/*", "semicolon");
+ tomcat.start();
+
+ ByteChunk responseBody = new ByteChunk();
+ int rc = getUrl("http://localhost:" + getPort() +
"/a/b/../../test/semicolon/foo%3bbar", responseBody, null);
+
+ Assert.assertEquals(200, rc);
+ // Same pathInfo before and after the dispatch
+ Assert.assertEquals("/foo;bar|/foo;bar", responseBody.toString());
+ }
+
+
+ /*
+ * Multiple leading slashes in the request URI must not break
AsyncContext.dispatch(). The servlet should see
+ * exactly the same path info before and after the dispatch.
+ */
+ @Test
+ public void testAsyncDispatchMultipleLeadingSlashes() throws Exception {
+ Tomcat tomcat = getTomcatInstance();
+ Context context = tomcat.addContext("/test", null);
+ // Disable class path scanning - it slows the tests down by almost an
order of magnitude
+ ((StandardJarScanner) context.getJarScanner()).setScanClassPath(false);
+
+ Wrapper w = Tomcat.addServlet(context, "slashes", new
AsyncDispatchPathInfoServlet());
+ w.setAsyncSupported(true);
+ context.addServletMapping("/slashes/*", "slashes");
+ tomcat.start();
+
+ ByteChunk responseBody = new ByteChunk();
+ int rc = getUrl("http://localhost:" + getPort() +
"//test/slashes/foo", responseBody, null);
+
+ Assert.assertEquals(200, rc);
+ Assert.assertEquals("/foo|/foo", responseBody.toString());
+ }
+
+
+ private static class AsyncDispatchPathInfoServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
+ if (req.getAttribute("first") == null) {
+ req.setAttribute("first", req.getPathInfo());
+ AsyncContext ac = req.startAsync();
+ ac.dispatch();
+ } else {
+ resp.setContentType("text/plain");
+ resp.getWriter().print(req.getAttribute("first") + "|" +
req.getPathInfo());
+ }
+ }
+ }
+
+
private static class AsyncDispatchUrlWithSpacesServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
@@ -2666,6 +2735,8 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
private void doTestAsyncIoEnd(boolean useThread, boolean useComplete)
throws Exception {
+ // Make sure the logger exists before setting the level
+ LogFactory.getLog("org.apache.coyote");
LogManager.getLogManager().getLogger("org.apache.coyote").setLevel(Level.ALL);
try {
Tomcat tomcat = getTomcatInstance();
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]