Compression zlib充气返回Z“数据错误”;标题检查不正确“;

Compression zlib充气返回Z“数据错误”;标题检查不正确“;,compression,zlib,deflate,spdy,Compression,Zlib,Deflate,Spdy,我正在尝试在web服务器上开发我自己的SPDY支持实现,SPDY是一个Google实验协议,用于减少加载网页的延迟。客户端/服务器交互通过“流”进行,即客户端和服务器之间名为“帧”的SPDY信息单元的双向交换。其中一些帧中有一个头块,并且该块总是被压缩的。我正在使用以下函数(web服务器是用C编写的)来解压缩一个“头块”,压缩/解压缩算法是deflate,因此zlib就是这样: int spdy_decompress_header_block( Byte* data, size_t data_l

我正在尝试在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_流的威胁,内部状态已经通过使用字典“预热”(也包括在SPDY规范中)。 字典设置和z_流初始化成功,第一个块解压缩工作正常,第二个帧块解压缩失败

rv=充气(减压、同步冲洗)

返回值为-3(Z_数据_错误),decomp->msg设置为“不正确的标题检查”。在我看来,充气机找不到zlib头。压缩和解压数据是通过使用Z_SYNC_FLUSH调用deflate()和inflate()来完成的,正如google规范所建议的那样,我在chromium(我实际用于测试的浏览器)源代码中检查了这一点。 第一个块(已成功解压缩)是:

而第二个街区(让我抓狂)是:

在这两个帧中,我都能识别出
Z_SYNC\u 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;
}

有关更多信息,请参阅有趣的内容:

嗨,Ramon,我在能够捕捉到的任何跟踪的第二个块上的SPDY帧也面临同样的问题。您是否有机会调整zlib流以使其正常工作?我也有同样的问题,您是否能够找到解决方案?我注意到您的第二个块,压缩方法设置为10(bin 1010),通常对于deflate is应该是8(1000),但是是的,我可以识别拖车0x00 0x00 0xFF 0xFF,这意味着它是zlib压缩。有人对此有什么见解吗?嗨,伙计们,我真的很抱歉我的缺席,使用Z_SYNC_FLUSH FLUSH FLUSH方法会导致生成单个zlib流的“块”(这不是一个正确的定义),压缩器和解压缩器可以以完全相同的顺序交换。每个区块都有一个预告片,所以解压器可以重新识别区块的结尾。压缩机和减压器可以获得一种同步,因此充气器(减压器)不应存在,它会擦除减压器内部状态,失去与压缩机块流的同步。因此,我建议您只初始化解压器一次。如果它有用,请参阅我在spdy dev group上的帖子:
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                                    
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;
}