Bun.serve: validate websocket integer options before narrowing

Closed
RO
1mo ago
+110-4

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 + 16 behaved as 16: every message over 16 bytes closed the connection with code 1006
  • idleTimeout: 65566 was accepted and behaved as 30 seconds, while idleTimeout: 961 threw websocket expects idleTimeout to be 960 or less (and idleTimeout: 65536 wrapped to 0, silently disabling the timeout)
  • backpressureLimit: 2**32 + 1 behaved 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

  • idleTimeout is range-checked on the wide i64 value before narrowing, matching how the top-level Bun.serve({ idleTimeout }) is handled in ServerConfig.rs, so any value above 960 now throws.
  • maxPayloadLength and backpressureLimit now use the saturating JSValue::to_u32() helper, so oversized values clamp to u32::MAX instead of wrapping. These two have no semantic cap (the u32 is a storage limit), and clamping keeps configs like maxPayloadLength: Number.MAX_SAFE_INTEGER meaning "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