Subject: [hybi] Client behavior with blank server Sec-WebSocket-Protocol header

From: Peter Thorson <[email-masked]>
Date: Fri, 27 Dec 2013 09:46:50 -0600

I have a question about the interpretation of RFC6455 with respect to client subprotocol negotiation. Specifically when a client sends a Sec-WebSocket-Protocol header requesting one or more subprotocols and the server does not support any of them The use case here would be a WebSocket application that wants to use a subprotocol if the server supports it but fall back to the default “no protocol” otherwise.

RFC6455 states:
	  
> Either a single value representing the subprotocol the server
> is ready to use or null.  The value chosen MUST be derived
> from the client's handshake, specifically by selecting one of
> the values from the |Sec-WebSocket-Protocol| field that the
> server is willing to use for this connection (if any).  If the
> client's handshake did not contain such a header field or if
> the server does not agree to any of the client's requested
> subprotocols, the only acceptable value is null.  The absence
> of such a field is equivalent to the null value (meaning that
> if the server does not wish to agree to one of the suggested
> subprotocols, it MUST NOT send back a |Sec-WebSocket-Protocol|
> header field in its response).  The empty string is not the
> same as the null value for these purposes and is not a legal
> value for this field.  The ABNF for the value of this header
> field is (token), where the definitions of constructs and
> rules are as given in [RFC2616].

Which seems to indicate that returning no Sec-WebSocket-Protocol header at all is the only correct response for a server.

This has come up as an issue because a number of my library users noted a change between chrome 29 and 31 such that v29 (and all other browsers) succeed when this situation happens and set the protocol value of the WebSocket object to blank (as if there had been no subprotocol negotiation). Chrome 31 fails the handshake.

Question for the group: What is the correct behavior for a client here?

1. As a client library author, is this situation a protocol error that my browser/library should enforce or is this a situation where the end user application should check the protocol value returned by the browser/library to determine if they want to continue?
2. If the latter, is the former behavior compliant with the spec?
3. If yes to #2, this seems to imply that an application cannot reliably implement test a subprotocol and fall back to null. Does that sound right?

Question for any chrome devs here: I’ve looked through all of the SVN logs between chrome 29 and current stable and can’t find anything that would obviously indicate that a change was made. Do you have any more information on where or why this change was made?

---

From: Joakim Erdfelt <[email-masked]>
Date: Fri, 27 Dec 2013 09:39:20 -0700

I think the spec allows for an non-response on the Sec-WebSocket-Protocol,
however Chrome 31, 32 (release soon), 33 (canary), and 34 (canary) all fail
this condition.

>From a javax.websocket (JSR-356 / Default websocket in Java) point of view,
a non-match on the sub-protocol that the client declares to what the server
response has would result in a forcibly failed client connection. (this is
because endpoints are bound to a path spec + a subprotocol)

>From a Jetty point of view, the client connection would still occur, the
client endpoint, would connect, but it can choose to access the subprotocol
for its own purposes.

A quick autobahn server test, it returns no Sec-WebSocket-Protocol if there
is no match.
A quick autobahn client test, the connection still occurs on no match.

Firefox 26 connects on no match too.
Tomcat 8(beta) client connects on no match as well.
Grizzly client connects on no match too.

Haven't tested any others.

--
Joakim Erdfelt <[email-masked]>
webtide.com <http://www.webtide.com/> - intalio.com/jetty
Expert advice, services and support from from the Jetty & CometD experts
eclipse.org/jetty - cometd.org

On Fri, Dec 27, 2013 at 8:46 AM, Peter Thorson <[email-masked]>wrote:

