Протокол Chrome DevTools - ContinueInterceptedRequest с телом gzip на Голанге - PullRequest
0 голосов
/ 13 октября 2018

Я работал над сценарием golang, который использует протокол chrome devtools для:

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) Измените тело ответа

Здесь я делаю небольшие изменения в разметке HTML в procesHtml() (но код этой функции не имеет отношения к этой проблеме, поэтому не буду публиковать ее здесь). Я также извлекаю заголовки из запроса и при необходимостиобновите content-length и date, прежде чем продолжить ответ. Затем я gzip сжимаю тело при вызове r := gZipCompress([]byte(alteredBody), который возвращает строку. Затем строка соединяется с заголовками, чтобы я мог обработать 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 для всех ответов. Вышеприведенное является временным, пока я выясняю, как решить эту проблему.функция выглядит следующим образом:

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для не сжатых запросов.Я также изменил уровень сжатия (без успеха).Я обрабатываю тело в неправильном порядке (строка> [] байт> 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 голосов
/ 21 октября 2018

В итоге я использовал другую библиотеку, которая обрабатывает большие ответы лучше и эффективнее.

Теперь кажется, что протокол DevTools возвращает тело ответа после распаковки, но перед его отображением в браузере при вызове Network.GetResponseBodyForInterception.Конечно, это только предположение, поскольку я не вижу кода для этого метода в https://github.com/ChromeDevTools/devtools-protocol. Предположение основано на том факте, что при вызове Network.GetResponseBodyForInterception полученное тело ответа НЕ сжимается (хотя это может бытьзакодировано в base64).Кроме того, метод помечен как экспериментальный, и в документации ничего не говорится о сжатых ответах.Исходя из этого предположения, я также предположу, что в момент, когда мы получим ответ от Network.GetResponseBodyForInterception, уже слишком поздно самостоятельно сжимать тело.Я подтверждаю, что библиотеки, с которыми я работаю, не сжимают и не распаковывают gzip-ответы.

Я могу продолжать работать с моим кодом, не беспокоясь о сжатых gzip-ответах, так как я могу изменитьтело без проблем.

Для справки, я сейчас использую https://github.com/wirepair/gcd,, так как он более устойчив и стабилен при перехвате больших ответов.

...