Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions connectd/test/run-websocket.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,30 @@ int main(int argc, char *argv[])
my_rbuf = tal_strdup(tmpctx, hdr);
my_wbuf = tal_arr(tmpctx, char, 0);

http_upgrade(STDIN_FILENO);
assert(streq(tal_strndup(tmpctx, my_wbuf, tal_bytelen(my_wbuf)),
"HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
"\r\n"));

/* Header names are case-insensitive (RFC 9110 5.1) and the Upgrade
* and Connection values are ASCII case-insensitive (RFC 6455 4.2.1).
* Node's built-in WebSocket sends lowercased header names. */
hdr = "GET /chat HTTP/1.1\r\n"
"host: server.example.com\r\n"
"upgrade: WebSocket\r\n"
"connection: upgrade\r\n"
"sec-websocket-key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"origin: http://example.com\r\n"
"sec-websocket-protocol: chat, superchat\r\n"
"sec-websocket-version: 13\r\n\r\n";

my_rbuf = tal_strdup(tmpctx, hdr);
my_rbuf_off = 0;
my_wbuf = tal_arr(tmpctx, char, 0);

http_upgrade(STDIN_FILENO);
assert(streq(tal_strndup(tmpctx, my_wbuf, tal_bytelen(my_wbuf)),
"HTTP/1.1 101 Switching Protocols\r\n"
Expand Down
24 changes: 20 additions & 4 deletions connectd/websocketd.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,11 @@ static const char *get_http_hdr(const tal_t *ctx, const u8 *buf, size_t buflen,
/* Empty line? End of headers. */
if (hdrlen == 0)
return NULL;
/* header name followed by : */
if (memstarts(buf, hdrlen, hdrname, strlen(hdrname))
/* header name (ASCII case-insensitive, RFC 9110 #5.1)
* followed by : */
if (hdrlen > strlen(hdrname)
&& strncasecmp((const char *)buf, hdrname,
strlen(hdrname)) == 0
&& buf[strlen(hdrname)] == ':')
break;
buf = end + 2;
Expand All @@ -126,6 +129,19 @@ static bool http_headers_complete(const u8 *buf, size_t len)
return memmem(buf, len, "\r\n\r\n", 4) != NULL;
}

/* Like strstr, but ASCII case-insensitive: RFC 6455 says the Upgrade and
* Connection values are "treated as an ASCII case-insensitive value". */
static bool contains_ci(const char *haystack, const char *needle)
{
size_t n = strlen(needle);

for (const char *p = haystack; *p; p++) {
if (strncasecmp(p, needle, n) == 0)
return true;
}
return false;
}

static void http_respond(int fd, const u8 *buf, size_t len)
{
const char *hdr;
Expand Down Expand Up @@ -160,10 +176,10 @@ static void http_respond(int fd, const u8 *buf, size_t len)
6. A |Sec-WebSocket-Version| header field, with a value of 13.
*/
hdr = get_http_hdr(tmpctx, buf, len, "Upgrade");
if (!hdr || !strstr(hdr, "websocket"))
if (!hdr || !contains_ci(hdr, "websocket"))
bad_http(fd, "Upgrade: websocket missing");
hdr = get_http_hdr(tmpctx, buf, len, "Connection");
if (!hdr || !strstr(hdr, "Upgrade"))
if (!hdr || !contains_ci(hdr, "Upgrade"))
bad_http(fd, "Connection: Upgrade missing");
hdr = get_http_hdr(tmpctx, buf, len, "Sec-WebSocket-Version");
if (!hdr || !streq(hdr, "13"))
Expand Down