Coverage Report

Created: 2025-11-16 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ppp-2.3.0/src/v1/model.rs
Line
Count
Source
1
//! The data model to represent the test PROXY protocol header.
2
3
use crate::ip::{IPv4, IPv6};
4
use std::borrow::Cow;
5
use std::fmt;
6
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
7
8
/// The prefix of the PROXY protocol header.
9
pub const PROTOCOL_PREFIX: &str = "PROXY";
10
11
/// The suffix of the PROXY protocol header.
12
pub const PROTOCOL_SUFFIX: &str = "\r\n";
13
14
/// TCP protocol with IPv4 address family.
15
pub const TCP4: &str = "TCP4";
16
17
/// TCP protocol with IPv6 address family.
18
pub const TCP6: &str = "TCP6";
19
20
/// Unknown protocol and address family. Address portion of the header should be ignored.
21
pub const UNKNOWN: &str = "UNKNOWN";
22
23
/// The separator of the header parts.
24
pub const SEPARATOR: char = ' ';
25
26
/// A text PROXY protocol header that borrows the input string.
27
///
28
/// ## Examples
29
/// ### Worst Case (from bytes)
30
/// ```rust
31
/// use ppp::v1::{Addresses, Header, UNKNOWN};
32
///
33
/// let input = "PROXY UNKNOWN ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n";
34
/// let header = Header::try_from(input.as_bytes()).unwrap();
35
///
36
/// assert_eq!(header, Header::new(input, Addresses::Unknown));
37
/// assert_eq!(header.protocol(), UNKNOWN);
38
/// assert_eq!(header.addresses_str(), "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535");
39
/// ```
40
///
41
/// ### UNKNOWN
42
/// ```rust
43
/// use ppp::v1::{Addresses, Header, UNKNOWN};
44
///
45
/// let input = "PROXY UNKNOWN\r\nhello";
46
/// let header = Header::try_from(input).unwrap();
47
///
48
/// assert_eq!(header, Header::new("PROXY UNKNOWN\r\n", Addresses::Unknown));
49
/// assert_eq!(header.protocol(), UNKNOWN);
50
/// assert_eq!(header.addresses_str(), "");
51
/// ```
52
///
53
/// ### TCP4
54
/// ```rust
55
/// use std::net::Ipv4Addr;
56
/// use ppp::v1::{Header, Addresses, TCP4};
57
///
58
/// let input = "PROXY TCP4 127.0.1.2 192.168.1.101 80 443\r\n";
59
/// let header = Header::try_from(input).unwrap();
60
///
61
/// assert_eq!(header, Header::new(input, Addresses::new_tcp4(Ipv4Addr::new(127, 0, 1, 2), Ipv4Addr::new(192, 168, 1, 101), 80, 443)));
62
/// assert_eq!(header.protocol(), TCP4);
63
/// assert_eq!(header.addresses_str(), "127.0.1.2 192.168.1.101 80 443");
64
/// ```
65
///
66
/// ### TCP6
67
/// ```rust
68
/// use std::net::Ipv6Addr;
69
/// use ppp::v1::{Header, Addresses, TCP6};
70
///
71
/// let input = "PROXY TCP6 1234:5678:90ab:cdef:fedc:ba09:8765:4321 4321:8765:ba09:fedc:cdef:90ab:5678:1234 443 65535\r\n";
72
/// let header = Header::try_from(input).unwrap();
73
///
74
/// assert_eq!(
75
///     header,
76
///     Header::new(
77
///         input,
78
///         Addresses::new_tcp6(
79
///             Ipv6Addr::from([0x1234, 0x5678, 0x90AB, 0xCDEF, 0xFEDC, 0xBA09, 0x8765, 0x4321]),
80
///             Ipv6Addr::from([0x4321, 0x8765, 0xBA09, 0xFEDC, 0xCDEF, 0x90AB, 0x5678, 0x01234,]),
81
///             443,
82
///             65535
83
///         )
84
///     )
85
/// );
86
/// assert_eq!(header.protocol(), TCP6);
87
/// assert_eq!(header.addresses_str(), "1234:5678:90ab:cdef:fedc:ba09:8765:4321 4321:8765:ba09:fedc:cdef:90ab:5678:1234 443 65535");
88
/// ```
89
///
90
/// ### Invalid
91
/// ```rust
92
/// use ppp::v1::{Header, Addresses, ParseError};
93
///
94
/// assert_eq!(Err(ParseError::InvalidProtocol), "PROXY tcp4\r\n".parse::<Addresses>());
95
/// ```
96
#[derive(Clone, Debug, PartialEq)]
97
pub struct Header<'a> {
98
    pub header: Cow<'a, str>,
