@Test public void canSendGoAwayUsingVoidPromise() throws Exception { handler = newHandler(); ByteBuf data = dummyData(); long errorCode = Http2Error.INTERNAL_ERROR.code(); handler = newHandler(); final Throwable cause = new RuntimeException("fake exception"); doAnswer(new Answer<ChannelFuture>() { @Override public ChannelFuture answer(InvocationOnMock invocation) throws Throwable { ChannelPromise promise = invocation.getArgument(4); assertFalse(promise.isVoid()); SimpleChannelPromiseAggregator aggregatedPromise = new SimpleChannelPromiseAggregator(promise, channel, ImmediateEventExecutor.INSTANCE); aggregatedPromise.newPromise(); aggregatedPromise.doneAllocatingPromises(); return aggregatedPromise.setFailure(cause); } }).when(frameWriter).writeGoAway( any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ByteBuf.class), any(ChannelPromise.class)); handler.goAway(ctx, STREAM_ID, errorCode, data, newVoidPromise(channel)); verify(pipeline).fireExceptionCaught(cause); }
@Override public ChannelFuture goAway(final ChannelHandlerContext ctx, final int lastStreamId, final long errorCode, final ByteBuf debugData, ChannelPromise promise) { try { promise = promise.unvoid(); final Http2Connection connection = connection(); if (connection().goAwaySent()) { if (lastStreamId == connection().remote().lastStreamKnownByPeer()) { debugData.release(); return promise.setSuccess(); } if (lastStreamId > connection.remote().lastStreamKnownByPeer()) { throw connectionError(PROTOCOL_ERROR, "Last stream identifier must not increase between " + "sending multiple GOAWAY frames (was '%d', is '%d').", connection.remote().lastStreamKnownByPeer(), lastStreamId); } } connection.goAwaySent(lastStreamId, errorCode, debugData); debugData.retain(); ChannelFuture future = frameWriter().writeGoAway(ctx, lastStreamId, errorCode, debugData, promise); if (future.isDone()) { processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future); } else { future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future); } }); } return future; } catch (Throwable cause) { debugData.release(); return promise.setFailure(cause); } }
Http2ConnectionHandler extends ByteToMessageDecoder implements Http2LifecycleManager,
                                                                            ChannelOutboundHandler { @Override public ChannelFuture goAway(final ChannelHandlerContext ctx, final int lastStreamId, final long errorCode, final ByteBuf debugData, ChannelPromise promise) { try { promise = promise.unvoid(); final Http2Connection connection = connection(); if (connection().goAwaySent()) { if (lastStreamId == connection().remote().lastStreamKnownByPeer()) { debugData.release(); return promise.setSuccess(); } if (lastStreamId > connection.remote().lastStreamKnownByPeer()) { throw connectionError(PROTOCOL_ERROR, "Last stream identifier must not increase between " + "sending multiple GOAWAY frames (was '%d', is '%d').", connection.remote().lastStreamKnownByPeer(), lastStreamId); } } connection.goAwaySent(lastStreamId, errorCode, debugData); debugData.retain(); ChannelFuture future = frameWriter().writeGoAway(ctx, lastStreamId, errorCode, debugData, promise); if (future.isDone()) { processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future); } else { future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future); } }); } return future; } catch (Throwable cause) { debugData.release(); return promise.setFailure(cause); } } }
Http2ConnectionHandler extends ByteToMessageDecoder implements Http2LifecycleManager,
                                                                            ChannelOutboundHandler { @Override public ChannelFuture goAway(final ChannelHandlerContext ctx, final int lastStreamId, final long errorCode, final ByteBuf debugData, ChannelPromise promise) { try { promise = promise.unvoid(); final Http2Connection connection = connection(); if (connection().goAwaySent()) { if (lastStreamId == connection().remote().lastStreamKnownByPeer()) { debugData.release(); return promise.setSuccess(); } if (lastStreamId > connection.remote().lastStreamKnownByPeer()) { throw connectionError(PROTOCOL_ERROR, "Last stream identifier must not increase between " + "sending multiple GOAWAY frames (was '%d', is '%d').", connection.remote().lastStreamKnownByPeer(), lastStreamId); } } connection.goAwaySent(lastStreamId, errorCode, debugData); debugData.retain(); ChannelFuture future = frameWriter().writeGoAway(ctx, lastStreamId, errorCode, debugData, promise); if (future.isDone()) { processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future); } else { future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future); } }); } return future; } catch (Throwable cause) { debugData.release(); return promise.setFailure(cause); } } protected  Http2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
                                     Http2Settings initialSettings);   Http2ConnectionHandler(boolean server, Http2FrameWriter frameWriter, Http2FrameLogger frameLogger,
                    Http2Settings initialSettings); }
Http2ConnectionHandler extends ByteToMessageDecoder implements Http2LifecycleManager,
                                                                            ChannelOutboundHandler { @Override public ChannelFuture goAway(final ChannelHandlerContext ctx, final int lastStreamId, final long errorCode, final ByteBuf debugData, ChannelPromise promise) { try { promise = promise.unvoid(); final Http2Connection connection = connection(); if (connection().goAwaySent()) { if (lastStreamId == connection().remote().lastStreamKnownByPeer()) { debugData.release(); return promise.setSuccess(); } if (lastStreamId > connection.remote().lastStreamKnownByPeer()) { throw connectionError(PROTOCOL_ERROR, "Last stream identifier must not increase between " + "sending multiple GOAWAY frames (was '%d', is '%d').", connection.remote().lastStreamKnownByPeer(), lastStreamId); } } connection.goAwaySent(lastStreamId, errorCode, debugData); debugData.retain(); ChannelFuture future = frameWriter().writeGoAway(ctx, lastStreamId, errorCode, debugData, promise); if (future.isDone()) { processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future); } else { future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future); } }); } return future; } catch (Throwable cause) { debugData.release(); return promise.setFailure(cause); } } protected  Http2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
                                     Http2Settings initialSettings);   Http2ConnectionHandler(boolean server, Http2FrameWriter frameWriter, Http2FrameLogger frameLogger,
                    Http2Settings initialSettings); long gracefulShutdownTimeoutMillis(); void gracefulShutdownTimeoutMillis(long gracefulShutdownTimeoutMillis); Http2Connection connection(); Http2ConnectionDecoder decoder(); Http2ConnectionEncoder encoder(); void onHttpClientUpgrade(); void onHttpServerUpgrade(Http2Settings settings); @Override void flush(ChannelHandlerContext ctx); @Override void handlerAdded(ChannelHandlerContext ctx); @Override void channelActive(ChannelHandlerContext ctx); @Override void channelInactive(ChannelHandlerContext ctx); @Override void channelWritabilityChanged(ChannelHandlerContext ctx); @Override void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise); @Override void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
                        ChannelPromise promise); @Override void disconnect(ChannelHandlerContext ctx, ChannelPromise promise); @Override void close(ChannelHandlerContext ctx, ChannelPromise promise); @Override void deregister(ChannelHandlerContext ctx, ChannelPromise promise); @Override void read(ChannelHandlerContext ctx); @Override void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise); @Override void channelReadComplete(ChannelHandlerContext ctx); @Override void exceptionCaught(ChannelHandlerContext ctx, Throwable cause); @Override void closeStreamLocal(Http2Stream stream, ChannelFuture future); @Override void closeStreamRemote(Http2Stream stream, ChannelFuture future); @Override void closeStream(final Http2Stream stream, ChannelFuture future); @Override void onError(ChannelHandlerContext ctx, boolean outbound, Throwable cause); @Override ChannelFuture resetStream(final ChannelHandlerContext ctx, int streamId, long errorCode,
                                     ChannelPromise promise); @Override ChannelFuture goAway(final ChannelHandlerContext ctx, final int lastStreamId, final long errorCode,
                                final ByteBuf debugData, ChannelPromise promise); }
Http2ConnectionHandler extends ByteToMessageDecoder implements Http2LifecycleManager,
                                                                            ChannelOutboundHandler { @Override public ChannelFuture goAway(final ChannelHandlerContext ctx, final int lastStreamId, final long errorCode, final ByteBuf debugData, ChannelPromise promise) { try { promise = promise.unvoid(); final Http2Connection connection = connection(); if (connection().goAwaySent()) { if (lastStreamId == connection().remote().lastStreamKnownByPeer()) { debugData.release(); return promise.setSuccess(); } if (lastStreamId > connection.remote().lastStreamKnownByPeer()) { throw connectionError(PROTOCOL_ERROR, "Last stream identifier must not increase between " + "sending multiple GOAWAY frames (was '%d', is '%d').", connection.remote().lastStreamKnownByPeer(), lastStreamId); } } connection.goAwaySent(lastStreamId, errorCode, debugData); debugData.retain(); ChannelFuture future = frameWriter().writeGoAway(ctx, lastStreamId, errorCode, debugData, promise); if (future.isDone()) { processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future); } else { future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future); } }); } return future; } catch (Throwable cause) { debugData.release(); return promise.setFailure(cause); } } protected  Http2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
                                     Http2Settings initialSettings);   Http2ConnectionHandler(boolean server, Http2FrameWriter frameWriter, Http2FrameLogger frameLogger,
                    Http2Settings initialSettings); long gracefulShutdownTimeoutMillis(); void gracefulShutdownTimeoutMillis(long gracefulShutdownTimeoutMillis); Http2Connection connection(); Http2ConnectionDecoder decoder(); Http2ConnectionEncoder encoder(); void onHttpClientUpgrade(); void onHttpServerUpgrade(Http2Settings settings); @Override void flush(ChannelHandlerContext ctx); @Override void handlerAdded(ChannelHandlerContext ctx); @Override void channelActive(ChannelHandlerContext ctx); @Override void channelInactive(ChannelHandlerContext ctx); @Override void channelWritabilityChanged(ChannelHandlerContext ctx); @Override void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise); @Override void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
                        ChannelPromise promise); @Override void disconnect(ChannelHandlerContext ctx, ChannelPromise promise); @Override void close(ChannelHandlerContext ctx, ChannelPromise promise); @Override void deregister(ChannelHandlerContext ctx, ChannelPromise promise); @Override void read(ChannelHandlerContext ctx); @Override void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise); @Override void channelReadComplete(ChannelHandlerContext ctx); @Override void exceptionCaught(ChannelHandlerContext ctx, Throwable cause); @Override void closeStreamLocal(Http2Stream stream, ChannelFuture future); @Override void closeStreamRemote(Http2Stream stream, ChannelFuture future); @Override void closeStream(final Http2Stream stream, ChannelFuture future); @Override void onError(ChannelHandlerContext ctx, boolean outbound, Throwable cause); @Override ChannelFuture resetStream(final ChannelHandlerContext ctx, int streamId, long errorCode,
                                     ChannelPromise promise); @Override ChannelFuture goAway(final ChannelHandlerContext ctx, final int lastStreamId, final long errorCode,
                                final ByteBuf debugData, ChannelPromise promise);  }