Bug 65285

Summary: mod_expires adds extra Cache-Control header
Product: Apache httpd-2 Reporter: jaroslav
Component: mod_expiresAssignee: Apache HTTPD Bugs Mailing List <bugs>
Status: NEW ---    
Severity: minor    
Priority: P2    
Version: 2.4.46   
Target Milestone: ---   
Hardware: PC   
OS: Linux   

Description jaroslav 2021-05-03 14:41:41 UTC
One of our clients encountered this behaviour when setting Cache-Control in his PHP script:

<?php
header("Content-Type: text/html; charset=utf-8");
header("Cache-Control: max-age=30, must-revalidate", false);

However, server is set to have default expiration of 2 hours for text/html documents:

ExpiresActive On
ExpiresByType text/html "access plus 120 minutes"

This results in these response headers:

  Cache-Control: max-age=30, must-revalidate
  Cache-Control: max-age=7200
  Expires: Mon, 03 May 2021 16:18:24 GMT

This is sort of in accordance with documentation at https://httpd.apache.org/docs/2.4/mod/mod_expires.html which states "When the Expires header is already part of the response generated by the server, for example when generated by a CGI script or proxied from an origin server, this module does not change or add an Expires or Cache-Control header." Indeed, there is no Expires header in response generated by CGI script, but there is a Cache-Control header which gets duplicated (with different value) by mod_expires.

I believe such a behaviour is a bug - server should not add its own Cache-Control header if one is already provided by the application. I understand that can result in final response with different expiration times in Expires (added by mod_expires) and Cache-Control max-age (added by the application), but according to RFC 7234 (section 5.3, https://tools.ietf.org/html/rfc7234#section-5.3 ) this should not pose s problem as Cache-Control takes precedence.

Obviously, workaround exists in the form of

header("Expires: date")

Tested with Apache 2.4.38 from Debian Buster and Apache 2.4.46 from Debian Bullseye.