snapview / tokio-tungstenite

Future-based Tungstenite for Tokio. Lightweight stream-based WebSocket implementation
MIT License
1.88k stars 236 forks source link

SendAfterClosing when doing the close handshake in 0.20.1 #310

Closed threema-donat closed 11 months ago

threema-donat commented 11 months ago

Recently, we updated our tokio-tungstenite dependency to the latest version. Since then, the close handshake cannot be completed anymore because the stream is closed automatically.

The flow is as following:

Client sends a close frame without a close code. The server then tries to call the tokio_tungstenite::WebSocketStream::close fn with the parameter None, which fails with the ProtocolError::SendAfterClosing.

Did something change from version 0.18.0 to 0.20.1 that this does not work anymore? Any hint in the right direction would be greatly appreciated.

daniel-abramov commented 11 months ago

Could you provide a SSCCE that reproduces the behavior you're describing?

So far it looks as if it might behave correctly. If the client sends a close to the server, you don't need to additionally close the stream as we've always automatically replied to the close frames. What must have happened is that by the time you called close(), the stream got already closed. But if you had some code that I could run and check how it behaves, I could provide a bit more insights.

That being said, you don't need to call close() when you receive a close frame (you may if you want, but there is no need to and I can't find any use case where it would be useful given that we anyway reply to close() automatically, so calling to close() after getting a close frame is futile).

threema-donat commented 11 months ago

Hi daniel, thank you for the quick response!

I've created a SSCCEE here.

In my understanding of the close handshake in the RFC the server could still be processing and receiving messages from the client until the server completes the closing handshake with a close message. For this reason, we want to control the code that is sent to the client and complete the handshake with e.g. the close code 1000 (Normal) when the close frame from the client is received. Like this, we're sure everything was handled correctly.

Right now, tokio-tungstenite automatically closes with the close code it received, and we can't indicate that the communication was indeed not successful.

daniel-abramov commented 11 months ago

I see, I understand what you mean.

So this behavior is not something you can accomplish with tokio-tungstenite at the moment, because it's built on top of tungstenite and tungstenite automatically replies to ping and close messages. We chose this behavior a long time ago to ensure that the 'batteries included' library just works, meaning that we would need to ensure that the library enforces RFC compliance by behaving according to the RFC (otherwise it would be a user's responsibility to reply to pings and close frames).

Unfortunately, we don't support a flag that opts out of this behavior (but it might be added if there is a PR that adds this support).

threema-donat commented 11 months ago

I see, thank you for the information. We will check whether there are free resources to submit such a PR.