From 8e281dc54ec0d1b991aa86e2941e457ddafeca9e Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Sun, 8 Dec 2019 07:43:11 +0100 Subject: [PATCH] DefaultHttp2ConnectionEncoder writeHeaders method always send an head frame with a priority (#9852) Motivation: The current implementation delegates to writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int streamDependency, short weight, boolean exclusive, int padding, boolean endStream, ChannelPromise promise) that will send an header frame with the priority flag set and the default priority values even if the user didnt want too. Modifications: - Change DefaultHttp2ConnectionEncoder to call the correct Http2FrameWriter method depending on if the user wants to use priorities or not - Adjust tests Result: Fixes https://github.com/netty/netty/issues/9842 --- .../http2/DefaultHttp2ConnectionEncoder.java | 47 ++++++-- .../DefaultHttp2ConnectionEncoderTest.java | 109 +++++++++++------- .../codec/http2/Http2FrameCodecTest.java | 8 +- .../codec/http2/Http2MultiplexTest.java | 19 ++- 4 files changed, 120 insertions(+), 63 deletions(-) diff --git a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2ConnectionEncoder.java b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2ConnectionEncoder.java index 1c9f3dd2fa..278dad76c4 100644 --- a/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2ConnectionEncoder.java +++ b/codec-http2/src/main/java/io/netty/handler/codec/http2/DefaultHttp2ConnectionEncoder.java @@ -148,7 +148,7 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht @Override public ChannelFuture writeHeaders(ChannelHandlerContext ctx, int streamId, Http2Headers headers, int padding, boolean endStream, ChannelPromise promise) { - return writeHeaders(ctx, streamId, headers, 0, DEFAULT_PRIORITY_WEIGHT, false, padding, endStream, promise); + return writeHeaders0(ctx, streamId, headers, false, 0, (short) 0, false, padding, endStream, promise); } private static boolean validateHeadersSentState(Http2Stream stream, Http2Headers headers, boolean isServer, @@ -164,6 +164,31 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht public ChannelFuture writeHeaders(final ChannelHandlerContext ctx, final int streamId, final Http2Headers headers, final int streamDependency, final short weight, final boolean exclusive, final int padding, final boolean endOfStream, ChannelPromise promise) { + return writeHeaders0(ctx, streamId, headers, true, streamDependency, + weight, exclusive, padding, endOfStream, promise); + } + + /** + * Write headers via {@link Http2FrameWriter}. If {@code hasPriority} is {@code false} it will ignore the + * {@code streamDependency}, {@code weight} and {@code exclusive} parameters. + */ + private static ChannelFuture sendHeaders(Http2FrameWriter frameWriter, ChannelHandlerContext ctx, int streamId, + Http2Headers headers, final boolean hasPriority, + int streamDependency, final short weight, + boolean exclusive, final int padding, + boolean endOfStream, ChannelPromise promise) { + if (hasPriority) { + return frameWriter.writeHeaders(ctx, streamId, headers, streamDependency, + weight, exclusive, padding, endOfStream, promise); + } + return frameWriter.writeHeaders(ctx, streamId, headers, padding, endOfStream, promise); + } + + private ChannelFuture writeHeaders0(final ChannelHandlerContext ctx, final int streamId, + final Http2Headers headers, final boolean hasPriority, + final int streamDependency, final short weight, + final boolean exclusive, final int padding, + final boolean endOfStream, ChannelPromise promise) { try { Http2Stream stream = connection.stream(streamId); if (stream == null) { @@ -205,8 +230,9 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht promise = promise.unvoid(); boolean isInformational = validateHeadersSentState(stream, headers, connection.isServer(), endOfStream); - ChannelFuture future = frameWriter.writeHeaders(ctx, streamId, headers, streamDependency, - weight, exclusive, padding, endOfStream, promise); + ChannelFuture future = sendHeaders(frameWriter, ctx, streamId, headers, hasPriority, streamDependency, + weight, exclusive, padding, endOfStream, promise); + // Writing headers may fail during the encode state if they violate HPACK limits. Throwable failureCause = future.cause(); if (failureCause == null) { @@ -236,8 +262,8 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht } else { // Pass headers to the flow-controller so it can maintain their sequence relative to DATA frames. flowController.addFlowControlled(stream, - new FlowControlledHeaders(stream, headers, streamDependency, weight, exclusive, padding, - true, promise)); + new FlowControlledHeaders(stream, headers, hasPriority, streamDependency, + weight, exclusive, padding, true, promise)); return promise; } } catch (Throwable t) { @@ -516,14 +542,17 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht */ private final class FlowControlledHeaders extends FlowControlledBase { private final Http2Headers headers; + private final boolean hasPriorty; private final int streamDependency; private final short weight; private final boolean exclusive; - FlowControlledHeaders(Http2Stream stream, Http2Headers headers, int streamDependency, short weight, - boolean exclusive, int padding, boolean endOfStream, ChannelPromise promise) { + FlowControlledHeaders(Http2Stream stream, Http2Headers headers, boolean hasPriority, + int streamDependency, short weight, boolean exclusive, + int padding, boolean endOfStream, ChannelPromise promise) { super(stream, padding, endOfStream, promise.unvoid()); this.headers = headers; + this.hasPriorty = hasPriority; this.streamDependency = streamDependency; this.weight = weight; this.exclusive = exclusive; @@ -549,8 +578,8 @@ public class DefaultHttp2ConnectionEncoder implements Http2ConnectionEncoder, Ht // closeStreamLocal(). promise.addListener(this); - ChannelFuture f = frameWriter.writeHeaders(ctx, stream.id(), headers, streamDependency, weight, exclusive, - padding, endOfStream, promise); + ChannelFuture f = sendHeaders(frameWriter, ctx, stream.id(), headers, hasPriorty, streamDependency, + weight, exclusive, padding, endOfStream, promise); // Writing headers may fail during the encode state if they violate HPACK limits. Throwable failureCause = f.cause(); if (failureCause == null) { diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2ConnectionEncoderTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2ConnectionEncoderTest.java index 0ff024461b..64d15abb16 100644 --- a/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2ConnectionEncoderTest.java +++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/DefaultHttp2ConnectionEncoderTest.java @@ -37,7 +37,6 @@ import org.mockito.ArgumentCaptor; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.util.ArrayList; @@ -162,7 +161,7 @@ public class DefaultHttp2ConnectionEncoderTest { when(writer.writeHeaders(eq(ctx), anyInt(), any(Http2Headers.class), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(), any(ChannelPromise.class))) .then((Answer) invocationOnMock -> { - ChannelPromise promise = (ChannelPromise) invocationOnMock.getArguments()[8]; + ChannelPromise promise = invocationOnMock.getArgument(8); if (streamClosed) { fail("Stream already closed"); } else { @@ -170,6 +169,17 @@ public class DefaultHttp2ConnectionEncoderTest { } return promise.setSuccess(); }); + when(writer.writeHeaders(eq(ctx), anyInt(), any(Http2Headers.class), + anyInt(), anyBoolean(), any(ChannelPromise.class))) + .then((Answer) invocationOnMock -> { + ChannelPromise promise = invocationOnMock.getArgument(5); + if (streamClosed) { + fail("Stream already closed"); + } else { + streamClosed = invocationOnMock.getArgument(4); + } + return promise.setSuccess(); + }); payloadCaptor = ArgumentCaptor.forClass(Http2RemoteFlowController.FlowControlled.class); doNothing().when(remoteFlow).addFlowControlled(any(Http2Stream.class), payloadCaptor.capture()); when(ctx.alloc()).thenReturn(UnpooledByteBufAllocator.DEFAULT); @@ -308,10 +318,10 @@ public class DefaultHttp2ConnectionEncoderTest { @Test public void writeHeadersUsingVoidPromise() throws Exception { final Throwable cause = new RuntimeException("fake exception"); - when(writer.writeHeaders(eq(ctx), eq(STREAM_ID), any(Http2Headers.class), anyInt(), anyShort(), anyBoolean(), + when(writer.writeHeaders(eq(ctx), eq(STREAM_ID), any(Http2Headers.class), anyInt(), anyBoolean(), any(ChannelPromise.class))) .then((Answer) invocationOnMock -> { - ChannelPromise promise = invocationOnMock.getArgument(8); + ChannelPromise promise = invocationOnMock.getArgument(5); assertFalse(promise.isVoid()); return promise.setFailure(cause); }); @@ -319,7 +329,7 @@ public class DefaultHttp2ConnectionEncoderTest { // END_STREAM flag, so that a listener is added to the future. encoder.writeHeaders(ctx, STREAM_ID, EmptyHttp2Headers.INSTANCE, 0, true, newVoidPromise(channel)); - verify(writer).writeHeaders(eq(ctx), eq(STREAM_ID), any(Http2Headers.class), anyInt(), anyShort(), anyBoolean(), + verify(writer).writeHeaders(eq(ctx), eq(STREAM_ID), any(Http2Headers.class), anyInt(), anyBoolean(), any(ChannelPromise.class)); // When using a void promise, the error should be propagated via the channel pipeline. verify(pipeline).fireExceptionCaught(cause); @@ -347,7 +357,7 @@ public class DefaultHttp2ConnectionEncoderTest { ChannelPromise promise = newPromise(); encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise); verify(writer).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), eq(0), - eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), eq(promise)); + eq(false), eq(promise)); assertTrue(promise.isSuccess()); } @@ -360,8 +370,8 @@ public class DefaultHttp2ConnectionEncoderTest { ChannelPromise promise = newPromise(); encoder.writeHeaders(ctx, PUSH_STREAM_ID, EmptyHttp2Headers.INSTANCE, 0, false, promise); assertEquals(HALF_CLOSED_REMOTE, stream(PUSH_STREAM_ID).state()); - verify(writer).writeHeaders(eq(ctx), eq(PUSH_STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), eq(0), - eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), eq(promise)); + verify(writer).writeHeaders(eq(ctx), eq(PUSH_STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), + eq(0), eq(false), eq(promise)); } @Test @@ -376,8 +386,8 @@ public class DefaultHttp2ConnectionEncoderTest { assertTrue(future.isDone()); assertFalse(future.isSuccess()); - verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), eq(0), - eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), eq(promise)); + verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), + eq(0), eq(false), eq(promise)); } @Test @@ -395,8 +405,8 @@ public class DefaultHttp2ConnectionEncoderTest { assertTrue(future.isDone()); assertFalse(future.isSuccess()); - verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), eq(0), - eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), eq(promise)); + verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), + eq(0), eq(false), eq(promise)); } @Test @@ -422,10 +432,10 @@ public class DefaultHttp2ConnectionEncoderTest { assertTrue(future.isDone()); assertFalse(future.isSuccess()); - verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), eq(0), - eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), eq(promise)); - verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), eq(0), - eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(true), eq(promise2)); + verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), + eq(0), eq(false), eq(promise)); + verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), + eq(0), eq(true), eq(promise2)); } @Test @@ -463,13 +473,13 @@ public class DefaultHttp2ConnectionEncoderTest { assertTrue(future.isDone()); assertEquals(eos, future.isSuccess()); - verify(writer, times(infoHeaderCount)).writeHeaders(eq(ctx), eq(streamId), eq(infoHeaders), eq(0), - eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), any(ChannelPromise.class)); - verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), eq(0), - eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), eq(promise2)); + 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(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(true), eq(promise3)); + verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), + eq(0), eq(true), eq(promise3)); } } @@ -506,10 +516,10 @@ public class DefaultHttp2ConnectionEncoderTest { assertTrue(future.isDone()); assertFalse(future.isSuccess()); - verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), eq(0), - eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), eq(promise)); - verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), eq(0), - eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(true), eq(promise2)); + verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), + eq(0), eq(false), eq(promise)); + verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), + eq(0), eq(true), eq(promise2)); } @Test @@ -551,13 +561,13 @@ public class DefaultHttp2ConnectionEncoderTest { assertTrue(future.isDone()); assertEquals(eos, future.isSuccess()); - verify(writer, times(infoHeaderCount)).writeHeaders(eq(ctx), eq(streamId), eq(infoHeaders), eq(0), - eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), any(ChannelPromise.class)); - verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), eq(0), - eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), eq(promise2)); + 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(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(true), eq(promise3)); + verify(writer, times(1)).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), + eq(0), eq(true), eq(promise3)); } } @@ -722,8 +732,7 @@ public class DefaultHttp2ConnectionEncoderTest { 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(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(true), eq(promise))) + when(writer.writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), eq(0), eq(true), eq(promise))) .thenAnswer((Answer) invocation -> { promise.setFailure(ex); return promise; @@ -746,8 +755,7 @@ public class DefaultHttp2ConnectionEncoderTest { 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(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(true), eq(promise))) + when(writer.writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), eq(0), eq(true), eq(promise))) .thenAnswer((Answer) invocation -> { promise.setFailure(ex); return promise; @@ -813,8 +821,8 @@ public class DefaultHttp2ConnectionEncoderTest { goAwaySent(0); ChannelPromise promise = newPromise(); encoder.writeHeaders(ctx, STREAM_ID, EmptyHttp2Headers.INSTANCE, 0, false, promise); - verify(writer).writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), eq(0), - eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), eq(promise)); + verify(writer).writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), + eq(0), eq(false), eq(promise)); } @Test @@ -832,8 +840,29 @@ public class DefaultHttp2ConnectionEncoderTest { goAwayReceived(STREAM_ID); ChannelPromise promise = newPromise(); encoder.writeHeaders(ctx, STREAM_ID, EmptyHttp2Headers.INSTANCE, 0, false, promise); - verify(writer).writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), eq(0), - eq(DEFAULT_PRIORITY_WEIGHT), eq(false), eq(0), eq(false), eq(promise)); + verify(writer).writeHeaders(eq(ctx), eq(STREAM_ID), eq(EmptyHttp2Headers.INSTANCE), + eq(0), eq(false), eq(promise)); + } + + @Test + public void headersWithNoPriority() { + writeAllFlowControlledFrames(); + final int streamId = 6; + ChannelPromise promise = newPromise(); + encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 0, false, promise); + verify(writer).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), + eq(0), eq(false), eq(promise)); + } + + @Test + public void headersWithPriority() { + writeAllFlowControlledFrames(); + final int streamId = 6; + ChannelPromise promise = newPromise(); + encoder.writeHeaders(ctx, streamId, EmptyHttp2Headers.INSTANCE, 10, DEFAULT_PRIORITY_WEIGHT, + true, 1, false, promise); + verify(writer).writeHeaders(eq(ctx), eq(streamId), eq(EmptyHttp2Headers.INSTANCE), eq(10), + eq(DEFAULT_PRIORITY_WEIGHT), eq(true), eq(1), eq(false), eq(promise)); } private void writeAllFlowControlledFrames() { diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2FrameCodecTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2FrameCodecTest.java index c59b64a8ce..91c69f020c 100644 --- a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2FrameCodecTest.java +++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2FrameCodecTest.java @@ -177,7 +177,7 @@ public class Http2FrameCodecTest { channel.writeOutbound(new DefaultHttp2HeadersFrame(response, true, 27).stream(stream2)); verify(frameWriter).writeHeaders( - eqFrameCodecCtx(), eq(1), eq(response), anyInt(), anyShort(), anyBoolean(), + eqFrameCodecCtx(), eq(1), eq(response), eq(27), eq(true), anyChannelPromise()); verify(frameWriter, never()).writeRstStream( eqFrameCodecCtx(), anyInt(), anyLong(), anyChannelPromise()); @@ -206,7 +206,7 @@ public class Http2FrameCodecTest { channel.writeOutbound(new DefaultHttp2HeadersFrame(response, true, 27).stream(stream2)); verify(frameWriter).writeHeaders( - eqFrameCodecCtx(), eq(1), eq(response), anyInt(), anyShort(), anyBoolean(), + eqFrameCodecCtx(), eq(1), eq(response), eq(27), eq(true), anyChannelPromise()); verify(frameWriter, never()).writeRstStream( eqFrameCodecCtx(), anyInt(), anyLong(), anyChannelPromise()); @@ -265,8 +265,8 @@ public class Http2FrameCodecTest { assertNull(inboundHandler.readInbound()); channel.writeOutbound(new DefaultHttp2HeadersFrame(response, false).stream(stream2)); - verify(frameWriter).writeHeaders(eqFrameCodecCtx(), eq(1), eq(response), anyInt(), - anyShort(), anyBoolean(), eq(0), eq(false), anyChannelPromise()); + verify(frameWriter).writeHeaders(eqFrameCodecCtx(), eq(1), eq(response), + eq(0), eq(false), anyChannelPromise()); channel.writeOutbound(new DefaultHttp2DataFrame(bb("world"), true, 27).stream(stream2)); ArgumentCaptor outboundData = ArgumentCaptor.forClass(ByteBuf.class); diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexTest.java index 7a341e7b3c..d53d3140a5 100644 --- a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexTest.java +++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexTest.java @@ -427,7 +427,7 @@ public abstract class Http2MultiplexTest { @Test public void outboundStreamShouldNotWriteResetFrameOnClose_IfStreamDidntExist() { when(frameWriter.writeHeaders(eqCodecCtx(), anyInt(), - any(Http2Headers.class), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(), + any(Http2Headers.class), anyInt(), anyBoolean(), any(ChannelPromise.class))).thenAnswer(new Answer() { private boolean headersWritten; @@ -437,9 +437,9 @@ public abstract class Http2MultiplexTest { // refuses to allocate a new stream due to having received a GOAWAY. if (!headersWritten) { headersWritten = true; - return ((ChannelPromise) invocationOnMock.getArgument(8)).setFailure(new Exception("boom")); + return ((ChannelPromise) invocationOnMock.getArgument(5)).setFailure(new Exception("boom")); } - return ((ChannelPromise) invocationOnMock.getArgument(8)).setSuccess(); + return ((ChannelPromise) invocationOnMock.getArgument(5)).setSuccess(); } }); @@ -497,9 +497,9 @@ public abstract class Http2MultiplexTest { Http2Headers headers = new DefaultHttp2Headers(); when(frameWriter.writeHeaders(eqCodecCtx(), anyInt(), - eq(headers), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(), + eq(headers), anyInt(), anyBoolean(), any(ChannelPromise.class))).thenAnswer(invocationOnMock -> { - return ((ChannelPromise) invocationOnMock.getArgument(8)).setFailure( + return ((ChannelPromise) invocationOnMock.getArgument(5)).setFailure( new StreamException(childChannel.stream().id(), Http2Error.STREAM_CLOSED, "Stream Closed")); }); ChannelFuture future = childChannel.writeAndFlush(new DefaultHttp2HeadersFrame(new DefaultHttp2Headers())); @@ -561,9 +561,8 @@ public abstract class Http2MultiplexTest { Http2Headers headers = new DefaultHttp2Headers(); when(frameWriter.writeHeaders(eqCodecCtx(), anyInt(), - eq(headers), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(), - any(ChannelPromise.class))).thenAnswer(invocationOnMock -> { - return ((ChannelPromise) invocationOnMock.getArgument(8)).setFailure( + eq(headers), anyInt(), anyBoolean(), any(ChannelPromise.class))).thenAnswer(invocationOnMock -> { + return ((ChannelPromise) invocationOnMock.getArgument(5)).setFailure( new Http2NoMoreStreamIdsException()); }); @@ -644,9 +643,9 @@ public abstract class Http2MultiplexTest { Http2Headers headers = new DefaultHttp2Headers(); when(frameWriter.writeHeaders(eqCodecCtx(), anyInt(), - eq(headers), anyInt(), anyShort(), anyBoolean(), anyInt(), anyBoolean(), + eq(headers), anyInt(), anyBoolean(), any(ChannelPromise.class))).thenAnswer(invocationOnMock -> { - ChannelPromise promise = invocationOnMock.getArgument(8); + ChannelPromise promise = invocationOnMock.getArgument(5); writePromises.offer(promise); return promise; });