use console::style;
use hyper::{header::HeaderValue, HeaderMap};
use serde::Deserialize;
use std::collections::HashMap;
use super::util::fmt_condition_connector;
use crate::rule_set::rule::{
when::condition_statement::ConditionStatement, ConditionKey,
};
#[derive(Clone, Debug, Deserialize)]
#[serde(transparent)]
pub struct Headers(pub HashMap<ConditionKey, ConditionStatement>);
impl Headers {
pub fn is_match(
&self,
parsed_request_headers: &HeaderMap<HeaderValue>,
rule_idx: usize,
rule_set_idx: usize,
) -> bool {
self.0
.iter()
.all(|(matcher_header_key, matcher_header_value)| {
let parsed_request_header_value = match parsed_request_headers.get(matcher_header_key) {
Some(x) => x,
None => return false,
};
let parsed_request_header_value = match parsed_request_header_value.to_str() {
Ok(x) => x,
Err(err) => {
log::error!(
"{} to get request header value by key (rule #{} in rule set #{}):\n`{}`\n({})",
style("failed").red(),
rule_idx + 1,
rule_set_idx + 1,
matcher_header_key,
err,
);
return true;
}
};
let ret = matcher_header_value
.op
.clone()
.unwrap_or_default()
.is_match(parsed_request_header_value, &matcher_header_value.value);
ret
})
}
pub fn validate(&self) -> bool {
!self.0.is_empty()
}
}
impl std::fmt::Display for Headers {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = self
.0
.iter()
.map(|(header_key, header_statement)| format!("{}{}", header_key, header_statement))
.collect::<Vec<String>>()
.join(fmt_condition_connector().as_str());
let _ = write!(f, "[headers] {}", s);
Ok(())
}
}