http_acl/
acl.rs

1//! Contains the [`HttpAcl`], [`HttpAclBuilder`],
2//! and related types.
3
4#[cfg(feature = "hashbrown")]
5use hashbrown::{HashMap, HashSet, hash_map::Entry};
6#[cfg(not(feature = "hashbrown"))]
7use std::collections::{HashMap, HashSet, hash_map::Entry};
8use std::hash::Hash;
9use std::net::{IpAddr, SocketAddr};
10use std::ops::RangeInclusive;
11use std::sync::Arc;
12
13use matchit::Router;
14#[cfg(feature = "serde")]
15use serde::{Deserialize, Serialize};
16
17use crate::{
18    error::AddError,
19    utils::{self, IntoIpRange, authority::Authority},
20};
21
22/// A function that validates an HTTP request against an ACL.
23pub type ValidateFn = Arc<
24    dyn for<'h> Fn(
25            &str,
26            &Authority,
27            Box<dyn Iterator<Item = (&'h str, &'h str)> + Send + Sync + 'h>,
28            Option<&[u8]>,
29        ) -> AclClassification
30        + Send
31        + Sync,
32>;
33
34#[derive(Clone)]
35/// Represents an HTTP ACL.
36pub struct HttpAcl {
37    allow_http: bool,
38    allow_https: bool,
39    allowed_methods: HashSet<HttpRequestMethod>,
40    denied_methods: HashSet<HttpRequestMethod>,
41    allowed_hosts: HashSet<Box<str>>,
42    denied_hosts: HashSet<Box<str>>,
43    allowed_port_ranges: Box<[RangeInclusive<u16>]>,
44    denied_port_ranges: Box<[RangeInclusive<u16>]>,
45    allowed_ip_ranges: Box<[RangeInclusive<IpAddr>]>,
46    denied_ip_ranges: Box<[RangeInclusive<IpAddr>]>,
47    static_dns_mapping: HashMap<Box<str>, SocketAddr>,
48    allowed_headers: HashMap<Box<str>, Option<Box<str>>>,
49    denied_headers: HashMap<Box<str>, Option<Box<str>>>,
50    allowed_url_paths_router: Router<()>,
51    denied_url_paths_router: Router<()>,
52    validate_fn: Option<ValidateFn>,
53    allow_non_global_ip_ranges: bool,
54    method_acl_default: bool,
55    host_acl_default: bool,
56    port_acl_default: bool,
57    ip_acl_default: bool,
58    header_acl_default: bool,
59    url_path_acl_default: bool,
60}
61
62impl std::fmt::Debug for HttpAcl {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        f.debug_struct("HttpAcl")
65            .field("allow_http", &self.allow_http)
66            .field("allow_https", &self.allow_https)
67            .field("allowed_methods", &self.allowed_methods)
68            .field("denied_methods", &self.denied_methods)
69            .field("allowed_hosts", &self.allowed_hosts)
70            .field("denied_hosts", &self.denied_hosts)
71            .field("allowed_port_ranges", &self.allowed_port_ranges)
72            .field("denied_port_ranges", &self.denied_port_ranges)
73            .field("allowed_ip_ranges", &self.allowed_ip_ranges)
74            .field("denied_ip_ranges", &self.denied_ip_ranges)
75            .field("static_dns_mapping", &self.static_dns_mapping)
76            .field("allowed_headers", &self.allowed_headers)
77            .field("denied_headers", &self.denied_headers)
78            .field(
79                "allow_non_global_ip_ranges",
80                &self.allow_non_global_ip_ranges,
81            )
82            .field("method_acl_default", &self.method_acl_default)
83            .field("host_acl_default", &self.host_acl_default)
84            .field("port_acl_default", &self.port_acl_default)
85            .field("ip_acl_default", &self.ip_acl_default)
86            .field("header_acl_default", &self.header_acl_default)
87            .field("url_path_acl_default", &self.url_path_acl_default)
88            .finish()
89    }
90}
91
92impl PartialEq for HttpAcl {
93    fn eq(&self, other: &Self) -> bool {
94        self.allow_http == other.allow_http
95            && self.allow_https == other.allow_https
96            && self.allowed_methods == other.allowed_methods
97            && self.denied_methods == other.denied_methods
98            && self.allowed_hosts == other.allowed_hosts
99            && self.denied_hosts == other.denied_hosts
100            && self.allowed_port_ranges == other.allowed_port_ranges
101            && self.denied_port_ranges == other.denied_port_ranges
102            && self.allowed_ip_ranges == other.allowed_ip_ranges
103            && self.denied_ip_ranges == other.denied_ip_ranges
104            && self.static_dns_mapping == other.static_dns_mapping
105            && self.allowed_headers == other.allowed_headers
106            && self.denied_headers == other.denied_headers
107            && self.allow_non_global_ip_ranges == other.allow_non_global_ip_ranges
108            && self.method_acl_default == other.method_acl_default
109            && self.host_acl_default == other.host_acl_default
110            && self.port_acl_default == other.port_acl_default
111            && self.ip_acl_default == other.ip_acl_default
112            && self.header_acl_default == other.header_acl_default
113            && self.url_path_acl_default == other.url_path_acl_default
114    }
115}
116
117impl std::default::Default for HttpAcl {
118    fn default() -> Self {
119        Self {
120            allow_http: true,
121            allow_https: true,
122            allowed_methods: [
123                HttpRequestMethod::CONNECT,
124                HttpRequestMethod::DELETE,
125                HttpRequestMethod::GET,
126                HttpRequestMethod::HEAD,
127                HttpRequestMethod::OPTIONS,
128                HttpRequestMethod::PATCH,
129                HttpRequestMethod::POST,
130                HttpRequestMethod::PUT,
131                HttpRequestMethod::TRACE,
132            ]
133            .into_iter()
134            .collect(),
135            denied_methods: HashSet::new(),
136            allowed_hosts: HashSet::new(),
137            denied_hosts: HashSet::new(),
138            allowed_port_ranges: vec![80..=80, 443..=443].into_boxed_slice(),
139            denied_port_ranges: Vec::new().into_boxed_slice(),
140            allowed_ip_ranges: Vec::new().into_boxed_slice(),
141            denied_ip_ranges: Vec::new().into_boxed_slice(),
142            static_dns_mapping: HashMap::new(),
143            allowed_headers: HashMap::new(),
144            denied_headers: HashMap::new(),
145            allowed_url_paths_router: Router::new(),
146            denied_url_paths_router: Router::new(),
147            validate_fn: None,
148            allow_non_global_ip_ranges: false,
149            method_acl_default: false,
150            host_acl_default: false,
151            port_acl_default: false,
152            ip_acl_default: false,
153            header_acl_default: true,
154            url_path_acl_default: true,
155        }
156    }
157}
158
159impl HttpAcl {
160    /// Returns a new [`HttpAclBuilder`].
161    pub fn builder() -> HttpAclBuilder {
162        HttpAclBuilder::new()
163    }
164
165    /// Returns whether the scheme is allowed.
166    pub fn is_scheme_allowed(&self, scheme: &str) -> AclClassification {
167        if scheme == "http" && self.allow_http || scheme == "https" && self.allow_https {
168            AclClassification::AllowedUserAcl
169        } else {
170            AclClassification::DeniedUserAcl
171        }
172    }
173
174    /// Returns whether the method is allowed.
175    ///
176    /// Note: If you pass a string ensure it is uppercased first.
177    pub fn is_method_allowed(&self, method: impl Into<HttpRequestMethod>) -> AclClassification {
178        let method = method.into();
179        if self.allowed_methods.contains(&method) {
180            AclClassification::AllowedUserAcl
181        } else if self.denied_methods.contains(&method) {
182            AclClassification::DeniedUserAcl
183        } else if self.method_acl_default {
184            AclClassification::AllowedDefault
185        } else {
186            AclClassification::DeniedDefault
187        }
188    }
189
190    /// Returns whether the host is allowed.
191    ///
192    /// Note: The host should be in its canonical form (lowercase, punycode for IDN).
193    pub fn is_host_allowed(&self, host: &str) -> AclClassification {
194        if self.allowed_hosts.iter().any(|h| h.as_ref() == host) {
195            AclClassification::AllowedUserAcl
196        } else if self.denied_hosts.iter().any(|h| h.as_ref() == host) {
197            AclClassification::DeniedUserAcl
198        } else if self.host_acl_default {
199            AclClassification::AllowedDefault
200        } else {
201            AclClassification::DeniedDefault
202        }
203    }
204
205    /// Returns whether the port is allowed.
206    pub fn is_port_allowed(&self, port: u16) -> AclClassification {
207        if Self::is_port_in_ranges(port, &self.allowed_port_ranges) {
208            AclClassification::AllowedUserAcl
209        } else if Self::is_port_in_ranges(port, &self.denied_port_ranges) {
210            AclClassification::DeniedUserAcl
211        } else if self.port_acl_default {
212            AclClassification::AllowedDefault
213        } else {
214            AclClassification::DeniedDefault
215        }
216    }
217
218    /// Returns whether an IP is allowed.
219    pub fn is_ip_allowed(&self, ip: &IpAddr) -> AclClassification {
220        if !utils::ip::is_global_ip(ip) && !self.allow_non_global_ip_ranges {
221            AclClassification::DeniedNotGlobal
222        } else if Self::is_ip_in_ranges(ip, &self.allowed_ip_ranges) {
223            AclClassification::AllowedUserAcl
224        } else if Self::is_ip_in_ranges(ip, &self.denied_ip_ranges) {
225            AclClassification::DeniedUserAcl
226        } else if self.ip_acl_default {
227            AclClassification::AllowedDefault
228        } else {
229            AclClassification::DeniedDefault
230        }
231    }
232
233    /// Resolve static DNS mapping.
234    ///
235    /// Note: The host should be in its canonical form (lowercase, punycode for IDN).
236    pub fn resolve_static_dns_mapping(&self, host: &str) -> Option<SocketAddr> {
237        self.static_dns_mapping.get(host).copied()
238    }
239
240    /// Returns whether a header is allowed.
241    ///
242    /// Note: Header names are case-insensitive, but this function assumes the caller provides them in a consistent case.
243    pub fn is_header_allowed(&self, header_name: &str, header_value: &str) -> AclClassification {
244        if let Some(allowed_value) = self.allowed_headers.get(header_name) {
245            if allowed_value.as_deref() == Some(header_value) || allowed_value.is_none() {
246                AclClassification::AllowedUserAcl
247            } else {
248                AclClassification::DeniedUserAcl
249            }
250        } else if let Some(denied_value) = self.denied_headers.get(header_name) {
251            if denied_value.as_deref() == Some(header_value) || denied_value.is_none() {
252                AclClassification::DeniedUserAcl
253            } else {
254                AclClassification::AllowedUserAcl
255            }
256        } else if self.header_acl_default {
257            AclClassification::AllowedDefault
258        } else {
259            AclClassification::DeniedDefault
260        }
261    }
262
263    /// Returns whether a URL path is allowed.
264    ///
265    /// Note: The URL path should be percent-decoded before passing it to this function.
266    pub fn is_url_path_allowed(&self, url_path: &str) -> AclClassification {
267        if self.allowed_url_paths_router.at(url_path).is_ok() {
268            AclClassification::AllowedUserAcl
269        } else if self.denied_url_paths_router.at(url_path).is_ok() {
270            AclClassification::DeniedUserAcl
271        } else if self.url_path_acl_default {
272            AclClassification::AllowedDefault
273        } else {
274            AclClassification::DeniedDefault
275        }
276    }
277
278    /// Returns whether a request is valid.
279    pub fn is_valid<'h>(
280        &self,
281        scheme: &str,
282        authority: &Authority,
283        headers: impl Iterator<Item = (&'h str, &'h str)> + Send + Sync + 'h,
284        body: Option<&[u8]>,
285    ) -> AclClassification {
286        if let Some(validate_fn) = &self.validate_fn {
287            validate_fn(scheme, authority, Box::new(headers), body)
288        } else {
289            AclClassification::AllowedDefault
290        }
291    }
292
293    /// Checks if an ip is in a list of ip ranges.
294    fn is_ip_in_ranges(ip: &IpAddr, ranges: &[RangeInclusive<IpAddr>]) -> bool {
295        ranges.iter().any(|range| range.contains(ip))
296    }
297
298    /// Checks if a port is in a list of port ranges.
299    fn is_port_in_ranges(port: u16, ranges: &[RangeInclusive<u16>]) -> bool {
300        ranges.iter().any(|range| range.contains(&port))
301    }
302}
303
304/// Represents an ACL Classification.
305#[non_exhaustive]
306#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
307pub enum AclClassification {
308    /// The entity is allowed according to the allowed ACL.
309    AllowedUserAcl,
310    /// The entity is allowed because the default is to allow if no ACL match is found.
311    AllowedDefault,
312    /// The entity is denied according to the denied ACL.
313    DeniedUserAcl,
314    /// The entity is denied because the default is to deny if no ACL match is found.
315    DeniedDefault,
316    /// The entity is denied.
317    Denied(String),
318    /// The IP is denied because it is not global.
319    DeniedNotGlobal,
320}
321
322impl std::fmt::Display for AclClassification {
323    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
324        match self {
325            AclClassification::AllowedUserAcl => {
326                write!(f, "The entity is allowed according to the allowed ACL.")
327            }
328            AclClassification::AllowedDefault => write!(
329                f,
330                "The entity is allowed because the default is to allow if no ACL match is found."
331            ),
332            AclClassification::DeniedUserAcl => {
333                write!(f, "The entity is denied according to the denied ACL.")
334            }
335            AclClassification::DeniedNotGlobal => {
336                write!(f, "The ip is denied because it is not global.")
337            }
338            AclClassification::DeniedDefault => write!(
339                f,
340                "The entity is denied because the default is to deny if no ACL match is found."
341            ),
342            AclClassification::Denied(reason) => {
343                write!(f, "The entity is denied because {reason}.")
344            }
345        }
346    }
347}
348
349impl AclClassification {
350    /// Returns whether the classification is allowed.
351    pub fn is_allowed(&self) -> bool {
352        matches!(
353            self,
354            AclClassification::AllowedUserAcl | AclClassification::AllowedDefault
355        )
356    }
357
358    /// Returns whether the classification is denied.
359    pub fn is_denied(&self) -> bool {
360        matches!(
361            self,
362            AclClassification::DeniedUserAcl
363                | AclClassification::Denied(_)
364                | AclClassification::DeniedDefault
365                | AclClassification::DeniedNotGlobal
366        )
367    }
368}
369
370/// Represents an HTTP request method.
371#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
372#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
373pub enum HttpRequestMethod {
374    /// The CONNECT method.
375    CONNECT,
376    /// The DELETE method.
377    DELETE,
378    /// The GET method.
379    GET,
380    /// The HEAD method.
381    HEAD,
382    /// The OPTIONS method.
383    OPTIONS,
384    /// The PATCH method.
385    PATCH,
386    /// The POST method.
387    POST,
388    /// The PUT method.
389    PUT,
390    /// The TRACE method.
391    TRACE,
392    /// Any other method.
393    OTHER(Box<str>),
394}
395
396impl From<&str> for HttpRequestMethod {
397    fn from(method: &str) -> Self {
398        match method {
399            "CONNECT" => HttpRequestMethod::CONNECT,
400            "DELETE" => HttpRequestMethod::DELETE,
401            "GET" => HttpRequestMethod::GET,
402            "HEAD" => HttpRequestMethod::HEAD,
403            "OPTIONS" => HttpRequestMethod::OPTIONS,
404            "PATCH" => HttpRequestMethod::PATCH,
405            "POST" => HttpRequestMethod::POST,
406            "PUT" => HttpRequestMethod::PUT,
407            "TRACE" => HttpRequestMethod::TRACE,
408            _ => HttpRequestMethod::OTHER(method.into()),
409        }
410    }
411}
412
413impl HttpRequestMethod {
414    /// Return the method as a `&str`.
415    pub fn as_str(&self) -> &str {
416        match self {
417            HttpRequestMethod::CONNECT => "CONNECT",
418            HttpRequestMethod::DELETE => "DELETE",
419            HttpRequestMethod::GET => "GET",
420            HttpRequestMethod::HEAD => "HEAD",
421            HttpRequestMethod::OPTIONS => "OPTIONS",
422            HttpRequestMethod::PATCH => "PATCH",
423            HttpRequestMethod::POST => "POST",
424            HttpRequestMethod::PUT => "PUT",
425            HttpRequestMethod::TRACE => "TRACE",
426            HttpRequestMethod::OTHER(other) => other,
427        }
428    }
429}
430
431/// A builder for [`HttpAcl`].
432#[derive(Default, Clone)]
433#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
434pub struct HttpAclBuilder {
435    allow_http: bool,
436    allow_https: bool,
437    allowed_methods: Vec<HttpRequestMethod>,
438    denied_methods: Vec<HttpRequestMethod>,
439    allowed_hosts: Vec<String>,
440    denied_hosts: Vec<String>,
441    allowed_port_ranges: Vec<RangeInclusive<u16>>,
442    denied_port_ranges: Vec<RangeInclusive<u16>>,
443    allowed_ip_ranges: Vec<RangeInclusive<IpAddr>>,
444    denied_ip_ranges: Vec<RangeInclusive<IpAddr>>,
445    static_dns_mapping: HashMap<String, SocketAddr>,
446    allowed_headers: HashMap<String, Option<String>>,
447    denied_headers: HashMap<String, Option<String>>,
448    allowed_url_paths: Vec<String>,
449    #[cfg_attr(feature = "serde", serde(skip))]
450    allowed_url_paths_router: Router<()>,
451    denied_url_paths: Vec<String>,
452    #[cfg_attr(feature = "serde", serde(skip))]
453    denied_url_paths_router: Router<()>,
454    allow_non_global_ip_ranges: bool,
455    method_acl_default: bool,
456    host_acl_default: bool,
457    port_acl_default: bool,
458    ip_acl_default: bool,
459    header_acl_default: bool,
460    url_path_acl_default: bool,
461}
462
463impl std::fmt::Debug for HttpAclBuilder {
464    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
465        f.debug_struct("HttpAclBuilder")
466            .field("allow_http", &self.allow_http)
467            .field("allow_https", &self.allow_https)
468            .field("allowed_methods", &self.allowed_methods)
469            .field("denied_methods", &self.denied_methods)
470            .field("allowed_hosts", &self.allowed_hosts)
471            .field("denied_hosts", &self.denied_hosts)
472            .field("allowed_port_ranges", &self.allowed_port_ranges)
473            .field("denied_port_ranges", &self.denied_port_ranges)
474            .field("allowed_ip_ranges", &self.allowed_ip_ranges)
475            .field("denied_ip_ranges", &self.denied_ip_ranges)
476            .field("static_dns_mapping", &self.static_dns_mapping)
477            .field("allowed_headers", &self.allowed_headers)
478            .field("denied_headers", &self.denied_headers)
479            .field("allowed_url_paths", &self.allowed_url_paths)
480            .field("denied_url_paths", &self.denied_url_paths)
481            .field(
482                "allow_non_global_ip_ranges",
483                &self.allow_non_global_ip_ranges,
484            )
485            .field("method_acl_default", &self.method_acl_default)
486            .field("host_acl_default", &self.host_acl_default)
487            .field("port_acl_default", &self.port_acl_default)
488            .field("ip_acl_default", &self.ip_acl_default)
489            .field("header_acl_default", &self.header_acl_default)
490            .field("url_path_acl_default", &self.url_path_acl_default)
491            .finish()
492    }
493}
494
495impl PartialEq for HttpAclBuilder {
496    fn eq(&self, other: &Self) -> bool {
497        self.allow_http == other.allow_http
498            && self.allow_https == other.allow_https
499            && self.allowed_methods == other.allowed_methods
500            && self.denied_methods == other.denied_methods
501            && self.allowed_hosts == other.allowed_hosts
502            && self.denied_hosts == other.denied_hosts
503            && self.allowed_port_ranges == other.allowed_port_ranges
504            && self.denied_port_ranges == other.denied_port_ranges
505            && self.allowed_ip_ranges == other.allowed_ip_ranges
506            && self.denied_ip_ranges == other.denied_ip_ranges
507            && self.static_dns_mapping == other.static_dns_mapping
508            && self.allowed_headers == other.allowed_headers
509            && self.denied_headers == other.denied_headers
510            && self.allowed_url_paths == other.allowed_url_paths
511            && self.denied_url_paths == other.denied_url_paths
512            && self.allow_non_global_ip_ranges == other.allow_non_global_ip_ranges
513            && self.method_acl_default == other.method_acl_default
514            && self.host_acl_default == other.host_acl_default
515            && self.port_acl_default == other.port_acl_default
516            && self.ip_acl_default == other.ip_acl_default
517            && self.header_acl_default == other.header_acl_default
518            && self.url_path_acl_default == other.url_path_acl_default
519    }
520}
521
522impl HttpAclBuilder {
523    /// Create a new [`HttpAclBuilder`].
524    pub fn new() -> Self {
525        Self {
526            allow_http: true,
527            allow_https: true,
528            allowed_methods: vec![
529                HttpRequestMethod::CONNECT,
530                HttpRequestMethod::DELETE,
531                HttpRequestMethod::GET,
532                HttpRequestMethod::HEAD,
533                HttpRequestMethod::OPTIONS,
534                HttpRequestMethod::PATCH,
535                HttpRequestMethod::POST,
536                HttpRequestMethod::PUT,
537                HttpRequestMethod::TRACE,
538            ],
539            denied_methods: Vec::new(),
540            allowed_hosts: Vec::new(),
541            denied_hosts: Vec::new(),
542            allowed_port_ranges: vec![80..=80, 443..=443],
543            denied_port_ranges: Vec::new(),
544            allowed_ip_ranges: Vec::new(),
545            denied_ip_ranges: Vec::new(),
546            allowed_headers: HashMap::new(),
547            denied_headers: HashMap::new(),
548            allowed_url_paths: Vec::new(),
549            allowed_url_paths_router: Router::new(),
550            denied_url_paths: Vec::new(),
551            denied_url_paths_router: Router::new(),
552            allow_non_global_ip_ranges: false,
553            static_dns_mapping: HashMap::new(),
554            method_acl_default: false,
555            host_acl_default: false,
556            port_acl_default: false,
557            ip_acl_default: false,
558            header_acl_default: true,
559            url_path_acl_default: true,
560        }
561    }
562
563    /// Sets whether HTTP is allowed.
564    pub fn http(mut self, allow: bool) -> Self {
565        self.allow_http = allow;
566        self
567    }
568
569    /// Sets whether HTTPS is allowed.
570    pub fn https(mut self, allow: bool) -> Self {
571        self.allow_https = allow;
572        self
573    }
574
575    /// Sets whether non-global IP ranges are allowed.
576    ///
577    /// Non-global IP ranges include private, loopback, link-local, and other special-use addresses.
578    pub fn non_global_ip_ranges(mut self, allow: bool) -> Self {
579        self.allow_non_global_ip_ranges = allow;
580        self
581    }
582
583    /// Set default action for HTTP methods if no ACL match is found.
584    pub fn method_acl_default(mut self, allow: bool) -> Self {
585        self.method_acl_default = allow;
586        self
587    }
588
589    /// Set default action for hosts if no ACL match is found.
590    pub fn host_acl_default(mut self, allow: bool) -> Self {
591        self.host_acl_default = allow;
592        self
593    }
594
595    /// Set default action for ports if no ACL match is found.
596    pub fn port_acl_default(mut self, allow: bool) -> Self {
597        self.port_acl_default = allow;
598        self
599    }
600
601    /// Set default action for IPs if no ACL match is found.
602    pub fn ip_acl_default(mut self, allow: bool) -> Self {
603        self.ip_acl_default = allow;
604        self
605    }
606
607    /// Set default action for headers if no ACL match is found.
608    pub fn header_acl_default(mut self, allow: bool) -> Self {
609        self.header_acl_default = allow;
610        self
611    }
612
613    /// Set default action for URL paths if no ACL match is found.
614    pub fn url_path_acl_default(mut self, allow: bool) -> Self {
615        self.url_path_acl_default = allow;
616        self
617    }
618
619    /// Adds a method to the allowed methods.
620    ///
621    /// Note: If you pass a string ensure it is uppercased first.
622    pub fn add_allowed_method(
623        mut self,
624        method: impl Into<HttpRequestMethod>,
625    ) -> Result<Self, AddError> {
626        let method = method.into();
627        if self.denied_methods.contains(&method) {
628            Err(AddError::AlreadyDeniedMethod(method))
629        } else if self.allowed_methods.contains(&method) {
630            Err(AddError::AlreadyAllowedMethod(method))
631        } else {
632            self.allowed_methods.push(method);
633            Ok(self)
634        }
635    }
636
637    /// Removes a method from the allowed methods.
638    ///
639    /// Note: If you pass a string ensure it is uppercased first.
640    pub fn remove_allowed_method(mut self, method: impl Into<HttpRequestMethod>) -> Self {
641        let method = method.into();
642        self.allowed_methods.retain(|m| m != &method);
643        self
644    }
645
646    /// Sets the allowed methods.
647    ///
648    /// Note: If you pass strings ensure they are uppercased first.
649    pub fn allowed_methods(
650        mut self,
651        methods: Vec<impl Into<HttpRequestMethod>>,
652    ) -> Result<Self, AddError> {
653        let methods = methods.into_iter().map(|m| m.into()).collect::<Vec<_>>();
654
655        for method in &methods {
656            if self.denied_methods.contains(method) {
657                return Err(AddError::AlreadyDeniedMethod(method.clone()));
658            }
659        }
660        self.allowed_methods = methods;
661        Ok(self)
662    }
663
664    /// Clears the allowed methods.
665    pub fn clear_allowed_methods(mut self) -> Self {
666        self.allowed_methods.clear();
667        self
668    }
669
670    /// Adds a method to the denied methods.
671    ///
672    /// Note: If you pass a string ensure it is uppercased first.
673    pub fn add_denied_method(
674        mut self,
675        method: impl Into<HttpRequestMethod>,
676    ) -> Result<Self, AddError> {
677        let method = method.into();
678        if self.allowed_methods.contains(&method) {
679            Err(AddError::AlreadyAllowedMethod(method))
680        } else if self.denied_methods.contains(&method) {
681            Err(AddError::AlreadyDeniedMethod(method))
682        } else {
683            self.denied_methods.push(method);
684            Ok(self)
685        }
686    }
687
688    /// Removes a method from the denied methods.
689    ///
690    /// Note: If you pass a string ensure it is uppercased first.
691    pub fn remove_denied_method(mut self, method: impl Into<HttpRequestMethod>) -> Self {
692        let method = method.into();
693        self.denied_methods.retain(|m| m != &method);
694        self
695    }
696
697    /// Sets the denied methods.
698    ///
699    /// Note: If you pass strings ensure they are uppercased first.
700    pub fn denied_methods(
701        mut self,
702        methods: Vec<impl Into<HttpRequestMethod>>,
703    ) -> Result<Self, AddError> {
704        let methods = methods.into_iter().map(|m| m.into()).collect::<Vec<_>>();
705
706        for method in &methods {
707            if self.allowed_methods.contains(method) {
708                return Err(AddError::AlreadyAllowedMethod(method.clone()));
709            }
710        }
711        self.denied_methods = methods;
712        Ok(self)
713    }
714
715    /// Clears the denied methods.
716    pub fn clear_denied_methods(mut self) -> Self {
717        self.denied_methods.clear();
718        self
719    }
720
721    /// Adds a host to the allowed hosts.
722    ///
723    /// Note: The host should be in its canonical form (lowercase, punycode for IDN).
724    pub fn add_allowed_host(mut self, host: String) -> Result<Self, AddError> {
725        if utils::authority::is_valid_host(&host) {
726            if self.denied_hosts.contains(&host) {
727                Err(AddError::AlreadyDeniedHost(host))
728            } else if self.allowed_hosts.contains(&host) {
729                Err(AddError::AlreadyAllowedHost(host))
730            } else {
731                self.allowed_hosts.push(host);
732                Ok(self)
733            }
734        } else {
735            Err(AddError::InvalidEntity(host))
736        }
737    }
738
739    /// Removes a host from the allowed hosts.
740    ///
741    /// Note: The host should be in its canonical form (lowercase, punycode for IDN).
742    pub fn remove_allowed_host(mut self, host: String) -> Self {
743        self.allowed_hosts.retain(|h| h != &host);
744        self
745    }
746
747    /// Sets the allowed hosts.
748    ///
749    /// Note: The hosts should be in their canonical form (lowercase, punycode for IDN).
750    pub fn allowed_hosts(mut self, hosts: Vec<String>) -> Result<Self, AddError> {
751        for host in &hosts {
752            if utils::authority::is_valid_host(host) {
753                if self.denied_hosts.contains(host) {
754                    return Err(AddError::AlreadyDeniedHost(host.clone()));
755                }
756            } else {
757                return Err(AddError::InvalidEntity(host.clone()));
758            }
759        }
760        self.allowed_hosts = hosts;
761        Ok(self)
762    }
763
764    /// Clears the allowed hosts.
765    pub fn clear_allowed_hosts(mut self) -> Self {
766        self.allowed_hosts.clear();
767        self
768    }
769
770    /// Adds a host to the denied hosts.
771    ///
772    /// Note: The host should be in its canonical form (lowercase, punycode for IDN).
773    pub fn add_denied_host(mut self, host: String) -> Result<Self, AddError> {
774        if utils::authority::is_valid_host(&host) {
775            if self.allowed_hosts.contains(&host) {
776                Err(AddError::AlreadyAllowedHost(host))
777            } else if self.denied_hosts.contains(&host) {
778                Err(AddError::AlreadyDeniedHost(host))
779            } else {
780                self.denied_hosts.push(host);
781                Ok(self)
782            }
783        } else {
784            Err(AddError::InvalidEntity(host))
785        }
786    }
787
788    /// Removes a host from the denied hosts.
789    ///
790    /// Note: The host should be in its canonical form (lowercase, punycode for IDN).
791    pub fn remove_denied_host(mut self, host: String) -> Self {
792        self.denied_hosts.retain(|h| h != &host);
793        self
794    }
795
796    /// Sets the denied hosts.
797    ///
798    /// Note: The hosts should be in their canonical form (lowercase, punycode for IDN).
799    pub fn denied_hosts(mut self, hosts: Vec<String>) -> Result<Self, AddError> {
800        for host in &hosts {
801            if utils::authority::is_valid_host(host) {
802                if self.allowed_hosts.contains(host) {
803                    return Err(AddError::AlreadyAllowedHost(host.clone()));
804                }
805            } else {
806                return Err(AddError::InvalidEntity(host.clone()));
807            }
808        }
809        self.denied_hosts = hosts;
810        Ok(self)
811    }
812
813    /// Clears the denied hosts.
814    pub fn clear_denied_hosts(mut self) -> Self {
815        self.denied_hosts.clear();
816        self
817    }
818
819    /// Adds a port range to the allowed port ranges.
820    pub fn add_allowed_port_range(
821        mut self,
822        port_range: RangeInclusive<u16>,
823    ) -> Result<Self, AddError> {
824        if self.denied_port_ranges.contains(&port_range) {
825            Err(AddError::AlreadyDeniedPortRange(port_range))
826        } else if self.allowed_port_ranges.contains(&port_range) {
827            Err(AddError::AlreadyAllowedPortRange(port_range))
828        } else if utils::range_overlaps(&self.allowed_port_ranges, &port_range, None)
829            || utils::range_overlaps(&self.denied_port_ranges, &port_range, None)
830        {
831            Err(AddError::Overlaps(format!("{port_range:?}")))
832        } else {
833            self.allowed_port_ranges.push(port_range);
834            Ok(self)
835        }
836    }
837
838    /// Removes a port range from the allowed port ranges.
839    pub fn remove_allowed_port_range(mut self, port_range: RangeInclusive<u16>) -> Self {
840        self.allowed_port_ranges.retain(|p| p != &port_range);
841        self
842    }
843
844    /// Sets the allowed port ranges.
845    pub fn allowed_port_ranges(
846        mut self,
847        port_ranges: Vec<RangeInclusive<u16>>,
848    ) -> Result<Self, AddError> {
849        for (i, port_range) in port_ranges.iter().enumerate() {
850            if self.denied_port_ranges.contains(port_range) {
851                return Err(AddError::AlreadyDeniedPortRange(port_range.clone()));
852            } else if utils::range_overlaps(&port_ranges, port_range, Some(i))
853                || utils::range_overlaps(&self.denied_port_ranges, port_range, None)
854            {
855                return Err(AddError::Overlaps(format!("{port_range:?}")));
856            }
857        }
858        self.allowed_port_ranges = port_ranges;
859        Ok(self)
860    }
861
862    /// Clears the allowed port ranges.
863    pub fn clear_allowed_port_ranges(mut self) -> Self {
864        self.allowed_port_ranges.clear();
865        self
866    }
867
868    /// Adds a port range to the denied port ranges.
869    pub fn add_denied_port_range(
870        mut self,
871        port_range: RangeInclusive<u16>,
872    ) -> Result<Self, AddError> {
873        if self.allowed_port_ranges.contains(&port_range) {
874            Err(AddError::AlreadyAllowedPortRange(port_range))
875        } else if self.denied_port_ranges.contains(&port_range) {
876            Err(AddError::AlreadyDeniedPortRange(port_range))
877        } else if utils::range_overlaps(&self.allowed_port_ranges, &port_range, None)
878            || utils::range_overlaps(&self.denied_port_ranges, &port_range, None)
879        {
880            Err(AddError::Overlaps(format!("{port_range:?}")))
881        } else {
882            self.denied_port_ranges.push(port_range);
883            Ok(self)
884        }
885    }
886
887    /// Removes a port range from the denied port ranges.
888    pub fn remove_denied_port_range(mut self, port_range: RangeInclusive<u16>) -> Self {
889        self.denied_port_ranges.retain(|p| p != &port_range);
890        self
891    }
892
893    /// Sets the denied port ranges.
894    pub fn denied_port_ranges(
895        mut self,
896        port_ranges: Vec<RangeInclusive<u16>>,
897    ) -> Result<Self, AddError> {
898        for port_range in &port_ranges {
899            if self.allowed_port_ranges.contains(port_range) {
900                return Err(AddError::AlreadyAllowedPortRange(port_range.clone()));
901            }
902        }
903        self.denied_port_ranges = port_ranges;
904        Ok(self)
905    }
906
907    /// Clears the denied port ranges.
908    pub fn clear_denied_port_ranges(mut self) -> Self {
909        self.denied_port_ranges.clear();
910        self
911    }
912
913    /// Adds an IP range to the allowed IP ranges.
914    pub fn add_allowed_ip_range<Ip: IntoIpRange>(mut self, ip_range: Ip) -> Result<Self, AddError> {
915        let ip_range = ip_range
916            .into_range()
917            .ok_or_else(|| AddError::InvalidEntity("Invalid IP range".to_string()))?;
918        if self.denied_ip_ranges.contains(&ip_range) {
919            return Err(AddError::AlreadyDeniedIpRange(ip_range));
920        } else if self.allowed_ip_ranges.contains(&ip_range) {
921            return Err(AddError::AlreadyAllowedIpRange(ip_range));
922        } else if utils::range_overlaps(&self.allowed_ip_ranges, &ip_range, None)
923            || utils::range_overlaps(&self.denied_ip_ranges, &ip_range, None)
924        {
925            return Err(AddError::Overlaps(format!("{ip_range:?}")));
926        }
927        self.allowed_ip_ranges.push(ip_range);
928        Ok(self)
929    }
930
931    /// Removes an IP range from the allowed IP ranges.
932    pub fn remove_allowed_ip_range<Ip: IntoIpRange>(
933        mut self,
934        ip_range: Ip,
935    ) -> Result<Self, AddError> {
936        let ip_range = ip_range
937            .into_range()
938            .ok_or_else(|| AddError::InvalidEntity("Invalid IP range".to_string()))?;
939        self.allowed_ip_ranges.retain(|ip| ip != &ip_range);
940        Ok(self)
941    }
942
943    /// Sets the allowed IP ranges.
944    pub fn allowed_ip_ranges<Ip: IntoIpRange>(
945        mut self,
946        ip_ranges: Vec<Ip>,
947    ) -> Result<Self, AddError> {
948        let ip_ranges = ip_ranges
949            .into_iter()
950            .map(|ip| ip.into_range())
951            .collect::<Option<Vec<_>>>()
952            .ok_or_else(|| AddError::InvalidEntity("Invalid IP range".to_string()))?;
953        for (i, ip_range) in ip_ranges.iter().enumerate() {
954            if self.denied_ip_ranges.contains(ip_range) {
955                return Err(AddError::AlreadyDeniedIpRange(ip_range.clone()));
956            } else if utils::range_overlaps(&ip_ranges, ip_range, Some(i))
957                || utils::range_overlaps(&self.denied_ip_ranges, ip_range, None)
958            {
959                return Err(AddError::Overlaps(format!("{ip_range:?}")));
960            }
961        }
962        self.allowed_ip_ranges = ip_ranges;
963        Ok(self)
964    }
965
966    /// Clears the allowed IP ranges.
967    pub fn clear_allowed_ip_ranges(mut self) -> Self {
968        self.allowed_ip_ranges.clear();
969        self
970    }
971
972    /// Adds an IP range to the denied IP ranges.
973    pub fn add_denied_ip_range<Ip: IntoIpRange>(mut self, ip_range: Ip) -> Result<Self, AddError> {
974        let ip_range = ip_range
975            .into_range()
976            .ok_or_else(|| AddError::InvalidEntity("Invalid IP range".to_string()))?;
977        if self.allowed_ip_ranges.contains(&ip_range) {
978            return Err(AddError::AlreadyAllowedIpRange(ip_range));
979        } else if self.denied_ip_ranges.contains(&ip_range) {
980            return Err(AddError::AlreadyDeniedIpRange(ip_range));
981        } else if utils::range_overlaps(&self.allowed_ip_ranges, &ip_range, None)
982            || utils::range_overlaps(&self.denied_ip_ranges, &ip_range, None)
983        {
984            return Err(AddError::Overlaps(format!("{ip_range:?}")));
985        }
986        self.denied_ip_ranges.push(ip_range);
987        Ok(self)
988    }
989
990    /// Removes an IP range from the denied IP ranges.
991    pub fn remove_denied_ip_range<Ip: IntoIpRange>(
992        mut self,
993        ip_range: Ip,
994    ) -> Result<Self, AddError> {
995        let ip_range = ip_range
996            .into_range()
997            .ok_or_else(|| AddError::InvalidEntity("Invalid IP range".to_string()))?;
998        self.denied_ip_ranges.retain(|ip| ip != &ip_range);
999        Ok(self)
1000    }
1001
1002    /// Sets the denied IP ranges.
1003    pub fn denied_ip_ranges<Ip: IntoIpRange>(
1004        mut self,
1005        ip_ranges: Vec<Ip>,
1006    ) -> Result<Self, AddError> {
1007        let ip_ranges = ip_ranges
1008            .into_iter()
1009            .map(|ip| ip.into_range())
1010            .collect::<Option<Vec<_>>>()
1011            .ok_or_else(|| AddError::InvalidEntity("Invalid IP range".to_string()))?;
1012        for (i, ip_range) in ip_ranges.iter().enumerate() {
1013            if self.allowed_ip_ranges.contains(ip_range) {
1014                return Err(AddError::AlreadyAllowedIpRange(ip_range.clone()));
1015            } else if utils::range_overlaps(&ip_ranges, ip_range, Some(i))
1016                || utils::range_overlaps(&self.allowed_ip_ranges, ip_range, None)
1017            {
1018                return Err(AddError::Overlaps(format!("{ip_range:?}")));
1019            }
1020        }
1021        self.denied_ip_ranges = ip_ranges;
1022        Ok(self)
1023    }
1024
1025    /// Clears the denied IP ranges.
1026    pub fn clear_denied_ip_ranges(mut self) -> Self {
1027        self.denied_ip_ranges.clear();
1028        self
1029    }
1030
1031    /// Add a static DNS mapping.
1032    ///
1033    /// Note: The host should be in its canonical form (lowercase, punycode for IDN).
1034    pub fn add_static_dns_mapping(
1035        mut self,
1036        host: String,
1037        sock_addr: SocketAddr,
1038    ) -> Result<Self, AddError> {
1039        if utils::authority::is_valid_host(&host) {
1040            if let Entry::Vacant(e) = self.static_dns_mapping.entry(host.clone()) {
1041                e.insert(sock_addr);
1042                Ok(self)
1043            } else {
1044                Err(AddError::AlreadyPresentStaticDnsMapping(host, sock_addr))
1045            }
1046        } else {
1047            Err(AddError::InvalidEntity(host))
1048        }
1049    }
1050
1051    /// Removes a static DNS mapping.
1052    ///
1053    /// Note: The host should be in its canonical form (lowercase, punycode for IDN).
1054    pub fn remove_static_dns_mapping(mut self, host: &str) -> Self {
1055        self.static_dns_mapping.remove(host);
1056        self
1057    }
1058
1059    /// Sets the static DNS mappings.
1060    ///
1061    /// Note: The hosts should be in their canonical form (lowercase, punycode for IDN).
1062    pub fn static_dns_mappings(
1063        mut self,
1064        mappings: HashMap<String, SocketAddr>,
1065    ) -> Result<Self, AddError> {
1066        for (host, ip) in &mappings {
1067            if utils::authority::is_valid_host(host) {
1068                if self.static_dns_mapping.contains_key(host) {
1069                    return Err(AddError::AlreadyPresentStaticDnsMapping(host.clone(), *ip));
1070                }
1071                self.static_dns_mapping.insert(host.to_string(), *ip);
1072            } else {
1073                return Err(AddError::InvalidEntity(host.clone()));
1074            }
1075        }
1076        Ok(self)
1077    }
1078
1079    /// Clears the static DNS mappings.
1080    pub fn clear_static_dns_mappings(mut self) -> Self {
1081        self.static_dns_mapping.clear();
1082        self
1083    }
1084
1085    /// Adds a header to the allowed headers.
1086    ///
1087    /// If `value` is `None`, any value for the header is allowed.
1088    ///
1089    /// Note: Ensure header names are lowercased.
1090    pub fn add_allowed_header(
1091        mut self,
1092        header: String,
1093        value: Option<String>,
1094    ) -> Result<Self, AddError> {
1095        if self.denied_headers.contains_key(&header) {
1096            Err(AddError::AlreadyDeniedHeader(header, value.clone()))
1097        } else if let Entry::Vacant(e) = self.allowed_headers.entry(header.clone()) {
1098            e.insert(value);
1099            Ok(self)
1100        } else {
1101            Err(AddError::AlreadyAllowedHeader(header, value))
1102        }
1103    }
1104
1105    /// Removes a header from the allowed headers.
1106    ///
1107    /// Note: Ensure header names are lowercased.
1108    pub fn remove_allowed_header(mut self, header: &str) -> Self {
1109        self.allowed_headers.remove(header);
1110        self
1111    }
1112
1113    /// Sets the allowed headers.
1114    ///
1115    /// Note: Ensure header names are lowercased.
1116    pub fn allowed_headers(
1117        mut self,
1118        headers: HashMap<String, Option<String>>,
1119    ) -> Result<Self, AddError> {
1120        for (header, value) in &headers {
1121            if self.denied_headers.contains_key(header) {
1122                return Err(AddError::AlreadyDeniedHeader(header.clone(), value.clone()));
1123            }
1124        }
1125        self.allowed_headers = headers;
1126        Ok(self)
1127    }
1128
1129    /// Clears the allowed headers.
1130    pub fn clear_allowed_headers(mut self) -> Self {
1131        self.allowed_headers.clear();
1132        self
1133    }
1134
1135    /// Adds a header to the denied headers.
1136    ///
1137    /// If `value` is `None`, any value for the header is denied.
1138    ///
1139    /// Note: Ensure header names are lowercased.
1140    pub fn add_denied_header(
1141        mut self,
1142        header: String,
1143        value: Option<String>,
1144    ) -> Result<Self, AddError> {
1145        if self.allowed_headers.contains_key(&header) {
1146            Err(AddError::AlreadyAllowedHeader(header, value.clone()))
1147        } else if let Entry::Vacant(e) = self.denied_headers.entry(header.clone()) {
1148            e.insert(value);
1149            Ok(self)
1150        } else {
1151            Err(AddError::AlreadyDeniedHeader(header, value))
1152        }
1153    }
1154
1155    /// Removes a header from the denied headers.
1156    ///
1157    /// Note: Ensure header names are lowercased.
1158    pub fn remove_denied_header(mut self, header: &str) -> Self {
1159        self.denied_headers.remove(header);
1160        self
1161    }
1162
1163    /// Sets the denied headers.
1164    ///
1165    /// Note: Ensure header names are lowercased.
1166    pub fn denied_headers(
1167        mut self,
1168        headers: HashMap<String, Option<String>>,
1169    ) -> Result<Self, AddError> {
1170        for (header, value) in &headers {
1171            if self.allowed_headers.contains_key(header) {
1172                return Err(AddError::AlreadyAllowedHeader(
1173                    header.clone(),
1174                    value.clone(),
1175                ));
1176            }
1177        }
1178        self.denied_headers = headers;
1179        Ok(self)
1180    }
1181
1182    /// Clears the denied headers.
1183    pub fn clear_denied_headers(mut self) -> Self {
1184        self.denied_headers.clear();
1185        self
1186    }
1187
1188    /// Adds a URL path to the allowed URL paths.
1189    ///
1190    /// Note: URL paths should start with a '/' and be properly URL-encoded.
1191    pub fn add_allowed_url_path(mut self, url_path: String) -> Result<Self, AddError> {
1192        if self.denied_url_paths.contains(&url_path)
1193            || self.denied_url_paths_router.at(&url_path).is_ok()
1194        {
1195            Err(AddError::AlreadyDeniedUrlPath(url_path))
1196        } else if self.allowed_url_paths.contains(&url_path)
1197            || self.allowed_url_paths_router.at(&url_path).is_ok()
1198        {
1199            Err(AddError::AlreadyAllowedUrlPath(url_path))
1200        } else {
1201            self.allowed_url_paths.push(url_path.clone());
1202            self.allowed_url_paths_router
1203                .insert(url_path, ())
1204                .map_err(|_| AddError::InvalidEntity("Invalid URL path".to_string()))?;
1205            Ok(self)
1206        }
1207    }
1208
1209    /// Removes a URL path from the allowed URL paths.
1210    ///
1211    /// Note: URL paths should start with a '/' and be properly URL-encoded.
1212    pub fn remove_allowed_url_path(mut self, url_path: &str) -> Self {
1213        self.allowed_url_paths.retain(|p| p != url_path);
1214        self.allowed_url_paths_router = {
1215            let mut router = Router::new();
1216            for url_path in &self.allowed_url_paths {
1217                router
1218                    .insert(url_path.clone(), ())
1219                    .expect("failed to insert url path");
1220            }
1221            router
1222        };
1223        self
1224    }
1225
1226    /// Sets the allowed URL paths.
1227    ///
1228    /// Note: URL paths should start with a '/' and be properly URL-encoded.
1229    pub fn allowed_url_paths(mut self, url_paths: Vec<String>) -> Result<Self, AddError> {
1230        for url_path in &url_paths {
1231            if self.denied_url_paths.contains(url_path)
1232                || self.denied_url_paths_router.at(url_path).is_ok()
1233            {
1234                return Err(AddError::AlreadyDeniedUrlPath(url_path.clone()));
1235            }
1236        }
1237        self.allowed_url_paths_router = Router::new();
1238        for url_path in &url_paths {
1239            self.allowed_url_paths_router
1240                .insert(url_path.clone(), ())
1241                .map_err(|_| AddError::InvalidEntity(format!("Invalid URL path: {url_path}")))?;
1242        }
1243        self.allowed_url_paths = url_paths;
1244        Ok(self)
1245    }
1246
1247    /// Clears the allowed URL paths.
1248    pub fn clear_allowed_url_paths(mut self) -> Self {
1249        self.allowed_url_paths.clear();
1250        self.allowed_url_paths_router = Router::new();
1251        self
1252    }
1253
1254    /// Adds a URL path to the denied URL paths.
1255    ///
1256    /// Note: URL paths should start with a '/' and be properly URL-encoded.
1257    pub fn add_denied_url_path(mut self, url_path: String) -> Result<Self, AddError> {
1258        if self.allowed_url_paths.contains(&url_path)
1259            || self.allowed_url_paths_router.at(&url_path).is_ok()
1260        {
1261            Err(AddError::AlreadyAllowedUrlPath(url_path))
1262        } else if self.denied_url_paths.contains(&url_path)
1263            || self.denied_url_paths_router.at(&url_path).is_ok()
1264        {
1265            Err(AddError::AlreadyDeniedUrlPath(url_path))
1266        } else {
1267            self.denied_url_paths.push(url_path.clone());
1268            self.denied_url_paths_router
1269                .insert(url_path, ())
1270                .map_err(|_| AddError::InvalidEntity("Invalid URL path".to_string()))?;
1271            Ok(self)
1272        }
1273    }
1274
1275    /// Removes a URL path from the denied URL paths.
1276    ///
1277    /// Note: URL paths should start with a '/' and be properly URL-encoded.
1278    pub fn remove_denied_url_path(mut self, url_path: &str) -> Self {
1279        self.denied_url_paths.retain(|p| p != url_path);
1280        self.denied_url_paths_router = {
1281            let mut router = Router::new();
1282            for url_path in &self.denied_url_paths {
1283                router
1284                    .insert(url_path.clone(), ())
1285                    .expect("failed to insert url path");
1286            }
1287            router
1288        };
1289        self
1290    }
1291
1292    /// Sets the denied URL paths.
1293    ///
1294    /// Note: URL paths should start with a '/' and be properly URL-encoded.
1295    pub fn denied_url_paths(mut self, url_paths: Vec<String>) -> Result<Self, AddError> {
1296        for url_path in &url_paths {
1297            if self.allowed_url_paths.contains(url_path)
1298                || self.allowed_url_paths_router.at(url_path).is_ok()
1299            {
1300                return Err(AddError::AlreadyAllowedUrlPath(url_path.clone()));
1301            }
1302        }
1303        self.denied_url_paths_router = Router::new();
1304        for url_path in &url_paths {
1305            self.denied_url_paths_router
1306                .insert(url_path.clone(), ())
1307                .map_err(|_| AddError::InvalidEntity(format!("Invalid URL path: {url_path}")))?;
1308        }
1309        self.denied_url_paths = url_paths;
1310        Ok(self)
1311    }
1312
1313    /// Clears the denied URL paths.
1314    pub fn clear_denied_url_paths(mut self) -> Self {
1315        self.denied_url_paths.clear();
1316        self.denied_url_paths_router = Router::new();
1317        self
1318    }
1319
1320    /// Builds the [`HttpAcl`].
1321    pub fn build(self) -> HttpAcl {
1322        self.build_full(None)
1323    }
1324
1325    /// Builds the [`HttpAcl`].
1326    pub fn build_full(self, validate_fn: Option<ValidateFn>) -> HttpAcl {
1327        HttpAcl {
1328            allow_http: self.allow_http,
1329            allow_https: self.allow_https,
1330            allowed_methods: self.allowed_methods.into_iter().collect(),
1331            denied_methods: self.denied_methods.into_iter().collect(),
1332            allowed_hosts: self
1333                .allowed_hosts
1334                .into_iter()
1335                .map(|x| x.into_boxed_str())
1336                .collect(),
1337            denied_hosts: self
1338                .denied_hosts
1339                .into_iter()
1340                .map(|x| x.into_boxed_str())
1341                .collect(),
1342            allowed_port_ranges: self.allowed_port_ranges.into_boxed_slice(),
1343            denied_port_ranges: self.denied_port_ranges.into_boxed_slice(),
1344            allowed_ip_ranges: self.allowed_ip_ranges.into_boxed_slice(),
1345            denied_ip_ranges: self.denied_ip_ranges.into_boxed_slice(),
1346            allowed_headers: self
1347                .allowed_headers
1348                .into_iter()
1349                .map(|(k, v)| (k.into_boxed_str(), v.map(|s| s.into_boxed_str())))
1350                .collect(),
1351            denied_headers: self
1352                .denied_headers
1353                .into_iter()
1354                .map(|(k, v)| (k.into_boxed_str(), v.map(|s| s.into_boxed_str())))
1355                .collect(),
1356            allowed_url_paths_router: self.allowed_url_paths_router,
1357            denied_url_paths_router: self.denied_url_paths_router,
1358            static_dns_mapping: self
1359                .static_dns_mapping
1360                .into_iter()
1361                .map(|(k, v)| (k.into_boxed_str(), v))
1362                .collect(),
1363            validate_fn,
1364            allow_non_global_ip_ranges: self.allow_non_global_ip_ranges,
1365            method_acl_default: self.method_acl_default,
1366            host_acl_default: self.host_acl_default,
1367            port_acl_default: self.port_acl_default,
1368            ip_acl_default: self.ip_acl_default,
1369            header_acl_default: self.header_acl_default,
1370            url_path_acl_default: self.url_path_acl_default,
1371        }
1372    }
1373
1374    /// Builds the [`HttpAcl`] and returns an error if the configuration is invalid.
1375    /// This is used for deserialized ACLs as the URL Path Routers need to be built.
1376    pub fn try_build_full(mut self, validate_fn: Option<ValidateFn>) -> Result<HttpAcl, AddError> {
1377        if !utils::has_unique_elements(&self.allowed_methods) {
1378            return Err(AddError::NotUnique(
1379                "Allowed methods must be unique.".to_string(),
1380            ));
1381        }
1382        for method in &self.allowed_methods {
1383            if self.denied_methods.contains(method) {
1384                return Err(AddError::BothAllowedAndDenied(format!(
1385                    "Method `{}`",
1386                    method.as_str()
1387                )));
1388            }
1389        }
1390        if !utils::has_unique_elements(&self.denied_methods) {
1391            return Err(AddError::NotUnique(
1392                "Denied methods must be unique.".to_string(),
1393            ));
1394        }
1395        for method in &self.denied_methods {
1396            if self.allowed_methods.contains(method) {
1397                return Err(AddError::BothAllowedAndDenied(format!(
1398                    "Method `{}`",
1399                    method.as_str()
1400                )));
1401            }
1402        }
1403        if !utils::has_unique_elements(&self.allowed_hosts) {
1404            return Err(AddError::NotUnique(
1405                "Allowed hosts must be unique.".to_string(),
1406            ));
1407        }
1408        for host in &self.allowed_hosts {
1409            if !utils::authority::is_valid_host(host) {
1410                return Err(AddError::InvalidEntity(host.to_string()));
1411            }
1412            if self.denied_hosts.contains(host) {
1413                return Err(AddError::BothAllowedAndDenied(format!("Host `{host}`")));
1414            }
1415        }
1416        if !utils::has_unique_elements(&self.denied_hosts) {
1417            return Err(AddError::NotUnique(
1418                "Denied hosts must be unique.".to_string(),
1419            ));
1420        }
1421        for host in &self.denied_hosts {
1422            if !utils::authority::is_valid_host(host) {
1423                return Err(AddError::InvalidEntity(host.to_string()));
1424            }
1425            if self.allowed_hosts.contains(host) {
1426                return Err(AddError::BothAllowedAndDenied(format!("Host `{host}`")));
1427            }
1428        }
1429        if !utils::has_unique_elements(&self.allowed_port_ranges) {
1430            return Err(AddError::NotUnique(
1431                "Allowed port ranges must be unique.".to_string(),
1432            ));
1433        }
1434        if utils::has_overlapping_ranges(&self.allowed_port_ranges) {
1435            return Err(AddError::Overlaps(
1436                "Allowed port ranges must not overlap.".to_string(),
1437            ));
1438        }
1439        for port_range in &self.allowed_port_ranges {
1440            if self.denied_port_ranges.contains(port_range) {
1441                return Err(AddError::BothAllowedAndDenied(format!(
1442                    "Port range `{port_range:?}`"
1443                )));
1444            }
1445        }
1446        if !utils::has_unique_elements(&self.denied_port_ranges) {
1447            return Err(AddError::NotUnique(
1448                "Denied port ranges must be unique.".to_string(),
1449            ));
1450        }
1451        if utils::has_overlapping_ranges(&self.denied_port_ranges) {
1452            return Err(AddError::Overlaps(
1453                "Denied port ranges must not overlap.".to_string(),
1454            ));
1455        }
1456        for port_range in &self.denied_port_ranges {
1457            if self.allowed_port_ranges.contains(port_range) {
1458                return Err(AddError::BothAllowedAndDenied(format!(
1459                    "Port range `{port_range:?}`"
1460                )));
1461            }
1462        }
1463        if !utils::has_unique_elements(&self.allowed_ip_ranges) {
1464            return Err(AddError::NotUnique(
1465                "Allowed IP ranges must be unique.".to_string(),
1466            ));
1467        }
1468        if utils::has_overlapping_ranges(&self.allowed_ip_ranges) {
1469            return Err(AddError::Overlaps(
1470                "Allowed IP ranges must not overlap.".to_string(),
1471            ));
1472        }
1473        for ip_range in &self.allowed_ip_ranges {
1474            if self.denied_ip_ranges.contains(ip_range) {
1475                return Err(AddError::BothAllowedAndDenied(format!(
1476                    "IP range `{ip_range:?}`"
1477                )));
1478            }
1479
1480            if (!utils::ip::is_global_ip(ip_range.start())
1481                || !utils::ip::is_global_ip(ip_range.end()))
1482                && !self.allow_non_global_ip_ranges
1483            {
1484                return Err(AddError::NonGlobalIpRange(ip_range.clone()));
1485            }
1486        }
1487        if !utils::has_unique_elements(&self.denied_ip_ranges) {
1488            return Err(AddError::NotUnique(
1489                "Denied IP ranges must be unique.".to_string(),
1490            ));
1491        }
1492        if utils::has_overlapping_ranges(&self.denied_ip_ranges) {
1493            return Err(AddError::Overlaps(
1494                "Denied IP ranges must not overlap.".to_string(),
1495            ));
1496        }
1497        for ip_range in &self.denied_ip_ranges {
1498            if self.allowed_ip_ranges.contains(ip_range) {
1499                return Err(AddError::BothAllowedAndDenied(format!(
1500                    "IP range `{ip_range:?}`"
1501                )));
1502            }
1503
1504            if (!utils::ip::is_global_ip(ip_range.start())
1505                || !utils::ip::is_global_ip(ip_range.end()))
1506                && !self.allow_non_global_ip_ranges
1507            {
1508                return Err(AddError::NonGlobalIpRange(ip_range.clone()));
1509            }
1510        }
1511        if !utils::has_unique_elements(&self.static_dns_mapping) {
1512            return Err(AddError::NotUnique(
1513                "Static DNS mapping must be unique.".to_string(),
1514            ));
1515        }
1516        for host in self.static_dns_mapping.keys() {
1517            if !utils::authority::is_valid_host(host) {
1518                return Err(AddError::InvalidEntity(host.to_string()));
1519            }
1520        }
1521        if !utils::has_unique_elements(&self.allowed_url_paths) {
1522            return Err(AddError::NotUnique(
1523                "Allowed URL paths must be unique.".to_string(),
1524            ));
1525        }
1526        for url_path in &self.allowed_url_paths {
1527            if self.denied_url_paths.contains(url_path)
1528                || self.denied_url_paths_router.at(url_path).is_ok()
1529            {
1530                return Err(AddError::BothAllowedAndDenied(format!(
1531                    "URL path `{url_path}`"
1532                )));
1533            } else if self.allowed_url_paths_router.at(url_path).is_err() {
1534                self.allowed_url_paths_router
1535                    .insert(url_path.clone(), ())
1536                    .map_err(|_| {
1537                        AddError::InvalidEntity(format!(
1538                            "Failed to insert allowed URL path `{url_path}`."
1539                        ))
1540                    })?;
1541            }
1542        }
1543        if !utils::has_unique_elements(&self.denied_url_paths) {
1544            return Err(AddError::NotUnique(
1545                "Denied URL paths must be unique.".to_string(),
1546            ));
1547        }
1548        for url_path in &self.denied_url_paths {
1549            if self.allowed_url_paths.contains(url_path)
1550                || self.allowed_url_paths_router.at(url_path).is_ok()
1551            {
1552                return Err(AddError::BothAllowedAndDenied(format!(
1553                    "URL path `{url_path}`"
1554                )));
1555            } else if self.denied_url_paths_router.at(url_path).is_err() {
1556                self.denied_url_paths_router
1557                    .insert(url_path.clone(), ())
1558                    .map_err(|_| {
1559                        AddError::InvalidEntity(format!(
1560                            "Failed to insert denied URL path `{url_path}`."
1561                        ))
1562                    })?;
1563            }
1564        }
1565        Ok(self.build_full(validate_fn))
1566    }
1567
1568    /// Builds the [`HttpAcl`] and returns an error if the configuration is invalid.
1569    /// This is used for deserialized ACLs as the URL Path Routers need to be built.
1570    pub fn try_build(self) -> Result<HttpAcl, AddError> {
1571        self.try_build_full(None)
1572    }
1573}