This is an automated email from the ASF dual-hosted git repository.
markt-asf pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push:
new dee3cc39d1 Improve AsyncContext.dispatch() when
dispatchersUseEncodedPaths=false
dee3cc39d1 is described below
commit dee3cc39d1fb7887b0acded60eb68a13c57258d3
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 | 8 ++++++++
3 files changed, 30 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 9915d0b1e5..c22e1078c5 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 pathInfo;
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 (pathInfo != null && !pathInfo.isEmpty()) {
path = path + pathInfo;
}
- if (context.getDispatchersUseEncodedPaths()) {
- path = URLEncoder.DEFAULT.encode(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 = URLEncoder.DEFAULT.encode(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 a3e0eca6c3..111fb24911 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -241,6 +241,14 @@
interface must implement this method. (markt)
</fix>
<!-- Entries for backport and removal before 12.0.0-M1 below this line
-->
+ <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">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]