@@ -89,9 +89,6 @@ notification: ?*Notification = null,
8989// restoring, this originally-configured value is what it goes to.
9090http_proxy : ? [:0 ]const u8 = null ,
9191
92- // does the client use a proxy?
93- use_proxy : bool = false ,
94-
9592const TransferQueue = std .DoublyLinkedList (* Transfer );
9693
9794pub fn init (allocator : Allocator , ca_blob : ? c.curl_blob , opts : Http.Opts ) ! * Client {
@@ -123,7 +120,6 @@ pub fn init(allocator: Allocator, ca_blob: ?c.curl_blob, opts: Http.Opts) !*Clie
123120 .blocking = blocking ,
124121 .allocator = allocator ,
125122 .http_proxy = opts .http_proxy ,
126- .use_proxy = opts .http_proxy != null ,
127123 .transfer_pool = transfer_pool ,
128124 .queue_node_pool = queue_node_pool ,
129125 };
@@ -246,7 +242,6 @@ fn makeTransfer(self: *Client, req: Request) !*Transfer {
246242 .req = req ,
247243 .ctx = req .ctx ,
248244 .client = self ,
249- ._use_proxy = self .use_proxy ,
250245 };
251246 return transfer ;
252247}
@@ -283,7 +278,6 @@ fn requestFailed(self: *Client, transfer: *Transfer, err: anyerror) void {
283278pub fn changeProxy (self : * Client , proxy : [:0 ]const u8 ) ! void {
284279 try self .ensureNoActiveConnection ();
285280
286- self .use_proxy = true ;
287281 for (self .handles .handles ) | * h | {
288282 try errorCheck (c .curl_easy_setopt (h .conn .easy , c .CURLOPT_PROXY , proxy .ptr ));
289283 }
@@ -295,7 +289,6 @@ pub fn changeProxy(self: *Client, proxy: [:0]const u8) !void {
295289pub fn restoreOriginalProxy (self : * Client ) ! void {
296290 try self .ensureNoActiveConnection ();
297291
298- self .use_proxy = self .http_proxy != null ;
299292 const proxy = if (self .http_proxy ) | p | p .ptr else null ;
300293 for (self .handles .handles ) | * h | {
301294 try errorCheck (c .curl_easy_setopt (h .conn .easy , c .CURLOPT_PROXY , proxy ));
@@ -589,10 +582,7 @@ pub const Transfer = struct {
589582 _handle : ? * Handle = null ,
590583
591584 _redirecting : bool = false ,
592-
593- // use_proxy is set when the transfer has been associated to a given
594- // connection in makeRequest().
595- _use_proxy : bool = undefined ,
585+ _forbidden : bool = false ,
596586
597587 fn deinit (self : * Transfer ) void {
598588 self .req .headers .deinit ();
@@ -603,17 +593,34 @@ pub const Transfer = struct {
603593 self .client .transfer_pool .destroy (self );
604594 }
605595
596+ fn buildResponseHeader (self : * Transfer , easy : * c.CURL ) ! void {
597+ std .debug .assert (self .response_header == null );
598+
599+ var url : [* c ]u8 = undefined ;
600+ try errorCheck (c .curl_easy_getinfo (easy , c .CURLINFO_EFFECTIVE_URL , & url ));
601+
602+ var status : c_long = undefined ;
603+ try errorCheck (c .curl_easy_getinfo (easy , c .CURLINFO_RESPONSE_CODE , & status ));
604+
605+ self .response_header = .{
606+ .url = url ,
607+ .status = @intCast (status ),
608+ };
609+
610+ if (getResponseHeader (easy , "content-type" , 0 )) | ct | {
611+ var hdr = & self .response_header .? ;
612+ const value = ct .value ;
613+ const len = @min (value .len , ResponseHeader .MAX_CONTENT_TYPE_LEN );
614+ hdr ._content_type_len = len ;
615+ @memcpy (hdr ._content_type [0.. len ], value [0.. len ]);
616+ }
617+ }
618+
606619 pub fn format (self : * const Transfer , comptime _ : []const u8 , _ : std.fmt.FormatOptions , writer : anytype ) ! void {
607620 const req = self .req ;
608621 return writer .print ("{s} {s}" , .{ @tagName (req .method ), req .url });
609622 }
610623
611- pub fn setBody (self : * Transfer , body : []const u8 ) ! void {
612- const easy = self .handle .easy ;
613- try errorCheck (c .curl_easy_setopt (easy , c .CURLOPT_POSTFIELDS , body .ptr ));
614- try errorCheck (c .curl_easy_setopt (easy , c .CURLOPT_POSTFIELDSIZE , @as (c_long , @intCast (body .len ))));
615- }
616-
617624 pub fn addHeader (self : * Transfer , value : [:0 ]const u8 ) ! void {
618625 self ._request_header_list = c .curl_slist_append (self ._request_header_list , value );
619626 }
@@ -695,10 +702,10 @@ pub const Transfer = struct {
695702 // w/o body.
696703 fn headerDoneCallback (transfer : * Transfer , easy : * c.CURL ) ! void {
697704 std .debug .assert (transfer ._header_done_called == false );
698- std .debug .assert (transfer .response_header != null );
699-
700705 defer transfer ._header_done_called = true ;
701706
707+ try transfer .buildResponseHeader (easy );
708+
702709 if (getResponseHeader (easy , "content-type" , 0 )) | ct | {
703710 var hdr = & transfer .response_header .? ;
704711 const value = ct .value ;
@@ -746,8 +753,12 @@ pub const Transfer = struct {
746753
747754 const header = buffer [0 .. buf_len - 2 ];
748755
749- // Is it the first header line?
756+ // We need to parse the first line headers for each request b/c curl's
757+ // CURLINFO_RESPONSE_CODE returns the status code of the final request.
758+ // If a redirection or a proxy's CONNECT forbidden happens, we won't
759+ // get this intermediary status code.
750760 if (std .mem .startsWith (u8 , header , "HTTP/" )) {
761+ // Is it the first header line.
751762 if (buf_len < 13 ) {
752763 log .debug (.http , "invalid response line" , .{ .line = header });
753764 return 0 ;
@@ -770,21 +781,17 @@ pub const Transfer = struct {
770781 }
771782 transfer ._redirecting = false ;
772783
773- var url : [ * c ] u8 = undefined ;
774- errorCheck ( c . curl_easy_getinfo ( easy , c . CURLINFO_EFFECTIVE_URL , & url )) catch | err | {
775- log . err ( .http , "failed to get URL" , .{ . err = err }) ;
776- return 0 ;
777- } ;
784+ if ( status == 401 or status == 407 ) {
785+ transfer . _forbidden = true ;
786+ return buf_len ;
787+ }
788+ transfer . _forbidden = false ;
778789
779- transfer .response_header = .{
780- .url = url ,
781- .status = status ,
782- };
783790 transfer .bytes_received = buf_len ;
784791 return buf_len ;
785792 }
786793
787- if (transfer ._redirecting == false ) {
794+ if (transfer ._redirecting == false and transfer . _forbidden == false ) {
788795 transfer .bytes_received += buf_len ;
789796 }
790797
@@ -794,12 +801,6 @@ pub const Transfer = struct {
794801
795802 // Starting here, we get the last header line.
796803
797- // We're connecting to a proxy. Consider the first request to be the
798- // proxy's result.
799- if (transfer ._use_proxy and transfer .proxy_response_header == null ) {
800- transfer .proxy_response_header = transfer .response_header ;
801- }
802-
803804 if (transfer ._redirecting ) {
804805 // parse and set cookies for the redirection.
805806 redirectionCookies (transfer , easy ) catch | err | {
0 commit comments