a2a_protocol_client/
tls.rs1use std::time::Duration;
19
20use http_body_util::Full;
21use hyper::body::Bytes;
22use hyper_util::client::legacy::connect::HttpConnector;
23use hyper_util::client::legacy::Client;
24use hyper_util::rt::TokioExecutor;
25use rustls::ClientConfig;
26
27pub type HttpsClient = Client<hyper_rustls::HttpsConnector<HttpConnector>, Full<Bytes>>;
29
30#[must_use]
34pub fn default_tls_config() -> ClientConfig {
35 ClientConfig::builder()
36 .with_root_certificates(root_cert_store())
37 .with_no_client_auth()
38}
39
40#[must_use]
46pub fn tls_config_with_extra_roots(
47 certs: Vec<rustls_pki_types::CertificateDer<'static>>,
48) -> ClientConfig {
49 let mut store = root_cert_store();
50 for cert in certs {
51 if let Err(_err) = store.add(cert) {
52 trace_warn!(error = %_err, "failed to add custom CA certificate to root store");
53 }
54 }
55 ClientConfig::builder()
56 .with_root_certificates(store)
57 .with_no_client_auth()
58}
59
60fn root_cert_store() -> rustls::RootCertStore {
62 let mut store = rustls::RootCertStore::empty();
63 store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
64 store
65}
66
67const DEFAULT_CONNECT_TIMEOUT: Duration = Duration::from_secs(10);
69
70pub(crate) fn build_https_client() -> HttpsClient {
73 build_https_client_with_connect_timeout(default_tls_config(), DEFAULT_CONNECT_TIMEOUT)
74}
75
76#[must_use]
79pub fn build_https_client_with_config(tls_config: ClientConfig) -> HttpsClient {
80 build_https_client_with_connect_timeout(tls_config, DEFAULT_CONNECT_TIMEOUT)
81}
82
83#[must_use]
86pub fn build_https_client_with_connect_timeout(
87 tls_config: ClientConfig,
88 connection_timeout: Duration,
89) -> HttpsClient {
90 let mut http_connector = HttpConnector::new();
91 http_connector.enforce_http(false); http_connector.set_connect_timeout(Some(connection_timeout));
93 http_connector.set_nodelay(true);
94
95 let https = hyper_rustls::HttpsConnectorBuilder::new()
96 .with_tls_config(tls_config)
97 .https_or_http()
98 .enable_all_versions()
99 .wrap_connector(http_connector);
100
101 Client::builder(TokioExecutor::new())
102 .pool_idle_timeout(Duration::from_secs(90))
103 .build(https)
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn default_tls_config_creates_valid_config() {
112 let _config = default_tls_config();
116 }
117
118 #[test]
119 fn tls_config_with_extra_roots_handles_empty() {
120 let _config = tls_config_with_extra_roots(vec![]);
121 }
122
123 #[test]
124 fn build_https_client_creates_client() {
125 let _client = build_https_client();
126 }
127
128 #[test]
129 fn build_https_client_with_custom_config() {
130 let config = default_tls_config();
131 let _client = build_https_client_with_config(config);
132 }
133}