1818
1919const std = @import ("std" );
2020const Notification = @import ("../../notification.zig" ).Notification ;
21+ const log = @import ("../../log.zig" );
2122
2223const Allocator = std .mem .Allocator ;
2324
@@ -26,12 +27,14 @@ pub fn processMessage(cmd: anytype) !void {
2627 enable ,
2728 disable ,
2829 setCacheDisabled ,
30+ setExtraHTTPHeaders ,
2931 }, cmd .input .action ) orelse return error .UnknownMethod ;
3032
3133 switch (action ) {
3234 .enable = > return enable (cmd ),
3335 .disable = > return disable (cmd ),
3436 .setCacheDisabled = > return cmd .sendResult (null , .{}),
37+ .setExtraHTTPHeaders = > return setExtraHTTPHeaders (cmd ),
3538 }
3639}
3740
@@ -47,6 +50,27 @@ fn disable(cmd: anytype) !void {
4750 return cmd .sendResult (null , .{});
4851}
4952
53+ fn setExtraHTTPHeaders (cmd : anytype ) ! void {
54+ const params = (try cmd .params (struct {
55+ headers : std .json .ArrayHashMap ([]const u8 ),
56+ })) orelse return error .InvalidParams ;
57+
58+ const bc = cmd .browser_context orelse return error .BrowserContextNotLoaded ;
59+
60+ // Copy the headers onto the browser context arena
61+ const arena = bc .arena ;
62+ const extra_headers = & bc .cdp .extra_headers ;
63+
64+ extra_headers .clearRetainingCapacity ();
65+ try extra_headers .ensureTotalCapacity (arena , params .headers .map .count ());
66+ var it = params .headers .map .iterator ();
67+ while (it .next ()) | header | {
68+ extra_headers .appendAssumeCapacity (.{ .name = try arena .dupe (u8 , header .key_ptr .* ), .value = try arena .dupe (u8 , header .value_ptr .* ) });
69+ }
70+
71+ return cmd .sendResult (null , .{});
72+ }
73+
5074pub fn httpRequestStart (arena : Allocator , bc : anytype , request : * const Notification.RequestStart ) ! void {
5175 // Isn't possible to do a network request within a Browser (which our
5276 // notification is tied to), without a page.
@@ -59,6 +83,21 @@ pub fn httpRequestStart(arena: Allocator, bc: anytype, request: *const Notificat
5983 const target_id = bc .target_id orelse unreachable ;
6084 const page = bc .session .currentPage () orelse unreachable ;
6185
86+ // Modify request with extra CDP headers
87+ const original_len = request .headers .items .len ;
88+ try request .headers .ensureTotalCapacity (arena , original_len + cdp .extra_headers .items .len );
89+ outer : for (cdp .extra_headers .items ) | extra | {
90+ for (request .headers .items [0.. original_len ]) | * existing_header | {
91+ if (std .mem .eql (u8 , existing_header .name , extra .name )) {
92+ // If the header already exists, we overwrite it
93+ log .debug (.cdp , "request header overwritten" , .{ .name = extra .name });
94+ existing_header .value = extra .value ;
95+ continue :outer ;
96+ }
97+ }
98+ request .headers .appendAssumeCapacity (extra );
99+ }
100+
62101 const document_url = try urlToString (arena , & page .url .uri , .{
63102 .scheme = true ,
64103 .authentication = true ,
@@ -80,8 +119,8 @@ pub fn httpRequestStart(arena: Allocator, bc: anytype, request: *const Notificat
80119 });
81120
82121 var headers : std .StringArrayHashMapUnmanaged ([]const u8 ) = .empty ;
83- try headers .ensureTotalCapacity (arena , request .headers .len );
84- for (request .headers ) | header | {
122+ try headers .ensureTotalCapacity (arena , request .headers .items . len );
123+ for (request .headers . items ) | header | {
85124 headers .putAssumeCapacity (header .name , header .value );
86125 }
87126
@@ -129,13 +168,13 @@ pub fn httpRequestComplete(arena: Allocator, bc: anytype, request: *const Notifi
129168 // We're missing a bunch of fields, but, for now, this seems like enough
130169 try cdp .sendEvent ("Network.responseReceived" , .{
131170 .requestId = try std .fmt .allocPrint (arena , "REQ-{d}" , .{request .id }),
132- .frameId = target_id ,
133171 .loaderId = bc .loader_id ,
134172 .response = .{
135173 .url = url ,
136174 .status = request .status ,
137175 .headers = std .json .ArrayHashMap ([]const u8 ){ .map = headers },
138176 },
177+ .frameId = target_id ,
139178 }, .{ .session_id = session_id });
140179}
141180
@@ -144,3 +183,26 @@ fn urlToString(arena: Allocator, url: *const std.Uri, opts: std.Uri.WriteToStrea
144183 try url .writeToStream (opts , buf .writer (arena ));
145184 return buf .items ;
146185}
186+
187+ const testing = @import ("../testing.zig" );
188+ test "cdp.network setExtraHTTPHeaders" {
189+ var ctx = testing .context ();
190+ defer ctx .deinit ();
191+
192+ // _ = try ctx.loadBrowserContext(.{ .id = "NID-A", .session_id = "NESI-A" });
193+ try ctx .processMessage (.{ .id = 10 , .method = "Target.createTarget" , .params = .{ .url = "about/blank" } });
194+
195+ try ctx .processMessage (.{
196+ .id = 3 ,
197+ .method = "Network.setExtraHTTPHeaders" ,
198+ .params = .{ .headers = .{ .foo = "bar" } },
199+ });
200+
201+ try ctx .processMessage (.{
202+ .id = 4 ,
203+ .method = "Network.setExtraHTTPHeaders" ,
204+ .params = .{ .headers = .{ .food = "bars" } },
205+ });
206+
207+ try testing .expectEqual (ctx .cdp_ .? .browser_context .? .cdp .extra_headers .items .len , 1 );
208+ }
0 commit comments