From 5432d19ef5ff8569d0d8de2bc309861f3f61892a Mon Sep 17 00:00:00 2001 From: Ppsoft1991 <18442117+Ppsoft1991@users.noreply.github.com> Date: Thu, 23 Jul 2026 17:57:08 +0800 Subject: [PATCH] cdp: make Network.enable idempotent Avoid registering the same BrowserContext notification callbacks more than once. Duplicate registrations emit duplicate Network events and append every response body chunk repeatedly. --- src/cdp/CDP.zig | 9 +++++++++ src/cdp/domains/network.zig | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/cdp/CDP.zig b/src/cdp/CDP.zig index 7cf27b991..4f45fdc19 100644 --- a/src/cdp/CDP.zig +++ b/src/cdp/CDP.zig @@ -573,6 +573,10 @@ pub const BrowserContext = struct { // Browser.setDownloadBehavior calls don't add duplicate listeners. download_events_registered: bool = false, + // True once we've registered for the network notifications, so repeated + // Network.enable calls don't add duplicate listeners. + network_events_registered: bool = false, + // Extra headers to add to all requests. extra_headers: std.ArrayList([*c]const u8) = .empty, @@ -808,12 +812,16 @@ pub const BrowserContext = struct { } pub fn networkEnable(self: *BrowserContext) !void { + if (self.network_events_registered) return; + errdefer self.networkDisable(); + try self.notification.register(.http_request_fail, self, onHttpRequestFail); try self.notification.register(.http_request_start, self, onHttpRequestStart); try self.notification.register(.http_request_done, self, onHttpRequestDone); try self.notification.register(.http_response_data, self, onHttpResponseData); try self.notification.register(.http_response_header_done, self, onHttpResponseHeadersDone); try self.notification.register(.http_request_served_from_cache, self, onHttpRequestServedFromCache); + self.network_events_registered = true; } pub fn networkDisable(self: *BrowserContext) void { @@ -823,6 +831,7 @@ pub const BrowserContext = struct { self.notification.unregister(.http_response_data, self); self.notification.unregister(.http_response_header_done, self); self.notification.unregister(.http_request_served_from_cache, self); + self.network_events_registered = false; } pub fn fetchEnable(self: *BrowserContext, authRequests: bool) !void { diff --git a/src/cdp/domains/network.zig b/src/cdp/domains/network.zig index 89db15679..a3d45402e 100644 --- a/src/cdp/domains/network.zig +++ b/src/cdp/domains/network.zig @@ -981,3 +981,35 @@ test "cdp.Network: configured CDP ignores setCacheDisabled" { try ctx.expectSentResult(null, .{ .id = 2 }); try testing.expect(client.cache == &cache); } + +test "cdp.Network: repeated enable does not duplicate captured response bodies" { + var ctx = try testing.context(); + defer ctx.deinit(); + + const cdp = ctx.cdp(); + _ = try cdp.createBrowserContext(); + var bc = &cdp.browser_context.?; + bc.id = "BID-NE"; + bc.session_id = "SID-NE"; + bc.target_id = "TID-NE-0000000".*; + + try ctx.processMessage(.{ .id = 1, .method = "Network.enable" }); + try ctx.processMessage(.{ .id = 2, .method = "Network.enable" }); + + const fixture_root = "http://127.0.0.1:9582/src/browser/tests/cdp/"; + const page = try bc.session.createPage(); + try page.navigate(fixture_root ++ "dom1.html", .{}); + try testing.waitForPage(bc); + + const expected = @embedFile("../../browser/tests/cdp/dom1.html"); + var matches: usize = 0; + var responses = bc.captured_responses.valueIterator(); + while (responses.next()) |response| { + if (std.mem.indexOf(u8, response.data.items, "
1
") == null) { + continue; + } + matches += 1; + try std.testing.expectEqualStrings(expected, response.data.items); + } + try testing.expectEqual(1, matches); +}