/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ppp-2.3.0/src/v1/mod.rs
Line | Count | Source |
1 | | //! Version 1 of the HAProxy protocol (text version). |
2 | | //! |
3 | | //! See <https://haproxy.org/download/1.8/doc/proxy-protocol.txt> |
4 | | |
5 | | mod error; |
6 | | mod model; |
7 | | |
8 | | pub use crate::ip::{IPv4, IPv6}; |
9 | | pub use error::{BinaryParseError, ParseError}; |
10 | | pub use model::{Addresses, Header, SEPARATOR, TCP4, TCP6, UNKNOWN}; |
11 | | pub use model::{PROTOCOL_PREFIX, PROTOCOL_SUFFIX}; |
12 | | use std::borrow::Cow; |
13 | | use std::cmp::min; |
14 | | use std::net::{AddrParseError, Ipv4Addr, Ipv6Addr}; |
15 | | use std::str::{from_utf8, FromStr}; |
16 | | |
17 | | const ZERO: &str = "0"; |
18 | | const NEWLINE: &str = "\n"; |
19 | | const CARRIAGE_RETURN: char = '\r'; |
20 | | |
21 | | /// The maximum length of a header in bytes. |
22 | | const MAX_LENGTH: usize = 107; |
23 | | /// The total number of parts in the header. |
24 | | const PARTS: usize = 7; |
25 | | |
26 | | /// Parses a text PROXY protocol header. |
27 | | /// The given string is expected to only include the header and to end in \r\n. |
28 | 0 | fn parse_header(header: &str) -> Result<Header, ParseError> { |
29 | 0 | if header.is_empty() { |
30 | 0 | return Err(ParseError::MissingPrefix); |
31 | 0 | } else if header.len() > MAX_LENGTH { |
32 | 0 | return Err(ParseError::HeaderTooLong); |
33 | 0 | } |
34 | | |
35 | 0 | let mut iterator = header |
36 | 0 | .splitn(PARTS, |c| c == SEPARATOR || c == CARRIAGE_RETURN) |
37 | 0 | .peekable(); |
38 | | |
39 | 0 | let prefix = iterator.next().ok_or(ParseError::MissingPrefix)?; |
40 | | |
41 | 0 | if !prefix.is_empty() && PROTOCOL_PREFIX.starts_with(prefix) && header.ends_with(prefix) { |
42 | 0 | return Err(ParseError::Partial); |
43 | 0 | } else if prefix != PROTOCOL_PREFIX { |
44 | 0 | return Err(ParseError::InvalidPrefix); |
45 | 0 | } |
46 | | |
47 | 0 | let addresses = match iterator.next() { |
48 | 0 | Some(TCP4) => { |
49 | 0 | let (source_address, destination_address, source_port, destination_port) = |
50 | 0 | parse_addresses::<Ipv4Addr, _>(&mut iterator)?; |
51 | | |
52 | 0 | Addresses::Tcp4(IPv4 { |
53 | 0 | source_address, |
54 | 0 | source_port, |
55 | 0 | destination_address, |
56 | 0 | destination_port, |
57 | 0 | }) |
58 | | } |
59 | 0 | Some(TCP6) => { |
60 | 0 | let (source_address, destination_address, source_port, destination_port) = |
61 | 0 | parse_addresses::<Ipv6Addr, _>(&mut iterator)?; |
62 | | |
63 | 0 | Addresses::Tcp6(IPv6 { |
64 | 0 | source_address, |
65 | 0 | source_port, |
66 | 0 | destination_address, |
67 | 0 | destination_port, |
68 | 0 | }) |
69 | | } |
70 | 0 | Some(UNKNOWN) => { |
71 | 0 | while iterator.next_if(|&s| s != NEWLINE).is_some() {} |
72 | | |
73 | 0 | Addresses::Unknown |
74 | | } |
75 | 0 | Some(protocol) if protocol.is_empty() && iterator.peek().is_none() => { |
76 | 0 | return Err(ParseError::MissingProtocol) |
77 | | } |
78 | 0 | Some(protocol) |
79 | 0 | if !protocol.is_empty() |
80 | 0 | && header.ends_with(protocol) |
81 | 0 | && (TCP4.starts_with(protocol) || UNKNOWN.starts_with(protocol)) => |
82 | | { |
83 | 0 | return Err(ParseError::Partial) |
84 | | } |
85 | 0 | Some(_) => return Err(ParseError::InvalidProtocol), |
86 | 0 | None => return Err(ParseError::MissingProtocol), |
87 | | }; |
88 | | |
89 | 0 | let newline = iterator |
90 | 0 | .next() |
91 | 0 | .filter(|s| !s.is_empty()) |
92 | 0 | .ok_or(ParseError::MissingNewLine)?; |
93 | | |
94 | 0 | if newline != NEWLINE { |
95 | 0 | return Err(ParseError::InvalidSuffix); |
96 | 0 | } |
97 | | |
98 | 0 | Ok(Header { |
99 | 0 | header: Cow::Borrowed(header), |
100 | 0 | addresses, |
101 | 0 | }) |
102 | 0 | } |
103 | | |
104 | | /// Parses the addresses and ports from a PROXY protocol header for IPv4 and IPv6. |
105 | 0 | fn parse_addresses<'a, T: FromStr<Err = AddrParseError>, I: Iterator<Item = &'a str>>( |
106 | 0 | iterator: &mut I, |
107 | 0 | ) -> Result<(T, T, u16, u16), ParseError> { |
108 | 0 | let source_address = iterator.next().ok_or(ParseError::MissingSourceAddress)?; |
109 | 0 | let destination_address = iterator |
110 | 0 | .next() |
111 | 0 | .ok_or(ParseError::MissingDestinationAddress)?; |
112 | 0 | let source_port = iterator.next().ok_or(ParseError::MissingSourcePort)?; |
113 | 0 | let destination_port = iterator.next().ok_or(ParseError::MissingDestinationPort)?; |
114 | | |
115 | 0 | let source_address = source_address |
116 | 0 | .parse::<T>() |
117 | 0 | .map_err(ParseError::InvalidSourceAddress)?; |
118 | 0 | let destination_address = destination_address |
119 | 0 | .parse::<T>() |
120 | 0 | .map_err(ParseError::InvalidDestinationAddress)?; |
121 | | |
122 | 0 | if source_port.starts_with(ZERO) && source_port != ZERO { |
123 | 0 | return Err(ParseError::InvalidSourcePort(None)); |
124 | 0 | } |
125 | | |
126 | 0 | let source_port = source_port |
127 | 0 | .parse::<u16>() |
128 | 0 | .map_err(|e| ParseError::InvalidSourcePort(Some(e)))?; Unexecuted instantiation: ppp::v1::parse_addresses::<core::net::ip_addr::Ipv4Addr, core::iter::adapters::peekable::Peekable<core::str::iter::SplitN<ppp::v1::parse_header::{closure#0}>>>::{closure#0}Unexecuted instantiation: ppp::v1::parse_addresses::<core::net::ip_addr::Ipv6Addr, core::iter::adapters::peekable::Peekable<core::str::iter::SplitN<ppp::v1::parse_header::{closure#0}>>>::{closure#0} |
129 | | |
130 | 0 | if destination_port.starts_with(ZERO) && destination_port != ZERO { |
131 | 0 | return Err(ParseError::InvalidDestinationPort(None)); |
132 | 0 | } |
133 | | |
134 | 0 | let destination_port = destination_port |
135 | 0 | .parse::<u16>() |
136 | 0 | .map_err(|e| ParseError::InvalidDestinationPort(Some(e)))?; Unexecuted instantiation: ppp::v1::parse_addresses::<core::net::ip_addr::Ipv4Addr, core::iter::adapters::peekable::Peekable<core::str::iter::SplitN<ppp::v1::parse_header::{closure#0}>>>::{closure#1}Unexecuted instantiation: ppp::v1::parse_addresses::<core::net::ip_addr::Ipv6Addr, core::iter::adapters::peekable::Peekable<core::str::iter::SplitN<ppp::v1::parse_header::{closure#0}>>>::{closure#1} |
137 | | |
138 | 0 | Ok(( |
139 | 0 | source_address, |
140 | 0 | destination_address, |
141 | 0 | source_port, |
142 | 0 | destination_port, |
143 | 0 | )) |
144 | 0 | } Unexecuted instantiation: ppp::v1::parse_addresses::<core::net::ip_addr::Ipv4Addr, core::iter::adapters::peekable::Peekable<core::str::iter::SplitN<ppp::v1::parse_header::{closure#0}>>>Unexecuted instantiation: ppp::v1::parse_addresses::<core::net::ip_addr::Ipv6Addr, core::iter::adapters::peekable::Peekable<core::str::iter::SplitN<ppp::v1::parse_header::{closure#0}>>> |
145 | | |
146 | | impl<'a> TryFrom<&'a str> for Header<'a> { |
147 | | type Error = ParseError; |
148 | | |
149 | 0 | fn try_from(input: &'a str) -> Result<Self, Self::Error> { |
150 | 0 | let length = match input.find(CARRIAGE_RETURN) { |
151 | 0 | Some(suffix) => min(suffix + PROTOCOL_SUFFIX.len(), input.len()), |
152 | 0 | None if input.len() >= MAX_LENGTH => return Err(ParseError::HeaderTooLong), |
153 | 0 | None => input.len(), |
154 | | }; |
155 | | |
156 | 0 | parse_header(&input[..length]) |
157 | 0 | } |
158 | | } |
159 | | |
160 | | impl<'a> TryFrom<&'a [u8]> for Header<'a> { |
161 | | type Error = BinaryParseError; |
162 | | |
163 | 0 | fn try_from(input: &'a [u8]) -> Result<Self, Self::Error> { |
164 | 0 | let length = match input.iter().position(|&c| CARRIAGE_RETURN == (c as char)) { |
165 | 0 | Some(suffix) => min(suffix + PROTOCOL_SUFFIX.len(), input.len()), |
166 | 0 | None if input.len() >= MAX_LENGTH => return Err(ParseError::HeaderTooLong.into()), |
167 | 0 | None => input.len(), |
168 | | }; |
169 | 0 | let header = from_utf8(&input[..length])?; |
170 | | |
171 | 0 | parse_header(header).map_err(BinaryParseError::Parse) |
172 | 0 | } |
173 | | } |
174 | | |
175 | | impl FromStr for Addresses { |
176 | | type Err = ParseError; |
177 | | |
178 | 0 | fn from_str(s: &str) -> Result<Self, Self::Err> { |
179 | 0 | Ok(Header::try_from(s)?.addresses) |
180 | 0 | } |
181 | | } |
182 | | |
183 | | impl FromStr for Header<'static> { |
184 | | type Err = ParseError; |
185 | | |
186 | 0 | fn from_str(s: &str) -> Result<Self, Self::Err> { |
187 | 0 | Ok(Header::try_from(s)?.to_owned()) |
188 | 0 | } |
189 | | } |
190 | | |
191 | | #[cfg(test)] |
192 | | mod tests { |
193 | | use super::*; |
194 | | |
195 | | #[test] |
196 | | fn bytes_invalid_utf8() { |
197 | | let text = b"Hello \xF0\x90\x80World\r\n"; |
198 | | |
199 | | assert_eq!( |
200 | | Header::try_from(&text[..]).unwrap_err(), |
201 | | BinaryParseError::InvalidUtf8(from_utf8(text).unwrap_err()) |
202 | | ); |
203 | | } |
204 | | |
205 | | #[test] |
206 | | fn exact_tcp4() { |
207 | | let ip: Ipv4Addr = "255.255.255.255".parse().unwrap(); |
208 | | let port = 65535; |
209 | | let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; |
210 | | let expected = Header::new(text, Addresses::new_tcp4(ip, ip, port, port)); |
211 | | |
212 | | assert_eq!(Header::try_from(text), Ok(expected.to_owned())); |
213 | | assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); |
214 | | } |
215 | | |
216 | | #[test] |
217 | | fn valid_tcp4() { |
218 | | let ip: Ipv4Addr = "255.255.255.255".parse().unwrap(); |
219 | | let port = 65535; |
220 | | let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\nFoobar"; |
221 | | let expected = Header::new( |
222 | | "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n", |
223 | | Addresses::new_tcp4(ip, ip, port, port), |
224 | | ); |
225 | | |
226 | | assert_eq!(Header::try_from(text), Ok(expected.to_owned())); |
227 | | assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); |
228 | | } |
229 | | |
230 | | #[test] |
231 | | fn parse_partial() { |
232 | | let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535"; |
233 | | |
234 | | assert_eq!( |
235 | | Header::try_from(text).unwrap_err(), |
236 | | ParseError::MissingNewLine |
237 | | ); |
238 | | assert_eq!( |
239 | | Header::try_from(text.as_bytes()).unwrap_err(), |
240 | | ParseError::MissingNewLine.into() |
241 | | ); |
242 | | } |
243 | | |
244 | | #[test] |
245 | | fn parse_tcp4_invalid() { |
246 | | let text = "PROXY TCP4 255.255.255.255 256.255.255.255 65535 65535\r\n"; |
247 | | |
248 | | assert_eq!( |
249 | | Header::try_from(text), |
250 | | Err(ParseError::InvalidDestinationAddress( |
251 | | "".parse::<Ipv4Addr>().unwrap_err() |
252 | | )) |
253 | | ); |
254 | | assert_eq!( |
255 | | Header::try_from(text.as_bytes()), |
256 | | Err(ParseError::InvalidDestinationAddress("".parse::<Ipv4Addr>().unwrap_err()).into()) |
257 | | ); |
258 | | } |
259 | | |
260 | | #[test] |
261 | | fn parse_tcp4_leading_zeroes() { |
262 | | let text = "PROXY TCP4 255.0255.255.255 255.255.255.255 65535 65535\r\n"; |
263 | | |
264 | | assert_eq!( |
265 | | Header::try_from(text), |
266 | | Err(ParseError::InvalidSourceAddress( |
267 | | "".parse::<Ipv4Addr>().unwrap_err() |
268 | | )) |
269 | | ); |
270 | | assert_eq!( |
271 | | Header::try_from(text.as_bytes()), |
272 | | Err(ParseError::InvalidSourceAddress("".parse::<Ipv4Addr>().unwrap_err()).into()) |
273 | | ); |
274 | | } |
275 | | |
276 | | #[test] |
277 | | fn parse_unknown_connection() { |
278 | | let text = "PROXY UNKNOWN\r\nTwo"; |
279 | | |
280 | | assert_eq!( |
281 | | Header::try_from(text), |
282 | | Ok(Header::new("PROXY UNKNOWN\r\n", Addresses::default())) |
283 | | ); |
284 | | assert_eq!( |
285 | | Header::try_from(text.as_bytes()), |
286 | | Ok(Header::new("PROXY UNKNOWN\r\n", Addresses::default())) |
287 | | ); |
288 | | } |
289 | | |
290 | | #[test] |
291 | | fn valid_tcp6() { |
292 | | let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); |
293 | | let port = 65535; |
294 | | let text = "PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\nHi!"; |
295 | | let expected = Header::new("PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n", Addresses::new_tcp6(ip, ip, port, port)); |
296 | | |
297 | | assert_eq!(Header::try_from(text), Ok(expected.to_owned())); |
298 | | assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); |
299 | | } |
300 | | |
301 | | #[test] |
302 | | fn valid_tcp6_short() { |
303 | | let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); |
304 | | let port = 65535; |
305 | | let short_ip = "::1".parse().unwrap(); |
306 | | let text = "PROXY TCP6 ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\nHi!"; |
307 | | let expected = Header::new( |
308 | | "PROXY TCP6 ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n", |
309 | | Addresses::new_tcp6(short_ip, ip, port, port), |
310 | | ); |
311 | | |
312 | | assert_eq!(Header::try_from(text), Ok(expected.to_owned())); |
313 | | assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); |
314 | | } |
315 | | |
316 | | #[test] |
317 | | fn parse_tcp6_invalid() { |
318 | | let text = "PROXY TCP6 ffff:gggg:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; |
319 | | |
320 | | assert_eq!( |
321 | | Header::try_from(text), |
322 | | Err(ParseError::InvalidSourceAddress( |
323 | | "".parse::<Ipv6Addr>().unwrap_err() |
324 | | )) |
325 | | ); |
326 | | assert_eq!( |
327 | | Header::try_from(text.as_bytes()), |
328 | | Err(ParseError::InvalidSourceAddress("".parse::<Ipv6Addr>().unwrap_err()).into()) |
329 | | ); |
330 | | } |
331 | | |
332 | | #[test] |
333 | | fn parse_tcp6_leading_zeroes() { |
334 | | let text = "PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:0ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; |
335 | | |
336 | | assert_eq!( |
337 | | Header::try_from(text), |
338 | | Err(ParseError::InvalidDestinationAddress( |
339 | | "".parse::<Ipv6Addr>().unwrap_err() |
340 | | )) |
341 | | ); |
342 | | assert_eq!( |
343 | | Header::try_from(text.as_bytes()), |
344 | | Err(ParseError::InvalidDestinationAddress("".parse::<Ipv6Addr>().unwrap_err()).into()) |
345 | | ); |
346 | | } |
347 | | |
348 | | #[test] |
349 | | fn parse_tcp6_shortened_connection() { |
350 | | let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); |
351 | | let short_ip = "ffff::ffff".parse().unwrap(); |
352 | | let port = 65535; |
353 | | let text = "PROXY TCP6 ffff::ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; |
354 | | let expected = Header::new(text, Addresses::new_tcp6(short_ip, ip, port, port)); |
355 | | |
356 | | assert_eq!(Header::try_from(text), Ok(expected.to_owned())); |
357 | | assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); |
358 | | } |
359 | | |
360 | | #[test] |
361 | | fn parse_tcp6_single_zero() { |
362 | | let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); |
363 | | let short_ip = "ffff:ffff:ffff:ffff::ffff:ffff:ffff".parse().unwrap(); |
364 | | let port = 65535; |
365 | | let text = "PROXY TCP6 ffff:ffff:ffff:ffff::ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; |
366 | | let expected = Header::new(text, Addresses::new_tcp6(short_ip, ip, port, port)); |
367 | | |
368 | | assert_eq!(Header::try_from(text), Ok(expected.to_owned())); |
369 | | assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); |
370 | | } |
371 | | |
372 | | #[test] |
373 | | fn parse_tcp6_wildcard() { |
374 | | let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); |
375 | | let short_ip = "::".parse().unwrap(); |
376 | | let port = 65535; |
377 | | let text = "PROXY TCP6 :: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; |
378 | | let expected = Header::new(text, Addresses::new_tcp6(short_ip, ip, port, port)); |
379 | | |
380 | | assert_eq!(Header::try_from(text), Ok(expected.to_owned())); |
381 | | assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); |
382 | | } |
383 | | |
384 | | #[test] |
385 | | fn parse_tcp6_implied() { |
386 | | let ip: Ipv6Addr = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff".parse().unwrap(); |
387 | | let short_ip = "ffff::".parse().unwrap(); |
388 | | let port = 65535; |
389 | | let text = "PROXY TCP6 ffff:: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; |
390 | | let expected = Header::new(text, Addresses::new_tcp6(short_ip, ip, port, port)); |
391 | | |
392 | | assert_eq!(Header::try_from(text), Ok(expected.to_owned())); |
393 | | assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); |
394 | | } |
395 | | |
396 | | #[test] |
397 | | fn parse_tcp6_over_shortened() { |
398 | | let text = "PROXY TCP6 ffff::ffff:ffff:ffff:ffff::ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; |
399 | | |
400 | | assert_eq!( |
401 | | Header::try_from(text), |
402 | | Err(ParseError::InvalidSourceAddress( |
403 | | "".parse::<Ipv6Addr>().unwrap_err() |
404 | | )) |
405 | | ); |
406 | | assert_eq!( |
407 | | Header::try_from(text.as_bytes()), |
408 | | Err(ParseError::InvalidSourceAddress("".parse::<Ipv6Addr>().unwrap_err()).into()) |
409 | | ); |
410 | | } |
411 | | |
412 | | #[test] |
413 | | fn parse_worst_case() { |
414 | | let text = "PROXY UNKNOWN ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535\r\n"; |
415 | | let expected = Header::new(text, Addresses::Unknown); |
416 | | |
417 | | assert_eq!(Header::try_from(text), Ok(expected.to_owned())); |
418 | | assert_eq!(Header::try_from(text.as_bytes()), Ok(expected)); |
419 | | } |
420 | | |
421 | | #[test] |
422 | | fn parse_leading_zeroes_in_source_port() { |
423 | | let text = "PROXY TCP4 255.255.255.255 255.255.255.255 05535 65535\r\n"; |
424 | | |
425 | | assert_eq!( |
426 | | Header::try_from(text), |
427 | | Err(ParseError::InvalidSourcePort(None)) |
428 | | ); |
429 | | assert_eq!( |
430 | | Header::try_from(text.as_bytes()), |
431 | | Err(ParseError::InvalidSourcePort(None).into()) |
432 | | ); |
433 | | } |
434 | | |
435 | | #[test] |
436 | | fn parse_leading_zeroes_in_destination_port() { |
437 | | let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 05535\r\n"; |
438 | | |
439 | | assert_eq!( |
440 | | Header::try_from(text), |
441 | | Err(ParseError::InvalidDestinationPort(None)) |
442 | | ); |
443 | | assert_eq!( |
444 | | Header::try_from(text.as_bytes()), |
445 | | Err(ParseError::InvalidDestinationPort(None).into()) |
446 | | ); |
447 | | } |
448 | | |
449 | | #[test] |
450 | | fn parse_source_port_too_large() { |
451 | | let text = "PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65536 65535\r\n"; |
452 | | |
453 | | assert_eq!( |
454 | | Header::try_from(text), |
455 | | Err(ParseError::InvalidSourcePort(Some( |
456 | | "65536".parse::<u16>().unwrap_err() |
457 | | ))) |
458 | | ); |
459 | | assert_eq!( |
460 | | Header::try_from(text.as_bytes()), |
461 | | Err(ParseError::InvalidSourcePort(Some("65536".parse::<u16>().unwrap_err())).into()) |
462 | | ); |
463 | | } |
464 | | |
465 | | #[test] |
466 | | fn parse_destination_port_too_large() { |
467 | | let text = "PROXY TCP6 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65536\r\n"; |
468 | | |
469 | | assert_eq!( |
470 | | Header::try_from(text), |
471 | | Err(ParseError::InvalidDestinationPort(Some( |
472 | | "65536".parse::<u16>().unwrap_err() |
473 | | ))) |
474 | | ); |
475 | | assert_eq!( |
476 | | Header::try_from(text.as_bytes()), |
477 | | Err( |
478 | | ParseError::InvalidDestinationPort(Some("65536".parse::<u16>().unwrap_err())) |
479 | | .into() |
480 | | ) |
481 | | ); |
482 | | } |
483 | | |
484 | | #[test] |
485 | | fn parse_lowercase_proxy() { |
486 | | let text = "proxy UNKNOWN\r\n"; |
487 | | |
488 | | assert_eq!(Header::try_from(text), Err(ParseError::InvalidPrefix)); |
489 | | assert_eq!( |
490 | | Header::try_from(text.as_bytes()), |
491 | | Err(ParseError::InvalidPrefix.into()) |
492 | | ); |
493 | | } |
494 | | |
495 | | #[test] |
496 | | fn parse_lowercase_protocol_family() { |
497 | | let text = "PROXY tcp4\r\n"; |
498 | | |
499 | | assert_eq!(Header::try_from(text), Err(ParseError::InvalidProtocol)); |
500 | | assert_eq!( |
501 | | Header::try_from(text.as_bytes()), |
502 | | Err(ParseError::InvalidProtocol.into()) |
503 | | ); |
504 | | } |
505 | | |
506 | | #[test] |
507 | | fn parse_too_long() { |
508 | | let text = "PROXY UNKNOWN ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 65535 \r\n"; |
509 | | |
510 | | assert_eq!(Header::try_from(text), Err(ParseError::HeaderTooLong)); |
511 | | assert_eq!( |
512 | | Header::try_from(text.as_bytes()), |
513 | | Err(ParseError::HeaderTooLong.into()) |
514 | | ); |
515 | | } |
516 | | |
517 | | #[test] |
518 | | fn parse_more_than_one_space() { |
519 | | let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; |
520 | | |
521 | | assert_eq!(Header::try_from(text), Err(ParseError::InvalidProtocol)); |
522 | | assert_eq!( |
523 | | Header::try_from(text.as_bytes()), |
524 | | Err(ParseError::InvalidProtocol.into()) |
525 | | ); |
526 | | } |
527 | | |
528 | | #[test] |
529 | | fn parse_more_than_one_space_source_address() { |
530 | | let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; |
531 | | |
532 | | assert_eq!( |
533 | | Header::try_from(text), |
534 | | Err(ParseError::InvalidSourceAddress("".parse::<Ipv4Addr>().unwrap_err()).into()) |
535 | | ); |
536 | | assert_eq!( |
537 | | Header::try_from(text.as_bytes()), |
538 | | Err(ParseError::InvalidSourceAddress("".parse::<Ipv4Addr>().unwrap_err()).into()) |
539 | | ); |
540 | | } |
541 | | |
542 | | #[test] |
543 | | fn parse_more_than_one_space_destination_address() { |
544 | | let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; |
545 | | |
546 | | assert_eq!( |
547 | | Header::try_from(text), |
548 | | Err(ParseError::InvalidDestinationAddress( |
549 | | "".parse::<Ipv4Addr>().unwrap_err() |
550 | | )) |
551 | | ); |
552 | | assert_eq!( |
553 | | Header::try_from(text.as_bytes()), |
554 | | Err(ParseError::InvalidDestinationAddress("".parse::<Ipv4Addr>().unwrap_err()).into()) |
555 | | ); |
556 | | } |
557 | | |
558 | | #[test] |
559 | | fn parse_more_than_one_space_source_port() { |
560 | | let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; |
561 | | |
562 | | assert_eq!( |
563 | | Header::try_from(text), |
564 | | Err(ParseError::InvalidSourcePort(Some( |
565 | | "".parse::<u16>().unwrap_err() |
566 | | ))) |
567 | | ); |
568 | | assert_eq!( |
569 | | Header::try_from(text.as_bytes()), |
570 | | Err(ParseError::InvalidSourcePort(Some("".parse::<u16>().unwrap_err())).into()) |
571 | | ); |
572 | | } |
573 | | |
574 | | #[test] |
575 | | fn parse_more_than_one_space_destination_port() { |
576 | | let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"; |
577 | | |
578 | | assert_eq!( |
579 | | Header::try_from(text), |
580 | | Err(ParseError::InvalidDestinationPort(Some( |
581 | | "".parse::<u16>().unwrap_err() |
582 | | ))) |
583 | | ); |
584 | | assert_eq!( |
585 | | Header::try_from(text.as_bytes()), |
586 | | Err(ParseError::InvalidDestinationPort(Some("".parse::<u16>().unwrap_err())).into()) |
587 | | ); |
588 | | } |
589 | | |
590 | | #[test] |
591 | | fn parse_more_than_one_space_end() { |
592 | | let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535 \r\n"; |
593 | | |
594 | | assert_eq!(Header::try_from(text), Err(ParseError::InvalidSuffix)); |
595 | | assert_eq!( |
596 | | Header::try_from(text.as_bytes()), |
597 | | Err(ParseError::InvalidSuffix.into()) |
598 | | ); |
599 | | } |
600 | | |
601 | | #[test] |
602 | | fn parse_partial_prefix() { |
603 | | let text = "PROX\r\n"; |
604 | | |
605 | | assert_eq!(Header::try_from(text), Err(ParseError::InvalidPrefix)); |
606 | | assert_eq!( |
607 | | Header::try_from(text.as_bytes()), |
608 | | Err(ParseError::InvalidPrefix.into()) |
609 | | ); |
610 | | } |
611 | | |
612 | | #[test] |
613 | | fn parse_empty_newline() { |
614 | | let text = "\r\n"; |
615 | | |
616 | | assert_eq!(Header::try_from(text), Err(ParseError::InvalidPrefix)); |
617 | | assert_eq!( |
618 | | Header::try_from(text.as_bytes()), |
619 | | Err(ParseError::InvalidPrefix.into()) |
620 | | ); |
621 | | } |
622 | | |
623 | | #[test] |
624 | | fn parse_partial_prefix_missing_newline() { |
625 | | let text = "PROX"; |
626 | | |
627 | | assert_eq!(Header::try_from(text), Err(ParseError::Partial)); |
628 | | assert_eq!( |
629 | | Header::try_from(text.as_bytes()), |
630 | | Err(ParseError::Partial.into()) |
631 | | ); |
632 | | } |
633 | | |
634 | | #[test] |
635 | | fn parse_partial_protocol_missing_newline() { |
636 | | let text = "PROXY UNKN"; |
637 | | |
638 | | assert_eq!(Header::try_from(text), Err(ParseError::Partial)); |
639 | | assert_eq!( |
640 | | Header::try_from(text.as_bytes()), |
641 | | Err(ParseError::Partial.into()) |
642 | | ); |
643 | | } |
644 | | |
645 | | #[test] |
646 | | fn parse_partial_protocol_with_newline() { |
647 | | let text = "PROXY UNKN\r\n"; |
648 | | |
649 | | assert_eq!(Header::try_from(text), Err(ParseError::InvalidProtocol)); |
650 | | assert_eq!( |
651 | | Header::try_from(text.as_bytes()), |
652 | | Err(ParseError::InvalidProtocol.into()) |
653 | | ); |
654 | | } |
655 | | |
656 | | #[test] |
657 | | fn parse_empty_protocol_with_newline() { |
658 | | let text = "PROXY \r\n"; |
659 | | |
660 | | assert_eq!(Header::try_from(text), Err(ParseError::InvalidProtocol)); |
661 | | assert_eq!( |
662 | | Header::try_from(text.as_bytes()), |
663 | | Err(ParseError::InvalidProtocol.into()) |
664 | | ); |
665 | | } |
666 | | |
667 | | #[test] |
668 | | fn parse_empty() { |
669 | | let text = ""; |
670 | | |
671 | | assert_eq!(Header::try_from(text), Err(ParseError::MissingPrefix)); |
672 | | assert_eq!( |
673 | | Header::try_from(text.as_bytes()), |
674 | | Err(ParseError::MissingPrefix.into()) |
675 | | ); |
676 | | } |
677 | | |
678 | | #[test] |
679 | | fn parse_no_new_line() { |
680 | | let text = "PROXY TCP4 127.0.0.1 192.168.1.1 80 443\r\t"; |
681 | | |
682 | | assert_eq!(Header::try_from(text), Err(ParseError::InvalidSuffix)); |
683 | | assert_eq!( |
684 | | Header::try_from(text.as_bytes()), |
685 | | Err(ParseError::InvalidSuffix.into()) |
686 | | ); |
687 | | } |
688 | | |
689 | | #[test] |
690 | | fn parse_invalid_prefix_missing_newline() { |
691 | | let text = "PRAX"; |
692 | | |
693 | | assert_eq!(Header::try_from(text), Err(ParseError::InvalidPrefix)); |
694 | | assert_eq!( |
695 | | Header::try_from(text.as_bytes()), |
696 | | Err(ParseError::InvalidPrefix.into()) |
697 | | ); |
698 | | } |
699 | | |
700 | | #[test] |
701 | | fn parse_partial_newline() { |
702 | | let text = "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r"; |
703 | | assert_eq!( |
704 | | Header::try_from(text).unwrap_err(), |
705 | | ParseError::MissingNewLine |
706 | | ); |
707 | | assert_eq!( |
708 | | Header::try_from(text.as_bytes()).unwrap_err(), |
709 | | ParseError::MissingNewLine.into() |
710 | | ); |
711 | | } |
712 | | |
713 | | #[test] |
714 | | fn parse_invalid_prefix_partial_newline() { |
715 | | let text = "abc\r"; |
716 | | assert_eq!( |
717 | | Header::try_from(text).unwrap_err(), |
718 | | ParseError::InvalidPrefix |
719 | | ); |
720 | | assert_eq!( |
721 | | Header::try_from(text.as_bytes()).unwrap_err(), |
722 | | ParseError::InvalidPrefix.into() |
723 | | ); |
724 | | } |
725 | | } |