@@ -96,6 +96,20 @@ impl Matcher {
96
96
Builder :: from_env ( ) . build ( )
97
97
}
98
98
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
+
99
113
/// Start a builder to configure a matcher.
100
114
pub fn builder ( ) -> Builder {
101
115
Builder :: default ( )
@@ -221,6 +235,16 @@ impl Builder {
221
235
}
222
236
}
223
237
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
+
224
248
/// Set the target proxy for all destinations.
225
249
pub fn all < S > ( mut self , val : S ) -> Self
226
250
where
@@ -531,6 +555,89 @@ mod builder {
531
555
}
532
556
}
533
557
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
+
534
641
#[ cfg( test) ]
535
642
mod tests {
536
643
use super :: * ;
0 commit comments