use of io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable in project netty by netty.
the class Http2ConnectionRoundtripTest method listenerIsNotifiedOfGoawayBeforeStreamsAreRemovedFromTheConnection.
@Test
public void listenerIsNotifiedOfGoawayBeforeStreamsAreRemovedFromTheConnection() throws Exception {
bootstrapEnv(1, 1, 2, 1, 1);
// We want both sides to do graceful shutdown during the test.
setClientGracefulShutdownTime(10000);
setServerGracefulShutdownTime(10000);
final AtomicReference<Http2Stream.State> clientStream3State = new AtomicReference<Http2Stream.State>();
final CountDownLatch clientGoAwayLatch = new CountDownLatch(1);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
clientStream3State.set(http2Client.connection().stream(3).state());
clientGoAwayLatch.countDown();
return null;
}
}).when(clientListener).onGoAwayRead(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class));
// 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(), 1, headers, 0, (short) 16, false, 0, false, newPromise());
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false, newPromise());
http2Client.flush(ctx());
}
});
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
// Server has received the headers, so the stream is open
assertTrue(requestLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
runInChannel(serverChannel, new Http2Runnable() {
@Override
public void run() throws Http2Exception {
http2Server.encoder().writeGoAway(serverCtx(), 1, NO_ERROR.code(), EMPTY_BUFFER, serverNewPromise());
http2Server.flush(serverCtx());
}
});
// wait for the client to receive the GO_AWAY.
assertTrue(clientGoAwayLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
verify(clientListener).onGoAwayRead(any(ChannelHandlerContext.class), eq(1), eq(NO_ERROR.code()), any(ByteBuf.class));
assertEquals(Http2Stream.State.OPEN, clientStream3State.get());
// Make sure that stream 3 has been closed which is true if it's gone.
final CountDownLatch probeStreamCount = new CountDownLatch(1);
final AtomicBoolean stream3Exists = new AtomicBoolean();
final AtomicInteger streamCount = new AtomicInteger();
runInChannel(this.clientChannel, new Http2Runnable() {
@Override
public void run() throws Http2Exception {
stream3Exists.set(http2Client.connection().stream(3) != null);
streamCount.set(http2Client.connection().numActiveStreams());
probeStreamCount.countDown();
}
});
// The stream should be closed right after
assertTrue(probeStreamCount.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
assertEquals(1, streamCount.get());
assertFalse(stream3Exists.get());
// Wait for the server to receive a GO_AWAY, but this is expected to timeout!
assertFalse(goAwayLatch.await(1, SECONDS));
verify(serverListener, never()).onGoAwayRead(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class));
// Shutdown shouldn't wait for the server to close streams
setClientGracefulShutdownTime(0);
setServerGracefulShutdownTime(0);
}
use of io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable in project netty by netty.
the class Http2ConnectionRoundtripTest method flowControlProperlyChunksLargeMessage.
@Test
public void flowControlProperlyChunksLargeMessage() throws Exception {
final Http2Headers headers = dummyHeaders();
// Create a large message to send.
// 10MB
final int length = 10485760;
// Create a buffer filled with random bytes.
final ByteBuf data = randomBytes(length);
final ByteArrayOutputStream out = new ByteArrayOutputStream(length);
doAnswer(new Answer<Integer>() {
@Override
public Integer answer(InvocationOnMock in) throws Throwable {
ByteBuf buf = (ByteBuf) in.getArguments()[2];
int padding = (Integer) in.getArguments()[3];
int processedBytes = buf.readableBytes() + padding;
buf.readBytes(out, buf.readableBytes());
return processedBytes;
}
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3), any(ByteBuf.class), eq(0), anyBoolean());
try {
// Initialize the data latch based on the number of bytes expected.
bootstrapEnv(length, 1, 2, 1);
// Create the stream and send all of the data at once.
runInChannel(clientChannel, new Http2Runnable() {
@Override
public void run() throws Http2Exception {
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, false, newPromise());
http2Client.encoder().writeData(ctx(), 3, data.retainedDuplicate(), 0, false, newPromise());
// Write trailers.
http2Client.encoder().writeHeaders(ctx(), 3, headers, 0, (short) 16, false, 0, true, newPromise());
http2Client.flush(ctx());
}
});
// Wait for the trailers to be received.
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
assertTrue(trailersLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
// Verify that headers and trailers were received.
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(3), eq(headers), eq(0), eq((short) 16), eq(false), eq(0), eq(false));
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(3), eq(headers), eq(0), eq((short) 16), eq(false), eq(0), eq(true));
// Verify we received all the bytes.
assertEquals(0, dataLatch.getCount());
out.flush();
byte[] received = out.toByteArray();
assertArrayEquals(data.array(), received);
} finally {
// Don't wait for server to close streams
setClientGracefulShutdownTime(0);
data.release();
out.close();
}
}
use of io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable in project netty by netty.
the class Http2ConnectionRoundtripTest method createStreamAfterReceiveGoAwayShouldNotSendGoAway.
@Test
public void createStreamAfterReceiveGoAwayShouldNotSendGoAway() throws Exception {
bootstrapEnv(1, 1, 2, 1, 1);
// We want both sides to do graceful shutdown during the test.
setClientGracefulShutdownTime(10000);
setServerGracefulShutdownTime(10000);
final CountDownLatch clientGoAwayLatch = new CountDownLatch(1);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
clientGoAwayLatch.countDown();
return null;
}
}).when(clientListener).onGoAwayRead(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class));
// 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, false, newPromise());
http2Client.flush(ctx());
}
});
assertTrue(serverSettingsAckLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
// Server has received the headers, so the stream is open
assertTrue(requestLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
runInChannel(serverChannel, new Http2Runnable() {
@Override
public void run() throws Http2Exception {
http2Server.encoder().writeGoAway(serverCtx(), 3, NO_ERROR.code(), EMPTY_BUFFER, serverNewPromise());
http2Server.flush(serverCtx());
}
});
// wait for the client to receive the GO_AWAY.
assertTrue(clientGoAwayLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
verify(clientListener).onGoAwayRead(any(ChannelHandlerContext.class), eq(3), eq(NO_ERROR.code()), any(ByteBuf.class));
final AtomicReference<ChannelFuture> clientWriteAfterGoAwayFutureRef = new AtomicReference<ChannelFuture>();
final CountDownLatch clientWriteAfterGoAwayLatch = new CountDownLatch(1);
runInChannel(clientChannel, new Http2Runnable() {
@Override
public void run() throws Http2Exception {
ChannelFuture f = http2Client.encoder().writeHeaders(ctx(), 5, headers, 0, (short) 16, false, 0, true, newPromise());
clientWriteAfterGoAwayFutureRef.set(f);
http2Client.flush(ctx());
f.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
clientWriteAfterGoAwayLatch.countDown();
}
});
}
});
// Wait for the client's write operation to complete.
assertTrue(clientWriteAfterGoAwayLatch.await(DEFAULT_AWAIT_TIMEOUT_SECONDS, SECONDS));
ChannelFuture clientWriteAfterGoAwayFuture = clientWriteAfterGoAwayFutureRef.get();
assertNotNull(clientWriteAfterGoAwayFuture);
Throwable clientCause = clientWriteAfterGoAwayFuture.cause();
assertThat(clientCause, is(instanceOf(Http2Exception.StreamException.class)));
assertEquals(Http2Error.REFUSED_STREAM.code(), ((Http2Exception.StreamException) clientCause).error().code());
// Wait for the server to receive a GO_AWAY, but this is expected to timeout!
assertFalse(goAwayLatch.await(1, SECONDS));
verify(serverListener, never()).onGoAwayRead(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class));
// Shutdown shouldn't wait for the server to close streams
setClientGracefulShutdownTime(0);
setServerGracefulShutdownTime(0);
}
use of io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable in project netty by netty.
the class InboundHttp2ToHttpAdapterTest method clientRequestSingleHeaderNonAsciiShouldThrow.
@Test
public void clientRequestSingleHeaderNonAsciiShouldThrow() throws Exception {
boostrapEnv(1, 1, 1);
final Http2Headers http2Headers = new DefaultHttp2Headers().method(new AsciiString("GET")).scheme(new AsciiString("https")).authority(new AsciiString("example.org")).path(new AsciiString("/some/path/resource2")).add(new AsciiString("çã".getBytes(CharsetUtil.UTF_8)), new AsciiString("Ãã".getBytes(CharsetUtil.UTF_8)));
runInChannel(clientChannel, new Http2Runnable() {
@Override
public void run() throws Http2Exception {
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers, 0, true, newPromiseClient());
clientChannel.flush();
}
});
awaitResponses();
assertTrue(isStreamError(clientException));
}
use of io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable in project netty by netty.
the class InboundHttp2ToHttpAdapterTest method serverRequestPushPromise.
@Test
public void serverRequestPushPromise() throws Exception {
boostrapEnv(1, 1, 1);
final String text = "hello world big time data!";
final ByteBuf content = Unpooled.copiedBuffer(text.getBytes());
final String text2 = "hello world smaller data?";
final ByteBuf content2 = Unpooled.copiedBuffer(text2.getBytes());
final FullHttpMessage response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content, true);
final FullHttpMessage response2 = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CREATED, content2, true);
final FullHttpMessage request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/push/test", true);
try {
HttpHeaders httpHeaders = response.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);
HttpHeaders httpHeaders2 = response2.headers();
httpHeaders2.set(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), "https");
httpHeaders2.set(HttpHeaderNames.HOST, "example.org");
httpHeaders2.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 5);
httpHeaders2.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_PROMISE_ID.text(), 3);
httpHeaders2.setInt(HttpHeaderNames.CONTENT_LENGTH, text2.length());
httpHeaders = request.headers();
httpHeaders.setInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text(), 3);
httpHeaders.setInt(HttpHeaderNames.CONTENT_LENGTH, 0);
httpHeaders.setShort(HttpConversionUtil.ExtensionHeaderNames.STREAM_WEIGHT.text(), (short) 16);
final Http2Headers http2Headers3 = new DefaultHttp2Headers().method(new AsciiString("GET")).path(new AsciiString("/push/test"));
runInChannel(clientChannel, new Http2Runnable() {
@Override
public void run() throws Http2Exception {
clientHandler.encoder().writeHeaders(ctxClient(), 3, http2Headers3, 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));
final Http2Headers http2Headers = new DefaultHttp2Headers().status(new AsciiString("200"));
// The PUSH_PROMISE frame includes a header block that contains a
// complete set of request header fields that the server attributes to
// the request.
// https://tools.ietf.org/html/rfc7540#section-8.2.1
// Therefore, we should consider the case where there is no Http response status.
final Http2Headers http2Headers2 = new DefaultHttp2Headers().scheme(new AsciiString("https")).authority(new AsciiString("example.org"));
runInChannel(serverConnectedChannel, new Http2Runnable() {
@Override
public void run() throws Http2Exception {
serverHandler.encoder().writeHeaders(ctxServer(), 3, http2Headers, 0, false, newPromiseServer());
serverHandler.encoder().writePushPromise(ctxServer(), 3, 2, http2Headers2, 0, newPromiseServer());
serverHandler.encoder().writeData(ctxServer(), 3, content.retainedDuplicate(), 0, true, newPromiseServer());
serverHandler.encoder().writeData(ctxServer(), 5, content2.retainedDuplicate(), 0, true, newPromiseServer());
serverConnectedChannel.flush();
}
});
awaitResponses();
ArgumentCaptor<FullHttpMessage> responseCaptor = ArgumentCaptor.forClass(FullHttpMessage.class);
verify(clientListener).messageReceived(responseCaptor.capture());
capturedResponses = responseCaptor.getAllValues();
assertEquals(response, capturedResponses.get(0));
} finally {
request.release();
response.release();
response2.release();
}
}
Aggregations