use of io.netty.handler.codec.http2.Http2StreamChannel in project netty by netty.
the class Http2MultiplexCodec method channelRead.
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (!(msg instanceof Http2Frame)) {
ctx.fireChannelRead(msg);
return;
}
if (msg instanceof Http2StreamFrame) {
Http2StreamFrame frame = (Http2StreamFrame) msg;
int streamId = frame.streamId();
Http2StreamChannel childChannel = childChannels.get(streamId);
if (childChannel == null) {
// TODO: Combine with DefaultHttp2ConnectionDecoder.shouldIgnoreHeadersOrDataFrame logic.
ReferenceCountUtil.release(msg);
throw new StreamException(streamId, STREAM_CLOSED, format("Received %s frame for an unknown stream %d", frame.name(), streamId));
}
fireChildReadAndRegister(childChannel, frame);
} else if (msg instanceof Http2GoAwayFrame) {
Http2GoAwayFrame goAwayFrame = (Http2GoAwayFrame) msg;
for (PrimitiveEntry<Http2StreamChannel> entry : childChannels.entries()) {
Http2StreamChannel childChannel = entry.value();
int streamId = entry.key();
if (streamId > goAwayFrame.lastStreamId() && isOutboundStream(server, streamId)) {
childChannel.pipeline().fireUserEventTriggered(goAwayFrame.retainedDuplicate());
}
}
goAwayFrame.release();
} else {
// It's safe to release, as UnsupportedMessageTypeException just calls msg.getClass()
ReferenceCountUtil.release(msg);
throw new UnsupportedMessageTypeException(msg);
}
}
use of io.netty.handler.codec.http2.Http2StreamChannel in project netty by netty.
the class Http2MultiplexTest method channelClosedWhenWriteFutureFails.
@Test
public void channelClosedWhenWriteFutureFails() {
final Queue<ChannelPromise> writePromises = new ArrayDeque<ChannelPromise>();
LastInboundHandler inboundHandler = new LastInboundHandler();
Http2StreamChannel childChannel = newInboundStream(3, false, inboundHandler);
assertTrue(childChannel.isOpen());
assertTrue(childChannel.isActive());
final AtomicBoolean channelOpen = new AtomicBoolean(true);
final AtomicBoolean channelActive = new AtomicBoolean(true);
Http2Headers headers = new DefaultHttp2Headers();
when(frameWriter.writeHeaders(eqCodecCtx(), anyInt(), eq(headers), anyInt(), anyBoolean(), any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
@Override
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
ChannelPromise promise = invocationOnMock.getArgument(5);
writePromises.offer(promise);
return promise;
}
});
ChannelFuture f = childChannel.writeAndFlush(new DefaultHttp2HeadersFrame(headers));
assertFalse(f.isDone());
f.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
channelOpen.set(future.channel().isOpen());
channelActive.set(future.channel().isActive());
}
});
ChannelPromise first = writePromises.poll();
first.setFailure(new ClosedChannelException());
f.awaitUninterruptibly();
assertFalse(channelOpen.get());
assertFalse(channelActive.get());
assertFalse(childChannel.isActive());
}
use of io.netty.handler.codec.http2.Http2StreamChannel in project netty by netty.
the class Http2MultiplexTest method endOfStreamDoesNotDiscardData.
@Test
public void endOfStreamDoesNotDiscardData() {
AtomicInteger numReads = new AtomicInteger(1);
final AtomicBoolean shouldDisableAutoRead = new AtomicBoolean();
Consumer<ChannelHandlerContext> ctxConsumer = new Consumer<ChannelHandlerContext>() {
@Override
public void accept(ChannelHandlerContext obj) {
if (shouldDisableAutoRead.get()) {
obj.channel().config().setAutoRead(false);
}
}
};
LastInboundHandler inboundHandler = new LastInboundHandler(ctxConsumer);
Http2StreamChannel childChannel = newInboundStream(3, false, numReads, inboundHandler);
childChannel.config().setAutoRead(false);
Http2DataFrame dataFrame1 = new DefaultHttp2DataFrame(bb("1")).stream(childChannel.stream());
Http2DataFrame dataFrame2 = new DefaultHttp2DataFrame(bb("2")).stream(childChannel.stream());
Http2DataFrame dataFrame3 = new DefaultHttp2DataFrame(bb("3")).stream(childChannel.stream());
Http2DataFrame dataFrame4 = new DefaultHttp2DataFrame(bb("4")).stream(childChannel.stream());
assertEquals(new DefaultHttp2HeadersFrame(request).stream(childChannel.stream()), inboundHandler.readInbound());
ChannelHandler readCompleteSupressHandler = new ChannelInboundHandlerAdapter() {
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
// We want to simulate the parent channel calling channelRead and delay calling channelReadComplete.
}
};
parentChannel.pipeline().addFirst(readCompleteSupressHandler);
frameInboundWriter.writeInboundData(childChannel.stream().id(), bb("1"), 0, false);
assertEqualsAndRelease(dataFrame1, inboundHandler.<Http2DataFrame>readInbound());
// Deliver frames, and then a stream closed while read is inactive.
frameInboundWriter.writeInboundData(childChannel.stream().id(), bb("2"), 0, false);
frameInboundWriter.writeInboundData(childChannel.stream().id(), bb("3"), 0, false);
frameInboundWriter.writeInboundData(childChannel.stream().id(), bb("4"), 0, false);
shouldDisableAutoRead.set(true);
childChannel.config().setAutoRead(true);
numReads.set(1);
frameInboundWriter.writeInboundRstStream(childChannel.stream().id(), Http2Error.NO_ERROR.code());
// Detecting EOS should flush all pending data regardless of read calls.
assertEqualsAndRelease(dataFrame2, inboundHandler.<Http2DataFrame>readInbound());
assertNull(inboundHandler.readInbound());
// As we limited the number to 1 we also need to call read() again.
childChannel.read();
assertEqualsAndRelease(dataFrame3, inboundHandler.<Http2DataFrame>readInbound());
assertEqualsAndRelease(dataFrame4, inboundHandler.<Http2DataFrame>readInbound());
Http2ResetFrame resetFrame = useUserEventForResetFrame() ? inboundHandler.<Http2ResetFrame>readUserEvent() : inboundHandler.<Http2ResetFrame>readInbound();
assertEquals(childChannel.stream(), resetFrame.stream());
assertEquals(Http2Error.NO_ERROR.code(), resetFrame.errorCode());
assertNull(inboundHandler.readInbound());
// Now we want to call channelReadComplete and simulate the end of the read loop.
parentChannel.pipeline().remove(readCompleteSupressHandler);
parentChannel.flushInbound();
childChannel.closeFuture().syncUninterruptibly();
}
use of io.netty.handler.codec.http2.Http2StreamChannel in project netty by netty.
the class Http2MultiplexTest method streamClosedErrorTranslatedToClosedChannelExceptionOnWrites.
@Test
public void streamClosedErrorTranslatedToClosedChannelExceptionOnWrites() throws Exception {
LastInboundHandler inboundHandler = new LastInboundHandler();
final Http2StreamChannel childChannel = newOutboundStream(inboundHandler);
assertTrue(childChannel.isActive());
Http2Headers headers = new DefaultHttp2Headers();
when(frameWriter.writeHeaders(eqCodecCtx(), anyInt(), eq(headers), anyInt(), anyBoolean(), any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
@Override
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
return ((ChannelPromise) invocationOnMock.getArgument(5)).setFailure(new StreamException(childChannel.stream().id(), Http2Error.STREAM_CLOSED, "Stream Closed"));
}
});
final ChannelFuture future = childChannel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()));
parentChannel.flush();
assertFalse(childChannel.isActive());
assertFalse(childChannel.isOpen());
inboundHandler.checkException();
assertThrows(ClosedChannelException.class, new Executable() {
@Override
public void execute() {
future.syncUninterruptibly();
}
});
}
use of io.netty.handler.codec.http2.Http2StreamChannel in project netty by netty.
the class Http2MultiplexTest method outboundStreamShouldNotWriteResetFrameOnClose_IfStreamDidntExist.
@Test
public void outboundStreamShouldNotWriteResetFrameOnClose_IfStreamDidntExist() {
when(frameWriter.writeHeaders(eqCodecCtx(), anyInt(), any(Http2Headers.class), anyInt(), anyBoolean(), any(ChannelPromise.class))).thenAnswer(new Answer<ChannelFuture>() {
private boolean headersWritten;
@Override
public ChannelFuture answer(InvocationOnMock invocationOnMock) {
// refuses to allocate a new stream due to having received a GOAWAY.
if (!headersWritten) {
headersWritten = true;
return ((ChannelPromise) invocationOnMock.getArgument(5)).setFailure(new Exception("boom"));
}
return ((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess();
}
});
Http2StreamChannel childChannel = newOutboundStream(new ChannelInboundHandlerAdapter() {
@Override
public void channelActive(ChannelHandlerContext ctx) {
ctx.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers()));
ctx.fireChannelActive();
}
});
assertFalse(childChannel.isActive());
childChannel.close();
parentChannel.runPendingTasks();
// The channel was never active so we should not generate a RST frame.
verify(frameWriter, never()).writeRstStream(eqCodecCtx(), eqStreamId(childChannel), anyLong(), anyChannelPromise());
assertTrue(parentChannel.outboundMessages().isEmpty());
}
Aggregations