Как сохранить ответ от сервера на диске в виде кэша и как отправить этот ответ веб-браузеру с помощью сокета в Python

Я написал прокси-сервер на Python и попытался создать собственный файл кэша, но на самом деле я не могу решить проблему с кодированием (я не уверен). Я предполагаю, что проблема может вызвать заголовок Content-encoding: gzip.

Это часть для входящего запроса, сервер создает новый поток и выполняет следующую функцию:

def proxy_thread(self, client_socket, client_addres):
    # get the request from browser
    request_queue = []

    request = client_socket.recv(17000)
    method = request.decode("utf-8").split("
")[0].split(" ")[0]

    if method == "GET":

        if is_in_cache(cache_path, request): # check wheter file is in C:TMP directory, if exist use this file

            print("From cache")
            id = parse_url(request)
            cached_request = open_cached_www(cache_path,id)
            remote_server, remote_port = parse_request(request)
            remote_socket = socket.socket(socket.AF_INET,
                                          socket.SOCK_STREAM)  # by default: socket.AF_INET, socket.SOCK_STREAM
            remote_socket.connect((remote_server,
                                   remote_port))

            res = remote_socket.send(cached_request.encode("UTF-8"))
            print(res)

            client_socket.settimeout(5)

        else:

            print("Not from cache")
            remote_server, remote_port = parse_request(request)
            request_queue.append(request)

            remote_socket = socket.socket(socket.AF_INET,
                                          socket.SOCK_STREAM)
            remote_socket.connect((remote_server,
                                   remote_port))

            res = remote_socket.sendall(request)
            client_socket.settimeout(5)


            if res == None:
                try:

                    data = remote_socket.recv(4096)
                    id = parse_url(request) # Function parse request extract url from request, and create HASH
                    client_socket.sendall(data)
                    write_to_cache(cache_path,id)
                    # ERROR: 'utf-8' codec can't decode byte 0x8b in position 367: invalid start byte

                    client_socket.close()
                    print("[*]data send successful!")

                except UnicodeDecodeError as U_err:
                    print(U_err)

Функция ниже, поддержка сервера в кэше чтения / записи

# Function write response from server, here are 
def write_to_cache(path, hash, http_response):
    full_path = path.strip(""") + "\" + hash  # full path to cached file
    with open(full_path, 'w') as write_cache:
        write_cache.write(http_response)
        write_cache.close()
    print("Write co cache successful")

def open_cached_www(path, hash):
    full_path = path.strip(""") + "\" + hash  # full path to cached file
    with open(full_path, "r") as read_cached_www:
        print("Load: ", full_path)
        cached_request = read_cached_www.read()
        read_cached_www.close()

Ниже ответ от http://www.example.com ,

b'HTTP/1.1 200 OK

Content-Encoding: gzip
 #<-- i suppose that might be a problem
Accept-Ranges: bytes

Cache-Control: max-age=604800

Content-Type: text/html; charset=UTF-8

Date: Tue, 14 Jan 2020 16:34:02 GMT

Etag: "3147526947"

Expires: Tue, 21 Jan 2020 16:34:02 GMT

Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT

Server: ECS (nyb/1D11)

Vary: Accept-Encoding

X-Cache: HIT

Content-Length: 648



x1fx8bx08x00xc2x15xa8]x00x03}TMsxdb x10xbdxfbWlxd5K2#$'ix1ax8f-ixfax99ix0fix0fix0f=x12xb1xb2x98x08Px01xc9xf6txf2xdfxbbBx8e#7x99x9ax91x81]xxbbxefxb1x90xbdx12xa6xf4xbbx16xa1xf6xaa)fxd9cx87\x143xa0_xe6xa5oxb0xf8xbcxe5xaamx10>x19xc5xa5xcexd2xd1:x1bx97(xf4x1cxcax9a[x87>x8f:_xb1Ex04i1qxd6xdexb7x0cx7fwxb2xcfxa3x8fF{xd4x9e
a#(xc7Yx1eyxdcxfatx08xbf:@xbdx84xa4xb9xc2<xea%nZcxfddxffF
_xe7x02{Y"x0bx93x18xa4x96^xf2x86xb9x927x98x9f=A9xbf#2Cx06xfbxc0xa5sxd1xe8xbb3bx07x7fxc20Lyyxbfxb6xa6xd3x82x95xa61v	xafxab9xb5xf3xd5ax89xe2v-xf5x12xe6Oxa6x96x0b!xf5xfaxc8VQxa6xacxe2J6xbb%0xdex92x9cxccxedx9cGx15xc3xd8xb3Nxc6xf0xa1x91xfaxfex86x97xb7xc1tMx9bbx88nqmx10~~x8dhxfcxbdE
xb7\xbbaxf2x05x9bx1exbd,9|xc3x0exc9r0xc4xf0xdex12wxc2xa6xa5xccxa1x95xd5S.axf0x10xfex85xec'tx83pKx;x9fxb7xdbxe7x0c/Qx01xefxbcyx81xe89xaaxd5x7fEx13xd4&x19xdcx19+xd02xcbx85xecx1cxe9x94\x1ex01x98-s5x17fCxc8xedx16.xe8xbbxa2ox18xdbxf5x1d?x99xc7xa1%xf3xf3xd3xd5x84x0c_x0exeaxc5xd4xf7xd2Ix8fbBxed1x93x8bxc5x9bxc5bx92xc9pxfeL`i,xf7xd2x10Km4NAxdf)x14x92xc3x89xe2[xb6xd7xe7jxd0xe7tx02~xacxe2QUxfcxa3xd8Dxe5cxc7xc3$dx96x86
-xc2Yexe9xx1dgxd9Px9bt;)xd8xbex8exebxb3g7x93Lxa3xaf-~xd4xd2x81x08vxa0Qe,tx0eax985Mxe7xfc@xb8Gxc0x11xc1
x0ezx0e:Exf7xc9%xf0xcbtDbx17xb6xBx1axabex8fxa6xa1!y	xa0xb3Ht|m:x0fxadx95x14xa24txb4Rx071x81xe6xdcxddSx85x84xe8-Z%x9d#Gx92xa5xed!xcfx8cx1ex08x8bUx1e
xcfx84[xa6xe9fxb3I$xd7<1vx9dx8e!]xbaO3*nx8cx1dHx10xa0
Ax92x84xd0xx11x10xb34x88x93xa5{xa9xd2xf1Axfbx0b(xeb|oxe8x04x00x00'

Мне нужно предоставить этот ответ веб-браузеру, но честно говоря, я не знаю, где проблема. Я думаю, что если я декодирую эти двоичные данные, у меня должен быть чистый HTML-контент, и этот контент должен быть отправлен в браузер в ответ. Я немного застрял :) помогите

Всего 1 ответ


Обратите внимание, что это никоим образом не является правильной или тщательной обработкой HTTP-ответа. Я просто отвечаю на твою проблему с gzip. Чтобы на самом деле реализовать кеш HTTP, вам, вероятно, нужно прочитать больше ... или быть более конкретным в своем вопросе.

Если вы хотите распаковать сжатые данные, вы можете просто использовать:

import gzip

gzip.decompress(data)

Для вашего ответа вы можете попробовать что-то похожее на:

import gzip

response = b'''HTTP/1.1 200 OK
Content-Encoding: gzip
Accept-Ranges: bytes
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Tue, 14 Jan 2020 16:34:02 GMT
Etag: "3147526947"
Expires: Tue, 21 Jan 2020 16:34:02 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Server: ECS (nyb/1D11)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 648

x1fx8bx08x00xc2x15xa8]x00x03}TMsxdb x10xbdxfbWlxd5K2#$'ix1ax8f-ixfax99ix0fix0fix0f=x12xb1xb2x98x08Px01xc9xf6txf2xdfxbbBx8e#7x99x9ax91x81]xxbbxefxb1x90xbdx12xa6xf4xbbx16xa1xf6xaa)fxd9cx87\x143xa0_xe6xa5oxb0xf8xbcxe5xaamx10>x19xc5xa5xcexd2xd1:x1bx97(xf4x1cxcax9a[x87>x8f:_xb1Ex04i1qxd6xdexb7x0cx7fwxb2xcfxa3x8fF{xd4x9e
a#(xc7Yx1eyxdcxfatx08xbf:@xbdx84xa4xb9xc2<xea%nZcxfddxffF
_xe7x02{Y"x0bx93x18xa4x96^xf2x86xb9x927x98x9f=A9xbf#2Cx06xfbxc0xa5sxd1xe8xbb3bx07x7fxc20Lyyxbfxb6xa6xd3x82x95xa61v	xafxab9xb5xf3xd5ax89xe2v-xf5x12xe6Oxa6x96x0b!xf5xfaxc8VQxa6xacxe2J6xbb%0xdex92x9cxccxedx9cGx15xc3xd8xb3Nxc6xf0xa1x91xfaxfex86x97xb7xc1tMx9bbx88nqmx10~~x8dhxfcxbdE
xb7\xbbaxf2x05x9bx1exbd,9|xc3x0exc9r0xc4xf0xdex12wxc2xa6xa5xccxa1x95xd5S.axf0x10xfex85xec'tx83pKx;x9fxb7xdbxe7x0c/Qx01xefxbcyx81xe89xaaxd5x7fEx13xd4&x19xdcx19+xd02xcbx85xecx1cxe9x94\x1ex01x98-s5x17fCxc8xedx16.xe8xbbxa2ox18xdbxf5x1d?x99xc7xa1%xf3xf3xd3xd5x84x0c_x0exeaxc5xd4xf7xd2Ix8fbBxed1x93x8bxc5x9bxc5bx92xc9pxfeL`i,xf7xd2x10Km4NAxdf)x14x92xc3x89xe2[xb6xd7xe7jxd0xe7tx02~xacxe2QUxfcxa3xd8Dxe5cxc7xc3$dx96x86
-xc2Yexe9xx1dgxd9Px9bt;)xd8xbex8exebxb3g7x93Lxa3xaf-~xd4xd2x81x08vxa0Qe,tx0eax985Mxe7xfc@xb8Gxc0x11xc1
x0ezx0e:Exf7xc9%xf0xcbtDbx17xb6xBx1axabex8fxa6xa1!y	xa0xb3Ht|m:x0fxadx95x14xa24txb4Rx071x81xe6xdcxddSx85x84xe8-Z%x9d#Gx92xa5xed!xcfx8cx1ex08x8bUx1e
xcfx84[xa6xe9fxb3I$xd7<1vx9dx8e!]xbaO3*nx8cx1dHx10xa0
Ax92x84xd0xx11x10xb34x88x93xa5{xa9xd2xf1Axfbx0b(xeb|oxe8x04x00x00'''

preamble, _, body = response.partition(b"

")
preamble_lines = preamble.splitlines()
status = preamble_lines[0]
headers = dict()
for line in preamble_lines[1:]:
    header, value = line.decode("utf-8").split(":", 1)
    headers[header.lower()] = value.strip()

if "content-encoding" in headers and headers["content-encoding"] == "gzip":
    body = gzip.decompress(body)

print(f"Status: {status}")
print(f"Headers: {headers}")
print(f"Body:
{body}")

который выдает в качестве вывода:

Status: b'HTTP/1.1 200 OK'
Headers: {'content-encoding': 'gzip', 'accept-ranges': 'bytes', 'cache-control': 'max-age=604800', 'content-type': 'text/html; charset=UTF-8', 'date': 'Tue, 14 Jan 2020 16:34:02 GMT', 'etag': '"3147526947"', 'expires': 'Tue, 21 Jan 2020 16:34:02 GMT', 'last-modified': 'Thu, 17 Oct 2019 07:18:26 GMT', 'server': 'ECS (nyb/1D11)', 'vary': 'Accept-Encoding', 'x-cache': 'HIT', 'content-length': 髠'}
Body:
b'<!doctype html>
<html>
<head>
    <title>Example Domain</title>

    <meta charset="utf-8" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style type="text/css">
    body {
        background-color: #f0f0f2;
        margin: 0;
        padding: 0;
        font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
        
    }
    div {
        width: 600px;
        margin: 5em auto;
        padding: 2em;
        background-color: #fdfdff;
        border-radius: 0.5em;
        box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
    }
    a:link, a:visited {
        color: #38488f;
        text-decoration: none;
    }
    @media (max-width: 700px) {
        div {
            margin: 0 auto;
            width: auto;
        }
    }
    </style>    
</head>

<body>
<div>
    <h1>Example Domain</h1>
    <p>This domain is for use in illustrative examples in documents. You may use this
    domain in literature without prior coordination or asking for permission.</p>
    <p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
'

Есть идеи?

10000