Skip to main content

nexus_web/http/
error.rs

1/// HTTP parsing error.
2#[derive(Debug, Clone, PartialEq, Eq)]
3pub enum HttpError {
4    /// Request or response head is malformed.
5    Malformed(&'static str),
6    /// Too many headers (exceeds configured limit).
7    TooManyHeaders,
8    /// Head section exceeds size limit.
9    HeadTooLarge {
10        /// Configured maximum head size in bytes.
11        max: usize,
12    },
13    /// Read buffer full.
14    BufferFull {
15        /// Bytes required to make progress.
16        needed: usize,
17        /// Bytes currently free in the buffer.
18        available: usize,
19    },
20    /// Write buffer too small for the HTTP message.
21    BufferTooSmall {
22        /// Bytes required to write the message.
23        needed: usize,
24        /// Bytes available in the supplied buffer.
25        available: usize,
26    },
27    /// Header name or value contains invalid characters (CR/LF).
28    InvalidHeaderValue,
29}
30
31impl std::fmt::Display for HttpError {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        match self {
34            Self::Malformed(ctx) => write!(f, "malformed HTTP: {ctx}"),
35            Self::TooManyHeaders => write!(f, "too many HTTP headers"),
36            Self::HeadTooLarge { max } => write!(f, "HTTP head exceeds {max} bytes"),
37            Self::BufferFull { needed, available } => {
38                write!(f, "buffer full: need {needed}, {available} available")
39            }
40            Self::BufferTooSmall { needed, available } => {
41                write!(
42                    f,
43                    "write buffer too small: need {needed} bytes, have {available}"
44                )
45            }
46            Self::InvalidHeaderValue => {
47                write!(f, "header name or value contains CR/LF")
48            }
49        }
50    }
51}
52
53impl std::error::Error for HttpError {}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    #[test]
60    fn http_error_malformed() {
61        let err = HttpError::Malformed("missing status line");
62        assert!(matches!(err, HttpError::Malformed("missing status line")));
63        assert_eq!(err.to_string(), "malformed HTTP: missing status line");
64    }
65
66    #[test]
67    fn http_error_too_many_headers() {
68        let err = HttpError::TooManyHeaders;
69        assert!(matches!(err, HttpError::TooManyHeaders));
70        assert_eq!(err.to_string(), "too many HTTP headers");
71    }
72
73    #[test]
74    fn http_error_head_too_large() {
75        let err = HttpError::HeadTooLarge { max: 8192 };
76        assert!(matches!(err, HttpError::HeadTooLarge { max: 8192 }));
77        assert_eq!(err.to_string(), "HTTP head exceeds 8192 bytes");
78    }
79
80    #[test]
81    fn http_error_buffer_full() {
82        let err = HttpError::BufferFull {
83            needed: 1024,
84            available: 256,
85        };
86        assert!(matches!(
87            err,
88            HttpError::BufferFull {
89                needed: 1024,
90                available: 256,
91            }
92        ));
93        assert_eq!(err.to_string(), "buffer full: need 1024, 256 available");
94    }
95
96    #[test]
97    fn http_error_buffer_too_small() {
98        let err = HttpError::BufferTooSmall {
99            needed: 512,
100            available: 128,
101        };
102        assert!(matches!(
103            err,
104            HttpError::BufferTooSmall {
105                needed: 512,
106                available: 128,
107            }
108        ));
109        assert_eq!(
110            err.to_string(),
111            "write buffer too small: need 512 bytes, have 128"
112        );
113    }
114
115    #[test]
116    fn http_error_invalid_header_value() {
117        let err = HttpError::InvalidHeaderValue;
118        assert!(matches!(err, HttpError::InvalidHeaderValue));
119        assert_eq!(err.to_string(), "header name or value contains CR/LF");
120    }
121
122    #[test]
123    fn http_error_eq() {
124        assert_eq!(HttpError::TooManyHeaders, HttpError::TooManyHeaders);
125        assert_ne!(HttpError::TooManyHeaders, HttpError::InvalidHeaderValue);
126        assert_eq!(
127            HttpError::HeadTooLarge { max: 100 },
128            HttpError::HeadTooLarge { max: 100 }
129        );
130    }
131}