conjure_runtime_rustls_platform_verifier/
raw_client_builder.rs

1use conjure_error::Error;
2use conjure_runtime::raw::BuildRawClient;
3use conjure_runtime::{Builder, builder};
4use conjure_runtime_raw::raw::DefaultRawClient;
5use conjure_runtime_raw::raw::{HTTP_KEEPALIVE, TCP_KEEPALIVE};
6use conjure_runtime_raw::service::proxy::ProxyConfig;
7use conjure_runtime_raw::service::proxy::connector::ProxyConnectorLayer;
8use conjure_runtime_raw::service::timeout::TimeoutLayer;
9use conjure_runtime_raw::service::tls_metrics::TlsMetricsLayer;
10use hyper_rustls::HttpsConnectorBuilder;
11use hyper_util::client::legacy::Client;
12use hyper_util::client::legacy::connect::HttpConnector;
13use hyper_util::rt::{TokioExecutor, TokioTimer};
14use rustls::ClientConfig;
15use rustls_platform_verifier::BuilderVerifierExt;
16use tower_layer::Layer;
17
18#[derive(Copy, Clone)]
19pub struct RawClientBuilder;
20
21// This code is copied and adapted from conjure-runtime's DefaultRawClientBuilder
22impl BuildRawClient for RawClientBuilder {
23    type RawClient = DefaultRawClient;
24
25    fn build_raw_client(
26        &self,
27        builder: &Builder<builder::Complete<Self>>,
28    ) -> Result<Self::RawClient, Error> {
29        let mut connector = HttpConnector::new();
30        connector.enforce_http(false);
31        connector.set_nodelay(true);
32        connector.set_keepalive(Some(TCP_KEEPALIVE));
33        connector.set_connect_timeout(Some(builder.get_connect_timeout()));
34
35        let proxy = ProxyConfig::from_config(builder.get_proxy())?;
36
37        let connector = TimeoutLayer::new(builder).layer(connector);
38        let connector = ProxyConnectorLayer::new(&proxy).layer(connector);
39
40        let client_config =
41            ClientConfig::builder_with_provider(crate::crypto::ring_crypto_provider().clone())
42                .with_safe_default_protocol_versions()
43                .map_err(Error::internal_safe)?
44                .with_platform_verifier()
45                .map_err(Error::internal_safe)?;
46
47        let client_config = match (
48            builder.get_security().cert_file(),
49            builder.get_security().key_file(),
50        ) {
51            (Some(cert_file), Some(key_file)) => {
52                let cert_chain = conjure_runtime_raw::raw::load_certs_file(cert_file)?;
53                let private_key = conjure_runtime_raw::raw::load_private_key(key_file)?;
54
55                client_config
56                    .with_client_auth_cert(cert_chain, private_key)
57                    .map_err(Error::internal_safe)?
58            }
59            (None, None) => client_config.with_no_client_auth(),
60            _ => {
61                return Err(Error::internal_safe(
62                    "neither or both of key-file and cert-file must be set in the client \
63                    security config",
64                ));
65            }
66        };
67
68        let connector = HttpsConnectorBuilder::new()
69            .with_tls_config(client_config)
70            .https_or_http()
71            .enable_all_versions()
72            .wrap_connector(connector);
73        let connector = TlsMetricsLayer::new(builder).layer(connector);
74
75        let client = Client::builder(TokioExecutor::new())
76            .pool_idle_timeout(HTTP_KEEPALIVE)
77            .pool_timer(TokioTimer::new())
78            .timer(TokioTimer::new())
79            .build(connector);
80
81        Ok(DefaultRawClient(client))
82    }
83}