http_acl/
utils.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//! Utility functions for the http-acl crate.

use std::collections::HashSet;
use std::hash::Hash;
use std::net::IpAddr;
use std::ops::RangeInclusive;

use ipnet::IpNet;

pub mod authority;
pub(crate) mod ip;
pub mod url;

// Taken from https://stackoverflow.com/a/46767732
pub(crate) fn has_unique_elements<T>(iter: T) -> bool
where
    T: IntoIterator,
    T::Item: Eq + Hash,
{
    let mut uniq = HashSet::new();
    iter.into_iter().all(move |x| uniq.insert(x))
}

/// Converts a type into an IP range.
pub trait IntoIpRange {
    /// Converts the type into an IP range.
    fn into_range(self) -> Option<RangeInclusive<IpAddr>>;

    /// Validates the IP range.
    fn validate(ip_range: RangeInclusive<IpAddr>) -> Option<RangeInclusive<IpAddr>> {
        if ip_range.start() <= ip_range.end() {
            Some(ip_range)
        } else {
            None
        }
    }
}

impl IntoIpRange for IpNet {
    fn into_range(self) -> Option<RangeInclusive<IpAddr>> {
        let start = self.network();
        let end = self.broadcast();
        Some(start..=end)
    }
}

impl IntoIpRange for RangeInclusive<IpAddr> {
    fn into_range(self) -> Option<RangeInclusive<IpAddr>> {
        Self::validate(self)
    }
}

impl IntoIpRange for (IpAddr, IpAddr) {
    fn into_range(self) -> Option<RangeInclusive<IpAddr>> {
        Self::validate(self.0..=self.1)
    }
}