Search in sources :

Example 36 with Http2Exception

use of io.netty.handler.codec.http2.Http2Exception in project netty by netty.

the class Http2ConnectionRoundtripTest method setGracefulShutdownTime.

private static void setGracefulShutdownTime(Channel channel, final Http2ConnectionHandler handler, final long millis) throws InterruptedException {
    final CountDownLatch latch = new CountDownLatch(1);
    runInChannel(channel, new Http2Runnable() {

        @Override
        public void run() throws Http2Exception {
            handler.gracefulShutdownTimeoutMillis(millis);
            latch.countDown();
        }
    });
    assertTrue(latch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
}
Also used : Http2Runnable(io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable) CountDownLatch(java.util.concurrent.CountDownLatch)

Example 37 with Http2Exception

use of io.netty.handler.codec.http2.Http2Exception in project netty by netty.

the class Http2ConnectionRoundtripTest method listenerExceptionShouldCloseConnection.

@Test
public void listenerExceptionShouldCloseConnection() throws Exception {
    final Http2Headers headers = dummyHeaders();
    doThrow(new RuntimeException("Fake Exception")).when(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(3), eq(headers), eq(0), eq((short) 16), eq(false), eq(0), eq(false));
    bootstrapEnv(1, 0, 1, 1);
    // Create a latch to track when the close occurs.
    final CountDownLatch closeLatch = new CountDownLatch(1);
    clientChannel.closeFuture().addListener(new ChannelFutureListener() {

        @Override
        public void operationComplete(ChannelFuture future) throws Exception {
            closeLatch.countDown();
        }
    });
    // Create a single stream by sending a HEADERS frame to the server.
    runInChannel(clientChannel, new Http2Runnable() {

        @Override
        public void run() throws Http2Exception {
            http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false, newPromise());
            http2Client.flush(ctx());
        }
    });
    // Wait for the server to create the stream.
    assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
    assertTrue(requestLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
    // Wait for the close to occur.
    assertTrue(closeLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
    assertFalse(clientChannel.isOpen());
}
Also used : ChannelFuture(io.netty.channel.ChannelFuture) Http2Runnable(io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) CountDownLatch(java.util.concurrent.CountDownLatch) ChannelFutureListener(io.netty.channel.ChannelFutureListener) IllegalReferenceCountException(io.netty.util.IllegalReferenceCountException) ExecutionException(java.util.concurrent.ExecutionException) Test(org.junit.jupiter.api.Test)

Example 38 with Http2Exception

use of io.netty.handler.codec.http2.Http2Exception in project netty by netty.

the class Http2ConnectionRoundtripTest method stressTest.

@Test
public void stressTest() throws Exception {
    final Http2Headers headers = dummyHeaders();
    int length = 10;
    final ByteBuf data = randomBytes(length);
    final String dataAsHex = ByteBufUtil.hexDump(data);
    final long pingData = 8;
    final int numStreams = 2000;
    // Collect all the ping buffers as we receive them at the server.
    final long[] receivedPings = new long[numStreams];
    doAnswer(new Answer<Void>() {

        int nextIndex;

        @Override
        public Void answer(InvocationOnMock in) throws Throwable {
            receivedPings[nextIndex++] = (Long) in.getArguments()[1];
            return null;
        }
    }).when(serverListener).onPingRead(any(ChannelHandlerContext.class), any(Long.class));
    // Collect all the data buffers as we receive them at the server.
    final StringBuilder[] receivedData = new StringBuilder[numStreams];
    doAnswer(new Answer<Integer>() {

        @Override
        public Integer answer(InvocationOnMock in) throws Throwable {
            int streamId = (Integer) in.getArguments()[1];
            ByteBuf buf = (ByteBuf) in.getArguments()[2];
            int padding = (Integer) in.getArguments()[3];
            int processedBytes = buf.readableBytes() + padding;
            int streamIndex = (streamId - 3) / 2;
            StringBuilder builder = receivedData[streamIndex];
            if (builder == null) {
                builder = new StringBuilder(dataAsHex.length());
                receivedData[streamIndex] = builder;
            }
            builder.append(ByteBufUtil.hexDump(buf));
            return processedBytes;
        }
    }).when(serverListener).onDataRead(any(ChannelHandlerContext.class), anyInt(), any(ByteBuf.class), anyInt(), anyBoolean());
    try {
        bootstrapEnv(numStreams * length, 1, numStreams * 4, numStreams);
        runInChannel(clientChannel, new Http2Runnable() {

            @Override
            public void run() throws Http2Exception {
                int upperLimit = 3 + 2 * numStreams;
                for (int streamId = 3; streamId < upperLimit; streamId += 2) {
                    // Send a bunch of data on each stream.
                    http2Client.encoder().writeHeaders(ctx(), streamId, headers, 0, (short) 16, false, 0, false, newPromise());
                    http2Client.encoder().writePing(ctx(), false, pingData, newPromise());
                    http2Client.encoder().writeData(ctx(), streamId, data.retainedSlice(), 0, false, newPromise());
                    // Write trailers.
                    http2Client.encoder().writeHeaders(ctx(), streamId, headers, 0, (short) 16, false, 0, true, newPromise());
                    http2Client.flush(ctx());
                }
            }
        });
        // Wait for all frames to be received.
        assertTrue(serverSettingsAckLatch.await(60, SECONDS));
        assertTrue(trailersLatch.await(60, SECONDS));
        verify(serverListener, times(numStreams)).onHeadersRead(any(ChannelHandlerContext.class), anyInt(), eq(headers), eq(0), eq((short) 16), eq(false), eq(0), eq(false));
        verify(serverListener, times(numStreams)).onHeadersRead(any(ChannelHandlerContext.class), anyInt(), eq(headers), eq(0), eq((short) 16), eq(false), eq(0), eq(true));
        verify(serverListener, times(numStreams)).onPingRead(any(ChannelHandlerContext.class), any(long.class));
        verify(serverListener, never()).onDataRead(any(ChannelHandlerContext.class), anyInt(), any(ByteBuf.class), eq(0), eq(true));
        for (StringBuilder builder : receivedData) {
            assertEquals(dataAsHex, builder.toString());
        }
        for (long receivedPing : receivedPings) {
            assertEquals(pingData, receivedPing);
        }
    } finally {
        // Don't wait for server to close streams
        setClientGracefulShutdownTime(0);
        data.release();
    }
}
Also used : Http2Runnable(io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) AsciiString(io.netty.util.AsciiString) Http2TestUtil.randomString(io.netty.handler.codec.http2.Http2TestUtil.randomString) ByteBuf(io.netty.buffer.ByteBuf) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) InvocationOnMock(org.mockito.invocation.InvocationOnMock) Mockito.anyLong(org.mockito.Mockito.anyLong) Test(org.junit.jupiter.api.Test)

Example 39 with Http2Exception

use of io.netty.handler.codec.http2.Http2Exception in project netty by netty.

the class Http2ConnectionRoundtripTest method encodeViolatesMaxHeaderListSizeCanStillUseConnection.

@Test
public void encodeViolatesMaxHeaderListSizeCanStillUseConnection() throws Exception {
    bootstrapEnv(1, 2, 1, 0, 0);
    final CountDownLatch serverSettingsAckLatch1 = new CountDownLatch(2);
    final CountDownLatch serverSettingsAckLatch2 = new CountDownLatch(3);
    final CountDownLatch clientSettingsLatch1 = new CountDownLatch(3);
    final CountDownLatch serverRevHeadersLatch = new CountDownLatch(1);
    final CountDownLatch clientHeadersLatch = new CountDownLatch(1);
    final CountDownLatch clientDataWrite = new CountDownLatch(1);
    final AtomicReference<Throwable> clientHeadersWriteException = new AtomicReference<Throwable>();
    final AtomicReference<Throwable> clientHeadersWriteException2 = new AtomicReference<Throwable>();
    final AtomicReference<Throwable> clientDataWriteException = new AtomicReference<Throwable>();
    final Http2Headers headers = dummyHeaders();
    doAnswer(new Answer<Void>() {

        @Override
        public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
            serverSettingsAckLatch1.countDown();
            serverSettingsAckLatch2.countDown();
            return null;
        }
    }).when(serverListener).onSettingsAckRead(any(ChannelHandlerContext.class));
    doAnswer(new Answer<Void>() {

        @Override
        public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
            clientSettingsLatch1.countDown();
            return null;
        }
    }).when(clientListener).onSettingsRead(any(ChannelHandlerContext.class), any(Http2Settings.class));
    // Manually add a listener for when we receive the expected headers on the server.
    doAnswer(new Answer<Void>() {

        @Override
        public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
            serverRevHeadersLatch.countDown();
            return null;
        }
    }).when(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5), eq(headers), anyInt(), anyShort(), anyBoolean(), eq(0), eq(true));
    // Set the maxHeaderListSize to 100 so we may be able to write some headers, but not all. We want to verify
    // that we don't corrupt state if some can be written but not all.
    runInChannel(serverConnectedChannel, new Http2Runnable() {

        @Override
        public void run() throws Http2Exception {
            http2Server.encoder().writeSettings(serverCtx(), new Http2Settings().copyFrom(http2Server.decoder().localSettings()).maxHeaderListSize(100), serverNewPromise());
            http2Server.flush(serverCtx());
        }
    });
    assertTrue(serverSettingsAckLatch1.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
    runInChannel(clientChannel, new Http2Runnable() {

        @Override
        public void run() throws Http2Exception {
            http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, false, newPromise()).addListener(new ChannelFutureListener() {

                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    clientHeadersWriteException.set(future.cause());
                }
            });
            // It is expected that this write should fail locally and the remote peer will never see this.
            http2Client.encoder().writeData(ctx(), 3, Unpooled.buffer(), 0, true, newPromise()).addListener(new ChannelFutureListener() {

                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    clientDataWriteException.set(future.cause());
                    clientDataWrite.countDown();
                }
            });
            http2Client.flush(ctx());
        }
    });
    assertTrue(clientDataWrite.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
    assertNotNull(clientHeadersWriteException.get(), "Header encode should have exceeded maxHeaderListSize!");
    assertNotNull(clientDataWriteException.get(), "Data on closed stream should fail!");
    // Set the maxHeaderListSize to the max value so we can send the headers.
    runInChannel(serverConnectedChannel, new Http2Runnable() {

        @Override
        public void run() throws Http2Exception {
            http2Server.encoder().writeSettings(serverCtx(), new Http2Settings().copyFrom(http2Server.decoder().localSettings()).maxHeaderListSize(Http2CodecUtil.MAX_HEADER_LIST_SIZE), serverNewPromise());
            http2Server.flush(serverCtx());
        }
    });
    assertTrue(clientSettingsLatch1.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
    assertTrue(serverSettingsAckLatch2.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
    runInChannel(clientChannel, new Http2Runnable() {

        @Override
        public void run() throws Http2Exception {
            http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, true, newPromise()).addListener(new ChannelFutureListener() {

                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    clientHeadersWriteException2.set(future.cause());
                    clientHeadersLatch.countDown();
                }
            });
            http2Client.flush(ctx());
        }
    });
    assertTrue(clientHeadersLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
    assertNull(clientHeadersWriteException2.get(), "Client write of headers should succeed with increased header list size!");
    assertTrue(serverRevHeadersLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
    verify(serverListener, never()).onDataRead(any(ChannelHandlerContext.class), anyInt(), any(ByteBuf.class), anyInt(), anyBoolean());
    // Verify that no errors have been received.
    verify(serverListener, never()).onGoAwayRead(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class));
    verify(serverListener, never()).onRstStreamRead(any(ChannelHandlerContext.class), anyInt(), anyLong());
    verify(clientListener, never()).onGoAwayRead(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class));
    verify(clientListener, never()).onRstStreamRead(any(ChannelHandlerContext.class), anyInt(), anyLong());
}
Also used : ChannelFuture(io.netty.channel.ChannelFuture) Http2Runnable(io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable) AtomicReference(java.util.concurrent.atomic.AtomicReference) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) CountDownLatch(java.util.concurrent.CountDownLatch) ByteBuf(io.netty.buffer.ByteBuf) ChannelFutureListener(io.netty.channel.ChannelFutureListener) InvocationOnMock(org.mockito.invocation.InvocationOnMock) Test(org.junit.jupiter.api.Test)

