Bun.serve: validate websocket integer options before narrowing
Closed
RO
1mo ago+110+110+012345678901234567890123456789-4-4-0123456789
Problem
The Bun.serve({ websocket }) integer options were narrowed with as u32 / as u16 before any range check in src/runtime/server/WebSocketServerContext.rs, so out-of-range values silently wrapped:
maxPayloadLength: 2**32 + 16behaved as 16: every message over 16 bytes closed the connection with code 1006idleTimeout: 65566was accepted and behaved as 30 seconds, whileidleTimeout: 961threwwebsocket expects idleTimeout to be 960 or less(andidleTimeout: 65536wrapped to 0, silently disabling the timeout)backpressureLimit: 2**32 + 1behaved as 1 byte, so queued sends were dropped (ws.send()returned 0)
for (const ws of [{ idleTimeout: 65566 }, { idleTimeout: 961 }]) {
try { Bun.serve({ port: 0, fetch() {}, websocket: { message() {}, ...ws } }).stop(true); console.log(ws, "accepted"); }
catch (e) { console.log(ws, "threw:", e.message); }
}
// before: {idleTimeout:65566} accepted, {idleTimeout:961} threw
// after: both throw
Fix
idleTimeoutis range-checked on the widei64value before narrowing, matching how the top-levelBun.serve({ idleTimeout })is handled inServerConfig.rs, so any value above 960 now throws.maxPayloadLengthandbackpressureLimitnow use the saturatingJSValue::to_u32()helper, so oversized values clamp tou32::MAXinstead of wrapping. These two have no semantic cap (the u32 is a storage limit), and clamping keeps configs likemaxPayloadLength: Number.MAX_SAFE_INTEGERmeaning "as large as supported" rather than turning them into startup errors.idleTimeout's 960 cap is a real uWebSockets limit, so exceeding it rejects.
Negative values clamp to 0 as before.
Verification
Three tests added to test/js/bun/http/bun-serve-args.test.ts under Bun.serve websocket options: all three fail on bun 1.4.0 (65566 accepted, 100-byte message closed with 1006, queued sends dropped) and pass with this change. The full file passes in 2.7s under a debug ASAN build.
no test proof · iteration 0 · Platform-specific test(s) that do not run on this machine. Deferring to CI, which covers all platforms: test/js/bun/http/bun-serve-args.test.ts