From e875e59a9bbe10671240e7ee96fee1a35eaee045 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 | 115 +++++++++++------- .../codec/http2/Http2FrameCodecTest.java | 8 +- .../codec/http2/Http2MultiplexTest.java | 18 +-- 4 files changed, 125 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 d4dee41546..c1bdbc695d 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) { @@ -519,14 +545,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; @@ -552,8 +581,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 9ca7b1fee1..aa4ffc3bba 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 @@ -177,12 +177,26 @@ public class DefaultHttp2ConnectionEncoderTest { anyInt(), anyBoolean(), any(ChannelPromise.class))) .then(new Answer() { @Override - public ChannelFuture answer(InvocationOnMock invocationOnMock) throws Throwable { - ChannelPromise promise = (ChannelPromise) invocationOnMock.getArguments()[8]; + public ChannelFuture answer(InvocationOnMock invocationOnMock) { + ChannelPromise promise = invocationOnMock.getArgument(8); if (streamClosed) { fail("Stream already closed"); } else { - streamClosed = (Boolean) invocationOnMock.getArguments()[5]; + streamClosed = invocationOnMock.getArgument(5); + } + return promise.setSuccess(); + } + }); + when(writer.writeHeaders(eq(ctx), anyInt(), any(Http2Headers.class), + anyInt(), anyBoolean(), any(ChannelPromise.class))) + .then(new Answer() { + @Override + public ChannelFuture answer(InvocationOnMock invocationOnMock) { + ChannelPromise promise = invocationOnMock.getArgument(5); + if (streamClosed) { + fail("Stream already closed"); + } else { + streamClosed = invocationOnMock.getArgument(4); } return promise.setSuccess(); } @@ -335,12 +349,12 @@ 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(new Answer() { @Override public ChannelFuture answer(InvocationOnMock invocationOnMock) throws Throwable { - ChannelPromise promise = invocationOnMock.getArgument(8); + ChannelPromise promise = invocationOnMock.getArgument(5); assertFalse(promise.isVoid()); return promise.setFailure(cause); } @@ -349,7 +363,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); @@ -377,7 +391,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()); } @@ -390,8 +404,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 @@ -406,8 +420,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 @@ -425,8 +439,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 @@ -452,10 +466,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 @@ -493,13 +507,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)); } } @@ -536,10 +550,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 @@ -581,13 +595,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)); } } @@ -752,8 +766,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(new Answer() { @Override public ChannelFuture answer(InvocationOnMock invocation) { @@ -779,8 +792,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(new Answer() { @Override public ChannelFuture answer(InvocationOnMock invocation) { @@ -849,8 +861,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 @@ -868,8 +880,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 0d1fb5b416..f2e3c93027 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 @@ -176,7 +176,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()); @@ -205,7 +205,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()); @@ -252,8 +252,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 02798a9b66..8dcc579797 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 @@ -433,7 +433,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; @@ -443,9 +443,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(); } }); @@ -503,11 +503,11 @@ 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(new Answer() { @Override public ChannelFuture answer(InvocationOnMock invocationOnMock) { - return ((ChannelPromise) invocationOnMock.getArgument(8)).setFailure( + return ((ChannelPromise) invocationOnMock.getArgument(5)).setFailure( new StreamException(childChannel.stream().id(), Http2Error.STREAM_CLOSED, "Stream Closed")); } }); @@ -565,11 +565,11 @@ 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(new Answer() { @Override public ChannelFuture answer(InvocationOnMock invocationOnMock) { - return ((ChannelPromise) invocationOnMock.getArgument(8)).setFailure( + return ((ChannelPromise) invocationOnMock.getArgument(5)).setFailure( new Http2NoMoreStreamIdsException()); } }); @@ -653,11 +653,11 @@ 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(new Answer() { @Override public ChannelFuture answer(InvocationOnMock invocationOnMock) { - ChannelPromise promise = invocationOnMock.getArgument(8); + ChannelPromise promise = invocationOnMock.getArgument(5); writePromises.offer(promise); return promise; }