Read HTTP headers from ``stream``. Non-ASCII characters are represented with surrogate escapes.
(stream: asyncio.StreamReader)
| 144 | |
| 145 | |
| 146 | async def read_headers(stream: asyncio.StreamReader) -> Headers: |
| 147 | """ |
| 148 | Read HTTP headers from ``stream``. |
| 149 | |
| 150 | Non-ASCII characters are represented with surrogate escapes. |
| 151 | |
| 152 | """ |
| 153 | # https://datatracker.ietf.org/doc/html/rfc7230#section-3.2 |
| 154 | |
| 155 | # We don't attempt to support obsolete line folding. |
| 156 | |
| 157 | headers = Headers() |
| 158 | for _ in range(MAX_NUM_HEADERS + 1): |
| 159 | try: |
| 160 | line = await read_line(stream) |
| 161 | except EOFError as exc: |
| 162 | raise EOFError("connection closed while reading HTTP headers") from exc |
| 163 | if line == b"": |
| 164 | break |
| 165 | |
| 166 | try: |
| 167 | raw_name, raw_value = line.split(b":", 1) |
| 168 | except ValueError: # not enough values to unpack (expected 2, got 1) |
| 169 | raise ValueError(f"invalid HTTP header line: {d(line)}") from None |
| 170 | if not _token_re.fullmatch(raw_name): |
| 171 | raise ValueError(f"invalid HTTP header name: {d(raw_name)}") |
| 172 | raw_value = raw_value.strip(b" \t") |
| 173 | if not _value_re.fullmatch(raw_value): |
| 174 | raise ValueError(f"invalid HTTP header value: {d(raw_value)}") |
| 175 | |
| 176 | name = raw_name.decode("ascii") # guaranteed to be ASCII at this point |
| 177 | value = raw_value.decode("ascii", "surrogateescape") |
| 178 | headers[name] = value |
| 179 | |
| 180 | else: |
| 181 | raise SecurityError("too many HTTP headers") |
| 182 | |
| 183 | return headers |
| 184 | |
| 185 | |
| 186 | async def read_line(stream: asyncio.StreamReader) -> bytes: |
searching dependent graphs…