Skip to content

Commit 41f7888

Browse files
committed
Auto merge of #11936 - ehuss:uncanonicalized-path-prefix, r=arlosi
Don't query permutations of the path prefix. This fixes the use of the `UncanonicalizedIter` to not create permutations that are not valid paths if the crate has a dash or underscore in the first four characters of the name. Previously it was permuting the path in the prefix, creating invalid paths. For example, `my-tool` would create a path like `my/_t/my-tool` which isn't valid since the filename doesn't match the prefix directories. This fixes it so that it permutes just the name, and then generates the index path *after* permuting it. The test included here goes from 16 queries to just 4 queries. Fixes #11935
2 parents 5a5c7e8 + 1ee340c commit 41f7888

File tree

3 files changed

+92
-14
lines changed

3 files changed

+92
-14
lines changed

crates/cargo-test-support/src/registry.rs

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ impl Token {
7878
}
7979
}
8080

81+
type RequestCallback = Box<dyn Send + Fn(&Request, &HttpServer) -> Response>;
82+
8183
/// A builder for initializing registries.
8284
pub struct RegistryBuilder {
8385
/// If set, configures an alternate registry with the given name.
@@ -97,7 +99,9 @@ pub struct RegistryBuilder {
9799
/// Write the registry in configuration.
98100
configure_registry: bool,
99101
/// API responders.
100-
custom_responders: HashMap<String, Box<dyn Send + Fn(&Request, &HttpServer) -> Response>>,
102+
custom_responders: HashMap<String, RequestCallback>,
103+
/// Handler for 404 responses.
104+
not_found_handler: RequestCallback,
101105
/// If nonzero, the git index update to be delayed by the given number of seconds.
102106
delayed_index_update: usize,
103107
}
@@ -149,6 +153,13 @@ impl TestRegistry {
149153
impl RegistryBuilder {
150154
#[must_use]
151155
pub fn new() -> RegistryBuilder {
156+
let not_found = |_req: &Request, _server: &HttpServer| -> Response {
157+
Response {
158+
code: 404,
159+
headers: vec![],
160+
body: b"not found".to_vec(),
161+
}
162+
};
152163
RegistryBuilder {
153164
alternative: None,
154165
token: None,
@@ -159,6 +170,7 @@ impl RegistryBuilder {
159170
configure_registry: true,
160171
configure_token: true,
161172
custom_responders: HashMap::new(),
173+
not_found_handler: Box::new(not_found),
162174
delayed_index_update: 0,
163175
}
164176
}
@@ -175,6 +187,15 @@ impl RegistryBuilder {
175187
self
176188
}
177189

190+
#[must_use]
191+
pub fn not_found_handler<R: 'static + Send + Fn(&Request, &HttpServer) -> Response>(
192+
mut self,
193+
responder: R,
194+
) -> Self {
195+
self.not_found_handler = Box::new(responder);
196+
self
197+
}
198+
178199
/// Configures the git index update to be delayed by the given number of seconds.
179200
#[must_use]
180201
pub fn delayed_index_update(mut self, delay: usize) -> Self {
@@ -276,6 +297,7 @@ impl RegistryBuilder {
276297
token.clone(),
277298
self.auth_required,
278299
self.custom_responders,
300+
self.not_found_handler,
279301
self.delayed_index_update,
280302
);
281303
let index_url = if self.http_index {
@@ -602,7 +624,8 @@ pub struct HttpServer {
602624
addr: SocketAddr,
603625
token: Token,
604626
auth_required: bool,
605-
custom_responders: HashMap<String, Box<dyn Send + Fn(&Request, &HttpServer) -> Response>>,
627+
custom_responders: HashMap<String, RequestCallback>,
628+
not_found_handler: RequestCallback,
606629
delayed_index_update: usize,
607630
}
608631

@@ -622,7 +645,8 @@ impl HttpServer {
622645
api_path: PathBuf,
623646
token: Token,
624647
auth_required: bool,
625-
api_responders: HashMap<String, Box<dyn Send + Fn(&Request, &HttpServer) -> Response>>,
648+
custom_responders: HashMap<String, RequestCallback>,
649+
not_found_handler: RequestCallback,
626650
delayed_index_update: usize,
627651
) -> HttpServerHandle {
628652
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
@@ -635,7 +659,8 @@ impl HttpServer {
635659
addr,
636660
token,
637661
auth_required,
638-
custom_responders: api_responders,
662+
custom_responders,
663+
not_found_handler,
639664
delayed_index_update,
640665
};
641666
let handle = Some(thread::spawn(move || server.start()));
@@ -928,12 +953,8 @@ impl HttpServer {
928953
}
929954

930955
/// Not found response
931-
pub fn not_found(&self, _req: &Request) -> Response {
932-
Response {
933-
code: 404,
934-
headers: vec![],
935-
body: b"not found".to_vec(),
936-
}
956+
pub fn not_found(&self, req: &Request) -> Response {
957+
(self.not_found_handler)(req, self)
937958
}
938959

939960
/// Respond OK without doing anything

src/cargo/sources/registry/index.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -360,15 +360,15 @@ impl<'cfg> RegistryIndex<'cfg> {
360360
.chars()
361361
.flat_map(|c| c.to_lowercase())
362362
.collect::<String>();
363-
let raw_path = make_dep_path(&fs_name, false);
364363

365364
let mut any_pending = false;
366365
// Attempt to handle misspellings by searching for a chain of related
367-
// names to the original `raw_path` name. Only return summaries
366+
// names to the original `fs_name` name. Only return summaries
368367
// associated with the first hit, however. The resolver will later
369368
// reject any candidates that have the wrong name, and with this it'll
370369
// along the way produce helpful "did you mean?" suggestions.
371-
for (i, path) in UncanonicalizedIter::new(&raw_path).take(1024).enumerate() {
370+
for (i, name_permutation) in UncanonicalizedIter::new(&fs_name).take(1024).enumerate() {
371+
let path = make_dep_path(&name_permutation, false);
372372
let summaries = Summaries::parse(
373373
root,
374374
&cache_root,

tests/testsuite/registry.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use cargo::core::SourceId;
44
use cargo_test_support::cargo_process;
55
use cargo_test_support::paths::{self, CargoPathExt};
66
use cargo_test_support::registry::{
7-
self, registry_path, Dependency, Package, RegistryBuilder, TestRegistry,
7+
self, registry_path, Dependency, Package, RegistryBuilder, Response, TestRegistry,
88
};
99
use cargo_test_support::{basic_manifest, project};
1010
use cargo_test_support::{git, install::cargo_home, t};
@@ -3135,3 +3135,60 @@ fn corrupted_ok_overwritten() {
31353135
p.cargo("fetch").with_stderr("").run();
31363136
assert_eq!(fs::read_to_string(&ok).unwrap(), "ok");
31373137
}
3138+
3139+
#[cargo_test]
3140+
fn not_found_permutations() {
3141+
// Test for querying permutations for a missing dependency.
3142+
let misses = Arc::new(Mutex::new(Vec::new()));
3143+
let misses2 = misses.clone();
3144+
let _registry = RegistryBuilder::new()
3145+
.http_index()
3146+
.not_found_handler(move |req, _server| {
3147+
let mut misses = misses2.lock().unwrap();
3148+
misses.push(req.url.path().to_string());
3149+
Response {
3150+
code: 404,
3151+
headers: vec![],
3152+
body: b"not found".to_vec(),
3153+
}
3154+
})
3155+
.build();
3156+
3157+
let p = project()
3158+
.file(
3159+
"Cargo.toml",
3160+
r#"
3161+
[package]
3162+
name = "foo"
3163+
version = "0.0.1"
3164+
authors = []
3165+
3166+
[dependencies]
3167+
a-b-c = "1.0"
3168+
"#,
3169+
)
3170+
.file("src/lib.rs", "")
3171+
.build();
3172+
3173+
p.cargo("check")
3174+
.with_status(101)
3175+
.with_stderr(
3176+
"\
3177+
[UPDATING] `dummy-registry` index
3178+
error: no matching package named `a-b-c` found
3179+
location searched: registry `crates-io`
3180+
required by package `foo v0.0.1 ([ROOT]/foo)`
3181+
",
3182+
)
3183+
.run();
3184+
let misses = misses.lock().unwrap();
3185+
assert_eq!(
3186+
&*misses,
3187+
&[
3188+
"/index/a-/b-/a-b-c",
3189+
"/index/a_/b-/a_b-c",
3190+
"/index/a-/b_/a-b_c",
3191+
"/index/a_/b_/a_b_c"
3192+
]
3193+
);
3194+
}

0 commit comments

Comments
 (0)