@@ -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 > {
@@ -2750,3 +2754,76 @@ impl Tool {
27502754 }
27512755 }
27522756}
2757+
2758+ /// Disable HTTP/2 multiplexing for some broken versions of libcurl.
2759+ ///
2760+ /// In certain versions of libcurl when proxy is in use with HTTP/2
2761+ /// multiplexing, connections will continue stacking up. This was
2762+ /// fixed in libcurl 8.0.0 in curl/curl@821f6e2a89de8aec1c7da3c0f381b92b2b801efc
2763+ ///
2764+ /// However, Cargo can still link against old system libcurl if it is from a
2765+ /// custom built one or on macOS. For those cases, multiplexing needs to be
2766+ /// disabled when those versions are detected.
2767+ fn disables_multiplexing_for_bad_curl (
2768+ curl_version : & str ,
2769+ http : & mut CargoHttpConfig ,
2770+ config : & Config ,
2771+ ) {
2772+ use crate :: util:: network;
2773+
2774+ if network:: proxy:: http_proxy_exists ( http, config) && http. multiplexing . is_none ( ) {
2775+ let bad_curl_versions = [ "7.87.0" , "7.88.0" , "7.88.1" ] ;
2776+ if bad_curl_versions
2777+ . iter ( )
2778+ . any ( |v| curl_version. starts_with ( v) )
2779+ {
2780+ log:: info!( "disabling multiplexing with proxy, curl version is {curl_version}" ) ;
2781+ http. multiplexing = Some ( false ) ;
2782+ }
2783+ }
2784+ }
2785+
2786+ #[ cfg( test) ]
2787+ mod tests {
2788+ use super :: disables_multiplexing_for_bad_curl;
2789+ use super :: CargoHttpConfig ;
2790+ use super :: Config ;
2791+ use super :: Shell ;
2792+
2793+ #[ test]
2794+ fn disables_multiplexing ( ) {
2795+ let mut config = Config :: new ( Shell :: new ( ) , "" . into ( ) , "" . into ( ) ) ;
2796+ config. set_search_stop_path ( std:: path:: PathBuf :: new ( ) ) ;
2797+ config. set_env ( Default :: default ( ) ) ;
2798+
2799+ let mut http = CargoHttpConfig :: default ( ) ;
2800+ http. proxy = Some ( "127.0.0.1:3128" . into ( ) ) ;
2801+ disables_multiplexing_for_bad_curl ( "7.88.1" , & mut http, & config) ;
2802+ assert_eq ! ( http. multiplexing, Some ( false ) ) ;
2803+
2804+ let cases = [
2805+ ( None , None , "7.87.0" , None ) ,
2806+ ( None , None , "7.88.0" , None ) ,
2807+ ( None , None , "7.88.1" , None ) ,
2808+ ( None , None , "8.0.0" , None ) ,
2809+ ( Some ( "" . into ( ) ) , None , "7.87.0" , Some ( false ) ) ,
2810+ ( Some ( "" . into ( ) ) , None , "7.88.0" , Some ( false ) ) ,
2811+ ( Some ( "" . into ( ) ) , None , "7.88.1" , Some ( false ) ) ,
2812+ ( Some ( "" . into ( ) ) , None , "8.0.0" , None ) ,
2813+ ( Some ( "" . into ( ) ) , Some ( false ) , "7.87.0" , Some ( false ) ) ,
2814+ ( Some ( "" . into ( ) ) , Some ( false ) , "7.88.0" , Some ( false ) ) ,
2815+ ( Some ( "" . into ( ) ) , Some ( false ) , "7.88.1" , Some ( false ) ) ,
2816+ ( Some ( "" . into ( ) ) , Some ( false ) , "8.0.0" , Some ( false ) ) ,
2817+ ] ;
2818+
2819+ for ( proxy, multiplexing, curl_v, result) in cases {
2820+ let mut http = CargoHttpConfig {
2821+ multiplexing,
2822+ proxy,
2823+ ..Default :: default ( )
2824+ } ;
2825+ disables_multiplexing_for_bad_curl ( curl_v, & mut http, & config) ;
2826+ assert_eq ! ( http. multiplexing, result) ;
2827+ }
2828+ }
2829+ }
0 commit comments