From b5eceb52fbb052b274f7d2ce39d0be4ad35f9662 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Tue, 2 Dec 2025 16:05:57 +0800 Subject: [PATCH] try safer http cleanup on page deinit --- src/browser/webapi/net/Fetch.zig | 7 +++++++ src/browser/webapi/net/XMLHttpRequest.zig | 7 +++++++ src/http/Client.zig | 11 ++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/browser/webapi/net/Fetch.zig b/src/browser/webapi/net/Fetch.zig index cea5a213..0f6c37f3 100644 --- a/src/browser/webapi/net/Fetch.zig +++ b/src/browser/webapi/net/Fetch.zig @@ -77,6 +77,13 @@ pub fn init(input: Input, options: ?RequestInit, page: *Page) !js.Promise { return fetch._resolver.promise(); } +pub fn deinit(self: *Fetch) void { + if (self.transfer) |transfer| { + transfer.abort(); + self.transfer = null; + } +} + fn httpHeaderDoneCallback(transfer: *Http.Transfer) !void { const self: *Fetch = @ptrCast(@alignCast(transfer.ctx)); diff --git a/src/browser/webapi/net/XMLHttpRequest.zig b/src/browser/webapi/net/XMLHttpRequest.zig index 3bb219e2..4b0cdb9f 100644 --- a/src/browser/webapi/net/XMLHttpRequest.zig +++ b/src/browser/webapi/net/XMLHttpRequest.zig @@ -74,6 +74,13 @@ pub fn init(page: *Page) !*XMLHttpRequest { }); } +pub fn deinit(self: *XMLHttpRequest) void { + if (self.transfer) |transfer| { + transfer.abort(); + self.transfer = null; + } +} + fn asEventTarget(self: *XMLHttpRequest) *EventTarget { return self._proto._proto; } diff --git a/src/http/Client.zig b/src/http/Client.zig index 65f31066..1a646ea0 100644 --- a/src/http/Client.zig +++ b/src/http/Client.zig @@ -153,7 +153,7 @@ pub fn abort(self: *Client) void { log.err(.http, "get private info", .{ .err = err, .source = "abort" }); continue; }; - transfer.abort(); + transfer.kill(); } std.debug.assert(self.active == 0); @@ -812,6 +812,15 @@ pub const Transfer = struct { self.deinit(); } + // internal, when the page is shutting down. Doesn't have the same ceremony + // as abort (doesn't send a notification, doesn't invoke an error callback) + fn kill(self: *Transfer) void { + if (self._handle != null) { + self.client.endTransfer(self); + } + self.deinit(); + } + // abortAuthChallenge is called when an auth chanllenge interception is // abort. We don't call self.client.endTransfer here b/c it has been done // before interception process.