@@ -1717,8 +1717,12 @@ impl Config {
17171717 }
17181718
17191719 pub fn http_config ( & self ) -> CargoResult < & CargoHttpConfig > {
1720- self . http_config
1721- . try_borrow_with ( || self . get :: < CargoHttpConfig > ( "http" ) )
1720+ self . http_config . try_borrow_with ( || {
1721+ let mut http = self . get :: < CargoHttpConfig > ( "http" ) ?;
1722+ let curl_v = curl:: Version :: get ( ) ;
1723+ disables_multiplexing_for_bad_curl ( curl_v. version ( ) , & mut http, self ) ;
1724+ Ok ( http)
1725+ } )
17221726 }
17231727
17241728 pub fn future_incompat_config ( & self ) -> CargoResult < & CargoFutureIncompatConfig > {
@@ -2731,3 +2735,76 @@ impl Tool {
27312735 }
27322736 }
27332737}
2738+
2739+ /// Disable HTTP/2 multiplexing for some broken versions of libcurl.
2740+ ///
2741+ /// In certain versions of libcurl when proxy is in use with HTTP/2
2742+ /// multiplexing, connections will continue stacking up. This was
2743+ /// fixed in libcurl 8.0.0 in curl/curl@821f6e2a89de8aec1c7da3c0f381b92b2b801efc
2744+ ///
2745+ /// However, Cargo can still link against old system libcurl if it is from a
2746+ /// custom built one or on macOS. For those cases, multiplexing needs to be
2747+ /// disabled when those versions are detected.
2748+ fn disables_multiplexing_for_bad_curl (
2749+ curl_version : & str ,
2750+ http : & mut CargoHttpConfig ,
2751+ config : & Config ,
2752+ ) {
2753+ use crate :: util:: network;
2754+
2755+ if network:: proxy:: http_proxy_exists ( http, config) && http. multiplexing . is_none ( ) {
2756+ let bad_curl_versions = [ "7.87.0" , "7.88.0" , "7.88.1" ] ;
2757+ if bad_curl_versions
2758+ . iter ( )
2759+ . any ( |v| curl_version. starts_with ( v) )
2760+ {
2761+ log:: info!( "disabling multiplexing with proxy, curl version is {curl_version}" ) ;
2762+ http. multiplexing = Some ( false ) ;
2763+ }
2764+ }
2765+ }
2766+
2767+ #[ cfg( test) ]
2768+ mod tests {
2769+ use super :: disables_multiplexing_for_bad_curl;
2770+ use super :: CargoHttpConfig ;
2771+ use super :: Config ;
2772+ use super :: Shell ;
2773+
2774+ #[ test]
2775+ fn disables_multiplexing ( ) {
2776+ let mut config = Config :: new ( Shell :: new ( ) , "" . into ( ) , "" . into ( ) ) ;
2777+ config. set_search_stop_path ( std:: path:: PathBuf :: new ( ) ) ;
2778+ config. set_env ( Default :: default ( ) ) ;
2779+
2780+ let mut http = CargoHttpConfig :: default ( ) ;
2781+ http. proxy = Some ( "127.0.0.1:3128" . into ( ) ) ;
2782+ disables_multiplexing_for_bad_curl ( "7.88.1" , & mut http, & config) ;
2783+ assert_eq ! ( http. multiplexing, Some ( false ) ) ;
2784+
2785+ let cases = [
2786+ ( None , None , "7.87.0" , None ) ,
2787+ ( None , None , "7.88.0" , None ) ,
2788+ ( None , None , "7.88.1" , None ) ,
2789+ ( None , None , "8.0.0" , None ) ,
2790+ ( Some ( "" . into ( ) ) , None , "7.87.0" , Some ( false ) ) ,
2791+ ( Some ( "" . into ( ) ) , None , "7.88.0" , Some ( false ) ) ,
2792+ ( Some ( "" . into ( ) ) , None , "7.88.1" , Some ( false ) ) ,
2793+ ( Some ( "" . into ( ) ) , None , "8.0.0" , None ) ,
2794+ ( Some ( "" . into ( ) ) , Some ( false ) , "7.87.0" , Some ( false ) ) ,
2795+ ( Some ( "" . into ( ) ) , Some ( false ) , "7.88.0" , Some ( false ) ) ,
2796+ ( Some ( "" . into ( ) ) , Some ( false ) , "7.88.1" , Some ( false ) ) ,
2797+ ( Some ( "" . into ( ) ) , Some ( false ) , "8.0.0" , Some ( false ) ) ,
2798+ ] ;
2799+
2800+ for ( proxy, multiplexing, curl_v, result) in cases {
2801+ let mut http = CargoHttpConfig {
2802+ multiplexing,
2803+ proxy,
2804+ ..Default :: default ( )
2805+ } ;
2806+ disables_multiplexing_for_bad_curl ( curl_v, & mut http, & config) ;
2807+ assert_eq ! ( http. multiplexing, result) ;
2808+ }
2809+ }
2810+ }
0 commit comments