On Wed, Oct 14, 2026 at 3:09 PM <[email protected]> wrote:
>
> 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.
So this looks like a "massive" initial error when this was written,
clearly the default is that async-supported is false. Maybe it was
snuck in to avoid disruption (??).
The initial code was only in ApplicationFilterChain, which did a
"false".equalsIgnoreCase(filterConfig.getFilterDef().getAsyncSupported()),
while it should instead check if it has an explicit "true" value.
Since I don't like trouble, I won't backport it.
Rémy
> 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]
>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]