From 492fd86badb3e80a4fae406131039957597d45a2 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Tue, 31 Mar 2026 16:46:31 +0800 Subject: [PATCH 1/3] Expand the lifetime of the XHR reference We need to take the self-reference to the XHR object as soon as the request is made. Previously, we were waiting until we got the start callback, but v8 could (and does) drop the reference before that happens. Unfortunately, that means we can no longer use _transfer == null to tell if we own a reference or not, so a new boolean was added. --- src/browser/webapi/net/XMLHttpRequest.zig | 16 +++++++++++++--- src/lightpanda.zig | 4 ++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/browser/webapi/net/XMLHttpRequest.zig b/src/browser/webapi/net/XMLHttpRequest.zig index 22587347..1572ebad 100644 --- a/src/browser/webapi/net/XMLHttpRequest.zig +++ b/src/browser/webapi/net/XMLHttpRequest.zig @@ -44,6 +44,7 @@ _page: *Page, _proto: *XMLHttpRequestEventTarget, _arena: Allocator, _transfer: ?*HttpClient.Transfer = null, +_has_ref: bool = false, _url: [:0]const u8 = "", _method: net_http.Method = .GET, @@ -136,6 +137,14 @@ pub fn deinit(self: *XMLHttpRequest, session: *Session) void { session.releaseArena(self._arena); } +fn releaseSelfRef(self: *XMLHttpRequest) void { + if (self._has_ref == false) { + return; + } + self.releaseRef(self._page._session); + self._has_ref = false; +} + pub fn releaseRef(self: *XMLHttpRequest, session: *Session) void { self._rc.release(self, session); } @@ -252,6 +261,8 @@ pub fn send(self: *XMLHttpRequest, body_: ?[]const u8) !void { .error_callback = httpErrorCallback, .shutdown_callback = httpShutdownCallback, }); + self.acquireRef(); + self._has_ref = true; } fn handleBlobUrl(self: *XMLHttpRequest, page: *Page) !void { @@ -393,7 +404,6 @@ fn httpStartCallback(transfer: *HttpClient.Transfer) !void { log.debug(.http, "request start", .{ .method = self._method, .url = self._url, .source = "xhr" }); } self._transfer = transfer; - self.acquireRef(); } fn httpHeaderCallback(transfer: *HttpClient.Transfer, header: net_http.Header) !void { @@ -501,8 +511,8 @@ fn httpErrorCallback(ctx: *anyopaque, err: anyerror) void { self.handleError(err); if (self._transfer != null) { self._transfer = null; - self.releaseRef(self._page._session); } + self.releaseSelfRef(); } fn httpShutdownCallback(ctx: *anyopaque) void { @@ -515,8 +525,8 @@ pub fn abort(self: *XMLHttpRequest) void { if (self._transfer) |transfer| { self._transfer = null; transfer.abort(error.Abort); - self.releaseRef(self._page._session); } + self.releaseSelfRef(); } fn handleError(self: *XMLHttpRequest, err: anyerror) void { diff --git a/src/lightpanda.zig b/src/lightpanda.zig index 36213624..7f202855 100644 --- a/src/lightpanda.zig +++ b/src/lightpanda.zig @@ -237,6 +237,10 @@ pub fn RC(comptime T: type) type { session.releaseArena(kv.value.arena); } } + + pub fn format(self: @This(), writer: *std.Io.Writer) !void { + return writer.print("{d}", .{self._refs}); + } }; } From 97161505303bf41b2e58a01e1848d60ccc342f42 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Tue, 31 Mar 2026 19:15:01 +0800 Subject: [PATCH 2/3] rename has_ref -> active_request --- src/browser/webapi/net/XMLHttpRequest.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/browser/webapi/net/XMLHttpRequest.zig b/src/browser/webapi/net/XMLHttpRequest.zig index 1572ebad..e5c70922 100644 --- a/src/browser/webapi/net/XMLHttpRequest.zig +++ b/src/browser/webapi/net/XMLHttpRequest.zig @@ -44,7 +44,7 @@ _page: *Page, _proto: *XMLHttpRequestEventTarget, _arena: Allocator, _transfer: ?*HttpClient.Transfer = null, -_has_ref: bool = false, +_active_request: bool = false, _url: [:0]const u8 = "", _method: net_http.Method = .GET, @@ -138,11 +138,11 @@ pub fn deinit(self: *XMLHttpRequest, session: *Session) void { } fn releaseSelfRef(self: *XMLHttpRequest) void { - if (self._has_ref == false) { + if (self._active_request == false) { return; } self.releaseRef(self._page._session); - self._has_ref = false; + self._active_request = false; } pub fn releaseRef(self: *XMLHttpRequest, session: *Session) void { @@ -262,7 +262,7 @@ pub fn send(self: *XMLHttpRequest, body_: ?[]const u8) !void { .shutdown_callback = httpShutdownCallback, }); self.acquireRef(); - self._has_ref = true; + self._active_request = true; } fn handleBlobUrl(self: *XMLHttpRequest, page: *Page) !void { From 571c3463164993d2023cb9479e1d064e2b133cbc Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Tue, 31 Mar 2026 20:39:11 +0800 Subject: [PATCH 3/3] use releaseSelfRef on done just to be extra safe --- src/browser/webapi/net/XMLHttpRequest.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/webapi/net/XMLHttpRequest.zig b/src/browser/webapi/net/XMLHttpRequest.zig index e5c70922..5de311ad 100644 --- a/src/browser/webapi/net/XMLHttpRequest.zig +++ b/src/browser/webapi/net/XMLHttpRequest.zig @@ -502,7 +502,7 @@ fn httpDoneCallback(ctx: *anyopaque) !void { .loaded = loaded, }, page); - self.releaseRef(page._session); + self.releaseSelfRef(); } fn httpErrorCallback(ctx: *anyopaque, err: anyerror) void {