From 3164ef34a5ee2937ecd7cf03b85e6a25952773ba Mon Sep 17 00:00:00 2001 From: tt-a1i <53142663+tt-a1i@users.noreply.github.com> Date: Tue, 23 Jun 2026 03:37:44 +0800 Subject: [PATCH] fix(serve): reject fractional max connections --- packages/cli/src/serve/run-qwen-serve.ts | 11 ++++++----- packages/cli/src/serve/server.test.ts | 20 ++++++++------------ 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/packages/cli/src/serve/run-qwen-serve.ts b/packages/cli/src/serve/run-qwen-serve.ts index bd712c7730c..82d00b01a2a 100644 --- a/packages/cli/src/serve/run-qwen-serve.ts +++ b/packages/cli/src/serve/run-qwen-serve.ts @@ -1158,14 +1158,15 @@ export async function runQwenServe( // promise instead of escaping as an uncaught exception inside the // listen callback (which fires from the `listening` event after the // outer promise has already resolved). Silent fail-OPEN on NaN / - // negative would weaken the DoS/FD-exhaustion guard the cap exists - // for. + // negative / fractional values would weaken or blur the + // DoS/FD-exhaustion guard the cap exists for. if ( opts.maxConnections !== undefined && - (Number.isNaN(opts.maxConnections) || opts.maxConnections < 0) + !isNonNegativeIntegerOrInfinity(opts.maxConnections) ) { throw new TypeError( - `Invalid maxConnections: ${opts.maxConnections}. Must be >= 0 ` + + `Invalid maxConnections: ${opts.maxConnections}. ` + + `Must be a non-negative integer ` + `(0 / Infinity = unlimited).`, ); } @@ -1190,7 +1191,7 @@ export async function runQwenServe( // with `SocketError: other side closed`). Treat 0 / Infinity // as "leave the property unset" so the documented disable // path actually disables instead of silently bricking the - // daemon. NaN / negative are rejected upstream so + // daemon. NaN / negative / fractional values are rejected upstream so // they never reach here. const cap = opts.maxConnections ?? 256; if (cap > 0 && Number.isFinite(cap)) { diff --git a/packages/cli/src/serve/server.test.ts b/packages/cli/src/serve/server.test.ts index 72e0dae3146..f2d4fd6aa81 100644 --- a/packages/cli/src/serve/server.test.ts +++ b/packages/cli/src/serve/server.test.ts @@ -8970,7 +8970,7 @@ describe('runQwenServe', () => { // Node 22 `server.maxConnections = 0` causes the listener to // refuse EVERY connection. An operator following the documented // disable path got a daemon that booted cleanly but silently - // bricked every request. Fix treats 0 / Infinity / non-finite as + // bricked every request. Fix treats 0 / Infinity as // "leave the property unset" so Node's default (no cap) actually // applies. handle = await runQwenServe({ @@ -9012,7 +9012,11 @@ describe('runQwenServe', () => { expect(handle.server.maxConnections).toBe(100); }); - it('--max-connections NaN/negative throws at boot (BUF9-)', async () => { + it.each([ + ['NaN', NaN], + ['negative', -5], + ['fractional', 1.5], + ])('--max-connections %s throws at boot (BUF9-)', async (_label, value) => { // Silent fail-OPEN on a CLI typo would weaken the DoS guard. // Boot-loud is the right behavior for an unparseable cap. await expect( @@ -9020,17 +9024,9 @@ describe('runQwenServe', () => { hostname: '127.0.0.1', port: 0, mode: 'http-bridge', - maxConnections: NaN, - }), - ).rejects.toThrow(/maxConnections: NaN/); - await expect( - runQwenServe({ - hostname: '127.0.0.1', - port: 0, - mode: 'http-bridge', - maxConnections: -5, + maxConnections: value, }), - ).rejects.toThrow(/maxConnections: -5/); + ).rejects.toThrow(/maxConnections/); }); it('case-insensitive loopback: --hostname Localhost / LOCALHOST does NOT require a token (BQ92B)', async () => {