Skip to main content

cloud_sdk_reqwest/blocking/
config.rs

1use core::fmt;
2
3use reqwest::blocking::Client;
4use reqwest::redirect::Policy;
5use reqwest::tls::Version;
6
7use crate::shared::{BearerToken, BuildError, HttpsEndpoint, RequestTimeouts, UserAgent};
8
9use super::BlockingClient;
10
11/// Builder requiring endpoint, bearer token, user agent, and all timeout
12/// dimensions before a client can be constructed.
13pub struct BlockingClientBuilder {
14    endpoint: HttpsEndpoint,
15    token: BearerToken,
16    user_agent: UserAgent,
17    timeouts: RequestTimeouts,
18}
19
20impl BlockingClientBuilder {
21    /// Creates a complete blocking-client configuration.
22    #[must_use]
23    pub const fn new(
24        endpoint: HttpsEndpoint,
25        token: BearerToken,
26        user_agent: UserAgent,
27        timeouts: RequestTimeouts,
28    ) -> Self {
29        Self {
30            endpoint,
31            token,
32            user_agent,
33            timeouts,
34        }
35    }
36
37    /// Builds a hardened HTTPS-only client.
38    pub fn build(self) -> Result<BlockingClient, BuildError> {
39        self.build_inner(true)
40    }
41
42    fn build_inner(self, https_only: bool) -> Result<BlockingClient, BuildError> {
43        let client = configured_client(&self.user_agent, self.timeouts, https_only)?;
44        Ok(BlockingClient::new(client, self.endpoint, self.token))
45    }
46
47    #[cfg(test)]
48    pub(super) fn build_for_loopback(self) -> Result<BlockingClient, BuildError> {
49        self.build_inner(false)
50    }
51}
52
53impl fmt::Debug for BlockingClientBuilder {
54    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
55        formatter
56            .debug_struct("BlockingClientBuilder")
57            .field("endpoint", &"[redacted]")
58            .field("token", &"[redacted]")
59            .field("user_agent", &self.user_agent)
60            .field("timeouts", &self.timeouts)
61            .finish()
62    }
63}
64
65fn configured_client(
66    user_agent: &UserAgent,
67    timeouts: RequestTimeouts,
68    https_only: bool,
69) -> Result<Client, BuildError> {
70    Client::builder()
71        .tls_backend_rustls()
72        .https_only(https_only)
73        .http1_only()
74        .no_hickory_dns()
75        .min_tls_version(Version::TLS_1_2)
76        .redirect(Policy::none())
77        .retry(reqwest::retry::never())
78        .referer(false)
79        .no_proxy()
80        .no_gzip()
81        .no_brotli()
82        .no_zstd()
83        .no_deflate()
84        .timeout(timeouts.total())
85        .connect_timeout(timeouts.connect())
86        .connection_verbose(false)
87        .user_agent(user_agent.value.clone())
88        .build()
89        .map_err(|_| BuildError::ClientBuildFailed)
90}