NETTY-383 deflate-raw support for HttpContentDecompressor

* Added ZlibWrapperType.ZLIB_OR_NONE for auto-detection and updated
the relevant Zlib implementation
This commit is contained in:
Trustin Lee 2011-02-22 18:05:16 +09:00
parent 429d3987dc
commit 7ab5ec5f74
8 changed files with 59 additions and 12 deletions

View File

@ -125,25 +125,32 @@ public class ZlibDecoder extends OneToOneDecoder {
z.next_out_index = 0;
z.avail_out = out.length;
do {
loop: for (;;) {
// Decompress 'in' into 'out'
int resultCode = z.inflate(JZlib.Z_SYNC_FLUSH);
if (z.next_out_index > 0) {
decompressed.writeBytes(out, 0, z.next_out_index);
z.avail_out = out.length;
}
z.next_out_index = 0;
switch (resultCode) {
case JZlib.Z_STREAM_END:
finished = true; // Do not decode anymore.
z.inflateEnd();
break loop;
case JZlib.Z_OK:
break;
case JZlib.Z_BUF_ERROR:
decompressed.writeBytes(out, 0, z.next_out_index);
z.next_out_index = 0;
z.avail_out = out.length;
if (resultCode == JZlib.Z_STREAM_END) {
finished = true; // Do not decode anymore.
z.inflateEnd();
if (z.avail_in <= 0) {
break loop;
}
break;
default:
ZlibUtil.fail(z, "decompression failure", resultCode);
}
} while (z.avail_in > 0);
}
if (decompressed.writerIndex() != 0) { // readerIndex is always 0
return decompressed;

View File

@ -104,6 +104,11 @@ public class ZlibEncoder extends OneToOneEncoder implements LifeCycleAwareChanne
if (wrapper == null) {
throw new NullPointerException("wrapper");
}
if (wrapper == ZlibWrapper.ZLIB_OR_NONE) {
throw new IllegalArgumentException(
"wrapper '" + ZlibWrapper.ZLIB_OR_NONE + "' is not " +
"allowed for compression.");
}
synchronized (z) {
int resultCode = z.deflateInit(compressionLevel, ZlibUtil.convertWrapperType(wrapper));

View File

@ -48,6 +48,9 @@ final class ZlibUtil {
case GZIP:
convertedWrapperType = JZlib.W_GZIP;
break;
case ZLIB_OR_NONE:
convertedWrapperType = JZlib.W_ZLIB_OR_NONE;
break;
default:
throw new Error();
}

View File

@ -35,5 +35,10 @@ public enum ZlibWrapper {
/**
* Raw DEFLATE stream only (no header and no footer).
*/
NONE;
NONE,
/**
* Try {@link #ZLIB} first and then {@link #NONE} if the first attempt fails.
* Please note that you can specify this wrapper type only when decompressing.
*/
ZLIB_OR_NONE;
}

View File

@ -35,7 +35,8 @@ public class HttpContentDecompressor extends HttpContentDecoder {
if ("gzip".equalsIgnoreCase(contentEncoding) || "x-gzip".equalsIgnoreCase(contentEncoding)) {
return new DecoderEmbedder<ChannelBuffer>(new ZlibDecoder(ZlibWrapper.GZIP));
} else if ("deflate".equalsIgnoreCase(contentEncoding) || "x-deflate".equalsIgnoreCase(contentEncoding)) {
return new DecoderEmbedder<ChannelBuffer>(new ZlibDecoder(ZlibWrapper.ZLIB));
// To be strict, 'deflate' means ZLIB, but some servers were not implemented correctly.
return new DecoderEmbedder<ChannelBuffer>(new ZlibDecoder(ZlibWrapper.ZLIB_OR_NONE));
}
// 'identity' or unsupported

View File

@ -1306,6 +1306,11 @@ final class Deflate {
private int deflateInit2(ZStream strm, int level, int method, int windowBits,
int memLevel, int strategy, WrapperType wrapperType) {
if (wrapperType == WrapperType.ZLIB_OR_NONE) {
throw new IllegalArgumentException("ZLIB_OR_NONE allowed only for inflate");
}
// byte[] my_version=ZLIB_VERSION;
//

View File

@ -111,6 +111,7 @@ final class Inflate {
z.istate.mode = BLOCKS;
break;
case ZLIB:
case ZLIB_OR_NONE:
z.istate.mode = METHOD;
break;
case GZIP:
@ -174,6 +175,19 @@ final class Inflate {
if (z.avail_in == 0) {
return r;
}
// Switch from zlib to none if necessary.
if (z.istate.wrapperType == WrapperType.ZLIB_OR_NONE) {
if ((z.next_in[z.next_in_index] & 0xf) != JZlib.Z_DEFLATED ||
(z.next_in[z.next_in_index] >> 4) + 8 > z.istate.wbits) {
z.istate.wrapperType = WrapperType.NONE;
z.istate.mode = BLOCKS;
break;
} else {
z.istate.wrapperType = WrapperType.ZLIB;
}
}
r = f;
z.avail_in --;
@ -286,17 +300,23 @@ final class Inflate {
gzipUncompressedBytes += decompressedBytes;
z.crc32 = CRC32.crc32(z.crc32, z.next_out, old_next_out_index, decompressedBytes);
}
if (z.istate.wrapperType == WrapperType.NONE) {
z.istate.mode = DONE;
break;
} else if (z.istate.wrapperType == WrapperType.ZLIB) {
z.istate.mode = CHECK4;
} else {
} else if (z.istate.wrapperType == WrapperType.GZIP){
gzipCRC32 = 0;
gzipISize = 0;
gzipBytesToRead = 4;
z.istate.mode = GZIP_CRC32;
break;
} else {
z.istate.mode = BAD;
z.msg = "unexpected state";
z.istate.marker = 0;
break;
}
case CHECK4:
if (z.avail_in == 0) {

View File

@ -54,6 +54,7 @@ public final class JZlib {
public static final Enum<?> W_NONE = WrapperType.NONE;
public static final Enum<?> W_ZLIB = WrapperType.ZLIB;
public static final Enum<?> W_GZIP = WrapperType.GZIP;
public static final Enum<?> W_ZLIB_OR_NONE = WrapperType.ZLIB_OR_NONE;
// compression levels
public static final int Z_NO_COMPRESSION = 0;
@ -103,6 +104,6 @@ public final class JZlib {
static final int MAX_BL_BITS = 7;
static enum WrapperType {
NONE, ZLIB, GZIP;
NONE, ZLIB, GZIP, ZLIB_OR_NONE;
}
}