Skip to main content

h11/
_util.rs

1use std::fmt;
2
3/// Error caused by invalid local API usage or invalid locally-created events.
4#[derive(Debug, PartialEq, Eq)]
5pub struct LocalProtocolError {
6    /// Human-readable error message.
7    pub message: String,
8    /// Suggested HTTP status code for this protocol error.
9    pub code: u16,
10}
11
12impl From<(String, u16)> for LocalProtocolError {
13    fn from(value: (String, u16)) -> Self {
14        LocalProtocolError {
15            message: value.0,
16            code: value.1,
17        }
18    }
19}
20
21impl From<(&str, u16)> for LocalProtocolError {
22    fn from(value: (&str, u16)) -> Self {
23        LocalProtocolError {
24            message: value.0.to_string(),
25            code: value.1,
26        }
27    }
28}
29
30impl From<String> for LocalProtocolError {
31    fn from(value: String) -> Self {
32        LocalProtocolError {
33            message: value,
34            code: 400,
35        }
36    }
37}
38
39impl From<&str> for LocalProtocolError {
40    fn from(value: &str) -> Self {
41        LocalProtocolError {
42            message: value.to_string(),
43            code: 400,
44        }
45    }
46}
47
48impl LocalProtocolError {
49    pub(crate) fn _reraise_as_remote_protocol_error(self) -> RemoteProtocolError {
50        RemoteProtocolError {
51            message: self.message,
52            code: self.code,
53        }
54    }
55}
56
57impl fmt::Display for LocalProtocolError {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        write!(f, "{} (status code {})", self.message, self.code)
60    }
61}
62
63impl std::error::Error for LocalProtocolError {}
64
65/// Error caused by malformed peer input.
66#[derive(Debug, PartialEq, Eq)]
67pub struct RemoteProtocolError {
68    /// Human-readable error message.
69    pub message: String,
70    /// Suggested HTTP status code for this protocol error.
71    pub code: u16,
72}
73
74impl From<(String, u16)> for RemoteProtocolError {
75    fn from(value: (String, u16)) -> Self {
76        RemoteProtocolError {
77            message: value.0,
78            code: value.1,
79        }
80    }
81}
82
83impl From<(&str, u16)> for RemoteProtocolError {
84    fn from(value: (&str, u16)) -> Self {
85        RemoteProtocolError {
86            message: value.0.to_string(),
87            code: value.1,
88        }
89    }
90}
91
92impl From<String> for RemoteProtocolError {
93    fn from(value: String) -> Self {
94        RemoteProtocolError {
95            message: value,
96            code: 400,
97        }
98    }
99}
100
101impl From<&str> for RemoteProtocolError {
102    fn from(value: &str) -> Self {
103        RemoteProtocolError {
104            message: value.to_string(),
105            code: 400,
106        }
107    }
108}
109
110impl fmt::Display for RemoteProtocolError {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        write!(f, "{} (status code {})", self.message, self.code)
113    }
114}
115
116impl std::error::Error for RemoteProtocolError {}
117
118/// Protocol error wrapper used by fallible public APIs.
119#[derive(Debug, PartialEq, Eq)]
120pub enum ProtocolError {
121    /// Local protocol misuse.
122    LocalProtocolError(LocalProtocolError),
123    /// Remote peer protocol violation.
124    RemoteProtocolError(RemoteProtocolError),
125}
126
127impl From<LocalProtocolError> for ProtocolError {
128    fn from(value: LocalProtocolError) -> Self {
129        ProtocolError::LocalProtocolError(value)
130    }
131}
132
133impl From<RemoteProtocolError> for ProtocolError {
134    fn from(value: RemoteProtocolError) -> Self {
135        ProtocolError::RemoteProtocolError(value)
136    }
137}
138
139impl fmt::Display for ProtocolError {
140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141        match self {
142            Self::LocalProtocolError(error) => write!(f, "local protocol error: {}", error),
143            Self::RemoteProtocolError(error) => write!(f, "remote protocol error: {}", error),
144        }
145    }
146}
147
148impl std::error::Error for ProtocolError {
149    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
150        match self {
151            Self::LocalProtocolError(error) => Some(error),
152            Self::RemoteProtocolError(error) => Some(error),
153        }
154    }
155}
156
157#[cfg(test)]
158mod tests {
159    use super::*;
160    use std::error::Error;
161
162    #[test]
163    fn protocol_errors_implement_display_and_error() {
164        let local = LocalProtocolError::from(("bad request", 400));
165        assert_eq!(local.to_string(), "bad request (status code 400)");
166
167        let remote = RemoteProtocolError::from(("bad gateway", 502));
168        assert_eq!(remote.to_string(), "bad gateway (status code 502)");
169
170        let error = ProtocolError::from(LocalProtocolError::from(("invalid", 400)));
171        assert_eq!(
172            error.to_string(),
173            "local protocol error: invalid (status code 400)"
174        );
175        assert!(error.source().is_some());
176    }
177}