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 }
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}