whatwg / websockets

WebSockets Standard
https://websockets.spec.whatwg.org/
Other
47 stars 13 forks source link

Close status is not optional? #61

Open rotu opened 2 months ago

rotu commented 2 months ago

What is the issue with the WebSockets Standard?

This spec says that the close code is optional, in self-acknowledged contradiction[^1] of RFC 6455. The RFC is very explicit about this:

If this Close control frame contains no status code, The WebSocket Connection Close Code is considered to be 1005.

[^1]: @ricea, what was the erratum that you wished to make?

For instance, with Chrome and Node.JS using the popular ws package, closing a connection from the client with .close() results in CloseEvent with code 1005. On the other hand, closing the connection from the client with .close(1000) results in a CloseEvent with code 1000.

The MDN page has another take, suggesting that .close() is synonymous with .close(1000):

If unspecified, a close code for the connection is automatically set: to 1000 for a normal closure


From an end-user perspective, I think the behavior documented on MDN page makes the most sense (even though it aligns with neither standard. Calling the .close() function without an error indicates a normal, intended closure.

ricea commented 1 month ago

@ricea, what was the erratum that you wished to make?

Section 7.1.2 says

To _Start the WebSocket Closing Handshake_ with a status code
   ([Section 7.4](https://datatracker.ietf.org/doc/html/rfc6455#section-7.4)) /code/ and an optional close reason ([Section 7.1.6](https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.6))
   /reason/, an endpoint MUST send a Close control frame, as described
   in [Section 5.5.1](https://datatracker.ietf.org/doc/html/rfc6455#section-5.5.1), whose status code is set to /code/ and whose close
   reason is set to /reason/.

It implies that /code/ is compulsory, whereas the rest of RFC6455 suggests that is is optional.

I don't like MDN's interpretation, because it provides no way to send a Close frame with no body. I don't want to force someone to waste 2 bytes sending the code "1000" if the server doesn't care.

rotu commented 1 month ago

The code is optional in the sense that, if omitted, the connection still gets closed. My reading is that it should be sent to indicate the client intended to close the connection (rather than, say, that the status was accidentally omitted or lost by an intermediary).

I don’t think economizing on 2 bytes is a compelling reason. The server does care in that it is expected to behave differently and it does populate those two bytes in the response regardless.

It’s notable that, while you can call .close(1000), it is erroneous by this spec to call .close(1005).

So I guess the issue here (and what I hoped to glean from your erratum on RFC6455) is essentially that it’s unclear how code 1005 should be regarded:

rotu commented 1 month ago

Also, per this spec, if a WebSocket object is garbage-collected while open, then no status code is sent. It seems odd to make this the same code as if close() is called with no status.

ricea commented 1 month ago

Interesting. From your analysis, it looks like there was a difference of opinion between the people who designed the protocol and the people who designed the API.

I don't have time to write an erratum, but if I did I would go for “the client does not use and does not care about the close code”, as I think it most closely describes real-world usage.

If a developer went to the trouble to send code 1000, I would take it to mean that they might send some other code in other circumstances.