99
    pub addresses: Addresses,
100
}
101
102
impl<'a> Header<'a> {
103
    /// Creates a new `Header` with the given addresses and a reference to the original input.
104
0
    pub fn new<H: Into<&'a str>, A: Into<Addresses>>(header: H, addresses: A) -> Self {
105
0
        Header {
106
0
            header: Cow::Borrowed(header.into()),
107
0
            addresses: addresses.into(),
108
0
        }
109
0
    }
110
111
    /// Creates an owned clone of this [`Header`].
112
0
    pub fn to_owned(&self) -> Header<'static> {
113
0
        Header {
114
0
            header: Cow::Owned::<'static>(self.header.to_string()),
115
0
            addresses: self.addresses,
116
0
        }
117
0
    }
118
119
    /// The protocol portion of this `Header`.
120
0
    pub fn protocol(&self) -> &str {
121
0
        self.addresses.protocol()
122
0
    }
123
124
    /// The source and destination addresses portion of this `Header`.
125
0
    pub fn addresses_str(&self) -> &str {
126
0
        let start = PROTOCOL_PREFIX.len() + SEPARATOR.len_utf8() + self.protocol().len();
127
0
        let end = self.header.len() - PROTOCOL_SUFFIX.len();
128
0
        let addresses = &self.header[start..end];
129
130
0
        if addresses.starts_with(SEPARATOR) {
131
0
            &addresses[SEPARATOR.len_utf8()..]
132
        } else {
133
0
            addresses
134
        }
135
0
    }
