From fc6fa2774e325da6076494ca3f23f9ea993c16ab Mon Sep 17 00:00:00 2001 From: Vladimir Schafer Date: Thu, 6 Feb 2014 20:41:38 +0200 Subject: [PATCH] #2183 Fix for releasing of the internal cumulation buffer in ByteToMessageDecoder --- .../handler/codec/ByteToMessageDecoder.java | 2 + .../codec/ByteToMessageDecoderTest.java | 47 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/codec/src/main/java/io/netty/handler/codec/ByteToMessageDecoder.java b/codec/src/main/java/io/netty/handler/codec/ByteToMessageDecoder.java index 50dc125886..637f4cd9d0 100644 --- a/codec/src/main/java/io/netty/handler/codec/ByteToMessageDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/ByteToMessageDecoder.java @@ -109,6 +109,8 @@ public abstract class ByteToMessageDecoder extends ChannelHandlerAdapter { ByteBuf bytes = buf.readBytes(readable); buf.release(); ctx.fireChannelRead(bytes); + } else { + buf.release(); } cumulation = null; ctx.fireChannelReadComplete(); diff --git a/codec/src/test/java/io/netty/handler/codec/ByteToMessageDecoderTest.java b/codec/src/test/java/io/netty/handler/codec/ByteToMessageDecoderTest.java index 09d5020073..bd3b343165 100644 --- a/codec/src/test/java/io/netty/handler/codec/ByteToMessageDecoderTest.java +++ b/codec/src/test/java/io/netty/handler/codec/ByteToMessageDecoderTest.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.embedded.EmbeddedChannel; +import io.netty.util.ReferenceCountUtil; import org.junit.Assert; import org.junit.Test; @@ -72,4 +73,50 @@ public class ByteToMessageDecoderTest { buf.release(); b.release(); } + + /** + * Verifies that internal buffer of the ByteToMessageDecoder is released once decoder is removed from pipeline. In + * this case input is read fully. + */ + @Test + public void testInternalBufferClearReadAll() { + final ByteBuf buf = ReferenceCountUtil.releaseLater(Unpooled.buffer().writeBytes(new byte[]{'a'})); + EmbeddedChannel channel = new EmbeddedChannel(new ByteToMessageDecoder() { + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + ByteBuf byteBuf = internalBuffer(); + Assert.assertEquals(1, byteBuf.refCnt()); + in.readByte(); + // Removal from pipeline should clear internal buffer + ctx.pipeline().remove(this); + Assert.assertEquals(0, byteBuf.refCnt()); + } + }); + Assert.assertFalse(channel.writeInbound(buf)); + Assert.assertFalse(channel.finish()); + } + + /** + * Verifies that internal buffer of the ByteToMessageDecoder is released once decoder is removed from pipeline. In + * this case input was not fully read. + */ + @Test + public void testInternalBufferClearReadPartly() { + final ByteBuf buf = ReferenceCountUtil.releaseLater(Unpooled.buffer().writeBytes(new byte[]{'a', 'b'})); + EmbeddedChannel channel = new EmbeddedChannel(new ByteToMessageDecoder() { + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + ByteBuf byteBuf = internalBuffer(); + Assert.assertEquals(1, byteBuf.refCnt()); + in.readByte(); + // Removal from pipeline should clear internal buffer + ctx.pipeline().remove(this); + Assert.assertEquals(0, byteBuf.refCnt()); + } + }); + Assert.assertTrue(channel.writeInbound(buf)); + Assert.assertTrue(channel.finish()); + Assert.assertEquals(channel.readInbound(), Unpooled.wrappedBuffer(new byte[] {'b'})); + Assert.assertNull(channel.readInbound()); + } }