server: take StaticRoute, FileRoute, HTMLBundle and DirectoryRoute to zero unsafe
What
Same treatment as #40055 for the Bun.serve route objects: StaticRoute.rs 29 → 0, HTMLBundle.rs 24 → 0, FileRoute.rs 7 → 0, DirectoryRoute.rs 2 → 0 (plus −27 across ServerConfig.rs, mod.rs, server_body.rs, DevServer.rs, js_bundle_completion_task.rs), by fixing the layer underneath instead of annotating call sites:
- Typed uws userdata.
bun_uws_sysgetsAnyResponse::on_writable_this/on_aborted_thisandApp::method_this/any_this(H1 and H3): the registrant passes theThisPtr<U>it was dispatched with and keeps a ref while registered; the trampoline hands the handler aThisPtr<U>(the oneunsafeper trampoline lives there).ServerConfig's hand-written per-route trampolines are gone;StaticRouteLiketakesThisPtr<Self>. - Ownership.
AnyRoute::{Static,File,Directory,Html}holdRefPtr; constructors returnRefPtr;StaticRoute::cloneno longer needs&mut *ptr. The ref that in-flight responses hold on aStaticRouteis an explicitRefPtrtaken by the first outstanding response and released with the last (pending_responses), rather than a bareref_()whose matchingderef_trusted the userdata pointer.FileRoute/DirectoryRoutehandFileResponseStreamaStreamOwner::{FileRoute,DirectoryRoute}(RefPtr)instead of(ctx, fn, fn, fn);RequestContextkeeps the rawCtxform. - HTMLBundle.
PendingResponses are stored by value and found byAnyResponseequality on abort (userdata is the route); the build task owns aRefPtr<Route>released afteron_complete;State::Htmlholds aRefPtr<StaticRoute>;State::Buildingdrops its task pointer (the cancel-and-deref arm inState::deinitwas unreachable — the task's ref keeps the route alive while building — and would have double-released the enqueue ref if reached).Route::dropnow releases itsHTMLBundleref (theIntrusiveRcfield previously leaked it). JSBundleCompletionTask::new()+schedule(self)replacecreate_and_schedule_completion_task+ post-hoc raw field writes;poll_ref.ref_moves to just before enqueue.JSValue::as_class_this_ptr::<T>()sibling ofas_class_reffor refcountedm_ctxpayloads.
Testing
Debug+ASAN: every bun-serve-static* / bun-serve-html* test, bun-serve-routes, bun-serve-file, serve-directory-routes, serve-http3, test/bake/dev/html.test.ts pass; serve.test.ts 296/297 (the uid-0 privileged-port case fails in the sandbox regardless). Hand-driven under the debug binary: GET/HEAD/304 on a static route, full and aborted (AbortController + raw socket destroy) reads of a 2 MB static body, server.reload({routes}) mid-stream + GC, file route incl. HEAD/Range, HTML import route incl. concurrent requests, abort during build, reload, development: {hmr:false} — exit 0, no ASAN output. rust-check-all for windows-msvc / apple-darwin passes.