Skip to content

Commit

Permalink
Use custom type
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Aug 24, 2024
1 parent e014bfb commit fba6f6a
Show file tree
Hide file tree
Showing 17 changed files with 217 additions and 94 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 34 additions & 19 deletions crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use clap::{Args, Parser, Subcommand};
use distribution_types::{FlatIndexLocation, IndexUrl};
use pep508_rs::Requirement;
use pypi_types::VerbatimParsedUrl;
use url::Url;
use uv_cache::CacheArgs;
use uv_configuration::{
ConfigSettingEntry, IndexStrategy, KeyringProviderType, PackageNameSpecifier, TargetTriple,
TrustedHost,
};
use uv_normalize::{ExtraName, PackageName};
use uv_python::{PythonDownloads, PythonPreference, PythonVersion};
Expand Down Expand Up @@ -679,12 +679,12 @@ fn parse_index_url(input: &str) -> Result<Maybe<IndexUrl>, String> {
}

/// Parse a string into an [`Url`], mapping the empty string to `None`.
fn parse_maybe_url(input: &str) -> Result<Maybe<Url>, String> {
fn parse_trusted_host(input: &str) -> Result<Maybe<TrustedHost>, String> {
if input.is_empty() {
Ok(Maybe::None)
} else {
match Url::parse(input) {
Ok(url) => Ok(Maybe::Some(url)),
match TrustedHost::from_str(input) {
Ok(host) => Ok(Maybe::Some(host)),
Err(err) => Err(err.to_string()),
}
}
Expand Down Expand Up @@ -1571,17 +1571,20 @@ pub struct PipUninstallArgs {
#[arg(long, value_enum, env = "UV_KEYRING_PROVIDER")]
pub keyring_provider: Option<KeyringProviderType>,

/// A list of trusted hostnames for SSL connections.
/// A list of trusted hosts for SSL connections.
///
/// Expects to receive either a hostname (e.g., `localhost`) or a host-port pair
/// (e.g., `localhost:8080`).
///
/// WARNING: Hosts included in this list will not be verified against the system's certificate
/// store.
#[arg(
long,
env = "UV_TRUSTED_HOST",
value_delimiter = ' ',
value_parser = parse_maybe_url,
value_parser = parse_trusted_host,
)]
pub trusted_host: Option<Vec<Maybe<Url>>>,
pub trusted_host: Option<Vec<Maybe<TrustedHost>>>,

/// Use the system Python to uninstall packages.
///
Expand Down Expand Up @@ -2009,17 +2012,20 @@ pub struct VenvArgs {
#[arg(long, value_enum, env = "UV_KEYRING_PROVIDER")]
pub keyring_provider: Option<KeyringProviderType>,

/// A list of trusted hostnames for SSL connections.
/// A list of trusted hosts for SSL connections.
///
/// Expects to receive either a hostname (e.g., `localhost`) or a host-port pair
/// (e.g., `localhost:8080`).
///
/// WARNING: Hosts included in this list will not be verified against the system's certificate
/// store.
#[arg(
long,
env = "UV_TRUSTED_HOST",
value_delimiter = ' ',
value_parser = parse_maybe_url,
value_parser = parse_trusted_host,
)]
pub trusted_host: Option<Vec<Maybe<Url>>>,
pub trusted_host: Option<Vec<Maybe<TrustedHost>>>,

/// Limit candidate packages to those that were uploaded prior to the given date.
///
Expand Down Expand Up @@ -3360,18 +3366,21 @@ pub struct InstallerArgs {
)]
pub keyring_provider: Option<KeyringProviderType>,

/// A list of trusted hostnames for SSL connections.
/// A list of trusted hosts for SSL connections.
///
/// Expects to receive either a hostname (e.g., `localhost`) or a host-port pair
/// (e.g., `localhost:8080`).
///
/// WARNING: Hosts included in this list will not be verified against the system's certificate
/// store.
#[arg(
long,
env = "UV_TRUSTED_HOST",
value_delimiter = ' ',
value_parser = parse_maybe_url,
value_parser = parse_trusted_host,
help_heading = "Index options"
)]
pub trusted_host: Option<Vec<Maybe<Url>>>,
pub trusted_host: Option<Vec<Maybe<TrustedHost>>>,

