diff --git a/codec/src/main/java/io/netty/handler/codec/compression/JdkZlibDecoder.java b/codec/src/main/java/io/netty/handler/codec/compression/JdkZlibDecoder.java index 9795c69735..65f06450c1 100644 --- a/codec/src/main/java/io/netty/handler/codec/compression/JdkZlibDecoder.java +++ b/codec/src/main/java/io/netty/handler/codec/compression/JdkZlibDecoder.java @@ -35,7 +35,7 @@ public class JdkZlibDecoder extends ZlibDecoder { private static final int FCOMMENT = 0x10; private static final int FRESERVED = 0xE0; - private final Inflater inflater; + private Inflater inflater; private final byte[] dictionary; // GZIP related @@ -58,6 +58,8 @@ public class JdkZlibDecoder extends ZlibDecoder { private volatile boolean finished; + private boolean decideZlibOrNone; + /** * Creates a new instance with the default wrapper ({@link ZlibWrapper#ZLIB}). */ @@ -100,6 +102,11 @@ public class JdkZlibDecoder extends ZlibDecoder { inflater = new Inflater(); crc = null; break; + case ZLIB_OR_NONE: + // Postpone the decision until decode(...) is called. + decideZlibOrNone = true; + crc = null; + break; default: throw new IllegalArgumentException("Only GZIP or ZLIB is supported, but you used " + wrapper); } @@ -123,6 +130,17 @@ public class JdkZlibDecoder extends ZlibDecoder { return; } + if (decideZlibOrNone) { + // First two bytes are needed to decide if it's a ZLIB stream. + if (in.readableBytes() < 2) { + return; + } + + boolean nowrap = !looksLikeZlib(in.getShort(0)); + inflater = new Inflater(nowrap); + decideZlibOrNone = false; + } + if (crc != null) { switch (gzipState) { case FOOTER_START: @@ -214,7 +232,9 @@ public class JdkZlibDecoder extends ZlibDecoder { @Override protected void handlerRemoved0(ChannelHandlerContext ctx) throws Exception { super.handlerRemoved0(ctx); - inflater.end(); + if (inflater != null) { + inflater.end(); + } } private boolean readGZIPHeader(ByteBuf in) { @@ -356,4 +376,16 @@ public class JdkZlibDecoder extends ZlibDecoder { "CRC value missmatch. Expected: " + crcValue + ", Got: " + readCrc); } } + + /* + * Returns true if the cmf_flg parameter (think: first two bytes of a zlib stream) + * indicates that this is a zlib stream. + *
+ * You can lookup the details in the ZLIB RFC: + * RFC 1950. + */ + private boolean looksLikeZlib(short cmf_flg) { + return (cmf_flg & 0x7800) == 0x7800 && + cmf_flg % 31 == 0; + } } diff --git a/codec/src/main/java/io/netty/handler/codec/compression/ZlibCodecFactory.java b/codec/src/main/java/io/netty/handler/codec/compression/ZlibCodecFactory.java index d3bf88597e..db97c24fd8 100644 --- a/codec/src/main/java/io/netty/handler/codec/compression/ZlibCodecFactory.java +++ b/codec/src/main/java/io/netty/handler/codec/compression/ZlibCodecFactory.java @@ -98,15 +98,10 @@ public final class ZlibCodecFactory { } public static ZlibDecoder newZlibDecoder(ZlibWrapper wrapper) { - switch (wrapper) { - case ZLIB_OR_NONE: - return new JZlibDecoder(wrapper); - default: - if (PlatformDependent.javaVersion() < 7 || noJdkZlibDecoder) { - return new JZlibDecoder(wrapper); - } else { - return new JdkZlibDecoder(wrapper); - } + if (PlatformDependent.javaVersion() < 7 || noJdkZlibDecoder) { + return new JZlibDecoder(wrapper); + } else { + return new JdkZlibDecoder(wrapper); } } diff --git a/codec/src/test/java/io/netty/handler/codec/compression/JdkZlibTest.java b/codec/src/test/java/io/netty/handler/codec/compression/JdkZlibTest.java index efc010a1af..b366d73b10 100644 --- a/codec/src/test/java/io/netty/handler/codec/compression/JdkZlibTest.java +++ b/codec/src/test/java/io/netty/handler/codec/compression/JdkZlibTest.java @@ -30,21 +30,8 @@ public class JdkZlibTest extends ZlibTest { return new JdkZlibDecoder(wrapper); } - @Override - @Test(expected = IllegalArgumentException.class) - public void testZLIB_OR_NONE() throws Exception { - new JdkZlibDecoder(ZlibWrapper.ZLIB_OR_NONE); - } - - @Override - @Test(expected = IllegalArgumentException.class) - public void testZLIB_OR_NONE2() throws Exception { - new JdkZlibDecoder(ZlibWrapper.ZLIB_OR_NONE); - } - - @Override - @Test(expected = IllegalArgumentException.class) + @Test(expected = DecompressionException.class) public void testZLIB_OR_NONE3() throws Exception { - new JdkZlibDecoder(ZlibWrapper.ZLIB_OR_NONE); + super.testZLIB_OR_NONE3(); } } diff --git a/codec/src/test/java/io/netty/handler/codec/compression/ZlibCrossTest2.java b/codec/src/test/java/io/netty/handler/codec/compression/ZlibCrossTest2.java index 4495bef4c3..9b5fec88b0 100644 --- a/codec/src/test/java/io/netty/handler/codec/compression/ZlibCrossTest2.java +++ b/codec/src/test/java/io/netty/handler/codec/compression/ZlibCrossTest2.java @@ -29,21 +29,8 @@ public class ZlibCrossTest2 extends ZlibTest { return new JdkZlibDecoder(wrapper); } - @Override - @Test(expected = IllegalArgumentException.class) - public void testZLIB_OR_NONE() throws Exception { - new JdkZlibDecoder(ZlibWrapper.ZLIB_OR_NONE); - } - - @Override - @Test(expected = IllegalArgumentException.class) - public void testZLIB_OR_NONE2() throws Exception { - new JdkZlibDecoder(ZlibWrapper.ZLIB_OR_NONE); - } - - @Override - @Test(expected = IllegalArgumentException.class) + @Test(expected = DecompressionException.class) public void testZLIB_OR_NONE3() throws Exception { - new JdkZlibDecoder(ZlibWrapper.ZLIB_OR_NONE); + super.testZLIB_OR_NONE3(); } } diff --git a/codec/src/test/java/io/netty/handler/codec/compression/ZlibTest.java b/codec/src/test/java/io/netty/handler/codec/compression/ZlibTest.java index 30566d8278..5250161be6 100644 --- a/codec/src/test/java/io/netty/handler/codec/compression/ZlibTest.java +++ b/codec/src/test/java/io/netty/handler/codec/compression/ZlibTest.java @@ -179,7 +179,7 @@ public abstract class ZlibTest { public void testZLIB_OR_NONE2() throws Exception { testCompressNone(ZlibWrapper.ZLIB, ZlibWrapper.ZLIB_OR_NONE); testCompressSmall(ZlibWrapper.ZLIB, ZlibWrapper.ZLIB_OR_NONE); - testCompressLarge(ZlibWrapper.GZIP, ZlibWrapper.ZLIB_OR_NONE); + testCompressLarge(ZlibWrapper.ZLIB, ZlibWrapper.ZLIB_OR_NONE); } @Test