This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 14474 - Make it possible to close a connection in such a manner that all subsequent events are suppressed
Summary: Make it possible to close a connection in such a manner that all subsequent e...
Status: RESOLVED FIXED
Alias: None
Product: WebAppsWG
Classification: Unclassified
Component: WebSocket API (editor: Ian Hickson) (show other bugs)
Version: unspecified
Hardware: PC All
: P2 normal
Target Milestone: ---
Assignee: Ian 'Hixie' Hickson
QA Contact: public-webapps-bugzilla
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-10-14 23:01 UTC by Jonas Sicking (Not reading bugmail)
Modified: 2011-10-31 23:23 UTC (History)
9 users (show)

See Also:


Attachments

Description Jonas Sicking (Not reading bugmail) 2011-10-14 23:01:48 UTC
According to bug 14331 comment 8, the protocol requires that a connection can be closed while still allowing incoming events.

At the same time, I suspect that many web developers expect that if you call .close on a connection, no more "message" events will be fired.

Consider for example a chat application based on HTML/JS which uses websockets to receive incoming messages as well as send outgoing messages. The chat application has a [X] icon in the corner which allows the user to close the chat.

When the user closes the chat, the webpage calls socket.close() on the websocket connection. It then simply drops its references to the socket without making any further modifications to it.

This means that the onmessage event handler still remains active. If a incoming message is received, that means that the page might create UI and display where the chat application used to be before it was closed. This is ugly and unexpected.

This is of course fixable from a webpage point of view. However since it seems like a rare condition, it's likely that the developer won't detect this during development, resulting in bugs for users which is bad.

To fix this, while still conforming to the websocket protocol, I propose that we make it possible to close the connection in such a manner that it allows additional incoming message, or close it in such a manner that any incoming messages as suppressed.

I can think of at least two ways of accomplishing this:
1. Add a optional boolean argument to close.
2. Add a new function which takes the same arguments as close.

The default behavior can be debated in either solution, but I propose that the default should be to suppress additional messages as that seems like the safer path which will generate fewer bugs.

If we go with 2 I therefor suggest that we make .close suppress messages, but .closeAllowIncoming allows additional incoming messages.
Comment 1 Brian Raymor [MSFT] 2011-10-17 23:53:53 UTC
I suggest modifying the specification from:
	
When a WebSocket message has been received with type type and data data, the user agent must queue a task to follow these steps: [WSP]
1.	If the readyState attribute's value is not OPEN (1) or CLOSING (2), then abort these steps. 

to:

1.	If the readyState attribute's value is not OPEN (1), then abort these steps.


Otherwise, the mitigation is to check the readyState value in the onmessage handler to determine if the value is OPEN, before processing the message.
Comment 2 Jonas Sicking (Not reading bugmail) 2011-10-18 02:56:34 UTC
Yeah, like I said, developers can most certainly work around this problem. My concern is that it's essentially a race condition and so developers won't check. That's why I think explicit opt-in should be required if you really want to receive messages after the call to .close()
Comment 3 Ian 'Hixie' Hickson 2011-10-18 20:14:23 UTC
As far as I can tell, the protocol is explicitly designed to support this: close() is just a way to tell the server that the client is done sending messages, it's not a way to indicate that the client no longer cares about any messages from the server.

Are you saying this design is flawed?