> I have a question about the interpretation of RFC6455 with respect to
> client subprotocol negotiation. Specifically when a client sends a
> Sec-WebSocket-Protocol header requesting one or more subprotocols and the
> server does not support any of them The use case here would be a WebSocket
> application that wants to use a subprotocol if the server supports it but
> fall back to the default “no protocol” otherwise.
>
> RFC6455 states:
>
> Which seems to indicate that returning no Sec-WebSocket-Protocol header at
> all is the only correct response for a server.
>
> This has come up as an issue because a number of my library users noted a
> change between chrome 29 and 31 such that v29 (and all other browsers)
> succeed when this situation happens and set the protocol value of the
> WebSocket object to blank (as if there had been no subprotocol
> negotiation). Chrome 31 fails the handshake.
>
> 1. As a client library author, is this situation a protocol error that my
> browser/library should enforce or is this a situation where the end user
> application should check the protocol value returned by the browser/library
> to determine if they want to continue?
> 3. If yes to #2, this seems to imply that an application cannot reliably
> implement test a subprotocol and fall back to null. Does that sound right?
>
> Question for any chrome devs here: I’ve looked through all of the SVN logs
> between chrome 29 and current stable and can’t find anything that would
> obviously indicate that a change was made. Do you have any more information
> on where or why this change was made?
> _______________________________________________
> hybi mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/hybi
>

---

From: "Joonas Lehtolahti" <[email-masked]>
Date: Fri, 27 Dec 2013 18:52:40 +0200

On Fri, 27 Dec 2013 17:46:50 +0200, Peter Thorson <[email-masked]>  
wrote:

> This has come up as an issue because a number of my library users noted  
> a change between chrome 29 and 31 such that v29 (and all other browsers)  

In the WebSocket Protocol point of view the client may either continue  
with no negotiated subprotocol, or not accept the situation and close the  
connection. Both are OK.

As for browser/library side you have to keep in mind that the WebSocket  
API for JavaScript is outside the scope of the WebSocket Protocol spec  
this mailing list is for. According to the current version of Editor's  
Draft at http://dev.w3.org/html5/websockets/#feedback-from-the-protocol it  
seems that current Chrome versions are doing the right thing: if the  
server returns null subprotocol but a non-empty list of subprotocols was  
supplied in the request, then the connection is to fail.

Whether that is good behavior or not, the debate on that should be had at  
the discussion forums for WebSocket API, not here. Personally I would like  
the previous behavior that the JavaScript app can determine whether it  
wants to continue with no negotiated subprotocol or close the connection.

I hope this helps.

Cheers,

Joonas Lehtolahti

---

From: Peter Thorson <[email-masked]>
Date: Fri, 27 Dec 2013 10:54:45 -0600

On Dec 27, 2013, at 10:52 , Joonas Lehtolahti <[email-masked]> wrote:

> On Fri, 27 Dec 2013 17:46:50 +0200, Peter Thorson <[email-masked]> wrote:
> 
> In the WebSocket Protocol point of view the client may either continue with no negotiated subprotocol, or not accept the situation and close the connection. Both are OK.
> 
> As for browser/library side you have to keep in mind that the WebSocket API for JavaScript is outside the scope of the WebSocket Protocol spec this mailing list is for. According to the current version of Editor's Draft at http://dev.w3.org/html5/websockets/#feedback-from-the-protocol it seems that current Chrome versions are doing the right thing: if the server returns null subprotocol but a non-empty list of subprotocols was supplied in the request, then the connection is to fail.
> 
> Whether that is good behavior or not, the debate on that should be had at the discussion forums for WebSocket API, not here. Personally I would like the previous behavior that the JavaScript app can determine whether it wants to continue with no negotiated subprotocol or close the connection.
> 
> I hope this helps.
> 
> Cheers,
> 
> Joonas Lehtolahti

OK that is what I wanted to confirm. Thanks.

---

From: Tobias Oberstein <[email-masked]>
Date: Sat, 28 Dec 2013 03:23:37 -0800

>A quick autobahn server test, it returns no Sec-WebSocket-Protocol if there is no match.

Yes, this is the default behavior of Autobahn: if the server does not speak any of the subprotocols announced
by the client, the server won't return a Sec-WebSocket-Protocol header at all.

And the client will only automatically fail the handshake if the server _did_ return a Sec-WebSocket-Protocol
_and_ the header value is different from any of the subprotocols initially announced.

This behavior can be tuned using the onConnect() hooks on server and client side.

The default behavior is designed to follow the spec:

"
   6.  If the response includes a |Sec-WebSocket-Protocol| header field
       and this header field indicates the use of a subprotocol that was
       not present in the client's handshake (the server has indicated a
       subprotocol not requested by the client), the client MUST _Fail
       the WebSocket Connection_.
"

/Tobias