The gap
RFC 9110 §13.1.2: If-None-Match: * matches when the target resource has any current representation. On GET/HEAD that means: representation exists → the server MUST answer 304.
The current answer treats * as an opaque tag. The server never stores a * key, so the answer is always a miss → always 200 with the full body.
Why this is low-priority
The failure direction is safe - the mirror image of #197. A wrong 304 lies to the client about content; a 200 where a 304 was possible only spends bandwidth, and the body it carries is correct. * on a conditional GET is also rare: its main use is guarding writes (PUT + If-None-Match: *), which does not pass through isNotModified().
Sketch of a fix, if a client ever needs it
Scoped path only (isNotModifiedFor($uri, $server)): answer * with storage->get($uri) !== null - a live RO-pool entry is a current representation. One extra pool read, only when the header is literally *. The unscoped pre-routing path cannot know the target resource and keeps ignoring *; that stays documented.
Known approximation: an expired RO entry with a still-live validator answers 200. Defensible - "current" is then what running the resource produces.
Split from the reserved-character issue (#202) on purpose: that one is input validation with a fix in EntityTags; this one is protocol semantics needing a new question asked of the storage.
The gap
RFC 9110 §13.1.2:
If-None-Match: *matches when the target resource has any current representation. On GET/HEAD that means: representation exists → the server MUST answer 304.The current answer treats
*as an opaque tag. The server never stores a*key, so the answer is always a miss → always 200 with the full body.Why this is low-priority
The failure direction is safe - the mirror image of #197. A wrong 304 lies to the client about content; a 200 where a 304 was possible only spends bandwidth, and the body it carries is correct.
*on a conditional GET is also rare: its main use is guarding writes (PUT+If-None-Match: *), which does not pass throughisNotModified().Sketch of a fix, if a client ever needs it
Scoped path only (
isNotModifiedFor($uri, $server)): answer*withstorage->get($uri) !== null- a live RO-pool entry is a current representation. One extra pool read, only when the header is literally*. The unscoped pre-routing path cannot know the target resource and keeps ignoring*; that stays documented.Known approximation: an expired RO entry with a still-live validator answers 200. Defensible - "current" is then what running the resource produces.
Split from the reserved-character issue (#202) on purpose: that one is input validation with a fix in
EntityTags; this one is protocol semantics needing a new question asked of the storage.