cloud_sdk_reqwest/blocking/
client.rs1use core::fmt;
2use std::sync::Arc;
3
4use cloud_sdk::authentication::{
5 AuthenticatedRequest, BlockingAuthenticatedTransport, CredentialGeneration,
6};
7use cloud_sdk::transport::{
8 BoundTransport, EndpointIdentity, EndpointIdentityError, ResponseStorageSanitizer,
9 ResponseWriter, TransportFailure,
10};
11use cloud_sdk_sanitization::{SecretBuffer, sanitize_bytes};
12
13use super::RawBlockingClient;
14use crate::shared::{
15 AuthenticatedTransportFailure, BearerCredential, BearerCredentialScope,
16 BearerCredentialSnapshot, BearerRefreshHandoff, BearerToken, CredentialStateError,
17 CredentialStore, CredentialUpdateError, HttpsEndpoint, TokenRefreshError, TokenRotationError,
18 TransportError, map_authentication_error, validate_bearer_authentication,
19};
20
21#[derive(Clone)]
23pub struct BlockingClient {
24 client: RawBlockingClient,
25 endpoint: HttpsEndpoint,
26 scope: Arc<BearerCredentialScope>,
27 credentials: Arc<CredentialStore>,
28 allow_insecure_loopback: bool,
29}
30
31impl BlockingClient {
32 pub(super) fn new(
33 client: RawBlockingClient,
34 endpoint: HttpsEndpoint,
35 credential: BearerCredential,
36 allow_insecure_loopback: bool,
37 ) -> Self {
38 Self {
39 client,
40 endpoint,
41 scope: Arc::new(credential.scope),
42 credentials: Arc::new(CredentialStore::new(credential.token)),
43 allow_insecure_loopback,
44 }
45 }
46
47 pub fn credential_snapshot(&self) -> Result<BearerCredentialSnapshot, CredentialStateError> {
49 self.credentials.snapshot()
50 }
51
52 pub fn rotate_bearer_token(
57 &self,
58 replacement: BearerToken,
59 ) -> Result<CredentialGeneration, CredentialUpdateError> {
60 self.credentials.rotate(replacement)
61 }
62
63 pub fn rotate_bearer_token_from_mut_bytes(
65 &self,
66 source: &mut [u8],
67 ) -> Result<CredentialGeneration, TokenRotationError> {
68 self.credentials.rotate_from_mut_bytes(source)
69 }
70
71 pub fn rotate_bearer_token_from_secret_buffer(
73 &self,
74 source: SecretBuffer<'_>,
75 ) -> Result<CredentialGeneration, TokenRotationError> {
76 self.credentials.rotate_from_secret_buffer(source)
77 }
78
79 pub fn refresh_bearer_token(
81 &self,
82 handoff: BearerRefreshHandoff,
83 replacement: BearerToken,
84 ) -> Result<CredentialGeneration, TokenRefreshError> {
85 self.credentials.refresh(handoff, replacement)
86 }
87
88 pub fn refresh_bearer_token_from_mut_bytes(
90 &self,
91 handoff: BearerRefreshHandoff,
92 source: &mut [u8],
93 ) -> Result<CredentialGeneration, TokenRefreshError> {
94 self.credentials.refresh_from_mut_bytes(handoff, source)
95 }
96
97 pub fn refresh_bearer_token_from_secret_buffer(
99 &self,
100 handoff: BearerRefreshHandoff,
101 source: SecretBuffer<'_>,
102 ) -> Result<CredentialGeneration, TokenRefreshError> {
103 self.credentials.refresh_from_secret_buffer(handoff, source)
104 }
105
106 fn send_inner(
107 &self,
108 authenticated: AuthenticatedRequest<'_, '_>,
109 response_writer: &mut ResponseWriter<'_>,
110 ) -> Result<(), AuthenticatedTransportFailure> {
111 let endpoint_identity = self.endpoint.identity().map_err(|_| {
112 TransportFailure::not_sent(TransportError::AuthenticationEndpointMismatch)
113 })?;
114 validate_bearer_authentication(
115 endpoint_identity,
116 &self.scope,
117 authenticated.policy(),
118 self.allow_insecure_loopback,
119 )
120 .map_err(|error| TransportFailure::not_sent(map_authentication_error(error)))?;
121 let token_snapshot = self
122 .credentials
123 .snapshot()
124 .map_err(|_| TransportFailure::not_sent(TransportError::CredentialStateUnavailable))?;
125 let authorization = token_snapshot
126 .header_value()
127 .map_err(|_| TransportFailure::not_sent(TransportError::HeaderRejected))?;
128 drop(token_snapshot);
129 self.client
130 .execute_authenticated(
131 authenticated.transport_request(),
132 authenticated.response_policy(),
133 authorization,
134 response_writer,
135 )
136 .map_err(|failure| failure.map(TransportError::RawHttp))
137 }
138}
139
140impl BlockingAuthenticatedTransport for BlockingClient {
141 type Error = AuthenticatedTransportFailure;
142
143 fn send_authenticated(
144 &self,
145 request: AuthenticatedRequest<'_, '_>,
146 response: &mut ResponseWriter<'_>,
147 ) -> Result<(), Self::Error> {
148 self.send_inner(request, response)
149 }
150}
151
152impl ResponseStorageSanitizer for BlockingClient {
153 fn sanitize_response_storage(&self, response_storage: &mut [u8]) {
154 sanitize_bytes(response_storage);
155 }
156}
157
158impl BoundTransport for BlockingClient {
159 fn endpoint_identity(&self) -> Result<EndpointIdentity<'_>, EndpointIdentityError> {
160 self.endpoint.identity()
161 }
162}
163
164impl fmt::Debug for BlockingClient {
165 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
166 formatter
167 .debug_struct("BlockingClient")
168 .field("endpoint", &"[redacted]")
169 .field("scope", &"[redacted]")
170 .field("credentials", &"[redacted]")
171 .finish_non_exhaustive()
172 }
173}