bucketwarden-server 0.1.0

BucketWarden storage server runtime.
Documentation
use super::*;

use super::*;
pub(crate) fn xml_response(status: u16, body: String) -> S3HttpResponse {
    S3HttpResponse::new(status)
        .with_header("content-type", "application/xml")
        .with_header("content-length", body.len().to_string())
        .with_body(body.into_bytes())
}
pub(crate) fn list_buckets_xml(buckets: &[Bucket]) -> String {
    let bucket_entries = buckets
        .iter()
        .map(|bucket| {
            format!(
                "<Bucket><Name>{}</Name><CreationDate>{}</CreationDate></Bucket>",
                xml_escape(&bucket.name),
                xml_escape(&bucket.creation_date)
            )
        })
        .collect::<String>();
    format!("<ListAllMyBucketsResult><Buckets>{bucket_entries}</Buckets></ListAllMyBucketsResult>")
}
pub(crate) fn list_directory_buckets_xml(result: &ListDirectoryBucketsResult) -> String {
    let buckets = result
        .buckets
        .iter()
        .map(|bucket| {
            let info = bucket.bucket_info.as_ref();
            format!(
                "<Bucket><BucketArn>{}</BucketArn><BucketRegion>{}</BucketRegion><CreationDate>{}</CreationDate><Name>{}</Name></Bucket>",
                xml_escape(info.and_then(|value| value.bucket_arn.as_deref()).unwrap_or_default()),
                xml_escape(info.and_then(|value| value.bucket_region.as_deref()).unwrap_or_default()),
                xml_escape(&bucket.creation_date),
                xml_escape(&bucket.name)
            )
        })
        .collect::<String>();
    let continuation_token = result
        .continuation_token
        .as_ref()
        .map(|value| {
            format!(
                "<ContinuationToken>{}</ContinuationToken>",
                xml_escape(value)
            )
        })
        .unwrap_or_default();
    format!(
        "<ListAllMyDirectoryBucketsResult><Buckets>{buckets}</Buckets>{continuation_token}</ListAllMyDirectoryBucketsResult>"
    )
}
pub(crate) fn bucket_versioning_xml(result: &BucketVersioningResult) -> String {
    format!(
        "<VersioningConfiguration><Status>{}</Status></VersioningConfiguration>",
        versioning_status_text(result.status)
    )
}
pub(crate) fn bucket_location_xml(result: &BucketLocationResult) -> String {
    let constraint = if result.region == DEFAULT_BUCKET_REGION {
        String::new()
    } else {
        xml_escape(&result.region)
    };
    format!("<LocationConstraint>{constraint}</LocationConstraint>")
}
pub(crate) fn bucket_cors_xml(result: &BucketCorsResult) -> String {
    let rules = result
        .rules
        .iter()
        .map(|rule| {
            let origins = rule
                .allowed_origins
                .iter()
                .map(|value| format!("<AllowedOrigin>{}</AllowedOrigin>", xml_escape(value)))
                .collect::<String>();
            let methods = rule
                .allowed_methods
                .iter()
                .map(|value| format!("<AllowedMethod>{}</AllowedMethod>", xml_escape(value)))
                .collect::<String>();
            let headers = rule
                .allowed_headers
                .iter()
                .map(|value| format!("<AllowedHeader>{}</AllowedHeader>", xml_escape(value)))
                .collect::<String>();
            let expose = rule
                .expose_headers
                .iter()
                .map(|value| format!("<ExposeHeader>{}</ExposeHeader>", xml_escape(value)))
                .collect::<String>();
            let max_age = rule
                .max_age_seconds
                .map(|value| format!("<MaxAgeSeconds>{value}</MaxAgeSeconds>"))
                .unwrap_or_default();
            format!("<CORSRule>{origins}{methods}{headers}{expose}{max_age}</CORSRule>")
        })
        .collect::<String>();
    format!("<CORSConfiguration>{rules}</CORSConfiguration>")
}
pub(crate) fn bucket_logging_xml(logging: Option<&str>) -> String {
    logging
        .map(parse_bucket_logging_status)
        .transpose()
        .expect("stored bucket logging XML must remain valid")
        .map(|status| bucket_logging_status_xml(&status))
        .unwrap_or_else(|| "<BucketLoggingStatus></BucketLoggingStatus>".to_string())
}
pub(crate) fn bucket_logging_status_xml(status: &BucketLoggingStatus) -> String {
    let logging_enabled = status
        .logging_enabled
        .as_ref()
        .map(|logging| {
            format!(
                "<LoggingEnabled><TargetBucket>{}</TargetBucket><TargetPrefix>{}</TargetPrefix></LoggingEnabled>",
                xml_escape(&logging.target_bucket),
                xml_escape(&logging.target_prefix)
            )
        })
        .unwrap_or_default();
    format!("<BucketLoggingStatus>{logging_enabled}</BucketLoggingStatus>")
}
pub(crate) fn bucket_website_configuration_xml(result: &BucketWebsiteConfiguration) -> String {
    let error_document = result
        .error_document_key
        .as_ref()
        .map(|key| {
            format!(
                "<ErrorDocument><Key>{}</Key></ErrorDocument>",
                xml_escape(key)
            )
        })
        .unwrap_or_default();
    let routing_rules = result
        .routing_rules
        .iter()
        .map(|rule| {
            let condition = Condition {
                key_prefix_equals: rule.condition_key_prefix_equals.clone(),
            }
            .key_prefix_equals
                .as_ref()
                .map(|prefix| {
                    format!(
                        "<Condition><KeyPrefixEquals>{}</KeyPrefixEquals></Condition>",
                        xml_escape(prefix)
                    )
                })
                .unwrap_or_default();
            let host_name = rule
                .redirect_host_name
                .as_ref()
                .map(|value| format!("<HostName>{}</HostName>", xml_escape(value)))
                .unwrap_or_default();
            let replace_prefix = rule
                .redirect_replace_key_prefix_with
                .as_ref()
                .map(|value| {
                    format!(
                        "<ReplaceKeyPrefixWith>{}</ReplaceKeyPrefixWith>",
                        xml_escape(value)
                    )
                })
                .unwrap_or_default();
            let code = rule
                .redirect_http_redirect_code
                .as_ref()
                .map(|value| format!("<HttpRedirectCode>{}</HttpRedirectCode>", xml_escape(value)))
                .unwrap_or_default();
            format!(
                "<RoutingRule>{condition}<Redirect>{host_name}{replace_prefix}{code}</Redirect></RoutingRule>"
            )
        })
        .collect::<String>();
    let routing_rules = if routing_rules.is_empty() {
        String::new()
    } else {
        format!("<RoutingRules>{routing_rules}</RoutingRules>")
    };
    format!(
        "<WebsiteConfiguration><IndexDocument><Suffix>{}</Suffix></IndexDocument>{error_document}{routing_rules}</WebsiteConfiguration>",
        xml_escape(&result.index_document_suffix)
    )
}
pub(crate) fn bucket_tagging_xml(result: &BucketTaggingResult) -> String {
    tags_xml(&result.tags)
}
pub(crate) fn bucket_accelerate_configuration_xml(
    result: &BucketAccelerateConfiguration,
) -> String {
    format!(
        "<AccelerateConfiguration><Status>{}</Status></AccelerateConfiguration>",
        xml_escape(&result.status)
    )
}
pub(crate) fn bucket_policy_status_xml(result: &BucketPolicyStatus) -> String {
    format!(
        "<PolicyStatus><IsPublic>{}</IsPublic></PolicyStatus>",
        if result.is_public { "true" } else { "false" }
    )
}
pub(crate) fn bucket_abac_status_xml(result: &BucketAbacStatus) -> String {
    format!(
        "<AbacStatus><Status>{}</Status></AbacStatus>",
        xml_escape(&result.status)
    )
}
pub(crate) fn bucket_request_payment_xml(result: &BucketRequestPaymentConfiguration) -> String {
    format!(
        "<RequestPaymentConfiguration><Payer>{}</Payer></RequestPaymentConfiguration>",
        xml_escape(&result.payer)
    )
}
pub(crate) fn create_session_result_xml(result: &CreateSessionResult) -> String {
    format!(
        "<CreateSessionResult><Credentials><AccessKeyId>{}</AccessKeyId><Expiration>{}</Expiration><SecretAccessKey>{}</SecretAccessKey><SessionToken>{}</SessionToken></Credentials></CreateSessionResult>",
        xml_escape(&result.credentials.access_key_id),
        xml_escape(&result.credentials.expiration),
        xml_escape(&result.credentials.secret_access_key),
        xml_escape(&result.credentials.session_token),
    )
}
pub(crate) fn public_access_block_configuration_xml(
    result: &PublicAccessBlockConfiguration,
) -> String {
    let bool_xml = |value: bool| if value { "true" } else { "false" };
    format!(
        "<PublicAccessBlockConfiguration><BlockPublicAcls>{}</BlockPublicAcls><IgnorePublicAcls>{}</IgnorePublicAcls><BlockPublicPolicy>{}</BlockPublicPolicy><RestrictPublicBuckets>{}</RestrictPublicBuckets></PublicAccessBlockConfiguration>",
        bool_xml(result.block_public_acls),
        bool_xml(result.ignore_public_acls),
        bool_xml(result.block_public_policy),
        bool_xml(result.restrict_public_buckets)
    )
}