use super::*;
pub(crate) fn list_objects_xml(result: &ListObjectsResult, list_type_v2: bool) -> String {
let contents = result
.objects
.iter()
.map(|object| {
let owner = object
.owner
.as_ref()
.map(|owner| {
format!(
"<Owner><ID>{}</ID><DisplayName>{}</DisplayName></Owner>",
xml_escape(owner),
xml_escape(owner)
)
})
.unwrap_or_default();
format!(
"<Contents><Key>{}</Key><ETag>{}</ETag><LastModified>{}</LastModified><VersionId>{}</VersionId><Size>{}</Size>{owner}</Contents>",
list_xml_value(&object.key, result),
xml_escape("e_etag(&object.etag)),
object.last_modified_epoch_seconds,
xml_escape(&object.version_id),
object.content_length
)
})
.collect::<String>();
let common_prefixes = result
.common_prefixes
.iter()
.map(|prefix| {
format!(
"<CommonPrefixes><Prefix>{}</Prefix></CommonPrefixes>",
list_xml_value(&prefix.prefix, result)
)
})
.collect::<String>();
let prefix = result
.prefix
.as_ref()
.map(|prefix| format!("<Prefix>{}</Prefix>", list_xml_value(prefix, result)))
.unwrap_or_default();
let delimiter = result
.delimiter
.as_ref()
.map(|delimiter| {
format!(
"<Delimiter>{}</Delimiter>",
list_xml_value(delimiter, result)
)
})
.unwrap_or_default();
let encoding_type = result
.encoding_type
.as_ref()
.map(|encoding_type| format!("<EncodingType>{}</EncodingType>", xml_escape(encoding_type)))
.unwrap_or_default();
let marker = result
.marker
.as_ref()
.map(|marker| format!("<Marker>{}</Marker>", list_xml_value(marker, result)))
.unwrap_or_default();
let next_marker = result
.next_marker
.as_ref()
.map(|marker| format!("<NextMarker>{}</NextMarker>", list_xml_value(marker, result)))
.unwrap_or_default();
let next_token = result
.next_continuation_token
.as_ref()
.map(|token| {
format!(
"<NextContinuationToken>{}</NextContinuationToken>",
list_xml_value(token, result)
)
})
.unwrap_or_default();
let continuation_token = result
.continuation_token
.as_ref()
.map(|token| {
format!(
"<ContinuationToken>{}</ContinuationToken>",
list_xml_value(token, result)
)
})
.unwrap_or_default();
let start_after = result
.start_after
.as_ref()
.map(|start_after| {
format!(
"<StartAfter>{}</StartAfter>",
list_xml_value(start_after, result)
)
})
.unwrap_or_default();
if list_type_v2 {
return format!(
"<ListBucketResult><Name>{}</Name>{prefix}{delimiter}{encoding_type}<KeyCount>{}</KeyCount><MaxKeys>{}</MaxKeys><IsTruncated>{}</IsTruncated>{continuation_token}{start_after}{next_token}{contents}{common_prefixes}</ListBucketResult>",
xml_escape(&result.bucket),
result.key_count,
result.max_keys,
result.is_truncated
);
}
format!(
"<ListBucketResult><Name>{}</Name>{prefix}{marker}{delimiter}{encoding_type}<MaxKeys>{}</MaxKeys><IsTruncated>{}</IsTruncated>{next_marker}{contents}{common_prefixes}</ListBucketResult>",
xml_escape(&result.bucket),
result.max_keys,
result.is_truncated
)
}
pub(crate) fn list_xml_value(value: &str, result: &ListObjectsResult) -> String {
if result.encoding_type.as_deref() == Some("url") {
percent_encode(value)
} else {
xml_escape(value)
}
}
pub(crate) fn list_object_versions_xml(result: &ListObjectVersionsResult) -> String {
let versions = result
.versions
.iter()
.map(|version| {
let owner = version
.owner
.as_ref()
.map(|owner| {
format!(
"<Owner><ID>{}</ID><DisplayName>{}</DisplayName></Owner>",
xml_escape(owner),
xml_escape(owner)
)
})
.unwrap_or_default();
format!(
"<Version><Key>{}</Key><VersionId>{}</VersionId><IsLatest>{}</IsLatest><LastModified>{}</LastModified><ETag>{}</ETag><Size>{}</Size>{owner}</Version>",
version_list_xml_value(&version.key, result),
xml_escape(&version.version_id),
version.is_latest,
version.last_modified_epoch_seconds,
xml_escape("e_etag(&version.etag)),
version.content_length
)
})
.collect::<String>();
let delete_markers = result
.delete_markers
.iter()
.map(|marker| {
format!(
"<DeleteMarker><Key>{}</Key><VersionId>{}</VersionId><IsLatest>{}</IsLatest><LastModified>{}</LastModified></DeleteMarker>",
version_list_xml_value(&marker.key, result),
xml_escape(&marker.version_id),
marker.is_latest,
marker.last_modified_epoch_seconds
)
})
.collect::<String>();
let prefix = result
.prefix
.as_ref()
.map(|prefix| {
format!(
"<Prefix>{}</Prefix>",
version_list_xml_value(prefix, result)
)
})
.unwrap_or_default();
let key_marker = result
.key_marker
.as_ref()
.map(|marker| {
format!(
"<KeyMarker>{}</KeyMarker>",
version_list_xml_value(marker, result)
)
})
.unwrap_or_default();
let version_id_marker = result
.version_id_marker
.as_ref()
.map(|marker| format!("<VersionIdMarker>{}</VersionIdMarker>", xml_escape(marker)))
.unwrap_or_default();
let next_key_marker = result
.next_key_marker
.as_ref()
.map(|marker| {
format!(
"<NextKeyMarker>{}</NextKeyMarker>",
version_list_xml_value(marker, result)
)
})
.unwrap_or_default();
let next_version_id_marker = result
.next_version_id_marker
.as_ref()
.map(|marker| {
format!(
"<NextVersionIdMarker>{}</NextVersionIdMarker>",
xml_escape(marker)
)
})
.unwrap_or_default();
let encoding_type = result
.encoding_type
.as_ref()
.map(|encoding_type| format!("<EncodingType>{}</EncodingType>", xml_escape(encoding_type)))
.unwrap_or_default();
format!(
"<ListVersionsResult><Name>{}</Name>{prefix}{encoding_type}{key_marker}{version_id_marker}<MaxKeys>{}</MaxKeys><IsTruncated>{}</IsTruncated><KeyCount>{}</KeyCount>{next_key_marker}{next_version_id_marker}{versions}{delete_markers}</ListVersionsResult>",
xml_escape(&result.bucket),
result.max_keys,
result.is_truncated,
result.key_count
)
}
pub(crate) fn object_tagging_xml(result: &ObjectTaggingResult) -> String {
tags_xml(&result.tags)
}
pub(crate) fn object_legal_hold_xml(result: &ObjectLegalHoldResult) -> String {
let status = if result.enabled { "ON" } else { "OFF" };
format!("<LegalHold><Status>{status}</Status></LegalHold>")
}
pub(crate) fn object_retention_xml(result: &ObjectRetentionResult) -> String {
match (&result.mode, result.retain_until_epoch_seconds) {
(Some(mode), Some(retain_until)) => format!(
"<Retention><Mode>{}</Mode><RetainUntilDate>{}</RetainUntilDate></Retention>",
xml_escape(mode),
format_retention_timestamp(retain_until)
),
_ => "<Retention></Retention>".to_string(),
}
}
pub(crate) fn tags_xml(tags: &BTreeMap<String, String>) -> String {
let tags = tags
.iter()
.map(|(key, value)| {
format!(
"<Tag><Key>{}</Key><Value>{}</Value></Tag>",
xml_escape(key),
xml_escape(value)
)
})
.collect::<String>();
format!("<Tagging><TagSet>{tags}</TagSet></Tagging>")
}
pub(crate) fn version_list_xml_value(value: &str, result: &ListObjectVersionsResult) -> String {
if result.encoding_type.as_deref() == Some("url") {
percent_encode(value)
} else {
xml_escape(value)
}
}
pub(crate) fn copy_object_xml(result: &CopyObjectResult) -> String {
format!(
"<CopyObjectResult><ETag>{}</ETag><VersionId>{}</VersionId></CopyObjectResult>",
xml_escape("e_etag(&result.etag)),
xml_escape(&result.version_id)
)
}