@@ -24,6 +24,8 @@ pub const Headers = Http.Headers;
24
24
const Notification = @import ("../notification.zig" ).Notification ;
25
25
const storage = @import ("../browser/storage/storage.zig" );
26
26
27
+ const urlStitch = @import ("../url.zig" ).stitch ;
28
+
27
29
const c = Http .c ;
28
30
29
31
const Allocator = std .mem .Allocator ;
@@ -83,12 +85,6 @@ blocking: Handle,
83
85
// To notify registered subscribers of events, the browser sets/nulls this for us.
84
86
notification : ? * Notification = null ,
85
87
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
-
92
88
// only needed for CDP which can change the proxy and then restore it. When
93
89
// restoring, this originally-configured value is what it goes to.
94
90
http_proxy : ? [:0 ]const u8 = null ,
@@ -126,7 +122,6 @@ pub fn init(allocator: Allocator, ca_blob: ?c.curl_blob, opts: Http.Opts) !*Clie
126
122
.http_proxy = opts .http_proxy ,
127
123
.transfer_pool = transfer_pool ,
128
124
.queue_node_pool = queue_node_pool ,
129
- .arena = ArenaAllocator .init (allocator ),
130
125
};
131
126
132
127
return client ;
@@ -141,7 +136,6 @@ pub fn deinit(self: *Client) void {
141
136
142
137
self .transfer_pool .deinit ();
143
138
self .queue_node_pool .deinit ();
144
- self .arena .deinit ();
145
139
self .allocator .destroy (self );
146
140
}
147
141
@@ -242,6 +236,7 @@ fn makeTransfer(self: *Client, req: Request) !*Transfer {
242
236
const id = self .next_request_id + 1 ;
243
237
self .next_request_id = id ;
244
238
transfer .* = .{
239
+ .arena = ArenaAllocator .init (self .allocator ),
245
240
.id = id ,
246
241
.uri = uri ,
247
242
.req = req ,
@@ -321,8 +316,6 @@ fn makeRequest(self: *Client, handle: *Handle, transfer: *Transfer) !void {
321
316
try errorCheck (c .curl_easy_setopt (easy , c .CURLOPT_HTTPHEADER , header_list .headers ));
322
317
323
318
// Add cookies.
324
- // Clear cookies from Curl's engine.
325
- try errorCheck (c .curl_easy_setopt (easy , c .CURLOPT_COOKIELIST , "ALL" ));
326
319
if (header_list .cookies ) | cookies | {
327
320
try errorCheck (c .curl_easy_setopt (easy , c .CURLOPT_COOKIE , cookies ));
328
321
}
@@ -542,6 +535,7 @@ pub const Request = struct {
542
535
};
543
536
544
537
pub const Transfer = struct {
538
+ arena : ArenaAllocator ,
545
539
id : usize = 0 ,
546
540
req : Request ,
547
541
uri : std.Uri , // used for setting/getting the cookie
@@ -561,6 +555,7 @@ pub const Transfer = struct {
561
555
if (self ._handle ) | handle | {
562
556
self .client .handles .release (handle );
563
557
}
558
+ self .arena .deinit ();
564
559
self .client .transfer_pool .destroy (self );
565
560
}
566
561
@@ -595,6 +590,42 @@ pub const Transfer = struct {
595
590
self .deinit ();
596
591
}
597
592
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
+
598
629
fn headerCallback (buffer : [* ]const u8 , header_count : usize , buf_len : usize , data : * anyopaque ) callconv (.c ) usize {
599
630
// libcurl should only ever emit 1 header at a time
600
631
std .debug .assert (header_count == 1 );
@@ -611,18 +642,16 @@ pub const Transfer = struct {
611
642
612
643
if (transfer .response_header == null ) {
613
644
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
+ };
626
655
return buf_len ;
627
656
}
628
657
0 commit comments