use core::fmt;
use std::sync::Arc;
use cloud_sdk::authentication::{AuthenticatedRequest, BlockingAuthenticatedTransport};
use cloud_sdk::transport::{
BoundTransport, EndpointIdentity, EndpointIdentityError, ResponseStorageSanitizer,
ResponseWriter,
};
use cloud_sdk_sanitization::sanitize_bytes;
use reqwest::blocking::Client;
use crate::shared::{
BasicCredential, HttpsEndpoint, TransportError, map_authentication_error,
validate_basic_authentication,
};
use super::client::execute;
#[derive(Clone)]
pub struct BlockingBasicClient {
client: Client,
endpoint: HttpsEndpoint,
credential: Arc<BasicCredential>,
allow_insecure_loopback: bool,
}
impl BlockingBasicClient {
pub(super) fn new(
client: Client,
endpoint: HttpsEndpoint,
credential: BasicCredential,
allow_insecure_loopback: bool,
) -> Self {
Self {
client,
endpoint,
credential: Arc::new(credential),
allow_insecure_loopback,
}
}
fn send_inner(
&self,
authenticated: AuthenticatedRequest<'_, '_>,
response: &mut ResponseWriter<'_>,
) -> Result<(), TransportError> {
let mut response_attempt = response
.begin_attempt()
.map_err(|_| TransportError::ResponseCommitFailed)?;
let endpoint = self
.endpoint
.identity()
.map_err(|_| TransportError::AuthenticationEndpointMismatch)?;
validate_basic_authentication(
endpoint,
self.credential.scope(),
authenticated.policy(),
self.allow_insecure_loopback,
)
.map_err(map_authentication_error)?;
let authorization = self
.credential
.header_value()
.map_err(|_| TransportError::HeaderRejected)?;
execute(
&self.client,
&self.endpoint,
authorization,
authenticated,
&mut response_attempt,
)
}
}
impl BlockingAuthenticatedTransport for BlockingBasicClient {
type Error = TransportError;
fn send_authenticated(
&self,
request: AuthenticatedRequest<'_, '_>,
response: &mut ResponseWriter<'_>,
) -> Result<(), Self::Error> {
self.send_inner(request, response)
}
}
impl ResponseStorageSanitizer for BlockingBasicClient {
fn sanitize_response_storage(&self, response_storage: &mut [u8]) {
sanitize_bytes(response_storage);
}
}
impl BoundTransport for BlockingBasicClient {
fn endpoint_identity(&self) -> Result<EndpointIdentity<'_>, EndpointIdentityError> {
self.endpoint.identity()
}
}
impl fmt::Debug for BlockingBasicClient {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("BlockingBasicClient")
.field("endpoint", &"[redacted]")
.field("credential", &"[redacted]")
.finish_non_exhaustive()
}
}