Skip to content

iili: model HEAD and delete WithHeadAsGet once smithy-cpp frames HEAD responses #1437

Description

@aaylward

Follow-up to #1433, closed by #1435 with a service-local workaround rather than the modeled contract.

Where it stands

HEAD /iili/v1/r/{slug} answers 302 with Location today, via WithHeadAsGet in domains/iili/apis/iili/smithy_handler.cc: it re-dispatches HEAD as the GET it mirrors and clears the body on the way out. main.cc and both test harnesses share that composition, and wire_test.cc pins the 302 and the 404.

It is deliberately not modeled. Routing was never the obstacle — smithy-cpp's router buckets by method and only checks conflicts within a bucket, so @http(method: "HEAD", uri: "/iili/v1/r/{slug}") would register cleanly beside the GET. The obstacle is framing: ToWireResponse copies the body and calls prepare_payload() without ever seeing the request method, so a modeled HEAD operation would put the generated {} body on a HEAD response — forbidden by RFC 9110 §9.3.2, and on a keep-alive connection the client reads those two bytes as the start of the next response. The handler cannot suppress it: the body comes from the generated serializer and the transport owns framing.

Filed upstream as muchq/smithy-cpp#192.

What to do here, once the pin picks that up

  1. Add the HEAD binding for Redirect to domains/iili/apis/iili/model/iili.smithy.
  2. Delete WithHeadAsGet and its declaration, and unwrap the three call sites (main.cc, wire_test.cc, production_chain_test.cc).
  3. Keep both HEAD wire tests exactly as they are — they assert behavior, not mechanism, so they should stay green across the swap. That is the check that the modeled version is a true replacement.

Why it is worth doing

The contract is invisible where a reader looks for it. Nothing in iili.smithy says HEAD is answered, so the model understates what the service serves, and a generated client has no HEAD operation. The workaround also lives only in this service; the modeled form would come from the same place every other route does.

Not urgent — behavior is correct on the wire today. This is about where the truth is written down.

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