In short. Drupal clears ETag, Last-Modified and Vary when it applies its uncacheable response policy.
Definition: An HTTP validator is response metadata that can be used in a precondition to make a conditional request. Drupal removes
ETag,Last-Modified, andVarywhen its response subscriber applies the uncacheable response path, because the path is intended to prevent cache reuse without the response being validated.
Key facts
- Drupal's
FinishResponseSubscribertreats a response as uncacheable when its cacheability policy or page cache configuration fails the cacheable branch, then callssetResponseNotCacheable. The Drupal implementation contains that decision. - That method sets
Cache-Control: no-cache, must-revalidate, sets anExpiresvalue in the past, and removesETag,Last-Modified, andVary. - HTTP defines
Last-Modifiedas the time at which the origin believes the selected representation was last modified, whileETagis an opaque validator for distinguishing representations of one resource. RFC 9110 defines both fields. Varyrecords request fields that may have influenced representation selection. RFC 9111 requires a cache to compare those fields before using a stored response without revalidation.- The
no-cachedirective requires validation before a stored response is used for another request. It does not carry the storage prohibition expressed byno-store.
When does Drupal remove the headers?
The subscriber's onRespond method returns for a subrequest. For a main request, a response implementing CacheableResponseInterface enters the cacheability decision. Drupal combines a request policy result of ALLOW with a response policy result other than DENY, and then requires a positive cache.page.max_age configuration value for the cacheable branch.
When either policy rejects caching or the configured page max age does not permit the cacheable branch, Drupal calls setResponseNotCacheable. A response that does not implement CacheableResponseInterface also reaches that method when Drupal finds no customized Cache-Control header. A customized header changes that path, so the method is not an unconditional cleanup of every response.
What does the uncacheable method change?
The implementation performs these operations together:
$this->setCacheControlNoCache($response);
$this->setExpiresNoCache($response);
$response->setEtag(NULL);
$response->setLastModified(NULL);
$response->headers->remove('Vary');
The helper writes Cache-Control: no-cache, must-revalidate. The expiration helper uses a date in the past. Clearing the two validators removes the metadata that a cache could copy into If-None-Match or If-Modified-Since for validation. Removing Vary also removes the request-field information that would otherwise participate in selecting a stored representation.
The same source shows the inverse behavior in the cacheable branch. Drupal writes a public max-age directive, creates Last-Modified when the response has none, derives an ETag from the request timestamp, and can add Vary: Cookie when no Vary value exists and omit_vary_cookie is false. The paired branches explain why header removal belongs to the uncacheable decision rather than to response generation in general.
How do HTTP validators and Vary relate to caching?
RFC 9110 describes Last-Modified as a timestamp for the selected representation and ETag as an opaque entity tag for differentiating representations. RFC 9111 describes those values as validator metadata: a cache can place the timestamp in If-Modified-Since or the entity tag in If-None-Match when it validates a stored response.
Vary serves a different part of the cache process. It describes request-message fields that may have influenced the origin's selection of the response. A cache that has a stored response with Vary must compare the nominated fields with the original request before using that response without revalidation. Once Drupal's method marks the response uncacheable and removes the response's cache revalidation metadata, it also removes this cache-selection metadata.
The wire semantics remain precise. RFC 9111 says an unqualified no-cache response must be forwarded for validation before it satisfies another request. The no-store directive says a cache must not store any part of the response. Drupal's method uses no-cache, must-revalidate, so its header behavior expresses mandatory validation before reuse, while the source comment explains the decision as denying caching for that response.
Related terms
- Conditional HTTP requests
- Cache-Control
- HTTP status codes
- Where does Drupal's Content-Language response header come from?
FAQ
Does removing ETag mean that the representation changed?
No. The method removes the validator because Drupal has selected its uncacheable response path. The source does not compare the representation before clearing the header.
Does removing Vary mean that content selection ignored request headers?
No. Vary describes request fields that may have influenced selection. Drupal removes it as part of the same response policy decision that removes the cache validators.
Does Cache-Control: no-cache mean that no cache can store the response?
No. RFC 9111 assigns no-cache a validation-before-use meaning. no-store carries the rule that a cache must not store the response.
When does Drupal add the validators instead?
In the cacheable branch, Drupal ensures that Last-Modified and ETag exist for HTTP cache revalidation. It may also add Vary: Cookie when the response has no Vary value and the omit_vary_cookie setting is false.
Sources
- Drupal, "FinishResponseSubscriber.php", undated
- IETF, "HTTP Semantics", June 2022
- IETF, "HTTP Caching", June 2022
Check how a page reads to answer engines. Open the GEO score analyzer