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_executed_response(response)
29    }
30
31    pub(crate) async fn send_local_async<'transport, 'buffer, T>(
32        &'transport self,
33        transport: &'transport T,
34        response_storage: &'buffer mut [u8],
35        response_header_storage: &'buffer mut [u8],
36    ) -> Result<ResponseBuffer<'buffer>, PreparedExecutionError<T::Error>>
37    where
38        T: LocalAsyncAuthenticatedTransport + BoundTransport,
39        'request: 'transport,
40    {
41        if self.requires_execution_permit() {
42            sanitize_bytes(response_storage);
43            sanitize_bytes(response_header_storage);
44            return Err(PreparedExecutionError::AuthorizationRequired);
45        }
46        self.send_local_async_authorized(transport, None, response_storage, response_header_storage)
47            .await
48    }
49
50    pub(crate) async fn execute_local_async_authorized<'transport, 'buffer, T>(
51        &'transport self,
52        transport: &'transport T,
53        confirmed_endpoint: Option<EndpointIdentity<'_>>,
54        response_storage: &'buffer mut [u8],
55        response_header_storage: &'buffer mut [u8],
56    ) -> Result<CheckedResponseGuard<'buffer>, PreparedExecutionError<T::Error>>
57    where
58        T: LocalAsyncAuthenticatedTransport + BoundTransport,
59        'request: 'transport,
60    {
61        let response = self
62            .send_local_async_authorized(
63                transport,
64                confirmed_endpoint,
65                response_storage,
66                response_header_storage,
67            )
68            .await?;
69        self.validate_executed_response(response)
70    }
71
72    pub(crate) async fn send_local_async_authorized<'transport, 'buffer, T>(
73        &'transport self,
74        transport: &'transport T,
75        confirmed_endpoint: Option<EndpointIdentity<'_>>,
76        response_storage: &'buffer mut [u8],
77        response_header_storage: &'buffer mut [u8],
78    ) -> Result<ResponseBuffer<'buffer>, PreparedExecutionError<T::Error>>
79    where
80        T: LocalAsyncAuthenticatedTransport + BoundTransport,
81        'request: 'transport,
82    {
83        let mut response = ResponseBuffer::new(
84            response_storage,
85            self.raw_response_policy().max_body_bytes(),
86            response_header_storage,
87        );
88        let actual = transport
89            .endpoint_identity()
90            .map_err(PreparedExecutionError::EndpointIdentity)?;
91        match confirmed_endpoint {
92            Some(expected) if actual == expected => {}
93            Some(_) => return Err(PreparedExecutionError::EndpointMismatch),
94            None => self
95                .service()
96                .endpoint_policy()
97                .verify(actual)
98                .map_err(|_| PreparedExecutionError::EndpointMismatch)?,
99        }
100        drive_local_authenticated(transport, self.authenticated_request(), response.writer())
101            .await
102            .map_err(map_local_error)?;
103        Ok(response)
104    }
105}
106
107fn map_local_error<E>(error: AsyncExecutionError<E>) -> PreparedExecutionError<E> {
108    match error {
109        AsyncExecutionError::Transport(error) => PreparedExecutionError::Transport(error),
110        AsyncExecutionError::Response(error) => PreparedExecutionError::ResponseWriter(error),
111    }
112}