Parse a WebSocket frame. This is a generator-based coroutine. Args: read_exact: Generator-based coroutine that reads the requested bytes or raises an exception if there isn't enough data. mask: Whether the frame should be masked i.e.
(
cls,
read_exact: Callable[[int], Generator[None, None, bytes | bytearray]],
*,
mask: bool,
max_size: int | None = None,
extensions: Sequence[extensions.Extension] | None = None,
)
| 199 | |
| 200 | @classmethod |
| 201 | def parse( |
| 202 | cls, |
| 203 | read_exact: Callable[[int], Generator[None, None, bytes | bytearray]], |
| 204 | *, |
| 205 | mask: bool, |
| 206 | max_size: int | None = None, |
| 207 | extensions: Sequence[extensions.Extension] | None = None, |
| 208 | ) -> Generator[None, None, Frame]: |
| 209 | """ |
| 210 | Parse a WebSocket frame. |
| 211 | |
| 212 | This is a generator-based coroutine. |
| 213 | |
| 214 | Args: |
| 215 | read_exact: Generator-based coroutine that reads the requested |
| 216 | bytes or raises an exception if there isn't enough data. |
| 217 | mask: Whether the frame should be masked i.e. whether the read |
| 218 | happens on the server side. |
| 219 | max_size: Maximum payload size in bytes. |
| 220 | extensions: List of extensions, applied in reverse order. |
| 221 | |
| 222 | Raises: |
| 223 | EOFError: If the connection is closed without a full WebSocket frame. |
| 224 | PayloadTooBig: If the frame's payload size exceeds ``max_size``. |
| 225 | ProtocolError: If the frame contains incorrect values. |
| 226 | |
| 227 | """ |
| 228 | # Read the header. |
| 229 | data = yield from read_exact(2) |
| 230 | head1, head2 = struct.unpack("!BB", data) |
| 231 | |
| 232 | # While not Pythonic, this is marginally faster than calling bool(). |
| 233 | fin = True if head1 & 0b10000000 else False |
| 234 | rsv1 = True if head1 & 0b01000000 else False |
| 235 | rsv2 = True if head1 & 0b00100000 else False |
| 236 | rsv3 = True if head1 & 0b00010000 else False |
| 237 | |
| 238 | try: |
| 239 | opcode = Opcode(head1 & 0b00001111) |
| 240 | except ValueError as exc: |
| 241 | raise ProtocolError("invalid opcode") from exc |
| 242 | |
| 243 | if (True if head2 & 0b10000000 else False) != mask: |
| 244 | raise ProtocolError("incorrect masking") |
| 245 | |
| 246 | length = head2 & 0b01111111 |
| 247 | if length == 126: |
| 248 | data = yield from read_exact(2) |
| 249 | (length,) = struct.unpack("!H", data) |
| 250 | elif length == 127: |
| 251 | data = yield from read_exact(8) |
| 252 | (length,) = struct.unpack("!Q", data) |
| 253 | if max_size is not None and length > max_size: |
| 254 | raise PayloadTooBig(length, max_size) |
| 255 | if mask: |
| 256 | mask_bytes = yield from read_exact(4) |
| 257 | |
| 258 | # Read the data. |