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

markt 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 7538d05b36 Fix BZ 69415. ExpiresFilter is too eager to add headers
7538d05b36 is described below

commit 7538d05b36a8286846b046df4c9628b8443e9356
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Nov 1 17:15:32 2024 +0000

    Fix BZ 69415. ExpiresFilter is too eager to add headers
    
    https://bz.apache.org/bugzilla/show_bug.cgi?id=69415
    The headers should only be added to methods that support caching and
    where no-store has not been set
---
 .../org/apache/catalina/filters/ExpiresFilter.java | 22 +++++++++++++++++++---
 .../catalina/filters/LocalStrings.properties       |  4 +++-
 .../apache/catalina/filters/TestExpiresFilter.java | 18 ++++++++++++++++++
 webapps/docs/changelog.xml                         |  6 ++++++
 4 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/java/org/apache/catalina/filters/ExpiresFilter.java 
b/java/org/apache/catalina/filters/ExpiresFilter.java
index b2215cdb2e..1cb05f0d82 100644
--- a/java/org/apache/catalina/filters/ExpiresFilter.java
+++ b/java/org/apache/catalina/filters/ExpiresFilter.java
@@ -1397,9 +1397,17 @@ public class ExpiresFilter extends FilterBase {
      */
     protected boolean 
isEligibleToExpirationHeaderGeneration(HttpServletRequest request,
             XHttpServletResponse response) {
-        boolean expirationHeaderHasBeenSet =
-                response.containsHeader(HEADER_EXPIRES) || 
contains(response.getCacheControlHeader(), "max-age");
-        if (expirationHeaderHasBeenSet) {
+
+        // Don't add cache headers unless the request is a GET or a HEAD 
request
+        String method = request.getMethod();
+        if (!"GET".equals(method) && !"HEAD".equals(method)) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("expiresFilter.invalidMethod", 
request.getRequestURI(), method));
+            }
+            return false;
+        }
+
+        if (response.containsHeader(HEADER_EXPIRES) || 
contains(response.getCacheControlHeader(), "max-age")) {
             if (log.isDebugEnabled()) {
                 
log.debug(sm.getString("expiresFilter.expirationHeaderAlreadyDefined", 
request.getRequestURI(),
                         Integer.valueOf(response.getStatus()), 
response.getContentType()));
@@ -1407,6 +1415,14 @@ public class ExpiresFilter extends FilterBase {
             return false;
         }
 
+        if (contains(response.getCacheControlHeader(), "no-store")) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("expiresFilter.cacheControlNoStore", 
request.getRequestURI(),
+                        Integer.valueOf(response.getStatus()), 
response.getContentType()));
+            }
+            return false;
+        }
+
         for (int skippedStatusCode : this.excludedResponseStatusCodes) {
             if (response.getStatus() == skippedStatusCode) {
                 if (log.isDebugEnabled()) {
diff --git a/java/org/apache/catalina/filters/LocalStrings.properties 
b/java/org/apache/catalina/filters/LocalStrings.properties
index 89628aa04f..6a4f97cd5a 100644
--- a/java/org/apache/catalina/filters/LocalStrings.properties
+++ b/java/org/apache/catalina/filters/LocalStrings.properties
@@ -34,8 +34,10 @@ csrfPrevention.rejectNoCache=Rejecting request for [{0}] 
with session [{1}] due
 csrfPrevention.rejectNoNonce=Rejecting request for [{0}] with session [{1}] 
because no CSRF nonce was found
 csrfPrevention.unsupportedPattern=Unsupported pattern [{0}]
 
+expiresFilter.cacheControlNoStore=Request [{0}] with response status [{1}] 
content-type [{2}], Cache-Control: no-store header already defined
 expiresFilter.exceptionProcessingParameter=Exception processing configuration 
parameter [{0}]:[{1}]
-expiresFilter.expirationHeaderAlreadyDefined=Request [{0}] with response 
status [{1}] content-type [{2}], expiration header already defined
+expiresFilter.expirationHeaderAlreadyDefined=Request [{0}] with response 
status [{1}] content-type [{2}], Expires header already defined
+expiresFilter.invalidMethod=Request [{0}] with request method [{1}], 
non-cacheable method
 expiresFilter.filterInitialized=Filter initialized with configuration [{0}]
 expiresFilter.invalidDurationNumber=Invalid duration (number) [{0}] in 
directive [{1}]
 expiresFilter.invalidDurationUnit=Invalid duration unit 
(years|months|weeks|days|hours|minutes|seconds) [{0}] in directive [{1}]
diff --git a/test/org/apache/catalina/filters/TestExpiresFilter.java 
b/test/org/apache/catalina/filters/TestExpiresFilter.java
index 38acb2eaa2..83a82d3a6e 100644
--- a/test/org/apache/catalina/filters/TestExpiresFilter.java
+++ b/test/org/apache/catalina/filters/TestExpiresFilter.java
@@ -327,6 +327,24 @@ public class TestExpiresFilter extends TomcatBaseTest {
         validate(servlet, Integer.valueOf(1 * 60));
     }
 
+    @Test
+    public void testUseDefaultConfiguration3() throws Exception {
+        HttpServlet servlet = new HttpServlet() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void service(HttpServletRequest request, 
HttpServletResponse response)
+                    throws ServletException, IOException {
+                response.setContentType("image/jpeg");
+                response.addHeader("Cache-Control", "no-store");
+
+                response.getWriter().print("Hello world");
+            }
+        };
+
+        validate(servlet, null);
+    }
+
     @Test
     public void testUseMajorTypeExpiresConfiguration() throws Exception {
         HttpServlet servlet = new HttpServlet() {
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 8503206349..cc8494d6d5 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -223,6 +223,12 @@
         file exists and some as set as if it does not. This resulted in
         inconsistent metadata. (markt)
       </fix>
+      <fix>
+        <bug>69415</bug>: Ensure that the <code>ExpiresFilter</code> only sets
+        cache headers on <code>GET</code> and <code>HEAD</code> requests. Also
+        skip requests where the application has set <code>Cache-Control:
+        no-store</code>. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Coyote">


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to