Skip to content

Commit 54543db

Browse files
committed
parse cookie headers fo all requests
Including redirections
1 parent b0fdbe2 commit 54543db

File tree

3 files changed

+12
-107
lines changed

3 files changed

+12
-107
lines changed

src/browser/storage/cookie.zig

Lines changed: 0 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -203,62 +203,6 @@ pub const Cookie = struct {
203203
self.arena.deinit();
204204
}
205205

206-
// Parse curl's cookie file format
207-
// https://curl.se/docs/http-cookies.html
208-
pub fn parseCurl(allocator: Allocator, str: []const u8) !Cookie {
209-
var c: Cookie = .{
210-
.arena = ArenaAllocator.init(allocator),
211-
.name = undefined,
212-
.value = undefined,
213-
.path = undefined,
214-
.same_site = undefined,
215-
.secure = undefined,
216-
.http_only = undefined,
217-
.domain = undefined,
218-
.expires = undefined,
219-
};
220-
errdefer c.deinit();
221-
222-
var aa = c.arena.allocator();
223-
224-
var it = std.mem.splitScalar(u8, str, '\t');
225-
var index: u8 = 0;
226-
while (it.next()) |v| {
227-
defer index += 1;
228-
229-
switch (index) {
230-
0 => {
231-
// domain name, can start with #HttpOnly_
232-
if (std.mem.indexOf(u8, v, "#HttpOnly_")) |pos| {
233-
c.http_only = true;
234-
c.domain = try aa.dupe(u8, v[pos + "#HttpOnly_".len ..]);
235-
} else {
236-
c.http_only = false;
237-
c.domain = try aa.dupe(u8, v);
238-
}
239-
},
240-
1 => c.same_site = .lax, // TODO
241-
2 => c.path = try aa.dupe(u8, v),
242-
3 => c.secure = std.mem.eql(u8, "TRUE", v),
243-
4 => {
244-
if (std.mem.eql(u8, "0", v)) {
245-
c.expires = null;
246-
} else {
247-
const i = try std.fmt.parseInt(i64, v, 10);
248-
c.expires = @floatFromInt(i);
249-
}
250-
},
251-
5 => c.name = try aa.dupe(u8, v),
252-
6 => c.value = try aa.dupe(u8, v),
253-
else => return error.TooMuchCookieFields,
254-
}
255-
}
256-
257-
if (index != 7) return error.MissingCookieFields;
258-
259-
return c;
260-
}
261-
262206
// There's https://datatracker.ietf.org/doc/html/rfc6265 but browsers are
263207
// far less strict. I only found 2 cases where browsers will reject a cookie:
264208
// - a byte 0...32 and 127..255 anywhere in the cookie (the HTTP header
@@ -979,25 +923,6 @@ test "Cookie: parse domain" {
979923
try expectError(error.InvalidDomain, "http://lightpanda.io/", "b;domain=other.example.com");
980924
}
981925