Example 40 with Http2Exception

use of io.netty.handler.codec.http2.Http2Exception in project netty by netty.

the class Http2ConnectionRoundtripTest method writeOfEmptyReleasedBufferQueuedInFlowControllerShouldFail.

private void writeOfEmptyReleasedBufferQueuedInFlowControllerShouldFail(final WriteEmptyBufferMode mode) throws Exception {
    bootstrapEnv(1, 1, 2, 1);
    final ChannelPromise emptyDataPromise = newPromise();
    runInChannel(clientChannel, new Http2Runnable() {

        @Override
        public void run() throws Http2Exception {
            http2Client.encoder().writeHeaders(ctx(), 3, EmptyHttp2Headers.INSTANCE, 0, (short) 16, false, 0, false, newPromise());
            ByteBuf emptyBuf = Unpooled.buffer();
            emptyBuf.release();
            switch(mode) {
                case SINGLE_END_OF_STREAM:
                    http2Client.encoder().writeData(ctx(), 3, emptyBuf, 0, true, emptyDataPromise);
                    break;
                case SECOND_END_OF_STREAM:
                    http2Client.encoder().writeData(ctx(), 3, emptyBuf, 0, false, emptyDataPromise);
                    http2Client.encoder().writeData(ctx(), 3, randomBytes(8), 0, true, newPromise());
                    break;
                case SINGLE_WITH_TRAILERS:
                    http2Client.encoder().writeData(ctx(), 3, emptyBuf, 0, false, emptyDataPromise);
                    http2Client.encoder().writeHeaders(ctx(), 3, EmptyHttp2Headers.INSTANCE, 0, (short) 16, false, 0, true, newPromise());
                    break;
                case SECOND_WITH_TRAILERS:
                    http2Client.encoder().writeData(ctx(), 3, emptyBuf, 0, false, emptyDataPromise);
                    http2Client.encoder().writeData(ctx(), 3, randomBytes(8), 0, false, newPromise());
                    http2Client.encoder().writeHeaders(ctx(), 3, EmptyHttp2Headers.INSTANCE, 0, (short) 16, false, 0, true, newPromise());
                    break;
                default:
                    throw new Error();
            }
            http2Client.flush(ctx());
        }
    });
    ExecutionException e = assertThrows(ExecutionException.class, new Executable() {

        @Override
        public void execute() throws Throwable {
            emptyDataPromise.get();
        }
    });
    assertThat(e.getCause(), is(instanceOf(IllegalReferenceCountException.class)));
}
Also used : Http2Runnable(io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable) ChannelPromise(io.netty.channel.ChannelPromise) ByteBuf(io.netty.buffer.ByteBuf) ExecutionException(java.util.concurrent.ExecutionException) Executable(org.junit.jupiter.api.function.Executable)

