Skip to main content

cloud_sdk_reqwest/blocking/
basic_client.rs

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