Apply percent-decoding to file-based URLs (#1541)

## Summary

Closes https://github.com/astral-sh/uv/issues/1537.
This commit is contained in:
Charlie Marsh 2024-02-16 16:11:16 -05:00 committed by GitHub
parent a97c207674
commit 01ffc36520
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 27 additions and 2 deletions

7
Cargo.lock generated
View file

@ -4054,6 +4054,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]] [[package]]
name = "usvg" name = "usvg"
version = "0.29.0" version = "0.29.0"
@ -4409,6 +4415,7 @@ dependencies = [
"junction", "junction",
"tempfile", "tempfile",
"tracing", "tracing",
"urlencoding",
"uv-warnings", "uv-warnings",
] ]

View file

@ -105,6 +105,7 @@ tracing-tree = { version = "0.3.0" }
unicode-width = { version = "0.1.11" } unicode-width = { version = "0.1.11" }
unscanny = { version = "0.1.0" } unscanny = { version = "0.1.0" }
url = { version = "2.5.0" } url = { version = "2.5.0" }
urlencoding = { version = "2.1.3" }
uuid = { version = "1.7.0", default-features = false } uuid = { version = "1.7.0", default-features = false }
walkdir = { version = "2.4.0" } walkdir = { version = "2.4.0" }
which = { version = "6.0.0" } which = { version = "6.0.0" }

View file

@ -21,6 +21,7 @@ fs2 = { workspace = true }
junction = { workspace = true } junction = { workspace = true }
tempfile = { workspace = true } tempfile = { workspace = true }
tracing = { workspace = true } tracing = { workspace = true }
urlencoding = { workspace = true }
[features] [features]
default = [] default = []

View file

@ -31,14 +31,18 @@ impl<T: AsRef<Path>> Normalized for T {
/// ///
/// On other platforms, this is a no-op. /// On other platforms, this is a no-op.
pub fn normalize_url_path(path: &str) -> Cow<'_, str> { pub fn normalize_url_path(path: &str) -> Cow<'_, str> {
// Apply percent-decoding to the URL.
let path = urlencoding::decode(path).unwrap_or(Cow::Borrowed(path));
// Return the path.
if cfg!(windows) { if cfg!(windows) {
Cow::Owned( Cow::Owned(
path.strip_prefix('/') path.strip_prefix('/')
.unwrap_or(path) .unwrap_or(&path)
.replace('/', std::path::MAIN_SEPARATOR_STR), .replace('/', std::path::MAIN_SEPARATOR_STR),
) )
} else { } else {
Cow::Borrowed(path) path
} }
} }
@ -71,5 +75,17 @@ mod tests {
"./ferris/wheel-0.42.0.tar.gz" "./ferris/wheel-0.42.0.tar.gz"
); );
} }
if cfg!(windows) {
assert_eq!(
normalize_url_path("./wheel%20cache/wheel-0.42.0.tar.gz"),
".\\wheel cache\\wheel-0.42.0.tar.gz"
);
} else {
assert_eq!(
normalize_url_path("./wheel%20cache/wheel-0.42.0.tar.gz"),
"./wheel cache/wheel-0.42.0.tar.gz"
);
}
} }
} }