This is an automated email from the ASF dual-hosted git repository.

markt-asf pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/11.0.x by this push:
     new d57aaacb4a Improve AsyncContext.dispatch() when 
dispatchersUseEncodedPaths=false
d57aaacb4a is described below

commit d57aaacb4a80f94ac10af457176c6a8958a370db
Author: Mark Thomas <[email protected]>
AuthorDate: Thu Aug 13 10:37:18 2026 +0100

    Improve AsyncContext.dispatch() when dispatchersUseEncodedPaths=false
---
 .../apache/catalina/core/ApplicationContext.java    |  7 +++++--
 java/org/apache/catalina/core/AsyncContextImpl.java | 21 +++++++++++++++++----
 webapps/docs/changelog.xml                          | 12 ++++++++++++
 3 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/java/org/apache/catalina/core/ApplicationContext.java 
b/java/org/apache/catalina/core/ApplicationContext.java
index 28363b2e44..d499bbe0ab 100644
--- a/java/org/apache/catalina/core/ApplicationContext.java
+++ b/java/org/apache/catalina/core/ApplicationContext.java
@@ -372,8 +372,11 @@ public class ApplicationContext implements ServletContext {
         // Remove path parameters
         String uriToMap = 
org.apache.catalina.util.RequestUtil.stripPathParams(uri, null);
 
+        boolean pathIsEncoded =
+                getContext().getDispatchersUseEncodedPaths() || 
AsyncContextImpl.uriEncoded.get().booleanValue();
+
         // Decode only if the uri derived from the provided path is expected 
to be encoded
-        if (getContext().getDispatchersUseEncodedPaths()) {
+        if (pathIsEncoded) {
             uriToMap = UDecoder.URLDecode(uriToMap, StandardCharsets.UTF_8, 
context.getEncodedSolidusHandlingEnum(),
                     context.getEncodedReverseSolidusHandlingEnum());
         }
@@ -391,7 +394,7 @@ public class ApplicationContext implements ServletContext {
          * getRequestURI() which returns encoded values. getContextPath() 
returns a decoded value. uri may be encoded or
          * not. Need to prepend the context path to uri and ensure the result 
is correctly encoded.
          */
-        if (getContext().getDispatchersUseEncodedPaths()) {
+        if (pathIsEncoded) {
             uri = URLEncoder.DEFAULT.encode(getContextPath(), 
StandardCharsets.UTF_8) + uri;
         } else {
             uri = URLEncoder.DEFAULT.encode(getContextPath() + uri, 
StandardCharsets.UTF_8);
diff --git a/java/org/apache/catalina/core/AsyncContextImpl.java 
b/java/org/apache/catalina/core/AsyncContextImpl.java
index afa148e861..2e8f1ccc6a 100644
--- a/java/org/apache/catalina/core/AsyncContextImpl.java
+++ b/java/org/apache/catalina/core/AsyncContextImpl.java
@@ -128,6 +128,10 @@ public class AsyncContextImpl implements AsyncContext, 
AsyncContextCallback {
     private final AtomicBoolean hasErrorProcessingStarted = new 
AtomicBoolean(false);
     private final AtomicBoolean hasOnErrorReturned = new AtomicBoolean(false);
 
+    /*
+     * ThreadLocal for passing over-ridden URL encoding state when dispatching.
+     */
+    static ThreadLocal<Boolean> uriEncoded = ThreadLocal.withInitial(() -> 
Boolean.FALSE);
 
     /**
      * Constructs an AsyncContextImpl for the given request.
@@ -219,7 +223,6 @@ public class AsyncContextImpl implements AsyncContext, 
AsyncContextCallback {
         String path;
         String cpath;
         Request request = this.request;
-        Context context = this.context;
         // Calls check() so local copies are validated
         ServletRequest servletRequest = getRequest();
         if (servletRequest instanceof HttpServletRequest sr) {
@@ -232,10 +235,20 @@ public class AsyncContextImpl implements AsyncContext, 
AsyncContextCallback {
         if (cpath.length() > 1) {
             path = path.substring(cpath.length());
         }
-        if (!context.getDispatchersUseEncodedPaths()) {
-            path = UDecoder.URLDecode(path, StandardCharsets.UTF_8);
+        /*
+         * This is a dispatch of the original request path. That path will 
always be URI-decoded. That will cause
+         * problems in ServletContext.getRequestDispatcher() if the decoded 
URI contains a literal '?' as it will be
+         * treated as a query delimiter. Therefore, ignore 
context.getDispatchersUseEncodedPaths() here and always
+         * encode. Also need to mark this request as ignoring 
context.getDispatchersUseEncodedPaths() so it is handled
+         * correctly in ServletContext.getRequestDispatcher().
+         */
+        path = UDecoder.URLDecode(path, StandardCharsets.UTF_8);
+        try {
+            uriEncoded.set(Boolean.TRUE);
+            dispatch(path);
+        } finally {
+            uriEncoded.set(Boolean.FALSE);
         }
-        dispatch(path);
     }
 
     @Override
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index e8720d622d..841c6caf32 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -108,6 +108,18 @@
   issues do not "pop up" wrt. others).
 -->
 <section name="Tomcat 11.0.26 (markt)" rtext="in development">
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Improve the handling of <code>AsyncContext.dispatch()</code> when the
+        <code>Context</code> attribute <code>dispatchersUseEncodedPaths</code>
+        is set to <code>false</code> since the application has no control over
+        the path used for the <code>AsyncContext.dispatch()</code>. Prior to
+        this fix, paths containing literal <code>'?'</code> characters were
+        truncated. (markt)
+      </fix>
+    </changelog>
+  </subsection>
   <subsection name="Coyote">
     <changelog>
       <fix>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to