@@ -96,6 +96,20 @@ impl Matcher {
9696 Builder :: from_env ( ) . build ( )
9797 }
9898
99+ /// Create a matcher from the environment or system.
100+ ///
101+ /// This checks the same environment variables as `from_env()`, and if not
102+ /// set, checks the system configuration for values for the OS.
103+ ///
104+ /// This constructor is always available, but if the `client-proxy-system`
105+ /// feature is enabled, it will check more configuration. Use this
106+ /// constructor if you want to allow users to optionally enable more, or
107+ /// use `from_env` if you do not want the values to change based on an
108+ /// enabled feature.
109+ pub fn from_system ( ) -> Self {
110+ Builder :: from_system ( ) . build ( )
111+ }
112+
99113 /// Start a builder to configure a matcher.
100114 pub fn builder ( ) -> Builder {
101115 Builder :: default ( )
@@ -221,6 +235,16 @@ impl Builder {
221235 }
222236 }
223237
238+ fn from_system ( ) -> Self {
239+ #[ allow( unused_mut) ]
240+ let mut builder = Self :: from_env ( ) ;
241+
242+ #[ cfg( all( feature = "client-proxy-system" , target_os = "macos" ) ) ]
243+ mac:: with_system ( & mut builder) ;
244+
245+ builder
246+ }
247+
224248 /// Set the target proxy for all destinations.
225249 pub fn all < S > ( mut self , val : S ) -> Self
226250 where
@@ -531,6 +555,89 @@ mod builder {
531555 }
532556}
533557
558+ #[ cfg( feature = "client-proxy-system" ) ]
559+ #[ cfg( target_os = "macos" ) ]
560+ mod mac {
561+ use system_configuration:: core_foundation:: base:: { CFType , TCFType , TCFTypeRef } ;
562+ use system_configuration:: core_foundation:: dictionary:: CFDictionary ;
563+ use system_configuration:: core_foundation:: number:: CFNumber ;
564+ use system_configuration:: core_foundation:: string:: { CFString , CFStringRef } ;
565+ use system_configuration:: dynamic_store:: SCDynamicStoreBuilder ;
566+ use system_configuration:: sys:: schema_definitions:: {
567+ kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPPort, kSCPropNetProxiesHTTPProxy,
568+ kSCPropNetProxiesHTTPSEnable, kSCPropNetProxiesHTTPSPort, kSCPropNetProxiesHTTPSProxy,
569+ } ;
570+
571+ pub ( super ) fn with_system ( builder : & mut super :: Builder ) {
572+ let store = SCDynamicStoreBuilder :: new ( "" ) . build ( ) ;
573+
574+ let proxies_map = if let Some ( proxies_map) = store. get_proxies ( ) {
575+ proxies_map
576+ } else {
577+ return ;
578+ } ;
579+
580+ if builder. http . is_empty ( ) {
581+ let http_proxy_config = parse_setting_from_dynamic_store (
582+ & proxies_map,
583+ unsafe { kSCPropNetProxiesHTTPEnable } ,
584+ unsafe { kSCPropNetProxiesHTTPProxy } ,
585+ unsafe { kSCPropNetProxiesHTTPPort } ,
586+ ) ;
587+ if let Some ( http) = http_proxy_config {
588+ builder. http = http;
589+ }
590+ }
591+
592+ if builder. https . is_empty ( ) {
593+ let https_proxy_config = parse_setting_from_dynamic_store (
594+ & proxies_map,
595+ unsafe { kSCPropNetProxiesHTTPSEnable } ,
596+ unsafe { kSCPropNetProxiesHTTPSProxy } ,
597+ unsafe { kSCPropNetProxiesHTTPSPort } ,
598+ ) ;
599+
600+ if let Some ( https) = https_proxy_config {
601+ builder. https = https;
602+ }
603+ }
604+ }
605+
606+ fn parse_setting_from_dynamic_store (
607+ proxies_map : & CFDictionary < CFString , CFType > ,
608+ enabled_key : CFStringRef ,
609+ host_key : CFStringRef ,
610+ port_key : CFStringRef ,
611+ ) -> Option < String > {
612+ let proxy_enabled = proxies_map
613+ . find ( enabled_key)
614+ . and_then ( |flag| flag. downcast :: < CFNumber > ( ) )
615+ . and_then ( |flag| flag. to_i32 ( ) )
616+ . unwrap_or ( 0 )
617+ == 1 ;
618+
619+ if proxy_enabled {
620+ let proxy_host = proxies_map
621+ . find ( host_key)
622+ . and_then ( |host| host. downcast :: < CFString > ( ) )
623+ . map ( |host| host. to_string ( ) ) ;
624+ let proxy_port = proxies_map
625+ . find ( port_key)
626+ . and_then ( |port| port. downcast :: < CFNumber > ( ) )
627+ . and_then ( |port| port. to_i32 ( ) ) ;
628+
629+ return match ( proxy_host, proxy_port) {
630+ ( Some ( proxy_host) , Some ( proxy_port) ) => Some ( format ! ( "{proxy_host}:{proxy_port}" ) ) ,
631+ ( Some ( proxy_host) , None ) => Some ( proxy_host) ,
632+ ( None , Some ( _) ) => None ,
633+ ( None , None ) => None ,
634+ } ;
635+ }
636+
637+ None
638+ }
639+ }
640+
534641#[ cfg( test) ]
535642mod tests {
536643 use super :: * ;
0 commit comments