Search in sources :

Example 1 with Http2StreamChannel

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);
    }
}
Also used : PrimitiveEntry(io.netty.util.collection.IntObjectMap.PrimitiveEntry) StreamException(io.netty.handler.codec.http2.Http2Exception.StreamException) UnsupportedMessageTypeException(io.netty.handler.codec.UnsupportedMessageTypeException)

Example 2 with Http2StreamChannel

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());
}
Also used : ChannelFuture(io.netty.channel.ChannelFuture) ClosedChannelException(java.nio.channels.ClosedChannelException) ChannelPromise(io.netty.channel.ChannelPromise) Http2TestUtil.anyChannelPromise(io.netty.handler.codec.http2.Http2TestUtil.anyChannelPromise) ChannelFutureListener(io.netty.channel.ChannelFutureListener) ArrayDeque(java.util.ArrayDeque) StreamException(io.netty.handler.codec.http2.Http2Exception.StreamException) ClosedChannelException(java.nio.channels.ClosedChannelException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) InvocationOnMock(org.mockito.invocation.InvocationOnMock) Test(org.junit.jupiter.api.Test)

Example 3 with Http2StreamChannel

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();
}
Also used : ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) ChannelHandler(io.netty.channel.ChannelHandler) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Consumer(io.netty.handler.codec.http2.LastInboundHandler.Consumer) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ChannelInboundHandlerAdapter(io.netty.channel.ChannelInboundHandlerAdapter) Test(org.junit.jupiter.api.Test)

Example 4 with Http2StreamChannel

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();
        }
    });
}
Also used : ChannelFuture(io.netty.channel.ChannelFuture) InvocationOnMock(org.mockito.invocation.InvocationOnMock) ChannelPromise(io.netty.channel.ChannelPromise) Http2TestUtil.anyChannelPromise(io.netty.handler.codec.http2.Http2TestUtil.anyChannelPromise) Executable(org.junit.jupiter.api.function.Executable) StreamException(io.netty.handler.codec.http2.Http2Exception.StreamException) Test(org.junit.jupiter.api.Test)

Example 5 with Http2StreamChannel

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());
}
Also used : ChannelFuture(io.netty.channel.ChannelFuture) ChannelPromise(io.netty.channel.ChannelPromise) Http2TestUtil.anyChannelPromise(io.netty.handler.codec.http2.Http2TestUtil.anyChannelPromise) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) StreamException(io.netty.handler.codec.http2.Http2Exception.StreamException) ClosedChannelException(java.nio.channels.ClosedChannelException) InvocationOnMock(org.mockito.invocation.InvocationOnMock) ChannelInboundHandlerAdapter(io.netty.channel.ChannelInboundHandlerAdapter) Test(org.junit.jupiter.api.Test)

Aggregations

Test (org.junit.jupiter.api.Test)14 ChannelHandlerContext (io.netty.channel.ChannelHandlerContext)9 ChannelInboundHandlerAdapter (io.netty.channel.ChannelInboundHandlerAdapter)9 StreamException (io.netty.handler.codec.http2.Http2Exception.StreamException)9 ChannelPromise (io.netty.channel.ChannelPromise)7 Http2TestUtil.anyChannelPromise (io.netty.handler.codec.http2.Http2TestUtil.anyChannelPromise)7 ClosedChannelException (java.nio.channels.ClosedChannelException)6 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)6 Channel (io.netty.channel.Channel)5 ChannelFuture (io.netty.channel.ChannelFuture)5 Http2StreamChannel (io.netty.handler.codec.http2.Http2StreamChannel)5 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)5 InvocationOnMock (org.mockito.invocation.InvocationOnMock)4 ChannelHandler (io.netty.channel.ChannelHandler)3 NioSocketChannel (io.netty.channel.socket.nio.NioSocketChannel)3 Http2StreamChannelBootstrap (io.netty.handler.codec.http2.Http2StreamChannelBootstrap)3 Consumer (io.netty.handler.codec.http2.LastInboundHandler.Consumer)3 ArrayList (java.util.ArrayList)3 MetricRegistry (com.codahale.metrics.MetricRegistry)2 MultiplexedChannelRecordTest (com.github.ambry.network.http2.MultiplexedChannelRecordTest)2