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