4. Constructing Responses from Caches
When presented with a request, a cache MUST NOT reuse a stored response unless all of the following conditions are met:
-
The presented target URI (see Section 7.1 of [HTTP]) matches the target URI of the stored response, and
-
The request method associated with the stored response allows it to be used for the presented request, and
-
The request header fields specified by the stored response (if any) match those of the presented request (see Section 4.1), and
-
The stored response does not contain a no-cache directive (Section 5.2.2.4), unless it has been successfully validated (Section 4.3), and
-
The stored response is one of the following:
-
Fresh (see Section 4.2), or
-
Allowed to be served stale (see Section 4.2.4), or
-
Successfully validated (see Section 4.3).
-
Note that cache extensions can override any of the requirements listed above; see Section 5.2.3.
When using a stored response to satisfy a request without validation, a cache MUST generate an Age header field (Section 5.1), replacing any Age field present in the response with a value equal to the stored response's current_age; see Section 4.2.3.
A cache MUST write through requests with unsafe methods (see Section 9.2.1 of [HTTP]) to the origin server; i.e., a cache is not allowed to generate a reply to such a request before having forwarded the request and received a corresponding response.
Also, note that unsafe requests might invalidate stored responses; see Section 4.4.
A cache MAY use a stored or storable response to satisfy multiple requests, provided that response is allowed to be reused for the requests in question. This allows caches to "collapse requests (Collapse Requests)" -- or combine multiple incoming requests into a single forwarding request during a cache miss -- thereby reducing load on the origin server and network. However, note that if the cache cannot use the returned response for some or all of the collapsed requests, it will need to forward those requests to satisfy them, which can introduce additional latency.
When multiple suitable responses are stored, a cache MUST use the most recent response (as determined by the Date header field). It can also forward the request with "Cache-Control: max-age=0" or "Cache-Control: no-cache" to disambiguate which response to use.
A cache without a clock (see Section 5.6.7 of [HTTP]) MUST revalidate stored responses upon every use.
4.1 Calculating Cache Keys with the Vary Header Field
When a cache receives a request that can be satisfied by a stored response and that stored response contains a Vary header field (see Section 12.5.5 of [HTTP]), the cache MUST NOT use that stored response without revalidation unless all of the request header fields nominated by the Vary field value match in both the original request (i.e., the request that caused the cached response to be stored) and the presented request.
The header fields from two requests are defined to match if and only if the header fields in the first request can be transformed to the header fields in the second request by applying any of the following:
-
Addition or removal of whitespace, where allowed by the header field's syntax
-
Combining multiple header field lines with the same field name (see Section 5.2 of [HTTP])
-
Normalizing both header field values in a way that is known to have identical semantics, according to the header field's specification (e.g., reordering field values when order is not significant; case normalization, where values are defined to be case-insensitive)
If a header field is absent from a request, it can only match if it is also absent from the other request.
A stored response with a Vary header field value containing the member "*" always fails to match.
If multiple stored responses match, a cache will need to choose one to use. When the nominated request header fields have a known preference ordering mechanism (e.g., qvalues on Accept and similar request header fields), that mechanism MAY be used to select the preferred response. If no such mechanism exists or results in equally preferred responses, the most recent response (as determined by the Date header field) is selected, as per Section 4.
Some resources incorrectly omit the Vary header field from their default response (i.e., the one sent when the request does not express any preferences), with the effect that it is selected for subsequent requests to that resource even when a more preferred response is available. When a cache has multiple stored responses for a target URI and one or more omit the Vary header field, the cache SHOULD select the most recent (see Section 4.2.3) stored response that has a valid Vary field value.
If no stored response matches, the cache cannot satisfy the presented request. Typically, the request is forwarded to the origin server, possibly with preconditions added to describe responses the cache already has stored (Section 4.3).
4.2 Freshness
A "fresh (Fresh)" response is one whose age has not yet exceeded its freshness lifetime. Conversely, a "stale (Stale)" response is one where it has.
A response's "freshness lifetime (Freshness Lifetime)" is the length of time between its generation by the origin server and its expiration time. An "explicit expiration time (Explicit Expiration Time)" is the time at which the origin server intends that a cache no longer use a stored response without further validation, whereas a "heuristic expiration time (Heuristic Expiration Time)" is one assigned by a cache when no explicit expiration time is available.
A response's "age (Age)" is the time that has elapsed since it was generated by or successfully validated at the origin server.
When a response is fresh, it can be used to satisfy subsequent requests without contacting the origin server, thereby improving efficiency.
The primary mechanism for determining freshness is for the origin server to provide an explicit expiration time in the future, using either the Expires header field (Section 5.3) or the max-age response directive (Section 5.2.2.1). Generally, an origin server will assign a future explicit expiration time to a response, believing that the representation is not likely to change in a semantically significant way before that expiration time.
If an origin server wishes to force a cache to validate every request, it can assign an explicit expiration time in the past to indicate that the response is already stale. Compliant caches will normally validate a stale cached response before reusing it (see Section 4.2.4).
Since origin servers do not always provide explicit expiration times, caches are also allowed to use a heuristic to determine an expiration time under some circumstances (see Section 4.2.2).
The calculation for determining whether a response is fresh is:
response_is_fresh = (freshness_lifetime > current_age)
freshness_lifetime is defined in Section 4.2.1; current_age is defined in Section 4.2.3.
Clients can send the max-age or min-fresh request directives (Section 5.2.1) to suggest limits on the freshness calculations for the corresponding response. However, caches are not required to honor them.
When calculating freshness, to avoid common problems in date parsing:
-
Although all date formats are specified to be case-sensitive, cache recipients SHOULD match field values case-insensitively.
-
If a cache recipient's internal representation of time has less resolution than the value of the HTTP-date, the recipient MUST internally represent the parsed Expires date as the earliest time equal to or before the received value.
-
A cache recipient MUST NOT allow local time zone to affect the calculation or comparison of age or expiration times.
-
A cache recipient SHOULD consider dates with time zone abbreviations other than "GMT" to be invalid for calculating expiration.
Note that freshness applies only to cache operations; it cannot be used to force a user agent to refresh its display or reload a resource. See Section 6 for an explanation of the differences between caches and history mechanisms.
4.2.1 Calculating Freshness Lifetime
A cache can calculate the freshness lifetime (denoted as freshness_lifetime) of a response by evaluating the following rules and using the first match:
-
If the cache is shared and the s-maxage response directive (Section 5.2.2.10) is present, use its value, or
-
If the max-age response directive (Section 5.2.2.1) is present, use its value, or
-
If the Expires response header field (Section 5.3) is present, use its value minus the value of the Date response header field (using the time the message was received if not present, as per Section 6.6.1 of [HTTP]), or
-
Otherwise, no explicit expiration time is present in the response. A heuristic freshness lifetime might be applicable; see Section 4.2.2.
Note that this calculation is intended to reduce clock skew by using information from the origin server's clock as much as possible.
When there are multiple occurrences of a given directive (e.g., two Expires header field lines or multiple Cache-Control: max-age directives), either the first occurrence should be used or the response should be considered stale. If directives conflict (e.g., both max-age and no-cache are present), the most restrictive directive should be honored. Caches are encouraged to consider responses with invalid freshness information (e.g., a max-age directive with non-integer content) to be stale.
4.2.2 Calculating Heuristic Freshness
Since origin servers do not always provide explicit expiration times, a cache MAY assign a heuristic expiration time when no explicit time is specified, using an algorithm that employs other header field values (such as the Last-Modified time) to estimate a plausible expiration time. This specification does not provide a specific algorithm but does impose worst-case constraints on its results.
A cache MUST NOT use heuristics to determine freshness when an explicit expiration time is present in a stored response. Since the requirement of Section 3 means heuristics can only be used on responses without explicit freshness that are either allowed by their status code to be heuristically cacheable (see, e.g., Section 15.1 of [HTTP]) or have been marked as explicitly cacheable (e.g., with a public response directive).
Note that in previous specifications, heuristically cacheable response status codes were known as "cacheable by default (Cacheable by Default)".
If the response has a Last-Modified header field (see Section 8.8.2 of [HTTP]), caches are encouraged to use a heuristic expiration value that is no more than some fraction of the interval since that time. A typical setting of this fraction might be 10%.
Note: Previous versions of the HTTP specification ([RFC2616], Section 13.9) prohibited caches from calculating heuristic freshness for URIs with query components (i.e., those containing "?"). In practice, this was not widely implemented. Therefore, origin servers are encouraged to send explicit directives (e.g., Cache-Control: no-cache) if they wish to prevent caching.
4.2.3 Calculating Age
The Age header field is used to convey an estimated age of the response message when obtained from a cache. The Age field value is the cache's estimate of the amount of time in seconds since the response was generated or validated at the origin server. Thus, the Age value is the sum of the time the response has resided in each cache along the path from the origin server to arrive, plus the amount of time spent in transit along the network path.
The following data is used for the age calculation:
age_value The term "age_value" denotes the value of the Age header field (Section 5.1) in a form appropriate for arithmetic operations; or 0, if not available.
date_value The term "date_value" denotes the value of the Date header field in a form appropriate for arithmetic operations. See Section 6.6.1 of [HTTP] for the definition of the Date header field and requirements for responses without it.
now The term "now" denotes the current value of this implementation's clock (see Section 5.6.7 of [HTTP]).
request_time The value of the clock at the time of the request that resulted in the stored response.
response_time The value of the clock at the time the response was received.
A response's age can be calculated in two entirely independent ways:
-
The "apparent_age": response_time minus date_value, if the implementation's clock is reasonably well synchronized with the origin server's clock. If the result is negative, the result is replaced with zero.
-
The "corrected_age_value", if all caches along the response path implement HTTP/1.1 or greater. A cache MUST interpret this value relative to the time the request was initiated, not the time the response was received.
apparent_age = max(0, response_time - date_value);
response_delay = response_time - request_time;
corrected_age_value = age_value + response_delay;
The corrected_age_value MAY be used as the corrected_initial_age. In cases where there might be very old cache implementations that do not properly insert Age, the corrected_initial_age can be calculated more conservatively as
corrected_initial_age = max(apparent_age, corrected_age_value);
The current_age of a stored response can then be calculated by adding the time (in seconds) since the stored response was last validated by the origin server to the corrected_initial_age.
resident_time = now - response_time;
current_age = corrected_initial_age + resident_time;
4.2.4 Serving Stale Responses
A "stale (Stale)" response is one that either has explicit expiry information or allows computing heuristic expiration and is not fresh according to the calculation in Section 4.2.
A cache MUST NOT generate a stale response if it is prohibited by an explicit in-protocol directive (e.g., by a no-cache response directive, a must-revalidate response directive, or an applicable s-maxage or proxy-revalidate response directive; see Section 5.2.2).
A cache MUST NOT generate a stale response unless the cache is disconnected or it is explicitly allowed by the client or origin server (e.g., by the max-stale request directive in Section 5.2.1, by an extension directive defined by [RFC5861], or by configuration according to an out-of-band contract).
4.3 Validation
When a cache has one or more stored responses for a requested URI but cannot serve any of them (e.g., because they are not fresh or a suitable one cannot be selected; see Section 4.1), it can use the conditional request mechanism (see Section 13 of [HTTP]) in a forwarded request to give the next inbound server an opportunity to select a valid stored response to use, updating the stored metadata in the process, or to replace the stored response(s) with a new response. This process is known as "validating (Validating)" or "revalidating (Revalidating)" the stored response.
4.3.1 Sending a Validation Request
When generating a conditional request for validation, a cache either starts with a request it is attempting to satisfy or -- if it is independently initiating a request -- synthesizes a request using a stored response by copying the method, target URI, and request header fields identified by the Vary header field (Section 4.1).
It then updates that request with one or more precondition header fields. These contain validator metadata obtained from stored responses for the same URI. Typically, this will include only stored responses with the same cache key, though a cache is allowed to validate responses it cannot select using the presented request header fields (see Section 4.1).
The recipient then compares the precondition header fields to determine whether any stored response is equivalent to a current representation of the resource.
One such validator is the timestamp given in a Last-Modified header field (see Section 8.8.2 of [HTTP]), which can be used in an If-Modified-Since header field for response validation, or in an If-Unmodified-Since or If-Range header field for representation selection (i.e., the client is referring specifically to a previously obtained representation with that timestamp).
Another validator is the entity-tag given in an ETag field (see Section 8.8.3 of [HTTP]). One or more entity-tags (indicating one or more stored responses) can be used in an If-None-Match header field for response validation or in an If-Match or If-Range header field for representation selection (i.e., the client is referring specifically to one or more previously obtained representation(s) with the listed entity-tag(s)).
When generating a conditional request for validation, a cache:
-
MUST send the relevant entity-tag (using If-Match, If-None-Match, or If-Range) if an entity-tag is provided in the stored response being validated.
-
SHOULD send the Last-Modified value (using If-Modified-Since) if the request is not for a subrange, a single stored response is being validated, and that response contains a Last-Modified value.
-
MAY send the Last-Modified value (using If-Unmodified-Since or If-Range) if the request is for a subrange, a single stored response is being validated, and that response contains only a Last-Modified value (instead of an entity-tag).
In most cases, both validators will be generated in cache validation requests, even when entity-tags are clearly superior, to allow old intermediaries that do not understand entity-tag preconditions to respond appropriately.
4.3.2 Handling a Received Validation Request
Each client in a request chain might have its own cache, so it is common for a cache of an intermediary to receive conditional requests from other (outbound) caches. Likewise, some user agents make conditional requests to limit data transfer to recently modified representations or to complete partial retrievals.
If a cache receives a request that can be satisfied by reusing a stored 200 (OK) or 206 (Partial Content) response (as per Section 4), the cache SHOULD evaluate any applicable conditional header field preconditions received in that request with respect to the corresponding validators contained in the stored response.
A cache MUST NOT evaluate conditional header fields that only apply to an origin server, occur in a request whose semantics cannot be satisfied with a cached response, or occur in a request for a target resource for which it has no stored response; such preconditions might be intended for some other (inbound) server.
Proper evaluation of a conditional request by a cache depends on the precondition header fields received and their precedence. In summary, the If-Match and If-Unmodified-Since conditional header fields are not applicable to a cache, and If-None-Match takes precedence over If-Modified-Since. See Section 13.2.2 of [HTTP] for a complete specification of precondition precedence.
A request containing an If-None-Match header field (see Section 13.1.2 of [HTTP]) indicates that the client wants to validate one or more of its own stored responses in comparison to the stored response selected by the cache (per Section 4).
If an If-None-Match header field is not present, a request containing an If-Modified-Since header field (see Section 13.1.3 of [HTTP]) indicates that the client wants to validate one or more of its own stored responses by modification date.
If a request contains an If-Modified-Since header field and a Last-Modified header field is not present in a stored response, the cache SHOULD use the Date field value of the stored response (or the time the stored response was received, if no Date field is present) to evaluate the conditional.
A cache that implements partial responses to range requests (as defined in Section 14.2 of [HTTP]) will also need to evaluate a received If-Range header field (see Section 13.1.5 of [HTTP]) with respect to the cache-selected response.
When a cache decides to forward a request to revalidate its own stored response for a request containing an If-None-Match list of entity-tags, the cache MAY combine the received list with a list of entity-tags from its own set of stored responses (fresh or stale) and send the union of the two lists as a replacement If-None-Match header field value in the forwarded request. If a stored response only contains partial content, the cache MUST NOT include its entity-tag in the union unless the request is for a range that would be entirely satisfied by that partial stored response. If the response to the forwarded request is 304 (Not Modified) and has an ETag field value with an entity-tag that is not in the client's list, the cache MUST generate a 200 (OK) response for the client by reusing its corresponding stored response, as updated by the 304 response metadata (Section 4.3.4).
4.3.3 Handling a Validation Response
Cache handling of a response to a conditional request depends on its status code:
-
A 304 (Not Modified) response status code indicates that the stored response can be updated and reused; see Section 4.3.4.
-
A full response (i.e., one with content) indicates that none of the stored responses nominated in the conditional request are suitable. Instead, the cache MUST use the full response to satisfy the request. The cache MAY store such a full response, subject to its constraints (see Section 3).
-
However, if a cache receives a 5xx (Server Error) response while attempting to validate a response, it can either forward that response to the requesting client or act as if the server failed to respond. In the latter case, the cache MAY send a previously stored response, subject to its constraints on doing so (see Section 4.2.4), or retry the validation request.
4.3.4 Freshening Stored Responses upon Validation
When a cache receives a 304 (Not Modified) response, it needs to identify the stored response(s) suitable for updating with the new information and then do so.
The initial set of stored responses to update is those that could have been chosen for this request -- i.e., those that meet the requirements in Section 4, with the exception of the last requirement that it be fresh, allowed to be served stale, or just validated.
The initial set of stored responses is then further filtered by the first of the following that matches:
-
If the new response contains one or more "strong validators (Strong Validators)" (see Section 8.8.1 of [HTTP]), then each of these strong validators identifies a selected representation for update. All of the stored responses in the initial set that have one of the same strong validators are identified for update. If none in the initial set contains at least one of the same strong validators, the cache MUST NOT use the new response to update any stored responses.
-
If the new response contains no strong validators but does contain one or more "weak validators (Weak Validators)", and those validators correspond to one of the initial set of stored responses, then the most recent of those matching stored responses is identified for update.
-
If the new response does not contain any form of validator (such as in the case where a client generates an If-Modified-Since request from a source other than the Last-Modified response header field), and there is only one stored response in the initial set, and that stored response also lacks a validator, then that stored response is identified for update.
For each identified stored response, the cache MUST update its header fields with the header fields provided in the 304 (Not Modified) response, as per Section 3.2.
4.3.5 Freshening Responses with HEAD
A response to the HEAD method is identical to what an equivalent request made with GET would be, except no content is sent. This property of a HEAD response can be used to invalidate or update a cached GET response if the more efficient conditional GET request mechanism is not available (due to no validators being present in the stored response) or when transmission of content is not desired even if it has been modified.
When a cache makes an inbound HEAD request for a target URI and receives a 200 (OK) response, the cache SHOULD update or invalidate each of its stored GET responses that could have been chosen for that request (see Section 4.1).
For each stored response that could have been selected, if the stored response and HEAD response have matching values for any received validator fields (ETag and Last-Modified) and, if the HEAD response has a Content-Length header field, its value matches that of the stored response, the cache SHOULD update the stored response as described below; otherwise, the cache SHOULD consider the stored response to be stale.
If the cache updates a stored response with metadata from a HEAD response, the cache MUST update the stored response with the header fields provided in the HEAD response (see Section 3.2).
4.4 Invalidating Stored Responses
Because unsafe request methods (see Section 9.2.1 of [HTTP]) such as PUT, POST, or DELETE have the potential for changing state on the origin server, intervening caches need to invalidate stored responses to keep their contents up to date.
When a cache receives a non-error status code response to an unsafe request method (including methods whose safety is unknown), the cache MUST invalidate the target URI (see Section 7.1 of [HTTP]).
When a cache receives a non-error status code response to an unsafe request method (including methods whose safety is unknown), the cache MAY invalidate other URIs. In particular, the URIs in the Location and Content-Location response header fields (if present) are candidates for invalidation; other URIs might be discovered by mechanisms not specified in this document. However, a cache MUST NOT trigger invalidation under these conditions if the origin (see Section 4.3.1 of [HTTP]) of the URI to be invalidated differs from that of the target URI (see Section 7.1 of [HTTP]). This helps prevent denial-of-service attacks.
"Invalidate (Invalidate)" means that the cache will either remove all stored responses whose target URI matches the given URI or mark them as "invalid (Invalid)" and in need of mandatory validation before they can be sent in response to a subsequent request.
A "non-error response (Non-Error Response)" is one with a 2xx (Successful) or 3xx (Redirection) status code.
Note that this does not guarantee invalidation of all appropriate responses globally; status-changing requests will only invalidate responses in the caches they pass through.