Chrome DevTools协议-Golang中带有gzip正文的ContinueInterceptedRequest

时间:2018-10-12 23:45:39

标签: google-chrome go google-chrome-devtools gzip

我一直在研究使用chrome devtools protocol进行以下操作的golang脚本:

1)拦截请求

2)抓住被拦截请求的响应正文

3)对html文档进行一些修改

4)继续被拦截的请求

该脚本适用于HTML文档,除非将Content-Encoding设置为gzip。逐步过程如下所示:

1)拦截请求

 s.Debugger.CallbackEvent("Network.requestIntercepted", func(params godet.Params) {
    iid := params.String("interceptionId")
    rtype := params.String("resourceType")
    reason := responses[rtype]
    headers := getHeadersString(params["responseHeaders"])

    log.Println("[+] Request intercepted for", iid, rtype, params.Map("request")["url"])
    if reason != "" {
        log.Println("  abort with reason", reason)
    }

    // Alter HTML in request response
    if s.Options.AlterDocument && rtype == "Document" && iid != "" {
        res, err := s.Debugger.GetResponseBodyForInterception(iid)

        if err != nil {
            log.Println("[-] Unable to get intercepted response body!")
        }

        rawAlteredResponse, err := AlterDocument(res, headers)
        if err != nil{
            log.Println("[-] Unable to alter HTML")
        }

        if rawAlteredResponse != "" {
            log.Println("[+] Sending modified body")

            err := s.Debugger.ContinueInterceptedRequest(iid, godet.ErrorReason(reason), rawAlteredResponse, "", "", "", nil)
            if err != nil {
                fmt.Println("OH NOES AN ERROR!")
                log.Println(err)
            }
        }
    } else {
        s.Debugger.ContinueInterceptedRequest(iid, godet.ErrorReason(reason), "", "", "", "", nil)
    }
})

2)更改响应正文

在这里,我对procesHtml()中的HTML标记进行了一些小的更改(但是该函数的代码与该问题无关,因此不会在此处发布)。我还会从请求中获取标头,并在必要时更新content-lengthdate,然后再继续响应。然后,我在调用r := gZipCompress([]byte(alteredBody)时gzip压缩主体,该主体返回一个字符串。然后将字符串连接到标题,以便我可以制作rawResponse

func AlterDocument(debuggerResponse []byte, headers map[string]string) (string, error) {
    alteredBody, err := processHtml(debuggerResponse)
    if err != nil {
        return "", err
    }


    alteredHeader := ""
    for k, v := range headers{
        switch strings.ToLower(k) {
            case "content-length":
                v = strconv.Itoa(len(alteredBody))
                fmt.Println("Updating content-length to: " + strconv.Itoa(len(alteredBody)))
                break
            case "date":
                v = fmt.Sprintf("%s", time.Now().Format(time.RFC3339))
                break
        }
        alteredHeader += k + ": " + v + "\r\n"
    }

    r := gZipCompress([]byte(alteredBody))

    rawAlteredResponse := 
    base64.StdEncoding.EncodeToString([]byte("HTTP/1.1 200 OK" + "\r\n" + alteredHeader + "\r\n\r\n\r\n" + r))

    return rawAlteredResponse, nil
}

注意:我现在gzip压缩所有响应的正文。以上是我暂时的解决之道。

gzip压缩功能如下:

func gZipCompress(dataToWorkWith []byte) string{
    var b bytes.Buffer

    gz, err := gzip.NewWriterLevel(&b, 5)
    if err != nil{
        panic(err)
    }
    if _, err := gz.Write(dataToWorkWith); err != nil {
        panic(err)
    }
    if err := gz.Flush(); err != nil {
        panic(err)
    }
    if err := gz.Close(); err != nil {
        panic(err)
    }
    return b.String()
}

如第一个代码段所示,在此处设置了响应正文和标头:

err := s.Debugger.ContinueInterceptedRequest(iid, godet.ErrorReason(reason), rawAlteredResponse, "", "", "", nil)

结果是浏览器中出现一堆乱码。对于未压缩的请求,如果没有gzip功能,则无法使用。我也更改了压缩级别(没有成功)。我是否以错误的顺序处理主体(字符串> [] byte> gzip>字符串> base64)?是否应该以其他顺序进行工作?任何帮助将不胜感激。

响应看起来像这样,Chrome将其放在<body></body>标签中

����rܸ���_A��Q%GH��Kʔ��vU�˷c�v�}

或在回复中:

response screenshot

我还可以说它正在正确压缩,因为当我删除标题时,请求将导致.gz文件下载,并且所有正确的.html都将在未压缩状态下下载。另外,在gZipCompress中返回的对象的前几个字节告诉我它已正确压缩:

31 139 8

0x1f 0x8B 0x08

1 个答案:

答案 0 :(得分:1)

我最终使用了一个不同的库,该库可以更好,更有效地处理更大的响应。

现在,当调用Network.GetResponseBodyForInterception时,似乎DevTools协议在解压缩后但在浏览器中呈现响应主体之前返回响应主体。当然,这只是一个假设,因为在https://github.com/ChromeDevTools/devtools-protocol中看不到该方法的代码。该假设基于以下事实:调用Network.GetResponseBodyForInterception时,获得的响应主体未压缩(尽管它可能是base64编码的)。此外,该方法被标记为实验性的,并且文档中未提及有关压缩响应的任何内容。基于该假设,我将进一步假设,从Network.GetResponseBodyForInterception得到响应的时刻,现在我们自己压缩身体已经为时已晚。我确认正在使用的库不会麻烦压缩或解压缩压缩的响应。

我可以继续使用我的代码,而不必担心gzip压缩的响应,因为我可以毫无问题地更改正文。

作为参考,我现在使用https://github.com/wirepair/gcd,因为它在拦截较大的响应时更加健壮和稳定。