Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ClientWebSocketResponse fails with TypeError if server closed the connection #3645

Open
dangusev opened this issue Mar 11, 2019 · 2 comments
Labels

Comments

@dangusev
Copy link

dangusev commented Mar 11, 2019

Long story short

Hi,

I have an application serving websockets and I test it using the aiohttp websockets as a client. When I call .close() on the server-side, the client-side fails with TypeError: Received message 8:4404 is not str. I want to determine how to handle these situations correctly, e.g. when client receives WSMsgType.CLOSE message instead of e.g WSMsgType.TEXT?

Expected behaviour

The ideal case would be to have an exception from e.g ClientError with error_code and message within.

Please, tell me if this way is appropriate or not and I'll try to make a PR.
It seems not to break backward incompatibility if the exception will be raised within receive_str|bytes|json methods, the receive code could stay the same.
Thanks!

Actual behaviour

Websocket client fails with TypeError: Received message **** is not str
It happens because ClientWebSocketResponse.receive() return msg in case of CLOSE https://github.com/aio-libs/aiohttp/blob/master/aiohttp/client_ws.py#L255 and then
ClientWebSocketResponse.receive_str() just raises the TypeError https://github.com/aio-libs/aiohttp/blob/master/aiohttp/client_ws.py#L272

Currently I have to write my own wrapper around receive and handle websocket's closing manually.

Steps to reproduce

  1. Run websocket server with endpoint that closes the connection write after accepting it. I use Sanic, but behaviour with aiohttp server should be the same.
  2. Connect to websocket using ws = await ClientSession.ws_connect()
  3. Call await ws.receive_json() or ws.receive_str()
  4. See the TypeError in logs

Your environment

python 3.7, aiohttp 3.5.4, OS X 10.14.3

@aio-libs-bot
Copy link

GitMate.io thinks the contributor most likely able to help you is @asvetlov.

Possibly related issues are #1814 (Close websocket connection when pong not received), #3052 (SSL with closed connections), #370 (Server closes connection before sending data), #2595 (Server handler halts after client connection closed), and #1768 (websocket connection is closing.).

@wenleix
Copy link

wenleix commented May 31, 2023

I ran into similar issue. This makes receive_json / receive_str less useful in applications if

  • we don't know in advance how many round server may sent client data; and server may close connection normally or crash
  • we want to distinguish between server closed vs. server sent malformed data.

As a result, I also end up often needs to write my own version of receive_json/str, e.g.

async def my_receive_str(response) -> Optional[str]:
    msg = await response.receive()	
    if msg == aiohttp.http.WS_CLOSED_MESSAGE or msg == aiohttp.http.WS_CLOSING_MESSAGE:	
        await response.close()
        return None # or throw exceptions other than TypeError

    if msg.type != aiohttp.WSMsgType.TEXT:	
        raise TypeError(f"Received message {msg.type}:{msg.data!r} is not str")

   return cast(str, msg.data)

Throw an different type of error (like WSConnectionClosedException) is one way. Another thought is to return None upon closed connection.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants