Ignore priority frames for non existing streams and so prevent a NPE (#10943)
Motivation: https://github.com/netty/netty/pull/10765 added support for push promise and priority frames when using the Http2FrameCodec. Unfortunally it didnt correctly guard against the possibility to receive a priority frame for an non-existing stream, which resulted in a NPE Modifications: - Ignore priority frame for non existing stream - Correctly implement equals / hashcode for DefaultHttp2PriorityFrame - Add unit tests Result: Fixes https://github.com/netty/netty/issues/10941
This commit is contained in:
parent
59b3831bbc
commit
8cae1ed959
@ -21,12 +21,11 @@ import io.netty.util.internal.UnstableApi;
|
||||
* Default implementation of {@linkplain Http2PriorityFrame}
|
||||
*/
|
||||
@UnstableApi
|
||||
public final class DefaultHttp2PriorityFrame implements Http2PriorityFrame {
|
||||
public final class DefaultHttp2PriorityFrame extends AbstractHttp2StreamFrame implements Http2PriorityFrame {
|
||||
|
||||
private final int streamDependency;
|
||||
private final short weight;
|
||||
private final boolean exclusive;
|
||||
private Http2FrameStream http2FrameStream;
|
||||
|
||||
public DefaultHttp2PriorityFrame(int streamDependency, short weight, boolean exclusive) {
|
||||
this.streamDependency = streamDependency;
|
||||
@ -50,25 +49,40 @@ public final class DefaultHttp2PriorityFrame implements Http2PriorityFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2PriorityFrame stream(Http2FrameStream stream) {
|
||||
http2FrameStream = stream;
|
||||
public DefaultHttp2PriorityFrame stream(Http2FrameStream stream) {
|
||||
super.stream(stream);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Http2FrameStream stream() {
|
||||
return http2FrameStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "PRIORITY_FRAME";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof DefaultHttp2PriorityFrame)) {
|
||||
return false;
|
||||
}
|
||||
DefaultHttp2PriorityFrame other = (DefaultHttp2PriorityFrame) o;
|
||||
boolean same = super.equals(other);
|
||||
return same && streamDependency == other.streamDependency
|
||||
&& weight == other.weight && exclusive == other.exclusive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = super.hashCode();
|
||||
hash = hash * 31 + streamDependency;
|
||||
hash = hash * 31 + weight;
|
||||
hash = hash * 31 + (exclusive ? 1 : 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DefaultHttp2PriorityFrame(" +
|
||||
"stream=" + http2FrameStream +
|
||||
"stream=" + stream() +
|
||||
", streamDependency=" + streamDependency +
|
||||
", weight=" + weight +
|
||||
", exclusive=" + exclusive +
|
||||
|
@ -657,6 +657,12 @@ public class Http2FrameCodec extends Http2ConnectionHandler {
|
||||
@Override
|
||||
public void onPriorityRead(ChannelHandlerContext ctx, int streamId, int streamDependency,
|
||||
short weight, boolean exclusive) {
|
||||
|
||||
Http2Stream stream = connection().stream(streamId);
|
||||
if (stream == null) {
|
||||
// The stream was not opened yet, let's just ignore this for now.
|
||||
return;
|
||||
}
|
||||
onHttp2Frame(ctx, new DefaultHttp2PriorityFrame(streamDependency, weight, exclusive)
|
||||
.stream(requireStream(streamId)));
|
||||
}
|
||||
|
@ -896,6 +896,40 @@ public class Http2FrameCodecTest {
|
||||
channel.pipeline().fireUserEventTriggered(upgradeEvent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void priorityForNonExistingStream() {
|
||||
writeHeaderAndAssert(1);
|
||||
|
||||
frameInboundWriter.writeInboundPriority(3, 1, (short) 31, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void priorityForExistingStream() {
|
||||
writeHeaderAndAssert(1);
|
||||
writeHeaderAndAssert(3);
|
||||
frameInboundWriter.writeInboundPriority(3, 1, (short) 31, true);
|
||||
|
||||
assertInboundStreamFrame(3, new DefaultHttp2PriorityFrame(1, (short) 31, true));
|
||||
}
|
||||
|
||||
private void writeHeaderAndAssert(int streamId) {
|
||||
frameInboundWriter.writeInboundHeaders(streamId, request, 31, false);
|
||||
|
||||
Http2Stream stream = frameCodec.connection().stream(streamId);
|
||||
assertNotNull(stream);
|
||||
assertEquals(State.OPEN, stream.state());
|
||||
|
||||
assertInboundStreamFrame(streamId, new DefaultHttp2HeadersFrame(request, false, 31));
|
||||
}
|
||||
|
||||
private void assertInboundStreamFrame(int expectedId, Http2StreamFrame streamFrame) {
|
||||
Http2StreamFrame inboundFrame = inboundHandler.readInbound();
|
||||
Http2FrameStream stream2 = inboundFrame.stream();
|
||||
assertNotNull(stream2);
|
||||
assertEquals(expectedId, stream2.id());
|
||||
assertEquals(inboundFrame, streamFrame.stream(stream2));
|
||||
}
|
||||
|
||||
private ChannelHandlerContext eqFrameCodecCtx() {
|
||||
return eq(frameCodec.ctx);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user