Merge pull request #940 from lightpanda-io/redirect-cookies
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled

enable curl cookie engine
This commit is contained in:
Karl Seguin
2025-08-15 08:50:25 +08:00
committed by GitHub
2 changed files with 56 additions and 15 deletions

View File

@@ -319,6 +319,14 @@ fn makeRequest(self: *Client, handle: *Handle, transfer: *Transfer) !void {
var header_list = req.headers;
try conn.secretHeaders(&header_list); // Add headers that must be hidden from intercepts
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_HTTPHEADER, header_list.headers));
// Add cookies.
// Clear cookies from Curl's engine.
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_COOKIELIST, "ALL"));
if (header_list.cookies) |cookies| {
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_COOKIE, cookies));
}
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_PRIVATE, transfer));
}
@@ -506,12 +514,11 @@ pub const RequestCookie = struct {
.is_http = self.is_http,
.is_navigation = self.is_navigation,
.origin_uri = self.origin,
.prefix = "Cookie: ",
});
if (arr.items.len > 0) {
try arr.append(temp, 0); //null terminate
try headers.add(@ptrCast(arr.items.ptr));
headers.cookies = @ptrCast(arr.items.ptr);
}
}
};
@@ -603,6 +610,22 @@ pub const Transfer = struct {
const header = buffer[0 .. buf_len - 2];
if (transfer.response_header == null) {
if (transfer._redirecting and buf_len == 2) {
// retrieve cookies from the redirect's response.
var i: usize = 0;
while (true) {
const ct = getResponseHeader(easy, "set-cookie", i);
if (ct == null) break;
transfer.req.cookie_jar.populateFromResponse(&transfer.uri, ct.?.value) catch |err| {
log.err(.http, "set cookie", .{ .err = err, .req = transfer });
};
i += 1;
if (i >= ct.?.amount) break;
}
return buf_len;
}
if (buf_len < 13 or std.mem.startsWith(u8, header, "HTTP/") == false) {
if (transfer._redirecting) {
return buf_len;
@@ -641,18 +664,6 @@ pub const Transfer = struct {
return buf_len;
}
{
const SET_COOKIE_LEN = "set-cookie:".len;
if (header.len > SET_COOKIE_LEN) {
if (std.ascii.eqlIgnoreCase(header[0..SET_COOKIE_LEN], "set-cookie:")) {
const value = std.mem.trimLeft(u8, header[SET_COOKIE_LEN..], " ");
transfer.req.cookie_jar.populateFromResponse(&transfer.uri, value) catch |err| {
log.err(.http, "set cookie", .{ .err = err, .req = transfer });
};
}
}
}
if (buf_len == 2) {
if (getResponseHeader(easy, "content-type", 0)) |ct| {
var hdr = &transfer.response_header.?;
@@ -662,6 +673,17 @@ pub const Transfer = struct {
@memcpy(hdr._content_type[0..len], value[0..len]);
}
var i: usize = 0;
while (true) {
const ct = getResponseHeader(easy, "set-cookie", i);
if (ct == null) break;
transfer.req.cookie_jar.populateFromResponse(&transfer.uri, ct.?.value) catch |err| {
log.err(.http, "set cookie", .{ .err = err, .req = transfer });
};
i += 1;
if (i >= ct.?.amount) break;
}
transfer.req.header_done_callback(transfer) catch |err| {
log.err(.http, "header_done_callback", .{ .err = err, .req = transfer });
// returning < buf_len terminates the request

View File

@@ -110,6 +110,9 @@ pub const Connection = struct {
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_FOLLOWLOCATION, @as(c_long, 2)));
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_REDIR_PROTOCOLS_STR, "HTTP,HTTPS")); // remove FTP and FTPS from the default
// enable cookie engine for redirections handled directly by Curl.
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_COOKIEFILE, ""));
// proxy
if (opts.http_proxy) |proxy| {
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_PROXY, proxy.ptr));
@@ -201,6 +204,13 @@ pub const Connection = struct {
try self.secretHeaders(&header_list);
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_HTTPHEADER, header_list.headers));
// Add cookies.
// Clear cookies from Curl's engine.
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_COOKIELIST, "ALL"));
if (header_list.cookies) |cookies| {
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_COOKIE, cookies));
}
try errorCheck(c.curl_easy_perform(easy));
var http_code: c_long = undefined;
try errorCheck(c.curl_easy_getinfo(easy, c.CURLINFO_RESPONSE_CODE, &http_code));
@@ -213,11 +223,12 @@ pub const Connection = struct {
pub const Headers = struct {
headers: *c.curl_slist,
cookies: ?[*c]const u8,
pub fn init() !Headers {
const header_list = c.curl_slist_append(null, "User-Agent: Lightpanda/1.0");
if (header_list == null) return error.OutOfMemory;
return .{ .headers = header_list };
return .{ .headers = header_list, .cookies = null };
}
pub fn deinit(self: *const Headers) void {
@@ -242,6 +253,10 @@ pub const Headers = struct {
list.putAssumeCapacity(header.name, header.value);
current = node.*.next;
}
// special case for cookies
if (self.cookies) |v| {
list.putAssumeCapacity("Cookie", std.mem.span(@as([*:0]const u8, @ptrCast(v))));
}
return list;
}
@@ -261,6 +276,10 @@ pub const Headers = struct {
num += 1;
current = node.*.next;
}
// special case for cookies
if (self.cookies != null) {
num += 1;
}
return num;
}
};