Package
http2_adapter
Motivation
What cannot be done today: read HTTP/2 response trailers. The adapter discards them.
In HTTP/2, a server may send a trailer section as a final HEADERS frame (no :status, END_STREAM set) after the response body (RFC 9113 §8.4, §8.8.5). Today Http2Adapter._fetch parses these frames and discards them:
Who needs this, and in which real-world scenario:
- gRPC over HTTP/2 through dio. The gRPC/HTTP2 spec requires the call result to travel in trailers:
Response → (Response-Headers *Length-Prefixed-Message Trailers) / Trailers-Only, and "Status must be sent in Trailers even if the status code is OK" (grpc/grpc, doc/PROTOCOL-HTTP2.md). Without trailer access, grpc-status / grpc-message are unreadable, and Trailers-Only error responses look like empty 200s.
- Integrity checksums in trailers (payload checksums sent after the body) cannot be verified.
- The same gap exists on the HTTP/1.1 side (
IOHttpClientAdapter), but HTTP/2 is where trailers are most common.
Why this belongs in dio rather than an interceptor / transformer / separate package: trailers exist only inside the adapter — they are dropped before the response pipeline sees anything, so no interceptor or transformer can recover them. Capture must happen in the adapter, and surfacing them usefully needs a small dio-side API.
Prior art
- Go
net/http: Response.Trailer (src/net/http/response.go) — a trailer map populated after the body is consumed.
- dart:io
HttpClientResponse does not expose trailers at all (no trailer API anywhere in sdk/lib/_http), so IOHttpClientAdapter has nothing to map today — worth noting for whichever option is chosen.
Proposal (options — all additive and non-breaking)
- Adapter-scoped, smallest surface: collect trailer headers in
Http2Adapter and expose them via a documented extra key on ResponseBody (similar to the existing extraKeyHttpVersion). No core API change; weaker discoverability, http2-only.
- Core API:
ResponseBody.trailers + Response.trailers (populated once the body stream completes), with each adapter mapping what its platform provides. Most usable and cross-adapter; requires core changes and per-adapter decisions (dart:io currently offers no API to map; browsers cannot provide trailers).
- Merge trailers into
Response.headers after body completion — not recommended: conflates the header section with trailers and breaks the assumption that headers are settled once the response headers arrive.
My inclination would be (2) for the long-term shape, or (1) as an incremental first step if maintainers prefer to keep the core surface untouched.
Compatibility
Any option is additive; no existing signature or default behavior changes. Interim (1xx) headers remain excluded regardless (see #2600 / #2601).
Issue body drafted with AI assistance (GLM), reviewed and submitted by a human.
Package
http2_adapter
Motivation
What cannot be done today: read HTTP/2 response trailers. The adapter discards them.
In HTTP/2, a server may send a trailer section as a final HEADERS frame (no
:status, END_STREAM set) after the response body (RFC 9113 §8.4, §8.8.5). TodayHttp2Adapter._fetchparses these frames and discards them:responseHeadersonly racily — observable only if they happened to arrive before the response object was built (Headers.mapreturns the live internal map), so it was never a usable API.Who needs this, and in which real-world scenario:
Response → (Response-Headers *Length-Prefixed-Message Trailers) / Trailers-Only, and "Status must be sent in Trailers even if the status code is OK" (grpc/grpc,doc/PROTOCOL-HTTP2.md). Without trailer access,grpc-status/grpc-messageare unreadable, andTrailers-Onlyerror responses look like empty 200s.IOHttpClientAdapter), but HTTP/2 is where trailers are most common.Why this belongs in dio rather than an interceptor / transformer / separate package: trailers exist only inside the adapter — they are dropped before the response pipeline sees anything, so no interceptor or transformer can recover them. Capture must happen in the adapter, and surfacing them usefully needs a small dio-side API.
Prior art
net/http:Response.Trailer(src/net/http/response.go) — a trailer map populated after the body is consumed.HttpClientResponsedoes not expose trailers at all (no trailer API anywhere insdk/lib/_http), soIOHttpClientAdapterhas nothing to map today — worth noting for whichever option is chosen.Proposal (options — all additive and non-breaking)
Http2Adapterand expose them via a documentedextrakey onResponseBody(similar to the existingextraKeyHttpVersion). No core API change; weaker discoverability, http2-only.ResponseBody.trailers+Response.trailers(populated once the body stream completes), with each adapter mapping what its platform provides. Most usable and cross-adapter; requires core changes and per-adapter decisions (dart:io currently offers no API to map; browsers cannot provide trailers).Response.headersafter body completion — not recommended: conflates the header section with trailers and breaks the assumption that headers are settled once the response headers arrive.My inclination would be (2) for the long-term shape, or (1) as an incremental first step if maintainers prefer to keep the core surface untouched.
Compatibility
Any option is additive; no existing signature or default behavior changes. Interim (1xx) headers remain excluded regardless (see #2600 / #2601).
Issue body drafted with AI assistance (GLM), reviewed and submitted by a human.