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 2435b5a00f Take account of headers set in a previous filter
2435b5a00f is described below

commit 2435b5a00f382c8062571076bd0b929e23337a26
Author: Mark Thomas <[email protected]>
AuthorDate: Tue Nov 3 18:57:53 2026 +0000

    Take account of headers set in a previous filter
---
 .../org/apache/catalina/filters/ExpiresFilter.java | 29 ++++++++++++++++++++--
 webapps/docs/changelog.xml                         |  5 ++++
 2 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/java/org/apache/catalina/filters/ExpiresFilter.java 
b/java/org/apache/catalina/filters/ExpiresFilter.java
index 299877746d..53ad01deed 100644
--- a/java/org/apache/catalina/filters/ExpiresFilter.java
+++ b/java/org/apache/catalina/filters/ExpiresFilter.java
@@ -573,6 +573,8 @@ public class ExpiresFilter extends FilterBase {
          */
         private String cacheControlHeader;
 
+        private boolean wrappedCacheControlHeaderRead;
+
         /**
          * Value of the {@code Last-Modified} HTTP response header if it has 
been set.
          */
@@ -583,6 +585,7 @@ public class ExpiresFilter extends FilterBase {
         private PrintWriter printWriter;
 
         private final HttpServletRequest request;
+        private final HttpServletResponse response;
 
         private ServletOutputStream servletOutputStream;
 
@@ -601,6 +604,7 @@ public class ExpiresFilter extends FilterBase {
         public XHttpServletResponse(HttpServletRequest request, 
HttpServletResponse response) {
             super(response);
             this.request = request;
+            this.response = response;
         }
 
         @Override
@@ -616,8 +620,12 @@ public class ExpiresFilter extends FilterBase {
 
         @Override
         public void addHeader(String name, String value) {
+            boolean isCacheControlHeader = 
HEADER_CACHE_CONTROL.equalsIgnoreCase(name);
+            if (isCacheControlHeader) {
+                synchroniseCacheControlHeader();
+            }
             super.addHeader(name, value);
-            if (HEADER_CACHE_CONTROL.equalsIgnoreCase(name)) {
+            if (isCacheControlHeader) {
                 if (cacheControlHeader == null) {
                     cacheControlHeader = value;
                 } else {
@@ -632,6 +640,7 @@ public class ExpiresFilter extends FilterBase {
          * @return the Cache-Control header value, or {@code null} if not set
          */
         public String getCacheControlHeader() {
+            synchroniseCacheControlHeader();
             return cacheControlHeader;
         }
 
@@ -684,6 +693,7 @@ public class ExpiresFilter extends FilterBase {
             this.lastModifiedHeader = 0;
             this.lastModifiedHeaderSet = false;
             this.cacheControlHeader = null;
+            this.wrappedCacheControlHeaderRead = false;
         }
 
         @Override
@@ -700,6 +710,21 @@ public class ExpiresFilter extends FilterBase {
             super.setHeader(name, value);
             if (HEADER_CACHE_CONTROL.equalsIgnoreCase(name)) {
                 this.cacheControlHeader = value;
+                this.wrappedCacheControlHeaderRead = true;
+            }
+        }
+
+        /*
+         * Copy any existing cache control headers from the wrapped response 
to the local copy. Only do this once to
+         * avoid duplicates. Subsequent calls to this method will be NO-OPs 
unless reset() is called.
+         */
+        private void synchroniseCacheControlHeader() {
+            if (!wrappedCacheControlHeaderRead) {
+                wrappedCacheControlHeaderRead = true;
+                String originalCacheControlHeader = 
StringUtils.join(response.getHeaders(HEADER_CACHE_CONTROL));
+                if (!originalCacheControlHeader.isEmpty()) {
+                    cacheControlHeader = originalCacheControlHeader;
+                }
             }
         }
 
@@ -1590,7 +1615,7 @@ public class ExpiresFilter extends FilterBase {
 
             String cacheControlHeader = response.getCacheControlHeader();
             String newCacheControlHeader =
-                    (cacheControlHeader == null) ? maxAgeDirective : 
cacheControlHeader + ", " + maxAgeDirective;
+                    (cacheControlHeader == null) ? maxAgeDirective : 
cacheControlHeader + "," + maxAgeDirective;
             response.setHeader(HEADER_CACHE_CONTROL, newCacheControlHeader);
             response.setDateHeader(HEADER_EXPIRES, expirationDate.getTime());
         }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 3fbaa19c86..ba6585a0ec 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -321,6 +321,7 @@
         pools to share the same name. (remm)
       </fix>
       <fix>
+<<<<<<< HEAD
         Use RequestDispatcher target rather than source when looking up
         <code>security-role-ref</code>s for the current Servlet. (markt)
       </fix>
@@ -337,6 +338,10 @@
       <fix>
         Align LockoutRealm with some Realm implementations and ignore leading
         and trailing space in user names by default. (markt)
+=======
+        <code>ExpiresFilter</code> now takes account of headers set by a
+        previous filter in the filter chain. (markt)
+>>>>>>> 4908896a8e (Take account of headers set in a previous filter)
       </fix>
     </changelog>
   </subsection>


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

Reply via email to