Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

exceptions.py 9.9KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. """
  2. :mod:`websockets.exceptions` defines the following exception hierarchy:
  3. * :exc:`WebSocketException`
  4. * :exc:`ConnectionClosed`
  5. * :exc:`ConnectionClosedError`
  6. * :exc:`ConnectionClosedOK`
  7. * :exc:`InvalidHandshake`
  8. * :exc:`SecurityError`
  9. * :exc:`InvalidMessage`
  10. * :exc:`InvalidHeader`
  11. * :exc:`InvalidHeaderFormat`
  12. * :exc:`InvalidHeaderValue`
  13. * :exc:`InvalidOrigin`
  14. * :exc:`InvalidUpgrade`
  15. * :exc:`InvalidStatus`
  16. * :exc:`InvalidStatusCode` (legacy)
  17. * :exc:`NegotiationError`
  18. * :exc:`DuplicateParameter`
  19. * :exc:`InvalidParameterName`
  20. * :exc:`InvalidParameterValue`
  21. * :exc:`AbortHandshake`
  22. * :exc:`RedirectHandshake`
  23. * :exc:`InvalidState`
  24. * :exc:`InvalidURI`
  25. * :exc:`PayloadTooBig`
  26. * :exc:`ProtocolError`
  27. """
  28. from __future__ import annotations
  29. import http
  30. from typing import Optional
  31. from . import datastructures, frames, http11
  32. __all__ = [
  33. "WebSocketException",
  34. "ConnectionClosed",
  35. "ConnectionClosedError",
  36. "ConnectionClosedOK",
  37. "InvalidHandshake",
  38. "SecurityError",
  39. "InvalidMessage",
  40. "InvalidHeader",
  41. "InvalidHeaderFormat",
  42. "InvalidHeaderValue",
  43. "InvalidOrigin",
  44. "InvalidUpgrade",
  45. "InvalidStatus",
  46. "InvalidStatusCode",
  47. "NegotiationError",
  48. "DuplicateParameter",
  49. "InvalidParameterName",
  50. "InvalidParameterValue",
  51. "AbortHandshake",
  52. "RedirectHandshake",
  53. "InvalidState",
  54. "InvalidURI",
  55. "PayloadTooBig",
  56. "ProtocolError",
  57. "WebSocketProtocolError",
  58. ]
  59. class WebSocketException(Exception):
  60. """
  61. Base class for all exceptions defined by websockets.
  62. """
  63. class ConnectionClosed(WebSocketException):
  64. """
  65. Raised when trying to interact with a closed connection.
  66. Attributes:
  67. rcvd (Optional[Close]): if a close frame was received, its code and
  68. reason are available in ``rcvd.code`` and ``rcvd.reason``.
  69. sent (Optional[Close]): if a close frame was sent, its code and reason
  70. are available in ``sent.code`` and ``sent.reason``.
  71. rcvd_then_sent (Optional[bool]): if close frames were received and
  72. sent, this attribute tells in which order this happened, from the
  73. perspective of this side of the connection.
  74. """
  75. def __init__(
  76. self,
  77. rcvd: Optional[frames.Close],
  78. sent: Optional[frames.Close],
  79. rcvd_then_sent: Optional[bool] = None,
  80. ) -> None:
  81. self.rcvd = rcvd
  82. self.sent = sent
  83. self.rcvd_then_sent = rcvd_then_sent
  84. def __str__(self) -> str:
  85. if self.rcvd is None:
  86. if self.sent is None:
  87. assert self.rcvd_then_sent is None
  88. return "no close frame received or sent"
  89. else:
  90. assert self.rcvd_then_sent is None
  91. return f"sent {self.sent}; no close frame received"
  92. else:
  93. if self.sent is None:
  94. assert self.rcvd_then_sent is None
  95. return f"received {self.rcvd}; no close frame sent"
  96. else:
  97. assert self.rcvd_then_sent is not None
  98. if self.rcvd_then_sent:
  99. return f"received {self.rcvd}; then sent {self.sent}"
  100. else:
  101. return f"sent {self.sent}; then received {self.rcvd}"
  102. # code and reason attributes are provided for backwards-compatibility
  103. @property
  104. def code(self) -> int:
  105. if self.rcvd is None:
  106. return 1006
  107. return self.rcvd.code
  108. @property
  109. def reason(self) -> str:
  110. if self.rcvd is None:
  111. return ""
  112. return self.rcvd.reason
  113. class ConnectionClosedError(ConnectionClosed):
  114. """
  115. Like :exc:`ConnectionClosed`, when the connection terminated with an error.
  116. A close frame with a code other than 1000 (OK) or 1001 (going away) was
  117. received or sent, or the closing handshake didn't complete properly.
  118. """
  119. class ConnectionClosedOK(ConnectionClosed):
  120. """
  121. Like :exc:`ConnectionClosed`, when the connection terminated properly.
  122. A close code with code 1000 (OK) or 1001 (going away) or without a code was
  123. received and sent.
  124. """
  125. class InvalidHandshake(WebSocketException):
  126. """
  127. Raised during the handshake when the WebSocket connection fails.
  128. """
  129. class SecurityError(InvalidHandshake):
  130. """
  131. Raised when a handshake request or response breaks a security rule.
  132. Security limits are hard coded.
  133. """
  134. class InvalidMessage(InvalidHandshake):
  135. """
  136. Raised when a handshake request or response is malformed.
  137. """
  138. class InvalidHeader(InvalidHandshake):
  139. """
  140. Raised when an HTTP header doesn't have a valid format or value.
  141. """
  142. def __init__(self, name: str, value: Optional[str] = None) -> None:
  143. self.name = name
  144. self.value = value
  145. def __str__(self) -> str:
  146. if self.value is None:
  147. return f"missing {self.name} header"
  148. elif self.value == "":
  149. return f"empty {self.name} header"
  150. else:
  151. return f"invalid {self.name} header: {self.value}"
  152. class InvalidHeaderFormat(InvalidHeader):
  153. """
  154. Raised when an HTTP header cannot be parsed.
  155. The format of the header doesn't match the grammar for that header.
  156. """
  157. def __init__(self, name: str, error: str, header: str, pos: int) -> None:
  158. super().__init__(name, f"{error} at {pos} in {header}")
  159. class InvalidHeaderValue(InvalidHeader):
  160. """
  161. Raised when an HTTP header has a wrong value.
  162. The format of the header is correct but a value isn't acceptable.
  163. """
  164. class InvalidOrigin(InvalidHeader):
  165. """
  166. Raised when the Origin header in a request isn't allowed.
  167. """
  168. def __init__(self, origin: Optional[str]) -> None:
  169. super().__init__("Origin", origin)
  170. class InvalidUpgrade(InvalidHeader):
  171. """
  172. Raised when the Upgrade or Connection header isn't correct.
  173. """
  174. class InvalidStatus(InvalidHandshake):
  175. """
  176. Raised when a handshake response rejects the WebSocket upgrade.
  177. """
  178. def __init__(self, response: http11.Response) -> None:
  179. self.response = response
  180. def __str__(self) -> str:
  181. return (
  182. "server rejected WebSocket connection: "
  183. f"HTTP {self.response.status_code:d}"
  184. )
  185. class InvalidStatusCode(InvalidHandshake):
  186. """
  187. Raised when a handshake response status code is invalid.
  188. """
  189. def __init__(self, status_code: int, headers: datastructures.Headers) -> None:
  190. self.status_code = status_code
  191. self.headers = headers
  192. def __str__(self) -> str:
  193. return f"server rejected WebSocket connection: HTTP {self.status_code}"
  194. class NegotiationError(InvalidHandshake):
  195. """
  196. Raised when negotiating an extension fails.
  197. """
  198. class DuplicateParameter(NegotiationError):
  199. """
  200. Raised when a parameter name is repeated in an extension header.
  201. """
  202. def __init__(self, name: str) -> None:
  203. self.name = name
  204. def __str__(self) -> str:
  205. return f"duplicate parameter: {self.name}"
  206. class InvalidParameterName(NegotiationError):
  207. """
  208. Raised when a parameter name in an extension header is invalid.
  209. """
  210. def __init__(self, name: str) -> None:
  211. self.name = name
  212. def __str__(self) -> str:
  213. return f"invalid parameter name: {self.name}"
  214. class InvalidParameterValue(NegotiationError):
  215. """
  216. Raised when a parameter value in an extension header is invalid.
  217. """
  218. def __init__(self, name: str, value: Optional[str]) -> None:
  219. self.name = name
  220. self.value = value
  221. def __str__(self) -> str:
  222. if self.value is None:
  223. return f"missing value for parameter {self.name}"
  224. elif self.value == "":
  225. return f"empty value for parameter {self.name}"
  226. else:
  227. return f"invalid value for parameter {self.name}: {self.value}"
  228. class AbortHandshake(InvalidHandshake):
  229. """
  230. Raised to abort the handshake on purpose and return an HTTP response.
  231. This exception is an implementation detail.
  232. The public API
  233. is :meth:`~websockets.server.WebSocketServerProtocol.process_request`.
  234. Attributes:
  235. status (~http.HTTPStatus): HTTP status code.
  236. headers (Headers): HTTP response headers.
  237. body (bytes): HTTP response body.
  238. """
  239. def __init__(
  240. self,
  241. status: http.HTTPStatus,
  242. headers: datastructures.HeadersLike,
  243. body: bytes = b"",
  244. ) -> None:
  245. self.status = status
  246. self.headers = datastructures.Headers(headers)
  247. self.body = body
  248. def __str__(self) -> str:
  249. return (
  250. f"HTTP {self.status:d}, "
  251. f"{len(self.headers)} headers, "
  252. f"{len(self.body)} bytes"
  253. )
  254. class RedirectHandshake(InvalidHandshake):
  255. """
  256. Raised when a handshake gets redirected.
  257. This exception is an implementation detail.
  258. """
  259. def __init__(self, uri: str) -> None:
  260. self.uri = uri
  261. def __str__(self) -> str:
  262. return f"redirect to {self.uri}"
  263. class InvalidState(WebSocketException, AssertionError):
  264. """
  265. Raised when an operation is forbidden in the current state.
  266. This exception is an implementation detail.
  267. It should never be raised in normal circumstances.
  268. """
  269. class InvalidURI(WebSocketException):
  270. """
  271. Raised when connecting to a URI that isn't a valid WebSocket URI.
  272. """
  273. def __init__(self, uri: str, msg: str) -> None:
  274. self.uri = uri
  275. self.msg = msg
  276. def __str__(self) -> str:
  277. return f"{self.uri} isn't a valid URI: {self.msg}"
  278. class PayloadTooBig(WebSocketException):
  279. """
  280. Raised when receiving a frame with a payload exceeding the maximum size.
  281. """
  282. class ProtocolError(WebSocketException):
  283. """
  284. Raised when a frame breaks the protocol.
  285. """
  286. WebSocketProtocolError = ProtocolError # for backwards compatibility