Repository navigation
Conversation
NodeHTTPResponse__setTimeout computed (to_int32() as c_uint).min(255), which bit-reinterprets a negative i32 as a large unsigned value before clamping, so req.setTimeout(-1000) set a 255-second idle timeout instead of disabling it. The Zig reference uses JSValue.toU32 (clamp negatives to 0, saturate at u32::MAX) and the sibling Request__setTimeout was already ported that way; this brings NodeHTTPResponse into line. Adds a bun:internal-for-testing hook to read back the stored uWS HttpResponseData::idleTimeout so the clamping can be asserted directly; the 0-vs-255 difference is otherwise only observable after ~255 seconds.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (7)
WalkthroughAdds a ChangesNode HTTP request timeout getter and setTimeout clamping fix
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
Updated 10:05 AM PT - Jun 15th, 2026
❌ @robobun, your commit 5c5d0ad has some failures in 🧪 To try this PR locally: bunx bun-pr 32308That installs a local version of the PR into your bun-32308 --bun |
There was a problem hiding this comment.
LGTM — one-line clamping fix matching the Zig reference, plus mechanical read-only test plumbing.
Extended reasoning...
Overview
The functional change is a single line in src/runtime/server/NodeHTTPResponse.rs: (seconds.to_int32() as c_uint).min(255) → seconds.to_u32().min(255). This fixes negative req.setTimeout(msecs) values wrapping to 255 instead of clamping to 0. The remaining ~50 lines thread a read-only get_timeout accessor through uWS C++ → Rust FFI → JSC host fn → bun:internal-for-testing so the test can observe the stored idleTimeout byte without waiting 255s.
Security risks
None. The new getter only reads a uint8_t field from HttpResponseData and is reachable solely via bun:internal-for-testing (debug/CI only). No new user-facing surface, no untrusted input parsing.
Level of scrutiny
Low-to-medium. The core fix is trivially verifiable: JSValue::to_u32() is documented at src/jsc/JSValue.rs:798 as clamping negatives to 0 and saturating at u32::MAX, exactly matching the Zig reference and the already-correct sibling Request__setTimeout (src/runtime/webcore/Request.rs:411). The test plumbing is mechanical — each new function is a near-copy of its adjacent setter (uws_res_get_timeout mirrors uws_res_timeout, jsHTTPGetTimeout mirrors jsHTTPSetTimeout, etc.) and follows established patterns in every layer.
Other factors
- Verified
idleTimeoutis auint8_tfield onHttpResponseData(packages/bun-uws/src/HttpResponseData.h:110), so the C accessor and Rustu8return type are correct. - Verified
kHandleis exported frominternal/http. - The new test covers a matrix of negative/zero/large/infinite inputs and the PR description shows it failing without the fix.
- robobun reports CI failures on the prior commit, but they're uniform
-no-pielinker warnings / genericci.tsbuild failures across all platforms — characteristic of base-branch infra noise rather than anything this diff introduced (the autofix commit hasn't reported yet).
There was a problem hiding this comment.
LGTM — one-line clamping fix matching the sibling Request__setTimeout, with a clean test-only readback path to verify it.
Extended reasoning...
Overview
The functional change is a single line in src/runtime/server/NodeHTTPResponse.rs: (seconds.to_int32() as c_uint).min(255) → seconds.to_u32().min(255), so negative IncomingMessage.setTimeout inputs clamp to 0 instead of wrapping to 255. I confirmed JSValue::to_u32 (src/jsc/JSValue.rs:803) is to_int64().clamp(0, u32::MAX as i64) as u32, and that the sibling Request__setTimeout (src/runtime/webcore/Request.rs:411) already uses the same pattern with a comment calling out exactly this hazard. The remaining ~50 lines thread a read-only idleTimeout getter from uWS (uws_res_get_timeout reading HttpResponseData::idleTimeout, a uint8_t) up through Rust FFI, a JSC host function, and a bun:internal-for-testing export so the new test can assert the stored value without waiting ~255s.
Security risks
None. The fix narrows behavior (negatives now disable the timeout instead of setting 255s). The new getter is read-only, returns a u8 widened to i32, and is only reachable via bun:internal-for-testing which is gated to debug builds / Bun CI.
Level of scrutiny
Low–medium. The core fix is mechanical and mirrors an already-correct sibling; the test plumbing follows the established uws_res_* shim pattern (compare adjacent uws_res_timeout/uws_res_reset_timeout) and the `` / internal-for-testing conventions used throughout the file. None of the touched paths match CODEOWNERS.
Other factors
The added test covers negatives, zero, in-range, boundary (254/255/256), and huge inputs, and the PR description shows it failing on the old code and passing on the new. No outstanding reviewer comments and no bugs were flagged by the bug-hunting pass.
|
CI status: the diff is green. Across both builds (#62443 and the retrigger #62573), 280+ lanes passed including the new
None of these touch |
|
Stale PR review: closing. This PR has had no human activity since 2026-06-15 and conflicts with main. The function it fixes no longer exists: #32488 (merged 2026-07-16) changed On current main, Reopen if this evidence is wrong. |
Problem
NodeHTTPResponse__setTimeout(the Rust port ofNodeHTTPResponse.zig:1165) computed the seconds value as:For negative inputs this bit-reinterprets the signed i32 as a large unsigned value before clamping, so e.g.
-1becomes4294967295which then clamps to255. The Zig reference routes throughJSValue.toU32, which clamps negatives to0and saturates atu32::MAX:The sibling
Request__setTimeoutinsrc/runtime/webcore/Request.rswas already ported correctly withseconds.to_u32()and carries a comment calling out exactly this hazard; this site was missed.Reachable from
node:httpviaIncomingMessage.prototype.setTimeout(msecs)on a server-side request:_http_incoming.tscallssetRequestTimeout(req, Math.ceil(msecs / 1000)), which dispatches toNodeHTTPResponse__setTimeoutwhen the underlying handle is aNodeHTTPResponse. Soreq.setTimeout(-1000)silently set a 255-second idle timeout instead of disabling it (0).Fix
Use
seconds.to_u32().min(255), matching both the Zig reference andRequest__setTimeout.Verification
The 0-vs-255 difference is only externally observable after ~255 seconds (uSockets
timeout(0)disables the idle timeout;timeout(255)fires after ~256s), so abun:internal-for-testinghook was added that reads backHttpResponseData::idleTimeoutfrom the underlying uWS response. The new test attest/js/node/http/node-http-req-settimeout-clamp.test.tsasserts the stored value for a matrix of inputs.With the buggy conversion in place (getter kept, fix reverted):
With the fix, all cases match the Zig reference semantics.