https://bz.apache.org/bugzilla/show_bug.cgi?id=63909

            Bug ID: 63909
           Summary: ExpiresFilter not account for 304 when content-type is
                    null
           Product: Tomcat 8
           Version: 8.5.x-trunk
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: Catalina
          Assignee: dev@tomcat.apache.org
          Reporter: some.java....@gmail.com
  Target Milestone: ----

Firstly, I apologize as I am quite new to contributing so I hope I am pursuing
the correct path.  I have struggled mightily recently trying to track down why
our caching configuration was not really working with tomcat 8.5.x and we
finally found the nugget in the ExpiresFilter.  Here is our ExpiresFilter
configuration snippet.

<filter>
  <filter-name>ExpiresFilter</filter-name>
  <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class>
  <init-param>
    <param-name>ExpiresByType image/gif</param-name>
    <param-value>access plus 6 hours</param-value>
  </init-param>
  <init-param>
    <param-name>ExpiresByType text/css</param-name>
    <param-value>access plus 6 hours</param-value>
  </init-param>
  <init-param>
    <param-name>ExpiresByType application/javascript</param-name>
    <param-value>access plus 6 hours</param-value>
  </init-param>
  <init-param>
    <param-name>ExpiresExcludedResponseStatusCodes</param-name>
    <param-value>302, 500, 503</param-value>
  </init-param>
</filter>

<filter-mapping>
  <filter-name>CustomExpiresFilter</filter-name>
  <url-pattern>/*</url-pattern>
  <dispatcher>REQUEST</dispatcher>
</filter-mapping>

The ExpiresFilter according to the documentation can be configured to expire
content by type or with a default or with both.  However, there is a hole in
the current logic of the getExpirationDate(XHttpServletResponse response)
method if the filter is not configured with a default.  When the response
status is 304 (which in our case not excluded - see config above) the
content-type is null in the first lines of the getExpirationDate method. The
ExpiresFilter is unable to set the appropriate cache-control and expires
headers because the content-type is not present.

The net effect is that once the content has expired with the ExpiresFilter
configuration settings above, the cache-control and expires headers cannot be
set by the ExpiresFilter and a slew of incoming browser requests for the same
static content are met with repeated 304s.  Essentially, using only
ExpiresByType in ExpiresFilter results in successful caching, but only until
the content expires, at which point, the wave of 304s begin.  I don't think
this was the intended effect.

One could argue that, even when a 304 is returned, one can still set the
cache-control and expires headers appropriately and extend the cache lifetime
thus reducing load as intended.  One way to do this is to add logic to the
ExpiresFilter to use the request URI and request file metadata to determine
what the content type would have been in this scenario - another might be an in
memory collection of URIs to content type for lookup.  I am sure there are
others but not knowing the source code surrounding this in depth, I cannot say
what would be best.

In our research several people have solved this issue by changing or entirely
removing other headers like the ETag header and the Last-Modified and that does
not seem correct.  I think it is perfectly valid to have ETag with a 304 and
cache-control and expires headers and maybe even more elegant and appropriate?

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to