From 3a470d1e8e001594276546e75dab0552fff8629f Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 28 Aug 2025 08:26:51 +0000 Subject: [PATCH] feat: Make all Url fields public This way it's easier to manipulate the URL at will. Since there is no validation, users of URLs should never take a parsed structure, but instead take the path or URL directly to parse it themselves. Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Byron <63622+Byron@users.noreply.github.com> --- deny.toml | 1 + gix-url/Cargo.toml | 2 +- gix-url/src/lib.rs | 27 +++++++++++++++++++++------ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/deny.toml b/deny.toml index 6dbb30897..c8f73c52d 100644 --- a/deny.toml +++ b/deny.toml @@ -10,6 +10,7 @@ [advisories] ignore = [ { id = "RUSTSEC-2024-0436", reason = "`paste` - macro crate without replacement" }, + { id = "RUSTSEC-2025-0052", reason = "`async-std` - unmaintained without replacement - needs some time to replace, but async version isn't too important right now" }, ] diff --git a/gix-url/Cargo.toml b/gix-url/Cargo.toml index dd73934ae..bf0c84b93 100644 --- a/gix-url/Cargo.toml +++ b/gix-url/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project implementing parsing and serializ authors = ["Sebastian Thiel "] edition = "2021" include = ["src/**/*", "LICENSE-*", "tests/baseline/**/*"] -rust-version = "1.70" +rust-version = "1.74" [lib] doctest = false diff --git a/gix-url/src/lib.rs b/gix-url/src/lib.rs index 7f3494f85..dfbfb6b04 100644 --- a/gix-url/src/lib.rs +++ b/gix-url/src/lib.rs @@ -78,6 +78,13 @@ pub enum ArgumentSafety<'a> { /// /// Additionally there is support for [deserialization](Url::from_bytes()) and [serialization](Url::to_bstring()). /// +/// # Mutability Warning +/// +/// Due to the mutability of this type, it's possible that the URL serializes to something invalid +/// when fields are modified directly. URLs should always be parsed to this type from string or byte +/// parameters, but never be accepted as an instance of this type and then reconstructed, to maintain +/// validity guarantees. +/// /// # Security Warning /// /// URLs may contain passwords and using standard [formatting](std::fmt::Display) will redact @@ -93,13 +100,13 @@ pub struct Url { /// The URL scheme. pub scheme: Scheme, /// The user to impersonate on the remote. - user: Option, + pub user: Option, /// The password associated with a user. - password: Option, + pub password: Option, /// The host to which to connect. Localhost is implied if `None`. - host: Option, + pub host: Option, /// When serializing, use the alternative forms as it was parsed as such. - serialize_alternative_form: bool, + pub serialize_alternative_form: bool, /// The port to use when connecting to a host. If `None`, standard ports depending on `scheme` will be used. pub port: Option, /// The path portion of the URL, usually the location of the git repository. @@ -346,7 +353,11 @@ impl Url { out.write_all(host.as_bytes())?; } (None, None) => {} - (Some(_user), None) => unreachable!("BUG: should not be possible to have a user but no host"), + (Some(_user), None) => { + return Err(std::io::Error::other( + "Invalid URL structure: user specified without host", + )); + } } if let Some(port) = &self.port { write!(out, ":{port}")?; @@ -370,7 +381,11 @@ impl Url { out.write_all(host.as_bytes())?; } (None, None) => {} - (Some(_user), None) => unreachable!("BUG: should not be possible to have a user but no host"), + (Some(_user), None) => { + return Err(std::io::Error::other( + "Invalid URL structure: user specified without host", + )); + } } assert!(self.port.is_none(), "BUG: cannot serialize port in alternative form"); if self.scheme == Scheme::Ssh {