Class Http3GrpcBidiStreamHandler
GrpcBidiStreamHandler but, instead of being a
Netty pipeline handler, it is a plain helper driven by Http3MockServerHandler
(which already extends Netty's Http3RequestStreamInboundHandler and receives
frames incrementally via channelRead / channelInputClosed).
A QUIC stream is full-duplex, so the server can write response frames while the client is still sending request frames. The lifecycle is:
start()-- write the initial response HEADERS (:status=200,content-type=application/grpc, plus any configured headers) and any EAGER messages from theGrpcBidiResponse(honouring per-message delays);onData(byte[])-- feed inbound bytes to the incremental gRPC frame decoder; for each complete inbound message, convert protobuf to JSON, evaluate rules in order, and emit the first matching rule's responses as DATA frames;onInputClosed()-- the client half-closed (FIN); once all scheduled response writes have drained, write the trailing HEADERS carryinggrpc-statusand shut the QUIC stream output;onChannelInactive()-- the stream/connection was torn down; clearsresponseInProgresson the matched expectation via the completion callback.
All methods run on the QUIC stream's single event-loop thread, so the activeChains
counter that orders the trailing HEADERS after all (possibly delayed) response writes needs
no synchronization. The completion callback is guarded by an AtomicBoolean so it runs
exactly once across every terminal path.
Inbound (client-to-server) breakpoints. When an INBOUND_STREAM
breakpoint matcher matches this bidi stream at stream onset, the driver passes a non-null
inboundStreamId (plus the matched breakpoint's clientId/id and the WS registry). Each
inbound gRPC DATA frame is then parked in the StreamFrameBreakpointRegistry /
StreamFrameCallbackDispatcher before being decoded, and resumed (CONTINUE / MODIFY /
DROP / INJECT / CLOSE) by a dashboard or callback client. This is the HTTP/3 analogue of the
inbound interception in GrpcBidiStreamHandler.
Ordering & flow control. The QUIC driver
(Http3MockServerHandler) copies each DATA frame's bytes to a byte[] and
releases the Http3DataFrame before calling onData(byte[]), so no
ByteBuf is retained across a hold and the QUIC stream/connection flow-control window is
never pinned by a parked frame. To preserve per-frame ordering while a frame is parked, at most
one inbound frame is dispatched at a time; any frames the client sends while a frame is held are
buffered in heldInboundFrames and drained in order when the held frame resolves. That
buffer is bounded by the driver's existing maxRequestBodySize enforcement (the driver
caps total accumulated inbound bytes before calling onData). When inbound breakpoints
are inactive the frame takes a byte-for-byte-identical default path with zero added work.
-
Constructor Summary
ConstructorsConstructorDescriptionHttp3GrpcBidiStreamHandler(io.netty.channel.ChannelHandlerContext ctx, com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, GrpcBidiResponse config, Runnable completionCallback, MockServerLogger mockServerLogger) Constructs a bidi handler without inbound breakpoint support (default path).Http3GrpcBidiStreamHandler(io.netty.channel.ChannelHandlerContext ctx, com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, GrpcBidiResponse config, Runnable completionCallback, MockServerLogger mockServerLogger, Configuration configuration, String inboundStreamId, String inboundBreakpointClientId, String inboundBreakpointId, WebSocketClientRegistry webSocketClientRegistry) Constructs a bidi handler with optional inbound (client-to-server) breakpoint support. -
Method Summary
-
Constructor Details
-
Http3GrpcBidiStreamHandler
public Http3GrpcBidiStreamHandler(io.netty.channel.ChannelHandlerContext ctx, com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, GrpcBidiResponse config, Runnable completionCallback, MockServerLogger mockServerLogger) Constructs a bidi handler without inbound breakpoint support (default path). -
Http3GrpcBidiStreamHandler
public Http3GrpcBidiStreamHandler(io.netty.channel.ChannelHandlerContext ctx, com.google.protobuf.Descriptors.MethodDescriptor methodDescriptor, GrpcJsonMessageConverter converter, GrpcBidiResponse config, Runnable completionCallback, MockServerLogger mockServerLogger, Configuration configuration, String inboundStreamId, String inboundBreakpointClientId, String inboundBreakpointId, WebSocketClientRegistry webSocketClientRegistry) Constructs a bidi handler with optional inbound (client-to-server) breakpoint support. Inbound breakpoints are active only wheninboundStreamId,inboundBreakpointClientIdandwebSocketClientRegistryare all non-null (i.e. anINBOUND_STREAMbreakpoint matcher matched this stream at onset).- Parameters:
configuration- active server configuration (timeout / max-held rails); nullableinboundStreamId- unique stream id for inbound frame parking; null disables inbound breakpointsinboundBreakpointClientId- the matched inbound breakpoint's owning callback clientId; nullableinboundBreakpointId- the matched inbound breakpoint's id; nullablewebSocketClientRegistry- per-server WS registry for callback dispatch; null disables inbound breakpoints
-
-
Method Details
-
start
public void start()Write the initial response HEADERS and any eager messages. The top-level action delay (Action.getDelay()), if configured, delays the eager message stream (the HEADERS are sent promptly so inbound DATA frames never race ahead of them). -
onData
public void onData(byte[] bytes) Feed inbound request bytes. When inbound breakpoints are inactive this decodes complete gRPC frames and emits matching rule responses immediately (byte-for-byte default path). When active, the frame is parked at a breakpoint first (see class javadoc); frames that arrive while one is held are buffered in order. -
onInputClosed
public void onInputClosed()The client half-closed (END_STREAM). Finish once all scheduled responses have drained. -
onChannelInactive
public void onChannelInactive()The QUIC stream / connection was torn down. Evict any held inbound breakpoint frames (releasing their futures and the per-stream registry entry) and clear responseInProgress so a times-limited expectation is not left stuck when a bidi stream is abandoned without a clean END_STREAM.
-