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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions