cloud-sdk 0.37.0

no_std-first provider-neutral cloud SDK foundations.
Documentation
use super::{ContentTypePolicy, ResponseBodyPolicy, ResponsePolicy, ResponsePolicyError};
use crate::transport::{
    MediaType, ResponseBuffer, ResponseContentType, ResponseMetadata, ResponseStorageSanitizer,
    StatusCode,
};

static OK_STATUS: [StatusCode; 1] = [StatusCode::OK];
static JSON_MEDIA: [MediaType<'static>; 1] = [MediaType::JSON];

#[test]
fn response_policy_classifies_every_rejection_before_decoding() {
    let required = json_response_policy(4);
    assert!(required.is_ok());
    let Ok(required) = required else { return };
    let json = ResponseContentType::new("application/json; charset=utf-8");
    assert!(json.is_ok());
    let Ok(json) = json else { return };

    let status = StatusCode::new(201).unwrap_or(StatusCode::OK);
    assert!(matches!(
        validate_fixture(required, status, b"{}", ResponseMetadata::EMPTY),
        Err(ResponsePolicyError::UnexpectedStatus)
    ));
    assert!(matches!(
        validate_fixture(required, StatusCode::OK, b"12345", ResponseMetadata::EMPTY,),
        Err(ResponsePolicyError::BodyTooLarge)
    ));
    assert!(matches!(
        validate_fixture(required, StatusCode::OK, b"", ResponseMetadata::EMPTY),
        Err(ResponsePolicyError::MissingBody)
    ));
    assert!(matches!(
        validate_fixture(required, StatusCode::OK, b"{}", ResponseMetadata::EMPTY,),
        Err(ResponsePolicyError::MissingContentType)
    ));
    let text = ResponseContentType::new("text/plain");
    assert!(text.is_ok());
    if let Ok(text) = text {
        assert!(matches!(
            validate_fixture(
                required,
                StatusCode::OK,
                b"{}",
                ResponseMetadata::EMPTY.with_content_type(text),
            ),
            Err(ResponsePolicyError::UnexpectedContentType)
        ));
    }
    assert_eq!(
        validate_fixture(
            required,
            StatusCode::OK,
            b"{}",
            ResponseMetadata::EMPTY.with_content_type(json),
        ),
        Ok(2)
    );

    let forbidden = ResponsePolicy::new(
        &OK_STATUS,
        ContentTypePolicy::Forbidden,
        ResponseBodyPolicy::Forbidden,
        0,
    );
    assert!(forbidden.is_ok());
    if let Ok(forbidden) = forbidden {
        assert!(matches!(
            validate_fixture(forbidden, StatusCode::OK, b"x", ResponseMetadata::EMPTY,),
            Err(ResponsePolicyError::ForbiddenBody)
        ));
        assert!(matches!(
            validate_fixture(
                forbidden,
                StatusCode::OK,
                b"",
                ResponseMetadata::EMPTY.with_content_type(json),
            ),
            Err(ResponsePolicyError::ForbiddenContentType)
        ));
    }
}

fn json_response_policy(
    max_body_bytes: usize,
) -> Result<ResponsePolicy, super::ResponsePolicyValidationError> {
    ResponsePolicy::new(
        &OK_STATUS,
        ContentTypePolicy::Required(&JSON_MEDIA),
        ResponseBodyPolicy::Required,
        max_body_bytes,
    )
}

fn validate_fixture(
    policy: ResponsePolicy,
    status: StatusCode,
    body: &[u8],
    metadata: ResponseMetadata,
) -> Result<usize, ResponsePolicyError> {
    let mut storage = [0_u8; 32];
    let mut response = ResponseBuffer::new(&mut storage, 32, &FixtureSanitizer);
    let output = response
        .writer()
        .body_mut()
        .map_err(|_| ResponsePolicyError::UncommittedResponse)?;
    let initialized = output
        .get_mut(..body.len())
        .ok_or(ResponsePolicyError::BodyTooLarge)?;
    initialized.copy_from_slice(body);
    response
        .writer()
        .commit(status, body.len(), metadata)
        .map_err(|_| ResponsePolicyError::UncommittedResponse)?;
    policy
        .validate(response)
        .map(|checked| checked.with_borrowed(|view| view.body().len()))
}

struct FixtureSanitizer;

impl ResponseStorageSanitizer for FixtureSanitizer {
    fn sanitize_response_storage(&self, response_storage: &mut [u8]) {
        response_storage.fill(0);
    }
}