/// Settings to pass to the PEP 517 build backend, specified as `KEY=VALUE` pairs.
#[arg(
Expand Down Expand Up @@ -3515,18 +3524,21 @@ pub struct ResolverArgs {
)]
pub keyring_provider: Option<KeyringProviderType>,

/// A list of trusted hostnames for SSL connections.
/// A list of trusted hosts for SSL connections.
///
/// Expects to receive either a hostname (e.g., `localhost`) or a host-port pair
/// (e.g., `localhost:8080`).
///
/// WARNING: Hosts included in this list will not be verified against the system's certificate
/// store.
#[arg(
long,
env = "UV_TRUSTED_HOST",
value_delimiter = ' ',
value_parser = parse_maybe_url,
value_parser = parse_trusted_host,
help_heading = "Index options"
)]
pub trusted_host: Option<Vec<Maybe<Url>>>,
pub trusted_host: Option<Vec<Maybe<TrustedHost>>>,

/// The strategy to use when selecting between the different compatible versions for a given
/// package requirement.
Expand Down Expand Up @@ -3700,18 +3712,21 @@ pub struct ResolverInstallerArgs {
)]
pub keyring_provider: Option<KeyringProviderType>,

/// A list of trusted hostnames for SSL connections.
/// A list of trusted hosts for SSL connections.
///
/// Expects to receive either a hostname (e.g., `localhost`) or a host-port pair
/// (e.g., `localhost:8080`).
///
/// WARNING: Hosts included in this list will not be verified against the system's certificate
/// store.
#[arg(
long,
env = "UV_TRUSTED_HOST",
value_delimiter = ' ',
value_parser = parse_maybe_url,
value_parser = parse_trusted_host,
help_heading = "Index options"
)]
pub trusted_host: Option<Vec<Maybe<Url>>>,
pub trusted_host: Option<Vec<Maybe<TrustedHost>>>,

