summaryrefslogtreecommitdiff
path: root/day9/task5/utils.py
blob: c1b3a044071730a58df87299fc63e24e5baa0c69 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
from io import BytesIO


CHUNK_SIZE = 49600

HTTP_STATUS_CODES = {
    100: "Continue",
    101: "Switching Protocols",
    102: "Processing",
    200: "OK",
    201: "Created",
    202: "Accepted",
    203: "Non Authoritative Information",
    204: "No Content",
    205: "Reset Content",
    206: "Partial Content",
    207: "Multi Status",
    226: "IM Used",  # see RFC 3229
    300: "Multiple Choices",
    301: "Moved Permanently",
    302: "Found",
    303: "See Other",
    304: "Not Modified",
    305: "Use Proxy",
    307: "Temporary Redirect",
    308: "Permanent Redirect",
    400: "Bad Request",
    401: "Unauthorized",
    402: "Payment Required",  # unused
    403: "Forbidden",
    404: "Not Found",
    405: "Method Not Allowed",
    406: "Not Acceptable",
    407: "Proxy Authentication Required",
    408: "Request Timeout",
    409: "Conflict",
    410: "Gone",
    411: "Length Required",
    412: "Precondition Failed",
    413: "Request Entity Too Large",
    414: "Request URI Too Long",
    415: "Unsupported Media Type",
    416: "Requested Range Not Satisfiable",
    417: "Expectation Failed",
    418: "I'm a teapot",  # see RFC 2324
    421: "Misdirected Request",  # see RFC 7540
    422: "Unprocessable Entity",
    423: "Locked",
    424: "Failed Dependency",
    426: "Upgrade Required",
    428: "Precondition Required",  # see RFC 6585
    429: "Too Many Requests",
    431: "Request Header Fields Too Large",
    449: "Retry With",  # proprietary MS extension
    451: "Unavailable For Legal Reasons",
    500: "Internal Server Error",
    501: "Not Implemented",
    502: "Bad Gateway",
    503: "Service Unavailable",
    504: "Gateway Timeout",
    505: "HTTP Version Not Supported",
    507: "Insufficient Storage",
    510: "Not Extended",
}

SUCCESS_CODE = 200
BAD_REQUEST_CODE = 400
NOT_FOUND_CODE = 404
METHOD_NOT_ALLOWED_CODE = 405


def render_template(path, **kwargs):
    with open(path, encoding='utf-8') as f:
        template = f.read()

    for key in kwargs:
        template = template.replace(f'%%{key}%%', kwargs[key])

    return template


def parse_multipart_form(data: bytes):
    b = BytesIO(data)
    separator = b.readline().strip()

    files = []

    while True:
        line = b.readline().strip().strip(b'-')
        if not line:
            break

        headers_raw = []
        while not line.strip() == b'':
            headers_raw.append(line.strip().decode())
            line = b.readline()

        headers = {'Content-Type': headers_raw[1].split(': ')[1]}
        for pair in headers_raw[0].split(': ')[1].split('; ')[1:]:
            key, value = pair.split('=')
            headers[key] = value[1:-1]

        data = b''
        prev_chunk = b.read(CHUNK_SIZE)
        chunk = b.read(CHUNK_SIZE)
        while separator not in (prev_chunk + chunk):
            data += prev_chunk
            prev_chunk = chunk
            chunk = b.read(CHUNK_SIZE)

            if not chunk:
                break

        chunk = (prev_chunk + chunk)
        if chunk.startswith(separator) or chunk.endswith(separator):
            with_sep = chunk.strip(separator)
        else:
            if separator in chunk:
                with_sep, buffer = chunk.split(separator)
                b = BytesIO(buffer + b.read())
                b.readline()

            else:
                with_sep = chunk

        data += with_sep
        headers['data'] = data

        files.append(headers)

    return files