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