1use std::{io, str::Utf8Error, string::FromUtf8Error};
4
5use http::{HeaderName, Response};
6use thiserror::Error;
7
8use crate::protocol::frame::codec::Data;
9
10pub type Result<T, E = Error> = std::result::Result<T, E>;
12
13#[derive(Debug, Error)]
15pub enum Error {
16 #[error("Connection closed")]
28 ConnectionClosed,
29
30 #[error("Connection already closed")]
38 AlreadyClosed,
39
40 #[error("I/O Error: {0}")]
43 Io(#[from] io::Error),
44
45 #[error("Protool Error: {0}")]
47 Protocol(#[from] ProtocolError),
48
49 #[error("UTF-8 Error: {0}")]
51 Utf8(String),
52
53 #[error("Write buffer is full")]
55 WriteBufferFull,
56
57 #[error("Capacity Error: {0}")]
61 Capacity(#[from] CapacityError),
62
63 #[error("HTTP Error: {}", .0.status())]
65 #[cfg(feature = "handshake")]
66 Http(Response<Option<Vec<u8>>>),
67
68 #[error("HTTP format error: {0}")]
70 #[cfg(feature = "handshake")]
71 HttpFormat(#[from] http::Error),
72
73 #[error("URL Error: {0}")]
75 Url(#[from] UrlError),
76
77 #[error("TLS Error: {0}")]
82 Tls(#[from] TlsError),
83
84 #[error("Detected attempted attack")]
86 AttackAttempt,
87}
88
89impl From<Utf8Error> for Error {
90 fn from(value: Utf8Error) -> Self {
91 Error::Utf8(value.to_string())
92 }
93}
94impl From<FromUtf8Error> for Error {
95 fn from(value: FromUtf8Error) -> Self {
96 Error::Utf8(value.to_string())
97 }
98}
99
100#[cfg(feature = "handshake")]
101impl From<http::header::InvalidHeaderName> for Error {
102 fn from(value: http::header::InvalidHeaderName) -> Self {
103 Error::HttpFormat(value.into())
104 }
105}
106
107#[cfg(feature = "handshake")]
108impl From<http::header::InvalidHeaderValue> for Error {
109 fn from(value: http::header::InvalidHeaderValue) -> Self {
110 Error::HttpFormat(value.into())
111 }
112}
113
114#[cfg(feature = "handshake")]
115impl From<http::header::ToStrError> for Error {
116 fn from(value: http::header::ToStrError) -> Self {
117 Error::Utf8(value.to_string())
118 }
119}
120
121#[cfg(feature = "handshake")]
122impl From<http::uri::InvalidUri> for Error {
123 fn from(value: http::uri::InvalidUri) -> Self {
124 Error::HttpFormat(value.into())
125 }
126}
127
128#[cfg(feature = "handshake")]
129impl From<http::status::InvalidStatusCode> for Error {
130 fn from(value: http::status::InvalidStatusCode) -> Self {
131 Error::HttpFormat(value.into())
132 }
133}
134
135#[cfg(feature = "handshake")]
136impl From<httparse::Error> for Error {
137 fn from(value: httparse::Error) -> Self {
138 match value {
139 httparse::Error::TooManyHeaders => Error::Capacity(CapacityError::TooManyHeaders),
140 e => Error::Protocol(ProtocolError::HttparseError(e)),
141 }
142 }
143}
144
145#[allow(missing_copy_implementations)]
147#[derive(Debug, Error, PartialEq, Eq, Clone)]
148pub enum ProtocolError {
149 #[error("Invalid HTTP method (must be GET)")]
151 InvalidHttpMethod,
152
153 #[error("Unsupported HTTP version (must be at least HTTP/1.1)")]
155 InvalidHttpVersion,
156
157 #[error("Missing, duplicated or incorrect header {0}")]
159 #[cfg(feature = "handshake")]
160 InvalidHeader(HeaderName),
161
162 #[error("Missing 'Connection: upgrade' header")]
164 MissingConnectionUpgradeHeader,
165
166 #[error("Missing 'Upgrade: websocket' header")]
168 MissingUpgradeHeader,
169
170 #[error("Missing 'Sec-WebSocket-Version: 13' header")]
172 MissingVersionHeader,
173
174 #[error("Missing 'Sec-WebSocket-Key' header")]
176 MissingKeyHeader,
177
178 #[error("Mismatched 'Sec-WebSocket-Accept' header")]
180 AcceptKeyMismatch,
181
182 #[error("SubProtocol error: {0}")]
184 SecWebSocketSubProtocolError(SubProtocolError),
185
186 #[error("Handshake incomplete")]
188 IncompleteHandshake,
189
190 #[error("httparse error: {0}")]
192 #[cfg(feature = "handshake")]
193 HttparseError(#[from] httparse::Error),
194
195 #[error("Encountered frame with non-zero reserved bits")]
197 NonZeroReservedBits,
198
199 #[error("Control frame must not be fragmented")]
201 FragmentedControlFrame,
202
203 #[error("Control frame payload too large")]
205 ControlFrameTooBig,
206
207 #[error("Received unmasked frame from client")]
209 UnmaskedFrameFromClient,
210
211 #[error("Received masked frame from server")]
213 MaskedFrameFromServer,
214
215 #[error("Received unknown control opcode: {0}")]
217 UnknownControlOpCode(u8),
218
219 #[error("Received unknown data opcode: {0}")]
221 UnknownDataOpCode(u8),
222
223 #[error("Received continue frame without open fragmentation context")]
225 UnexpectedContinue,
226
227 #[error("Expected fragment of type {0:?} but received something else")]
229 ExpectedFragment(Data),
230
231 #[error("Sent after close handshake started")]
233 SendAfterClose,
234
235 #[error("Received after close handshake completed")]
237 ReceiveAfterClose,
238
239 #[error("Invalid close frame payload")]
241 InvalidCloseFrame,
242
243 #[error("Connection closed without proper handshake")]
245 ResetWithoutClosing,
246
247 #[error("Junk after client request")]
249 JunkAfterRequest,
250
251 #[error("Custom response must not be successful")]
253 CustomResponseSuccessful,
254}
255
256#[derive(Error, Clone, PartialEq, Eq, Debug, Copy)]
258pub enum SubProtocolError {
259 #[error("Server sent a subprotocol but none was requested")]
261 ServerSentSubProtocolNoneRequested,
262
263 #[error("Server sent an invalid subprotocol")]
265 InvalidSubProtocol,
266
267 #[error("Server sent no subprotocol")]
270 NoSubProtocol,
271}
272
273#[derive(Debug, Error, PartialEq, Eq, Clone, Copy)]
275pub enum CapacityError {
276 #[error("Too many headers received")]
278 TooManyHeaders,
279
280 #[error("Payload too large: {size} > {max}")]
283 MessageTooLarge {
284 size: usize,
286 max: usize,
288 },
289}
290
291#[derive(Debug, Error, PartialEq, Eq, Clone)]
293pub enum UrlError {
294 #[error("Missing host name in URL")]
296 MissingHost,
297
298 #[error("Empty host name in URL")]
300 EmptyHost,
301
302 #[error("Unsupported URL scheme (expected 'ws://' or 'wss://')")]
304 UnsupportedScheme,
305
306 #[error("TLS feature not enabled but 'wss://' URL used")]
308 TlsFeatureNotEnabled,
309
310 #[error("No path / query segment in URL")]
312 NoPathOrQuery,
313
314 #[error("Unable to connect to host: {0}")]
316 UnableToConnect(String),
317}
318
319#[allow(missing_copy_implementations)]
324#[derive(Error, Debug)]
325#[non_exhaustive]
326pub enum TlsError {
327 #[cfg(feature = "native-tls")]
329 #[error("Native TLS Error: {0}")]
330 Native(#[from] native_tls_crate::Error),
331
332 #[cfg(feature = "rustls")]
334 #[error("Rustls Error: {0}")]
335 Rustls(#[from] rustls::Error),
336
337 #[cfg(feature = "rustls")]
339 #[error("Invalid DNS name for TLS")]
340 InvalidDnsName,
341}