Search in sources :

Example 21 with Http2Headers

use of io.netty.handler.codec.http2.Http2Headers 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("Header encode should have exceeded maxHeaderListSize!", clientHeadersWriteException.get());
    assertNotNull("Data on closed stream should fail!", clientDataWriteException.get());
    // 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("Client write of headers should succeed with increased header list size!", clientHeadersWriteException2.get());
    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.Test)

Example 22 with Http2Headers

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

the class Http2ConnectionRoundtripTest method stressTest.

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

        int nextIndex;

        @Override
        public Void answer(InvocationOnMock in) throws Throwable {
            receivedPings[nextIndex++] = ((ByteBuf) in.getArguments()[1]).toString(UTF_8);
            return null;
        }
    }).when(serverListener).onPingRead(any(ChannelHandlerContext.class), any(ByteBuf.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.retainedSlice(), 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(ByteBuf.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 (String receivedPing : receivedPings) {
            assertEquals(pingMsg, receivedPing);
        }
    } finally {
        // Don't wait for server to close streams
        http2Client.gracefulShutdownTimeoutMillis(0);
        data.release();
        pingData.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) InvocationOnMock(org.mockito.invocation.InvocationOnMock) Test(org.junit.Test)

Example 23 with Http2Headers

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

the class Http2ConnectionRoundtripTest method inflightFrameAfterStreamResetShouldNotMakeConnectionUnsuable.

@Test
public void inflightFrameAfterStreamResetShouldNotMakeConnectionUnsuable() throws Exception {
    bootstrapEnv(1, 1, 2, 1);
    final CountDownLatch latch = new CountDownLatch(1);
    doAnswer(new Answer<Void>() {

        @Override
        public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
            ChannelHandlerContext ctx = invocationOnMock.getArgument(0);
            http2Server.encoder().writeHeaders(ctx, (Integer) invocationOnMock.getArgument(1), (Http2Headers) invocationOnMock.getArgument(2), 0, false, ctx.newPromise());
            http2Server.flush(ctx);
            return null;
        }
    }).when(serverListener).onHeadersRead(any(ChannelHandlerContext.class), anyInt(), any(Http2Headers.class), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean());
    doAnswer(new Answer<Void>() {

        @Override
        public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
            latch.countDown();
            return null;
        }
    }).when(clientListener).onHeadersRead(any(ChannelHandlerContext.class), eq(5), any(Http2Headers.class), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean());
    // Create a single stream by sending a HEADERS frame to the server.
    final short weight = 16;
    final Http2Headers headers = dummyHeaders();
    runInChannel(clientChannel, new Http2Runnable() {

        @Override
        public void run() throws Http2Exception {
            http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, weight, false, 0, false, newPromise());
            http2Client.flush(ctx());
            http2Client.encoder().writeRstStream(ctx(), 3, Http2Error.INTERNAL_ERROR.code(), newPromise());
            http2Client.flush(ctx());
        }
    });
    runInChannel(clientChannel, new Http2Runnable() {

        @Override
        public void run() throws Http2Exception {
            http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, weight, false, 0, false, newPromise());
            http2Client.flush(ctx());
        }
    });
    assertTrue(latch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
}
Also used : Http2Runnable(io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable) InvocationOnMock(org.mockito.invocation.InvocationOnMock) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) CountDownLatch(java.util.concurrent.CountDownLatch) Test(org.junit.Test)

Example 24 with Http2Headers

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

the class Http2ConnectionRoundtripTest method noMoreStreamIdsShouldSendGoAway.

@Test
public void noMoreStreamIdsShouldSendGoAway() throws Exception {
    bootstrapEnv(1, 1, 3, 1, 1);
    // Don't wait for the server to close streams
    http2Client.gracefulShutdownTimeoutMillis(0);
    // Create a single stream by sending a HEADERS frame to the server.
    final Http2Headers headers = dummyHeaders();
    runInChannel(clientChannel, new Http2Runnable() {

        @Override
        public void run() throws Http2Exception {
            http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, true, newPromise());
            http2Client.flush(ctx());
        }
    });
    assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
    runInChannel(clientChannel, new Http2Runnable() {

        @Override
        public void run() throws Http2Exception {
            http2Client.encoder().writeHeaders(ctx(), Integer.MAX_VALUE + 1, headers, 0, (short) 16, false, 0, true, newPromise());
            http2Client.flush(ctx());
        }
    });
    assertTrue(goAwayLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
    verify(serverListener).onGoAwayRead(any(ChannelHandlerContext.class), eq(0), eq(PROTOCOL_ERROR.code()), any(ByteBuf.class));
}
Also used : Http2Runnable(io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) ByteBuf(io.netty.buffer.ByteBuf) Test(org.junit.Test)

