Skip to content

Commit 35b806a

Browse files
committed
fix: disable multiplexing on macOS for bad curl
In certain versions of libcurl when proxy is in use with HTTP/2 multiplexing, connections will continue stacking up. This was fixed in libcurl 8.0.0 in curl/curl@821f6e2 However, a custom built Cargo can still link against old system libcurl. Multiplexing needs to be disabled when those versions are detected. We only take care of macOS now, since it is one of the major platforms. For other OS we encourage not to stick to older versions of licurl.
1 parent a2e6862 commit 35b806a

File tree

1 file changed

+84
-12
lines changed

1 file changed

+84
-12
lines changed

Diff for: src/cargo/util/config/mod.rs

+84-12
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ use crate::core::{features, CliUnstable, Shell, SourceId, Workspace, WorkspaceRo
7272
use crate::ops::{self, RegistryCredentialConfig};
7373
use crate::util::auth::Secret;
7474
use crate::util::errors::CargoResult;
75+
use crate::util::network;
7576
use crate::util::CanonicalUrl;
7677
use crate::util::{internal, toml as cargo_toml};
7778
use crate::util::{try_canonicalize, validate_package_name};
@@ -1717,18 +1718,16 @@ impl Config {
17171718
}
17181719

17191720
pub fn http_config(&self) -> CargoResult<&CargoHttpConfig> {
1720-
self.http_config
1721-
.try_borrow_with(|| {
1722-
let http_config = self.get::<CargoHttpConfig>("http")?;
1723-
if cfg!(target_os = "macos") {
1724-
let versions = ["7.87", "7.88"];
1725-
let curl_v = curl::Version::get().version();
1726-
if versions.iter().any(|v| curl_v.starts_with(v)) {
1727-
http_config.multiplexing = Some(false);
1728-
}
1729-
}
1730-
Ok(http_config)
1731-
})
1721+
self.http_config.try_borrow_with(|| {
1722+
let http = self.get::<CargoHttpConfig>("http")?;
1723+
#[cfg(target_os = "macos")]
1724+
{
1725+
let mut http = http;
1726+
let curl_v = curl::Version::get();
1727+
disables_multiplexing_for_bad_curl(curl_v.version(), &mut http, self);
1728+
}
1729+
Ok(http)
1730+
})
17321731
}
17331732

17341733
pub fn future_incompat_config(&self) -> CargoResult<&CargoFutureIncompatConfig> {
@@ -2760,3 +2759,76 @@ impl Tool {
27602759
}
27612760
}
27622761
}
2762+
2763+
/// Disable HTTP/2 multiplexing for some broken versions of libcurl.
2764+
///
2765+
/// In certain versions of libcurl when proxy is in use with HTTP/2
2766+
/// multiplexing, connections will continue stacking up. This was
2767+
/// fixed in libcurl 8.0.0 in curl/curl@821f6e2a89de8aec1c7da3c0f381b92b2b801efc
2768+
///
2769+
/// However, a custom built Cargo can still link against old system libcurl.
2770+
/// Multiplexing needs to be disabled when those versions are detected.
2771+
///
2772+
/// We only take care of macOS now, since it is one of the major platforms.
2773+
/// For other OS we encourage not to stick to older versions of licurl.
2774+
#[cfg(target_os = "macos")]
2775+
fn disables_multiplexing_for_bad_curl(
2776+
curl_version: &str,
2777+
http: &mut CargoHttpConfig,
2778+
config: &Config,
2779+
) {
2780+
if network::proxy::http_proxy_exists(http, config) && http.multiplexing.is_none() {
2781+
let bad_curl_versions = ["7.87", "7.88"];
2782+
if bad_curl_versions
2783+
.iter()
2784+
.any(|v| curl_version.starts_with(v))
2785+
{
2786+
http.multiplexing = Some(false);
2787+
}
2788+
}
2789+
}
2790+
2791+
#[cfg(test)]
2792+
mod tests {
2793+
use super::disables_multiplexing_for_bad_curl;
2794+
use super::CargoHttpConfig;
2795+
use super::Config;
2796+
use super::Shell;
2797+
2798+
#[cfg(target_os = "macos")]
2799+
#[test]
2800+
fn disables_multiplexing() {
2801+
let mut config = Config::new(Shell::new(), "".into(), "".into());
2802+
config.set_search_stop_path(std::path::PathBuf::new());
2803+
config.set_env(Default::default());
2804+
2805+
let mut http = CargoHttpConfig::default();
2806+
http.proxy = Some("127.0.0.1:3128".into());
2807+
disables_multiplexing_for_bad_curl("7.88.1", &mut http, &config);
2808+
assert_eq!(http.multiplexing, Some(false));
2809+
2810+
let cases = [
2811+
(None, None, "7.87.0", None),
2812+
(None, None, "7.88.0", None),
2813+
(None, None, "7.88.1", None),
2814+
(None, None, "8.0.0", None),
2815+
(Some("".into()), None, "7.87.0", Some(false)),
2816+
(Some("".into()), None, "7.88.0", Some(false)),
2817+
(Some("".into()), None, "7.88.1", Some(false)),
2818+
(Some("".into()), None, "8.0.0", None),
2819+
(Some("".into()), Some(false), "7.87.0", Some(false)),
2820+
(Some("".into()), Some(false), "7.88.0", Some(false)),
2821+
(Some("".into()), Some(false), "7.88.1", Some(false)),
2822+
(Some("".into()), Some(false), "8.0.0", Some(false)),
2823+
];
2824+
for (proxy, multiplexing, curl_v, result) in cases {
2825+
let mut http = CargoHttpConfig {
2826+
multiplexing,
2827+
proxy,
2828+
..Default::default()
2829+
};
2830+
disables_multiplexing_for_bad_curl(curl_v, &mut http, &config);
2831+
assert_eq!(http.multiplexing, result);
2832+
}
2833+
}
2834+
}

0 commit comments

Comments
 (0)