If so, why should we be working around it in the API rather than in the protocol?
Comment 4 Brian Raymor [MSFT] 2011-10-20 03:19:39 UTC
(In reply to comment #3)
> As far as I can tell, the protocol is explicitly designed to support this:
> close() is just a way to tell the server that the client is done sending
> messages, it's not a way to indicate that the client no longer cares about any
> messages from the server.
> 
> Are you saying this design is flawed?
> 
> If so, why should we be working around it in the API rather than in the
> protocol?

No, I'm not saying that the design is flawed. The IETF discussion was quite thoughtful. I was responding to Jonas's comments about the expectations of web developers.

There were a number of subtle reasons for the close handshake design. For example:

http://www.ietf.org/mail-archive/web/hybi/current/msg01173.html
http://www.ietf.org/mail-archive/web/hybi/current/msg01181.html

As noted in msg001173, server implementations may follow this guidance:

       Because the sender must have a timeout after sending the close
       message(***), for clean shutdown from *both* sides, it's
       desirable that the receiver finishes the connection quickly,
       rather than writing "all queued messages", which can be any
       amount of data and take any amount of time.  The receiver
       should detect the close message as soon as possible, and finish
       sending its current message only, or even abort the current
       message ...

which would reduce the amount of data sent from the server after it receives a close from the client. We'll know more with broader deployment experience.

If it's important to not suppress messages received after the client sends a close, then we would prefer to use the existing readyState attribute values in onmessage rather than adding additional parameters or functions. Additional support could be added in V2 if this was noted as a common case.
Comment 5 Ian 'Hixie' Hickson 2011-10-20 06:15:50 UTC
It's unclear to me what you are asking for the API spec to say. Suppressing messages after you've send a close handshake is counter to the protocol's design. If we're to do something counter to the protocol's design, it seems better to fix the protocol.
Comment 6 Jonas Sicking (Not reading bugmail) 2011-10-20 08:24:43 UTC
How is this different from the .binaryType API?

In both cases we're adding a feature to the API in order to make life easier for web developers, even though the protocol doesn't have any such feature.

In the case of .binaryType we added a feature to ease the use of binary data by allowing the API consumer to choose a format which is more convenient or efficient.

In the case of .close/.closeAllowIncoming, we're adding a feature to allow (but not force) the consumer of the API to suppress messages which are most likely commonly unexpected.

The protocol and the API doesn't need to have exactly the same feature set. Our goal shouldn't be to mindlessly expose the protocol exactly as it is to the users of the API. Our goal should be to design a good protocol and a good API, each for the consumers that are appropriate to them. (We're not exposing ping/ack for example, even though it's in the protocol.)
Comment 7 Brian Raymor [MSFT] 2011-10-20 20:20:25 UTC
(In reply to comment #5)
> It's unclear to me what you are asking for the API spec to say. Suppressing
> messages after you've send a close handshake is counter to the protocol's
> design. If we're to do something counter to the protocol's design, it seems
> better to fix the protocol.

To be clear, we're requesting no changes to the specification, beyond perhaps clarifying this use case - that the value of the readyState attribute can be queried in onmessage to detect messages received after the client sends a close if special processing is required. No additional APIs or parameters are required.
Comment 8 Ian 'Hixie' Hickson 2011-10-26 23:23:41 UTC
Input from Opera and WebKit would be useful here.
Comment 9 Simon Pieters 2011-10-27 08:08:57 UTC
If the author don't want any more messages, just remove the event listeners.
Comment 10 Jonas Sicking (Not reading bugmail) 2011-10-27 17:42:38 UTC
Do you think authors will remember to do this? I.e. do you think the scenario in comment 0 is really unlikely?

I personally prefer to *always* suppress incoming messages after .close is called. But Hixie is resisting this simpler option.
Comment 11 Brian Raymor [MSFT] 2011-10-28 05:10:49 UTC
(In reply to comment #10)

> 
> I personally prefer to *always* suppress incoming messages after .close is
> called. But Hixie is resisting this simpler option.

I support this proposal to always suppress incoming messages during CLOSING.

After further consideration, I don't believe that suppressing messages after .close is counter to the protocol design (see comment #5).

Section 5.5.1 of the protocol states:

"However, there is no guarantee that the endpoint which has already sent a Close frame will continue to process data."

http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5.5.1

In addition, it is strongly implied that the close handshake was not intended to implement half-close (socket shutdown) semantics, because the recommendation is for the server to send a close as soon as "practical" :

"If an endpoint receives a Close frame and that endpoint did not previously send a Close frame, the endpoint MUST send a Close frame in response ...  It SHOULD do so as soon as practical.  An endpoint MAY delay sending a close frame until its current message is sent (for instance, if the majority of a fragmented message is already sent, an endpoint MAY send the remaining fragments before sending a Close frame)."
Comment 12 contributor 2011-10-31 23:23:11 UTC
Checked in as WHATWG revision r6792.
Check-in comment: Drop messages on the floor after a call to close()
http://html5.org/tools/web-apps-tracker?from=6791&to=6792