Step 1 of 5 · Reading · ~3 min
Read
Caching, Compression & Beyond
Conditional Requests & ETags
Browsers and CDNs revalidate cached responses before refetching them. A conditional request lets the client say "give me this only if it changed", and the server answers with a tiny 304 Not Modified instead of the whole body. Two mechanisms do it: hash-based (ETag with If-None-Match) and time-based (Last-Modified with If-Modified-Since). Your program will evaluate the preconditions on a request against the current version of a resource and answer with the right status.
The validators
HTTP/1.1 200 OK
ETag: "a1b2c3" <- opaque identifier of this exact version
Last-Modified: Tue, 15 Nov 2022 12:00:00 GMT
An entity-tag is a quoted opaque string, optionally prefixed W/. A strong tag ("a1b2c3") promises byte-for-byte equality. A weak tag (W/"a1b2c3") promises only that the two versions are semantically interchangeable (the same page gzip-compressed or not). Servers usually derive strong tags from a hash of the content.
The tag is opaque and may contain commas, so a header such as If-None-Match: "x,y", "z" holds two tags, not three. Split by walking the quotes, never by splitting on commas.
Two comparison functions
- Strong comparison (used by
If-Match): both tags must be strong and their opaque strings equal. - Weak comparison (used by
If-None-Match): ignore theW/prefixes and compare the opaque strings.
W/"v1" and "v1" therefore match weakly and never match strongly.
What each header means
| Header | Passes when | When it fails |
|---|---|---|
If-Match: "a", "b" or * | some listed tag strong-matches the current tag, or * | 412 Precondition Failed |
If-None-Match: "a", W/"b" or * | no listed tag weak-matches, and not * | GET/HEAD: 304 Not Modified; other methods: 412 |
If-Modified-Since: <date> | the resource changed after the date | 304 (GET/HEAD only) |
If-Match protects writes from lost updates ("change this only if it is still version X"). If-None-Match: * on a PUT means "create only, never overwrite".
Order of evaluation (RFC 9110 section 13.2.2)
If-Match, if present. Failure:412.If-None-Match, if present. Failure:304for GET and HEAD,412otherwise.- Only when
If-None-Matchis absent:If-Modified-Since, for GET and HEAD, with a date that parses. Resource not modified since:304. - Otherwise the request proceeds:
200 OK.
The ETag wins over the date because the date has one-second resolution and trusts two clocks to agree: a file changed twice within a second looks unchanged. A date that does not parse as an HTTP date is ignored, never an error.
An HTTP-date in the preferred format is exactly 29 characters: Tue, 15 Nov 2022 12:00:00 GMT. Compare two of them by year, month, day, hour, minute, second.
What the response carries
200 OK:ETagandLast-Modified, then the body.304 Not Modified: no body, and it repeats theETagso the cache can refresh its entry.412 Precondition Failed: no validators needed.
The contract
The first two input lines (LF terminated) describe the current resource: ETAG <tag> and LASTMOD <http-date>. The rest is the raw request (CRLF). Print the status line and then, for 200, ETag: ... and Last-Modified: ...; for 304, ETag: ...; for 412 nothing more.
Common mistakes
- Splitting
If-None-Matchon every comma, which breaks tags that contain one. - Using strong comparison for
If-None-Match, so weak clients never get a 304. - Letting a matching
If-Modified-Sinceoverride a non-matchingIf-None-Match. - Sending a body, or omitting the
ETag, on a 304.
Your exercise
The starter reads the resource and the request line and headers for you. You implement the two comparisons, the tag list walk, the date comparison and the order of evaluation.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…