Skip to main content

cloud_sdk/operation/
local_async.rs

1//! Local asynchronous prepared-request execution.
2
3use super::{CheckedResponseGuard, PreparedExecutionError, PreparedRequest};
4use crate::authentication::{LocalAsyncAuthenticatedTransport, drive_local_authenticated};
5use crate::transport::{AsyncExecutionError, BoundTransport, EndpointIdentity, ResponseBuffer};
6use cloud_sdk_sanitization::sanitize_bytes;
7
8impl<'request> PreparedRequest<'request> {
9    /// Verifies endpoint identity, executes once on a local async transport,
10    /// and validates the response.
11    ///
12    /// This method owns no executor and does not require the returned future
13    /// to be `Send`. Dropping it clears the response buffer while request
14    /// delivery remains conservatively possibly sent.
15    pub async fn execute_local_async<'transport, 'buffer, T>(
16        &'transport self,
17        transport: &'transport T,
18        response_storage: &'buffer mut [u8],
19        response_header_storage: &'buffer mut [u8],
20    ) -> Result<CheckedResponseGuard<'buffer>, PreparedExecutionError<T::Error>>
21    where
22        T: LocalAsyncAuthenticatedTransport + BoundTransport,
23        'request: 'transport,
24    {
25        let response = self
26            .send_local_async(transport, response_storage, response_header_storage)
27            .await?;
28        self.validate_response(response)
29            .map_err(PreparedExecutionError::ResponsePolicy)
30    }
31
32    pub(crate) async fn send_local_async<'transport, 'buffer, T>(
33        &'transport self,
34        transport: &'transport T,
35        response_storage: &'buffer mut [u8],
36        response_header_storage: &'buffer mut [u8],
37    ) -> Result<ResponseBuffer<'buffer>, PreparedExecutionError<T::Error>>
38    where
39        T: LocalAsyncAuthenticatedTransport + BoundTransport,
40        'request: 'transport,
41    {
42        if self.requires_execution_permit() {
43            sanitize_bytes(response_storage);
44            sanitize_bytes(response_header_storage);
45            return Err(PreparedExecutionError::AuthorizationRequired);
46        }
47        self.send_local_async_authorized(transport, None, response_storage, response_header_storage)
48            .await
49    }
50
51    pub(crate) async fn execute_local_async_authorized<'transport, 'buffer, T>(
52        &'transport self,
53        transport: &'transport T,
54        confirmed_endpoint: Option<EndpointIdentity<'_>>,
55        response_storage: &'buffer mut [u8],
56        response_header_storage: &'buffer mut [u8],
57    ) -> Result<CheckedResponseGuard<'buffer>, PreparedExecutionError<T::Error>>
58    where
59        T: LocalAsyncAuthenticatedTransport + BoundTransport,
60        'request: 'transport,
61    {
62        let response = self
63            .send_local_async_authorized(
64                transport,
65                confirmed_endpoint,
66                response_storage,
67                response_header_storage,
68            )
69            .await?;
70        self.validate_response(response)
71            .map_err(PreparedExecutionError::ResponsePolicy)
72    }
73
74    pub(crate) async fn send_local_async_authorized<'transport, 'buffer, T>(
75        &'transport self,
76        transport: &'transport T,
77        confirmed_endpoint: Option<EndpointIdentity<'_>>,
78        response_storage: &'buffer mut [u8],
79        response_header_storage: &'buffer mut [u8],
80    ) -> Result<ResponseBuffer<'buffer>, PreparedExecutionError<T::Error>>
81    where
82        T: LocalAsyncAuthenticatedTransport + BoundTransport,
83        'request: 'transport,
84    {
85        let mut response = ResponseBuffer::new(
86            response_storage,
87            self.raw_response_policy().max_body_bytes(),
88            response_header_storage,
89        );
90        let actual = transport
91            .endpoint_identity()
92            .map_err(PreparedExecutionError::EndpointIdentity)?;
93        match confirmed_endpoint {
94            Some(expected) if actual == expected => {}
95            Some(_) => return Err(PreparedExecutionError::EndpointMismatch),
96            None => self
97                .service()
98                .endpoint_policy()
99                .verify(actual)
100                .map_err(|_| PreparedExecutionError::EndpointMismatch)?,
101        }
102        drive_local_authenticated(transport, self.authenticated_request(), response.writer())
103            .await
104            .map_err(map_local_error)?;
105        Ok(response)
106    }
107}
108
109fn map_local_error<E>(error: AsyncExecutionError<E>) -> PreparedExecutionError<E> {
110    match error {
111        AsyncExecutionError::Transport(error) => PreparedExecutionError::Transport(error),
112        AsyncExecutionError::Response(error) => PreparedExecutionError::ResponseWriter(error),
113    }
114}