136
}
137
138
/// The source and destination of a header.
139
/// Includes IP (v4 or v6) addresses and TCP ports.
140
///
141
/// ## Examples
142
/// ### Worst Case
143
/// ```rust
144
/// use ppp::v1::{Addresses, Header, UNKNOWN};
145
///
146
/// let header = "PROXY UNKNOWN ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n";
147
/// let addresses = Addresses::Unknown;
148
///
149
/// assert_eq!(addresses, header.parse().unwrap());
150
/// assert_ne!(addresses.to_string().as_str(), header);
151
/// ```
152
///
153
/// ### UNKNOWN
154
/// ```rust
155
/// use ppp::v1::Addresses;
156
///
157
/// let header = "PROXY UNKNOWN\r\n";
158
/// let addresses = Addresses::Unknown;
159
///
160
/// assert_eq!(addresses, header.parse().unwrap());
161
/// assert_eq!(addresses.to_string().as_str(), header);
162
/// ```
163
///
164
/// ### TCP4
165
/// ```rust
166
/// use std::net::Ipv4Addr;
167
/// use ppp::v1::Addresses;
168
///
169
/// let header = "PROXY TCP4 127.0.1.2 192.168.1.101 80 443\r\n";
170
/// let addresses = Addresses::new_tcp4(Ipv4Addr::new(127, 0, 1, 2), Ipv4Addr::new(192, 168, 1, 101), 80, 443);
171
///
172
/// assert_eq!(addresses, header.parse().unwrap());
173
/// assert_eq!(addresses.to_string().as_str(), header);
174
/// ```
175
///
176
/// ### TCP6
177
/// ```rust
178
/// use std::net::Ipv6Addr;
179
/// use ppp::v1::Addresses;
180
///
181
/// let header = "PROXY TCP6 1234:5678:90ab:cdef:fedc:ba09:8765:4321 4321:8765:ba09:fedc:cdef:90ab:5678:1234 443 65535\r\n";
182
/// let addresses = Addresses::new_tcp6(
183
///     Ipv6Addr::from([0x1234, 0x5678, 0x90AB, 0xCDEF, 0xFEDC, 0xBA09, 0x8765, 0x4321]),
184
///     Ipv6Addr::from([0x4321, 0x8765, 0xBA09, 0xFEDC, 0xCDEF, 0x90AB, 0x5678, 0x01234,]),
185
///     443,
186
///     65535
187
/// );
188
///
189
/// assert_eq!(addresses, header.parse().unwrap());
190
/// assert_eq!(addresses.to_string().as_str(), header);
191
/// ```
192
///
193
/// ### Invalid
194
/// ```rust
195
/// use ppp::v1::{Addresses, ParseError};
196
///
197
/// assert_eq!(Err(ParseError::InvalidProtocol), "PROXY tcp4\r\n".parse::<Addresses>());
198
/// ```
199
#[derive(Copy, Clone, Debug, PartialEq)]
200
pub enum Addresses {
201
    Unknown,
202
    Tcp4(IPv4),
203
    Tcp6(IPv6),
204
}
205
206
impl Addresses {
207
    /// Create a new IPv4 TCP address.
208
0
    pub fn new_tcp4<T: Into<Ipv4Addr>>(
209
0
        source_address: T,
210
0
        destination_address: T,
211
0
        source_port: u16,
212
0
        destination_port: u16,
213
0
    ) -> Self {
214
0
        Addresses::Tcp4(IPv4 {
215
0
            source_address: source_address.into(),
216
0
            source_port,
217
0
            destination_address: destination_address.into(),
218
0
            destination_port,
219
0
        })
220
0
    }
221
222
    /// Create a new IPv6 TCP address.
223
0
    pub fn new_tcp6<T: Into<Ipv6Addr>>(
224
0
        source_address: T,
225
0
        destination_address: T,
226
0
        source_port: u16,
227
0
        destination_port: u16,
228
0
    ) -> Self {
229
0
        Addresses::Tcp6(IPv6 {
230
0
            source_address: source_address.into(),
231
0
            source_port,
232
0
            destination_address: destination_address.into(),
233
0
            destination_port,
234
0
        })
235
0
    }
236
237
    /// The protocol portion of this `Addresses`.
238
0
    pub fn protocol(&self) -> &str {
239
0
        match self {
240
0
            Addresses::Tcp4(..) => TCP4,
241
0
            Addresses::Tcp6(..) => TCP6,
242
0
            Addresses::Unknown => UNKNOWN,
243
        }
244
0
    }
245
}
246
247
impl Default for Addresses {
248
0
    fn default() -> Self {
249
0
        Addresses::Unknown
250
0
    }
251
}
252
253
impl From<(SocketAddr, SocketAddr)> for Addresses {
254
0
    fn from(addresses: (SocketAddr, SocketAddr)) -> Self {
255
0
        match addresses {
256
0
            (SocketAddr::V4(source), SocketAddr::V4(destination)) => Addresses::Tcp4(IPv4::new(
257
0
                *source.ip(),
258
0
                *destination.ip(),
259
0
                source.port(),
260
0
                destination.port(),
261
0
            )),
262
0
            (SocketAddr::V6(source), SocketAddr::V6(destination)) => Addresses::Tcp6(IPv6::new(
263
0
                *source.ip(),
264
0
                *destination.ip(),
265
0
                source.port(),
266
0
                destination.port(),
267
0
            )),
268
0
            _ => Addresses::Unknown,
269
        }
270
0
    }
271
}
272
273
impl From<IPv4> for Addresses {
274
0
    fn from(addresses: IPv4) -> Self {
275
0
        Addresses::Tcp4(addresses)
276
0
    }
277
}
278
279
impl From<IPv6> for Addresses {
280
0
    fn from(addresses: IPv6) -> Self {
281
0
        Addresses::Tcp6(addresses)
282
0
    }
283
}
284
285
impl<'a> fmt::Display for Header<'a> {
286
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287
0
        f.write_str(self.header.as_ref())
288
0
    }
289
}
290
291
impl fmt::Display for Addresses {
292
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293
0
        match self {
294
0
            Self::Unknown => f.write_str("PROXY UNKNOWN\r\n"),
295
0
            Self::Tcp4(a) => write!(
296
0
                f,
297
0
                "PROXY TCP4 {} {} {} {}\r\n",
298
                a.source_address, a.destination_address, a.source_port, a.destination_port
299
            ),
300
0
            Self::Tcp6(a) => write!(
301
0
                f,
302
0
                "PROXY TCP6 {} {} {} {}\r\n",
303
                a.source_address, a.destination_address, a.source_port, a.destination_port
304
            ),
305
        }
306
0
    }
307
}