Skip to content

Conditional requests for static files (ETag / Last-Modified / 304)#298

Open
balat wants to merge 4 commits into
masterfrom
qw2-conditional-requests
Open

Conditional requests for static files (ETag / Last-Modified / 304)#298
balat wants to merge 4 commits into
masterfrom
qw2-conditional-requests

Conversation

@balat

@balat balat commented Jun 26, 2026

Copy link
Copy Markdown
Member

What

Static files are now served with validators and honour conditional requests, so
browsers and caches can revalidate cheaply (RFC 7232) — even python -m http.server
did this and we did not.

  • Every static response carries a weak ETag (derived from the file's
    modification time and size) and a Last-Modified header.
  • A request with If-None-Match (or, as a fallback, If-Modified-Since)
    that matches gets 304 Not Modified with an empty body, keeping the
    validators.

Where

Response.respond_file gained the ETag/Last-Modified generation and optional
?if_none_match / ?if_modified_since parameters; Staticmod passes the
request's headers. If-None-Match takes precedence over If-Modified-Since per
RFC 7232; the latter only returns 304 on an exact match of our Last-Modified
value, so it never answers 304 wrongly.

Tests

test/conditional-requests.t checks the validators are present, that
re-requesting with either validator returns 304 with an empty body, and that a
non-matching ETag still serves the file.

Note

Independent of #297 (reverse proxy); both branch from master.

balat added 4 commits June 26, 2026 13:20
Response.respond_file now always adds a weak ETag (derived from the file's
modification time and size) and a Last-Modified header, and takes optional
If-None-Match / If-Modified-Since values; when they match, it answers
304 Not Modified with an empty body, keeping the validators (RFC 7232).
Pass the request's If-None-Match and If-Modified-Since headers to
Response.respond_file so that unchanged static files return 304 Not Modified.
Checks that static files carry ETag and Last-Modified, that re-requesting with
either validator returns 304 with an empty body, and that a non-matching ETag
still serves the file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant