1 //! Error handling.
2 
3 use std::{io, result, str, string};
4 
5 use crate::protocol::{frame::coding::Data, Message};
6 #[cfg(feature = "handshake")]
7 use http::{header::HeaderName, Response};
8 use thiserror::Error;
9 
10 /// Result type of all Tungstenite library calls.
11 pub type Result<T, E = Error> = result::Result<T, E>;
12 
13 /// Possible WebSocket errors.
14 #[derive(Error, Debug)]
15 pub enum Error {
16     /// WebSocket connection closed normally. This informs you of the close.
17     /// It's not an error as such and nothing wrong happened.
18     ///
19     /// This is returned as soon as the close handshake is finished (we have both sent and
20     /// received a close frame) on the server end and as soon as the server has closed the
21     /// underlying connection if this endpoint is a client.
22     ///
23     /// Thus when you receive this, it is safe to drop the underlying connection.
24     ///
25     /// Receiving this error means that the WebSocket object is not usable anymore and the
26     /// only meaningful action with it is dropping it.
27     #[error("Connection closed normally")]
28     ConnectionClosed,
29     /// Trying to work with already closed connection.
30     ///
31     /// Trying to read or write after receiving `ConnectionClosed` causes this.
32     ///
33     /// As opposed to `ConnectionClosed`, this indicates your code tries to operate on the
34     /// connection when it really shouldn't anymore, so this really indicates a programmer
35     /// error on your part.
36     #[error("Trying to work with closed connection")]
37     AlreadyClosed,
38     /// Input-output error. Apart from WouldBlock, these are generally errors with the
39     /// underlying connection and you should probably consider them fatal.
40     #[error("IO error: {0}")]
41     Io(#[from] io::Error),
42     /// TLS error.
43     ///
44     /// Note that this error variant is enabled unconditionally even if no TLS feature is enabled,
45     /// to provide a feature-agnostic API surface.
46     #[error("TLS error: {0}")]
47     Tls(#[from] TlsError),
48     /// - When reading: buffer capacity exhausted.
49     /// - When writing: your message is bigger than the configured max message size
50     ///   (64MB by default).
51     #[error("Space limit exceeded: {0}")]
52     Capacity(#[from] CapacityError),
53     /// Protocol violation.
54     #[error("WebSocket protocol error: {0}")]
55     Protocol(#[from] ProtocolError),
56     /// Message write buffer is full.
57     #[error("Write buffer is full")]
58     WriteBufferFull(Message),
59     /// UTF coding error.
60     #[error("UTF-8 encoding error")]
61     Utf8,
62     /// Attack attempt detected.
63     #[error("Attack attempt detected")]
64     AttackAttempt,
65     /// Invalid URL.
66     #[error("URL error: {0}")]
67     Url(#[from] UrlError),
68     /// HTTP error.
69     #[error("HTTP error: {}", .0.status())]
70     #[cfg(feature = "handshake")]
71     Http(Response<Option<Vec<u8>>>),
72     /// HTTP format error.
73     #[error("HTTP format error: {0}")]
74     #[cfg(feature = "handshake")]
75     HttpFormat(#[from] http::Error),
76 }
77 
78 impl From<str::Utf8Error> for Error {
from(_: str::Utf8Error) -> Self79     fn from(_: str::Utf8Error) -> Self {
80         Error::Utf8
81     }
82 }
83 
84 impl From<string::FromUtf8Error> for Error {
from(_: string::FromUtf8Error) -> Self85     fn from(_: string::FromUtf8Error) -> Self {
86         Error::Utf8
87     }
88 }
89 
90 #[cfg(feature = "handshake")]
91 impl From<http::header::InvalidHeaderValue> for Error {
from(err: http::header::InvalidHeaderValue) -> Self92     fn from(err: http::header::InvalidHeaderValue) -> Self {
93         Error::HttpFormat(err.into())
94     }
95 }
96 
97 #[cfg(feature = "handshake")]
98 impl From<http::header::InvalidHeaderName> for Error {
from(err: http::header::InvalidHeaderName) -> Self99     fn from(err: http::header::InvalidHeaderName) -> Self {
100         Error::HttpFormat(err.into())
101     }
102 }
103 
104 #[cfg(feature = "handshake")]
105 impl From<http::header::ToStrError> for Error {
from(_: http::header::ToStrError) -> Self106     fn from(_: http::header::ToStrError) -> Self {
107         Error::Utf8
108     }
109 }
110 
111 #[cfg(feature = "handshake")]
112 impl From<http::uri::InvalidUri> for Error {
from(err: http::uri::InvalidUri) -> Self113     fn from(err: http::uri::InvalidUri) -> Self {
114         Error::HttpFormat(err.into())
115     }
116 }
117 
118 #[cfg(feature = "handshake")]
119 impl From<http::status::InvalidStatusCode> for Error {
from(err: http::status::InvalidStatusCode) -> Self120     fn from(err: http::status::InvalidStatusCode) -> Self {
121         Error::HttpFormat(err.into())
122     }
123 }
124 
125 #[cfg(feature = "handshake")]
126 impl From<httparse::Error> for Error {
from(err: httparse::Error) -> Self127     fn from(err: httparse::Error) -> Self {
128         match err {
129             httparse::Error::TooManyHeaders => Error::Capacity(CapacityError::TooManyHeaders),
130             e => Error::Protocol(ProtocolError::HttparseError(e)),
131         }
132     }
133 }
134 
135 /// Indicates the specific type/cause of a capacity error.
136 #[derive(Error, Debug, PartialEq, Eq, Clone, Copy)]
137 pub enum CapacityError {
138     /// Too many headers provided (see [`httparse::Error::TooManyHeaders`]).
139     #[error("Too many headers")]
140     TooManyHeaders,
141     /// Received header is too long.
142     /// Message is bigger than the maximum allowed size.
143     #[error("Message too long: {size} > {max_size}")]
144     MessageTooLong {
145         /// The size of the message.
146         size: usize,
147         /// The maximum allowed message size.
148         max_size: usize,
149     },
150 }
151 
152 /// Indicates the specific type/cause of a protocol error.
153 #[allow(missing_copy_implementations)]
154 #[derive(Error, Debug, PartialEq, Eq, Clone)]
155 pub enum ProtocolError {
156     /// Use of the wrong HTTP method (the WebSocket protocol requires the GET method be used).
157     #[error("Unsupported HTTP method used - only GET is allowed")]
158     WrongHttpMethod,
159     /// Wrong HTTP version used (the WebSocket protocol requires version 1.1 or higher).
160     #[error("HTTP version must be 1.1 or higher")]
161     WrongHttpVersion,
162     /// Missing `Connection: upgrade` HTTP header.
163     #[error("No \"Connection: upgrade\" header")]
164     MissingConnectionUpgradeHeader,
165     /// Missing `Upgrade: websocket` HTTP header.
166     #[error("No \"Upgrade: websocket\" header")]
167     MissingUpgradeWebSocketHeader,
168     /// Missing `Sec-WebSocket-Version: 13` HTTP header.
169     #[error("No \"Sec-WebSocket-Version: 13\" header")]
170     MissingSecWebSocketVersionHeader,
171     /// Missing `Sec-WebSocket-Key` HTTP header.
172     #[error("No \"Sec-WebSocket-Key\" header")]
173     MissingSecWebSocketKey,
174     /// The `Sec-WebSocket-Accept` header is either not present or does not specify the correct key value.
175     #[error("Key mismatch in \"Sec-WebSocket-Accept\" header")]
176     SecWebSocketAcceptKeyMismatch,
177     /// Garbage data encountered after client request.
178     #[error("Junk after client request")]
179     JunkAfterRequest,
180     /// Custom responses must be unsuccessful.
181     #[error("Custom response must not be successful")]
182     CustomResponseSuccessful,
183     /// Invalid header is passed. Or the header is missing in the request. Or not present at all. Check the request that you pass.
184     #[error("Missing, duplicated or incorrect header {0}")]
185     #[cfg(feature = "handshake")]
186     InvalidHeader(HeaderName),
187     /// No more data while still performing handshake.
188     #[error("Handshake not finished")]
189     HandshakeIncomplete,
190     /// Wrapper around a [`httparse::Error`] value.
191     #[error("httparse error: {0}")]
192     #[cfg(feature = "handshake")]
193     HttparseError(#[from] httparse::Error),
194     /// Not allowed to send after having sent a closing frame.
195     #[error("Sending after closing is not allowed")]
196     SendAfterClosing,
197     /// Remote sent data after sending a closing frame.
198     #[error("Remote sent after having closed")]
199     ReceivedAfterClosing,
200     /// Reserved bits in frame header are non-zero.
201     #[error("Reserved bits are non-zero")]
202     NonZeroReservedBits,
203     /// The server must close the connection when an unmasked frame is received.
204     #[error("Received an unmasked frame from client")]
205     UnmaskedFrameFromClient,
206     /// The client must close the connection when a masked frame is received.
207     #[error("Received a masked frame from server")]
208     MaskedFrameFromServer,
209     /// Control frames must not be fragmented.
210     #[error("Fragmented control frame")]
211     FragmentedControlFrame,
212     /// Control frames must have a payload of 125 bytes or less.
213     #[error("Control frame too big (payload must be 125 bytes or less)")]
214     ControlFrameTooBig,
215     /// Type of control frame not recognised.
216     #[error("Unknown control frame type: {0}")]
217     UnknownControlFrameType(u8),
218     /// Type of data frame not recognised.
219     #[error("Unknown data frame type: {0}")]
220     UnknownDataFrameType(u8),
221     /// Received a continue frame despite there being nothing to continue.
222     #[error("Continue frame but nothing to continue")]
223     UnexpectedContinueFrame,
224     /// Received data while waiting for more fragments.
225     #[error("While waiting for more fragments received: {0}")]
226     ExpectedFragment(Data),
227     /// Connection closed without performing the closing handshake.
228     #[error("Connection reset without closing handshake")]
229     ResetWithoutClosingHandshake,
230     /// Encountered an invalid opcode.
231     #[error("Encountered invalid opcode: {0}")]
232     InvalidOpcode(u8),
233     /// The payload for the closing frame is invalid.
234     #[error("Invalid close sequence")]
235     InvalidCloseSequence,
236 }
237 
238 /// Indicates the specific type/cause of URL error.
239 #[derive(Error, Debug, PartialEq, Eq)]
240 pub enum UrlError {
241     /// TLS is used despite not being compiled with the TLS feature enabled.
242     #[error("TLS support not compiled in")]
243     TlsFeatureNotEnabled,
244     /// The URL does not include a host name.
245     #[error("No host name in the URL")]
246     NoHostName,
247     /// Failed to connect with this URL.
248     #[error("Unable to connect to {0}")]
249     UnableToConnect(String),
250     /// Unsupported URL scheme used (only `ws://` or `wss://` may be used).
251     #[error("URL scheme not supported")]
252     UnsupportedUrlScheme,
253     /// The URL host name, though included, is empty.
254     #[error("URL contains empty host name")]
255     EmptyHostName,
256     /// The URL does not include a path/query.
257     #[error("No path/query in URL")]
258     NoPathOrQuery,
259 }
260 
261 /// TLS errors.
262 ///
263 /// Note that even if you enable only the rustls-based TLS support, the error at runtime could still
264 /// be `Native`, as another crate in the dependency graph may enable native TLS support.
265 #[allow(missing_copy_implementations)]
266 #[derive(Error, Debug)]
267 #[non_exhaustive]
268 pub enum TlsError {
269     /// Native TLS error.
270     #[cfg(feature = "native-tls")]
271     #[error("native-tls error: {0}")]
272     Native(#[from] native_tls_crate::Error),
273     /// Rustls error.
274     #[cfg(feature = "__rustls-tls")]
275     #[error("rustls error: {0}")]
276     Rustls(#[from] rustls::Error),
277     /// DNS name resolution error.
278     #[cfg(feature = "__rustls-tls")]
279     #[error("Invalid DNS name")]
280     InvalidDnsName,
281 }
282