Problem/Motivation
PageCache determines which responses to cache by inspecting the Expires
header. (This should be updated to use the Cache-Control
header instead, but that's out of scope here.)
Responses that have Expires: Sun, 19 Nov 1978 05:00:00 GMT
are meant to not be cached, because it's an expiration date in the past. Yet PageCache caches them permanently:
$expire = ($date > $request_time) ? $date : Cache::PERMANENT;
This has been the case for a very long time, even predating
#2527126: Only send X-Drupal-Cache-Tags and -Contexts headers when developer explicitly enables them β
. Quite possibly the rationale was .
Now, to make matters worse, even when you configure a non-zero "max age" at /admin/config/development/performance
, \Drupal\Core\EventSubscriber\FinishResponseSubscriber::setResponseCacheable()
will still cause that same Expires
header to be set? Why? Because when \Drupal\Core\EventSubscriber\FinishResponseSubscriber::onRespond()
calls \Drupal\Core\EventSubscriber\FinishResponseSubscriber::setResponseCacheable()
, the latter contains this code:
// HTTP/1.0 proxies do not support the Vary header, so prevent any caching
// by sending an Expires date in the past. HTTP/1.1 clients ignore the
// Expires header if a Cache-Control: max-age directive is specified (see
// RFC 2616, section 14.9.3).
if (!$response->headers->has('Expires')) {
$this->setExpiresNoCache($response);
}
In other words:
- Drupal 8 intentionally disables HTTP/1.0 proxies
- Drupal 8 ships with a HTTP/1.0 reverse proxy that is breaking the spec: Page Cache
Proposed resolution
Make \Drupal\page_cache\StackMiddleware\PageCache
a HTTP/1.1 proxy: make it inspect Cache-Control
rather than Expires
Remaining tasks
TBD
Remaining tasks
TBD
User interface changes
None.
API changes
None.
Data model changes
None.