Skip to main content

cloud_sdk_reqwest/blocking/
basic_client.rs

1use core::fmt;
2use std::sync::Arc;
3
4use cloud_sdk::authentication::{AuthenticatedRequest, BlockingAuthenticatedTransport};
5use cloud_sdk::transport::{
6    BoundTransport, EndpointIdentity, EndpointIdentityError, ResponseStorageSanitizer,
7    ResponseWriter,
8};
9use cloud_sdk_sanitization::sanitize_bytes;
10use reqwest::blocking::Client;
11
12use crate::shared::{
13    BasicCredential, HttpsEndpoint, TransportError, map_authentication_error,
14    validate_basic_authentication,
15};
16
17use super::client::execute;
18
19/// Hardened provider-neutral reqwest blocking Basic-auth transport.
20#[derive(Clone)]
21pub struct BlockingBasicClient {
22    client: Client,
23    endpoint: HttpsEndpoint,
24    credential: Arc<BasicCredential>,
25    allow_insecure_loopback: bool,
26}
27
28impl BlockingBasicClient {
29    pub(super) fn new(
30        client: Client,
31        endpoint: HttpsEndpoint,
32        credential: BasicCredential,
33        allow_insecure_loopback: bool,
34    ) -> Self {
35        Self {
36            client,
37            endpoint,
38            credential: Arc::new(credential),
39            allow_insecure_loopback,
40        }
41    }
42
43    fn send_inner(
44        &self,
45        authenticated: AuthenticatedRequest<'_, '_>,
46        response: &mut ResponseWriter<'_>,
47    ) -> Result<(), TransportError> {
48        let mut response_attempt = response
49            .begin_attempt()
50            .map_err(|_| TransportError::ResponseCommitFailed)?;
51        let endpoint = self
52            .endpoint
53            .identity()
54            .map_err(|_| TransportError::AuthenticationEndpointMismatch)?;
55        validate_basic_authentication(
56            endpoint,
57            self.credential.scope(),
58            authenticated.policy(),
59            self.allow_insecure_loopback,
60        )
61        .map_err(map_authentication_error)?;
62        let authorization = self
63            .credential
64            .header_value()
65            .map_err(|_| TransportError::HeaderRejected)?;
66        execute(
67            &self.client,
68            &self.endpoint,
69            authorization,
70            authenticated,
71            &mut response_attempt,
72        )
73    }
74}
75
76impl BlockingAuthenticatedTransport for BlockingBasicClient {
77    type Error = TransportError;
78
79    fn send_authenticated(
80        &self,
81        request: AuthenticatedRequest<'_, '_>,
82        response: &mut ResponseWriter<'_>,
83    ) -> Result<(), Self::Error> {
84        self.send_inner(request, response)
85    }
86}
87
88impl ResponseStorageSanitizer for BlockingBasicClient {
89    fn sanitize_response_storage(&self, response_storage: &mut [u8]) {
90        sanitize_bytes(response_storage);
91    }
92}
93
94impl BoundTransport for BlockingBasicClient {
95    fn endpoint_identity(&self) -> Result<EndpointIdentity<'_>, EndpointIdentityError> {
96        self.endpoint.identity()
97    }
98}
99
100impl fmt::Debug for BlockingBasicClient {
101    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
102        formatter
103            .debug_struct("BlockingBasicClient")
104            .field("endpoint", &"[redacted]")
105            .field("credential", &"[redacted]")
106            .finish_non_exhaustive()
107    }
108}