Skip to main content

specter/websocket/
error.rs

1use std::io;
2
3pub type WebSocketResult<T> = std::result::Result<T, WebSocketError>;
4
5#[derive(Debug, thiserror::Error)]
6pub enum WebSocketError {
7    #[error("WebSocket handshake failed for {url}: expected status 101, got {status}")]
8    InvalidStatus { url: String, status: u16 },
9
10    #[error("WebSocket handshake failed for {url}: invalid Sec-WebSocket-Accept")]
11    InvalidAccept { url: String },
12
13    #[error("WebSocket handshake failed for {url}: unexpected subprotocol")]
14    UnexpectedSubprotocol { url: String },
15
16    #[error("WebSocket handshake failed for {url}: unexpected extension")]
17    UnexpectedExtension { url: String },
18
19    #[error("WebSocket protocol error for {url}: {message}")]
20    Protocol { url: String, message: String },
21
22    #[error("WebSocket UTF-8 error for {url}: {message}")]
23    Utf8 { url: String, message: String },
24
25    #[error("WebSocket size limit exceeded for {url}: {message}")]
26    LimitExceeded { url: String, message: String },
27
28    #[error("WebSocket connection closed for {url}")]
29    ConnectionClosed { url: String },
30
31    #[error("WebSocket timeout for {url}: {operation}")]
32    Timeout { url: String, operation: String },
33
34    #[error("WebSocket I/O error for {url}: {source}")]
35    Io {
36        url: String,
37        #[source]
38        source: io::Error,
39    },
40
41    #[error("WebSocket URL error: {0}")]
42    Url(String),
43}
44
45impl WebSocketError {
46    #[cold]
47    #[inline(never)]
48    pub(crate) fn protocol(url: &crate::url::Url, message: impl Into<String>) -> Self {
49        Self::Protocol {
50            url: url.to_string(),
51            message: message.into(),
52        }
53    }
54
55    #[cold]
56    #[inline(never)]
57    pub(crate) fn utf8(url: &crate::url::Url, message: impl Into<String>) -> Self {
58        Self::Utf8 {
59            url: url.to_string(),
60            message: message.into(),
61        }
62    }
63
64    #[cold]
65    #[inline(never)]
66    pub(crate) fn limit_exceeded(url: &crate::url::Url, message: impl Into<String>) -> Self {
67        Self::LimitExceeded {
68            url: url.to_string(),
69            message: message.into(),
70        }
71    }
72
73    #[cold]
74    #[inline(never)]
75    pub(crate) fn connection_closed(url: &crate::url::Url) -> Self {
76        Self::ConnectionClosed {
77            url: url.to_string(),
78        }
79    }
80
81    #[cold]
82    #[inline(never)]
83    pub(crate) fn io(url: &crate::url::Url, source: io::Error) -> Self {
84        Self::Io {
85            url: url.to_string(),
86            source,
87        }
88    }
89
90    pub(crate) fn close_code(&self) -> Option<crate::websocket::CloseCode> {
91        match self {
92            Self::Protocol { .. } => Some(crate::websocket::CloseCode::Protocol),
93            Self::Utf8 { .. } => Some(crate::websocket::CloseCode::Invalid),
94            Self::LimitExceeded { .. } => Some(crate::websocket::CloseCode::Size),
95            _ => None,
96        }
97    }
98}
99
100impl From<crate::url::ParseError> for WebSocketError {
101    fn from(err: crate::url::ParseError) -> Self {
102        Self::Url(err.to_string())
103    }
104}