proxy_protocol_codec/
lib.rs

1//! PROXY Protocol codec.
2//!
3//! See [HAProxy](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) for the protocol specification.
4
5#![no_std]
6#![cfg_attr(feature = "feat-nightly", feature(cold_path))]
7
8#[cfg(feature = "feat-codec-v2-uni-addr")]
9compile_error!("The `feat-codec-v2-uni-addr` feature is deprecated. Please use the `feat-uni-addr` feature instead.");
10
11#[cfg(feature = "feat-codec-v1")]
12pub mod v1;
13#[cfg(feature = "feat-codec-v2")]
14pub mod v2;
15
16#[cfg(any(test, feature = "feat-alloc"))]
17extern crate alloc;
18
19#[cfg(any(test, feature = "feat-std"))]
20extern crate std;
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23/// The supported PROXY Protocol versions.
24pub enum Version {
25    /// PROXY Protocol version 1
26    V1,
27
28    /// PROXY Protocol version 2
29    V2,
30}
31
32impl Version {
33    /// The magic bytes that indicate a PROXY Protocol v1 header.
34    pub const MAGIC_V1: &'static str = "PROXY";
35    /// The magic bytes that indicate a PROXY Protocol v2 header.
36    pub const MAGIC_V2: &'static [u8; 12] = b"\r\n\r\n\x00\r\nQUIT\n";
37
38    #[allow(clippy::result_unit_err)]
39    #[inline]
40    /// Peeks into the given buffer to determine if it contains a valid PROXY
41    /// Protocol version magic.
42    ///
43    /// ## Behaviours
44    ///
45    /// If the buffer is too short to determine the version, `Ok(None)` is
46    /// returned. If the buffer contains a valid version magic,
47    /// `Ok(Some(Version))` is returned. Otherwise, `Err(())` is returned.
48    pub fn peek(buf: &[u8]) -> Result<Option<Self>, ()> {
49        const V1_MAGIC_LEN: usize = Version::MAGIC_V1.len();
50        const V2_MAGIC_LEN: usize = Version::MAGIC_V2.len();
51
52        #[allow(overlapping_range_endpoints)]
53        // Rust 1.77 doesn't support exclusive range endpoints in pattern matching.
54        match buf.len() {
55            0 => Ok(None),
56            V2_MAGIC_LEN.. if buf.starts_with(Self::MAGIC_V2) => Ok(Some(Self::V2)),
57            V1_MAGIC_LEN.. if buf.starts_with(Self::MAGIC_V1.as_bytes()) => Ok(Some(Self::V1)),
58            1..=V2_MAGIC_LEN if Self::MAGIC_V2.starts_with(buf) => Ok(None),
59            1..=V1_MAGIC_LEN if Self::MAGIC_V1.as_bytes().starts_with(buf) => Ok(None),
60            _ => Err(()),
61        }
62    }
63}