Example 25 with Http2Headers

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

the class InboundHttp2ToHttpAdapterTest method clientRequestMultipleDataFrames.

@Test
public void clientRequestMultipleDataFrames() throws Exception {
    boostrapEnv(1, 1, 1);
    final String text = "hello world big time data!";
    final ByteBuf content = Unpooled.copiedBuffer(text.getBytes());
    final FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/some/path/resource2", content, true);
    try {
        HttpHeaders httpHeaders = request.headers();
        httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
        httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, text.length());
        httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16);
        final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")).path(new AsciiString("/some/path/resource2"));
        final int midPoint = text.length() / 2;
        runInChannel(clientChannel, new Http2Runnable() {

            @Override
            public void run() throws Http2Exception {
                clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, false, newPromiseClient());
                clientHandler.encoder().writeData(ctxClient(), 3, content.retainedSlice(0, midPoint), 0, false, newPromiseClient());
                clientHandler.encoder().writeData(ctxClient(), 3, content.retainedSlice(midPoint, text.length() - midPoint), 0, true, newPromiseClient());
                clientChannel.flush();
            }
        });
        awaitRequests();
        ArgumentCaptor<FullHttpMessage> requestCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
        verify(serverListener).messageReceived(requestCaptor.capture());
        capturedRequests = requestCaptor.getAllValues();
        assertEquals(request, capturedRequests.get(0));
    } finally {
        request.release();
    }
}
Also used : HttpHeaders(io.netty.handler.codec.http.HttpHeaders) DefaultFullHttpRequest(io.netty.handler.codec.http.DefaultFullHttpRequest) FullHttpRequest(io.netty.handler.codec.http.FullHttpRequest) Http2CodecUtil.getEmbeddedHttp2Exception(io.netty.handler.codec.http2.Http2CodecUtil.getEmbeddedHttp2Exception) DefaultFullHttpRequest(io.netty.handler.codec.http.DefaultFullHttpRequest) Http2Runnable(io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable) FullHttpMessage(io.netty.handler.codec.http.FullHttpMessage) AsciiString(io.netty.util.AsciiString) AsciiString(io.netty.util.AsciiString) ByteBuf(io.netty.buffer.ByteBuf) Test(org.junit.Test)

Aggregations

Test (org.junit.Test)68 Http2Headers (io.netty.handler.codec.http2.Http2Headers)57 ByteBuf (io.netty.buffer.ByteBuf)51 DefaultHttp2Headers (io.netty.handler.codec.http2.DefaultHttp2Headers)47 ChannelHandlerContext (io.netty.channel.ChannelHandlerContext)39 ChannelFuture (io.netty.channel.ChannelFuture)33 AsciiString (io.netty.util.AsciiString)33 Http2Runnable (io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable)29 Http2Exception (io.netty.handler.codec.http2.Http2Exception)27 Http2ConnectionEncoder (io.netty.handler.codec.http2.Http2ConnectionEncoder)25 Http2EventAdapter (io.netty.handler.codec.http2.Http2EventAdapter)23 Http2Stream (io.netty.handler.codec.http2.Http2Stream)23 HttpClientRequest (io.vertx.core.http.HttpClientRequest)23 HttpConnection (io.vertx.core.http.HttpConnection)23 HttpMethod (io.vertx.core.http.HttpMethod)23 Channel (io.netty.channel.Channel)22 ChannelInitializer (io.netty.channel.ChannelInitializer)22 ChannelPipeline (io.netty.channel.ChannelPipeline)22 EventLoopGroup (io.netty.channel.EventLoopGroup)22 NioEventLoopGroup (io.netty.channel.nio.NioEventLoopGroup)22