[#1788] Correctly decode CRC32 and ISIZE when using JdkZlibDecoder

Because of incorrect decoding a CompressionException was thrown before
This commit is contained in:
Norman Maurer 2013-08-28 09:51:04 +02:00
parent 3aa77f54f7
commit 7a38163743
4 changed files with 161 additions and 106 deletions

View File

@ -18,6 +18,7 @@ package io.netty.handler.codec.compression;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import java.nio.ByteOrder;
import java.util.List;
import java.util.zip.CRC32;
import java.util.zip.DataFormatException;
@ -156,7 +157,7 @@ public class JdkZlibDecoder extends ZlibDecoder {
if (outputLength > 0) {
decompressed.writerIndex(decompressed.writerIndex() + outputLength);
if (crc != null) {
crc.update(outArray, outIndex, length);
crc.update(outArray, outIndex, outputLength);
}
} else {
if (inflater.needsDictionary()) {
@ -298,15 +299,10 @@ public class JdkZlibDecoder extends ZlibDecoder {
gzipState = GzipState.PROCESS_FHCRC;
case PROCESS_FHCRC:
if ((flags & FHCRC) != 0) {
if (!in.isReadable()) {
if (in.readableBytes() < 4) {
return false;
}
int headerCrc = in.readShort();
int readCrc = (int) crc.getValue() & 0xffff;
if (headerCrc != readCrc) {
throw new CompressionException(
"Header CRC value missmatch. Expected: " + headerCrc + ", Got: " + readCrc);
}
verifyCrc(in);
}
crc.reset();
gzipState = GzipState.HEADER_END;
@ -321,14 +317,14 @@ public class JdkZlibDecoder extends ZlibDecoder {
if (buf.readableBytes() < 8) {
return false;
}
int dataCrc = buf.readInt();
int readCrc = (int) crc.getValue() & 0xffff;
if (dataCrc != readCrc) {
throw new CompressionException(
"Data CRC value missmatch. Expected: " + dataCrc + ", Got: " + readCrc);
}
int dataLength = buf.readInt();
verifyCrc(buf);
// read ISIZE and verify
int dataLength = 0;
for (int i = 0; i < 4; ++i) {
dataLength |= buf.readUnsignedByte() << (i * 8);
}
int readLength = inflater.getTotalOut();
if (dataLength != readLength) {
throw new CompressionException(
@ -336,4 +332,16 @@ public class JdkZlibDecoder extends ZlibDecoder {
}
return true;
}
private void verifyCrc(ByteBuf in) {
long crcValue = 0;
for (int i = 0; i < 4; ++i) {
crcValue |= (long) in.readUnsignedByte() << (i * 8);
}
long readCrc = crc.getValue();
if (crcValue != readCrc) {
throw new CompressionException(
"CRC value missmatch. Expected: " + crcValue + ", Got: " + readCrc);
}
}
}

View File

@ -22,27 +22,31 @@ import io.netty.util.CharsetUtil;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
public class JZlibTest {
public class JZlibTest extends ZlibTest {
@Override
protected ZlibEncoder createEncoder(ZlibWrapper wrapper) {
return new JZlibEncoder(wrapper);
}
@Override
protected ZlibDecoder createDecoder(ZlibWrapper wrapper) {
return new JZlibDecoder(wrapper);
}
@Test
public void testZLIB() throws Exception {
public void testZLIB_OR_NONE() throws Exception {
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
EmbeddedChannel chEncoder = new EmbeddedChannel(new JZlibEncoder(ZlibWrapper.ZLIB));
EmbeddedChannel chEncoder = new EmbeddedChannel(new JZlibEncoder(ZlibWrapper.NONE));
chEncoder.writeOutbound(data.copy());
assertTrue(chEncoder.finish());
ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound();
EmbeddedChannel chDecoderZlib = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB));
chDecoderZlib.writeInbound(deflatedData.copy());
assertTrue(chDecoderZlib.finish());
assertEquals(data, chDecoderZlib.readInbound());
EmbeddedChannel chDecoderZlibOrNone = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE));
chDecoderZlibOrNone.writeInbound(deflatedData);
@ -52,25 +56,17 @@ public class JZlibTest {
}
@Test
public void testNONE() throws Exception {
public void testZLIB_OR_NONE2() throws Exception {
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
EmbeddedChannel chEncoder = new EmbeddedChannel(new JZlibEncoder(ZlibWrapper.NONE));
EmbeddedChannel chEncoder = new EmbeddedChannel(new JZlibEncoder(ZlibWrapper.ZLIB));
chEncoder.writeOutbound(data.copy());
assertTrue(chEncoder.finish());
ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound();
EmbeddedChannel chDecoderZlibNone = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.NONE));
chDecoderZlibNone.writeInbound(deflatedData.copy());
assertTrue(chDecoderZlibNone.finish());
assertEquals(data, chDecoderZlibNone.readInbound());
EmbeddedChannel chDecoderZlibOrNone =
new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE));
EmbeddedChannel chDecoderZlibOrNone = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE));
chDecoderZlibOrNone.writeInbound(deflatedData);
assertTrue(chDecoderZlibOrNone.finish());
@ -79,7 +75,7 @@ public class JZlibTest {
}
@Test
public void testGZIP() throws Exception {
public void testZLIB_OR_NONE3() throws Exception {
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
EmbeddedChannel chEncoder = new EmbeddedChannel(new JZlibEncoder(ZlibWrapper.GZIP));
@ -89,15 +85,7 @@ public class JZlibTest {
ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound();
EmbeddedChannel chDecoderGZip = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.GZIP));
chDecoderGZip.writeInbound(deflatedData.copy());
assertTrue(chDecoderGZip.finish());
assertEquals(data, chDecoderGZip.readInbound());
EmbeddedChannel chDecoderZlibOrNone =
new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE));
EmbeddedChannel chDecoderZlibOrNone = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE));
chDecoderZlibOrNone.writeInbound(deflatedData);
assertTrue(chDecoderZlibOrNone.finish());

