From 2622074d43e256a6b15be16be72f72a7d66b9899 Mon Sep 17 00:00:00 2001 From: Arlo Siemsen Date: Mon, 23 May 2022 21:39:23 -0500 Subject: [PATCH] Require http-registry URLs to end with a '/' --- src/cargo/sources/registry/http_remote.rs | 28 +++++++++++++++-------- src/cargo/sources/registry/mod.rs | 5 +--- tests/testsuite/registry.rs | 13 +++++++++-- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/cargo/sources/registry/http_remote.rs b/src/cargo/sources/registry/http_remote.rs index 326c3f34855..18734ef6ba0 100644 --- a/src/cargo/sources/registry/http_remote.rs +++ b/src/cargo/sources/registry/http_remote.rs @@ -126,16 +126,25 @@ struct CompletedDownload { } impl<'cfg> HttpRegistry<'cfg> { - pub fn new(source_id: SourceId, config: &'cfg Config, name: &str) -> HttpRegistry<'cfg> { - let url = source_id - .url() - .to_string() + pub fn new( + source_id: SourceId, + config: &'cfg Config, + name: &str, + ) -> CargoResult> { + if !config.cli_unstable().http_registry { + anyhow::bail!("usage of HTTP-based registries requires `-Z http-registry`"); + } + let url = source_id.url().as_str(); + // Ensure the url ends with a slash so we can concatenate paths. + if !url.ends_with('/') { + anyhow::bail!("registry url must end in a slash `/`: {url}") + } + let url = url .trim_start_matches("sparse+") - .trim_end_matches('/') .into_url() .expect("a url with the protocol stripped should still be valid"); - HttpRegistry { + Ok(HttpRegistry { index_path: config.registry_index_path().join(name), cache_path: config.registry_cache_path().join(name), source_id, @@ -149,7 +158,7 @@ impl<'cfg> HttpRegistry<'cfg> { pending_ids: HashMap::new(), results: HashMap::new(), progress: RefCell::new(Some(Progress::with_style( - "Fetching", + "Fetch", ProgressStyle::Ratio, config, ))), @@ -159,7 +168,7 @@ impl<'cfg> HttpRegistry<'cfg> { requested_update: false, fetch_started: false, registry_config: None, - } + }) } fn handle_http_header(buf: &[u8]) -> Option<(&str, &str)> { @@ -245,7 +254,8 @@ impl<'cfg> HttpRegistry<'cfg> { } fn full_url(&self, path: &Path) -> String { - format!("{}/{}", self.url, path.display()) + // self.url always ends with a slash. + format!("{}{}", self.url, path.display()) } fn is_fresh(&self, path: &Path) -> bool { diff --git a/src/cargo/sources/registry/mod.rs b/src/cargo/sources/registry/mod.rs index fc9c29510c1..95510e313b6 100644 --- a/src/cargo/sources/registry/mod.rs +++ b/src/cargo/sources/registry/mod.rs @@ -546,10 +546,7 @@ impl<'cfg> RegistrySource<'cfg> { ) -> CargoResult> { let name = short_name(source_id); let ops = if source_id.url().scheme().starts_with("sparse+") { - if !config.cli_unstable().http_registry { - anyhow::bail!("Usage of HTTP-based registries requires `-Z http-registry`"); - } - Box::new(http_remote::HttpRegistry::new(source_id, config, &name)) as Box<_> + Box::new(http_remote::HttpRegistry::new(source_id, config, &name)?) as Box<_> } else { Box::new(remote::RemoteRegistry::new(source_id, config, &name)) as Box<_> }; diff --git a/tests/testsuite/registry.rs b/tests/testsuite/registry.rs index f9afa2919c6..7c4e3f6e07c 100644 --- a/tests/testsuite/registry.rs +++ b/tests/testsuite/registry.rs @@ -41,7 +41,7 @@ fn configure_source_replacement_for_http(addr: &str) { replace-with = 'dummy-registry' [source.dummy-registry] - registry = 'sparse+http://{}' + registry = 'sparse+http://{}/' ", addr ) @@ -2680,6 +2680,15 @@ fn http_requires_z_flag() { p.cargo("build") .with_status(101) - .with_stderr_contains(" Usage of HTTP-based registries requires `-Z http-registry`") + .with_stderr_contains(" usage of HTTP-based registries requires `-Z http-registry`") .run(); } + +#[cargo_test] +fn http_requires_trailing_slash() { + cargo_process("-Z http-registry install bar --index sparse+https://index.crates.io") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr("[ERROR] registry url must end in a slash `/`: sparse+https://index.crates.io") + .run() +}