@@ -32,12 +32,14 @@ pub fn processMessage(cmd: anytype) !void {
3232 continueRequest ,
3333 failRequest ,
3434 fulfillRequest ,
35+ continueWithAuth ,
3536 }, cmd .input .action ) orelse return error .UnknownMethod ;
3637
3738 switch (action ) {
3839 .disable = > return disable (cmd ),
3940 .enable = > return enable (cmd ),
4041 .continueRequest = > return continueRequest (cmd ),
42+ .continueWithAuth = > return continueWithAuth (cmd ),
4143 .failRequest = > return failRequest (cmd ),
4244 .fulfillRequest = > return fulfillRequest (cmd ),
4345 }
@@ -144,12 +146,8 @@ fn enable(cmd: anytype) !void {
144146 return cmd .sendResult (null , .{});
145147 }
146148
147- if (params .handleAuthRequests ) {
148- log .warn (.cdp , "not implemented" , .{ .feature = "Fetch.enable handleAuthRequests is not supported yet" });
149- }
150-
151149 const bc = cmd .browser_context orelse return error .BrowserContextNotLoaded ;
152- try bc .fetchEnable ();
150+ try bc .fetchEnable (params . handleAuthRequests );
153151
154152 return cmd .sendResult (null , .{});
155153}
@@ -276,6 +274,56 @@ fn continueRequest(cmd: anytype) !void {
276274 return cmd .sendResult (null , .{});
277275}
278276
277+ fn continueWithAuth (cmd : anytype ) ! void {
278+ const bc = cmd .browser_context orelse return error .BrowserContextNotLoaded ;
279+ const params = (try cmd .params (struct {
280+ requestId : []const u8 , // "INTERCEPT-{d}"
281+ authChallengeResponse : struct {
282+ response : []const u8 ,
283+ username : ? []const u8 = null ,
284+ password : ? []const u8 = null ,
285+ },
286+ })) orelse return error .InvalidParams ;
287+
288+ const page = bc .session .currentPage () orelse return error .PageNotLoaded ;
289+
290+ var intercept_state = & bc .intercept_state ;
291+ const request_id = try idFromRequestId (params .requestId );
292+ const transfer = intercept_state .remove (request_id ) orelse return error .RequestNotFound ;
293+
294+ log .debug (.cdp , "request intercept" , .{
295+ .state = "continue with auth" ,
296+ .id = transfer .id ,
297+ .response = params .authChallengeResponse .response ,
298+ });
299+
300+ if (! std .mem .eql (u8 , params .authChallengeResponse .response , "ProvideCredentials" )) {
301+ transfer .abortAuthChallenge ();
302+ return cmd .sendResult (null , .{});
303+ }
304+
305+ // cancel the request, deinit the transfer on error.
306+ errdefer transfer .abortAuthChallenge ();
307+
308+ const username = params .authChallengeResponse .username orelse "" ;
309+ const password = params .authChallengeResponse .password orelse "" ;
310+
311+ // restart the request with the provided credentials.
312+ // we need to duplicate the cre
313+ const arena = transfer .arena .allocator ();
314+ transfer .updateCredentials (
315+ try std .fmt .allocPrintZ (arena , "{s}:{s}" , .{ username , password }),
316+ );
317+
318+ try bc .cdp .browser .http_client .process (transfer );
319+
320+ if (intercept_state .empty ()) {
321+ page .request_intercepted = false ;
322+ }
323+
324+ return cmd .sendResult (null , .{});
325+ }
326+
279327fn fulfillRequest (cmd : anytype ) ! void {
280328 const bc = cmd .browser_context orelse return error .BrowserContextNotLoaded ;
281329
@@ -346,6 +394,50 @@ fn failRequest(cmd: anytype) !void {
346394 return cmd .sendResult (null , .{});
347395}
348396
397+ pub fn requestAuthRequired (arena : Allocator , bc : anytype , intercept : * const Notification.RequestAuthRequired ) ! void {
398+ // unreachable because we _have_ to have a page.
399+ const session_id = bc .session_id orelse unreachable ;
400+ const target_id = bc .target_id orelse unreachable ;
401+ const page = bc .session .currentPage () orelse unreachable ;
402+
403+ // We keep it around to wait for modifications to the request.
404+ // NOTE: we assume whomever created the request created it with a lifetime of the Page.
405+ // TODO: What to do when receiving replies for a previous page's requests?
406+
407+ const transfer = intercept .transfer ;
408+ try bc .intercept_state .put (transfer );
409+
410+ const challenge = transfer ._auth_challenge orelse return error .NullAuthChallenge ;
411+
412+ try bc .cdp .sendEvent ("Fetch.authRequired" , .{
413+ .requestId = try std .fmt .allocPrint (arena , "INTERCEPT-{d}" , .{transfer .id }),
414+ .request = network .TransferAsRequestWriter .init (transfer ),
415+ .frameId = target_id ,
416+ .resourceType = switch (transfer .req .resource_type ) {
417+ .script = > "Script" ,
418+ .xhr = > "XHR" ,
419+ .document = > "Document" ,
420+ },
421+ .authChallenge = .{
422+ .source = if (challenge .source == .server ) "Server" else "Proxy" ,
423+ .origin = "" , // TODO get origin, could be the proxy address for example.
424+ .scheme = if (challenge .scheme == .digest ) "digest" else "basic" ,
425+ .realm = challenge .realm ,
426+ },
427+ .networkId = try std .fmt .allocPrint (arena , "REQ-{d}" , .{transfer .id }),
428+ }, .{ .session_id = session_id });
429+
430+ log .debug (.cdp , "request auth required" , .{
431+ .state = "paused" ,
432+ .id = transfer .id ,
433+ .url = transfer .uri ,
434+ });
435+ // Await continueWithAuth
436+
437+ intercept .wait_for_interception .* = true ;
438+ page .request_intercepted = true ;
439+ }
440+
349441// Get u64 from requestId which is formatted as: "INTERCEPT-{d}"
350442fn idFromRequestId (request_id : []const u8 ) ! u64 {
351443 if (! std .mem .startsWith (u8 , request_id , "INTERCEPT-" )) {
0 commit comments