du21064 2015-04-08 11:35
浏览 504
已采纳

Golang:“ compress / flate”模块无法解压缩有效的deflate压缩HTTP正文

This question continues the discussion started here. I found out that the HTTP response body can't be unmarshaled into JSON object because of deflate compression of the latter. Now I wonder how can I perform decompression with Golang. I will appreciate anyone who can show the errors in my code.

Input data

I've dumped the HTTP response body into the 'test' file. Here is it:

$ cat test
x��PAN�0�
;��NtJ�FӮdU�|"oVR�C%�f�����Z.�^Hs�dW뮑�'��DH�S�SFVC����r)G,�����<���z}�x_g�+�2��sl�r/�Oy>��J3\�G�9���N���#[5M�^v/�2Ҕ��|�h��[�~7�_崛<D*���/��i

Let's make sure that this file can be decompressed and even contains valid JSON:

$ zlib-flate -uncompress < test
{"timestamp":{"tv_sec":1428488670,"tv_usec":197041},"string_timestamp":"2015-04-08 10:24:30.197041","monitor_status":"enabled","commands":{"REVERSE_LOOKUP":{"cache":{"outside":{"successes":0,"failures":0,"size":0,"time":0},"internal":{"successes":0,"failures":0,"size":0,"time":0}},"disk":{"outside":{"successes":0,"failures":0,"size":0,"time":0},"internal":{"successes":13366,"failures":0,"size":0,"time":501808}},"total":{"storage":{"successes":0,"failures":0},"proxy":{"successes":13366,"failures":0}}},"clients":{}}}
$ zlib-flate -uncompress < test | python -m json.tool
{
    "commands": {
        "REVERSE_LOOKUP": {
            "cache": {
               ....

Source code

package main

import (
    "bytes"
    "compress/flate"
    "fmt"
    "io/ioutil"
)

func main() {
    fname := "./test"
    content, err := ioutil.ReadFile(fname)
    if err != nil {
        panic(err)
    }
    fmt.Println("File content:
", content)

    enflated, err := ioutil.ReadAll(flate.NewReader(bytes.NewReader(content)))
    if err != nil {
        panic(err)
    }
    fmt.Println("Enflated:
", enflated)
}

Error

$ go run uncompress.go 
File content:
 [120 156 181 80 65 78 195 48 16 252 10 242 57 69 118 226 166 38 247 156 64 42 42 130 107 100 156 165 88 196 118 149 93 35 160 234 223 89 183 61 112 42 226 192 109 118 118 102 103 180 123 65 62 0 146 13 59 209 237 5 189 15 8 78 116 74 215 70 27 211 174 100 85 184 124 34 111 86 82 171 67 37 144 102 31 183 195 15 167 168 165 90 46 164 94 72 115 165 100 87 235 174 145 215 39 189 168 68 72 209 83 154 7 22 83 70 86 67 180 207 19 140 188 114 41 4 27 71 44 225 155 254 169 223 60 244 195 221 122 125 251 120 95 24 103 221 43 20 144 50 161 31 143 16 179 115 128 8 108 225 114 47 214 79 121 62 15 232 191 224 8 74 51 6 92 213 71 130 57 218 233 175 78 182 142 30 223 254 35 91 53 77 219 94 118 47 165 50 210 148 18 148 232 124 128 31 104 183 151 91 176 126 55 167 143 207 95 3 15 229 180 155 60 68 42 159 231 241 27 47 165 167 25]
panic: flate: corrupt input before offset 5

goroutine 1 [running]:
runtime.panic(0x4a7180, 0x5)
    /usr/lib/go/src/pkg/runtime/panic.c:266 +0xb6
main.main()
    /home/isaev/side-projects/elliptics-manager/uncompress.go:20 +0x2a3
exit status 2

PS Ubuntu 14.10, Go 1.2.1

  • 写回答

1条回答 默认 最新

  • doujiayao8433 2015-04-08 11:55
    关注

    Your input is not a simple deflated block, it's a zlib stream.

    According to the ZLIB Compressed Data Format Specification 3.3 the first 2 bytes are:

    -------------
    | CMF | FLG |
    -------------
    

    The Compression Method and flags. Your input starts with [120, 156] which is 78 9C in hexa. This is the Default Compression. Also no dictionary follows, so the subsequent data is the compressed data.

    Bits 0 to 3 are CM Compression Method and bits 4 to 7 are CINFO Compression Info. In this case CINFO=7 indicates a 32K window size, CM=8 denotes the "deflate" compression method. FLG bit 5 tells if a dictionary is preset, which is in this case. Details of the FLG are also in the linked RFC 1950.

    So your input basically tells the rest of the data was constructed using default compression, but the go flate package does not decode this.

    Change your decompression to omit the first 2 bytes like this and it will work:

    enflated, err := ioutil.ReadAll(flate.NewReader(bytes.NewReader(content[2:])))
    

    Try it on the Go Playground. But...

    Use Proper ZLib decompression!

    We got lucky this time because the compression level is the default and dictionary was preset. If not, you won't be able to decode it using the flate package. Since the input is a zlib stream, you should use the compress/zlib package to properly decode it and not rely on luck:

    r, err := zlib.NewReader(bytes.NewReader(content))
    if err != nil {
        panic(err)
    }
    enflated, err := ioutil.ReadAll(r)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(enflated))
    

    Try the zlib variant on the Go Playground.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效