18
18
19
19
const std = @import ("std" );
20
20
const Notification = @import ("../../notification.zig" ).Notification ;
21
+ const log = @import ("../../log.zig" );
21
22
22
23
const Allocator = std .mem .Allocator ;
23
24
@@ -26,12 +27,14 @@ pub fn processMessage(cmd: anytype) !void {
26
27
enable ,
27
28
disable ,
28
29
setCacheDisabled ,
30
+ setExtraHTTPHeaders ,
29
31
}, cmd .input .action ) orelse return error .UnknownMethod ;
30
32
31
33
switch (action ) {
32
34
.enable = > return enable (cmd ),
33
35
.disable = > return disable (cmd ),
34
36
.setCacheDisabled = > return cmd .sendResult (null , .{}),
37
+ .setExtraHTTPHeaders = > return setExtraHTTPHeaders (cmd ),
35
38
}
36
39
}
37
40
@@ -47,6 +50,40 @@ fn disable(cmd: anytype) !void {
47
50
return cmd .sendResult (null , .{});
48
51
}
49
52
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
+
74
+ // Upsert a header into the headers array.
75
+ // returns true if the header was added, false if it was updated
76
+ fn putAssumeCapacity (headers : * std .ArrayListUnmanaged (std.http.Header ), extra : std .http .Header ) bool {
77
+ for (headers .items ) | * header | {
78
+ if (std .mem .eql (u8 , header .name , extra .name )) {
79
+ header .value = extra .value ;
80
+ return false ;
81
+ }
82
+ }
83
+ headers .appendAssumeCapacity (extra );
84
+ return true ;
85
+ }
86
+
50
87
pub fn httpRequestStart (arena : Allocator , bc : anytype , request : * const Notification.RequestStart ) ! void {
51
88
// Isn't possible to do a network request within a Browser (which our
52
89
// notification is tied to), without a page.
@@ -59,6 +96,13 @@ pub fn httpRequestStart(arena: Allocator, bc: anytype, request: *const Notificat
59
96
const target_id = bc .target_id orelse unreachable ;
60
97
const page = bc .session .currentPage () orelse unreachable ;
61
98
99
+ // Modify request with extra CDP headers
100
+ try request .headers .ensureTotalCapacity (request .arena , request .headers .items .len + cdp .extra_headers .items .len );
101
+ for (cdp .extra_headers .items ) | extra | {
102
+ const new = putAssumeCapacity (request .headers , extra );
103
+ if (! new ) log .debug (.cdp , "request header overwritten" , .{ .name = extra .name });
104
+ }
105
+
62
106
const document_url = try urlToString (arena , & page .url .uri , .{
63
107
.scheme = true ,
64
108
.authentication = true ,
@@ -80,8 +124,8 @@ pub fn httpRequestStart(arena: Allocator, bc: anytype, request: *const Notificat
80
124
});
81
125
82
126
var headers : std .StringArrayHashMapUnmanaged ([]const u8 ) = .empty ;
83
- try headers .ensureTotalCapacity (arena , request .headers .len );
84
- for (request .headers ) | header | {
127
+ try headers .ensureTotalCapacity (arena , request .headers .items . len );
128
+ for (request .headers . items ) | header | {
85
129
headers .putAssumeCapacity (header .name , header .value );
86
130
}
87
131
@@ -129,13 +173,13 @@ pub fn httpRequestComplete(arena: Allocator, bc: anytype, request: *const Notifi
129
173
// We're missing a bunch of fields, but, for now, this seems like enough
130
174
try cdp .sendEvent ("Network.responseReceived" , .{
131
175
.requestId = try std .fmt .allocPrint (arena , "REQ-{d}" , .{request .id }),
132
- .frameId = target_id ,
133
176
.loaderId = bc .loader_id ,
134
177
.response = .{
135
178
.url = url ,
136
179
.status = request .status ,
137
180
.headers = std .json .ArrayHashMap ([]const u8 ){ .map = headers },
138
181
},
182
+ .frameId = target_id ,
139
183
}, .{ .session_id = session_id });
140
184
}
141
185
@@ -144,3 +188,30 @@ fn urlToString(arena: Allocator, url: *const std.Uri, opts: std.Uri.WriteToStrea
144
188
try url .writeToStream (opts , buf .writer (arena ));
145
189
return buf .items ;
146
190
}
191
+
192
+ const testing = @import ("../testing.zig" );
193
+ test "cdp.network setExtraHTTPHeaders" {
194
+ var ctx = testing .context ();
195
+ defer ctx .deinit ();
196
+
197
+ // _ = try ctx.loadBrowserContext(.{ .id = "NID-A", .session_id = "NESI-A" });
198
+ try ctx .processMessage (.{ .id = 10 , .method = "Target.createTarget" , .params = .{ .url = "about/blank" } });
199
+
200
+ try ctx .processMessage (.{
201
+ .id = 3 ,
202
+ .method = "Network.setExtraHTTPHeaders" ,
203
+ .params = .{ .headers = .{ .foo = "bar" } },
204
+ });
205
+
206
+ try ctx .processMessage (.{
207
+ .id = 4 ,
208
+ .method = "Network.setExtraHTTPHeaders" ,
209
+ .params = .{ .headers = .{ .food = "bars" } },
210
+ });
211
+
212
+ const bc = ctx .cdp ().browser_context .? ;
213
+ try testing .expectEqual (bc .cdp .extra_headers .items .len , 1 );
214
+
215
+ try ctx .processMessage (.{ .id = 5 , .method = "Target.attachToTarget" , .params = .{ .targetId = bc .target_id .? } });
216
+ try testing .expectEqual (bc .cdp .extra_headers .items .len , 0 );
217
+ }
0 commit comments