@@ -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,93 @@ 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,
568
+ kSCPropNetProxiesHTTPPort,
569
+ kSCPropNetProxiesHTTPProxy,
570
+ kSCPropNetProxiesHTTPSEnable,
571
+ kSCPropNetProxiesHTTPSPort,
572
+ kSCPropNetProxiesHTTPSProxy,
573
+ } ;
574
+
575
+ pub ( super ) fn with_system ( builder : & mut super :: Builder ) {
576
+ let store = SCDynamicStoreBuilder :: new ( "" ) . build ( ) ;
577
+
578
+ let proxies_map = if let Some ( proxies_map) = store. get_proxies ( ) {
579
+ proxies_map
580
+ } else {
581
+ return ;
582
+ } ;
583
+
584
+ if builder. http . is_empty ( ) {
585
+ let http_proxy_config = parse_setting_from_dynamic_store (
586
+ & proxies_map,
587
+ unsafe { kSCPropNetProxiesHTTPEnable } ,
588
+ unsafe { kSCPropNetProxiesHTTPProxy } ,
589
+ unsafe { kSCPropNetProxiesHTTPPort } ,
590
+ ) ;
591
+ if let Some ( http) = http_proxy_config {
592
+ builder. http = http;
593
+ }
594
+ }
595
+
596
+ if builder. https . is_empty ( ) {
597
+ let https_proxy_config = parse_setting_from_dynamic_store (
598
+ & proxies_map,
599
+ unsafe { kSCPropNetProxiesHTTPSEnable } ,
600
+ unsafe { kSCPropNetProxiesHTTPSProxy } ,
601
+ unsafe { kSCPropNetProxiesHTTPSPort } ,
602
+ ) ;
603
+
604
+ if let Some ( https) = https_proxy_config {
605
+ builder. https = https;
606
+ }
607
+ }
608
+ }
609
+
610
+ fn parse_setting_from_dynamic_store (
611
+ proxies_map : & CFDictionary < CFString , CFType > ,
612
+ enabled_key : CFStringRef ,
613
+ host_key : CFStringRef ,
614
+ port_key : CFStringRef ,
615
+ ) -> Option < String > {
616
+ let proxy_enabled = proxies_map
617
+ . find ( enabled_key)
618
+ . and_then ( |flag| flag. downcast :: < CFNumber > ( ) )
619
+ . and_then ( |flag| flag. to_i32 ( ) )
620
+ . unwrap_or ( 0 )
621
+ == 1 ;
622
+
623
+ if proxy_enabled {
624
+ let proxy_host = proxies_map
625
+ . find ( host_key)
626
+ . and_then ( |host| host. downcast :: < CFString > ( ) )
627
+ . map ( |host| host. to_string ( ) ) ;
628
+ let proxy_port = proxies_map
629
+ . find ( port_key)
630
+ . and_then ( |port| port. downcast :: < CFNumber > ( ) )
631
+ . and_then ( |port| port. to_i32 ( ) ) ;
632
+
633
+ return match ( proxy_host, proxy_port) {
634
+ ( Some ( proxy_host) , Some ( proxy_port) ) => Some ( format ! ( "{proxy_host}:{proxy_port}" ) ) ,
635
+ ( Some ( proxy_host) , None ) => Some ( proxy_host) ,
636
+ ( None , Some ( _) ) => None ,
637
+ ( None , None ) => None ,
638
+ } ;
639
+ }
640
+
641
+ None
642
+ }
643
+ }
644
+
534
645
#[ cfg( test) ]
535
646
mod tests {
536
647
use super :: * ;
0 commit comments