@@ -24,6 +24,8 @@ pub const Headers = Http.Headers;
2424const Notification = @import ("../notification.zig" ).Notification ;
2525const storage = @import ("../browser/storage/storage.zig" );
2626
27+ const urlStitch = @import ("../url.zig" ).stitch ;
28+
2729const c = Http .c ;
2830
2931const Allocator = std .mem .Allocator ;
@@ -83,12 +85,6 @@ blocking: Handle,
8385// To notify registered subscribers of events, the browser sets/nulls this for us.
8486notification : ? * Notification = null ,
8587
86- // The only place this is meant to be used is in `makeRequest` BEFORE `perform`
87- // is called. It is used to generate our Cookie header. It can be used for other
88- // purposes, but keep in mind that, while single-threaded, calls like makeRequest
89- // can result in makeRequest being re-called (from a doneCallback).
90- arena : ArenaAllocator ,
91-
9288// only needed for CDP which can change the proxy and then restore it. When
9389// restoring, this originally-configured value is what it goes to.
9490http_proxy : ? [:0 ]const u8 = null ,
@@ -126,7 +122,6 @@ pub fn init(allocator: Allocator, ca_blob: ?c.curl_blob, opts: Http.Opts) !*Clie
126122 .http_proxy = opts .http_proxy ,
127123 .transfer_pool = transfer_pool ,
128124 .queue_node_pool = queue_node_pool ,
129- .arena = ArenaAllocator .init (allocator ),
130125 };
131126
132127 return client ;
@@ -141,7 +136,6 @@ pub fn deinit(self: *Client) void {
141136
142137 self .transfer_pool .deinit ();
143138 self .queue_node_pool .deinit ();
144- self .arena .deinit ();
145139 self .allocator .destroy (self );
146140}
147141
@@ -242,6 +236,7 @@ fn makeTransfer(self: *Client, req: Request) !*Transfer {
242236 const id = self .next_request_id + 1 ;
243237 self .next_request_id = id ;
244238 transfer .* = .{
239+ .arena = ArenaAllocator .init (self .allocator ),
245240 .id = id ,
246241 .uri = uri ,
247242 .req = req ,
@@ -321,8 +316,6 @@ fn makeRequest(self: *Client, handle: *Handle, transfer: *Transfer) !void {
321316 try errorCheck (c .curl_easy_setopt (easy , c .CURLOPT_HTTPHEADER , header_list .headers ));
322317
323318 // Add cookies.
324- // Clear cookies from Curl's engine.
325- try errorCheck (c .curl_easy_setopt (easy , c .CURLOPT_COOKIELIST , "ALL" ));
326319 if (header_list .cookies ) | cookies | {
327320 try errorCheck (c .curl_easy_setopt (easy , c .CURLOPT_COOKIE , cookies ));
328321 }
@@ -542,6 +535,7 @@ pub const Request = struct {
542535};
543536
544537pub const Transfer = struct {
538+ arena : ArenaAllocator ,
545539 id : usize = 0 ,
546540 req : Request ,
547541 uri : std.Uri , // used for setting/getting the cookie
@@ -561,6 +555,7 @@ pub const Transfer = struct {
561555 if (self ._handle ) | handle | {
562556 self .client .handles .release (handle );
563557 }
558+ self .arena .deinit ();
564559 self .client .transfer_pool .destroy (self );
565560 }
566561
@@ -595,6 +590,42 @@ pub const Transfer = struct {
595590 self .deinit ();
596591 }
597592
593+ // redirectionCookies manages cookies during redirections handled by Curl.
594+ // It sets the cookies from the current response to the cookie jar.
595+ // It also immediately sets cookies for the following request.
596+ fn redirectionCookies (arena : Allocator , easy : * c.CURL , cookie_jar : * storage.CookieJar , origin : * const std.Uri ) ! void {
597+ // retrieve cookies from the redirect's response.
598+ var i : usize = 0 ;
599+ while (true ) {
600+ const ct = getResponseHeader (easy , "set-cookie" , i );
601+ if (ct == null ) break ;
602+ try cookie_jar .populateFromResponse (origin , ct .? .value );
603+ i += 1 ;
604+ if (i >= ct .? .amount ) break ;
605+ }
606+
607+ // set cookies for the following redirection's request.
608+ const hlocation = getResponseHeader (easy , "location" , 0 );
609+ if (hlocation == null ) {
610+ return error .LocationNotFound ;
611+ }
612+
613+ var baseurl : [* c ]u8 = undefined ;
614+ try errorCheck (c .curl_easy_getinfo (easy , c .CURLINFO_EFFECTIVE_URL , & baseurl ));
615+
616+ const url = try urlStitch (arena , hlocation .? .value , std .mem .span (baseurl ), .{});
617+ const uri = try std .Uri .parse (url );
618+
619+ var cookies : std .ArrayListUnmanaged (u8 ) = .{};
620+ try cookie_jar .forRequest (& uri , cookies .writer (arena ), .{
621+ .is_http = true ,
622+ .is_navigation = true ,
623+ .origin_uri = origin ,
624+ });
625+ try cookies .append (arena , 0 ); //null terminate
626+ try errorCheck (c .curl_easy_setopt (easy , c .CURLOPT_COOKIE , @as ([* c ]const u8 , @ptrCast (cookies .items .ptr ))));
627+ }
628+
598629 fn headerCallback (buffer : [* ]const u8 , header_count : usize , buf_len : usize , data : * anyopaque ) callconv (.c ) usize {
599630 // libcurl should only ever emit 1 header at a time
600631 std .debug .assert (header_count == 1 );
@@ -611,18 +642,16 @@ pub const Transfer = struct {
611642
612643 if (transfer .response_header == null ) {
613644 if (transfer ._redirecting and buf_len == 2 ) {
614- // retrieve cookies from the redirect's response.
615- var i : usize = 0 ;
616- while (true ) {
617- const ct = getResponseHeader (easy , "set-cookie" , i );
618- if (ct == null ) break ;
619- transfer .req .cookie_jar .populateFromResponse (& transfer .uri , ct .? .value ) catch | err | {
620- log .err (.http , "set cookie" , .{ .err = err , .req = transfer });
621- };
622- i += 1 ;
623- if (i >= ct .? .amount ) break ;
624- }
625-
645+ // parse and set cookies for the redirection.
646+ redirectionCookies (
647+ transfer .arena .allocator (),
648+ easy ,
649+ transfer .req .cookie_jar ,
650+ & transfer .uri ,
651+ ) catch | err | {
652+ log .debug (.http , "redirection cookies" , .{ .err = err });
653+ return 0 ;
654+ };
626655 return buf_len ;
627656 }
628657
0 commit comments