Skip to content

Commit

Permalink
Reintroduce InvalidMessage.
Browse files Browse the repository at this point in the history
This improves compatibility with the legacy implementation and clarifies
error reporting.

Fix #1548.
  • Loading branch information
aaugustin committed Nov 13, 2024
1 parent d8891a1 commit 65bd931
Show file tree
Hide file tree
Showing 10 changed files with 32 additions and 20 deletions.
4 changes: 2 additions & 2 deletions docs/reference/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ also reported by :func:`~websockets.asyncio.server.serve` in logs.

.. autoexception:: InvalidHandshake

.. autoexception:: InvalidMessage

.. autoexception:: SecurityError

.. autoexception:: InvalidStatus
Expand Down Expand Up @@ -74,8 +76,6 @@ Legacy exceptions

These exceptions are only used by the legacy :mod:`asyncio` implementation.

.. autoexception:: InvalidMessage

.. autoexception:: InvalidStatusCode

.. autoexception:: AbortHandshake
Expand Down
4 changes: 3 additions & 1 deletion src/websockets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"InvalidHeader",
"InvalidHeaderFormat",
"InvalidHeaderValue",
"InvalidMessage",
"InvalidOrigin",
"InvalidParameterName",
"InvalidParameterValue",
Expand Down Expand Up @@ -71,6 +72,7 @@
InvalidHeader,
InvalidHeaderFormat,
InvalidHeaderValue,
InvalidMessage,
InvalidOrigin,
InvalidParameterName,
InvalidParameterValue,
Expand Down Expand Up @@ -122,6 +124,7 @@
"InvalidHeader": ".exceptions",
"InvalidHeaderFormat": ".exceptions",
"InvalidHeaderValue": ".exceptions",
"InvalidMessage": ".exceptions",
"InvalidOrigin": ".exceptions",
"InvalidParameterName": ".exceptions",
"InvalidParameterValue": ".exceptions",
Expand Down Expand Up @@ -159,7 +162,6 @@
"WebSocketClientProtocol": ".legacy.client",
# .legacy.exceptions
"AbortHandshake": ".legacy.exceptions",
"InvalidMessage": ".legacy.exceptions",
"InvalidStatusCode": ".legacy.exceptions",
"RedirectHandshake": ".legacy.exceptions",
"WebSocketProtocolError": ".legacy.exceptions",
Expand Down
6 changes: 5 additions & 1 deletion src/websockets/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
InvalidHandshake,
InvalidHeader,
InvalidHeaderValue,
InvalidMessage,
InvalidStatus,
InvalidUpgrade,
NegotiationError,
Expand Down Expand Up @@ -318,7 +319,10 @@ def parse(self) -> Generator[None]:
self.reader.read_to_eof,
)
except Exception as exc:
self.handshake_exc = exc
self.handshake_exc = InvalidMessage(
"did not receive a valid HTTP response"
)
self.handshake_exc.__cause__ = exc
self.send_eof()
self.parser = self.discard()
next(self.parser) # start coroutine
Expand Down
11 changes: 9 additions & 2 deletions src/websockets/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* :exc:`InvalidURI`
* :exc:`InvalidHandshake`
* :exc:`SecurityError`
* :exc:`InvalidMessage` (legacy)
* :exc:`InvalidMessage`
* :exc:`InvalidStatus`
* :exc:`InvalidStatusCode` (legacy)
* :exc:`InvalidHeader`
Expand Down Expand Up @@ -48,6 +48,7 @@
"InvalidHeader",
"InvalidHeaderFormat",
"InvalidHeaderValue",
"InvalidMessage",
"InvalidOrigin",
"InvalidUpgrade",
"NegotiationError",
Expand Down Expand Up @@ -185,6 +186,13 @@ class SecurityError(InvalidHandshake):
"""


class InvalidMessage(InvalidHandshake):
"""
Raised when a handshake request or response is malformed.
"""


class InvalidStatus(InvalidHandshake):
"""
Raised when a handshake response rejects the WebSocket upgrade.
Expand Down Expand Up @@ -410,7 +418,6 @@ class ConcurrencyError(WebSocketException, RuntimeError):
deprecated_aliases={
# deprecated in 14.0 - 2024-11-09
"AbortHandshake": ".legacy.exceptions",
"InvalidMessage": ".legacy.exceptions",
"InvalidStatusCode": ".legacy.exceptions",
"RedirectHandshake": ".legacy.exceptions",
"WebSocketProtocolError": ".legacy.exceptions",
Expand Down
3 changes: 2 additions & 1 deletion src/websockets/legacy/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from ..exceptions import (
InvalidHeader,
InvalidHeaderValue,
InvalidMessage,
NegotiationError,
SecurityError,
)
Expand All @@ -34,7 +35,7 @@
from ..http11 import USER_AGENT
from ..typing import ExtensionHeader, LoggerLike, Origin, Subprotocol
from ..uri import WebSocketURI, parse_uri
from .exceptions import InvalidMessage, InvalidStatusCode, RedirectHandshake
from .exceptions import InvalidStatusCode, RedirectHandshake
from .handshake import build_request, check_response
from .http import read_response
from .protocol import WebSocketCommonProtocol
Expand Down
7 changes: 0 additions & 7 deletions src/websockets/legacy/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,6 @@
from ..typing import StatusLike


class InvalidMessage(InvalidHandshake):
"""
Raised when a handshake request or response is malformed.
"""


class InvalidStatusCode(InvalidHandshake):
"""
Raised when a handshake response status code is invalid.
Expand Down
3 changes: 2 additions & 1 deletion src/websockets/legacy/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from ..exceptions import (
InvalidHandshake,
InvalidHeader,
InvalidMessage,
InvalidOrigin,
InvalidUpgrade,
NegotiationError,
Expand All @@ -32,7 +33,7 @@
from ..http11 import SERVER
from ..protocol import State
from ..typing import ExtensionHeader, LoggerLike, Origin, StatusLike, Subprotocol
from .exceptions import AbortHandshake, InvalidMessage
from .exceptions import AbortHandshake
from .handshake import build_response, check_request
from .http import read_request
from .protocol import WebSocketCommonProtocol, broadcast
Expand Down
6 changes: 5 additions & 1 deletion src/websockets/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
InvalidHandshake,
InvalidHeader,
InvalidHeaderValue,
InvalidMessage,
InvalidOrigin,
InvalidUpgrade,
NegotiationError,
Expand Down Expand Up @@ -552,7 +553,10 @@ def parse(self) -> Generator[None]:
self.reader.read_line,
)
except Exception as exc:
self.handshake_exc = exc
self.handshake_exc = InvalidMessage(
"did not receive a valid HTTP request"
)
self.handshake_exc.__cause__ = exc
self.send_eof()
self.parser = self.discard()
next(self.parser) # start coroutine
Expand Down
4 changes: 0 additions & 4 deletions tests/legacy/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@
class ExceptionsTests(unittest.TestCase):
def test_str(self):
for exception, exception_str in [
(
InvalidMessage("malformed HTTP message"),
"malformed HTTP message",
),
(
InvalidStatusCode(403, Headers()),
"server rejected WebSocket connection: HTTP 403",
Expand Down
4 changes: 4 additions & 0 deletions tests/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ def test_str(self):
SecurityError("redirect from WSS to WS"),
"redirect from WSS to WS",
),
(
InvalidMessage("malformed HTTP message"),
"malformed HTTP message",
),
(
InvalidStatus(Response(401, "Unauthorized", Headers())),
"server rejected WebSocket connection: HTTP 401",
Expand Down

0 comments on commit 65bd931

Please sign in to comment.