rama_haproxy/protocol/v1/
mod.rs

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