Skip to content

conneg: HEAD ignores the Accept header — content-type diverges from GET on the same resource #552

Description

@melvincarvalho

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions