@@ -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,86 @@ 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 =
776+ WindowsProxy :: from_proxy_server_setting ( "http=127.0.0.1:8080;https=127.0.0.1:8443" ) ;
777+ assert_eq ! ( proxy. http. as_deref( ) , Some ( "127.0.0.1:8080" ) ) ;
778+ assert_eq ! ( proxy. https. as_deref( ) , Some ( "127.0.0.1:8443" ) ) ;
779+ assert_eq ! ( proxy. all, None ) ;
780+ }
781+
782+ #[ test]
783+ fn socks_is_normalized_to_socks5_and_stored_as_all ( ) {
784+ let proxy = WindowsProxy :: from_proxy_server_setting ( "socks=127.0.0.1:1080" ) ;
785+ assert_eq ! ( proxy. http, None ) ;
786+ assert_eq ! ( proxy. https, None ) ;
787+ assert_eq ! ( proxy. all. as_deref( ) , Some ( "socks5://127.0.0.1:1080" ) ) ;
788+ }
789+
790+ #[ test]
791+ fn socks_with_existing_scheme_is_rewritten_to_socks5 ( ) {
792+ let proxy = WindowsProxy :: from_proxy_server_setting ( "socks=socks://127.0.0.1:1080" ) ;
793+ assert_eq ! ( proxy. all. as_deref( ) , Some ( "socks5://127.0.0.1:1080" ) ) ;
794+ }
795+
796+ #[ test]
797+ fn all_schemes_together ( ) {
798+ let proxy = WindowsProxy :: from_proxy_server_setting (
799+ "http=10.0.0.1:8080;https=10.0.0.1:8443;socks=10.0.0.1:1080" ,
800+ ) ;
801+ assert_eq ! ( proxy. http. as_deref( ) , Some ( "10.0.0.1:8080" ) ) ;
802+ assert_eq ! ( proxy. https. as_deref( ) , Some ( "10.0.0.1:8443" ) ) ;
803+ assert_eq ! ( proxy. all. as_deref( ) , Some ( "socks5://10.0.0.1:1080" ) ) ;
804+ }
805+
806+ #[ test]
807+ fn single_proxy_without_scheme_goes_to_all ( ) {
808+ let proxy = WindowsProxy :: from_proxy_server_setting ( "127.0.0.1:8080" ) ;
809+ assert_eq ! ( proxy. http, None ) ;
810+ assert_eq ! ( proxy. https, None ) ;
811+ assert_eq ! ( proxy. all. as_deref( ) , Some ( "127.0.0.1:8080" ) ) ;
812+ }
813+
814+ #[ test]
815+ fn unknown_schemes_are_ignored ( ) {
816+ let proxy = WindowsProxy :: from_proxy_server_setting ( "ftp=127.0.0.1:8021" ) ;
817+ assert_eq ! ( proxy. http, None ) ;
818+ assert_eq ! ( proxy. https, None ) ;
819+ assert_eq ! ( proxy. all, None ) ;
820+ }
821+
822+ #[ test]
823+ fn whitespace_and_empty_segments_are_ignored ( ) {
824+ let proxy = WindowsProxy :: from_proxy_server_setting ( " http=127.0.0.1:8080 ; ; " ) ;
825+ assert_eq ! ( proxy. http. as_deref( ) , Some ( "127.0.0.1:8080" ) ) ;
826+ assert_eq ! ( proxy. https, None ) ;
827+ assert_eq ! ( proxy. all, None ) ;
828+ }
829+
830+ #[ test]
831+ fn trailing_separator_does_not_clobber_socks ( ) {
832+ let proxy = WindowsProxy :: from_proxy_server_setting ( "socks=127.0.0.1:1080;" ) ;
833+ assert_eq ! ( proxy. all. as_deref( ) , Some ( "socks5://127.0.0.1:1080" ) ) ;
834+ }
835+
836+ #[ test]
837+ fn uri_from_schema_and_authority_strips_existing_scheme ( ) {
838+ assert_eq ! (
839+ WindowsProxy :: uri_from_schema_and_authority( "socks5" , "127.0.0.1:1080" ) ,
840+ "socks5://127.0.0.1:1080"
841+ ) ;
842+ assert_eq ! (
843+ WindowsProxy :: uri_from_schema_and_authority( "socks5" , "socks://127.0.0.1:1080" ) ,
844+ "socks5://127.0.0.1:1080"
845+ ) ;
846+ }
847+ }
698848}
699849
700850#[ cfg( test) ]
0 commit comments