use aho_corasick::AhoCorasick;
use once_cell::sync::Lazy;
use serde::Deserialize;
#[derive(Deserialize)]
struct BlockingRules {
indicator: Vec<BlockingIndicator>,
}
#[derive(Deserialize)]
struct BlockingIndicator {
phrase: String,
#[serde(default)]
#[allow(dead_code)] description: String,
}
static BLOCK_INDICATORS: Lazy<Vec<String>> = Lazy::new(|| {
let raw = include_str!("../../rules/blocking/indicators.toml");
let parsed: BlockingRules =
toml::from_str(raw).expect("rules/blocking/indicators.toml must parse");
parsed.indicator.into_iter().map(|i| i.phrase).collect()
});
static BLOCK_AC: Lazy<AhoCorasick> = Lazy::new(|| {
AhoCorasick::builder()
.ascii_case_insensitive(true)
.build(BLOCK_INDICATORS.iter().map(String::as_str))
.expect("block indicators are valid AC patterns")
});
#[must_use]
pub fn is_blocked_response(status: u16, body: &[u8]) -> bool {
if matches!(
status,
401 | 403 | 405 | 406 | 407 | 429 | 499 | 502 | 503 | 504 | 520..=526
) {
return true;
}
let window = &body[..body.len().min(4096)];
BLOCK_AC.is_match(window)
}