Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Support for websocket subprotocol field #193

Closed
oribrost opened this Issue · 18 comments

3 participants

@oribrost

Currently cowboy does not allow us to control the sec-websocket-protocol field in the upgrade response. This is needed for proper upgrade negotiation with some browsers (Safari 5.1.5 for example).

@essen
Owner

Can you give us more details as how you expect that field to be used?

@oribrost

This field should is used for negotiating a protocol with a client.
For example, let's say our client sends

sec-websocket-protocol: foo, bar

Then the client expects the server to decide which subprotocol it prefers of the two. If the server prefers foo it is expected to reply with

sec-websocket-protocol: foo

We have done some testing with Safari and it appears that even if only one subprotocol is sent, safari expects the server to reply with the same subprotocol or an error message appears.

@oribrost

Here is the dummy implementaiton we currently use to overcome this:
nivertech@0be97bc

@ghost

Looks like a good diff to base an @essen blessed fix on.

@oribrost Should we count on a pull request coming up or are we doing a hand off of the problem here?

@essen
Owner

I suppose we do want to allow the application to select the protocol they want, otherwise return the first in the list as a default.

@ghost

Not sure if that's a reasonable default behavior. We would want to attempt to do the "right" thing to ensure that older websocket handlers continue to work for a reasonable amount of time. @essen what do you think about adding an optional list of protocol names to the return values from the websocket_init/3 callback?

@oribrost

@klaar
I'd prefer if the diff I sent would be the base for a change that you will make, since I'm not sure about what would be the best way to pass a parameter back saying which protocol the server has chosen.

@ghost

An alternative solution is to add an optional websocket_protocols/2 callback for websockets.

@nivertech

@oribrost fix was workaround for the problem we had with Safari, but I believe this behavior should be default.

I'll give a more generic use case:

  1. Suppose we have JS application, which uses two websocket based protocols: AMQP-over-WebSocket and XMPP-over-WebSocket with corresponding subprotocol names "amqp" and "xmpp".

  2. Now let's suppose that it communicates with two servers: one ejabberd and another Cowboy-based.
    Ejabberd server only supports XMPP-over-Websockets, but Cowboy-based supports both.

  3. When I say Cowboy-based server support both subprotocols, I mean, that we have two callback modules implementing cowboy_http_websocket_handler behaviour: amqp_websocket_handler and xmpp_websocket_handler. When creating listener for these handlers their supported suprotocols should be specified. Each handler may handle more than one subprotocol or use '*' (or '_') if subprotocols not used or do not matter.

  4. There are should be another callback module, which will resolve cases, when server can handle when multiple requested subprotocols are supported. Or simple solution should be used where Cowboy will choose the first handler, which support one of the requested subprotocols. I think dispatch table in cowboy:start_listener can be a good place to specify subprotocols.

  5. In our example if JS client connects to ejabberd it will choose "xmpp" subprotocol. But when connected to Cowboy-based server with both "amqp" and "xmpp" handlers, it will need to decide which subprotocol to use.

Hope this defines more generic use case.

@ghost

That's an excellent summary of how you are actually intending to use this feature. I was under the impression that you were using the same callback module to implement a protocol that was sometimes identified by name when Safari was used.

@nivertech

Yes, you are right, in our case the same callback module implements two subprotocols. They very similar, so it's not a big problem. But in the not so distant future we'll want to implement very different WS subprotocols, like in my example above.

@ghost

@nivertech The biggest "issue" at this point is how to associate multiple callback modules with one entry in the dispatch table. Personally I like the possibility of upgrading the handler module the same way that you perform protocol upgrades at the moment. Any strong opinions on that? (for example: returning {upgrade, handler, XMPPMod, Opts} from websocket_init.

@oribrost

why not combine with {upgrade, protocol, cowboy_http_websocket} already returned by init()?

@essen
Owner

I'll add a function to parse the websocket protocol header. I don't see much need to add anything special in the reply, since you can probably already use set_resp_header to set the protocol you need in websocket_init.

@essen
Owner

Or do I not understand and some browsers set a protocol header with a value by default?

@oribrost

you are right, set_resp_header is the correct solution for this, we've updated our cowboy fork as needed (https://github.com/nivertech/cowboy/tree/ori_cowboy_0.5.0_changes_080412)

@essen
Owner

I have added parse_header support for sec-websocket-protocol. Please open a new ticket if more is needed. Thanks!

@essen essen closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.