use http::{HeaderMap, header::AsHeaderName};
use crate::{Error, Result};
pub(crate) fn header_string<N>(headers: &HeaderMap, name: N) -> Option<String>
where
N: AsHeaderName,
{
headers
.get(name)
.and_then(|v| v.to_str().ok())
.map(|v| v.to_string())
}
pub(crate) fn header_u64<N>(headers: &HeaderMap, name: N) -> Option<u64>
where
N: AsHeaderName,
{
headers
.get(name)
.and_then(|v| v.to_str().ok())
.and_then(|v| v.parse::<u64>().ok())
}
pub(crate) fn copy_source_header_value(
bucket: &str,
key: &str,
version_id: Option<&str>,
) -> Result<String> {
let bucket_enc = crate::util::encode::aws_percent_encode(bucket);
let key_enc = crate::util::encode::aws_percent_encode_path(key);
let value = match version_id {
Some(v) => {
validate_version_id(v)?;
let version_enc = crate::util::encode::aws_percent_encode(v);
format!("/{bucket_enc}/{key_enc}?versionId={version_enc}")
}
None => format!("/{bucket_enc}/{key_enc}"),
};
Ok(value)
}
pub(crate) fn validate_version_id(version_id: &str) -> Result<()> {
if version_id.is_empty() {
return Err(Error::invalid_config("version_id must not be empty"));
}
if version_id.trim() != version_id {
return Err(Error::invalid_config(
"version_id must not include leading or trailing whitespace",
));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn extracts_string_and_u64_headers() {
let mut headers = HeaderMap::new();
headers.insert("etag", "\"abc\"".parse().unwrap());
headers.insert("content-length", "42".parse().unwrap());
assert_eq!(header_string(&headers, "etag").as_deref(), Some("\"abc\""));
assert_eq!(header_u64(&headers, "content-length"), Some(42));
}
#[test]
fn copy_source_header_value_encodes_bucket_key_and_version() {
assert_eq!(
copy_source_header_value("bucket name", "dir/file name.txt", Some("v 1")).unwrap(),
"/bucket%20name/dir/file%20name.txt?versionId=v%201"
);
}
#[test]
fn copy_source_header_value_rejects_invalid_version_id() {
assert!(copy_source_header_value("bucket", "key", Some("")).is_err());
assert!(copy_source_header_value("bucket", "key", Some(" version")).is_err());
assert!(copy_source_header_value("bucket", "key", Some("version ")).is_err());
}
}