diff --git a/src/http/Client.zig b/src/http/Client.zig index 8b308c3b..d228cbec 100644 --- a/src/http/Client.zig +++ b/src/http/Client.zig @@ -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 diff --git a/src/http/Http.zig b/src/http/Http.zig index 3195a24c..1d8cde58 100644 --- a/src/http/Http.zig +++ b/src/http/Http.zig @@ -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; } };