Skip to content

feat: set and read a SETTINGS parameter by identifier - #993

Open
robertream wants to merge 1 commit into
hyperium:masterfrom
robertream:settings-by-identifier
Open

robertream wants to merge 1 commit into
hyperium:masterfrom
robertream:settings-by-identifier

Conversation

@robertream

@robertream robertream commented Oct 31, 2026 •

Copy link
Copy Markdown

RFC 9113 §5.5 lets an extension define new settings, but h2 gives a dependent crate no way to use that: fields are private even under unstable, nothing addresses a setting by identifier, and load drops unrecognised ones at parse time.

I need this for a WebTransport over HTTP/2 implementation I've written, following the draft now in WGLC, which negotiates via SETTINGS_WT_ENABLED and six flow-control parameters. The alternative is h2 carrying one protocol's constants and setters, repeated for the next extension.

The API is additive. Every existing typed accessor keeps its signature and behaviour; only the internal storage changes, from named fields to two arrays sorted by identifier, so the frame stays Copy with no allocation. Settings goes from 60 bytes to 124; carrying WebTransport's settings as named Option<u32> fields instead measures 116, so the growth is the cost of extension settings rather than of the generic representation.

One change is not additive. RFC 9113 §3.4 makes the client's SETTINGS part of the connection preface, so server::handshake now waits for it before yielding a connection, where it previously yielded earlier and reported the peer's parameters as absent. The wait is unbounded by design: §3.4 specifies no timeout, and a peer that sends the preface and then goes silent produces no events for this crate to wake on, so bounding it falls to the caller. If you'd rather h2 not take that on, the wait can sit behind a builder flag instead, at the cost of peer_settings only being reliable when it is set.

@robertream
robertream force-pushed the settings-by-identifier branch 2 times, most recently from 50d9024 to 1beaf75 Compare October 31, 2026 16:10
RFC 9113 5.5 lets an extension define new settings and obliges an endpoint to
ignore identifiers it does not understand. h2 honoured the obligation but
offered no way to use the permission: `Settings`' fields are private even
under `unstable`, nothing addresses one by identifier, and `load` discarded an
unrecognised identifier at parse time, so there was no retained frame to
expose either. That ruled out three of the ten identifiers IANA has assigned,
and any an extension built on h2 wants to advertise for itself.

- `Builder::setting(id, value)` sends one, on both ends.
- `SendRequest::poll_peer_settings` and its async form hand back a
  `PeerSettings` snapshot with `get(id)` and `iter()`, resolving once the
  peer's opening frame has been applied. A client may send requests before
  seeing the peer's SETTINGS (3.4), so an accessor answering earlier would
  answer wrongly.

Storage is two fixed arrays sorted by identifier rather than a map, so the
frame stays `Copy` with no allocation. Retention keeps the numerically lowest
identifiers, so pressure can cost the observability of a high identifier but
never whether a setting this crate acts on is applied, which keeps wire order
from changing behaviour (6.5.3).

Outbound, `set` reserves one slot per identifier this crate defines, so an
extension a caller added can never crowd one out. A thirteenth extension
identifier is a configuration that cannot be sent: it trips a `debug_assert`
and, in release, is dropped and logged rather than displacing one already set.
Nothing on the peer's path can panic; `load` validates fallibly and `insert`
drops what will not fit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013CWmskbkrYMCKcuYaufajw

This branch has not been deployed

No deployments
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