diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/extensions/compression/DeflateDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/extensions/compression/DeflateDecoder.java index 03475f6e95..8612bf3a72 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/extensions/compression/DeflateDecoder.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/extensions/compression/DeflateDecoder.java @@ -68,6 +68,7 @@ abstract class DeflateDecoder extends WebSocketExtensionDecoder { decoder = new EmbeddedChannel(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.NONE)); } + boolean readable = msg.content().isReadable(); decoder.writeInbound(msg.content().retain()); if (appendFrameTail(msg)) { decoder.writeInbound(Unpooled.wrappedBuffer(FRAME_TAIL)); @@ -87,7 +88,9 @@ abstract class DeflateDecoder extends WebSocketExtensionDecoder { compositeUncompressedContent.writerIndex(compositeUncompressedContent.writerIndex() + partUncompressedContent.readableBytes()); } - if (compositeUncompressedContent.numComponents() <= 0) { + // Correctly handle empty frames + // See https://github.com/netty/netty/issues/4348 + if (readable && compositeUncompressedContent.numComponents() <= 0) { compositeUncompressedContent.release(); throw new CodecException("cannot read uncompressed buffer"); } diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/extensions/compression/PerFrameDeflateDecoderTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/extensions/compression/PerFrameDeflateDecoderTest.java index bb61e8a1cf..e59d380287 100644 --- a/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/extensions/compression/PerFrameDeflateDecoderTest.java +++ b/codec-http/src/test/java/io/netty/handler/codec/http/websocketx/extensions/compression/PerFrameDeflateDecoderTest.java @@ -95,4 +95,29 @@ public class PerFrameDeflateDecoderTest { newFrame.release(); } + // See https://github.com/netty/netty/issues/4348 + @Test + public void testCompressedEmptyFrame() { + EmbeddedChannel encoderChannel = new EmbeddedChannel( + ZlibCodecFactory.newZlibEncoder(ZlibWrapper.NONE, 9, 15, 8)); + EmbeddedChannel decoderChannel = new EmbeddedChannel(new PerFrameDeflateDecoder(false)); + + encoderChannel.writeOutbound(Unpooled.EMPTY_BUFFER); + ByteBuf compressedPayload = encoderChannel.readOutbound(); + BinaryWebSocketFrame compressedFrame = + new BinaryWebSocketFrame(true, WebSocketExtension.RSV1 | WebSocketExtension.RSV3, compressedPayload); + + // execute + decoderChannel.writeInbound(compressedFrame); + BinaryWebSocketFrame uncompressedFrame = decoderChannel.readInbound(); + + // test + assertNotNull(uncompressedFrame); + assertNotNull(uncompressedFrame.content()); + assertTrue(uncompressedFrame instanceof BinaryWebSocketFrame); + assertEquals(WebSocketExtension.RSV3, uncompressedFrame.rsv()); + assertEquals(0, uncompressedFrame.content().readableBytes()); + uncompressedFrame.release(); + } + }