Skip to content

Commit 4563aa7

Browse files
committed
wip
1 parent fe3b9c2 commit 4563aa7

File tree

2 files changed

+87
-2
lines changed

2 files changed

+87
-2
lines changed

src/cdp/domains/fetch.zig

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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
}
@@ -272,6 +274,60 @@ fn continueRequest(cmd: anytype) !void {
272274
return cmd.sendResult(null, .{});
273275
}
274276

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,
284+
password: ?[]const u8,
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.abort(); // Is it the correct way to cancel the transfer?
302+
transfer.deinit();
303+
return cmd.sendResult(null, .{});
304+
}
305+
306+
// cancel the request, deinit the transfer on error.
307+
errdefer {
308+
transfer.abort(); // Is it the correct way to cancel the transfer?
309+
transfer.deinit();
310+
}
311+
312+
const username = params.authChallengeResponse.username orelse "";
313+
const password = params.authChallengeResponse.password orelse "";
314+
315+
// restart the request with the provided credentials.
316+
// we need to duplicate the cre
317+
const arena = transfer.arena.allocator();
318+
transfer.updateCredentials(
319+
try std.fmt.allocPrintZ(arena, "{s}:{s}", .{ username, password }),
320+
);
321+
322+
try bc.cdp.browser.http_client.process(transfer);
323+
324+
if (intercept_state.empty()) {
325+
page.request_intercepted = false;
326+
}
327+
328+
return cmd.sendResult(null, .{});
329+
}
330+
275331
fn fulfillRequest(cmd: anytype) !void {
276332
const bc = cmd.browser_context orelse return error.BrowserContextNotLoaded;
277333

@@ -371,7 +427,6 @@ const AuthChallenge = struct {
371427
};
372428

373429
pub fn requestAuthRequired(arena: Allocator, bc: anytype, intercept: *const Notification.RequestAuthRequired) !void {
374-
std.log.debug("AUTH REQU FETCH\n", .{});
375430
// unreachable because we _have_ to have a page.
376431
const session_id = bc.session_id orelse unreachable;
377432
const target_id = bc.target_id orelse unreachable;

src/http/Client.zig

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,11 @@ fn makeRequest(self: *Client, handle: *Handle, transfer: *Transfer) !void {
331331
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_COOKIE, cookies));
332332
}
333333

334+
// Proxy credentials
335+
if (req.credentials) |creds| {
336+
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_PROXYUSERPWD, creds.ptr));
337+
}
338+
334339
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_PRIVATE, transfer));
335340
}
336341

@@ -383,7 +388,10 @@ fn perform(self: *Client, timeout_ms: c_int) !void {
383388
// If the transfer is waiting for auth challenge interception, don't
384389
// deinit the transfer and don't call the callbacks. All will be done
385390
// later during the interception's response.
391+
// we only reset the transfer to release the handle and be reused later.
386392
if (transfer._auth_challenge) {
393+
log.debug(.http, "transfer reset", .{});
394+
transfer.reset();
387395
continue;
388396
}
389397

@@ -551,6 +559,7 @@ pub const Request = struct {
551559
body: ?[]const u8 = null,
552560
cookie_jar: *CookieJar,
553561
resource_type: ResourceType,
562+
credentials: ?[:0]const u8 = null,
554563

555564
// arbitrary data that can be associated with this request
556565
ctx: *anyopaque = undefined,
@@ -599,7 +608,7 @@ pub const Transfer = struct {
599608
// stateful variables used to parse responses headers.
600609
_resp_header_status: enum { empty, first, next, end } = .empty,
601610

602-
fn deinit(self: *Transfer) void {
611+
pub fn deinit(self: *Transfer) void {
603612
self.req.headers.deinit();
604613
if (self._handle) |handle| {
605614
self.client.handles.release(handle);
@@ -608,6 +617,21 @@ pub const Transfer = struct {
608617
self.client.transfer_pool.destroy(self);
609618
}
610619

620+
fn reset(self: *Transfer) void {
621+
if (self._handle) |handle| {
622+
self.client.handles.release(handle);
623+
self._handle = null;
624+
}
625+
self.bytes_received = 0;
626+
self.proxy_response_header = null;
627+
self.response_header = null;
628+
self._notified_fail = false;
629+
self._redirecting = false;
630+
self._auth_challenge = false;
631+
self._use_proxy = false;
632+
self._resp_header_status = .empty;
633+
}
634+
611635
pub fn format(self: *const Transfer, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
612636
const req = self.req;
613637
return writer.print("{s} {s}", .{ @tagName(req.method), req.url });
@@ -623,6 +647,10 @@ pub const Transfer = struct {
623647
self._request_header_list = c.curl_slist_append(self._request_header_list, value);
624648
}
625649

650+
pub fn updateCredentials(self: *Transfer, userpwd: [:0]const u8) void {
651+
self.req.credentials = userpwd;
652+
}
653+
626654
pub fn updateURL(self: *Transfer, url: [:0]const u8) !void {
627655
// for cookies
628656
self.uri = try std.Uri.parse(url);
@@ -816,10 +844,12 @@ pub const Transfer = struct {
816844
// We won't call the req's callbacks now, but for the following request only.
817845
const status = transfer.response_header.?.status;
818846
if (status == 401 or status == 407) {
847+
log.debug(.http, "FORBIDDEN", .{});
819848
if (transfer.client.notification) |notification| {
820849
var wait_for_interception = false;
821850
notification.dispatch(.http_request_auth_required, &.{ .transfer = transfer, .wait_for_interception = &wait_for_interception });
822851
if (wait_for_interception) {
852+
log.debug(.http, "WAIT FOR INTERCEPT", .{});
823853
transfer._auth_challenge = true;
824854
// The user is send an invitation to intercept this request.
825855
return buf_len;

0 commit comments

Comments
 (0)