Read an HTTP/1.1 GET request and return ``(path, headers)``. ``path`` isn't URL-decoded or validated in any way. ``path`` and ``headers`` are expected to contain only ASCII characters. Other characters are represented with surrogate escapes. :func:`read_request` doesn't attem
(stream: asyncio.StreamReader)
| 43 | |
| 44 | |
| 45 | async def read_request(stream: asyncio.StreamReader) -> tuple[str, Headers]: |
| 46 | """ |
| 47 | Read an HTTP/1.1 GET request and return ``(path, headers)``. |
| 48 | |
| 49 | ``path`` isn't URL-decoded or validated in any way. |
| 50 | |
| 51 | ``path`` and ``headers`` are expected to contain only ASCII characters. |
| 52 | Other characters are represented with surrogate escapes. |
| 53 | |
| 54 | :func:`read_request` doesn't attempt to read the request body because |
| 55 | WebSocket handshake requests don't have one. If the request contains a |
| 56 | body, it may be read from ``stream`` after this coroutine returns. |
| 57 | |
| 58 | Args: |
| 59 | stream: Input to read the request from. |
| 60 | |
| 61 | Raises: |
| 62 | EOFError: If the connection is closed without a full HTTP request. |
| 63 | SecurityError: If the request exceeds a security limit. |
| 64 | ValueError: If the request isn't well formatted. |
| 65 | |
| 66 | """ |
| 67 | # https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.1 |
| 68 | |
| 69 | # Parsing is simple because fixed values are expected for method and |
| 70 | # version and because path isn't checked. Since WebSocket software tends |
| 71 | # to implement HTTP/1.1 strictly, there's little need for lenient parsing. |
| 72 | |
| 73 | try: |
| 74 | request_line = await read_line(stream) |
| 75 | except EOFError as exc: |
| 76 | raise EOFError("connection closed while reading HTTP request line") from exc |
| 77 | |
| 78 | try: |
| 79 | method, raw_path, version = request_line.split(b" ", 2) |
| 80 | except ValueError: # not enough values to unpack (expected 3, got 1-2) |
| 81 | raise ValueError(f"invalid HTTP request line: {d(request_line)}") from None |
| 82 | |
| 83 | if method != b"GET": |
| 84 | raise ValueError(f"unsupported HTTP method: {d(method)}") |
| 85 | if version != b"HTTP/1.1": |
| 86 | raise ValueError(f"unsupported HTTP version: {d(version)}") |
| 87 | path = raw_path.decode("ascii", "surrogateescape") |
| 88 | |
| 89 | headers = await read_headers(stream) |
| 90 | |
| 91 | return path, headers |
| 92 | |
| 93 | |
| 94 | async def read_response(stream: asyncio.StreamReader) -> tuple[int, str, Headers]: |
searching dependent graphs…