Skip to content

Websocket invalid upgrade exception handling b0rkage #2743

Closed
@Tronic

Description

@Tronic

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

A client apparently sent no Upgrade header to a websocket endpoint, leading to an error as it should. An ugly traceback is printed on terminal even though the error eventually gets handled correctly it would seem.

It would appear that the websockets module attempts to attach its exception on request._exception field which Sanic's Request doesn't have a slot for. This could be hidden if Sanic later used raise BadRequest(...) from None rather than raise SanicException(...), suppressing the chain and giving a non-500 error for what really is no server error. Not sure though if that would from this context ever reach the client anyway but at least it could avoid a traceback in server log.

If anyone wants to investigate and make a PR, feel free to (I am currently busy and cannot do that unfortunately).

Traceback (most recent call last):
  File "/home/user/.local/lib/python3.10/site-packages/websockets/server.py", line 111, in accept
    ) = self.process_request(request)
  File "/home/user/.local/lib/python3.10/site-packages/websockets/server.py", line 218, in process_request
    raise InvalidUpgrade("Upgrade", ", ".join(upgrade) if upgrade else None)
websockets.exceptions.InvalidUpgrade: missing Upgrade header

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/user/sanic/sanic/server/protocols/websocket_protocol.py", line 120, in websocket_handshake
    resp: "http11.Response" = ws_proto.accept(request)
  File "/home/user/.local/lib/python3.10/site-packages/websockets/server.py", line 122, in accept
    request._exception = exc
AttributeError: 'Request' object has no attribute '_exception'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "handle_request", line 97, in handle_request
  File "/home/user/sanic/sanic/app.py", line 1047, in _websocket_handler
    ws = await protocol.websocket_handshake(request, subprotocols)
  File "/home/user/sanic/sanic/server/protocols/websocket_protocol.py", line 126, in websocket_handshake
    raise SanicException(msg, status_code=500)
sanic.exceptions.SanicException: Failed to open a WebSocket connection.
See server log for more information.

Code snippet

No response

Expected Behavior

400 Bad Request error reaching the client and being more silent on server side. Including the message of missing Upgrade header would be helpful for debugging (e.g. in case Nginx proxy config forgot to forward that header).

How do you run Sanic?

Sanic CLI

Operating System

Linux

Sanic Version

Almost 23.03.0 (a git version slightly before release)

Additional context

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions