use super::{
component_name::{DerivedComponentName, HttpMessageComponentName},
component_param::{HttpMessageComponentParam, HttpMessageComponentParams},
};
use crate::error::{HttpSigError, HttpSigResult};
use sfv::Parser;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct HttpMessageComponentId {
pub name: HttpMessageComponentName,
pub params: HttpMessageComponentParams,
}
impl HttpMessageComponentId {
pub fn add_req_param(&mut self) {
self.params.0.insert(HttpMessageComponentParam::Req);
}
}
impl std::fmt::Display for HttpMessageComponentId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}{}", self.name, self.params)
}
}
impl TryFrom<&str> for HttpMessageComponentId {
type Error = HttpSigError;
fn try_from(val: &str) -> HttpSigResult<Self> {
let val = val.trim();
let item = if !val.starts_with('"') && !val.ends_with('"') && !val.is_empty() && !val.contains('"') {
Parser::parse_item(format!("\"{val}\"").as_bytes()).map_err(|e| HttpSigError::ParseSFVError(e.to_string()))?
} else {
Parser::parse_item(val.as_bytes()).map_err(|e| HttpSigError::ParseSFVError(e.to_string()))?
};
let res = Self {
name: HttpMessageComponentName::try_from(&item.bare_item)?,
params: HttpMessageComponentParams::try_from(&item.params)?,
};
if res.params.0.iter().any(|v| matches!(v, &HttpMessageComponentParam::Name(_)))
&& !matches!(res.name, HttpMessageComponentName::Derived(DerivedComponentName::QueryParam))
{
return Err(HttpSigError::InvalidComponentId(format!(
"Invalid http message component id: {res}"
)));
}
if res.params.0.iter().any(|v| {
matches!(v, &HttpMessageComponentParam::Bs)
|| matches!(v, &HttpMessageComponentParam::Sf)
|| matches!(v, &HttpMessageComponentParam::Tr)
|| matches!(v, &HttpMessageComponentParam::Key(_))
}) && !matches!(res.name, HttpMessageComponentName::HttpField(_))
{
return Err(HttpSigError::InvalidComponentId(format!(
"Invalid http message component id: {res}"
)));
}
Ok(res)
}
}