Class Http2StreamIdAuditHandler

java.lang.Object
io.netty.channel.ChannelHandlerAdapter
io.netty.channel.ChannelInboundHandlerAdapter
io.netty.channel.ChannelDuplexHandler
org.mockserver.netty.unification.Http2StreamIdAuditHandler
All Implemented Interfaces:
io.netty.channel.ChannelHandler, io.netty.channel.ChannelInboundHandler, io.netty.channel.ChannelOutboundHandler

public class Http2StreamIdAuditHandler extends io.netty.channel.ChannelDuplexHandler
Makes the "response written on a phantom HTTP/2 stream" defect class loud instead of silent.

On the HTTP/2 server pipeline, HttpToHttp2ConnectionHandler routes an outbound response head onto a stream by reading its x-http2-stream-id header. When the header is missing it does not fail — it silently allocates a fresh server-initiated stream, so the client never receives the response and simply hangs until its own timeout fires. Nothing is logged, no exception is raised, and every server-side test that inspects model objects still passes. That is how GitHub issue #2419 (server-streaming gRPC delivering zero messages) shipped, and how the SSE, streaming-body, metrics and MCP instances of the same bug shipped alongside it.

This handler sits immediately downstream of the HTTP/2 connection handler, so every outbound response head written by any handler added after it passes through here. A head without a stream id is always a bug, so it is logged at WARN naming the handler that is about to mis-route it.

It deliberately only warns; it neither throws nor tries to repair the head. Repair is not possible safely: this pipeline multiplexes many concurrent streams over one connection, and a streaming response is written asynchronously long after its request was read, so any stream id this handler could infer from "the most recent inbound request" would sometimes be another client's stream. Writing a response onto the wrong stream leaks one client's data to another, which is strictly worse than the hang it would be fixing. Correctness therefore has to come from the write site stamping the id it already holds (Http2StreamIds); this handler exists to ensure a site that forgets is discovered in the first test run rather than in production.

  • Nested Class Summary

    Nested classes/interfaces inherited from interface io.netty.channel.ChannelHandler

    io.netty.channel.ChannelHandler.Sharable
  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    write(io.netty.channel.ChannelHandlerContext ctx, Object msg, io.netty.channel.ChannelPromise promise)
     

    Methods inherited from class io.netty.channel.ChannelDuplexHandler

    bind, close, connect, deregister, disconnect, flush, read

    Methods inherited from class io.netty.channel.ChannelInboundHandlerAdapter

    channelActive, channelInactive, channelRead, channelReadComplete, channelRegistered, channelUnregistered, channelWritabilityChanged, exceptionCaught, userEventTriggered

    Methods inherited from class io.netty.channel.ChannelHandlerAdapter

    ensureNotSharable, handlerAdded, handlerRemoved, isSharable

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

    Methods inherited from interface io.netty.channel.ChannelHandler

    handlerAdded, handlerRemoved
  • Constructor Details

    • Http2StreamIdAuditHandler

      public Http2StreamIdAuditHandler(MockServerLogger mockServerLogger)
  • Method Details

    • write

      public void write(io.netty.channel.ChannelHandlerContext ctx, Object msg, io.netty.channel.ChannelPromise promise) throws Exception
      Specified by:
      write in interface io.netty.channel.ChannelOutboundHandler
      Overrides:
      write in class io.netty.channel.ChannelDuplexHandler
      Throws:
      Exception