Skip to content

[RFC] http2_adapter: expose response trailers (currently dropped) #2602

Description

@AlexV525

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)

  1. 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.
  2. 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).
  3. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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