From fa66f0b509fc1290ef181ad81a8b2f4161e5dd28 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Sat, 31 Jan 2026 10:31:16 +0800 Subject: [PATCH] Don't release XHR object until request complete We previously figured that we could release the XHR object as soon as the JS reference was out of scope. But the callbacks could still exist and thus the XHR request should proceed. This commit ensures the XHR instance remains valid so long as we have an active request. Might help with https://github.com/lightpanda-io/browser/issues/1448 but I can't reliably reproduce this, so I'm not 100% sure it resolve the issue. That bug appears to be caused by some timing interaction between the underlying HTTP request and the v8 GC. --- src/browser/webapi/net/XMLHttpRequest.zig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/browser/webapi/net/XMLHttpRequest.zig b/src/browser/webapi/net/XMLHttpRequest.zig index dc75b6f7..7996abbd 100644 --- a/src/browser/webapi/net/XMLHttpRequest.zig +++ b/src/browser/webapi/net/XMLHttpRequest.zig @@ -213,6 +213,8 @@ pub fn send(self: *XMLHttpRequest, body_: ?[]const u8) !void { .done_callback = httpDoneCallback, .error_callback = httpErrorCallback, }); + + page.js.strongRef(self); } pub fn getReadyState(self: *const XMLHttpRequest) u32 { return @intFromEnum(self._ready_state); @@ -427,6 +429,8 @@ fn httpDoneCallback(ctx: *anyopaque) !void { .total = loaded, .loaded = loaded, }, local, page); + + page.js.weakRef(self); } fn httpErrorCallback(ctx: *anyopaque, err: anyerror) void { @@ -434,6 +438,7 @@ fn httpErrorCallback(ctx: *anyopaque, err: anyerror) void { // http client will close it after an error, it isn't safe to keep around self._transfer = null; self.handleError(err); + self._page.js.weakRef(self); } pub fn abort(self: *XMLHttpRequest) void { @@ -442,6 +447,7 @@ pub fn abort(self: *XMLHttpRequest) void { transfer.abort(error.Abort); self._transfer = null; } + self._page.js.weakRef(self); } fn handleError(self: *XMLHttpRequest, err: anyerror) void {