@@ -46,6 +46,34 @@ pub const ProxyType = enum {
4646 connect ,
4747};
4848
49+ pub const ProxyAuth = union (enum ) {
50+ basic : struct { user_pass : []const u8 },
51+ bearer : struct { token : []const u8 },
52+
53+ pub fn header_value (self : ProxyAuth , allocator : Allocator ) ! []const u8 {
54+ switch (self ) {
55+ .basic = > | * auth | {
56+ if (std .mem .indexOfScalar (u8 , auth .user_pass , ':' ) == null ) return error .InvalidProxyAuth ;
57+
58+ const prefix = "Basic " ;
59+ var encoder = std .base64 .standard .Encoder ;
60+ const size = encoder .calcSize (auth .user_pass .len );
61+ var buffer = try allocator .alloc (u8 , size + prefix .len );
62+ std .mem .copyForwards (u8 , buffer , prefix );
63+ _ = std .base64 .standard .Encoder .encode (buffer [prefix .len .. ], auth .user_pass );
64+ return buffer ;
65+ },
66+ .bearer = > | * auth | {
67+ const prefix = "Bearer " ;
68+ var buffer = try allocator .alloc (u8 , auth .token .len + prefix .len );
69+ std .mem .copyForwards (u8 , buffer , prefix );
70+ std .mem .copyForwards (u8 , buffer [prefix .len .. ], auth .token );
71+ return buffer ;
72+ },
73+ }
74+ }
75+ };
76+
4977// Thread-safe. Holds our root certificate, connection pool and state pool
5078// Used to create Requests.
5179pub const Client = struct {
@@ -54,6 +82,7 @@ pub const Client = struct {
5482 state_pool : StatePool ,
5583 http_proxy : ? Uri ,
5684 proxy_type : ? ProxyType ,
85+ proxy_auth : ? []const u8 , // Basic <user:pass; base64> or Bearer <token>
5786 root_ca : tls.config.CertBundle ,
5887 tls_verify_host : bool = true ,
5988 connection_manager : ConnectionManager ,
@@ -63,6 +92,7 @@ pub const Client = struct {
6392 max_concurrent : usize = 3 ,
6493 http_proxy : ? std.Uri = null ,
6594 proxy_type : ? ProxyType = null ,
95+ proxy_auth : ? ProxyAuth = null ,
6696 tls_verify_host : bool = true ,
6797 max_idle_connection : usize = 10 ,
6898 };
@@ -71,10 +101,10 @@ pub const Client = struct {
71101 var root_ca : tls.config.CertBundle = if (builtin .is_test ) .{} else try tls .config .CertBundle .fromSystem (allocator );
72102 errdefer root_ca .deinit (allocator );
73103
74- const state_pool = try StatePool .init (allocator , opts .max_concurrent );
104+ var state_pool = try StatePool .init (allocator , opts .max_concurrent );
75105 errdefer state_pool .deinit (allocator );
76106
77- const connection_manager = ConnectionManager .init (allocator , opts .max_idle_connection );
107+ var connection_manager = ConnectionManager .init (allocator , opts .max_idle_connection );
78108 errdefer connection_manager .deinit ();
79109
80110 return .{
@@ -84,6 +114,7 @@ pub const Client = struct {
84114 .state_pool = state_pool ,
85115 .http_proxy = opts .http_proxy ,
86116 .proxy_type = if (opts .http_proxy == null ) null else (opts .proxy_type orelse .connect ),
117+ .proxy_auth = if (opts .proxy_auth ) | * auth | try auth .header_value (allocator ) else null ,
87118 .tls_verify_host = opts .tls_verify_host ,
88119 .connection_manager = connection_manager ,
89120 .request_pool = std .heap .MemoryPool (Request ).init (allocator ),
@@ -98,6 +129,10 @@ pub const Client = struct {
98129 self .state_pool .deinit (allocator );
99130 self .connection_manager .deinit ();
100131 self .request_pool .deinit ();
132+
133+ if (self .proxy_auth ) | auth | {
134+ allocator .free (auth );
135+ }
101136 }
102137
103138 pub fn request (self : * Client , method : Request.Method , uri : * const Uri ) ! * Request {
@@ -763,6 +798,13 @@ pub const Request = struct {
763798
764799 try self .headers .append (arena , .{ .name = "User-Agent" , .value = "Lightpanda/1.0" });
765800 try self .headers .append (arena , .{ .name = "Accept" , .value = "*/*" });
801+
802+ if (self ._client .isSimpleProxy ()) {
803+ if (self ._client .proxy_auth ) | proxy_auth | {
804+ try self .headers .append (arena , .{ .name = "Proxy-Authorization" , .value = proxy_auth });
805+ }
806+ }
807+
766808 self .requestStarting ();
767809 }
768810
@@ -887,7 +929,13 @@ pub const Request = struct {
887929 var writer = fbs .writer ();
888930
889931 try writer .print ("CONNECT {s}:{d} HTTP/1.1\r \n " , .{ self ._request_host , self ._request_port });
890- try writer .print ("Host: {s}:{d}\r \n \r \n " , .{ self ._request_host , self ._request_port });
932+ try writer .print ("Host: {s}:{d}\r \n " , .{ self ._request_host , self ._request_port });
933+
934+ if (self ._client .proxy_auth ) | proxy_auth | {
935+ try writer .print ("Proxy-Authorization: {s}\r \n " , .{proxy_auth });
936+ }
937+
938+ _ = try writer .write ("\r \n " );
891939 return buf [0.. fbs .pos ];
892940 }
893941
0 commit comments