From f46a93b13915f4b72d4f0a19beb7bce9a8b1c936 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 9 Apr 2024 10:59:23 -0400 Subject: [PATCH] review --- src/connector.rs | 107 ++++++++++++++++++++++++++---------- src/connector/builder.rs | 31 ++++++++--- src/lib.rs | 6 +- src/server_name_resolver.rs | 44 --------------- 4 files changed, 104 insertions(+), 84 deletions(-) delete mode 100644 src/server_name_resolver.rs diff --git a/src/connector.rs b/src/connector.rs index afb7599..2be36da 100644 --- a/src/connector.rs +++ b/src/connector.rs @@ -12,7 +12,6 @@ use pki_types::ServerName; use tokio_rustls::TlsConnector; use tower_service::Service; -use crate::server_name_resolver::ResolveServerName; use crate::stream::MaybeHttpsStream; pub(crate) mod builder; @@ -25,7 +24,7 @@ pub struct HttpsConnector { force_https: bool, http: T, tls_config: Arc, - server_name_resolver: Option>, + server_name_resolver: Arc, } impl HttpsConnector { @@ -91,31 +90,10 @@ where }; let cfg = self.tls_config.clone(); - let hostname = match &self.server_name_resolver { - Some(server_name_resolver) => match server_name_resolver.resolve(&dst) { - Ok(hostname) => hostname, - Err(e) => { - return Box::pin(async move { Err(e) }); - } - }, - None => { - let mut hostname = dst.host().unwrap_or_default(); - - // Remove square brackets around IPv6 address. - if let Some(trimmed) = hostname - .strip_prefix('[') - .and_then(|h| h.strip_suffix(']')) - { - hostname = trimmed; - } - - match ServerName::try_from(hostname) { - Ok(dns_name) => dns_name.to_owned(), - Err(_) => { - let err = io::Error::new(io::ErrorKind::Other, "invalid dnsname"); - return Box::pin(async move { Err(Box::new(err).into()) }); - } - } + let hostname = match self.server_name_resolver.resolve(&dst) { + Ok(hostname) => hostname, + Err(e) => { + return Box::pin(async move { Err(e) }); } }; @@ -143,7 +121,7 @@ where force_https: false, http, tls_config: cfg.into(), - server_name_resolver: None, + server_name_resolver: Arc::new(DefaultServerNameResolver::new()), } } } @@ -155,3 +133,76 @@ impl fmt::Debug for HttpsConnector { .finish() } } + +/// The default server name resolver, which uses the hostname in the URI. +#[derive(Default)] +pub struct DefaultServerNameResolver(()); + +impl DefaultServerNameResolver { + /// Creates a new resolver. + pub fn new() -> Self { + Self::default() + } +} + +impl ResolveServerName for DefaultServerNameResolver { + fn resolve( + &self, + uri: &Uri, + ) -> Result, Box> { + let mut hostname = uri.host().unwrap_or_default(); + + // Remove square brackets around IPv6 address. + if let Some(trimmed) = hostname + .strip_prefix('[') + .and_then(|h| h.strip_suffix(']')) + { + hostname = trimmed; + } + + ServerName::try_from(hostname.to_string()).map_err(|e| Box::new(e) as _) + } +} + +/// A server name resolver which always returns the same fixed name. +pub struct FixedServerNameResolver { + name: ServerName<'static>, +} + +impl FixedServerNameResolver { + /// Creates a new resolver returning the specified name. + pub fn new(name: ServerName<'static>) -> Self { + Self { name } + } +} + +impl ResolveServerName for FixedServerNameResolver { + fn resolve( + &self, + _: &Uri, + ) -> Result, Box> { + Ok(self.name.clone()) + } +} + +impl ResolveServerName for F +where + F: Fn(&Uri) -> Result, E>, + E: Into>, +{ + fn resolve( + &self, + uri: &Uri, + ) -> Result, Box> { + self(uri).map_err(Into::into) + } +} + +/// A trait implemented by types that can resolve a [`ServerName`] for a request. +pub trait ResolveServerName { + /// Maps a [`Uri`] into a [`ServerName`]. + fn resolve( + &self, + uri: &Uri, + ) -> Result, Box>; +} diff --git a/src/connector/builder.rs b/src/connector/builder.rs index aedae09..6a0e064 100644 --- a/src/connector/builder.rs +++ b/src/connector/builder.rs @@ -5,10 +5,10 @@ use hyper_util::client::legacy::connect::HttpConnector; use rustls::crypto::CryptoProvider; use rustls::ClientConfig; -use super::HttpsConnector; +use super::{DefaultServerNameResolver, HttpsConnector, ResolveServerName}; #[cfg(any(feature = "rustls-native-certs", feature = "webpki-roots"))] use crate::config::ConfigBuilderExt; -use crate::server_name_resolver::{FixedServerNameResolver, ResolveServerName}; +use pki_types::ServerName; /// A builder for an [`HttpsConnector`] /// @@ -189,7 +189,9 @@ impl WantsProtocols1 { force_https: self.https_only, http: conn, tls_config: std::sync::Arc::new(self.tls_config), - server_name_resolver: self.server_name_resolver, + server_name_resolver: self + .server_name_resolver + .unwrap_or_else(|| Arc::new(DefaultServerNameResolver::new())), } } @@ -248,10 +250,10 @@ impl ConnectorBuilder { /// /// If this method is called, hyper-rustls will instead use this resolver /// to compute the value used to verify the server certificate. - pub fn with_server_name_resolver(mut self, resolver: T) -> Self - where - T: ResolveServerName + 'static + Sync + Send, - { + pub fn with_server_name_resolver( + mut self, + resolver: impl ResolveServerName + 'static + Sync + Send, + ) -> Self { self.0.server_name_resolver = Some(Arc::new(resolver)); self } @@ -265,8 +267,19 @@ impl ConnectorBuilder { /// If this method is called, hyper-rustls will instead verify that server /// certificate contains `override_server_name`. Domain name included in /// the URL will not affect certificate validation. - pub fn with_server_name(self, override_server_name: String) -> Self { - self.with_server_name_resolver(FixedServerNameResolver::new(override_server_name)) + #[deprecated(since = "0.27.1", note = "use Self::with_server_name_resolver instead")] + pub fn with_server_name(self, mut override_server_name: String) -> Self { + // remove square brackets around IPv6 address. + if let Some(trimmed) = override_server_name + .strip_prefix('[') + .and_then(|s| s.strip_suffix(']')) + { + override_server_name = trimmed.to_string(); + } + + self.with_server_name_resolver(move |_: &_| { + ServerName::try_from(override_server_name.clone()) + }) } } diff --git a/src/lib.rs b/src/lib.rs index 3ed7432..1920e78 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,7 +37,6 @@ mod config; mod connector; -mod server_name_resolver; mod stream; #[cfg(feature = "logging")] @@ -56,8 +55,9 @@ mod log { pub use crate::config::ConfigBuilderExt; pub use crate::connector::builder::ConnectorBuilder as HttpsConnectorBuilder; -pub use crate::connector::HttpsConnector; -pub use crate::server_name_resolver::ResolveServerName; +pub use crate::connector::{ + DefaultServerNameResolver, FixedServerNameResolver, HttpsConnector, ResolveServerName, +}; pub use crate::stream::MaybeHttpsStream; /// The various states of the [`HttpsConnectorBuilder`] diff --git a/src/server_name_resolver.rs b/src/server_name_resolver.rs deleted file mode 100644 index 204a3f4..0000000 --- a/src/server_name_resolver.rs +++ /dev/null @@ -1,44 +0,0 @@ -use std::error::Error; - -use http::Uri; -use pki_types::ServerName; - -/// A trait implemented by types that can resolve a [`ServerName`] for a request. -pub trait ResolveServerName { - /// Maps a [`Uri`] into a [`ServerName`]. - fn resolve(&self, uri: &Uri) -> Result, Box>; -} - -impl ResolveServerName for F -where - F: Fn(&Uri) -> Result, E>, - E: Into>, -{ - fn resolve(&self, uri: &Uri) -> Result, Box> { - self(uri).map_err(Into::into) - } -} - -pub(crate) struct FixedServerNameResolver { - name: String, -} - -impl FixedServerNameResolver { - pub(crate) fn new(mut name: String) -> Self { - // Remove square brackets around IPv6 address. - if let Some(trimmed) = name - .strip_prefix('[') - .and_then(|h| h.strip_suffix(']')) - { - name = trimmed.to_string(); - } - - Self { name } - } -} - -impl ResolveServerName for FixedServerNameResolver { - fn resolve(&self, _: &Uri) -> Result, Box> { - ServerName::try_from(self.name.clone()).map_err(|e| Box::new(e) as _) - } -}