@@ -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,87 @@ mod builder {
531
555
}
532
556
}
533
557
558
+ #[ cfg( feature = "client-proxy-system" ) ]
559
+ #[ cfg( target_os = "macos" ) ]
560
+ mod mac {
561
+
562
+ use system_configuration:: core_foundation:: array:: CFArray ;
563
+ use system_configuration:: core_foundation:: base:: { CFType , TCFType , TCFTypeRef } ;
564
+ use system_configuration:: core_foundation:: dictionary:: CFDictionary ;
565
+ use system_configuration:: core_foundation:: number:: CFNumber ;
566
+ use system_configuration:: core_foundation:: string:: { CFString , CFStringRef } ;
567
+ use system_configuration:: dynamic_store:: { SCDynamicStore , SCDynamicStoreBuilder } ;
568
+
569
+ pub ( super ) fn with_system ( builder : & mut super :: Builder ) {
570
+ let store = SCDynamicStoreBuilder :: new ( "" ) . build ( ) ;
571
+
572
+ let proxies_map = if let Some ( proxies_map) = store. get_proxies ( ) {
573
+ proxies_map
574
+ } else {
575
+ return ;
576
+ } ;
577
+
578
+ if builder. http . is_empty ( ) {
579
+ let http_proxy_config = parse_setting_from_dynamic_store (
580
+ & proxies_map,
581
+ unsafe { kSCPropNetProxiesHTTPEnable } ,
582
+ unsafe { kSCPropNetProxiesHTTPProxy } ,
583
+ unsafe { kSCPropNetProxiesHTTPPort } ,
584
+ ) ;
585
+ if let Some ( http) = http_proxy_config {
586
+ builder. http = http;
587
+ }
588
+ }
589
+
590
+ if builder. https . is_empty ( ) {
591
+ let https_proxy_config = parse_setting_from_dynamic_store (
592
+ & proxies_map,
593
+ unsafe { kSCPropNetProxiesHTTPSEnable } ,
594
+ unsafe { kSCPropNetProxiesHTTPSProxy } ,
595
+ unsafe { kSCPropNetProxiesHTTPSPort } ,
596
+ ) ;
597
+
598
+ if let Some ( https) = https_proxy_config {
599
+ builder. https = https;
600
+ }
601
+ }
602
+ }
603
+
604
+ fn parse_setting_from_dynamic_store (
605
+ proxies_map : & CFDictionary < CFString , CFType > ,
606
+ enabled_key : CFStringRef ,
607
+ host_key : CFStringRef ,
608
+ port_key : CFStringRef ,
609
+ ) -> Option < String > {
610
+ let proxy_enabled = proxies_map
611
+ . find ( enabled_key)
612
+ . and_then ( |flag| flag. downcast :: < CFNumber > ( ) )
613
+ . and_then ( |flag| flag. to_i32 ( ) )
614
+ . unwrap_or ( 0 )
615
+ == 1 ;
616
+
617
+ if proxy_enabled {
618
+ let proxy_host = proxies_map
619
+ . find ( host_key)
620
+ . and_then ( |host| host. downcast :: < CFString > ( ) )
621
+ . map ( |host| host. to_string ( ) ) ;
622
+ let proxy_port = proxies_map
623
+ . find ( port_key)
624
+ . and_then ( |port| port. downcast :: < CFNumber > ( ) )
625
+ . and_then ( |port| port. to_i32 ( ) ) ;
626
+
627
+ return match ( proxy_host, proxy_port) {
628
+ ( Some ( proxy_host) , Some ( proxy_port) ) => Some ( format ! ( "{proxy_host}:{proxy_port}" ) ) ,
629
+ ( Some ( proxy_host) , None ) => Some ( proxy_host) ,
630
+ ( None , Some ( _) ) => None ,
631
+ ( None , None ) => None ,
632
+ } ;
633
+ }
634
+
635
+ None
636
+ }
637
+ }
638
+
534
639
#[ cfg( test) ]
535
640
mod tests {
536
641
use super :: * ;
0 commit comments