use crate::header::{AmzDate, CredentialV4};
use crate::http::OrderedQs;
use crate::utils::is_sha256_checksum;
use smallvec::SmallVec;
#[derive(Debug)]
pub struct PresignedUrl<'a> {
pub algorithm: &'a str,
pub credential: CredentialV4<'a>,
pub amz_date: AmzDate,
pub expires: u32,
pub signed_headers: SmallVec<[&'a str; 16]>,
pub signature: &'a str,
}
#[derive(Debug, thiserror::Error)]
#[error("ParsePresignedUrlError")]
pub struct ParsePresignedUrlError {
_priv: (),
}
struct PresignedQs<'a> {
x_amz_algorithm: &'a str,
x_amz_credential: &'a str,
x_amz_date: &'a str,
x_amz_expires: &'a str,
x_amz_signed_headers: &'a str,
x_amz_signature: &'a str,
}
impl<'a> PresignedQs<'a> {
fn from_ordered_qs(qs: &'a OrderedQs) -> Option<Self> {
Some(PresignedQs {
x_amz_algorithm: qs.get_unique("X-Amz-Algorithm")?,
x_amz_credential: qs.get_unique("X-Amz-Credential")?,
x_amz_date: qs.get_unique("X-Amz-Date")?,
x_amz_expires: qs.get_unique("X-Amz-Expires")?,
x_amz_signed_headers: qs.get_unique("X-Amz-SignedHeaders")?,
x_amz_signature: qs.get_unique("X-Amz-Signature")?,
})
}
}
impl<'a> PresignedUrl<'a> {
pub fn parse(qs: &'a OrderedQs) -> Result<Self, ParsePresignedUrlError> {
let err = || ParsePresignedUrlError { _priv: () };
let info = PresignedQs::from_ordered_qs(qs).ok_or_else(err)?;
let algorithm = info.x_amz_algorithm;
let credential = CredentialV4::parse(info.x_amz_credential).map_err(|_e| err())?;
let amz_date = AmzDate::parse(info.x_amz_date).map_err(|_e| err())?;
let expires: u32 = info.x_amz_expires.parse().map_err(|_e| err())?;
if !info.x_amz_signed_headers.is_ascii() {
return Err(err());
}
let signed_headers = info.x_amz_signed_headers.split(';').collect();
if !is_sha256_checksum(info.x_amz_signature) {
return Err(err());
}
let signature = info.x_amz_signature;
Ok(Self {
algorithm,
credential,
amz_date,
expires,
signed_headers,
signature,
})
}
}