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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use crate::error::OpaqueError;
use rama_utils::macros::match_ignore_ascii_case_str;
use std::str::FromStr;

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
/// Kind of fowarder to use, to help you forward the client Ip information.
///
/// Useful in case your service is behind a load balancer.
pub enum ForwardKind {
    /// [`Forwarded`] header.
    ///
    /// [`Forwarded`]: crate::net::forwarded::Forwarded
    Forwarded,
    /// [`X-Forwarded-For`] header.
    ///
    /// [`X-Forwarded-For`]: crate::http::headers::XForwardedFor
    XForwardedFor,
    /// [`X-Client-Ip`] header.
    ///
    /// [`X-Client-Ip`]: crate::http::headers::XClientIp
    XClientIp,
    /// [`Client-Ip`] header.
    ///
    /// [`Client-Ip`]: crate::http::headers::ClientIp
    ClientIp,
    /// [`X-Real-Ip`] header.
    ///
    /// [`X-Real-Ip`]: crate::http::headers::XRealIp
    XRealIp,
    /// [`Cf-Connecting-Ip`] header.
    ///
    /// [`Cf-Connecting-Ip`]: crate::http::headers::CFConnectingIp
    CFConnectingIp,
    /// [`True-Client-Ip`] header.
    ///
    /// [`True-Client-Ip`]: crate::http::headers::TrueClientIp
    TrueClientIp,
    /// [`HaProxy`] protocol (transport layer).
    ///
    /// [`HaProxy`]: crate::proxy::haproxy
    HaProxy,
}

impl<'a> TryFrom<&'a str> for ForwardKind {
    type Error = OpaqueError;

    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
        match_ignore_ascii_case_str! {
            match(value) {
                "forwarded" => Ok(Self::Forwarded),
                "x-forwarded-for" => Ok(Self::XForwardedFor),
                "x-client-ip" => Ok(Self::XClientIp),
                "x-real-ip" => Ok(Self::XRealIp),
                "cf-connecting-ip" => Ok(Self::CFConnectingIp),
                "true-client-ip" => Ok(Self::TrueClientIp),
                "haproxy" => Ok(Self::HaProxy),
                _ => Err(OpaqueError::from_display(format!("unknown forward kind: {value})"))),
            }
        }
    }
}

impl TryFrom<String> for ForwardKind {
    type Error = OpaqueError;

    fn try_from(value: String) -> Result<Self, Self::Error> {
        value.as_str().try_into()
    }
}

impl FromStr for ForwardKind {
    type Err = OpaqueError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        s.try_into()
    }
}