Found while live-verifying #71.
Gap
GET runs content negotiation correctly (q-weights, listed order — fixed by #325), but HEAD on the same resource returns the stored content type regardless of the Accept header:
# resource: /public/test.jsonld (stored as JSON-LD), server with --conneg
# GET negotiates:
curl -s /public/test.jsonld -H 'Accept: text/turtle, application/ld+json' \
-o /dev/null -w "%{content_type}" # → text/turtle ✓
# HEAD does not:
curl -sI /public/test.jsonld -H 'Accept: text/turtle, application/ld+json' \
| grep -i content-type # → application/ld+json ✗
RFC 9110 §9.3.2: "The server SHOULD send the same header fields in response to a HEAD request as it would have sent if the request method had been GET." Clients that probe with HEAD before fetching (caches, link checkers, conneg-aware clients) see a content type the subsequent GET won't return.
Notable
#71's original repro used curl -I (HEAD) — so the literal repro command "passes" today only coincidentally: HEAD returns the stored type, which happens to be what that Accept header prefers for a JSON-LD-stored resource.
Likely shape
handleHead in src/handlers/resource.js presumably takes a cheaper path that skips the conneg branch handleGet runs. Fix is probably routing HEAD through the same content-type selection (without the body work), or extracting the negotiation into a shared helper both use.
Related
Found while live-verifying #71.
Gap
GETruns content negotiation correctly (q-weights, listed order — fixed by #325), butHEADon the same resource returns the stored content type regardless of theAcceptheader:RFC 9110 §9.3.2: "The server SHOULD send the same header fields in response to a HEAD request as it would have sent if the request method had been GET." Clients that probe with HEAD before fetching (caches, link checkers, conneg-aware clients) see a content type the subsequent GET won't return.
Notable
#71's original repro used
curl -I(HEAD) — so the literal repro command "passes" today only coincidentally: HEAD returns the stored type, which happens to be what that Accept header prefers for a JSON-LD-stored resource.Likely shape
handleHeadinsrc/handlers/resource.jspresumably takes a cheaper path that skips the conneg branchhandleGetruns. Fix is probably routing HEAD through the same content-type selection (without the body work), or extracting the negotiation into a shared helper both use.Related
application/octet-streamignoring Accept entirely (separate, already-tracked coupling between stored extension and served type)