/// The strategy to use when selecting between the different compatible versions for a given
/// package requirement.
Expand Down
12 changes: 6 additions & 6 deletions crates/uv-client/src/base_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use reqwest_retry::{
use tracing::debug;
use url::Url;
use uv_auth::AuthMiddleware;
use uv_configuration::KeyringProviderType;
use uv_configuration::{KeyringProviderType, TrustedHost};
use uv_fs::Simplified;
use uv_version::version;
use uv_warnings::warn_user_once;
Expand All @@ -29,7 +29,7 @@ use crate::Connectivity;
#[derive(Debug, Clone)]
pub struct BaseClientBuilder<'a> {
keyring: KeyringProviderType,
trusted_host: Vec<Url>,
trusted_host: Vec<TrustedHost>,
native_tls: bool,
retries: u32,
pub connectivity: Connectivity,
Expand Down Expand Up @@ -67,7 +67,7 @@ impl<'a> BaseClientBuilder<'a> {
}

#[must_use]
pub fn trusted_host(mut self, trusted_host: Vec<Url>) -> Self {
pub fn trusted_host(mut self, trusted_host: Vec<TrustedHost>) -> Self {
self.trusted_host = trusted_host;
self
}
Expand Down Expand Up @@ -175,10 +175,10 @@ impl<'a> BaseClientBuilder<'a> {

BaseClient {
connectivity: self.connectivity,
trusted_host: self.trusted_host.clone(),
client,
dangerous_client,
timeout,
trusted_host: vec![],
}
}

Expand Down Expand Up @@ -265,7 +265,7 @@ pub struct BaseClient {
/// Configured client timeout, in seconds.
timeout: u64,
/// The host that is trusted to use the insecure client.
trusted_host: Vec<Url>,
trusted_host: Vec<TrustedHost>,
}

#[derive(Debug, Clone, Copy)]
Expand All @@ -287,7 +287,7 @@ impl BaseClient {
if self
.trusted_host
.iter()
.any(|trusted| url.host() == trusted.host())
.any(|trusted_host| trusted_host.matches(url))
{
&self.dangerous_client
} else {
Expand Down
4 changes: 2 additions & 2 deletions crates/uv-client/src/registry_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ use pep508_rs::MarkerEnvironment;
use platform_tags::Platform;
use pypi_types::{Metadata23, SimpleJson};
use uv_cache::{Cache, CacheBucket, CacheEntry, WheelCache};
use uv_configuration::IndexStrategy;
use uv_configuration::KeyringProviderType;
use uv_configuration::{IndexStrategy, TrustedHost};
use uv_normalize::PackageName;

use crate::base_client::BaseClientBuilder;
Expand Down Expand Up @@ -73,7 +73,7 @@ impl<'a> RegistryClientBuilder<'a> {
}

#[must_use]
pub fn trusted_host(mut self, trusted_host: Vec<Url>) -> Self {
pub fn trusted_host(mut self, trusted_host: Vec<TrustedHost>) -> Self {
self.base_client_builder = self.base_client_builder.trusted_host(trusted_host);
self
}
Expand Down
2 changes: 2 additions & 0 deletions crates/uv-configuration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ rustc-hash = { workspace = true }
schemars = { workspace = true, optional = true }
serde = { workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
url = { workspace = true }

[dev-dependencies]
anyhow = { workspace = true }
Expand Down
2 changes: 2 additions & 0 deletions crates/uv-configuration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub use package_options::*;
pub use preview::*;
pub use sources::*;
pub use target_triple::*;
pub use trusted_host::*;

mod authentication;
mod build_options;
Expand All @@ -25,3 +26,4 @@ mod package_options;
mod preview;
mod sources;
mod target_triple;
mod trusted_host;
69 changes: 69 additions & 0 deletions crates/uv-configuration/src/trusted_host.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use serde::{Deserialize, Serialize};

use url::Url;

/// A trusted host, which could be a host or a host-port pair.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum TrustedHost {
Host(String),
HostPort(String, u16),
}

impl TrustedHost {
pub fn matches(&self, url: &Url) -> bool {
match self {
Self::Host(host) => url.host_str() == Some(host.as_str()),
Self::HostPort(host, port) => {
url.host_str() == Some(host.as_str()) && url.port() == Some(*port)
}
}
}
}

#[derive(Debug, thiserror::Error)]
pub enum TrustedHostError {
#[error("missing host for `--trusted-host`: `{0}`")]
MissingHost(String),
#[error("invalid port for `--trusted-host`: `{0}`")]
InvalidPort(String),
}

impl std::str::FromStr for TrustedHost {
type Err = TrustedHostError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parts = s.splitn(2, ':');
let host = parts
.next()
.ok_or_else(|| TrustedHostError::MissingHost(s.to_string()))?;
let port = parts
.next()
.map(str::parse)
.transpose()
.map_err(|_| TrustedHostError::InvalidPort(s.to_string()))?;

match port {
Some(port) => Ok(TrustedHost::HostPort(host.to_string(), port)),
None => Ok(TrustedHost::Host(host.to_string())),
}
}
}

#[cfg(feature = "schemars")]
impl schemars::JsonSchema for TrustedHost {
fn schema_name() -> String {
"TrustedHost".to_string()
}

fn json_schema(_gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
schemars::schema::SchemaObject {
instance_type: Some(schemars::schema::InstanceType::String.into()),
metadata: Some(Box::new(schemars::schema::Metadata {
description: Some("A host or host-port pair.".to_string()),
..schemars::schema::Metadata::default()
})),
..schemars::schema::SchemaObject::default()
}
.into()
}
}
Loading

0 comments on commit fba6f6a

Please sign in to comment.