HTTP Caching
Extracted elements (33)
HTTP cache requirements are deliberately focused on preventing a cache from storing a non-reusable response or reusing a stored response inappropriately, rather than mandating that caches always store and reuse particular responses, because reuse is the desired default and prohibition is the exception.
The must-understand directive was introduced (new in RFC 9111) so that caches are not required to understand all new response status codes. A response with must-understand is only cacheable by a cache that understands and implements the status code's caching requirements, removing an obstacle to deploying new status codes.
The Pragma request header field (notably 'Pragma: no-cache') is deprecated in this specification in favor of Cache-Control. Because the meaning of 'Pragma: no-cache' in responses was never specified, it cannot reliably replace 'Cache-Control: no-cache' in responses.
The Warning header field is obsoleted by RFC 9111 because it is not widely generated or surfaced to users. The information it carried can be derived from examining other fields such as Age, and remaining advisory information was not in practice added by caches or intermediaries.
A cache MUST ignore unrecognized cache directives. Extension directives are designed as modifiers paired with a base directive, so caches that do not recognize the extension fall back to the behavior of the base directive, preserving backward compatibility.
A cache MUST invalidate the target URI when it receives a non-error (2xx or 3xx) status code in response to an unsafe request method. A cache MUST NOT trigger invalidation of a URI whose origin differs from that of the target URI, to prevent denial-of-service attacks.
A cache MUST NOT generate a stale response if prohibited by an explicit in-protocol directive (no-cache, must-revalidate, s-maxage, or proxy-revalidate). A cache MUST NOT generate a stale response unless it is disconnected or the client or origin server explicitly permits it.
A cache MUST NOT reuse a stored response unless the target URI matches, the request method allows reuse, Vary-nominated header fields match, no-cache is absent or the response has been successfully validated, and the stored response is fresh, allowed to be served stale, or successfully validated.
A cache MUST NOT store a response unless: the request method is understood, the response status is final, no no-store directive is present, shared-cache restrictions on private/Authorization are satisfied, and the response contains at least one of: public/private directive, Expires, max-age, s-maxage, a permitting cache extension, or a heuristically cacheable status code.
A cache MUST NOT use heuristics to determine freshness when an explicit expiration time is present in the stored response. Heuristic expiration may only be used on responses without explicit freshness whose status codes are heuristically cacheable or that are marked explicitly cacheable (e.g., via the public directive).
A cache MUST write through requests with unsafe methods (PUT, POST, DELETE, etc.) to the origin server; a cache MUST NOT generate a reply to such a request before having forwarded the request and received a corresponding response.
A shared cache MUST NOT use a cached response to a request with an Authorization header field to satisfy a subsequent request unless the response contains a Cache-Control directive that explicitly allows shared caching: must-revalidate, public, or s-maxage.
The must-revalidate response directive requires that once stale, a cache MUST NOT reuse the response without successful origin revalidation. If disconnected, the cache MUST generate a 504 (Gateway Timeout) error rather than serve the stale response; the directive MUST NOT be ignored under any circumstances.
The no-store response directive requires that a cache MUST NOT store any part of the immediate request or response and MUST NOT use the response to satisfy any other request, applying to both private and shared caches. It is not a sufficient mechanism for ensuring privacy.
The unqualified private response directive requires that a shared cache MUST NOT store the response. The qualified form (with field-name arguments) limits only those listed header fields in shared caches, permitting the remainder of the response to be shared-cached without them.
When a cache receives a 304 (Not Modified) response, it MUST update each identified stored response's header fields with the fields provided in the 304 response. If no strong validator in the 304 matches any stored response, the cache MUST NOT use the new response to update any stored responses.
When a stored response contains a Vary header field, a cache MUST NOT reuse that response without revalidation unless all request header fields nominated by the Vary field match those of the original request. A Vary value of '*' always fails to match.
When a stored response is used to satisfy a request without validation, a cache MUST generate an Age header field with a value equal to the stored response's current_age, replacing any existing Age field in the response.
When generating a conditional validation request, a cache MUST send the relevant entity tags using If-Match, If-None-Match, or If-Range if entity tags were provided in the stored response(s) being validated, and SHOULD send Last-Modified via If-Modified-Since for single non-subrange validations.
A response's freshness is determined by response_is_fresh = (freshness_lifetime > current_age). Freshness lifetime is resolved in priority order: s-maxage (shared caches), max-age, Expires minus Date, or heuristic calculation. A stale response may still be served if the cache is disconnected or explicitly permitted.
Age is computed as current_age = corrected_initial_age + resident_time, where corrected_initial_age = max(apparent_age, age_value + response_delay). A cache MUST interpret corrected_age_value relative to the time the request was initiated, not the time the response was received, to account for transit delay.
The Age response header field conveys the sender's estimate of the number of seconds since the response was generated or validated at the origin server. Its presence implies the response was not generated directly for the current request; its absence does not imply the origin was contacted.
The Cache-Control header field lists cache directives that are unidirectional (request directives do not imply the same directive in the response). A proxy MUST pass cache directives through in forwarded messages regardless of their significance to the proxy.
The cache key is composed from at minimum the request method and target URI. Content-negotiated responses are differentiated by incorporating Vary-nominated request header fields. Caches may add additional material such as the referring site's identity ('double keying') to mitigate privacy risks.
The Expires response header field gives the HTTP-date after which the response is considered stale. When Cache-Control max-age or s-maxage is also present, recipients MUST ignore Expires, as it exists only for implementations that have not implemented Cache-Control.
The s-maxage response directive overrides both max-age and Expires for shared caches and incorporates proxy-revalidate semantics. A shared cache MUST NOT reuse a stale s-maxage response without revalidation, and it permits caching of responses to requests with an Authorization header field.
RFC 9111 updates the HTTP Field Name Registry: Age, Cache-Control, and Expires are registered as permanent; Pragma is marked deprecated; Warning is marked obsoleted. The HTTP Warn Codes registry is annotated to note that Warning has been obsoleted.
The 'Hypertext Transfer Protocol (HTTP) Cache Directive Registry' defines the namespace for cache directives. New registrations require IETF Review and must include the cache directive name and a pointer to specification text.
Cache poisoning attacks occur when an attacker inserts a malicious response into a shared cache, distributing malicious content to many clients. A common vector exploits differences in HTTP message parsing between proxies and user agents.
Sensitive information such as authentication credentials may be inadvertently cached due to misconfigured or misunderstood cache directives. The Set-Cookie header field does not inherently inhibit caching; servers must emit explicit Cache-Control directives to prevent caching of responses containing cookies.
Timing attacks exploit cache hit/miss latency differences to infer a user's browsing history. The recommended mitigation is 'double keying'—incorporating the referring site's identity into the cache key—to prevent cross-site cache probing.
Age = delta-seconds (non-negative integer, seconds). Cache-Control = #cache-directive where cache-directive = token [ "=" ( token / quoted-string ) ]. Expires = HTTP-date. These are the three primary caching header field grammars.
The delta-seconds rule is encoded as 1*DIGIT (one or more decimal digits), representing non-negative integer seconds. A recipient MUST use at least 31 bits of non-negative integer range; on overflow the value MUST be treated as 2147483648 (2^31), not as a negative number.