Skip to main content

rama_haproxy/protocol/v1/
error.rs

1//! Errors for the text proxy protocol.
2
3use std::fmt;
4
5/// An error in parsing a text PROXY protocol header.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub enum ParseError {
8    /// Header must start with 'PROXY'.
9    InvalidPrefix,
10    /// Header is only partially present.
11    Partial,
12    /// Header is empty.
13    MissingPrefix,
14    /// Header does not end with the string '\r\n'.
15    MissingNewLine,
16    /// Header missing protocol.
17    MissingProtocol,
18    /// Header missing source address.
19    MissingSourceAddress,
20    /// Header missing destination address.
21    MissingDestinationAddress,
22    /// Header missing source port.
23    MissingSourcePort,
24    /// Header missing destination port.
25    MissingDestinationPort,
26    /// Header does not fit within the expected buffer size of 107 bytes (plus 1 byte for null-terminated strings).
27    HeaderTooLong,
28    /// Header has an invalid protocol.
29    InvalidProtocol,
30    /// Header must end in '\r\n'.
31    InvalidSuffix,
32    /// Header contains invalid IP address for the source.
33    InvalidSourceAddress(std::net::AddrParseError),
34    /// Header contains invalid IP address for the destination.
35    InvalidDestinationAddress(std::net::AddrParseError),
36    /// Header contains invalid TCP port for the source.
37    InvalidSourcePort(Option<std::num::ParseIntError>),
38    /// Header contains invalid TCP port for the destination.]
39    InvalidDestinationPort(Option<std::num::ParseIntError>),
40}
41
42impl fmt::Display for ParseError {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        match self {
45            Self::InvalidPrefix => write!(f, "Header must start with 'PROXY'."),
46            Self::Partial => write!(f, "Header is only partially present."),
47            Self::MissingPrefix => write!(f, "Header is empty."),
48            Self::MissingNewLine => write!(f, "Header does not end with the string '\\r\\n'."),
49            Self::MissingProtocol => write!(f, "Header missing protocol."),
50            Self::MissingSourceAddress => write!(f, "Header missing source address."),
51            Self::MissingDestinationAddress => write!(f, "Header missing destination address."),
52            Self::MissingSourcePort => write!(f, "Header missing source port."),
53            Self::MissingDestinationPort => write!(f, "Header missing destination port."),
54            Self::HeaderTooLong => write!(
55                f,
56                "Header does not fit within the expected buffer size of 107 bytes (plus 1 byte for null-terminated strings)."
57            ),
58            Self::InvalidProtocol => write!(f, "Header has an invalid protocol."),
59            Self::InvalidSuffix => write!(f, "Header must end in '\r\n'."),
60            Self::InvalidSourceAddress(source) => write!(
61                f,
62                "Header contains invalid IP address for the source: {source}",
63            ),
64            Self::InvalidDestinationAddress(destination) => write!(
65                f,
66                "Header contains invalid IP address for the destination: {destination}",
67            ),
68            Self::InvalidSourcePort(port) => write!(
69                f,
70                "Header contains invalid TCP port for the source: {}",
71                port.as_ref().map(|e| e.to_string()).unwrap_or_default()
72            ),
73            Self::InvalidDestinationPort(port) => write!(
74                f,
75                "Header contains invalid TCP port for the destination: {}",
76                port.as_ref().map(|e| e.to_string()).unwrap_or_default()
77            ),
78        }
79    }
80}
81
82impl std::error::Error for ParseError {
83    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
84        match self {
85            Self::InvalidSourceAddress(source) => Some(source),
86            Self::InvalidDestinationAddress(destination) => Some(destination),
87            Self::InvalidSourcePort(port) => port.as_ref().map(|e| e as &dyn std::error::Error),
88            Self::InvalidDestinationPort(port) => {
89                port.as_ref().map(|e| e as &dyn std::error::Error)
90            }
91            _ => None,
92        }
93    }
94}
95
96/// An error in parsing a text PROXY protocol header that is represented as a byte slice.
97#[derive(Debug, Clone, PartialEq, Eq)]
98pub enum BinaryParseError {
99    /// An error in parsing a binary PROXY protocol header.
100    Parse(ParseError),
101    /// Header is not valid UTF-8.
102    InvalidUtf8(std::str::Utf8Error),
103}
104
105impl From<ParseError> for BinaryParseError {
106    fn from(error: ParseError) -> Self {
107        Self::Parse(error)
108    }
109}
110
111impl From<std::str::Utf8Error> for BinaryParseError {
112    fn from(error: std::str::Utf8Error) -> Self {
113        Self::InvalidUtf8(error)
114    }
115}
116
117impl fmt::Display for BinaryParseError {
118    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119        match self {
120            Self::Parse(error) => write!(f, "{error}"),
121            Self::InvalidUtf8(error) => write!(f, "Header is not valid UTF-8: {error}"),
122        }
123    }
124}
125
126impl std::error::Error for BinaryParseError {
127    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
128        match self {
129            Self::Parse(error) => Some(error),
130            Self::InvalidUtf8(error) => Some(error),
131        }
132    }
133}