Skip to content

fix(http): do not advertise codec headers on bodyless GET/HEAD - #12

Open
xylophonez wants to merge 1 commit into
candidate/fast-arweave-scheduler-1from
fix/http-bodyless-request-codec
Open

fix(http): do not advertise codec headers on bodyless GET/HEAD#12
xylophonez wants to merge 1 commit into
candidate/fast-arweave-scheduler-1from
fix/http-bodyless-request-codec

Conversation

@xylophonez

Copy link
Copy Markdown
Owner

Problem

The outbound request encoder in hb_http:prepare_request/6 attaches entity representation metadata to requests that carry no entity at all. A GET or HEAD whose message holds a codec-device or content-type field re-emits those fields as headers alongside a zero-byte body: the ans104@1.0 branch sets both headers unconditionally, and the httpsig@1.0 and generic branches forward them from the message as ordinary fields.

Strict peers reject such requests with a 500 rather than ignoring the stray metadata, because their ingress path (req_to_tabm_singleton/3 selects the request codec from codec-device, then content-type, then the default, with no bodyless-method guard) attempts header-driven body decoding on an empty binary. The observed matrix against a deployed peer: a bodyless HEAD returns 200 both plainly and with Accept: application/json, but adding either Content-Type: application/json or codec-device: json@1.0 — with the body still zero bytes — turns the same lookup into a 500. This makes the stock client encoder unable to relay such requests at all.

Repro

Captured status matrix for a bodyless HEAD against the peer:

case body bytes entity metadata status
plain 0 none 200
Accept: application/json 0 none 200
Content-Type: application/json 0 content-type 500
codec-device: json@1.0 0 codec-device 500

In-module: prepare_request(<<"json@1.0">>, <<"GET">>, Peer, Path, #{ <<"codec-device">> => <<"json@1.0">>, <<"content-type">> => <<"application/json">> }, Opts) previously produced a request with both headers set and body => <<>>.

Fix

Route genuinely bodyless requests around the codec advertisement:

  • An uncommitted GET/HEAD whose message encodes without an entity body is now sent header-only: content-type and codec-device are stripped, while all other fields (accept, accept-bundle, cookies, and so on) are preserved as headers.
  • "Genuinely bodyless" is decided by the encoder itself: if the message produces a body after all (for example, nested messages that must be transmitted as multipart parts), the request falls back to the existing format-specific encoders unchanged.
  • Committed requests are excluded from the rewrite, since their wire form must continue to carry every committed field to remain verifiable by the recipient.

The format-specific encoding itself is untouched; it moves verbatim from the tail of prepare_request/6 into a new encode_request/6 so the bodyless path can fall back to it.

Tests

  • New: hb_http:bodyless_get_no_codec_headers_test asserts that (1) bodyless GET and HEAD requests are sent with an empty body and neither content-type nor codec-device, while accept survives, (2) a GET that carries an entity body still transmits it, and (3) a POST with a body continues to advertise its codec.
  • Full hb_http eunit suite passes: rebar3 eunit --module=hb_http — all 19 tests, including the round-trip tests that issue real GETs through the new path against a local node (cors_get_test, get_deep_*_wasm_state_test, index_test, remote_response_links_test).

The outbound request encoder attached entity representation metadata to
requests that carry no entity at all. A GET or HEAD whose message held a
codec-device or content-type field re-emitted those fields as headers with
a zero-byte body (the ans104@1.0 branch sets both unconditionally, and the
httpsig@1.0 and generic branches forward them from the message), and strict
peers reject such requests with a 500 instead of ignoring the stray
metadata, because header-driven body decoding is attempted on an empty
binary.

Route genuinely bodyless requests around the codec advertisement: an
uncommitted GET/HEAD whose message encodes without an entity body is now
sent header-only, with content-type and codec-device stripped and all other
fields (accept, accept-bundle, cookies, and so on) preserved. Requests that
produce a body (including nested messages that encode as multipart parts)
and committed requests, whose wire form must remain verifiable, fall back
to the existing format-specific encoders unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant