use of io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable 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));
}
use of io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable 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());
}
use of io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable 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();
}
}
use of io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable 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());
}
use of io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable 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)));
}
Aggregations