I have a situation where I have a caching Apache in front of a back end.
The backend sends a response header "Expires: -1" and mod_cache
unconditionally refuses to cache the response with the error "Broken
expires header".
RFC 7234 section 5.3 [1] contains the text:
=======================================================
...
The Expires value is an HTTP-date timestamp, as defined in Section
7.1.1.1 of [RFC7231].
Expires = HTTP-date
For example
Expires: Thu, 01 Dec 1994 16:00:00 GMT
A cache recipient MUST interpret invalid date formats, especially the
value "0", as representing a time in the past (i.e., "already expired").
...
=======================================================
Furthermore:
=======================================================
...
If a response includes a Cache-Control field with the max-age directive
(Section 5.2.2.8), a recipient MUST ignore the Expires field. Likewise,
if a response includes the s-maxage directive (Section 5.2.2.9), a
shared cache recipient MUST ignore the Expires field. In both these
cases, the value in Expires is only intended for recipients that have
not yet implemented the Cache-Control field.
...
=======================================================
I would like to make the following case a) to behave like case b):
a) expires header contains no valid date format
b) expires header contains a valid date format, but that date is in the past
This is currently not the case. Case a) never caches, case b) does not
cache by default, but caching can be forced by CacheStoreExpired in the
configuration. Also max-age and s-maxage take precendence over expires
in case b).
Code archeology of mod_cache shows:
1) originally content with expires being an HTTP-date but that date is
in the past was cached (case b) not handled RFC compliant). Content with
invalid expires wasn't cached from the beginning (that's case a)).
2) r450055 (minfrin) added a check to refuse caching in case expires was
an HTTP-date in the past (case b))
3) r1000106 (wrowe) added a config option the allow caching stale
content but applied this option only to case b), not to case a),
although the RFC says "A cache recipient MUST interpret invalid date
formats, ..., as representing a time in the past (i.e., "already
expired").".
4) r1003882 (minfrin) added more options to control more caching
behavior by configuration, for example in case b).
5) r1726675 (covener) added max-age and s-maxage checks to case b).
I guess that case a) simply wasn't on the radar when 3), 4) and 5) were
added.
I propose the following patch for trunk and 2.4. Of course in the above
case a), caching behavior will not be completely the same (additional
caching in case of broken Expires header if the config uses
CacheStoreExpired of either max-age or a-maxage was send). The condition
and comment additions was copied from the case b) "if" directly below
the changed block:
Index: modules/cache/mod_cache.c
===================================================================
--- modules/cache/mod_cache.c (revision 1833803)
+++ modules/cache/mod_cache.c (working copy)
@@ -1040,8 +1040,11 @@
if (reason) {
/* noop */
}
- else if (exps != NULL && exp == APR_DATE_BAD) {
- /* if a broken Expires header is present, don't cache it */
+ else if (!control.s_maxage && !control.max_age && !dconf->store_expired
+ && exps != NULL && exp == APR_DATE_BAD) {
+ /* if a broken Expires header is present, don't cache it
+ * Unless CC: s-maxage or max-age is present
+ */
reason = apr_pstrcat(p, "Broken expires header: ", exps, NULL);
}
else if (!control.s_maxage && !control.max_age
Thanks for any feedback!
Regards,
Rainer
[1] https://tools.ietf.org/html/rfc7234#section-5.3