1use std::{io, result, str, string};
4
5use crate::{
6 extensions::{compression::CompressionError, ExtensionsError},
7 protocol::{frame::coding::Data, Message},
8};
9#[cfg(feature = "handshake")]
10use http::{header::HeaderName, Response};
11use thiserror::Error;
12
13pub type Result<T, E = Error> = result::Result<T, E>;
15
16#[derive(Error, Debug)]
18pub enum Error {
19 #[error("Connection closed normally")]
31 ConnectionClosed,
32 #[error("Trying to work with closed connection")]
40 AlreadyClosed,
41 #[error("IO error: {0}")]
44 Io(#[from] io::Error),
45 #[error("TLS error: {0}")]
50 Tls(#[from] TlsError),
51 #[error("Space limit exceeded: {0}")]
55 Capacity(#[from] CapacityError),
56 #[error("WebSocket protocol error: {0}")]
58 Protocol(#[from] ProtocolError),
59 #[error("Write buffer is full")]
61 WriteBufferFull(Box<Message>),
62 #[error("UTF-8 encoding error: {0}")]
64 Utf8(String),
65 #[error("Attack attempt detected")]
67 AttackAttempt,
68 #[error("URL error: {0}")]
70 Url(#[from] UrlError),
71 #[error("HTTP error: {}", .0.status())]
73 #[cfg(feature = "handshake")]
74 Http(Box<Response<Option<Vec<u8>>>>),
75 #[error("HTTP format error: {0}")]
77 #[cfg(feature = "handshake")]
78 HttpFormat(#[from] http::Error),
79}
80
81impl From<str::Utf8Error> for Error {
82 fn from(err: str::Utf8Error) -> Self {
83 Error::Utf8(err.to_string())
84 }
85}
86
87impl From<string::FromUtf8Error> for Error {
88 fn from(err: string::FromUtf8Error) -> Self {
89 Error::Utf8(err.to_string())
90 }
91}
92
93#[cfg(feature = "handshake")]
94impl From<http::header::InvalidHeaderValue> for Error {
95 fn from(err: http::header::InvalidHeaderValue) -> Self {
96 Error::HttpFormat(err.into())
97 }
98}
99
100#[cfg(feature = "handshake")]
101impl From<http::header::InvalidHeaderName> for Error {
102 fn from(err: http::header::InvalidHeaderName) -> Self {
103 Error::HttpFormat(err.into())
104 }
105}
106
107#[cfg(feature = "handshake")]
108impl From<http::header::ToStrError> for Error {
109 fn from(err: http::header::ToStrError) -> Self {
110 Error::Utf8(err.to_string())
111 }
112}
113
114#[cfg(feature = "handshake")]
115impl From<http::uri::InvalidUri> for Error {
116 fn from(err: http::uri::InvalidUri) -> Self {
117 Error::HttpFormat(err.into())
118 }
119}
120
121#[cfg(feature = "handshake")]
122impl From<http::status::InvalidStatusCode> for Error {
123 fn from(err: http::status::InvalidStatusCode) -> Self {
124 Error::HttpFormat(err.into())
125 }
126}
127
128#[cfg(feature = "handshake")]
129impl From<httparse::Error> for Error {
130 fn from(err: httparse::Error) -> Self {
131 match err {
132 httparse::Error::TooManyHeaders => Error::Capacity(CapacityError::TooManyHeaders),
133 e => Error::Protocol(ProtocolError::HttparseError(e)),
134 }
135 }
136}
137
138#[derive(Error, Debug, PartialEq, Eq, Clone, Copy)]
140pub enum CapacityError {
141 #[error("Too many headers")]
143 TooManyHeaders,
144 #[error("Message too long: {size} > {max_size}")]
147 MessageTooLong {
148 size: usize,
150 max_size: usize,
152 },
153}
154
155#[derive(Error, Clone, PartialEq, Eq, Debug, Copy)]
157pub enum SubProtocolError {
158 #[error("Server sent a subprotocol but none was requested")]
160 ServerSentSubProtocolNoneRequested,
161
162 #[error("Server sent an invalid subprotocol")]
164 InvalidSubProtocol,
165
166 #[error("Server sent no subprotocol")]
169 NoSubProtocol,
170}
171
172#[allow(missing_copy_implementations)]
174#[derive(Error, Debug, PartialEq, Eq, Clone)]
175pub enum ProtocolError {
176 #[error("Unsupported HTTP method used - only GET is allowed")]
178 WrongHttpMethod,
179 #[error("HTTP version must be 1.1 or higher")]
181 WrongHttpVersion,
182 #[error("No \"Connection: upgrade\" header")]
184 MissingConnectionUpgradeHeader,
185 #[error("No \"Upgrade: websocket\" header")]
187 MissingUpgradeWebSocketHeader,
188 #[error("No \"Sec-WebSocket-Version: 13\" header")]
190 MissingSecWebSocketVersionHeader,
191 #[error("No \"Sec-WebSocket-Key\" header")]
193 MissingSecWebSocketKey,
194 #[error("Key mismatch in \"Sec-WebSocket-Accept\" header")]
196 SecWebSocketAcceptKeyMismatch,
197 #[error("SubProtocol error: {0}")]
199 SecWebSocketSubProtocolError(SubProtocolError),
200 #[error("Invalid \"Sec-WebSocket-Extensions\" header: {0}")]
202 InvalidExtensionsHeader(#[from] ExtensionsError),
203 #[error("Junk after client request")]
205 JunkAfterRequest,
206 #[error("Custom response must not be successful")]
208 CustomResponseSuccessful,
209 #[error("Missing, duplicated or incorrect header {0}")]
211 #[cfg(feature = "handshake")]
212 InvalidHeader(Box<HeaderName>),
213 #[error("Handshake not finished")]
215 HandshakeIncomplete,
216 #[error("httparse error: {0}")]
218 #[cfg(feature = "handshake")]
219 HttparseError(#[from] httparse::Error),
220 #[error("Sending after closing is not allowed")]
222 SendAfterClosing,
223 #[error("Remote sent after having closed")]
225 ReceivedAfterClosing,
226 #[error("Reserved bits are non-zero")]
228 NonZeroReservedBits,
229 #[error("Received an unmasked frame from client")]
231 UnmaskedFrameFromClient,
232 #[error("Received a masked frame from server")]
234 MaskedFrameFromServer,
235 #[error("Fragmented control frame")]
237 FragmentedControlFrame,
238 #[error("Compressed control frame")]
240 CompressedControlFrame,
241 #[error("Control frame too big (payload must be 125 bytes or less)")]
243 ControlFrameTooBig,
244 #[error("Unknown control frame type: {0}")]
246 UnknownControlFrameType(u8),
247 #[error("Unknown data frame type: {0}")]
249 UnknownDataFrameType(u8),
250 #[error("Continue frame but nothing to continue")]
252 UnexpectedContinueFrame,
253 #[error("Continue frame must not have compress bit set")]
255 CompressedContinueFrame,
256 #[error("While waiting for more fragments received: {0}")]
258 ExpectedFragment(Data),
259 #[error("Connection reset without closing handshake")]
261 ResetWithoutClosingHandshake,
262 #[error("Encountered invalid opcode: {0}")]
264 InvalidOpcode(u8),
265 #[error("Invalid close sequence")]
267 InvalidCloseSequence,
268 #[error("Compression/decompression failed: {0}")]
270 CompressionFailure(#[from] CompressionError),
271}
272
273#[derive(Error, Debug, PartialEq, Eq)]
275pub enum UrlError {
276 #[error("TLS support not compiled in")]
278 TlsFeatureNotEnabled,
279 #[error("No host name in the URL")]
281 NoHostName,
282 #[error("Unable to connect to {0}")]
284 UnableToConnect(String),
285 #[error("URL scheme not supported")]
287 UnsupportedUrlScheme,
288 #[error("URL contains empty host name")]
290 EmptyHostName,
291 #[error("No path/query in URL")]
293 NoPathOrQuery,
294 #[error("Proxy URL scheme not supported")]
296 UnsupportedProxyScheme,
297 #[error("Invalid proxy configuration: {0}")]
299 InvalidProxyConfig(String),
300 #[error("Proxy connection failed: {0}")]
302 ProxyConnect(String),
303}
304
305#[allow(missing_copy_implementations)]
310#[derive(Error, Debug)]
311#[non_exhaustive]
312pub enum TlsError {
313 #[cfg(feature = "native-tls")]
315 #[error("native-tls error: {0}")]
316 Native(Box<native_tls_crate::Error>),
317 #[cfg(feature = "__rustls-tls")]
319 #[error("rustls error: {0}")]
320 Rustls(Box<rustls::Error>),
321 #[cfg(feature = "__rustls-tls")]
323 #[error("Invalid DNS name")]
324 InvalidDnsName,
325}
326
327#[cfg(feature = "native-tls")]
328impl From<native_tls_crate::Error> for TlsError {
329 fn from(e: native_tls_crate::Error) -> Self {
330 Self::Native(e.into())
331 }
332}
333
334#[cfg(feature = "__rustls-tls")]
335impl From<rustls::Error> for TlsError {
336 fn from(e: rustls::Error) -> Self {
337 Self::Rustls(e.into())
338 }
339}
340
341#[cfg(test)]
342mod test {
343 #[test]
344 fn error_size() {
345 let size = std::mem::size_of::<crate::Error>();
346 assert!(size <= 32, "Error is large: {size}");
347 }
348
349 #[test]
350 fn tls_error_size() {
351 let size = std::mem::size_of::<crate::error::TlsError>();
352 assert!(size <= 16, "TlsError is large: {size}");
353 }
354
355 #[test]
356 fn protocol_error_size() {
357 let size = std::mem::size_of::<crate::error::ProtocolError>();
358 assert!(size <= 24, "ProtocolError is large: {size}");
359 }
360}