Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 

759 rader
26 KiB

  1. from __future__ import annotations
  2. import enum
  3. import logging
  4. import uuid
  5. from collections.abc import Generator
  6. from typing import Union
  7. from .exceptions import (
  8. ConnectionClosed,
  9. ConnectionClosedError,
  10. ConnectionClosedOK,
  11. InvalidState,
  12. PayloadTooBig,
  13. ProtocolError,
  14. )
  15. from .extensions import Extension
  16. from .frames import (
  17. OK_CLOSE_CODES,
  18. OP_BINARY,
  19. OP_CLOSE,
  20. OP_CONT,
  21. OP_PING,
  22. OP_PONG,
  23. OP_TEXT,
  24. Close,
  25. CloseCode,
  26. Frame,
  27. )
  28. from .http11 import Request, Response
  29. from .streams import StreamReader
  30. from .typing import LoggerLike, Origin, Subprotocol
  31. __all__ = [
  32. "Protocol",
  33. "Side",
  34. "State",
  35. "SEND_EOF",
  36. ]
  37. # Change to Request | Response | Frame when dropping Python < 3.10.
  38. Event = Union[Request, Response, Frame]
  39. """Events that :meth:`~Protocol.events_received` may return."""
  40. class Side(enum.IntEnum):
  41. """A WebSocket connection is either a server or a client."""
  42. SERVER, CLIENT = range(2)
  43. SERVER = Side.SERVER
  44. CLIENT = Side.CLIENT
  45. class State(enum.IntEnum):
  46. """A WebSocket connection is in one of these four states."""
  47. CONNECTING, OPEN, CLOSING, CLOSED = range(4)
  48. CONNECTING = State.CONNECTING
  49. OPEN = State.OPEN
  50. CLOSING = State.CLOSING
  51. CLOSED = State.CLOSED
  52. SEND_EOF = b""
  53. """Sentinel signaling that the TCP connection must be half-closed."""
  54. class Protocol:
  55. """
  56. Sans-I/O implementation of a WebSocket connection.
  57. Args:
  58. side: :attr:`~Side.CLIENT` or :attr:`~Side.SERVER`.
  59. state: Initial state of the WebSocket connection.
  60. max_size: Maximum size of incoming messages in bytes;
  61. :obj:`None` disables the limit.
  62. logger: Logger for this connection; depending on ``side``,
  63. defaults to ``logging.getLogger("websockets.client")``
  64. or ``logging.getLogger("websockets.server")``;
  65. see the :doc:`logging guide <../../topics/logging>` for details.
  66. """
  67. def __init__(
  68. self,
  69. side: Side,
  70. *,
  71. state: State = OPEN,
  72. max_size: int | None = 2**20,
  73. logger: LoggerLike | None = None,
  74. ) -> None:
  75. # Unique identifier. For logs.
  76. self.id: uuid.UUID = uuid.uuid4()
  77. """Unique identifier of the connection. Useful in logs."""
  78. # Logger or LoggerAdapter for this connection.
  79. if logger is None:
  80. logger = logging.getLogger(f"websockets.{side.name.lower()}")
  81. self.logger: LoggerLike = logger
  82. """Logger for this connection."""
  83. # Track if DEBUG is enabled. Shortcut logging calls if it isn't.
  84. self.debug = logger.isEnabledFor(logging.DEBUG)
  85. # Connection side. CLIENT or SERVER.
  86. self.side = side
  87. # Connection state. Initially OPEN because subclasses handle CONNECTING.
  88. self.state = state
  89. # Maximum size of incoming messages in bytes.
  90. self.max_size = max_size
  91. # Current size of incoming message in bytes. Only set while reading a
  92. # fragmented message i.e. a data frames with the FIN bit not set.
  93. self.cur_size: int | None = None
  94. # True while sending a fragmented message i.e. a data frames with the
  95. # FIN bit not set.
  96. self.expect_continuation_frame = False
  97. # WebSocket protocol parameters.
  98. self.origin: Origin | None = None
  99. self.extensions: list[Extension] = []
  100. self.subprotocol: Subprotocol | None = None
  101. # Close code and reason, set when a close frame is sent or received.
  102. self.close_rcvd: Close | None = None
  103. self.close_sent: Close | None = None
  104. self.close_rcvd_then_sent: bool | None = None
  105. # Track if an exception happened during the handshake.
  106. self.handshake_exc: Exception | None = None
  107. """
  108. Exception to raise if the opening handshake failed.
  109. :obj:`None` if the opening handshake succeeded.
  110. """
  111. # Track if send_eof() was called.
  112. self.eof_sent = False
  113. # Parser state.
  114. self.reader = StreamReader()
  115. self.events: list[Event] = []
  116. self.writes: list[bytes] = []
  117. self.parser = self.parse()
  118. next(self.parser) # start coroutine
  119. self.parser_exc: Exception | None = None
  120. @property
  121. def state(self) -> State:
  122. """
  123. State of the WebSocket connection.
  124. Defined in 4.1_, 4.2_, 7.1.3_, and 7.1.4_ of :rfc:`6455`.
  125. .. _4.1: https://datatracker.ietf.org/doc/html/rfc6455#section-4.1
  126. .. _4.2: https://datatracker.ietf.org/doc/html/rfc6455#section-4.2
  127. .. _7.1.3: https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.3
  128. .. _7.1.4: https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.4
  129. """
  130. return self._state
  131. @state.setter
  132. def state(self, state: State) -> None:
  133. if self.debug:
  134. self.logger.debug("= connection is %s", state.name)
  135. self._state = state
  136. @property
  137. def close_code(self) -> int | None:
  138. """
  139. WebSocket close code received from the remote endpoint.
  140. Defined in 7.1.5_ of :rfc:`6455`.
  141. .. _7.1.5: https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.5
  142. :obj:`None` if the connection isn't closed yet.
  143. """
  144. if self.state is not CLOSED:
  145. return None
  146. elif self.close_rcvd is None:
  147. return CloseCode.ABNORMAL_CLOSURE
  148. else:
  149. return self.close_rcvd.code
  150. @property
  151. def close_reason(self) -> str | None:
  152. """
  153. WebSocket close reason received from the remote endpoint.
  154. Defined in 7.1.6_ of :rfc:`6455`.
  155. .. _7.1.6: https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.6
  156. :obj:`None` if the connection isn't closed yet.
  157. """
  158. if self.state is not CLOSED:
  159. return None
  160. elif self.close_rcvd is None:
  161. return ""
  162. else:
  163. return self.close_rcvd.reason
  164. @property
  165. def close_exc(self) -> ConnectionClosed:
  166. """
  167. Exception to raise when trying to interact with a closed connection.
  168. Don't raise this exception while the connection :attr:`state`
  169. is :attr:`~websockets.protocol.State.CLOSING`; wait until
  170. it's :attr:`~websockets.protocol.State.CLOSED`.
  171. Indeed, the exception includes the close code and reason, which are
  172. known only once the connection is closed.
  173. Raises:
  174. AssertionError: If the connection isn't closed yet.
  175. """
  176. assert self.state is CLOSED, "connection isn't closed yet"
  177. exc_type: type[ConnectionClosed]
  178. if (
  179. self.close_rcvd is not None
  180. and self.close_sent is not None
  181. and self.close_rcvd.code in OK_CLOSE_CODES
  182. and self.close_sent.code in OK_CLOSE_CODES
  183. ):
  184. exc_type = ConnectionClosedOK
  185. else:
  186. exc_type = ConnectionClosedError
  187. exc: ConnectionClosed = exc_type(
  188. self.close_rcvd,
  189. self.close_sent,
  190. self.close_rcvd_then_sent,
  191. )
  192. # Chain to the exception raised in the parser, if any.
  193. exc.__cause__ = self.parser_exc
  194. return exc
  195. # Public methods for receiving data.
  196. def receive_data(self, data: bytes) -> None:
  197. """
  198. Receive data from the network.
  199. After calling this method:
  200. - You must call :meth:`data_to_send` and send this data to the network.
  201. - You should call :meth:`events_received` and process resulting events.
  202. Raises:
  203. EOFError: If :meth:`receive_eof` was called earlier.
  204. """
  205. self.reader.feed_data(data)
  206. next(self.parser)
  207. def receive_eof(self) -> None:
  208. """
  209. Receive the end of the data stream from the network.
  210. After calling this method:
  211. - You must call :meth:`data_to_send` and send this data to the network;
  212. it will return ``[b""]``, signaling the end of the stream, or ``[]``.
  213. - You aren't expected to call :meth:`events_received`; it won't return
  214. any new events.
  215. :meth:`receive_eof` is idempotent.
  216. """
  217. if self.reader.eof:
  218. return
  219. self.reader.feed_eof()
  220. next(self.parser)
  221. # Public methods for sending events.
  222. def send_continuation(self, data: bytes, fin: bool) -> None:
  223. """
  224. Send a `Continuation frame`_.
  225. .. _Continuation frame:
  226. https://datatracker.ietf.org/doc/html/rfc6455#section-5.6
  227. Parameters:
  228. data: payload containing the same kind of data
  229. as the initial frame.
  230. fin: FIN bit; set it to :obj:`True` if this is the last frame
  231. of a fragmented message and to :obj:`False` otherwise.
  232. Raises:
  233. ProtocolError: If a fragmented message isn't in progress.
  234. """
  235. if not self.expect_continuation_frame:
  236. raise ProtocolError("unexpected continuation frame")
  237. if self._state is not OPEN:
  238. raise InvalidState(f"connection is {self.state.name.lower()}")
  239. self.expect_continuation_frame = not fin
  240. self.send_frame(Frame(OP_CONT, data, fin))
  241. def send_text(self, data: bytes, fin: bool = True) -> None:
  242. """
  243. Send a `Text frame`_.
  244. .. _Text frame:
  245. https://datatracker.ietf.org/doc/html/rfc6455#section-5.6
  246. Parameters:
  247. data: payload containing text encoded with UTF-8.
  248. fin: FIN bit; set it to :obj:`False` if this is the first frame of
  249. a fragmented message.
  250. Raises:
  251. ProtocolError: If a fragmented message is in progress.
  252. """
  253. if self.expect_continuation_frame:
  254. raise ProtocolError("expected a continuation frame")
  255. if self._state is not OPEN:
  256. raise InvalidState(f"connection is {self.state.name.lower()}")
  257. self.expect_continuation_frame = not fin
  258. self.send_frame(Frame(OP_TEXT, data, fin))
  259. def send_binary(self, data: bytes, fin: bool = True) -> None:
  260. """
  261. Send a `Binary frame`_.
  262. .. _Binary frame:
  263. https://datatracker.ietf.org/doc/html/rfc6455#section-5.6
  264. Parameters:
  265. data: payload containing arbitrary binary data.
  266. fin: FIN bit; set it to :obj:`False` if this is the first frame of
  267. a fragmented message.
  268. Raises:
  269. ProtocolError: If a fragmented message is in progress.
  270. """
  271. if self.expect_continuation_frame:
  272. raise ProtocolError("expected a continuation frame")
  273. if self._state is not OPEN:
  274. raise InvalidState(f"connection is {self.state.name.lower()}")
  275. self.expect_continuation_frame = not fin
  276. self.send_frame(Frame(OP_BINARY, data, fin))
  277. def send_close(self, code: int | None = None, reason: str = "") -> None:
  278. """
  279. Send a `Close frame`_.
  280. .. _Close frame:
  281. https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.1
  282. Parameters:
  283. code: close code.
  284. reason: close reason.
  285. Raises:
  286. ProtocolError: If the code isn't valid or if a reason is provided
  287. without a code.
  288. """
  289. # While RFC 6455 doesn't rule out sending more than one close Frame,
  290. # websockets is conservative in what it sends and doesn't allow that.
  291. if self._state is not OPEN:
  292. raise InvalidState(f"connection is {self.state.name.lower()}")
  293. if code is None:
  294. if reason != "":
  295. raise ProtocolError("cannot send a reason without a code")
  296. close = Close(CloseCode.NO_STATUS_RCVD, "")
  297. data = b""
  298. else:
  299. close = Close(code, reason)
  300. data = close.serialize()
  301. # 7.1.3. The WebSocket Closing Handshake is Started
  302. self.send_frame(Frame(OP_CLOSE, data))
  303. # Since the state is OPEN, no close frame was received yet.
  304. # As a consequence, self.close_rcvd_then_sent remains None.
  305. assert self.close_rcvd is None
  306. self.close_sent = close
  307. self.state = CLOSING
  308. def send_ping(self, data: bytes) -> None:
  309. """
  310. Send a `Ping frame`_.
  311. .. _Ping frame:
  312. https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.2
  313. Parameters:
  314. data: payload containing arbitrary binary data.
  315. """
  316. # RFC 6455 allows control frames after starting the closing handshake.
  317. if self._state is not OPEN and self._state is not CLOSING:
  318. raise InvalidState(f"connection is {self.state.name.lower()}")
  319. self.send_frame(Frame(OP_PING, data))
  320. def send_pong(self, data: bytes) -> None:
  321. """
  322. Send a `Pong frame`_.
  323. .. _Pong frame:
  324. https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.3
  325. Parameters:
  326. data: payload containing arbitrary binary data.
  327. """
  328. # RFC 6455 allows control frames after starting the closing handshake.
  329. if self._state is not OPEN and self._state is not CLOSING:
  330. raise InvalidState(f"connection is {self.state.name.lower()}")
  331. self.send_frame(Frame(OP_PONG, data))
  332. def fail(self, code: int, reason: str = "") -> None:
  333. """
  334. `Fail the WebSocket connection`_.
  335. .. _Fail the WebSocket connection:
  336. https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.7
  337. Parameters:
  338. code: close code
  339. reason: close reason
  340. Raises:
  341. ProtocolError: If the code isn't valid.
  342. """
  343. # 7.1.7. Fail the WebSocket Connection
  344. # Send a close frame when the state is OPEN (a close frame was already
  345. # sent if it's CLOSING), except when failing the connection because
  346. # of an error reading from or writing to the network.
  347. if self.state is OPEN:
  348. if code != CloseCode.ABNORMAL_CLOSURE:
  349. close = Close(code, reason)
  350. data = close.serialize()
  351. self.send_frame(Frame(OP_CLOSE, data))
  352. self.close_sent = close
  353. # If recv_messages() raised an exception upon receiving a close
  354. # frame but before echoing it, then close_rcvd is not None even
  355. # though the state is OPEN. This happens when the connection is
  356. # closed while receiving a fragmented message.
  357. if self.close_rcvd is not None:
  358. self.close_rcvd_then_sent = True
  359. self.state = CLOSING
  360. # When failing the connection, a server closes the TCP connection
  361. # without waiting for the client to complete the handshake, while a
  362. # client waits for the server to close the TCP connection, possibly
  363. # after sending a close frame that the client will ignore.
  364. if self.side is SERVER and not self.eof_sent:
  365. self.send_eof()
  366. # 7.1.7. Fail the WebSocket Connection "An endpoint MUST NOT continue
  367. # to attempt to process data(including a responding Close frame) from
  368. # the remote endpoint after being instructed to _Fail the WebSocket
  369. # Connection_."
  370. self.parser = self.discard()
  371. next(self.parser) # start coroutine
  372. # Public method for getting incoming events after receiving data.
  373. def events_received(self) -> list[Event]:
  374. """
  375. Fetch events generated from data received from the network.
  376. Call this method immediately after any of the ``receive_*()`` methods.
  377. Process resulting events, likely by passing them to the application.
  378. Returns:
  379. Events read from the connection.
  380. """
  381. events, self.events = self.events, []
  382. return events
  383. # Public method for getting outgoing data after receiving data or sending events.
  384. def data_to_send(self) -> list[bytes]:
  385. """
  386. Obtain data to send to the network.
  387. Call this method immediately after any of the ``receive_*()``,
  388. ``send_*()``, or :meth:`fail` methods.
  389. Write resulting data to the connection.
  390. The empty bytestring :data:`~websockets.protocol.SEND_EOF` signals
  391. the end of the data stream. When you receive it, half-close the TCP
  392. connection.
  393. Returns:
  394. Data to write to the connection.
  395. """
  396. writes, self.writes = self.writes, []
  397. return writes
  398. def close_expected(self) -> bool:
  399. """
  400. Tell if the TCP connection is expected to close soon.
  401. Call this method immediately after any of the ``receive_*()``,
  402. ``send_close()``, or :meth:`fail` methods.
  403. If it returns :obj:`True`, schedule closing the TCP connection after a
  404. short timeout if the other side hasn't already closed it.
  405. Returns:
  406. Whether the TCP connection is expected to close soon.
  407. """
  408. # During the opening handshake, when our state is CONNECTING, we expect
  409. # a TCP close if and only if the hansdake fails. When it does, we start
  410. # the TCP closing handshake by sending EOF with send_eof().
  411. # Once the opening handshake completes successfully, we expect a TCP
  412. # close if and only if we sent a close frame, meaning that our state
  413. # progressed to CLOSING:
  414. # * Normal closure: once we send a close frame, we expect a TCP close:
  415. # server waits for client to complete the TCP closing handshake;
  416. # client waits for server to initiate the TCP closing handshake.
  417. # * Abnormal closure: we always send a close frame and the same logic
  418. # applies, except on EOFError where we don't send a close frame
  419. # because we already received the TCP close, so we don't expect it.
  420. # If our state is CLOSED, we already received a TCP close so we don't
  421. # expect it anymore.
  422. # Micro-optimization: put the most common case first
  423. if self.state is OPEN:
  424. return False
  425. if self.state is CLOSING:
  426. return True
  427. if self.state is CLOSED:
  428. return False
  429. assert self.state is CONNECTING
  430. return self.eof_sent
  431. # Private methods for receiving data.
  432. def parse(self) -> Generator[None]:
  433. """
  434. Parse incoming data into frames.
  435. :meth:`receive_data` and :meth:`receive_eof` run this generator
  436. coroutine until it needs more data or reaches EOF.
  437. :meth:`parse` never raises an exception. Instead, it sets the
  438. :attr:`parser_exc` and yields control.
  439. """
  440. try:
  441. while True:
  442. if (yield from self.reader.at_eof()):
  443. if self.debug:
  444. self.logger.debug("< EOF")
  445. # If the WebSocket connection is closed cleanly, with a
  446. # closing handhshake, recv_frame() substitutes parse()
  447. # with discard(). This branch is reached only when the
  448. # connection isn't closed cleanly.
  449. raise EOFError("unexpected end of stream")
  450. if self.max_size is None:
  451. max_size = None
  452. elif self.cur_size is None:
  453. max_size = self.max_size
  454. else:
  455. max_size = self.max_size - self.cur_size
  456. # During a normal closure, execution ends here on the next
  457. # iteration of the loop after receiving a close frame. At
  458. # this point, recv_frame() replaced parse() by discard().
  459. frame = yield from Frame.parse(
  460. self.reader.read_exact,
  461. mask=self.side is SERVER,
  462. max_size=max_size,
  463. extensions=self.extensions,
  464. )
  465. if self.debug:
  466. self.logger.debug("< %s", frame)
  467. self.recv_frame(frame)
  468. except ProtocolError as exc:
  469. self.fail(CloseCode.PROTOCOL_ERROR, str(exc))
  470. self.parser_exc = exc
  471. except EOFError as exc:
  472. self.fail(CloseCode.ABNORMAL_CLOSURE, str(exc))
  473. self.parser_exc = exc
  474. except UnicodeDecodeError as exc:
  475. self.fail(CloseCode.INVALID_DATA, f"{exc.reason} at position {exc.start}")
  476. self.parser_exc = exc
  477. except PayloadTooBig as exc:
  478. exc.set_current_size(self.cur_size)
  479. self.fail(CloseCode.MESSAGE_TOO_BIG, str(exc))
  480. self.parser_exc = exc
  481. except Exception as exc:
  482. self.logger.error("parser failed", exc_info=True)
  483. # Don't include exception details, which may be security-sensitive.
  484. self.fail(CloseCode.INTERNAL_ERROR)
  485. self.parser_exc = exc
  486. # During an abnormal closure, execution ends here after catching an
  487. # exception. At this point, fail() replaced parse() by discard().
  488. yield
  489. raise AssertionError("parse() shouldn't step after error")
  490. def discard(self) -> Generator[None]:
  491. """
  492. Discard incoming data.
  493. This coroutine replaces :meth:`parse`:
  494. - after receiving a close frame, during a normal closure (1.4);
  495. - after sending a close frame, during an abnormal closure (7.1.7).
  496. """
  497. # After the opening handshake completes, the server closes the TCP
  498. # connection in the same circumstances where discard() replaces parse().
  499. # The client closes it when it receives EOF from the server or times
  500. # out. (The latter case cannot be handled in this Sans-I/O layer.)
  501. assert (self.side is SERVER or self.state is CONNECTING) == (self.eof_sent)
  502. while not (yield from self.reader.at_eof()):
  503. self.reader.discard()
  504. if self.debug:
  505. self.logger.debug("< EOF")
  506. # A server closes the TCP connection immediately, while a client
  507. # waits for the server to close the TCP connection.
  508. if self.side is CLIENT and self.state is not CONNECTING:
  509. self.send_eof()
  510. self.state = CLOSED
  511. # If discard() completes normally, execution ends here.
  512. yield
  513. # Once the reader reaches EOF, its feed_data/eof() methods raise an
  514. # error, so our receive_data/eof() methods don't step the generator.
  515. raise AssertionError("discard() shouldn't step after EOF")
  516. def recv_frame(self, frame: Frame) -> None:
  517. """
  518. Process an incoming frame.
  519. """
  520. if frame.opcode is OP_TEXT or frame.opcode is OP_BINARY:
  521. if self.cur_size is not None:
  522. raise ProtocolError("expected a continuation frame")
  523. if not frame.fin:
  524. self.cur_size = len(frame.data)
  525. elif frame.opcode is OP_CONT:
  526. if self.cur_size is None:
  527. raise ProtocolError("unexpected continuation frame")
  528. if frame.fin:
  529. self.cur_size = None
  530. else:
  531. self.cur_size += len(frame.data)
  532. elif frame.opcode is OP_PING:
  533. # 5.5.2. Ping: "Upon receipt of a Ping frame, an endpoint MUST
  534. # send a Pong frame in response"
  535. pong_frame = Frame(OP_PONG, frame.data)
  536. self.send_frame(pong_frame)
  537. elif frame.opcode is OP_PONG:
  538. # 5.5.3 Pong: "A response to an unsolicited Pong frame is not
  539. # expected."
  540. pass
  541. elif frame.opcode is OP_CLOSE:
  542. # 7.1.5. The WebSocket Connection Close Code
  543. # 7.1.6. The WebSocket Connection Close Reason
  544. self.close_rcvd = Close.parse(frame.data)
  545. if self.state is CLOSING:
  546. assert self.close_sent is not None
  547. self.close_rcvd_then_sent = False
  548. if self.cur_size is not None:
  549. raise ProtocolError("incomplete fragmented message")
  550. # 5.5.1 Close: "If an endpoint receives a Close frame and did
  551. # not previously send a Close frame, the endpoint MUST send a
  552. # Close frame in response. (When sending a Close frame in
  553. # response, the endpoint typically echos the status code it
  554. # received.)"
  555. if self.state is OPEN:
  556. # Echo the original data instead of re-serializing it with
  557. # Close.serialize() because that fails when the close frame
  558. # is empty and Close.parse() synthesizes a 1005 close code.
  559. # The rest is identical to send_close().
  560. self.send_frame(Frame(OP_CLOSE, frame.data))
  561. self.close_sent = self.close_rcvd
  562. self.close_rcvd_then_sent = True
  563. self.state = CLOSING
  564. # 7.1.2. Start the WebSocket Closing Handshake: "Once an
  565. # endpoint has both sent and received a Close control frame,
  566. # that endpoint SHOULD _Close the WebSocket Connection_"
  567. # A server closes the TCP connection immediately, while a client
  568. # waits for the server to close the TCP connection.
  569. if self.side is SERVER:
  570. self.send_eof()
  571. # 1.4. Closing Handshake: "after receiving a control frame
  572. # indicating the connection should be closed, a peer discards
  573. # any further data received."
  574. # RFC 6455 allows reading Ping and Pong frames after a Close frame.
  575. # However, that doesn't seem useful; websockets doesn't support it.
  576. self.parser = self.discard()
  577. next(self.parser) # start coroutine
  578. else:
  579. # This can't happen because Frame.parse() validates opcodes.
  580. raise AssertionError(f"unexpected opcode: {frame.opcode:02x}")
  581. self.events.append(frame)
  582. # Private methods for sending events.
  583. def send_frame(self, frame: Frame) -> None:
  584. if self.debug:
  585. self.logger.debug("> %s", frame)
  586. self.writes.append(
  587. frame.serialize(
  588. mask=self.side is CLIENT,
  589. extensions=self.extensions,
  590. )
  591. )
  592. def send_eof(self) -> None:
  593. assert not self.eof_sent
  594. self.eof_sent = True
  595. if self.debug:
  596. self.logger.debug("> EOF")
  597. self.writes.append(SEND_EOF)