Parse a WebSocket handshake response. This is a generator-based coroutine. The reason phrase and headers are expected to contain only ASCII characters. Other characters are represented with surrogate escapes. Args: read_line: Generator-based co
(
cls,
read_line: Callable[[int], Generator[None, None, bytes | bytearray]],
read_exact: Callable[[int], Generator[None, None, bytes | bytearray]],
read_to_eof: Callable[[int], Generator[None, None, bytes | bytearray]],
proxy: bool = False,
)
| 209 | |
| 210 | @classmethod |
| 211 | def parse( |
| 212 | cls, |
| 213 | read_line: Callable[[int], Generator[None, None, bytes | bytearray]], |
| 214 | read_exact: Callable[[int], Generator[None, None, bytes | bytearray]], |
| 215 | read_to_eof: Callable[[int], Generator[None, None, bytes | bytearray]], |
| 216 | proxy: bool = False, |
| 217 | ) -> Generator[None, None, Response]: |
| 218 | """ |
| 219 | Parse a WebSocket handshake response. |
| 220 | |
| 221 | This is a generator-based coroutine. |
| 222 | |
| 223 | The reason phrase and headers are expected to contain only ASCII |
| 224 | characters. Other characters are represented with surrogate escapes. |
| 225 | |
| 226 | Args: |
| 227 | read_line: Generator-based coroutine that reads a LF-terminated |
| 228 | line or raises an exception if there isn't enough data. |
| 229 | read_exact: Generator-based coroutine that reads the requested |
| 230 | bytes or raises an exception if there isn't enough data. |
| 231 | read_to_eof: Generator-based coroutine that reads until the end |
| 232 | of the stream. |
| 233 | |
| 234 | Raises: |
| 235 | EOFError: If the connection is closed without a full HTTP response. |
| 236 | SecurityError: If the response exceeds a security limit. |
| 237 | LookupError: If the response isn't well formatted. |
| 238 | ValueError: If the response isn't well formatted. |
| 239 | |
| 240 | """ |
| 241 | # https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2 |
| 242 | |
| 243 | try: |
| 244 | status_line = yield from parse_line(read_line) |
| 245 | except EOFError as exc: |
| 246 | raise EOFError("connection closed while reading HTTP status line") from exc |
| 247 | |
| 248 | try: |
| 249 | protocol, raw_status_code, raw_reason = status_line.split(b" ", 2) |
| 250 | except ValueError: # not enough values to unpack (expected 3, got 1-2) |
| 251 | raise ValueError(f"invalid HTTP status line: {d(status_line)}") from None |
| 252 | if proxy: # some proxies still use HTTP/1.0 |
| 253 | if protocol not in [b"HTTP/1.1", b"HTTP/1.0"]: |
| 254 | raise ValueError( |
| 255 | f"unsupported protocol; expected HTTP/1.1 or HTTP/1.0: " |
| 256 | f"{d(status_line)}" |
| 257 | ) |
| 258 | else: |
| 259 | if protocol != b"HTTP/1.1": |
| 260 | raise ValueError( |
| 261 | f"unsupported protocol; expected HTTP/1.1: {d(status_line)}" |
| 262 | ) |
| 263 | try: |
| 264 | status_code = int(raw_status_code) |
| 265 | except ValueError: # invalid literal for int() with base 10 |
| 266 | raise ValueError( |
| 267 | f"invalid status code; expected integer; got {d(raw_status_code)}" |
| 268 | ) from None |
nothing calls this directly
no test coverage detected