python-websockets / websockets

Library for building WebSocket servers and clients in Python
https://websockets.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
5.07k stars 506 forks source link

Accessing the websocket object after leaving the process_request function #1401

Closed lonode closed 9 months ago

lonode commented 10 months ago

Hello,

Like suggested in the documentation, i'm defining a custom Websocket protocol to authenticate a client. I'm therefore overriding process_request in my custom class definition. In my backend, when the client is authenticated, it leads to stateful modification behind the scenes.

I noticed that if a browser sends a pure HTTP request to the websocket endpoint, it gets rejected because it does not talk with the websocket protocol, all good. But the request still goes through the process_request function and can go without problem if the Authorization is validated.

The websocket is then immediatly closed, how do you access it again to know that it has been closed, so that i can clean my backend other services ?

aaugustin commented 10 months ago

To be pragmatic, I recommend that you test if headers.get("Upgrade").lower() == "websocket" and, if that's not true, cleanup immediately in process_request.

This conditions should be true for WebSocket connections and false for HTTP requests. Strictly speaking, the handshake could fail for other reasons but that should be good enough in practice.

You need a cleanup mechanism anyway in case the Python process dies unexpectedly, and therefore doesn't free backend resources on exit.

lonode commented 9 months ago

Thanks, i wanted to avoid double checking myself something you do inside your lib, maybe i'll forget some corner case when checking the invalidity of the websocket header.

Can't i override a function defined in the object WebSocketServerProtocol or WebSocketCommonProtocol to check if the state property is CLOSED ?

aaugustin commented 9 months ago

There is no public API for that in the current version of websockets.

If, some day, I rewrite the asyncio implementation, you may get a process_response API that does what you want. Right now this is only available in the threading implementation (docs), which doesn't scale to more than a few hundred clients. I don't imagine having time for that in the next year so don't hold your breath...