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 { final Http2Connection connection = connection(); if (connection.goAwaySent() && 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); 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, Throwable cause); @Override ChannelFuture resetStream(final ChannelHandlerContext ctx, int streamId, long errorCode,
            final ChannelPromise promise); @Override ChannelFuture goAway(final ChannelHandlerContext ctx, final int lastStreamId, final long errorCode,
                                final ByteBuf debugData, ChannelPromise promise);  }
@Test public void canSendGoAwayFramesWithDecreasingLastStreamIds() throws Exception { handler = newHandler(); ByteBuf data = dummyData(); long errorCode = Http2Error.INTERNAL_ERROR.code(); handler.goAway(ctx, STREAM_ID + 2, errorCode, data.retain(), promise); verify(frameWriter).writeGoAway(eq(ctx), eq(STREAM_ID + 2), eq(errorCode), eq(data), eq(promise)); verify(connection).goAwaySent(eq(STREAM_ID + 2), eq(errorCode), eq(data)); promise = new DefaultChannelPromise(channel); handler.goAway(ctx, STREAM_ID, errorCode, data, promise); verify(frameWriter).writeGoAway(eq(ctx), eq(STREAM_ID), eq(errorCode), eq(data), eq(promise)); verify(connection).goAwaySent(eq(STREAM_ID), eq(errorCode), eq(data)); assertEquals(0, data.refCnt()); }
@Test public void cannotSendGoAwayFrameWithIncreasingLastStreamIds() throws Exception { handler = newHandler(); ByteBuf data = dummyData(); long errorCode = Http2Error.INTERNAL_ERROR.code(); handler.goAway(ctx, STREAM_ID, errorCode, data.retain(), promise); verify(connection).goAwaySent(eq(STREAM_ID), eq(errorCode), eq(data)); verify(frameWriter).writeGoAway(eq(ctx), eq(STREAM_ID), eq(errorCode), eq(data), eq(promise)); assertFalse(promise.isDone()); when(connection.goAwaySent()).thenReturn(true); when(remote.lastStreamKnownByPeer()).thenReturn(STREAM_ID); handler.goAway(ctx, STREAM_ID + 2, errorCode, data, promise); assertTrue(promise.isDone()); assertFalse(promise.isSuccess()); assertEquals(0, data.refCnt()); verifyNoMoreInteractions(frameWriter); }