diff --git a/src/modules/autodrop.rs b/src/modules/autodrop.rs index 74a58cd..b280f5a 100644 --- a/src/modules/autodrop.rs +++ b/src/modules/autodrop.rs @@ -7,10 +7,18 @@ //! autodrop_commands = GET POST HEAD CONNECT PUT DELETE OPTIONS TRACE PATCH //! ``` +use crate::map::HashSet; use crate::module::{ModResult, Module}; use crate::server::Server; use crate::Uid; +/// The autodrop-command set, parsed once and re-parsed only on rehash. +#[derive(Default)] +struct DropCache { + gen: u64, + cmds: HashSet, // uppercased +} + pub struct AutoDrop; impl Module for AutoDrop { @@ -29,10 +37,23 @@ impl Module for AutoDrop { if s.users.get(&uid).map(|u| u.registered).unwrap_or(true) { return ModResult::Passthru; } + // cache the set (config_gen-tagged): this hook runs hottest under the exact + // scanner flood it defends against, so don't re-split the config per packet. + let gen = s.config_gen; + let stale = s.ext.get::().map(|c| c.gen != gen).unwrap_or(true); + if stale { + let cmds: HashSet = s + .conf_all("autodrop_commands") + .iter() + .flat_map(|line| line.split_whitespace()) + .map(|w| w.to_ascii_uppercase()) + .collect(); + s.ext.set(DropCache { gen, cmds }); + } let hit = s - .conf_all("autodrop_commands") - .iter() - .any(|line| line.split_whitespace().any(|w| w.eq_ignore_ascii_case(cmd))); + .ext + .get::() + .is_some_and(|c| c.cmds.contains(&cmd.to_ascii_uppercase())); if hit { s.send(uid, "ERROR :Closing link (dropped)".to_string()); s.remove_user(uid, "Autodropped");