Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests
Extracted elements (29)
A Last-Modified time used as a validator is implicitly weak unless the origin server can confirm the representation did not change twice during the same second, or the client has a cache entry with a Date value at least 60 seconds newer than the Last-Modified time. The 60-second limit guards against clock skew between Date and Last-Modified generation.
Conditional GET requests are the most efficient mechanism for HTTP cache updates. Conditionals can also be applied to state-changing methods such as PUT and DELETE to prevent the 'lost update' problem, where one client accidentally overwrites the work of another acting in parallel.
The fixed precedence order for evaluating conditional header fields reflects that 'lost update' preconditions have more strict requirements than cache validation, a validated cache is more efficient than a partial response, and entity-tags are presumed to be more accurate than date validators.
Content codings are a property of representation data, so a strong entity-tag for a content-encoded representation must be distinct from the entity-tag of an unencoded representation to prevent conflicts during cache updates and range requests. Transfer codings, in contrast, do not result in distinct entity-tags.
A client MUST send an entity-tag in any cache validation request (using If-Match or If-None-Match) if an entity-tag has been provided by the origin server. It SHOULD send both validators if both have been provided, to allow both HTTP/1.0 and HTTP/1.1 caches to respond appropriately.
A recipient cache or origin server MUST evaluate received request preconditions after successfully performing its normal request checks and just before it would perform the action associated with the request method. A server MUST ignore all received preconditions if its response without those conditions would have been a status code other than 2xx or 412.
A recipient MUST ignore If-Modified-Since if the request contains an If-None-Match header field, as If-None-Match is a more accurate replacement. A recipient MUST also ignore If-Modified-Since if the field-value is not a valid HTTP-date or if the request method is neither GET nor HEAD.
A recipient MUST ignore If-Unmodified-Since if the request contains an If-Match header field, as If-Match is considered a more accurate replacement. A recipient MUST also ignore If-Unmodified-Since if the received field-value is not a valid HTTP-date.
A recipient MUST use the weak comparison function when comparing entity-tags for If-None-Match, since weak entity-tags can be used for cache validation even if there have been changes to the representation data.
A server that is not the origin server for the target resource and cannot act as a cache MUST NOT evaluate the conditional request header fields defined by this specification, and MUST forward them if the request is forwarded. A server MUST also ignore conditional request header fields when received with CONNECT, OPTIONS, or TRACE.
An origin server MUST NOT perform the requested method if If-None-Match evaluates to false; instead it MUST respond with 304 (Not Modified) if the request method is GET or HEAD, or 412 (Precondition Failed) for all other request methods.
An origin server MUST use the strong comparison function when comparing entity-tags for If-Match, since the client intends this precondition to prevent the method from being applied if there have been any changes to the representation data.
An origin server SHOULD change a weak entity-tag whenever it considers prior representations to be unacceptable as a substitute for the current representation; i.e., a weak entity-tag ought to change whenever the origin server wants caches to invalidate old responses.
An origin server with a clock MUST NOT send a Last-Modified date that is later than the server's time of message origination (Date). If the last modification time evaluates to a future time, the origin server MUST replace that value with the message origination date.
An origin server without a clock MUST NOT assign Last-Modified values to a response unless these values were associated with the resource by some other system or user with a reliable clock.
If an origin server provides an entity-tag for a representation and the generation of that entity-tag does not satisfy all characteristics of a strong validator, then the origin server MUST mark the entity-tag as weak by prefixing its opaque value with 'W/' (case-sensitive).
The server generating a 304 response MUST generate any of the following header fields that would have been sent in a 200 (OK) response to the same request: Cache-Control, Content-Location, Date, ETag, Expires, and Vary.
A 'strong validator' is representation metadata that changes value whenever a change occurs to the representation data that would be observable in the payload body of a 200 (OK) response to GET. Strong validators are unique across all versions of all representations associated with a particular resource over time.
A 'weak validator' is representation metadata that might not change for every change to the representation data. Weakness may result from limited clock resolution, an inability to ensure uniqueness, or a deliberate grouping of equivalent representations. Weak entity-tags are prefixed with 'W/'.
The 304 (Not Modified) status code indicates that a conditional GET or HEAD request would have resulted in a 200 (OK) response but for the condition evaluating to false. A 304 response cannot contain a message-body; it is always terminated by the first empty line after the header fields.
The 'If-Match' header field makes a request conditional on the origin server having a current representation with an entity-tag matching a member of the listed tags, or any representation when the value is '*'. Syntax: If-Match = '*' / 1#entity-tag.
The 'If-None-Match' header field makes a request conditional on the recipient not having any current representation of the target resource (when '*') or having a selected representation with an entity-tag not matching any listed tag. Syntax: If-None-Match = '*' / 1#entity-tag.
The 'Last-Modified' header field in a response provides a timestamp indicating the date and time at which the origin server believes the selected representation was last modified. Its ABNF is: Last-Modified = HTTP-date.
Two entity-tag comparison functions are defined. Strong comparison: both tags must be non-weak and their opaque-tags match character-by-character. Weak comparison: opaque-tags match character-by-character regardless of either or both being tagged as weak.
This document updates the 'Hypertext Transfer Protocol (HTTP) Status Code Registry' with entries for 304 (Not Modified) and 412 (Precondition Failed), and updates the 'Message Headers' registry with permanent standard registrations for ETag, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, and Last-Modified.
An entity-tag can be abused to create privacy risks: a site may construct a semantically invalid but user-unique entity-tag in a long-lived cacheable response and later read it in conditional requests as a persistent identifier for re-identification. User agents should clear or replace caches when users perform privacy-maintaining actions such as clearing cookies or entering private browsing mode.
Validators are not intended to ensure the validity of a representation, guard against malicious changes, or detect man-in-the-middle attacks. They enable more efficient cache updates and optimistic concurrent writes only when all participants are behaving cooperatively.
Preconditions MUST be evaluated in a fixed order: (1) If-Match at origin server; (2) If-Unmodified-Since at origin server when If-Match absent; (3) If-None-Match; (4) If-Modified-Since for GET/HEAD when If-None-Match absent; (5) If-Range when method is GET with Range present; (6) otherwise perform the action. False conditions at steps 1–2 yield 412; false at steps 3–4 yield 304 for GET/HEAD or 412 for other methods.
The entity-tag format is: entity-tag = [ weak ] opaque-tag; weak = %x57.2F ('W/', case-sensitive); opaque-tag = DQUOTE *etagc DQUOTE. Backslash characters ought to be avoided in entity-tags because older recipients may perform backslash unescaping.