Branch: ircv3.2-upgrade @ 3868b34.
Summary
Any inbound WebSocket frame whose payload is ≥ 528 bytes disconnects the client with WebSocket frame error. The decoder advertises a 16 KB limit, but the buffer it's handed is 528 bytes. Since browsers don't let a page control fragmentation, a web client can't work around this except by refusing to send lines over ~500 bytes — which rules out draft/multiline (the server advertises max-bytes=16384) and larger client-tag payloads.
Reproduction
Over wss:// (see #97 for why not ws://), register a client and send a single frame:
PRIVMSG #seance :xxxx… (600 bytes total)
Server response:
ERROR :Closing Link: bigframe by irc.seance.test (WebSocket frame error)
followed by TCP close (WS close code 1006 — no Close frame is sent). A 400-byte line in one frame is delivered fine.
Script used (Node 22, ws package):
const ws = new WebSocket("wss://localhost:8443/", ["text.ircv3.net"], {rejectUnauthorized: false});
ws.on("open", () => { ws.send("CAP END"); ws.send("NICK bigframe"); ws.send("USER b 0 * :b"); });
ws.on("message", (d) => {
const line = d.toString();
if (line.startsWith("PING")) ws.send("PONG" + line.slice(4));
if (/ 001 /.test(line)) { ws.send("JOIN #seance"); ws.send("PRIVMSG #seance :" + "x".repeat(583)); }
if (/ERROR/.test(line)) console.log(line);
});
Cause
ircd/websocket.c:67 — WS_MAX_PAYLOAD is 16384 and websocket_decode_frame() accepts payload lengths up to that.
ircd/s_bsd.c:1126 — the caller passes a stack buffer char ws_payload[BUFSIZE + 16] (= 528 bytes).
ircd/websocket.c:551-554 — the decoder rejects any frame whose payload length ≥ payload_size, returning the error that becomes WebSocket frame error at s_bsd.c (exit_client(... "WebSocket frame error")).
So the effective inbound frame cap is 527 bytes, not 16 KB.
Suggested fix
Size the decode buffer to WS_MAX_PAYLOAD (heap or a static per-call buffer, same as the ws_frame/concat_buf statics on the send side at s_bsd.c:332-333), then hand the decoded payload to the existing line splitter so an oversized IRC line still gets the normal ERR_INPUTTOOLONG / truncation treatment rather than a transport-level disconnect. Also worth sending a WS Close frame (1009 Message Too Big) before dropping the TCP connection so clients can distinguish this from a network failure.
Context
Found while bringing up a browser IRCv3 client (Seance, a TheLounge fork) against a docker build of this branch. Happy to test a fix.
Branch:
ircv3.2-upgrade@3868b34.Summary
Any inbound WebSocket frame whose payload is ≥ 528 bytes disconnects the client with
WebSocket frame error. The decoder advertises a 16 KB limit, but the buffer it's handed is 528 bytes. Since browsers don't let a page control fragmentation, a web client can't work around this except by refusing to send lines over ~500 bytes — which rules outdraft/multiline(the server advertisesmax-bytes=16384) and larger client-tag payloads.Reproduction
Over
wss://(see #97 for why notws://), register a client and send a single frame:Server response:
followed by TCP close (WS close code 1006 — no Close frame is sent). A 400-byte line in one frame is delivered fine.
Script used (Node 22,
wspackage):Cause
ircd/websocket.c:67—WS_MAX_PAYLOADis 16384 andwebsocket_decode_frame()accepts payload lengths up to that.ircd/s_bsd.c:1126— the caller passes a stack bufferchar ws_payload[BUFSIZE + 16](= 528 bytes).ircd/websocket.c:551-554— the decoder rejects any frame whose payload length ≥payload_size, returning the error that becomesWebSocket frame errorats_bsd.c(exit_client(... "WebSocket frame error")).So the effective inbound frame cap is 527 bytes, not 16 KB.
Suggested fix
Size the decode buffer to
WS_MAX_PAYLOAD(heap or a static per-call buffer, same as thews_frame/concat_bufstatics on the send side ats_bsd.c:332-333), then hand the decoded payload to the existing line splitter so an oversized IRC line still gets the normalERR_INPUTTOOLONG/ truncation treatment rather than a transport-level disconnect. Also worth sending a WS Close frame (1009 Message Too Big) before dropping the TCP connection so clients can distinguish this from a network failure.Context
Found while bringing up a browser IRCv3 client (Seance, a TheLounge fork) against a
docker buildof this branch. Happy to test a fix.