Skip to content

Commit fb7749d

Browse files
committed
Ignore presence of Upgrade header on Safari browsers
First user-agent specific workaround in Lwan. Ugh. This will ignore the absence of the Upgrade header when establishing websocket connections if we detect that the user agent is Safari. Hopefully newer versions of Safari have fixed this, but like many workarounds, this one is probably forever. Fixes #345.
1 parent 44675ea commit fb7749d

File tree

1 file changed

+29
-1
lines changed

1 file changed

+29
-1
lines changed

src/lib/lwan-request.c

+29-1
Original file line numberDiff line numberDiff line change
@@ -1371,8 +1371,36 @@ prepare_websocket_handshake(struct lwan_request *request, char **encoded)
13711371
return HTTP_BAD_REQUEST;
13721372

13731373
const char *upgrade = lwan_request_get_header(request, "Upgrade");
1374-
if (UNLIKELY(!upgrade || !streq(upgrade, "websocket")))
1374+
if (UNLIKELY(!upgrade)) {
1375+
/* Ugh. Some older versions of Safari do not send an Upgrade header
1376+
* when establishing websocket connections. I don't want to ignore
1377+
* this header in the name of being as strict as possible, but if
1378+
* the handshake doesn't work in those browsers, this whole thing is
1379+
* useless. Sniffing the user agent here for compatibility reasons
1380+
* makes me want to puke in my mouth a little bit, but seems to be
1381+
* the best way to workaround this, while being more strict for those
1382+
* user agents that are actually compliant with the RFC. */
1383+
const char *user_agent = lwan_request_get_header(request, "User-Agent");
1384+
if (!user_agent)
1385+
return HTTP_BAD_REQUEST;
1386+
1387+
/* A bunch of browsers include the substring "Safari" in their user
1388+
* agent, so look for them first. If we find "Chrome" or "Android"
1389+
* then it's not Safari. Hopefully this catches other Chrome-based
1390+
* browsers too, where the handshake is correctly performed with the
1391+
* Upgrade header. */
1392+
if (strstr(user_agent, "Chrome") || strstr(user_agent, "Android"))
1393+
return HTTP_BAD_REQUEST;
1394+
1395+
/* If we find a "Safari" string in the user agent at this point,
1396+
* then we're almost certain it's a Safari browser, and we can
1397+
* ignore the absence of an Upgrade header. If it's not there, then
1398+
* they should've sent the Upgrade header. Blergh. */
1399+
if (!strstr(user_agent, "Safari"))
1400+
return HTTP_BAD_REQUEST;
1401+
} else if (UNLIKELY(!streq(upgrade, "websocket"))) {
13751402
return HTTP_BAD_REQUEST;
1403+
}
13761404

13771405
const char *sec_websocket_key =
13781406
lwan_request_get_header(request, "Sec-WebSocket-Key");

0 commit comments

Comments
 (0)