[#1788] Correctly decode CRC32 and ISIZE when using JdkZlibDecoder
Because of incorrect decoding a CompressionException was thrown before
This commit is contained in:
parent
3aa77f54f7
commit
7a38163743
@ -18,6 +18,7 @@ package io.netty.handler.codec.compression;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
|
||||||
|
import java.nio.ByteOrder;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
import java.util.zip.DataFormatException;
|
import java.util.zip.DataFormatException;
|
||||||
@ -156,7 +157,7 @@ public class JdkZlibDecoder extends ZlibDecoder {
|
|||||||
if (outputLength > 0) {
|
if (outputLength > 0) {
|
||||||
decompressed.writerIndex(decompressed.writerIndex() + outputLength);
|
decompressed.writerIndex(decompressed.writerIndex() + outputLength);
|
||||||
if (crc != null) {
|
if (crc != null) {
|
||||||
crc.update(outArray, outIndex, length);
|
crc.update(outArray, outIndex, outputLength);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (inflater.needsDictionary()) {
|
if (inflater.needsDictionary()) {
|
||||||
@ -298,15 +299,10 @@ public class JdkZlibDecoder extends ZlibDecoder {
|
|||||||
gzipState = GzipState.PROCESS_FHCRC;
|
gzipState = GzipState.PROCESS_FHCRC;
|
||||||
case PROCESS_FHCRC:
|
case PROCESS_FHCRC:
|
||||||
if ((flags & FHCRC) != 0) {
|
if ((flags & FHCRC) != 0) {
|
||||||
if (!in.isReadable()) {
|
if (in.readableBytes() < 4) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int headerCrc = in.readShort();
|
verifyCrc(in);
|
||||||
int readCrc = (int) crc.getValue() & 0xffff;
|
|
||||||
if (headerCrc != readCrc) {
|
|
||||||
throw new CompressionException(
|
|
||||||
"Header CRC value missmatch. Expected: " + headerCrc + ", Got: " + readCrc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
crc.reset();
|
crc.reset();
|
||||||
gzipState = GzipState.HEADER_END;
|
gzipState = GzipState.HEADER_END;
|
||||||
@ -321,14 +317,14 @@ public class JdkZlibDecoder extends ZlibDecoder {
|
|||||||
if (buf.readableBytes() < 8) {
|
if (buf.readableBytes() < 8) {
|
||||||
return false;
|
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();
|
int readLength = inflater.getTotalOut();
|
||||||
if (dataLength != readLength) {
|
if (dataLength != readLength) {
|
||||||
throw new CompressionException(
|
throw new CompressionException(
|
||||||
@ -336,4 +332,16 @@ public class JdkZlibDecoder extends ZlibDecoder {
|
|||||||
}
|
}
|
||||||
return true;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,27 +22,31 @@ import io.netty.util.CharsetUtil;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
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
|
@Test
|
||||||
public void testZLIB() throws Exception {
|
public void testZLIB_OR_NONE() throws Exception {
|
||||||
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
|
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());
|
chEncoder.writeOutbound(data.copy());
|
||||||
assertTrue(chEncoder.finish());
|
assertTrue(chEncoder.finish());
|
||||||
|
|
||||||
ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound();
|
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));
|
EmbeddedChannel chDecoderZlibOrNone = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE));
|
||||||
|
|
||||||
chDecoderZlibOrNone.writeInbound(deflatedData);
|
chDecoderZlibOrNone.writeInbound(deflatedData);
|
||||||
@ -52,25 +56,17 @@ public class JZlibTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNONE() throws Exception {
|
public void testZLIB_OR_NONE2() throws Exception {
|
||||||
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
|
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());
|
chEncoder.writeOutbound(data.copy());
|
||||||
assertTrue(chEncoder.finish());
|
assertTrue(chEncoder.finish());
|
||||||
|
|
||||||
ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound();
|
ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound();
|
||||||
|
|
||||||
EmbeddedChannel chDecoderZlibNone = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.NONE));
|
EmbeddedChannel chDecoderZlibOrNone = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE));
|
||||||
|
|
||||||
chDecoderZlibNone.writeInbound(deflatedData.copy());
|
|
||||||
assertTrue(chDecoderZlibNone.finish());
|
|
||||||
|
|
||||||
assertEquals(data, chDecoderZlibNone.readInbound());
|
|
||||||
|
|
||||||
EmbeddedChannel chDecoderZlibOrNone =
|
|
||||||
new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE));
|
|
||||||
|
|
||||||
chDecoderZlibOrNone.writeInbound(deflatedData);
|
chDecoderZlibOrNone.writeInbound(deflatedData);
|
||||||
assertTrue(chDecoderZlibOrNone.finish());
|
assertTrue(chDecoderZlibOrNone.finish());
|
||||||
@ -79,7 +75,7 @@ public class JZlibTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGZIP() throws Exception {
|
public void testZLIB_OR_NONE3() throws Exception {
|
||||||
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
|
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
|
||||||
|
|
||||||
EmbeddedChannel chEncoder = new EmbeddedChannel(new JZlibEncoder(ZlibWrapper.GZIP));
|
EmbeddedChannel chEncoder = new EmbeddedChannel(new JZlibEncoder(ZlibWrapper.GZIP));
|
||||||
@ -89,15 +85,7 @@ public class JZlibTest {
|
|||||||
|
|
||||||
ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound();
|
ByteBuf deflatedData = (ByteBuf) chEncoder.readOutbound();
|
||||||
|
|
||||||
EmbeddedChannel chDecoderGZip = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.GZIP));
|
EmbeddedChannel chDecoderZlibOrNone = new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE));
|
||||||
|
|
||||||
chDecoderGZip.writeInbound(deflatedData.copy());
|
|
||||||
assertTrue(chDecoderGZip.finish());
|
|
||||||
|
|
||||||
assertEquals(data, chDecoderGZip.readInbound());
|
|
||||||
|
|
||||||
EmbeddedChannel chDecoderZlibOrNone =
|
|
||||||
new EmbeddedChannel(new JZlibDecoder(ZlibWrapper.ZLIB_OR_NONE));
|
|
||||||
|
|
||||||
chDecoderZlibOrNone.writeInbound(deflatedData);
|
chDecoderZlibOrNone.writeInbound(deflatedData);
|
||||||
assertTrue(chDecoderZlibOrNone.finish());
|
assertTrue(chDecoderZlibOrNone.finish());
|
||||||
|
@ -15,76 +15,23 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.handler.codec.compression;
|
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 org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
public class JdkZlibTest {
|
public class JdkZlibTest extends ZlibTest {
|
||||||
|
|
||||||
@Test
|
@Override
|
||||||
public void testZLIB() throws Exception {
|
protected ZlibEncoder createEncoder(ZlibWrapper wrapper) {
|
||||||
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
|
return new JdkZlibEncoder(wrapper);
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Override
|
||||||
public void testNONE() throws Exception {
|
protected ZlibDecoder createDecoder(ZlibWrapper wrapper) {
|
||||||
ByteBuf data = Unpooled.copiedBuffer("test", CharsetUtil.UTF_8);
|
return new JdkZlibDecoder(wrapper);
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void testZLIB_OR_NONE() throws Exception {
|
public void testZLIB_OR_NONE() throws Exception {
|
||||||
new JdkZlibDecoder(ZlibWrapper.ZLIB_OR_NONE);
|
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user