Repository navigation
Conversation
|
Updated 4:52 PM PT - Sep 6th, 2026
❌ @robobun, your commit 7bc1713 has 3 failures in
🧪 To try this PR locally: bunx bun-pr 34958That installs a local version of the PR into your bun-34958 --bun |
|
Reproduced with a raw-socket probe against a hung handler: with CI (build 111801):
Ready for maintainer review. |
WalkthroughChangesServer timeout behavior
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/js/bun/http/serve.test.ts`:
- Around line 2779-2829: Extend the inputs matrix in the “server.timeout()
validates its seconds argument” test with an extreme finite integer such as 2 **
64, probe it, and assert the same out-of-range error as other values above 255,
preserving the existing cases and expected messages.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 02912e1a-6594-4951-bd0c-278a944a3c1e
📒 Files selected for processing (2)
src/runtime/server/server_body.rstest/js/bun/http/serve.test.ts
There was a problem hiding this comment.
No bugs found; the validation matches idleTimeout's pattern and the tests are solid. Deferring to a maintainer only because this tightens a public Bun API — inputs that previously truncated/clamped (e.g. 1.9 → 1s, 300 → 255s) will now throw, which is a user-visible behavior change worth a human sign-off.
What was reviewed:
- Confirmed the new check mirrors
idleTimeoutinServerConfig.rs(is_any_int()+to_int64()+ range) and uses the samethrow_invalid_argumentshelper. - Verified dropping
% 255is correct (and fixes255 % 255 = 0on theNodeHTTPResponsebranch);RequestContext::set_timeoutalready.min(255)-clamps internally so nothing >255 was ever meaningfully honored. - Checked that moving the Unix-socket early-return after validation only means invalid args now throw on Unix servers too — consistent, no side effect ordering concern.
- Prior nit (redundant
connection.end()alongsideawait using) was addressed in e7b0c19.
Extended reasoning...
Overview
Two files: src/runtime/server/server_body.rs (~15 net lines in NewServer::timeout) and two new concurrent tests in test/js/bun/http/serve.test.ts. The Rust change replaces is_number() + to_u32() with is_any_int() + to_int64() + an explicit 0..=255 range check, moves the Unix-socket short-circuit after validation, and drops the value % 255 on the NodeHTTPResponse branch now that the range is enforced.
Security risks
None. This is input validation on a per-request idle-timeout knob; no auth/crypto/permissions surface. Tightening validation strictly reduces the input space that reaches set_timeout.
Level of scrutiny
Medium. The implementation is mechanical and mirrors the existing idleTimeout validation in ServerConfig.rs:1126-1143 almost line-for-line. What warrants a human look is the API-design decision, not the code: this changes server.timeout() from accepting any number (with silent truncation/clamping) to rejecting non-integers and out-of-range values. Previously server.timeout(req, 1.9) set a ~1s timeout and server.timeout(req, 300) clamped to 255s on the Request path (or bizarrely became 45s via % 255 on the node:http path); both now throw. The clearly-buggy cases (NaN/negative/0.4 silently disabling the timeout, 255 % 255 → 0) are unambiguous fixes, but rejecting fractional seconds and >255 rather than truncating/clamping is a choice a maintainer should confirm for a Bun-native public API.
Other factors
- All prior review threads (CodeRabbit's
2 ** 64case, myconnection.end()nit) are resolved with follow-up commits. - Tests cover the full input matrix including boundaries (0, 255) and adversarial values (NaN, ±Infinity, negative, fractional, 300, 2**64), plus a behavioral test proving the idle timeout stays armed after an invalid
timeout()call. The behavioral test uses a boundedPromise.raceagainst a 12s sleep with a 20s test timeout, matching the neighboringallow custom timeout per requesttest's structure. - The
.d.tssignature (timeout(request: Request, seconds: number): void) is unchanged; it might merit a doc note that seconds must be an integer 0–255, but that's non-blocking.
server.timeout(req, N) only checked is_number() before converting with to_u32(), so NaN, negatives, and fractional values all became 0, which clears the per-request timeout entirely. A typo or unit mistake (0.4 intended as 500ms) silently removed the hung-handler/slow-loris bound the code asked for. idleTimeout on the same server validates with is_any_int() and a range check; apply the same here (integer, 0..=255) so bad input throws an ERR_INVALID_ARG_TYPE instead of disabling the timeout.
e7b0c19 to
7bc1713
Compare
|
Rebased onto current main (the branch had gone stale and conflicted in |
Problem
server.timeout(req, seconds)only checkedis_number()and converted withto_u32().NaN, negatives and fractions below 1 became0, which clears the timeout. Anything above 255 was clamped byRequestContext::set_timeout(seconds.min(255) as u8), soserver.timeout(req, 3600)is a 4 min 16 s cutoff with no diagnostic.idleTimeoutoption validates the same quantity and throws for all of these. The method accepted them.timeoutinsrc/runtime/server/server_body.rs. TheNodeHTTPResponsearm also used(value % 255) as u8, which maps 255 to 0 (disabled).Fix
is_any_int(), elseTypeError: timeout() expects an integer number of seconds) in0..=255(elseRangeError [ERR_OUT_OF_RANGE]: The value of "seconds" is out of range. It must be >= 0 and <= 255. Received N, the same shapeoptions.portuses). The validatedu8goes to both arms, so the% 255is gone.0:0is the documented way to disable the timeout.0..=255range forserver.timeout().test/js/bun/http/serve.test.ts(server.timeout() validates its seconds argument,... does not silently disable the idle timeout on invalid input; both fail on 1.4.3). Also every othertimeouttest in that file andserve-http2-lifecycle.test.ts.Background
u8count of seconds on a 4 s granularity wheel, which is whyidleTimeoutcaps at 255.server.timeout(req, n)re-arms that same timer for one request's socket, so it has the same range.set_timeout(0)callsclear_timeout(): zero means "never time out", not "time out now".Notes
TypeErrorfor out-of-range values too; the range failure is now aRangeErrorwithcode: "ERR_OUT_OF_RANGE", and the test pins the error class with each message.idleTimeout: 30:timeout(req, 256 | 1000 | 3600 | Infinity)all close the connection after ~256 s,timeout(req, -1 | NaN)never close it,timeout(req, 0.4)never closes it.1.9to 1 s,300to 255 s) now throw. That is the point of the change, and it matches what theidleTimeoutoption already does for the same numbers.server.timeout()on a unix-socket server still returns early without validating further (unchanged).