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

rmaucher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 5f6da06c35a9bdfb296e107d3cd689bc2d16b560
Author: opencode <[email protected]>
AuthorDate: Wed Oct 14 14:13:53 2026 +0200

    Default filters to async unsupported unless set to true
    
    FilterDef.asyncSupportedBoolean defaulted to true and any value
    other than "false"/"no" was parsed as true. The Servlet specification
    defaults filters to not supporting async processing.
    
    The web.xml path masked the incorrect default because ContextConfig
    normalises a missing async-supported element to "false", but filters
    registered dynamically through ServletContext.addFilter() that never
    called Dynamic.setAsyncSupported(true) were treated as async supported,
    so ApplicationFilterChain applied them to ASYNC and ERROR dispatches
    contrary to the specification.
    
    The boolean field could also disagree with the stored string: values
    such as "yes" or "1" returned true from getAsyncSupportedBoolean() but
    false from the getAsyncSupported().equals("true") checks used elsewhere,
    so the same filter was inconsistently treated as async supported and
    async unsupported.
    
    asyncSupportedBoolean now defaults to false and the setter derives it
    with "true".equalsIgnoreCase(), consistent with ServletDef and the
    Boolean parsing used by the other descriptor setters. The string value
    is stored unchanged so a storeconfig round-trip preserves the original
    descriptor value.
    
    This is a user-visible behaviour change: dynamically registered filters
    now require an explicit setAsyncSupported(true) to receive async and
    error dispatches. Annotation-defined filters and the shipped filter
    definitions are unaffected. Adds tests for the default and the full
    setter matrix, plus a changelog entry.
---
 .../tomcat/util/descriptor/web/FilterDef.java      |  8 +++--
 .../tomcat/util/descriptor/web/TestFilterDef.java  | 40 +++++++++++++++++++++-
 webapps/docs/changelog.xml                         | 10 ++++++
 3 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/java/org/apache/tomcat/util/descriptor/web/FilterDef.java 
b/java/org/apache/tomcat/util/descriptor/web/FilterDef.java
index 01e6af030a..4e7f028215 100644
--- a/java/org/apache/tomcat/util/descriptor/web/FilterDef.java
+++ b/java/org/apache/tomcat/util/descriptor/web/FilterDef.java
@@ -247,19 +247,21 @@ public class FilterDef implements Serializable {
     }
 
     /**
-     * Sets the async-supported setting for this filter.
+     * Sets the async-supported setting for this filter. Only the value
+     * <code>"true"</code> enables async support; anything else, including
+     * <code>null</code>, leaves the specification default of no async support.
      *
      * @param asyncSupported The async-supported value
      */
     public void setAsyncSupported(String asyncSupported) {
         this.asyncSupported = asyncSupported;
-        asyncSupportedBoolean = !("false".equalsIgnoreCase(asyncSupported));
+        asyncSupportedBoolean = "true".equalsIgnoreCase(asyncSupported);
     }
 
     /**
      * The async-supported boolean setting for this filter.
      */
-    private boolean asyncSupportedBoolean = true;
+    private boolean asyncSupportedBoolean = false;
 
     /**
      * Returns whether async processing is supported for this filter.
diff --git a/test/org/apache/tomcat/util/descriptor/web/TestFilterDef.java 
b/test/org/apache/tomcat/util/descriptor/web/TestFilterDef.java
index 0f4b6cdecf..810e8de837 100644
--- a/test/org/apache/tomcat/util/descriptor/web/TestFilterDef.java
+++ b/test/org/apache/tomcat/util/descriptor/web/TestFilterDef.java
@@ -42,4 +42,42 @@ public class TestFilterDef {
                 "test", filterDef.getFilterName());
     }
 
-}
\ No newline at end of file
+    @Test
+    public void testAsyncSupportedDefaultsToFalse() {
+        // The specification default is that a filter does not support async
+        // processing and every other async-supported default in the container
+        // is false. This matters in particular for filters registered
+        // dynamically via ServletContext.addFilter() which do not pass through
+        // the ContextConfig normalisation of the descriptor value.
+        FilterDef filterDef = new FilterDef();
+        Assert.assertNull(filterDef.getAsyncSupported());
+        Assert.assertFalse(filterDef.getAsyncSupportedBoolean());
+    }
+
+    @Test
+    public void testSetAsyncSupported() {
+        FilterDef filterDef = new FilterDef();
+
+        filterDef.setAsyncSupported("true");
+        Assert.assertTrue(filterDef.getAsyncSupportedBoolean());
+
+        filterDef.setAsyncSupported("TRUE");
+        Assert.assertTrue(filterDef.getAsyncSupportedBoolean());
+
+        filterDef.setAsyncSupported("false");
+        Assert.assertFalse(filterDef.getAsyncSupportedBoolean());
+
+        // Only "true" enables async support. Anything else, including null
+        // and invalid values such as "yes", is not supported which matches
+        // the handling by ServletDef and by Boolean. The string value is
+        // stored as-is since WebXml.mergeFilter() and the ContextConfig
+        // normalisation of the descriptor value operate on it.
+        filterDef.setAsyncSupported("yes");
+        Assert.assertEquals("yes", filterDef.getAsyncSupported());
+        Assert.assertFalse(filterDef.getAsyncSupportedBoolean());
+
+        filterDef.setAsyncSupported(null);
+        Assert.assertFalse(filterDef.getAsyncSupportedBoolean());
+    }
+
+}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index d402a2858f..664c31e0a1 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -121,6 +121,16 @@
   </subsection>
   <subsection name="Catalina">
     <changelog>
+      <fix>
+        Treat a filter as not supporting asynchronous processing unless
+        async supported is explicitly set to <code>"true"</code>.
+        Previously, a filter registered via
+        <code>ServletContext.addFilter()</code> that did not call
+        <code>setAsyncSupported(true)</code> was incorrectly treated as
+        async supported, and descriptor values such as <code>"yes"</code>
+        were treated as <code>true</code> for some uses and
+        <code>false</code> for others. (remm)
+      </fix>
       <fix>
         Lower the log level to debug when OpenSSL initialization fails in
         <code>OpenSSLLifecycleListener</code> to avoid stack traces


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

Reply via email to