gzip 与 deflate
2009-02-06 14:07:24 | 才被看了855次 | 要评论?
分类: 未分类 | 发布: OurApache | 来源:唐福林
Tags: deflate,gzip
新东家还没有报道,就安排先做一个小任务:把 nginx 的 gzip 换成 deflate ,问为什么,老大说能省 18 个字节。
在baidu上搜了好久,搜到的中文基本上都是讲 apache 的 gzip(apache 1.3) 和 deflate(apache 2.x)的配置的,仅有的几个跟 nginx 相关的,也逃不出配置文件的范畴。至于原理,算法等等,只有去 Google 英文资料了。
换了关键词,直接搜 zlib ,终于找到一些有用的东西,在 http://www.cppblog.com/jinq0123/archive/2007/07/09/HttpCompressConv.html 处看到这样一段话:
deflate与gzip解压的代码几乎相同,应该可以合成一块代码。
区别仅有:
- deflate使用inflateInit(),而gzip使用inflateInit2()进行初始化,比 inflateInit()多一个参数: -MAX_WBITS,表示处理raw deflate数据。因为gzip数据中的zlib压缩数据块没有zlib header的两个字节。使用inflateInit2时要求zlib库忽略zlib header。在zlib手册中要求windowBits为8..15,但是实际上其它范围的数据有特殊作用,见zlib.h中的注释,如负数表示raw deflate。
- Apache的deflate变种可能也没有zlib header,需要添加假头后处理。即MS的错误deflate (raw deflate).zlib头第1字节一般是0×78, 第2字节与第一字节合起来的双字节应能被31整除,详见rfc1950。例如Firefox的zlib假头为0×7801,python zlib.compress()结果头部为0x789c。
再去检查 zlib.h 中的注释说明,在 zlib-1.2.3/zlib.h Line 500 的地方发现这样一段话:
The windowBits parameter is the base two logarithm of the window size
(the size of the history buffer). It should be in the range 8..15 for this
version of the library. Larger values of this parameter result in better
compression at the expense of memory usage. The default value is 15 if
deflateInit is used instead.windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
determines the window size. deflate() will then generate raw deflate data
with no zlib header or trailer, and will not compute an adler32 check value.windowBits can also be greater than 15 for optional gzip encoding. Add
16 to windowBits to write a simple gzip header and trailer around the
compressed data instead of a zlib wrapper. The gzip header will have no
file name, no extra data, no comment, no modification time (set to zero),
no header crc, and the operating system will be set to 255 (unknown). If a
gzip stream is being written, strm->adler is a crc32 instead of an adler32.
回过头来看 nginx 和 apache 的实现:
nginx-0.6.34/src/http/modules/ngx_http_gzip_filter_module.c Line 335:
rc = deflateInit2(&ctx->zstream, (int) conf->level, Z_DEFLATED,
-wbits, memlevel, Z_DEFAULT_STRATEGY);
httpd-2.0.63/modules/filters/mod_deflate.c Line 374:
zRC = deflateInit2(&ctx->stream, c->compressionlevel, Z_DEFLATED,
c->windowSize, c->memlevel,
Z_DEFAULT_STRATEGY);(Line 153: c->windowSize = i * -1; )
也就是说,nginx 和 apache 在程序里处理的都是 raw deflate data ,windowBits 都是负数,那为什么 Content-Encoding 都写的是 gzip 而不是 deflate 呢?
在 apache 的 mod_deflate.c 里,首先发现了这样一个写入 gzip header 的动作:
/* RFC 1952 Section 2.3 dictates the gzip header:
*
* +—+—+—+—+—+—+—+—+—+—+
* |ID1|ID2|CM |FLG| MTIME |XFL|OS |
* +—+—+—+—+—+—+—+—+—+—+
*
* If we wish to populate in MTIME (as hinted in RFC 1952), do:
* putLong(date_array, apr_time_now() / APR_USEC_PER_SEC);
* where date_array is a char[4] and then print date_array in the
* MTIME position. WARNING: ENDIANNESS ISSUE HERE.
*/
buf = apr_psprintf(r->pool, “%c%c%c%c%c%c%c%c%c%c”, deflate_magic[0],
deflate_magic[1], Z_DEFLATED, 0 /* flags */,
0, 0, 0, 0 /* 4 chars for mtime */,
0 /* xflags */, OS_CODE);
deflate_magic 是这样定义的:
/* magic header */
static char deflate_magic[2] = { ‘
