Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
exceptions.py474 linesDownload Raw Back to websockets
1"""
2:mod:`websockets.exceptions` defines the following hierarchy of exceptions.
3
4* :exc:`WebSocketException`
5    * :exc:`ConnectionClosed`
6        * :exc:`ConnectionClosedOK`
7        * :exc:`ConnectionClosedError`
8    * :exc:`InvalidURI`
9    * :exc:`InvalidProxy`
10    * :exc:`InvalidHandshake`
11        * :exc:`SecurityError`
12        * :exc:`ProxyError`
13            * :exc:`InvalidProxyMessage`
14            * :exc:`InvalidProxyStatus`
15        * :exc:`InvalidMessage`
16        * :exc:`InvalidStatus`
17        * :exc:`InvalidStatusCode` (legacy)
18        * :exc:`InvalidHeader`
19            * :exc:`InvalidHeaderFormat`
20            * :exc:`InvalidHeaderValue`
21            * :exc:`InvalidOrigin`
22            * :exc:`InvalidUpgrade`
23        * :exc:`NegotiationError`
24            * :exc:`DuplicateParameter`
25            * :exc:`InvalidParameterName`
26            * :exc:`InvalidParameterValue`
27        * :exc:`AbortHandshake` (legacy)
28        * :exc:`RedirectHandshake` (legacy)
29    * :exc:`ProtocolError` (Sans-I/O)
30    * :exc:`PayloadTooBig` (Sans-I/O)
31    * :exc:`InvalidState` (Sans-I/O)
32    * :exc:`ConcurrencyError`
33
34"""
35
36from __future__ import annotations
37
38import warnings
39
40from .imports import lazy_import
41
42
43__all__ = [
44    "WebSocketException",
45    "ConnectionClosed",
46    "ConnectionClosedOK",
47    "ConnectionClosedError",
48    "InvalidURI",
49    "InvalidProxy",
50    "InvalidHandshake",
51    "SecurityError",
52    "ProxyError",
53    "InvalidProxyMessage",
54    "InvalidProxyStatus",
55    "InvalidMessage",
56    "InvalidStatus",
57    "InvalidHeader",
58    "InvalidHeaderFormat",
59    "InvalidHeaderValue",
60    "InvalidOrigin",
61    "InvalidUpgrade",
62    "NegotiationError",
63    "DuplicateParameter",
64    "InvalidParameterName",
65    "InvalidParameterValue",
66    "ProtocolError",
67    "PayloadTooBig",
68    "InvalidState",
69    "ConcurrencyError",
70]
71
72
73class WebSocketException(Exception):
74    """
75    Base class for all exceptions defined by websockets.
76
77    """
78
79
80class ConnectionClosed(WebSocketException):
81    """
82    Raised when trying to interact with a closed connection.
83
84    Attributes:
85        rcvd: If a close frame was received, its code and reason are available
86            in ``rcvd.code`` and ``rcvd.reason``.
87        sent: If a close frame was sent, its code and reason are available
88            in ``sent.code`` and ``sent.reason``.
89        rcvd_then_sent: If close frames were received and sent, this attribute
90            tells in which order this happened, from the perspective of this
91            side of the connection.
92
93    """
94
95    def __init__(
96        self,
97        rcvd: frames.Close | None,
98        sent: frames.Close | None,
99        rcvd_then_sent: bool | None = None,
100    ) -> None:
101        self.rcvd = rcvd
102        self.sent = sent
103        self.rcvd_then_sent = rcvd_then_sent
104        assert (self.rcvd_then_sent is None) == (self.rcvd is None or self.sent is None)
105
106    def __str__(self) -> str:
107        if self.rcvd is None:
108            if self.sent is None:
109                return "no close frame received or sent"
110            else:
111                return f"sent {self.sent}; no close frame received"
112        else:
113            if self.sent is None:
114                return f"received {self.rcvd}; no close frame sent"
115            else:
116                if self.rcvd_then_sent:
117                    return f"received {self.rcvd}; then sent {self.sent}"
118                else:
119                    return f"sent {self.sent}; then received {self.rcvd}"
120
121    # code and reason attributes are provided for backwards-compatibility
122
123    @property
124    def code(self) -> int:
125        warnings.warn(  # deprecated in 13.1 - 2024-09-21
126            "ConnectionClosed.code is deprecated; "
127            "use Protocol.close_code or ConnectionClosed.rcvd.code",
128            DeprecationWarning,
129        )
130        if self.rcvd is None:
131            return frames.CloseCode.ABNORMAL_CLOSURE
132        return self.rcvd.code
133
134    @property
135    def reason(self) -> str:
136        warnings.warn(  # deprecated in 13.1 - 2024-09-21
137            "ConnectionClosed.reason is deprecated; "
138            "use Protocol.close_reason or ConnectionClosed.rcvd.reason",
139            DeprecationWarning,
140        )
141        if self.rcvd is None:
142            return ""
143        return self.rcvd.reason
144
145
146class ConnectionClosedOK(ConnectionClosed):
147    """
148    Like :exc:`ConnectionClosed`, when the connection terminated properly.
149
150    A close code with code 1000 (OK) or 1001 (going away) or without a code was
151    received and sent.
152
153    """
154
155
156class ConnectionClosedError(ConnectionClosed):
157    """
158    Like :exc:`ConnectionClosed`, when the connection terminated with an error.
159
160    A close frame with a code other than 1000 (OK) or 1001 (going away) was
161    received or sent, or the closing handshake didn't complete properly.
162
163    """
164
165
166class InvalidURI(WebSocketException):
167    """
168    Raised when connecting to a URI that isn't a valid WebSocket URI.
169
170    """
171
172    def __init__(self, uri: str, msg: str) -> None:
173        self.uri = uri
174        self.msg = msg
175
176    def __str__(self) -> str:
177        return f"{self.uri} isn't a valid URI: {self.msg}"
178
179
180class InvalidProxy(WebSocketException):
181    """
182    Raised when connecting via a proxy that isn't valid.
183
184    """
185
186    def __init__(self, proxy: str, msg: str) -> None:
187        self.proxy = proxy
188        self.msg = msg
189
190    def __str__(self) -> str:
191        return f"{self.proxy} isn't a valid proxy: {self.msg}"
192
193
194class InvalidHandshake(WebSocketException):
195    """
196    Base class for exceptions raised when the opening handshake fails.
197
198    """
199
200
201class SecurityError(InvalidHandshake):
202    """
203    Raised when a handshake request or response breaks a security rule.
204
205    Security limits can be configured with :doc:`environment variables
206    <../reference/variables>`.
207
208    """
209
210
211class ProxyError(InvalidHandshake):
212    """
213    Raised when failing to connect to a proxy.
214
215    """
216
217
218class InvalidProxyMessage(ProxyError):
219    """
220    Raised when an HTTP proxy response is malformed.
221
222    """
223
224
225class InvalidProxyStatus(ProxyError):
226    """
227    Raised when an HTTP proxy rejects the connection.
228
229    """
230
231    def __init__(self, response: http11.Response) -> None:
232        self.response = response
233
234    def __str__(self) -> str:
235        return f"proxy rejected connection: HTTP {self.response.status_code:d}"
236
237
238class InvalidMessage(InvalidHandshake):
239    """
240    Raised when a handshake request or response is malformed.
241
242    """
243
244
245class InvalidStatus(InvalidHandshake):
246    """
247    Raised when a handshake response rejects the WebSocket upgrade.
248
249    """
250
251    def __init__(self, response: http11.Response) -> None:
252        self.response = response
253
254    def __str__(self) -> str:
255        return (
256            f"server rejected WebSocket connection: HTTP {self.response.status_code:d}"
257        )
258
259
260class InvalidHeader(InvalidHandshake):
261    """
262    Raised when an HTTP header doesn't have a valid format or value.
263
264    """
265
266    def __init__(self, name: str, value: str | None = None) -> None:
267        self.name = name
268        self.value = value
269
270    def __str__(self) -> str:
271        if self.value is None:
272            return f"missing {self.name} header"
273        elif self.value == "":
274            return f"empty {self.name} header"
275        else:
276            return f"invalid {self.name} header: {self.value}"
277
278
279class InvalidHeaderFormat(InvalidHeader):
280    """
281    Raised when an HTTP header cannot be parsed.
282
283    The format of the header doesn't match the grammar for that header.
284
285    """
286
287    def __init__(self, name: str, error: str, header: str, pos: int) -> None:
288        super().__init__(name, f"{error} at {pos} in {header}")
289
290
291class InvalidHeaderValue(InvalidHeader):
292    """
293    Raised when an HTTP header has a wrong value.
294
295    The format of the header is correct but the value isn't acceptable.
296
297    """
298
299
300class InvalidOrigin(InvalidHeader):
301    """
302    Raised when the Origin header in a request isn't allowed.
303
304    """
305
306    def __init__(self, origin: str | None) -> None:
307        super().__init__("Origin", origin)
308
309
310class InvalidUpgrade(InvalidHeader):
311    """
312    Raised when the Upgrade or Connection header isn't correct.
313
314    """
315
316
317class NegotiationError(InvalidHandshake):
318    """
319    Raised when negotiating an extension or a subprotocol fails.
320
321    """
322
323
324class DuplicateParameter(NegotiationError):
325    """
326    Raised when a parameter name is repeated in an extension header.
327
328    """
329
330    def __init__(self, name: str) -> None:
331        self.name = name
332
333    def __str__(self) -> str:
334        return f"duplicate parameter: {self.name}"
335
336
337class InvalidParameterName(NegotiationError):
338    """
339    Raised when a parameter name in an extension header is invalid.
340
341    """
342
343    def __init__(self, name: str) -> None:
344        self.name = name
345
346    def __str__(self) -> str:
347        return f"invalid parameter name: {self.name}"
348
349
350class InvalidParameterValue(NegotiationError):
351    """
352    Raised when a parameter value in an extension header is invalid.
353
354    """
355
356    def __init__(self, name: str, value: str | None) -> None:
357        self.name = name
358        self.value = value
359
360    def __str__(self) -> str:
361        if self.value is None:
362            return f"missing value for parameter {self.name}"
363        elif self.value == "":
364            return f"empty value for parameter {self.name}"
365        else:
366            return f"invalid value for parameter {self.name}: {self.value}"
367
368
369class ProtocolError(WebSocketException):
370    """
371    Raised when receiving or sending a frame that breaks the protocol.
372
373    The Sans-I/O implementation raises this exception when:
374
375    * receiving or sending a frame that contains invalid data;
376    * receiving or sending an invalid sequence of frames.
377
378    """
379
380
381class PayloadTooBig(WebSocketException):
382    """
383    Raised when parsing a frame with a payload that exceeds the maximum size.
384
385    The Sans-I/O layer uses this exception internally. It doesn't bubble up to
386    the I/O layer.
387
388    The :meth:`~websockets.extensions.Extension.decode` method of extensions
389    must raise :exc:`PayloadTooBig` if decoding a frame would exceed the limit.
390
391    """
392
393    def __init__(
394        self,
395        size_or_message: int | None | str,
396        max_size: int | None = None,
397        current_size: int | None = None,
398    ) -> None:
399        if isinstance(size_or_message, str):
400            assert max_size is None
401            assert current_size is None
402            warnings.warn(  # deprecated in 14.0 - 2024-11-09
403                "PayloadTooBig(message) is deprecated; "
404                "change to PayloadTooBig(size, max_size)",
405                DeprecationWarning,
406            )
407            self.message: str | None = size_or_message
408        else:
409            self.message = None
410            self.size: int | None = size_or_message
411            assert max_size is not None
412            self.max_size: int = max_size
413            self.current_size: int | None = None
414            self.set_current_size(current_size)
415
416    def __str__(self) -> str:
417        if self.message is not None:
418            return self.message
419        else:
420            message = "frame "
421            if self.size is not None:
422                message += f"with {self.size} bytes "
423            if self.current_size is not None:
424                message += f"after reading {self.current_size} bytes "
425            message += f"exceeds limit of {self.max_size} bytes"
426            return message
427
428    def set_current_size(self, current_size: int | None) -> None:
429        assert self.current_size is None
430        if current_size is not None:
431            self.max_size += current_size
432            self.current_size = current_size
433
434
435class InvalidState(WebSocketException, AssertionError):
436    """
437    Raised when sending a frame is forbidden in the current state.
438
439    Specifically, the Sans-I/O layer raises this exception when:
440
441    * sending a data frame to a connection in a state other
442      :attr:`~websockets.protocol.State.OPEN`;
443    * sending a control frame to a connection in a state other than
444      :attr:`~websockets.protocol.State.OPEN` or
445      :attr:`~websockets.protocol.State.CLOSING`.
446
447    """
448
449
450class ConcurrencyError(WebSocketException, RuntimeError):
451    """
452    Raised when receiving or sending messages concurrently.
453
454    WebSocket is a connection-oriented protocol. Reads must be serialized; so
455    must be writes. However, reading and writing concurrently is possible.
456
457    """
458
459
460# At the bottom to break import cycles created by type annotations.
461from . import frames, http11  # noqa: E402
462
463
464lazy_import(
465    globals(),
466    deprecated_aliases={
467        # deprecated in 14.0 - 2024-11-09
468        "AbortHandshake": ".legacy.exceptions",
469        "InvalidStatusCode": ".legacy.exceptions",
470        "RedirectHandshake": ".legacy.exceptions",
471        "WebSocketProtocolError": ".legacy.exceptions",
472    },
473)
474 
codekingpro/portable-devtools · Team Ai