use std::time::Duration;
use http_body_util::Full;
use hyper::body::Bytes;
use hyper_util::client::legacy::connect::HttpConnector;
use hyper_util::client::legacy::Client;
use hyper_util::rt::TokioExecutor;
use rustls::ClientConfig;
pub type HttpsClient = Client<hyper_rustls::HttpsConnector<HttpConnector>, Full<Bytes>>;
#[must_use]
pub fn default_tls_config() -> ClientConfig {
ClientConfig::builder()
.with_root_certificates(root_cert_store())
.with_no_client_auth()
}
#[must_use]
pub fn tls_config_with_extra_roots(
certs: Vec<rustls_pki_types::CertificateDer<'static>>,
) -> ClientConfig {
let mut store = root_cert_store();
for cert in certs {
if let Err(_err) = store.add(cert) {
trace_warn!(error = %_err, "failed to add custom CA certificate to root store");
}
}
ClientConfig::builder()
.with_root_certificates(store)
.with_no_client_auth()
}
fn root_cert_store() -> rustls::RootCertStore {
let mut store = rustls::RootCertStore::empty();
store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
store
}
const DEFAULT_CONNECT_TIMEOUT: Duration = Duration::from_secs(10);
pub(crate) fn build_https_client() -> HttpsClient {
build_https_client_with_connect_timeout(default_tls_config(), DEFAULT_CONNECT_TIMEOUT)
}
#[must_use]
pub fn build_https_client_with_config(tls_config: ClientConfig) -> HttpsClient {
build_https_client_with_connect_timeout(tls_config, DEFAULT_CONNECT_TIMEOUT)
}
#[must_use]
pub fn build_https_client_with_connect_timeout(
tls_config: ClientConfig,
connection_timeout: Duration,
) -> HttpsClient {
let mut http_connector = HttpConnector::new();
http_connector.enforce_http(false); http_connector.set_connect_timeout(Some(connection_timeout));
http_connector.set_nodelay(true);
let https = hyper_rustls::HttpsConnectorBuilder::new()
.with_tls_config(tls_config)
.https_or_http()
.enable_all_versions()
.wrap_connector(http_connector);
Client::builder(TokioExecutor::new())
.pool_idle_timeout(Duration::from_secs(90))
.build(https)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_tls_config_creates_valid_config() {
let _config = default_tls_config();
}
#[test]
fn tls_config_with_extra_roots_handles_empty() {
let _config = tls_config_with_extra_roots(vec![]);
}
#[test]
fn build_https_client_creates_client() {
let _client = build_https_client();
}
#[test]
fn build_https_client_with_custom_config() {
let config = default_tls_config();
let _client = build_https_client_with_config(config);
}
}