webapi: window.stop()

window.stop() is less destructive than other mechanisms we have. For one, it
seems largely isolated to pending or inflight HTTP requests. For anther, it
keeps the page intact.

To achieve this, HttpClient gains an `cancelRequests` which is a gentler version
of `abortOwner`. It cancels inflight/pending HTTP requests, which results in
error callbacks (not shutdown callbacks) firing.

Just like https://github.com/lightpanda-io/browser/pull/3189 I ran into the
problem that I couldn't distinguish between an HTTP request that was canceled
because of user-action (e.g. calling window.stop(), or xhr.abort()) and an HTTP
request that was internally aborted. These now have distinct errors/flows so
that we can present the correct state. Most places that aborted now all
transfer.cancel() which results in a distinct `error.TransferCanceled` (some
places still abort -> `error.Abort`). It should be possible to revisit 3189 now.

The CDP "Page.stopLoading" now hooks into this new behavior. Fixes
https://github.com/lightpanda-io/browser/issues/3351
This commit is contained in:
Karl Seguin committed 2026-09-01 14:55:19 +08:00
1 parent 053ea6aac0
commit 76c8f4bb6e
17 files changed
+311 -25

No files matched your search

+18
View File
@@ -865,6 +865,24 @@ fn testHTTPHandler(req: *std.http.Server.Request) !void {
});
}
if (std.mem.eql(u8, path, "/stop_loading/streaming.html")) {
var send_buffer: [1024]u8 = undefined;
var res = try req.respondStreaming(&send_buffer, .{
.respond_options = .{
.extra_headers = &.{
.{ .name = "Content-Type", .value = "text/html; charset=utf-8" },
},
},
});
try res.writer.writeAll("<html><body><p id=first>first</p>");
try res.writer.flush();
try res.flush();
lp.io.sleep(.fromMilliseconds(1500), .awake) catch {};
try res.writer.writeAll("<p id=second>second</p></body></html>");
try res.writer.flush();
return res.end();
}
if (std.mem.eql(u8, path, "/sse/streaming")) {
sse_flag.store(false, .release);
var send_buffer: [1024]u8 = undefined;