zlib inflate返回Z_DATA_ERROR“不正确的标题检查”

时间:2013-03-18 15:41:16

标签: compression zlib deflate spdy

我正在尝试在Web服务器上开发自己的SPDY支持实现,SPDY是一种用于减少加载网页延迟的Google实验性协议。客户端/服务器交互通过“流”发生,就像在客户端和服务器之间的SPDY信息单元(称为“帧”)的双向交换一样。其中一些帧中有一个标题块,并且该块总是被压缩。我正在使用以下功能(Web服务器是用C编写的)解压缩“头块”,压缩/解压缩算法是deflate,所以zlib就是这样:

int spdy_decompress_header_block( Byte* data, size_t data_len, unsigned char* processed, size_t* processed_len, z_stream* decomp) {

if (!decomp) {
    // I should return error...
    spdy_log_error("Error occurred getting decompressor!!!");
    return -1;
}

char decomp_buffer[HEADER_CHUNK_MAX_SIZE];
size_t decompressed_len = 0;
int rv = -1;

inflateReset(decomp);
decomp->next_in = data;
decomp->avail_in = data_len;
while (decomp->avail_in > 0) {

    decomp->next_out = (Byte*)decomp_buffer;
    decomp->avail_out = HEADER_CHUNK_MAX_SIZE;

    rv = inflate(decomp,Z_SYNC_FLUSH);

    if (rv == Z_NEED_DICT) {

        uLong dictionary_id = calculate_dictionary_id((Byte*)SPDY_dictionary, sizeof(SPDY_dictionary));

        if (decomp->adler == dictionary_id){

            rv = inflateSetDictionary(decomp, (Byte*)SPDY_dictionary, sizeof(SPDY_dictionary));
            rv = inflate(decomp, Z_SYNC_FLUSH);
        }

    }

    if ((rv == Z_OK) || ((rv == Z_BUF_ERROR) && (decomp->avail_in == 0))) {
        decompressed_len = HEADER_CHUNK_MAX_SIZE - decomp->avail_out;
        if (decompressed_len > 0) {
            memcpy(processed + *processed_len, decomp_buffer, decompressed_len);
            *processed_len += decompressed_len;
        }

    } else {
        if(rv == Z_DATA_ERROR){
            spdy_log_error("Error inflating headers:  Z_DATA_ERROR encountered" );
        }else{
            spdy_log_error("Error inflating headers!!!");
        }
        return -1;
    }

}
return *processed_len;

}

SPDY规范建议为SPDY会话中的每个帧(对应于TCP连接)重用流中每个帧的相同压缩器/解压缩器 ,这样每个头块都由z_stream进行威胁内部状态已经通过使用字典(也包括在SPDY规范中)“加热”。 字典设置和z_stream初始化都是成功的,第一块解压缩工作正常,第二帧块解压缩失败

  

rv = inflate(decomp,Z_SYNC_FLUSH);

返回值为-3(Z_DATA_ERROR),decomp-> msg设置为“不正确的标题检查”。在我看来膨胀无法找到zlib标头。压缩和解压缩数据是通过谷歌规范建议使用Z_SYNC_FLUSH调用deflate()和inflate()来完成的,我在chrome(浏览器我实际用于测试)源代码中检查了这一点。 第一个块(成功解压缩)是:

00111000 11101010 11011111 10100010 01010001 10110010 01100010 11100000 01100110 01100000
10000011 10100100 00010111 00000110 01111011 10111000 00001011 01110101 00110000 00101100
...
00001000 01001110 01001100 01001011 00101100 11001010 10000100 01101010 01100010 01100000
10000111 01000110 00001001 00000011 00000111 00101100 10100110 00000000 00000000 00000000
00000000 11111111 11111111      

而第二块(这让我发疯)是:

00011010 01110110 00010001 00000011 00010000 01000000 10111001 10001001 00010101 10111010 10001001 11101001 10101001 10110110 00000110 00000000 00000001 01000100 01101110 11000100 00000000 00000100 10010000 00111110 01000000 00000000 00001101 10001110 10001000 00000001 00000000 00000000 00000000 11111111 11111111                                    

在他们两个中我都能识别Z_SYNC_FLUSH预告片(00FF),但我无法确定第二帧是否在其开头有正确的标题。我的问题:第二个压缩内容实际上是无头?并且,在这种情况下,我可以通过哪种方式解压缩此流,可能使用原始deflate解压缩(使用inflateBack())?

就像我在下面的评论中简要解释的那样,错误发生在inflateReset()调用中,因为它破坏了使用00FF预告片获得的压缩器和解压缩器之间的同步。最后,正确版本的代码将是:

int spdy_decompress_header_block( Byte* data, size_t data_len, unsigned char* processed,     size_t* processed_len, z_stream* decomp) {

if (!decomp) {
    // I should return error...
    spdy_log_error("Error occurred getting decompressor!!!");
    return -1;
}

char decomp_buffer[HEADER_CHUNK_MAX_SIZE];
size_t decompressed_len = 0;
int rv = -1;

decomp->next_in = data;
decomp->avail_in = data_len;
while (decomp->avail_in > 0) {

    decomp->next_out = (Byte*)decomp_buffer;
    decomp->avail_out = HEADER_CHUNK_MAX_SIZE;

    rv = inflate(decomp,Z_SYNC_FLUSH);

    if (rv == Z_NEED_DICT) {

        uLong dictionary_id = calculate_dictionary_id((Byte*)SPDY_dictionary, sizeof(SPDY_dictionary));

        if (decomp->adler == dictionary_id){

            rv = inflateSetDictionary(decomp, (Byte*)SPDY_dictionary, sizeof(SPDY_dictionary));
            rv = inflate(decomp, Z_SYNC_FLUSH);
        }

    }

    if ((rv == Z_OK) || ((rv == Z_BUF_ERROR) && (decomp->avail_in == 0))) {
        decompressed_len = HEADER_CHUNK_MAX_SIZE - decomp->avail_out;
        if (decompressed_len > 0) {
            memcpy(processed + *processed_len, decomp_buffer, decompressed_len);
            *processed_len += decompressed_len;
        }

    } else {
        if(rv == Z_DATA_ERROR){
            spdy_log_error("Error inflating headers:  Z_DATA_ERROR encountered" );
        }else{
            spdy_log_error("Error inflating headers!!!");
        }
        return -1;
    }
}
return *processed_len;
}

有关详细信息,请参阅有趣的:http://www.bolet.org/~pornin/deflate-flush.htm

0 个答案:

没有答案