Skip to main content

cloud_sdk_reqwest/blocking/
config.rs

1use core::fmt;
2
3#[cfg(any(feature = "blocking-rustls", feature = "blocking-rustls-webpki-roots"))]
4use rustls::ClientConfig;
5#[cfg(feature = "blocking-rustls-webpki-roots")]
6use rustls::RootCertStore;
7#[cfg(feature = "blocking-rustls-webpki-roots")]
8use std::sync::Arc;
9
10#[cfg(not(feature = "blocking-rustls-webpki-roots"))]
11use crate::shared::platform_client_config;
12use crate::shared::{
13    BearerCredential, BuildError, HttpsEndpoint, RawHyperClient, RequestTimeouts, UserAgent,
14};
15
16use super::{BlockingClient, RawBlockingClient};
17
18/// Builder requiring endpoint, bearer token, user agent, and all timeout
19/// dimensions before a client can be constructed.
20pub struct BlockingClientBuilder {
21    endpoint: HttpsEndpoint,
22    credential: BearerCredential,
23    user_agent: UserAgent,
24    timeouts: RequestTimeouts,
25}
26
27/// Builder for a raw client with no credential, provider, media, or retry policy.
28pub struct RawBlockingClientBuilder {
29    endpoint: HttpsEndpoint,
30    user_agent: UserAgent,
31    timeouts: RequestTimeouts,
32}
33
34impl BlockingClientBuilder {
35    /// Creates a complete blocking-client configuration.
36    #[must_use]
37    pub const fn new(
38        endpoint: HttpsEndpoint,
39        credential: BearerCredential,
40        user_agent: UserAgent,
41        timeouts: RequestTimeouts,
42    ) -> Self {
43        Self {
44            endpoint,
45            credential,
46            user_agent,
47            timeouts,
48        }
49    }
50
51    /// Builds a hardened HTTPS-only client.
52    pub fn build(self) -> Result<BlockingClient, BuildError> {
53        self.build_inner(true)
54    }
55
56    fn build_inner(self, https_only: bool) -> Result<BlockingClient, BuildError> {
57        if !self.credential.scope.matches_endpoint(&self.endpoint) {
58            return Err(BuildError::CredentialEndpointMismatch);
59        }
60        let settings = ClientSettings {
61            timeouts: self.timeouts,
62        };
63        let client = configured_raw_client(
64            self.endpoint.clone(),
65            &self.user_agent,
66            settings,
67            https_only,
68        )?;
69        Ok(BlockingClient::new(
70            client,
71            self.endpoint,
72            self.credential,
73            !https_only,
74        ))
75    }
76
77    #[cfg(test)]
78    pub(super) fn build_for_loopback(self) -> Result<BlockingClient, BuildError> {
79        self.build_inner(false)
80    }
81}
82
83impl RawBlockingClientBuilder {
84    /// Creates a complete raw blocking configuration without credentials.
85    #[must_use]
86    pub const fn new(
87        endpoint: HttpsEndpoint,
88        user_agent: UserAgent,
89        timeouts: RequestTimeouts,
90    ) -> Self {
91        Self {
92            endpoint,
93            user_agent,
94            timeouts,
95        }
96    }
97
98    /// Builds an HTTPS-only executor with no implicit authorization.
99    pub fn build(self) -> Result<RawBlockingClient, BuildError> {
100        self.build_inner(true)
101    }
102
103    fn build_inner(self, https_only: bool) -> Result<RawBlockingClient, BuildError> {
104        let settings = ClientSettings {
105            timeouts: self.timeouts,
106        };
107        configured_raw_client(self.endpoint, &self.user_agent, settings, https_only)
108    }
109
110    #[cfg(test)]
111    pub(super) fn build_for_loopback(self) -> Result<RawBlockingClient, BuildError> {
112        self.build_inner(false)
113    }
114}
115
116impl fmt::Debug for BlockingClientBuilder {
117    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
118        let mut debug = formatter.debug_struct("BlockingClientBuilder");
119        debug
120            .field("endpoint", &"[redacted]")
121            .field("credential", &"[redacted]")
122            .field("user_agent", &self.user_agent)
123            .field("timeouts", &self.timeouts);
124        debug.finish()
125    }
126}
127
128impl fmt::Debug for RawBlockingClientBuilder {
129    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
130        let mut debug = formatter.debug_struct("RawBlockingClientBuilder");
131        debug
132            .field("endpoint", &"[redacted]")
133            .field("user_agent", &self.user_agent)
134            .field("timeouts", &self.timeouts);
135        debug.finish()
136    }
137}
138
139#[derive(Clone, Copy)]
140pub(super) struct ClientSettings {
141    pub(super) timeouts: RequestTimeouts,
142}
143
144pub(super) fn configured_raw_client(
145    endpoint: HttpsEndpoint,
146    user_agent: &UserAgent,
147    settings: ClientSettings,
148    https_only: bool,
149) -> Result<RawBlockingClient, BuildError> {
150    let tls_config = raw_tls_config(settings)?;
151    let client = RawHyperClient::new(
152        endpoint.clone(),
153        user_agent,
154        settings.timeouts,
155        tls_config,
156        https_only,
157    )?;
158    Ok(RawBlockingClient::new(client, endpoint))
159}
160
161#[cfg(not(feature = "blocking-rustls-webpki-roots"))]
162fn raw_tls_config(_settings: ClientSettings) -> Result<ClientConfig, BuildError> {
163    platform_client_config()
164}
165
166#[cfg(feature = "blocking-rustls-webpki-roots")]
167fn raw_tls_config(_settings: ClientSettings) -> Result<ClientConfig, BuildError> {
168    webpki_roots_client_config()
169}
170
171#[cfg(feature = "blocking-rustls-webpki-roots")]
172fn webpki_roots_client_config() -> Result<ClientConfig, BuildError> {
173    let provider = Arc::new(rustls::crypto::aws_lc_rs::default_provider());
174    let mut roots = RootCertStore::empty();
175    roots.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
176    Ok(ClientConfig::builder_with_provider(provider)
177        .with_safe_default_protocol_versions()
178        .map_err(|_| BuildError::WebPkiRootsProtocolConfigurationFailed)?
179        .with_root_certificates(roots)
180        .with_no_client_auth())
181}
182
183#[cfg(all(test, feature = "blocking-rustls-webpki-roots"))]
184pub(super) fn test_webpki_roots_configuration() -> Result<(usize, bool), BuildError> {
185    let config = webpki_roots_client_config()?;
186    Ok((webpki_roots::TLS_SERVER_ROOTS.len(), config.fips()))
187}