使用 zlib+dictionary 压缩/解压缩 spdy 名称/值块时出错

Posted

技术标签:

【中文标题】使用 zlib+dictionary 压缩/解压缩 spdy 名称/值块时出错【英文标题】:Error compress/decompress spdy name/value block with zlib+dictionary 【发布时间】:2014-01-22 03:30:42 【问题描述】:

我正在尝试编写一个 spdy 代理服务器,但在压缩/解压缩 spdy 名称/值块时遇到问题。

我正在使用 python 3.3 zlib 库来压缩/解压缩字典。

从chrome 31接收spdy帧时,帧大部分时间都可以解析,但有些name/value块无法正确解压。

我有 3 个测试用例:

import zlib

dictionary = (
b"optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
b"languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
b"f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
b"-agent10010120020120220320420520630030130230330430530630740040140240340440"
b"5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
b"glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
b"ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
b"sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
b"oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
b"ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
b"pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
b"ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
b".1statusversionurl\0")


def decompress(buf):
    decompressor = zlib.decompressobj(zdict=dictionary)
    return decompressor.decompress(buf)

def compress(buf):
    compressor = zlib.compressobj(zdict=dictionary)
    return compressor.compress(buf)

if __name__ == '__main__':
    # Test 1: buf -(compress)-> cb -(decompress)->buf2, buf2 become ''
    buf = b'\x00\x01\x00\x06status\x00\x1a200 Connection established'
    print(buf)
    cb = compress(buf)
    print(cb)  # b'x\xbb\xdf\xa2Q\xb2'
    buf = decompress(cb)
    print(buf) # b''

    # Test 2: This name/value block data was sent by chrome, which decompressed correctly
    print(decompress(b'8\xea\xdf\xa2Q\xb2b`e`\x01\xe5\x12\x06\x9e4`\xc6K\x02\x06\x83^r~.\x03[.0o\xe6\xa70\xb0;\xfb\xfb\xf9\xb9:\x8700\x83\x14\x0b\x00\x04PZbrjR~~\xb6^r~\xae\x95\x89\x891@\x001p!\x12<C\x8eo~UfNN\xa2\xbe\xa9\x9e\x81\x82Fxf^J~y\xb1\x82_\x88\x82\x99\x9e\xa1\xb5B\xb8\x7f\xb8\x99\x89\xa6\x82#\xd0K\xa9\xe1\xa9I\xde\x99%\xfa\xa6\xc6\xe6z\xc6f\n\x1a\xde\x1e!\xbe>:\n9\x99\xd9\xa9\n\xee\xa9\xc9\xd9\xf9\x9a\n\xce\x19\xc0\xdc\x9b\xaaol\xa8g\xa0ghfj\xa0gf\xac\x10\x9c\x98\x96X\x94\t\xd5\xc5\xc0\x0e\xf5\x04\x03\x07\xcco\x00\x00\x00\x00\xff\xff'))
    # b'\x00\x05\x00\x04host\x00\x0cfacebook.com\x00\x06method\x00\x07CONNECT\x00\x03url\x00\x10facebook.com:443\x00\nuser-agent\x00lMozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36\x00\x07version\x00\x08HTTP/1.1'

    # Test 3: This was another name/value block data sent by chrome, which can not be decompressed
    print(decompress(b'"\xcd+\x00\x01\x94\x96\x98\x9c\x9a\x94\x9f\x9f\xad\x97\x9c\x9fkebb\x0c\x10@\x83\xca+\x00\x00\x00\x00\xff\xff'))
    # Error -3 while decompressing data: incorrect header check

我是 python3+zlib 的新手(在这个项目之前使用 python 2.7)和 spdy。 非常感谢您的帮助。

【问题讨论】:

【参考方案1】:

压缩和解压都需要刷新。否则,部分或全部数据保留在对象中。即:

def decompress(buf):
    decompressor = zlib.decompressobj()
    result = decompressor.decompress(buf)
    return result + decompressor.flush()

def compress(buf):
    compressor = zlib.compressobj()
    result = compressor.compress(buf)
    return result + compressor.flush()

【讨论】:

以上是关于使用 zlib+dictionary 压缩/解压缩 spdy 名称/值块时出错的主要内容,如果未能解决你的问题,请参考以下文章

使用 zlib 解压缩文件 - 卡在 256kb 限制

Zlib在C中解压缩具有未知压缩长度的字节

Python zlib 解压缩 gzipped 数据

13MD5编码Zlib压缩解压缩

zLib inflate() 在解压缩缓冲区时挂起

zlib gunzip解压缩每个在同一文件上运行的不同缓冲区大小