Aggregations

ByteBuf (io.netty.buffer.ByteBuf)109 ChannelHandlerContext (io.netty.channel.ChannelHandlerContext)100 ChannelFuture (io.netty.channel.ChannelFuture)92 Test (org.junit.Test)89 Http2Exception (io.netty.handler.codec.http2.Http2Exception)85 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)81 AtomicReference (java.util.concurrent.atomic.AtomicReference)78 ByteArrayOutputStream (java.io.ByteArrayOutputStream)76 Channel (io.netty.channel.Channel)75 ChannelPipeline (io.netty.channel.ChannelPipeline)75 ArrayList (java.util.ArrayList)75 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)75 ChannelInitializer (io.netty.channel.ChannelInitializer)74 NioEventLoopGroup (io.netty.channel.nio.NioEventLoopGroup)74 HttpHeaderNames (io.netty.handler.codec.http.HttpHeaderNames)74 DefaultHttp2Headers (io.netty.handler.codec.http2.DefaultHttp2Headers)74 Http2Headers (io.netty.handler.codec.http2.Http2Headers)74 ApplicationProtocolNames (io.netty.handler.ssl.ApplicationProtocolNames)74 ApplicationProtocolNegotiationHandler (io.netty.handler.ssl.ApplicationProtocolNegotiationHandler)74 SslHandler (io.netty.handler.ssl.SslHandler)74