Class StreamAddressedContentHandler
- All Implemented Interfaces:
io.netty.channel.ChannelHandler,io.netty.channel.ChannelOutboundHandler
StreamAddressedHttpContent into the child-channel equivalent when a streaming
response is written on an Http2MultiplexHandler child channel.
The StreamAddressedHttpContent wrapper carries two pieces of out-of-band state — a stream id
and an endStream() flag. On the multiplex path every stream has its own
Http2StreamChannel — the channel is the stream — so the
streamId() field is redundant here. Only the endStream() flag still carries
information the child pipeline cannot otherwise recover.
Why this handler is required: without it the wrapper reaches
Http2StreamFrameToHttpObjectCodec.encode(io.netty.channel.ChannelHandlerContext, io.netty.handler.codec.http.HttpObject, java.util.List<java.lang.Object>), whose only
bare-HttpContent branch emits new DefaultHttp2DataFrame(content.retain(), false) —
it hard-codes endStream=false. The terminal frame's endStream=true is therefore
silently discarded, the stream is never closed, and an SSE/NDJSON/AWS-event-stream client receives
every event and then hangs until it times out. Nothing is logged (GitHub issue #2669 follow-up).
The translation preserves the flag by picking the HttpObject subtype the codec maps
correctly:
endStream() == true→DefaultLastHttpContent. The codec'sencodeLastContentsetsneedFiller = truefor a non-FullHttpMessagewith empty trailers, so it emitsDefaultHttp2DataFrame(content, endStream=true)even for an empty terminal buffer.endStream() == false→ plainDefaultHttpContent, which the codec maps to a non-terminal DATA frame exactly as the non-terminal chunks already work today.
Reference counting: the replacement content wraps the same
ByteBuf, so buffer ownership transfers with it. The wrapper holds no
resource of its own beyond that buffer, so this handler neither retains nor releases anything —
it just swaps the object that carries the buffer downstream.
The handler is @Sharable and stateless, so a single INSTANCE
can be installed on every child pipeline, matching how ConnectionScopeHandler.INSTANCE is
used.
-
Nested Class Summary
Nested classes/interfaces inherited from interface io.netty.channel.ChannelHandler
io.netty.channel.ChannelHandler.Sharable -
Field Summary
Fields -
Constructor Summary
Constructors -
Method Summary
Methods inherited from class io.netty.channel.ChannelOutboundHandlerAdapter
bind, close, connect, deregister, disconnect, flush, readMethods inherited from class io.netty.channel.ChannelHandlerAdapter
ensureNotSharable, exceptionCaught, handlerAdded, handlerRemoved, isSharableMethods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface io.netty.channel.ChannelHandler
exceptionCaught, handlerAdded, handlerRemoved
-
Field Details
-
INSTANCE
-
-
Constructor Details
-
StreamAddressedContentHandler
public StreamAddressedContentHandler()
-
-
Method Details
-
write
public void write(io.netty.channel.ChannelHandlerContext ctx, Object msg, io.netty.channel.ChannelPromise promise) throws Exception - Specified by:
writein interfaceio.netty.channel.ChannelOutboundHandler- Overrides:
writein classio.netty.channel.ChannelOutboundHandlerAdapter- Throws:
Exception
-