Skip to content

Commit 0a3c39b

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 0a3c39b

File tree

1 file changed

+83
-12
lines changed

1 file changed

+83
-12
lines changed

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

+83-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,15 @@ 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 mut http = self.get::<CargoHttpConfig>("http")?;
1723+
#[cfg(target_os = "macos")]
1724+
{
1725+
let curl_v = curl::Version::get();
1726+
disables_multiplexing_for_bad_curl(curl_v.version(), &mut http, self);
1727+
}
1728+
Ok(http)
1729+
})
17321730
}
17331731

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

0 commit comments

Comments
 (0)