httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jacob Champion <>
Subject Thoughts on the new Protocols architecture
Date Mon, 21 Sep 2015 04:22:08 GMT
Hi all,

At Stefan's suggestion, I took a look at the new Upgrade-related hooks 
with the Protocols directive, and I tried to get mod_websocket to use 
the same machinery as an experiment. I have some thoughts and questions 
based on that -- hopefully they're of interest and/or use to you.

== Immediate Concerns ==

1) WebSocket requires a handshake to be made with the 101 response, 
which means a module that implements the protocol_switch hook needs to 
be able to affect the response headers, as well as abort the upgrade 
with a 4xx/5xx if necessary. To do this I added a hook that I called 
pre_protocol_switch; you can take a look at the patch at

I also ported mod_websocket to use this new experimental hook along with 
the other Protocols-related hooks, so you can see what a module using it 
might look like:

I'm not sure I like my new hook, to be honest. I think I may have made 
it too general with the RUN_ALL hook implementation and I'm not 
convinced that more than one module needs to be able to affect an 
Upgrade handshake. I also don't like the brittle coupling the 
mod_websocket implementation has: when the module responds to 
pre_protocol_switch, it takes several actions (mutex locking, 
subprotocol negotiation, allocation) with the assumption that it will be 
the module handling the protocol_switch hook. If another module steals 
the switch, we'll be left with leaked mutexes and probably hung client 

But I haven't come up with a better idea yet. A corresponding 
post_protocol_switch hook _might_ help with cleanup in the general case, 
but I don't think mod_websocket's implementation could make use of it. 
Perhaps a hook is not the right way to do what I'm trying to do.

2) WebSocket requires the Upgrade protocol to be handled 
case-insensitively (`Upgrade: websocket` and `Upgrade: WebSocket` are 
both valid), but the current protocol_propose implementation dance is 
case-sensitive. I hacked ap_array_str_index to use strcasecmp just to 
get it to work on my end, but it made me wonder: are Upgrade header 
values case-sensitive as a general rule? I wasn't able to find any 
statement in RFC 7230 on this, unlike the rule for Connection header 
values (they're case-insensitive).

== Medium-term (more WebSocket-specific) ==

1) WebSocket prefers that the server close the TCP connection before the 
client, and if I don't do an explicit close before returning from 
protocol_switch, Autobahn fails my test cases because the server is 
apparently waiting for the client to close first. But if I close the 
connection explicitly, mpm_event complains about a "network write 
failure in core output filter", so that doesn't seem good either. Is 
there a "proper" way to do this on my end, or is there more 
architectural work that would be needed to support server-led TCP closes?

2) Protocols is per-virtual-host, but I think typically people want to 
enable WebSocket for a particular URI, not an entire server. And it 
doesn't make much sense to me to set a "preference" for WebSocket vs. 
HTTP/2 in the Protocols directive -- they're doing entirely different 
things, and I don't think a client is likely to send them both in the 
same upgrade request anyway. Maybe WebSocket is just an oddball protocol 
from Upgrade's point of view?

== Long-term/Idle Thoughts ==

In no particular order:

- The access_log is only updated (with the 101 status) once the entire 
connection comes to an end, which seems undesirable.
- h2_session_process seems conceptually similar to mod_websocket's 
framing loop, which I think is a good thing. We seem to have settled on 
the same way to solve the "read and write simultaneously" problem.
- How does mod_h2 interact with MPMs? From a first reading it seemed 
like it would always split requests into separate threads. Are there any 
plans to have it use different strategies according to which MPM is 
installed? (In particular, I'm hoping that one WebSocket connection 
won't necessarily have to steal an entire thread from httpd, and that 
MotorZ might help us out here...)


View raw message