diff --git a/gix-url/src/parse.rs b/gix-url/src/parse.rs index e6496ccf48a..f4cf870571c 100644 --- a/gix-url/src/parse.rs +++ b/gix-url/src/parse.rs @@ -114,19 +114,26 @@ pub(crate) fn url(input: &BStr, protocol_end: usize) -> Result String { - percent_decode_str(s) +fn percent_decoded_utf8(s: &str, kind: UrlKind) -> Result { + Ok(percent_decode_str(s) .decode_utf8() - .expect("it's not possible to sneak illegal UTF8 into a URL") - .into_owned() + .map_err(|err| Error::Utf8 { + url: s.into(), + kind, + source: err, + })? + .into_owned()) } pub(crate) fn scp(input: &BStr, colon: usize) -> Result { @@ -157,19 +164,22 @@ pub(crate) fn scp(input: &BStr, colon: usize) -> Result { Ok(crate::Url { serialize_alternative_form: true, scheme: url.scheme().into(), - user: url_user(&url), - password: url.password().map(percent_decoded_utf8), + user: url_user(&url, UrlKind::Scp)?, + password: url + .password() + .map(|s| percent_decoded_utf8(s, UrlKind::Scp)) + .transpose()?, host: url.host_str().map(Into::into), port: url.port(), path: path.into(), }) } -fn url_user(url: &url::Url) -> Option { +fn url_user(url: &url::Url, kind: UrlKind) -> Result, Error> { if url.username().is_empty() && url.password().is_none() { - None + Ok(None) } else { - Some(percent_decoded_utf8(url.username())) + Ok(Some(percent_decoded_utf8(url.username(), kind)?)) } } diff --git a/gix-url/tests/fixtures/fuzzed/illegal-utf8.url b/gix-url/tests/fixtures/fuzzed/illegal-utf8.url new file mode 100644 index 00000000000..be44c9dd267 --- /dev/null +++ b/gix-url/tests/fixtures/fuzzed/illegal-utf8.url @@ -0,0 +1 @@ +BBi%BBBBB,@}:m\ \ No newline at end of file diff --git a/gix-url/tests/access/mod.rs b/gix-url/tests/url/access.rs similarity index 100% rename from gix-url/tests/access/mod.rs rename to gix-url/tests/url/access.rs diff --git a/gix-url/tests/baseline.rs b/gix-url/tests/url/baseline.rs similarity index 99% rename from gix-url/tests/baseline.rs rename to gix-url/tests/url/baseline.rs index 99b0870549f..1186fa2366a 100644 --- a/gix-url/tests/baseline.rs +++ b/gix-url/tests/url/baseline.rs @@ -164,6 +164,7 @@ fn assert_urls_equal(expected: &baseline::GitDiagUrl<'_>, actual: &gix_url::Url) assert_eq!(actual.path, expected.path.unwrap_or_default()); } +#[allow(clippy::module_inception)] mod baseline { use bstr::{BStr, BString, ByteSlice}; use gix_testtools::once_cell::sync::Lazy; diff --git a/gix-url/tests/expand_path/mod.rs b/gix-url/tests/url/expand_path.rs similarity index 100% rename from gix-url/tests/expand_path/mod.rs rename to gix-url/tests/url/expand_path.rs diff --git a/gix-url/tests/fuzzed.rs b/gix-url/tests/url/fuzzed.rs similarity index 97% rename from gix-url/tests/fuzzed.rs rename to gix-url/tests/url/fuzzed.rs index 8bc345e2926..53deda7cfb7 100644 --- a/gix-url/tests/fuzzed.rs +++ b/gix-url/tests/url/fuzzed.rs @@ -5,6 +5,7 @@ use bstr::ByteSlice; #[test] fn fuzzed() { for name in [ + "illegal-utf8", "short-panic", "very-long-abort2", "very-long-abort", diff --git a/gix-url/tests/url.rs b/gix-url/tests/url/main.rs similarity index 83% rename from gix-url/tests/url.rs rename to gix-url/tests/url/main.rs index 9efd0163648..d25742b2120 100644 --- a/gix-url/tests/url.rs +++ b/gix-url/tests/url/main.rs @@ -2,5 +2,7 @@ pub type Error = Box; pub type Result = std::result::Result<(), Error>; mod access; +mod baseline; mod expand_path; +mod fuzzed; mod parse; diff --git a/gix-url/tests/parse/file.rs b/gix-url/tests/url/parse/file.rs similarity index 100% rename from gix-url/tests/parse/file.rs rename to gix-url/tests/url/parse/file.rs diff --git a/gix-url/tests/parse/http.rs b/gix-url/tests/url/parse/http.rs similarity index 100% rename from gix-url/tests/parse/http.rs rename to gix-url/tests/url/parse/http.rs diff --git a/gix-url/tests/parse/invalid.rs b/gix-url/tests/url/parse/invalid.rs similarity index 100% rename from gix-url/tests/parse/invalid.rs rename to gix-url/tests/url/parse/invalid.rs diff --git a/gix-url/tests/parse/mod.rs b/gix-url/tests/url/parse/mod.rs similarity index 100% rename from gix-url/tests/parse/mod.rs rename to gix-url/tests/url/parse/mod.rs diff --git a/gix-url/tests/parse/ssh.rs b/gix-url/tests/url/parse/ssh.rs similarity index 100% rename from gix-url/tests/parse/ssh.rs rename to gix-url/tests/url/parse/ssh.rs