[Solved] Possible problem with mod_wstunnel going from V1.4.72 and earlier to V1.4.73 and later
Added by amcbride1 about 1 month ago
I have a simple websocket setup in the lighttpd.conf file:
$HTTP["url"] =~ "^/websocket" { wstunnel.server = ( "" => ( ( "host" => "127.0.0.1", "port" => "5039" ) ) ) wstunnel.frame-type = "binary" wstunnel.ping-interval = 10 server.stream-request-body = 2 server.stream-response-body = 2 }
When making a connection you get:
GET /websocket HTTP/1.1 Host: 10.1.3.193 Connection: Upgrade Pragma: no-cache Cache-Control: no-cache User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0 Upgrade: websocket Origin: http://10.1.3.193 Sec-WebSocket-Version: 13 Accept-Encoding: gzip, deflate Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,es;q=0.7,pt;q=0.6 Cookie: Phone=0 Sec-WebSocket-Key: 040ULsL6Scq0VprjPMTw7A== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits Sec-WebSocket-Protocol: binary HTTP/1.1 101 Switching Protocols Upgrade: websocket Sec-WebSocket-Accept: FecC6uqHnpBiJtDqKIO9PDhEcpk= Sec-WebSocket-Protocol: binary Connection: upgrade Date: Thu, 03 Oct 2024 11:36:10 GMT Server: lighttpd
When updating to anything after V1.4.73, it does not work. Although it requests binary there is no protocol header in the response which seems to stop things working.
GET /websocket HTTP/1.1 Host: 10.1.1.220 Connection: Upgrade Pragma: no-cache Cache-Control: no-cache User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0 Upgrade: websocket Origin: http://10.1.1.220 Sec-WebSocket-Version: 13 Accept-Encoding: gzip, deflate Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,es;q=0.7,pt;q=0.6 Cookie: Phone=0 Sec-WebSocket-Key: DIQ8iSGO+Dr3J+2zCOMJ3g== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits Sec-WebSocket-Protocol: binary HTTP/1.1 101 Switching Protocols Upgrade: websocket Sec-WebSocket-Accept: M4Zn1RiZ11aYCxnnLGO9SsM3KFM= Connection: upgrade Date: Thu, 03 Oct 2024 11:32:05 GMT Server: lighttpd
Looking at the code I think it is sort of related to the change in V1.4.73 "[mod_wstunnel] Sec-WebSocket-Protocol only if req hdr".
The problem is if the frame-type in the config is set to "binary" then in the "wstunnel_handler_setup" function it doesn't go into the code that sets hctx->subproto variable, so left alone which picks up 0.
This means no header gets generated for the response. Previously it just used the hctx->frame.type variable.
The workaround is to either set the frame-type to "text" as below or remove the setting of the frame-type.
$HTTP["url"] =~ "^/websocket" { wstunnel.server = ( "" => ( ( "host" => "127.0.0.1", "port" => "5039" ) ) ) wstunnel.frame-type = "text" wstunnel.ping-interval = 10 server.stream-request-body = 2 server.stream-response-body = 2 }
I wonder if the "if (!binary)" part in the "wstunnel_handler_setup" function needs changed ?
Replies (6)
RE: Possible problem with mod_wstunnel going from V1.4.72 and earlier to V1.4.73 and later - Added by gstrauss about 1 month ago
Thanks for digging into this.
Please see discussion in https://redmine.lighttpd.net/boards/2/topics/11202 for why this was changed.
Unconditionally sending Sec-WebSocket-Protocol: binary
with lighttpd config wstunnel.frame-type = "binary"
caused issues with some clients.
Please see https://redmine.lighttpd.net/boards/2/topics/11202?r=11213#message-11213 or the commit message in commit 83eadca2 for another workaround.
Is there a specific reason you must lock the configuration to wstunnel.frame-type = "binary"
, or can you leave the config as wstunnel.frame-type = "text"
, or omit wstunnel.frame-type
from the config?
BTW, streaming is automatic with mod_wstunnel, so this should not be necessary to specify for the websocket config:
server.stream-request-body = 2 server.stream-response-body = 2
I'll consider your suggestion: If the client does send explicit Sec-WebSocket-Protocol: binary
, then lighttpd should respond with Sec-WebSocket-Protocol: binary
if lighttpd is configured for wstunnel.frame-type = "binary"
, though maybe only for HTTP/1.1.
Another alternative to implement that test in your lighttpd config is
server.modules += ("mod_setenv") $HTTP["url"] =~ "^/websocket" { wstunnel.server = ( "" => ( ( "host" => "127.0.0.1", "port" => "5039" ) ) ) wstunnel.ping-interval = 10 wstunnel.frame-type = "binary" $REQUEST_HEADER["Sec-WebSocket-Protocol"] == "binary" { setenv.set-response-header = ("Sec-WebSocket-Protocol" => "binary") } }
RE: Possible problem with mod_wstunnel going from V1.4.72 and earlier to V1.4.73 and later - Added by amcbride1 about 1 month ago
Thanks for the reply, I did have a look at that.
I think the reason I had put in the 'binary' originally was just that we were using binary frames in the web socket.
It was more the fact of having that in the config and then upgrading it then broke.
So taking it out or changing it for me was fine.
I may well add the set response just to be sure.
More just a question / note in case anyone else had that set and upgraded.
RE: Possible problem with mod_wstunnel going from V1.4.72 and earlier to V1.4.73 and later - Added by gstrauss about 1 month ago
Untested patch [Edited]:
--- a/src/mod_wstunnel.c +++ b/src/mod_wstunnel.c @@ -523,7 +523,7 @@ static handler_t wstunnel_handler_setup (request_st * const r, plugin_data * con hctx->frame.payload = chunk_buffer_acquire(); unsigned int binary = hctx->conf.frame_type; /*(0 = "text"; 1 = "binary")*/ - if (!binary) { + { const buffer *vb = http_header_request_get(r, HTTP_HEADER_OTHER, CONST_STR_LEN("Sec-WebSocket-Protocol")); if (NULL != vb) { @@ -538,6 +538,9 @@ static handler_t wstunnel_handler_setup (request_st * const r, plugin_data * con break; } } + else if (binary) { + /* ignore other subprotos if already configured "binary" */ + } else if (buffer_eq_icase_ssn(s, CONST_STR_LEN("base64"))) { s += sizeof("base64")-1; while (*s==' '||*s=='\t'||*s=='\r'||*s=='\n') ++s;
RE: Possible problem with mod_wstunnel going from V1.4.72 and earlier to V1.4.73 and later - Added by amcbride1 about 1 month ago
That worked for me. It works if I specify 'binary', 'text' or leave it out.
I did have a look at the websocket procotol a bit more and I was wondering if the processing of that header would actually be better done outside of the plugin.
I had not noticed that the specification says that is more of an application defined thing so can be something like:
Sec-WebSocket-Protocol: soap, chat
For example, so you are saying in the request what you want in order of preference and then the backend would say what it supports.
I don't know if something like would work:
server.modules += ("mod_setenv") $HTTP["url"] =~ "^/websocket" { $REQUEST_HEADER["Sec-WebSocket-Protocol"] =~ "/soap/" { wstunnel.server = ( "" => ( ( "host" => "127.0.0.1", "port" => "5039" ) ) ) wstunnel.ping-interval = 10 wstunnel.frame-type = "binary" setenv.set-response-header = ("Sec-WebSocket-Protocol" => "soap") } else $REQUEST_HEADER["Sec-WebSocket-Protocol"] ~= "/chat/" { wstunnel.server = ( "" => ( ( "host" => "127.0.0.1", "port" => "5040" ) ) ) wstunnel.ping-interval = 10 wstunnel.frame-type = "binary" setenv.set-response-header = ("Sec-WebSocket-Protocol" => "chat") } }
In this case you would be using the header to choose the backend, not sure about the regex but maybe something like that would be better ?
RE: Possible problem with mod_wstunnel going from V1.4.72 and earlier to V1.4.73 and later - Added by gstrauss about 1 month ago
These are not mutually exclusive solutions.
Your last post would cause mod_setenv to overwrite the Sec-WebSocket-Protocol
response header with your desired value before the response was sent to the client. The idea is fine.
(...although the syntax for the regex would need to be corrected, e.g. $REQUEST_HEADER["Sec-WebSocket-Protocol"] =~ "soap"
)
A more pedantic, but probably unnecessary regex: $REQUEST_HEADER["Sec-WebSocket-Protocol"] =~ "(?:^| |,)soap(?:,| |$)"
Again, I do not understand why specifying wstunnel.frame-type = "binary"
in lighttpd.conf is necessary and would recommend leaving it out unless you have a reason to explicitly specify it.
RE: [Solved] Possible problem with mod_wstunnel going from V1.4.72 and earlier to V1.4.73 and later - Added by amcbride1 about 1 month ago
Thanks again for looking, as you say I don't think I should be setting it.
I think the fact I was came from the example on the wiki so was a misunderstanding on my part.
Doing the setenv in the config seems the better way of handing it given other people may be using different sub-protocols and that would mean it would be set to one of the values in the request if it was there.
It probably needs another else to handle the case when no Sec-WebSocket-Protocol was send but that does depend on the thing that is connecting.