use of io.netty.channel.ChannelPromise in project netty by netty.
the class DefaultHttp2ConnectionEncoderTest method headersWriteShouldHalfCloseAfterOnErrorForPreCreatedStream.
@Test
public void headersWriteShouldHalfCloseAfterOnErrorForPreCreatedStream() throws Exception {
final ChannelPromise promise = newPromise();
final Throwable ex = new RuntimeException();
// Fake an encoding error, like HPACK's HeaderListSizeException
when(writer.writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), eq(0), eq(true), eq(promise))).thenAnswer(new Answer<ChannelFuture>() {
@Override
public ChannelFuture answer(InvocationOnMock invocation) {
promise.setFailure(ex);
return promise;
}
});
writeAllFlowControlledFrames();
Http2Stream stream = createStream(STREAM_ID, false);
encoder.writeHeaders(ctx, STREAM_ID, EmptyHttp2Headers.INSTANCE, 0, true, promise);
assertTrue(promise.isDone());
assertFalse(promise.isSuccess());
assertFalse(stream.isHeadersSent());
InOrder inOrder = inOrder(lifecycleManager);
inOrder.verify(lifecycleManager).onError(eq(ctx), eq(true), eq(ex));
inOrder.verify(lifecycleManager).closeStreamLocal(eq(stream(STREAM_ID)), eq(promise));
}
use of io.netty.channel.ChannelPromise in project netty by netty.
the class DefaultHttp2ConnectionEncoderTest method headersWriteShouldHalfCloseAfterOnErrorForImplicitlyCreatedStream.
@Test
public void headersWriteShouldHalfCloseAfterOnErrorForImplicitlyCreatedStream() throws Exception {
final ChannelPromise promise = newPromise();
final Throwable ex = new RuntimeException();
// Fake an encoding error, like HPACK's HeaderListSizeException
when(writer.writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), eq(0), eq(true), eq(promise))).thenAnswer(new Answer<ChannelFuture>() {
@Override
public ChannelFuture answer(InvocationOnMock invocation) {
promise.setFailure(ex);
return promise;
}
});
writeAllFlowControlledFrames();
encoder.writeHeaders(ctx, STREAM_ID, EmptyHttp2Headers.INSTANCE, 0, true, promise);
assertTrue(promise.isDone());
assertFalse(promise.isSuccess());
assertFalse(stream(STREAM_ID).isHeadersSent());
InOrder inOrder = inOrder(lifecycleManager);
inOrder.verify(lifecycleManager).onError(eq(ctx), eq(true), eq(ex));
inOrder.verify(lifecycleManager).closeStreamLocal(eq(stream(STREAM_ID)), eq(promise));
}
use of io.netty.channel.ChannelPromise in project netty by netty.
the class DefaultHttp2ConnectionEncoderTest method infoHeadersAndTrailersWithData.
private void infoHeadersAndTrailersWithData(boolean eos, int infoHeaderCount) {
writeAllFlowControlledFrames();
final int streamId = 6;
Http2Headers infoHeaders = informationalHeaders();
for (int i = 0; i < infoHeaderCount; ++i) {
encoder.writeHeaders(ctx, streamId, infoHeaders, 0, false, newPromise());
}
Http2Stream stream = connection.stream(streamId);
when(remoteFlow.hasFlowControlled(eq(stream))).thenReturn(true);
ChannelPromise promise2 = newPromise();
encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise2);
ChannelPromise promise3 = newPromise();
ChannelFuture future = encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, eos, promise3);
assertTrue(future.isDone());
assertEquals(eos, future.isSuccess());
verify(writer, times(infoHeaderCount)).writeHeaders(eq(ctx), eq(streamId), eq(infoHeaders), eq(0), eq(false), any(ChannelPromise.class));
verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), eq(0), eq(false), eq(promise2));
if (eos) {
verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), eq(0), eq(true), eq(promise3));
}
}
use of io.netty.channel.ChannelPromise in project netty by netty.
the class HttpProxyHandlerTest method testInitialMessage.
private static void testInitialMessage(InetSocketAddress socketAddress, String expectedUrl, String expectedHostHeader, HttpHeaders headers, boolean ignoreDefaultPortsInConnectHostHeader) throws Exception {
InetSocketAddress proxyAddress = new InetSocketAddress(NetUtil.LOCALHOST, 8080);
ChannelPromise promise = mock(ChannelPromise.class);
verifyNoMoreInteractions(promise);
ChannelHandlerContext ctx = mock(ChannelHandlerContext.class);
when(ctx.connect(same(proxyAddress), isNull(InetSocketAddress.class), same(promise))).thenReturn(promise);
HttpProxyHandler handler = new HttpProxyHandler(new InetSocketAddress(NetUtil.LOCALHOST, 8080), headers, ignoreDefaultPortsInConnectHostHeader);
handler.connect(ctx, socketAddress, null, promise);
FullHttpRequest request = (FullHttpRequest) handler.newInitialMessage(ctx);
try {
assertEquals(HttpVersion.HTTP_1_1, request.protocolVersion());
assertEquals(expectedUrl, request.uri());
HttpHeaders actualHeaders = request.headers();
assertEquals(expectedHostHeader, actualHeaders.get(HttpHeaderNames.HOST));
if (headers != null) {
// The actual request header is a strict superset of the custom header
for (String name : headers.names()) {
assertEquals(headers.getAll(name), actualHeaders.getAll(name));
}
}
} finally {
request.release();
}
verify(ctx).connect(proxyAddress, null, promise);
}
use of io.netty.channel.ChannelPromise in project netty by netty.
the class LocalChannel method doClose.
@Override
protected void doClose() throws Exception {
final LocalChannel peer = this.peer;
State oldState = state;
try {
if (oldState != State.CLOSED) {
// Update all internal state before the closeFuture is notified.
if (localAddress != null) {
if (parent() == null) {
LocalChannelRegistry.unregister(localAddress);
}
localAddress = null;
}
// State change must happen before finishPeerRead to ensure writes are released either in doWrite or
// channelRead.
state = State.CLOSED;
// Preserve order of event and force a read operation now before the close operation is processed.
if (writeInProgress && peer != null) {
finishPeerRead(peer);
}
ChannelPromise promise = connectPromise;
if (promise != null) {
// Use tryFailure() instead of setFailure() to avoid the race against cancel().
promise.tryFailure(new ClosedChannelException());
connectPromise = null;
}
}
if (peer != null) {
this.peer = null;
// Always call peer.eventLoop().execute() even if peer.eventLoop().inEventLoop() is true.
// This ensures that if both channels are on the same event loop, the peer's channelInActive
// event is triggered *after* this peer's channelInActive event
EventLoop peerEventLoop = peer.eventLoop();
final boolean peerIsActive = peer.isActive();
try {
peerEventLoop.execute(new Runnable() {
@Override
public void run() {
peer.tryClose(peerIsActive);
}
});
} catch (Throwable cause) {
logger.warn("Releasing Inbound Queues for channels {}-{} because exception occurred!", this, peer, cause);
if (peerEventLoop.inEventLoop()) {
peer.releaseInboundBuffers();
} else {
// inboundBuffers is a SPSC so we may leak if the event loop is shutdown prematurely or
// rejects the close Runnable but give a best effort.
peer.close();
}
PlatformDependent.throwException(cause);
}
}
} finally {
// Release all buffers if the Channel was already registered in the past and if it was not closed before.
if (oldState != null && oldState != State.CLOSED) {
// We need to release all the buffers that may be put into our inbound queue since we closed the Channel
// to ensure we not leak any memory. This is fine as it basically gives the same guarantees as TCP which
// means even if the promise was notified before its not really guaranteed that the "remote peer" will
// see the buffer at all.
releaseInboundBuffers();
}
}
}
Aggregations