Skip to content

fetch: make the idle timer an absolute deadline for the response header block - #36145

Merged
Jarred-Sumner merged 6 commits into
mainfrom
farm/93de5ad2/fetch-headers-absolute-timeout
Jul 30, 2026
Merged

Jarred-Sumner merged 6 commits into
mainfrom
farm/93de5ad2/fetch-headers-absolute-timeout

Conversation

@robobun

@robobun robobun commented Jul 27, 2026 •

Copy link
Copy Markdown
Collaborator

A server that trickles one response-header byte at a time, each interval shorter than the request's idle timeout, can keep a fetch() alive indefinitely. The HTTP client re-arms its socket idle timer inside the short_read! path of handle_on_data_headers, so every dripped byte resets the clock. A fully silent stall in the same phase is already bounded by the same timer (armed at on_open); only the drip defeats it.

Reproduction

import net from "net";
const FULL = "HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nok";
const server = net.createServer(sock => {
  sock.on("data", () => {});
  let i = 0;
  const iv = setInterval(() => {
    if (sock.destroyed) return clearInterval(iv);
    if (i < 10) sock.write(FULL[i++]);
    else { clearInterval(iv); sock.end(FULL.slice(i)); }
  }, 2000);
});
await new Promise(r => server.listen(0, "127.0.0.1", r));
await fetch(`http://127.0.0.1:${server.address().port}/`, { timeout: 5000 });
// 1.4.0-canary: resolves 200 after ~22s. With this change: TimeoutError at ~5-9s.

The same shape with no bytes written (silent stall) already rejects with TimeoutError: The operation timed out. on the existing build, so AbortSignal.timeout() is the only way to bound the drip case today.

