Class Http2StreamIds
MockServer's HTTP/2 server pipeline uses HttpToHttp2ConnectionHandler, which routes an
outbound HttpMessage onto an HTTP/2 stream by reading the x-http2-stream-id
extension header. When that header is absent Netty falls back to
connection().local().incrementAndGetNextStreamId() — a new, server-initiated
stream. A response written on a server-initiated stream is never delivered to the client that
made the request, so the client simply hangs until it times out. Nothing is logged and nothing
fails, which is why this defect class has repeatedly shipped undetected:
- GitHub issue #2419 — server-streaming gRPC delivered zero messages over HTTP/2;
- SSE responses, streaming bodies, the metrics endpoint and MCP — all of which built a Netty response head by hand and wrote it straight to the channel.
Every one of those sites bypassed MockServerHttpResponseToFullHttpResponse, which was the
only code that knew about the header. Consolidating the knowledge here means a new direct-write
site has one obvious thing to call, and Http2StreamIdAuditHandler makes a site that
forgets it fail loudly instead of silently.
All methods first remove any existing x-http2-stream-id header before adding the
derived one. That is deliberate: a stream id which leaked in as an ordinary model header (for
example from a forwarded or proxied upstream HTTP/2 response) carries a foreign stream
id, and writing on it triggers a PROTOCOL_ERROR/GOAWAY that hangs the client just
as badly as the missing-header case. The stamped value is therefore always the single source of
truth, and stamping is idempotent.
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final io.netty.util.AsciiStringx-http2-stream-id— the Netty HTTP/1-to-HTTP/2 extension header used to route an outbound response head onto the stream that carried the request. -
Method Summary
Modifier and TypeMethodDescriptionstatic voidStampstreamIdontonettyMessage, replacing any header already present.static voidstampFromNettyRequest(io.netty.handler.codec.http.HttpMessage nettyMessage, io.netty.handler.codec.http.HttpMessage inboundNettyRequest) Stamp the stream id carried by an inbound Netty request onto the outbound Netty response head.static voidstampFromRequest(io.netty.handler.codec.http.HttpMessage nettyMessage, HttpRequest request) Stamp the stream id carried by a MockServer modelHttpRequestonto the outbound Netty response head, so the response goes back down the stream the request arrived on.static IntegerstreamIdOf(io.netty.handler.codec.http.HttpMessage nettyMessage) The stream id carried by a Netty message, ornullwhen there is none (HTTP/1.1) or the header value is not a valid integer.
-
Field Details
-
STREAM_ID_HEADER
public static final io.netty.util.AsciiString STREAM_ID_HEADERx-http2-stream-id— the Netty HTTP/1-to-HTTP/2 extension header used to route an outbound response head onto the stream that carried the request.
-
-
Method Details
-
stamp
StampstreamIdontonettyMessage, replacing any header already present. AnullstreamId(the HTTP/1.1 case) strips the header and adds nothing, so this is safe to call unconditionally from transport-agnostic code. -
stampFromRequest
public static void stampFromRequest(io.netty.handler.codec.http.HttpMessage nettyMessage, HttpRequest request) Stamp the stream id carried by a MockServer modelHttpRequestonto the outbound Netty response head, so the response goes back down the stream the request arrived on. -
stampFromNettyRequest
public static void stampFromNettyRequest(io.netty.handler.codec.http.HttpMessage nettyMessage, io.netty.handler.codec.http.HttpMessage inboundNettyRequest) Stamp the stream id carried by an inbound Netty request onto the outbound Netty response head. For handlers that work on raw Netty objects and never build a MockServer model request — on HTTP/2 the inbound request carriesx-http2-stream-id, added byInboundHttp2ToHttpAdapter. A no-op on HTTP/1.1, where there is no id to copy. -
streamIdOf
The stream id carried by a Netty message, ornullwhen there is none (HTTP/1.1) or the header value is not a valid integer.
-