Http2ConnectionHandler Http2ConnectionPrefaceAndSettingsFrameWrittenEvent propagation

Motivation:
Http2ConnectionHandler uses ctx.fireUserEvent to propagate the Http2ConnectionPrefaceAndSettingsFrameWrittenEvent through the pipeline. This will propagate the event to the next inbound handler in the pipeline. If the user extends Http2ConnectionHandler the Http2ConnectionPrefaceAndSettingsFrameWrittenEvent may be missed and initialization dependent upon this event will not be run.

Modifications:
- Http2ConnectionHandler should use userEventTriggered instead of ctx.fireUserEvent

Result:
Classes that extend Http2ConnectionHandler will see the Http2ConnectionPrefaceAndSettingsFrameWrittenEvent user event.
This commit is contained in:
Scott Mitchell 2017-11-30 22:33:22 -08:00 committed by Norman Maurer
parent 32746c53c1
commit 7cced5576f
2 changed files with 24 additions and 5 deletions

View File

@ -233,7 +233,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
private ByteBuf clientPrefaceString;
private boolean prefaceSent;
public PrefaceDecoder(ChannelHandlerContext ctx) {
public PrefaceDecoder(ChannelHandlerContext ctx) throws Exception {
clientPrefaceString = clientPrefaceString(encoder.connection());
// This handler was just added to the context. In case it was handled after
// the connection became active, send the connection preface now.
@ -357,7 +357,7 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
/**
* Sends the HTTP/2 connection preface upon establishment of the connection, if not already sent.
*/
private void sendPreface(ChannelHandlerContext ctx) {
private void sendPreface(ChannelHandlerContext ctx) throws Exception {
if (prefaceSent || !ctx.channel().isActive()) {
return;
}
@ -375,8 +375,10 @@ public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http
ChannelFutureListener.CLOSE_ON_FAILURE);
if (isClient) {
ctx.fireUserEventTriggered(
Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.INSTANCE);
// If this handler is extended by the user and we directly fire the userEvent from this context then
// the user will not see the event. We should fire the event starting with this handler so this class
// (and extending classes) have a chance to process the event.
userEventTriggered(ctx, Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.INSTANCE);
}
}
}

View File

@ -43,6 +43,7 @@ import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@ -55,6 +56,7 @@ import static io.netty.handler.codec.http2.Http2Stream.State.IDLE;
import static io.netty.handler.codec.http2.Http2TestUtil.newVoidPromise;
import static io.netty.util.CharsetUtil.US_ASCII;
import static io.netty.util.CharsetUtil.UTF_8;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@ -63,9 +65,9 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ -444,6 +446,21 @@ public class Http2ConnectionHandlerTest {
verify(frameWriter).writeRstStream(ctx, STREAM_ID, PROTOCOL_ERROR.code(), promise);
}
@Test
public void prefaceUserEventProcessed() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
handler = new Http2ConnectionHandler(decoder, encoder, new Http2Settings()) {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt == Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.INSTANCE) {
latch.countDown();
}
}
};
handler.handlerAdded(ctx);
assertTrue(latch.await(5, SECONDS));
}
@Test
public void serverShouldNeverSend431IfHeadersAlreadySent() throws Exception {
int padding = 0;