Change

  • Drop the set_timeout call from short_read! in handle_on_data_headers. The timer stays as armed by on_open / on_writable, so it is an absolute deadline for the header block (undici headersTimeout semantics).
  • Gate the proxy-tunnel on_data re-arm on response_stage == Body | BodyChunk, mirroring the non-proxy dispatch, so the same deadline holds for HTTPS through a CONNECT proxy.
  • Re-arm once right after handle_response_metadata succeeds so the body phase starts with a fresh idle window rather than whatever was left of the header deadline (folded from fetch: make the response-header phase an absolute deadline #36146). Body reads continue to re-arm per chunk (undici bodyTimeout semantics).
  • Update the IDLE_TIMEOUT_SECONDS doc comment to describe the new header-phase behaviour.

The default deadline is unchanged (300 s / BUN_CONFIG_HTTP_IDLE_TIMEOUT / per-request timeout), and {timeout: false} still disables it.

Verification

New test in test/js/web/fetch/fetch.test.ts: a raw net.Server drips 10 header bytes at 2 s each against {timeout: 5000} and must reject with TimeoutError, then drips a 5-byte body after a burst header block and must resolve with 200.

$ USE_SYSTEM_BUN=1 bun test test/js/web/fetch/fetch.test.ts -t "absolute deadline"
(fail)  header drip resolves {status: 200, body: "hello"} after 22011 ms

$ bun bd test test/js/web/fetch/fetch.test.ts -t "absolute deadline"
(pass)  [18250 ms]

bun-install-stalled-tls.test.ts, fetch-keepalive.test.ts, the adjacent "explicit numeric `timeout` extends the socket idle deadline" test, and proxy.test.ts / proxy-stress-lifecycle.test.ts / proxy-stress-matrix.test.ts (496 proxy tests total, including the trickled-tunnel-bytes cases) all pass on the debug build.

Scope

HTTP/1 only. Related: #33338 adds connectTimeout / socketTimeout / whole-request timeout as per-request options with no change to the header-phase re-arm; this change is independent and composes with it. A headersTimeout option distinct from the body-phase idle value can follow once the per-request plumbing in #33338 lands.


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/web/fetch/fetch.test.ts

…er block

The HTTP client re-armed its socket idle timer on every partial header
read (the short_read! path in handle_on_data_headers), so a server that
trickled one header byte per interval shorter than the configured idle
timeout could keep a request alive indefinitely. A silent stall in the
same phase was already bounded; only the drip defeated it.

Stop re-arming on a partial header read. The timer stays as armed by
on_open / on_writable (the last outbound write), which turns it into an
absolute deadline for the header block to complete, matching undici's
headersTimeout semantics. The body path continues to re-arm per chunk
(undici bodyTimeout semantics), so a slow-but-steady body is still
accepted.
@robobun

robobun commented Jul 27, 2026 •

Copy link
Copy Markdown
Collaborator Author

Reproduced with the net.Server drip in the PR body: release bun resolves 200 after ~22 s with {timeout: 5000}; debug build of this branch rejects with TimeoutError at ~8 s and the body-drip control still resolves. Now also covers the proxy-tunnel path (gated on body phase) and re-arms once at headers-complete so the body window starts fresh; 496 proxy tests plus the adjacent timeout tests pass. Drip test runs both cases concurrently (~8 s). Waiting on CI.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

HTTP idle-timeout behavior

Layer / File(s) Summary
Timeout phase rules
src/http/lib.rs
Header reads retain an absolute timeout, completed headers re-arm the timer for body processing, redundant body-chunk re-arming is removed, and proxy-tunneled responses re-arm only during body stages.
Fetch timeout regression coverage
test/js/web/fetch/fetch.test.ts
Adds tests for timing out during slowly dripped headers and succeeding when headers arrive together before a slowly dripped body.

Suggested reviewers: jarred-sumner

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: making the fetch idle timer an absolute deadline for response headers.
Description check ✅ Passed The description covers what changed and how it was verified, even though it uses different headings than the template.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Found 1 issue this PR may fix:

  1. HTTPS requests hanging (regression 1.2.23 -> 1.3.x) #26066 - HTTP/1.1 fetch() calls hang indefinitely after many requests (regression in 1.3.x); the symptom pattern (request sent, no response, hangs until manual AbortSignal fires) is consistent with the idle timer being re-armed by trickling header bytes

If this is helpful, copy the block below into the PR description to auto-close this issue on merge.

Fixes #26066

🤖 Generated with Claude Code

@robobun

robobun commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator Author

Re #26066: I don't think this PR fixes it. That report describes requests to AWS that go silent after ~400-500 requests ("request is sent but no response is ever received"). A fully silent stall was already bounded by the 300 s idle timer before this change; the reporters are tripping a 30 s manual timeout first, so they never observe it, but it is there. This PR only changes the case where the server does send bytes during the header phase, just too slowly to ever complete, and there's no evidence AWS endpoints do that. #26066 reads more like a keep-alive pool / half-open socket problem. Leaving the description as-is.

Comment thread src/http/lib.rs Outdated
Comment thread src/http/lib.rs Outdated
@robobun

robobun commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator Author

Opened #36146 for the same bug a few minutes after this one; closing that in favor of this PR.

One difference worth considering: #36146 also re-arms the timer once right after handle_response_metadata succeeds (the headers-complete boundary). Without that, a response whose headers take most of the idle window and whose body then stalls silently gets whatever is left of the original timer instead of a fresh window; undici's bodyTimeout starts fresh at headers-complete. The diff is here if you want to fold it in.

The outer on_data re-armed the idle timer on every tunnelled byte before
decryption, so the header-phase absolute deadline did not hold for
HTTPS-through-CONNECT-proxy requests. Gate the re-arm on
response_stage == Body/BodyChunk, mirroring the non-proxy dispatch.

Also update the IDLE_TIMEOUT_SECONDS doc comment to match the new
header-phase semantics.
Comment thread src/http/lib.rs
Comment thread src/http/lib.rs Outdated
Comment thread src/http/lib.rs Outdated
@robobun

robobun commented Jul 27, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 4:03 PM PT - Jul 27th, 2026

✅ @robobun, your commit 97e21033b3ac22682523ed9de9a3d3a469b8d736 passed in Build #83625! 🎉


🧪   To try this PR locally:

bunx bun-pr 36145

That installs a local version of the PR into your bun-36145 executable, so you can run:

bun-36145 --bun

Comment thread src/http/lib.rs
Comment thread src/http/lib.rs
Gives the body phase a fresh idle window instead of whatever was left
of the header-phase deadline, matching undici where headersTimeout and
bodyTimeout are independent.

Folded from #36146.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional findings (outside current diff — PR may have been updated during review):

  • 🔴 src/http/lib.rs:3646-3649 — The idle timer is not re-armed at the headers→body boundary: after handle_response_metadata succeeds, both the to_read.is_empty() return (lib.rs:3770-3776) and the Body arm (3778-3790) proceed without a set_timeout, so a body that stalls right after headers-complete inherits only the remainder of the header-phase window instead of a fresh idle_timeout_seconds — undici starts bodyTimeout fresh at headers-complete, and the sibling BodyChunk arm at 3792 already re-arms, so this is internally inconsistent. This regresses the multi-chunk-header case (previously short_read! left the timer armed near headers-complete) and was raised in this thread via #36146 but not folded in; the fix is to call self.set_timeout(&socket) once right after clone_metadata.

    Extended reasoning...

    What the bug is

    This PR removes the set_timeout call from short_read! so the idle timer becomes an absolute deadline for the response header block. That is correct for the header phase, but the timer is never re-armed at the point where the header phase ends and the body phase begins. The PR's new comment (and the updated doc on IDLE_TIMEOUT_SECONDS) claims "undici headersTimeout semantics" with the body path re-arming per chunk — but undici also starts a fresh bodyTimeout window when headers complete, and this change does not.

    Code path

    In handle_on_data_headers, once handle_response_metadata succeeds and response_stage transitions to Body/BodyChunk:

    • to_read.is_empty() (lib.rs:3770-3776): returns after clone_metadata with no set_timeout. If the server then goes silent, the request times out with only the remainder of the window that was armed at on_writable, not a fresh idle_timeout_seconds.
    • Body arm (3778-3790): calls handle_response_body(to_read, true) with no preceding set_timeout (and handle_response_body does not re-arm internally).
    • BodyChunk arm (3791-3792): does call self.set_timeout(&socket) before handle_response_body_chunked_encoding.

    The Body and BodyChunk arms are siblings handling the same transition, and only one of them re-arms — that internal inconsistency alone signals this is unintentional. Subsequent body bytes do re-arm via the on_data Body/BodyChunk arms, so this only bites when the body stalls immediately after headers-complete.

    Why this is a regression

    Before this PR, short_read! re-armed on every partial header read. So when headers arrived over multiple on_data calls, the timer was left armed at the last partial-header read — i.e. very close to headers-complete. A subsequent silent body stall then had roughly a full idle_timeout_seconds before firing. After this PR, the timer stays as armed at on_writable (t≈0), so the body's first-stall window shrinks to idle_timeout_seconds − header_arrival_time.

    Step-by-step proof

    Take {timeout: 5000} against a server that drips the header block one byte at a time over 4 s (chunks at t=0.5, 1.0, …, 4.0 s; the t=4.0 s chunk completes the headers with no trailing body bytes), then stalls before sending the first body byte until t=8 s.

    • Before this PR: each partial-header on_data at t=0.5…3.5 s calls short_read!, which re-arms the timer. At t=3.5 s the timer is freshly armed. The t=4.0 s chunk completes the headers; to_read.is_empty() returns without re-arming, but the timer is still armed from t=3.5 s. It would fire at ~t=8.5 s (plus the 4 s tick slop), so the body byte at t=8 s arrives in time and the request succeeds.
    • After this PR: short_read! no longer re-arms. The timer stays as armed by on_writable at t≈0 s and fires at ~t=5-9 s. The body byte at t=8 s is likely past the deadline; the request fails with TimeoutError where it previously succeeded.

    For Content-Length bodies this always applies (the Body arm never re-arms at the transition); for chunked bodies it applies only when the header-completing packet carried no trailing bytes (the BodyChunk arm at 3792 re-arms when it does).

    Impact and prior notice

    This was explicitly raised in the PR thread by robobun on 2026-07-27 ("#36146 also re-arms the timer once right after handle_response_metadata succeeds … undici's bodyTimeout starts fresh at headers-complete"). The follow-up commit b278169 addressed the proxy-tunnel gate and the IDLE_TIMEOUT_SECONDS doc comment but did not fold this in. Per REVIEW.md "Fix the whole class in the same PR", the header-phase and body-phase timer semantics are one concern, and the updated doc comment now over-claims ("body-phase reads re-arm") for the first body window.

    Suggested fix

    Call self.set_timeout(&socket) once immediately after self.clone_metadata(&response) (i.e. right after handle_response_metadata returns Continue and the stage has transitioned to Body/BodyChunk). That gives the body a fresh idle_timeout_seconds window at headers-complete, matches undici's bodyTimeout start point, and makes the Body and BodyChunk arms consistent (the explicit set_timeout at 3792 can then be dropped).

Comment thread test/js/web/fetch/fetch.test.ts Outdated
The headers-complete re-arm in 94b065e made the BodyChunk-arm set_timeout
in handle_on_data_headers redundant (same value, same on_data call).

Drip test: run /h and /b concurrently and shrink the body to 3 bytes so
wall-clock drops from ~18s to ~8s.
@robobun

robobun commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator Author

Re the headers→body boundary re-arm: that was folded in at 94b065e (one set_timeout right after handle_response_metadata returns), which landed just before the review comment posted. 7869e08 additionally drops the now-redundant set_timeout in the BodyChunk arm of handle_on_data_headers, so Body and BodyChunk are now consistent: both get a fresh window at headers-complete and neither re-arms a second time in the same on_data.

Comment thread src/http/lib.rs
Comment thread src/http/lib.rs
… on_data

maybe_pause_receive early-returns when proxy_tunnel.is_some(), so
receive_paused is never true inside the proxy on_data branch. Document
the invariant with a debug_assert instead of a conjunct that can never
be false.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 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 `@src/http/lib.rs`:
- Around line 3822-3830: Add a test covering the proxy_tunnel entry point with
HTTPS sent through a CONNECT proxy, using both header-drip and body-drip
behavior to exercise the ResponseStage::Body | BodyChunk timeout gate. Keep the
existing direct HTTP coverage and ensure the new case validates timeout behavior
for the CONNECT tunnel path.

In `@test/js/web/fetch/fetch.test.ts`:
- Around line 3092-3098: Update the sock.once("data") request-handling logic to
accumulate incoming bytes until the HTTP header terminator is received, rather
than determining headerDrip from the first chunk. Parse the framed request
target with the repository’s real HTTP parser, then select the /h or /b fixture
mode from that parsed target while preserving the existing response-drip
behavior.
- Line 3117: Update the server setup promise around server.listen in the fetch
test so it rejects when the server emits an error, while still resolving from
the successful listen callback. Wire the server's failure event to the promise
rejection before starting the listener, preserving the existing host and port
behavior.
🪄 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: 0ad52fb7-827b-4ccd-967b-9ebcbbe626d3

📥 Commits

Reviewing files that changed from the base of the PR and between 4eb6f99 and 97e2103.

📒 Files selected for processing (2)
  • src/http/lib.rs
  • test/js/web/fetch/fetch.test.ts

Comment thread src/http/lib.rs
Comment thread test/js/web/fetch/fetch.test.ts
Comment thread test/js/web/fetch/fetch.test.ts

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No bugs found this pass. This is a small but user-visible behavioral change to fetch() timeout semantics on the HTTP/1 client hot path (header-phase reads no longer re-arm the idle timer), so it's worth a human look before landing.

Checked this round: the headers-complete re-arm at lib.rs:3731 correctly covers both direct and CONNECT-tunnel dispatch (ProxyTunnel.rs:345/349 pass the real outer socket); the 100-Continue early return at :3715 was never a short_read! path so no regression there; the proxy-tunnel debug_assert!(!receive_paused) holds because maybe_pause_receive bails on proxy_tunnel.is_some(); the removed BodyChunk-arm re-arm is fully subsumed by :3731.

Extended reasoning...

Overview

Removes set_timeout from the short_read! macro in handle_on_data_headers so partial response-header reads no longer reset the socket idle timer. Adds a single re-arm at headers-complete (right after handle_response_metadata returns Ok) so the body phase starts with a fresh window, drops the now-redundant re-arm in the piggybacked BodyChunk arm, and gates the proxy-tunnel on_data re-arm on response_stage == Body | BodyChunk (with a debug_assert! documenting that receive_paused cannot be set on the tunnel path). Updates the IDLE_TIMEOUT_SECONDS doc comment. New ~8s test in fetch.test.ts proves a header drip now hits TimeoutError while a body drip still resolves 200.

Security risks

None introduced. If anything this is a client-side hardening: a hostile or misbehaving server can no longer hold a Bun fetch() open indefinitely by trickling one header byte per interval. No new input parsing, no allocation sizing on untrusted data, no auth/crypto surface.

Level of scrutiny

Medium-high. src/http/lib.rs on_data / handle_on_data_headers is the HTTP/1 client hot path used by every fetch(), bun install, etc. The diff is small and mechanically simple, but it changes user-visible timing semantics: a server that previously kept a request alive by dripping header bytes will now time out after the idle window (default 300 s / BUN_CONFIG_HTTP_IDLE_TIMEOUT / per-request timeout). That matches undici's headersTimeout, and {timeout: false} still opts out, but a human should sign off on the semantic shift.

Other factors

Four prior review rounds on this PR have already been folded in (doc comment sync, comment length, test wall-clock 18s→8s via concurrent cases + 3-byte body, dead BodyChunk-arm re-arm dropped, dead receive_paused conjunct replaced with debug_assert!). The author gave a reasonable explanation for not adding a dedicated test for the :3731 re-arm (uSockets' 4 s sweep tick makes the delta phase-dependent and non-deterministic under ~12 s), and reasonably declined CodeRabbit's three suggestions with reference to existing suite conventions. CI build #83625 is in flight.

@Jarred-Sumner
Jarred-Sumner merged commit 5b82486 into main Jul 30, 2026
53 checks passed
@Jarred-Sumner
Jarred-Sumner deleted the farm/93de5ad2/fetch-headers-absolute-timeout branch July 30, 2026 02:04
hughescr added a commit to hughescr/bun that referenced this pull request Jul 31, 2026
* upstream/main: (422 commits)
  install: drop packages held only by optional-peer resolution slots from bun.lock (oven-sh#35681)
  Update mimalloc to the upstream dev3 (v3.4.3) sync (oven-sh#36431)
  compile(pe): ftruncate the Windows --compile output after writing (oven-sh#36430)
  Strong: back bun_jsc::Strong with StrongRootBlock; free AbortSignal.timeout at wrapper GC (oven-sh#35849)
  test(harness): replace toRun matcher with async bunRun + toSpawn (oven-sh#36424)
  test: measure memory via harness rss() instead of process.memoryUsage.rss() (oven-sh#36429)
  Deflake a few tests
  no-orphans(windows): allow CREATE_BREAKAWAY_FROM_JOB and set DIE_ON_UNHANDLED_EXCEPTION on the Job (oven-sh#36414)
  GarbageCollectionController: replace per-tick heap sampler with idle timer only (oven-sh#35356)
  exe_format(pe): write a valid OptionalHeader.CheckSum for --compile output (oven-sh#36383)
  FileSink: flush buffered bytes when process.exit() runs in the same tick as write() (oven-sh#36250)
  test(http): speed up and de-flake serve-async-stream-client-abort.test.ts (oven-sh#35919)
  test(20144): stop racing child startup against the 1s SIGKILL guard (oven-sh#34166)
  test(no-orphans): skip fast-exit perl daemon test on macOS (oven-sh#36413)
  fs: return negative BigIntStats *Ns for pre-epoch timestamps (oven-sh#36187)
  event_loop: make DeferredTaskQueue::run tolerate re-entrant map mutation (oven-sh#32703)
  dotenv: stop panicking on nested `${...}` inside `${VAR:-default}` (oven-sh#36199)
  fetch: make the idle timer an absolute deadline for the response header block (oven-sh#36145)
  bundler: don't panic on unterminated naming template placeholders (oven-sh#36325)
  Buffer#indexOf/lastIndexOf: rare-byte SIMD filter with a Two-Way O(n+m) fallback (oven-sh#36420)
  ...

# Conflicts:
#	src/jsc/bindings/BunDebugger.cpp
hughescr added a commit to hughescr/bun that referenced this pull request Jul 31, 2026
* upstream/main: (422 commits)
  install: drop packages held only by optional-peer resolution slots from bun.lock (oven-sh#35681)
  Update mimalloc to the upstream dev3 (v3.4.3) sync (oven-sh#36431)
  compile(pe): ftruncate the Windows --compile output after writing (oven-sh#36430)
  Strong: back bun_jsc::Strong with StrongRootBlock; free AbortSignal.timeout at wrapper GC (oven-sh#35849)
  test(harness): replace toRun matcher with async bunRun + toSpawn (oven-sh#36424)
  test: measure memory via harness rss() instead of process.memoryUsage.rss() (oven-sh#36429)
  Deflake a few tests
  no-orphans(windows): allow CREATE_BREAKAWAY_FROM_JOB and set DIE_ON_UNHANDLED_EXCEPTION on the Job (oven-sh#36414)
  GarbageCollectionController: replace per-tick heap sampler with idle timer only (oven-sh#35356)
  exe_format(pe): write a valid OptionalHeader.CheckSum for --compile output (oven-sh#36383)
  FileSink: flush buffered bytes when process.exit() runs in the same tick as write() (oven-sh#36250)
  test(http): speed up and de-flake serve-async-stream-client-abort.test.ts (oven-sh#35919)
  test(20144): stop racing child startup against the 1s SIGKILL guard (oven-sh#34166)
  test(no-orphans): skip fast-exit perl daemon test on macOS (oven-sh#36413)
  fs: return negative BigIntStats *Ns for pre-epoch timestamps (oven-sh#36187)
  event_loop: make DeferredTaskQueue::run tolerate re-entrant map mutation (oven-sh#32703)
  dotenv: stop panicking on nested `${...}` inside `${VAR:-default}` (oven-sh#36199)
  fetch: make the idle timer an absolute deadline for the response header block (oven-sh#36145)
  bundler: don't panic on unterminated naming template placeholders (oven-sh#36325)
  Buffer#indexOf/lastIndexOf: rare-byte SIMD filter with a Two-Way O(n+m) fallback (oven-sh#36420)
  ...
hughescr added a commit to hughescr/bun that referenced this pull request Jul 31, 2026
* upstream/main: (422 commits)
  install: drop packages held only by optional-peer resolution slots from bun.lock (oven-sh#35681)
  Update mimalloc to the upstream dev3 (v3.4.3) sync (oven-sh#36431)
  compile(pe): ftruncate the Windows --compile output after writing (oven-sh#36430)
  Strong: back bun_jsc::Strong with StrongRootBlock; free AbortSignal.timeout at wrapper GC (oven-sh#35849)
  test(harness): replace toRun matcher with async bunRun + toSpawn (oven-sh#36424)
  test: measure memory via harness rss() instead of process.memoryUsage.rss() (oven-sh#36429)
  Deflake a few tests
  no-orphans(windows): allow CREATE_BREAKAWAY_FROM_JOB and set DIE_ON_UNHANDLED_EXCEPTION on the Job (oven-sh#36414)
  GarbageCollectionController: replace per-tick heap sampler with idle timer only (oven-sh#35356)
  exe_format(pe): write a valid OptionalHeader.CheckSum for --compile output (oven-sh#36383)
  FileSink: flush buffered bytes when process.exit() runs in the same tick as write() (oven-sh#36250)
  test(http): speed up and de-flake serve-async-stream-client-abort.test.ts (oven-sh#35919)
  test(20144): stop racing child startup against the 1s SIGKILL guard (oven-sh#34166)
  test(no-orphans): skip fast-exit perl daemon test on macOS (oven-sh#36413)
  fs: return negative BigIntStats *Ns for pre-epoch timestamps (oven-sh#36187)
  event_loop: make DeferredTaskQueue::run tolerate re-entrant map mutation (oven-sh#32703)
  dotenv: stop panicking on nested `${...}` inside `${VAR:-default}` (oven-sh#36199)
  fetch: make the idle timer an absolute deadline for the response header block (oven-sh#36145)
  bundler: don't panic on unterminated naming template placeholders (oven-sh#36325)
  Buffer#indexOf/lastIndexOf: rare-byte SIMD filter with a Two-Way O(n+m) fallback (oven-sh#36420)
  ...

# Conflicts:
#	src/js/internal/debugger.ts
hughescr added a commit to hughescr/bun that referenced this pull request Jul 31, 2026
* upstream/main: (422 commits)
  install: drop packages held only by optional-peer resolution slots from bun.lock (oven-sh#35681)
  Update mimalloc to the upstream dev3 (v3.4.3) sync (oven-sh#36431)
  compile(pe): ftruncate the Windows --compile output after writing (oven-sh#36430)
  Strong: back bun_jsc::Strong with StrongRootBlock; free AbortSignal.timeout at wrapper GC (oven-sh#35849)
  test(harness): replace toRun matcher with async bunRun + toSpawn (oven-sh#36424)
  test: measure memory via harness rss() instead of process.memoryUsage.rss() (oven-sh#36429)
  Deflake a few tests
  no-orphans(windows): allow CREATE_BREAKAWAY_FROM_JOB and set DIE_ON_UNHANDLED_EXCEPTION on the Job (oven-sh#36414)
  GarbageCollectionController: replace per-tick heap sampler with idle timer only (oven-sh#35356)
  exe_format(pe): write a valid OptionalHeader.CheckSum for --compile output (oven-sh#36383)
  FileSink: flush buffered bytes when process.exit() runs in the same tick as write() (oven-sh#36250)
  test(http): speed up and de-flake serve-async-stream-client-abort.test.ts (oven-sh#35919)
  test(20144): stop racing child startup against the 1s SIGKILL guard (oven-sh#34166)
  test(no-orphans): skip fast-exit perl daemon test on macOS (oven-sh#36413)
  fs: return negative BigIntStats *Ns for pre-epoch timestamps (oven-sh#36187)
  event_loop: make DeferredTaskQueue::run tolerate re-entrant map mutation (oven-sh#32703)
  dotenv: stop panicking on nested `${...}` inside `${VAR:-default}` (oven-sh#36199)
  fetch: make the idle timer an absolute deadline for the response header block (oven-sh#36145)
  bundler: don't panic on unterminated naming template placeholders (oven-sh#36325)
  Buffer#indexOf/lastIndexOf: rare-byte SIMD filter with a Two-Way O(n+m) fallback (oven-sh#36420)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants