@@ -662,6 +662,66 @@ mod mac {
662662#[ cfg( feature = "client-proxy-system" ) ]
663663#[ cfg( windows) ]
664664mod win {
665+
666+ struct WindowsProxy {
667+ http : Option < String > ,
668+ https : Option < String > ,
669+ all : Option < String > ,
670+ }
671+
672+ const HTTP_SCHEME : & str = "http" ;
673+ const HTTPS_SCHEME : & str = "https" ;
674+ const SOCKS_SCHEME : & str = "socks" ;
675+
676+ const SOCKS_WINDOWS_MAP_TO : & str = "socks5" ;
677+
678+ impl WindowsProxy {
679+ fn uri_from_schema_and_authority ( scheme : & str , authority : & str ) -> String {
680+ let safe_authority = authority
681+ . split_once ( "://" )
682+ . map ( |( _scheme, authority) | authority)
683+ . unwrap_or ( authority) ;
684+ format ! ( "{scheme}://{safe_authority}" )
685+ }
686+
687+ fn from_proxy_server_setting ( proxy_server_setting : & str ) -> Self {
688+ let mut http = None ;
689+ let mut https = None ;
690+ let mut all = None ;
691+ for proxy in proxy_server_setting
692+ . split ( ';' )
693+ . map ( str:: trim)
694+ . filter ( |p| !p. is_empty ( ) )
695+ {
696+ let schema_authority = proxy
697+ . split_once ( '=' )
698+ . map ( |( a, b) | ( Some ( a) , Some ( b) ) )
699+ . unwrap_or ( ( None , None ) ) ;
700+ match schema_authority {
701+ ( Some ( HTTP_SCHEME ) , Some ( authority) ) => http = Some ( authority. to_owned ( ) ) ,
702+ ( Some ( HTTPS_SCHEME ) , Some ( authority) ) => https = Some ( authority. to_owned ( ) ) ,
703+ ( Some ( SOCKS_SCHEME ) , Some ( authority) ) => {
704+ all = Some ( Self :: uri_from_schema_and_authority (
705+ SOCKS_WINDOWS_MAP_TO ,
706+ authority,
707+ ) )
708+ }
709+ // What to do if a non-schemed proxy is there? Set all, or http and https
710+ // Lets set all so http and https can override later on Matcher's build
711+ ( None , None ) => all = Some ( proxy. into ( ) ) ,
712+ _ => { }
713+ }
714+ }
715+ Self { http, https, all }
716+ }
717+ }
718+
719+ impl From < String > for WindowsProxy {
720+ fn from ( value : String ) -> Self {
721+ Self :: from_proxy_server_setting ( value. as_str ( ) )
722+ }
723+ }
724+
665725 pub ( super ) fn with_system ( builder : & mut super :: Builder ) {
666726 let settings = if let Ok ( settings) = windows_registry:: CURRENT_USER
667727 . open ( "Software\\ Microsoft\\ Windows\\ CurrentVersion\\ Internet Settings" )
@@ -676,11 +736,21 @@ mod win {
676736 }
677737
678738 if let Ok ( val) = settings. get_string ( "ProxyServer" ) {
679- if builder. http . is_empty ( ) {
680- builder. http = val. clone ( ) ;
739+ let windows_proxy: WindowsProxy = val. into ( ) ;
740+ if let Some ( val) = windows_proxy. http {
741+ if builder. http . is_empty ( ) {
742+ builder. http = val;
743+ }
681744 }
682- if builder. https . is_empty ( ) {
683- builder. https = val;
745+ if let Some ( val) = windows_proxy. https {
746+ if builder. https . is_empty ( ) {
747+ builder. https = val;
748+ }
749+ }
750+ if let Some ( val) = windows_proxy. all {
751+ if builder. all . is_empty ( ) {
752+ builder. all = val;
753+ }
684754 }
685755 }
686756
@@ -695,6 +765,85 @@ mod win {
695765 }
696766 }
697767 }
768+
769+ #[ cfg( test) ]
770+ mod tests {
771+ use super :: WindowsProxy ;
772+
773+ #[ test]
774+ fn per_scheme_values_go_to_their_own_slots ( ) {
775+ let proxy = WindowsProxy :: from_proxy_server_setting ( "http=127.0.0.1:8080;https=127.0.0.1:8443" ) ;
776+ assert_eq ! ( proxy. http. as_deref( ) , Some ( "127.0.0.1:8080" ) ) ;
777+ assert_eq ! ( proxy. https. as_deref( ) , Some ( "127.0.0.1:8443" ) ) ;
778+ assert_eq ! ( proxy. all, None ) ;
779+ }
780+
781+ #[ test]
782+ fn socks_is_normalized_to_socks5_and_stored_as_all ( ) {
783+ let proxy = WindowsProxy :: from_proxy_server_setting ( "socks=127.0.0.1:1080" ) ;
784+ assert_eq ! ( proxy. http, None ) ;
785+ assert_eq ! ( proxy. https, None ) ;
786+ assert_eq ! ( proxy. all. as_deref( ) , Some ( "socks5://127.0.0.1:1080" ) ) ;
787+ }
788+
789+ #[ test]
790+ fn socks_with_existing_scheme_is_rewritten_to_socks5 ( ) {
791+ let proxy = WindowsProxy :: from_proxy_server_setting ( "socks=socks://127.0.0.1:1080" ) ;
792+ assert_eq ! ( proxy. all. as_deref( ) , Some ( "socks5://127.0.0.1:1080" ) ) ;
793+ }
794+
795+ #[ test]
796+ fn all_schemes_together ( ) {
797+ let proxy = WindowsProxy :: from_proxy_server_setting (
798+ "http=10.0.0.1:8080;https=10.0.0.1:8443;socks=10.0.0.1:1080" ,
799+ ) ;
800+ assert_eq ! ( proxy. http. as_deref( ) , Some ( "10.0.0.1:8080" ) ) ;
801+ assert_eq ! ( proxy. https. as_deref( ) , Some ( "10.0.0.1:8443" ) ) ;
802+ assert_eq ! ( proxy. all. as_deref( ) , Some ( "socks5://10.0.0.1:1080" ) ) ;
803+ }
804+
805+ #[ test]
806+ fn single_proxy_without_scheme_goes_to_all ( ) {
807+ let proxy = WindowsProxy :: from_proxy_server_setting ( "127.0.0.1:8080" ) ;
808+ assert_eq ! ( proxy. http, None ) ;
809+ assert_eq ! ( proxy. https, None ) ;
810+ assert_eq ! ( proxy. all. as_deref( ) , Some ( "127.0.0.1:8080" ) ) ;
811+ }
812+
813+ #[ test]
814+ fn unknown_schemes_are_ignored ( ) {
815+ let proxy = WindowsProxy :: from_proxy_server_setting ( "ftp=127.0.0.1:8021" ) ;
816+ assert_eq ! ( proxy. http, None ) ;
817+ assert_eq ! ( proxy. https, None ) ;
818+ assert_eq ! ( proxy. all, None ) ;
819+ }
820+
821+ #[ test]
822+ fn whitespace_and_empty_segments_are_ignored ( ) {
823+ let proxy = WindowsProxy :: from_proxy_server_setting ( " http=127.0.0.1:8080 ; ; " ) ;
824+ assert_eq ! ( proxy. http. as_deref( ) , Some ( "127.0.0.1:8080" ) ) ;
825+ assert_eq ! ( proxy. https, None ) ;
826+ assert_eq ! ( proxy. all, None ) ;
827+ }
828+
829+ #[ test]
830+ fn trailing_separator_does_not_clobber_socks ( ) {
831+ let proxy = WindowsProxy :: from_proxy_server_setting ( "socks=127.0.0.1:1080;" ) ;
832+ assert_eq ! ( proxy. all. as_deref( ) , Some ( "socks5://127.0.0.1:1080" ) ) ;
833+ }
834+
835+ #[ test]
836+ fn uri_from_schema_and_authority_strips_existing_scheme ( ) {
837+ assert_eq ! (
838+ WindowsProxy :: uri_from_schema_and_authority( "socks5" , "127.0.0.1:1080" ) ,
839+ "socks5://127.0.0.1:1080"
840+ ) ;
841+ assert_eq ! (
842+ WindowsProxy :: uri_from_schema_and_authority( "socks5" , "socks://127.0.0.1:1080" ) ,
843+ "socks5://127.0.0.1:1080"
844+ ) ;
845+ }
846+ }
698847}
699848
700849#[ cfg( test) ]
0 commit comments