982-
test "Cookie: parse curl" {
983-
try expectCookieCurl(.{
984-
.name = "cookie_key",
985-
.value = "cookie_value",
986-
.path = "/cookies/",
987-
.domain = "httpbin.io",
988-
.http_only = true,
989-
}, "#HttpOnly_httpbin.io\tFALSE\t/cookies/\tFALSE\t0\tcookie_key\tcookie_value");
990-
991-
try expectCookieCurl(.{
992-
.name = "cookie_key",
993-
.value = "cookie_value",
994-
.path = "/cookies/",
995-
.domain = "httpbin.io",
996-
.expires = 10,
997-
.secure = true,
998-
}, "httpbin.io\tTRUE\t/cookies/\tTRUE\t10\tcookie_key\tcookie_value");
999-
}
1000-
1001926
const ExpectedCookie = struct {
1002927
name: []const u8,
1003928
value: []const u8,
@@ -1025,21 +950,6 @@ fn expectCookie(expected: ExpectedCookie, url: []const u8, set_cookie: []const u
1025950
try testing.expectDelta(expected.expires, cookie.expires, 2.0);
1026951
}
1027952

1028-
fn expectCookieCurl(expected: ExpectedCookie, set_cookie: []const u8) !void {
1029-
var cookie = try Cookie.parseCurl(testing.allocator, set_cookie);
1030-
defer cookie.deinit();
1031-
1032-
try testing.expectEqual(expected.name, cookie.name);
1033-
try testing.expectEqual(expected.value, cookie.value);
1034-
try testing.expectEqual(expected.secure, cookie.secure);
1035-
try testing.expectEqual(expected.http_only, cookie.http_only);
1036-
try testing.expectEqual(expected.same_site, cookie.same_site);
1037-
try testing.expectEqual(expected.path, cookie.path);
1038-
try testing.expectEqual(expected.domain, cookie.domain);
1039-
1040-
try testing.expectDelta(expected.expires, cookie.expires, 2.0);
1041-
}
1042-
1043953
fn expectAttribute(expected: anytype, url: ?[]const u8, set_cookie: []const u8) !void {
1044954
const uri = if (url) |u| try Uri.parse(u) else test_uri;
1045955
var cookie = try Cookie.parse(testing.allocator, &uri, set_cookie);

src/http/Client.zig

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,18 @@ pub const Transfer = struct {
556556

557557
const header = buffer[0 .. buf_len - 2];
558558

559+
{
560+
const SET_COOKIE_LEN = "set-cookie:".len;
561+
if (header.len > SET_COOKIE_LEN) {
562+
if (std.ascii.eqlIgnoreCase(header[0..SET_COOKIE_LEN], "set-cookie:")) {
563+
const value = std.mem.trimLeft(u8, header[SET_COOKIE_LEN..], " ");
564+
transfer.req.cookie_jar.populateFromResponse(&transfer.uri, value) catch |err| {
565+
log.err(.http, "set cookie", .{ .err = err, .req = transfer });
566+
};
567+
}
568+
}
569+
}
570+
559571
if (transfer.response_header == null) {
560572
if (buf_len < 13 or std.mem.startsWith(u8, header, "HTTP/") == false) {
561573
if (transfer._redirecting) {
@@ -610,22 +622,6 @@ pub const Transfer = struct {
610622
}
611623

612624
if (buf_len == 2) {
613-
// Read all cookies.
614-
var cookies: ?*c.curl_slist = undefined;
615-
errorCheck(c.curl_easy_getinfo(easy, c.CURLINFO_COOKIELIST, &cookies)) catch |err| {
616-
log.err(.http, "failed to get cookies", .{ .err = err });
617-
return 0;
618-
};
619-
defer c.curl_slist_free_all(cookies);
620-
621-
// populate cookies in the jar
622-
while (cookies) |_cookie| {
623-
transfer.req.cookie_jar.populateFromCurl(std.mem.span(_cookie.data[0..])) catch |err| {
624-
log.err(.http, "set cookie", .{ .err = err, .req = transfer });
625-
};
626-
cookies = _cookie.next;
627-
}
628-
629625
transfer.req.header_done_callback(transfer) catch |err| {
630626
log.err(.http, "header_done_callback", .{ .err = err, .req = transfer });
631627
// returning < buf_len terminates the request

src/http/Http.zig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ pub const Connection = struct {
107107
// redirect behavior
108108
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_MAXREDIRS, @as(c_long, @intCast(opts.max_redirects))));
109109
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_FOLLOWLOCATION, @as(c_long, 2)));
110-
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_COOKIEFILE, "")); // enable curl's cookie engine
111110
try errorCheck(c.curl_easy_setopt(easy, c.CURLOPT_REDIR_PROTOCOLS_STR, "HTTP,HTTPS")); // remove FTP and FTPS from the default
112111

113112
// proxy

0 commit comments

Comments
 (0)