use super::service::TlsConnector;
use crate::transport::{
Error,
tls::{Certificate, Identity},
};
use http::Uri;
use std::sync::Arc;
use std::time::Duration;
use tokio_rustls::rustls::client::danger::ServerCertVerifier;
use tokio_rustls::rustls::pki_types::TrustAnchor;
#[derive(Debug, Clone, Default)]
pub struct ClientTlsConfig {
domain: Option<String>,
certs: Vec<Certificate>,
trust_anchors: Vec<TrustAnchor<'static>>,
identity: Option<Identity>,
assume_http2: bool,
#[cfg(feature = "tls-native-roots")]
with_native_roots: bool,
#[cfg(feature = "tls-webpki-roots")]
with_webpki_roots: bool,
use_key_log: bool,
timeout: Option<Duration>,
}
impl ClientTlsConfig {
pub fn new() -> Self {
Self::default()
}
pub fn domain_name(self, domain_name: impl Into<String>) -> Self {
ClientTlsConfig {
domain: Some(domain_name.into()),
..self
}
}
pub fn ca_certificate(self, ca_certificate: Certificate) -> Self {
let mut certs = self.certs;
certs.push(ca_certificate);
ClientTlsConfig { certs, ..self }
}
pub fn ca_certificates(self, ca_certificates: impl IntoIterator<Item = Certificate>) -> Self {
let mut certs = self.certs;
certs.extend(ca_certificates);
ClientTlsConfig { certs, ..self }
}
pub fn trust_anchor(self, trust_anchor: TrustAnchor<'static>) -> Self {
let mut trust_anchors = self.trust_anchors;
trust_anchors.push(trust_anchor);
ClientTlsConfig {
trust_anchors,
..self
}
}
pub fn trust_anchors(
mut self,
trust_anchors: impl IntoIterator<Item = TrustAnchor<'static>>,
) -> Self {
self.trust_anchors.extend(trust_anchors);
self
}
pub fn identity(self, identity: Identity) -> Self {
ClientTlsConfig {
identity: Some(identity),
..self
}
}
pub fn assume_http2(self, assume_http2: bool) -> Self {
ClientTlsConfig {
assume_http2,
..self
}
}
pub fn use_key_log(self) -> Self {
ClientTlsConfig {
use_key_log: true,
..self
}
}
#[cfg(feature = "tls-native-roots")]
pub fn with_native_roots(self) -> Self {
ClientTlsConfig {
with_native_roots: true,
..self
}
}
#[cfg(feature = "tls-webpki-roots")]
pub fn with_webpki_roots(self) -> Self {
ClientTlsConfig {
with_webpki_roots: true,
..self
}
}
pub fn with_enabled_roots(self) -> Self {
let config = self;
#[cfg(feature = "tls-native-roots")]
let config = config.with_native_roots();
#[cfg(feature = "tls-webpki-roots")]
let config = config.with_webpki_roots();
config
}
pub fn timeout(self, timeout: Duration) -> Self {
ClientTlsConfig {
timeout: Some(timeout),
..self
}
}
pub(crate) fn into_tls_connector(self, uri: &Uri) -> Result<TlsConnector, crate::BoxError> {
self.build_tls_connector(uri, None)
}
pub(crate) fn into_tls_connector_with_verifier(
self,
uri: &Uri,
verifier: Arc<dyn ServerCertVerifier>,
) -> Result<TlsConnector, crate::BoxError> {
self.build_tls_connector(uri, Some(verifier))
}
fn build_tls_connector(
self,
uri: &Uri,
server_cert_verifier: Option<Arc<dyn ServerCertVerifier>>,
) -> Result<TlsConnector, crate::BoxError> {
let domain = match &self.domain {
Some(domain) => domain,
None => uri.host().ok_or_else(Error::new_invalid_uri)?,
};
TlsConnector::new(
self.certs,
self.trust_anchors,
self.identity,
server_cert_verifier,
domain,
self.assume_http2,
self.use_key_log,
self.timeout,
#[cfg(feature = "tls-native-roots")]
self.with_native_roots,
#[cfg(feature = "tls-webpki-roots")]
self.with_webpki_roots,
)
}
}