View File

@ -15,76 +15,23 @@
*/
package io.netty.handler.codec.compression;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.util.CharsetUtil;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class JdkZlibTest {
public class JdkZlibTest extends ZlibTest {
@Test
public void testZLIB() throws Exception {
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
EmbeddedChannel chEncoder = new EmbeddedChannel(new JdkZlibEncoder(ZlibWrapper.ZLIB));
chEncoder.writeOutbound(data.copy());
assertTrue(chEncoder.finish());
ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound();
EmbeddedChannel chDecoderZlib = new EmbeddedChannel(new JdkZlibDecoder(ZlibWrapper.ZLIB));
chDecoderZlib.writeInbound(deflatedData.copy());
assertTrue(chDecoderZlib.finish());
assertEquals(data, chDecoderZlib.readInbound());
@Override
protected ZlibEncoder createEncoder(ZlibWrapper wrapper) {
return new JdkZlibEncoder(wrapper);
}
@Test
public void testNONE() throws Exception {
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
EmbeddedChannel chEncoder = new EmbeddedChannel(new JdkZlibEncoder(ZlibWrapper.NONE));
chEncoder.writeOutbound(data.copy());
assertTrue(chEncoder.finish());
ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound();
EmbeddedChannel chDecoderZlibNone = new EmbeddedChannel(new JdkZlibDecoder(ZlibWrapper.NONE));
chDecoderZlibNone.writeInbound(deflatedData.copy());
assertTrue(chDecoderZlibNone.finish());
assertEquals(data, chDecoderZlibNone.readInbound());
@Override
protected ZlibDecoder createDecoder(ZlibWrapper wrapper) {
return new JdkZlibDecoder(wrapper);
}
@Test(expected = IllegalArgumentException.class)
public void testZLIB_OR_NONE() throws Exception {
new JdkZlibDecoder(ZlibWrapper.ZLIB_OR_NONE);
}
@Test
public void testGZIP() throws Exception {
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
EmbeddedChannel chEncoder = new EmbeddedChannel(new JdkZlibEncoder(ZlibWrapper.GZIP));
chEncoder.writeOutbound(data.copy());
assertTrue(chEncoder.finish());
ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound();
EmbeddedChannel chDecoderGZip = new EmbeddedChannel(new JdkZlibDecoder(ZlibWrapper.GZIP));
chDecoderGZip.writeInbound(deflatedData.copy());
assertTrue(chDecoderGZip.finish());
assertEquals(data, chDecoderGZip.readInbound());
}
}

View File

@ -0,0 +1,112 @@
/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.compression;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.util.CharsetUtil;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public abstract class ZlibTest {
protected abstract ZlibEncoder createEncoder(ZlibWrapper wrapper);
protected abstract ZlibDecoder createDecoder(ZlibWrapper wrapper);
@Test
public void testGZIP2() throws Exception {
ByteBuf data = Unpooled.wrappedBuffer("message".getBytes(CharsetUtil.UTF_8));
ByteBuf deflatedData = Unpooled.wrappedBuffer(gzip("message"));
EmbeddedChannel chDecoderGZip = new EmbeddedChannel(createDecoder(ZlibWrapper.GZIP));
chDecoderGZip.writeInbound(deflatedData.copy());
assertTrue(chDecoderGZip.finish());
assertEquals(chDecoderGZip.readInbound(), data);
}
@Test
public void testZLIB() throws Exception {
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
EmbeddedChannel chEncoder = new EmbeddedChannel(createEncoder(ZlibWrapper.ZLIB));
chEncoder.writeOutbound(data.copy());
assertTrue(chEncoder.finish());
ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound();
EmbeddedChannel chDecoderZlib = new EmbeddedChannel(createDecoder(ZlibWrapper.ZLIB));
chDecoderZlib.writeInbound(deflatedData.copy());
assertTrue(chDecoderZlib.finish());
assertEquals(data, chDecoderZlib.readInbound());
}
@Test
public void testNONE() throws Exception {
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
EmbeddedChannel chEncoder = new EmbeddedChannel(createEncoder(ZlibWrapper.NONE));
chEncoder.writeOutbound(data.copy());
assertTrue(chEncoder.finish());
ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound();
EmbeddedChannel chDecoderZlibNone = new EmbeddedChannel(createDecoder(ZlibWrapper.NONE));
chDecoderZlibNone.writeInbound(deflatedData.copy());
assertTrue(chDecoderZlibNone.finish());
assertEquals(data, chDecoderZlibNone.readInbound());
}
@Test
public void testGZIP() throws Exception {
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
EmbeddedChannel chEncoder = new EmbeddedChannel(createEncoder(ZlibWrapper.GZIP));
chEncoder.writeOutbound(data.copy());
assertTrue(chEncoder.finish());
ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound();
EmbeddedChannel chDecoderGZip = new EmbeddedChannel(createDecoder(ZlibWrapper.GZIP));
chDecoderGZip.writeInbound(deflatedData.copy());
assertTrue(chDecoderGZip.finish());
assertEquals(data, chDecoderGZip.readInbound());
}
private static byte[] gzip(String message) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPOutputStream stream = new GZIPOutputStream(out);
stream.write(message.getBytes(CharsetUtil.UTF_8));
stream.close();
return out.toByteArray();
}
}