Skip to content

Ignore Range in Plug.Static unless If-Range matches the ETag - #1337

Merged
josevalim merged 1 commit into
elixir-plug:mainfrom
wleeaf:static-if-range
Oct 26, 2026
Merged

josevalim merged 1 commit into
elixir-plug:mainfrom
wleeaf:static-if-range

Conversation

@wleeaf

@wleeaf wleeaf commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Plug.Static serves a Range request without looking at If-Range, so a client resuming a download of a file that has changed gets the requested bytes of the new file. For example, the first response's ETag is "A", the file is then replaced, and the client resumes with Range: bytes=500- and If-Range: "A". It gets 206 with bytes 500 onwards of the new content and stitches them onto the old first half.

RFC 9110 section 13.1.5 says the server must ignore Range when the If-Range validator does not match. A matching validator is an entity tag that equals the current ETag under the strong comparison, or a date that equals Last-Modified.

serve_range/5 now only uses the range when there is no If-Range, or when If-Range is the response's ETag and that ETag is not weak. Otherwise it sends the whole file with 200, as it already does for a range it can't serve. A date never matches because Plug.Static doesn't send Last-Modified. This also applies when the response has no ETag at all, for vsn requests or when cache_control_for_etags is nil.

The new tests in the "range request" block check:

  • If-Range with the current ETag still gets 206.
  • Another ETag, the weak form of the ETag, or a date gets 200 with the full body. This holds for a satisfiable range and for one that would otherwise be a 416.
  • If-Range on a vsn request, which has no ETag, gets 200.

Without the change, the first mismatch case gets 206 and the test fails. With it, mix test passes (617 tests) and mix format --check-formatted is clean.

@josevalim
josevalim merged commit 4a0477e into elixir-plug:main Oct 26, 2026
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.

2 participants