headers_client_ip/
lib.rs

1use std::fmt;
2use std::fmt::{Display, Formatter};
3use std::net::{AddrParseError, IpAddr};
4use std::str::FromStr;
5use headers::{Header, HeaderName, HeaderValue};
6use lazy_static::lazy_static;
7
8lazy_static! {
9    static ref X_REAL_IP: HeaderName = HeaderName::from_lowercase(b"x-real-ip").unwrap();
10}
11
12#[derive(Clone, PartialEq, Eq, Debug)]
13pub struct XRealIP(pub IpAddr);
14
15impl XRealIP {
16
17    fn new(ip: IpAddr) -> Self {
18        XRealIP{ 0: ip }
19    }
20
21}
22
23impl From<IpAddr> for XRealIP {
24
25    #[inline]
26    fn from(ip: IpAddr) -> XRealIP {
27        XRealIP::new(ip)
28    }
29
30}
31
32impl Display for XRealIP {
33
34    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
35        write!(f, "{}", self.0)
36    }
37
38}
39
40impl FromStr for XRealIP {
41
42    type Err = AddrParseError;
43
44    fn from_str(s: &str) -> Result<Self, Self::Err> {
45        let addr = s.parse::<IpAddr>()?;
46        Ok(XRealIP::new(addr))
47    }
48
49}
50
51impl Header for XRealIP {
52
53    fn name() -> &'static HeaderName {
54        &X_REAL_IP
55    }
56
57    fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(values: &mut I) -> Result<Self, headers::Error> {
58        values
59            .next()
60            .cloned()
61            .and_then(|value| {
62                if value.is_empty() {
63                    return None
64                }
65
66                let ip = value.to_str().ok();
67
68                if ip.is_some() {
69                    if let Ok(xrealip) = ip.unwrap().to_string().parse::<XRealIP>() {
70                        return Some(xrealip);
71                    }
72                }
73
74                None
75            })
76            .ok_or_else(headers::Error::invalid)
77    }
78
79    fn encode<E: Extend<HeaderValue>>(&self, _values: &mut E) {
80        // values.extend(::std::iter::once(HeaderValue::from_static("true")));
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use crate::XRealIP;
87    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
88
89    #[test]
90    fn string_formatter_works() {
91        let ip = XRealIP::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 4)));
92        assert_eq!(ip.to_string(), "127.0.0.4");
93    }
94
95    #[test]
96    fn xrealip_from_ipaddr_works() {
97        let ipv6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 4);
98        let ip = XRealIP::from(IpAddr::V6(ipv6));
99        assert_eq!(ip.to_string(), ipv6.to_string());
100    }
101
102    #[test]
103    fn parse_from_string_works() {
104        let xrealip = "192.168.0.4".parse::<XRealIP>().unwrap();
105        assert_eq!(xrealip, XRealIP::from(IpAddr::from([192, 168, 0, 4])))
106    }
107}