tokio_websockets/
error.rs

1//! General error type used in the crate.
2use std::{fmt, io};
3
4#[cfg(any(
5    feature = "rustls-webpki-roots",
6    feature = "rustls-native-roots",
7    feature = "rustls-platform-verifier",
8    feature = "rustls-bring-your-own-connector"
9))]
10use rustls_pki_types::InvalidDnsNameError;
11#[cfg(feature = "native-tls")]
12use tokio_native_tls::native_tls;
13
14use crate::proto::ProtocolError;
15
16/// Generic error when using WebSockets with this crate.
17#[derive(Debug)]
18#[non_exhaustive]
19pub enum Error {
20    /// Attempted to read from or write to a closed stream.
21    AlreadyClosed,
22    /// DNS lookup failed.
23    CannotResolveHost,
24    /// Attempted to connect a client to a remote without configured URI.
25    #[cfg(feature = "client")]
26    NoUriConfigured,
27    /// Attempted to add a disallowed header.
28    #[cfg(feature = "client")]
29    DisallowedHeader,
30    /// WebSocket protocol violation.
31    Protocol(ProtocolError),
32    /// Payload length limit was exceeded.
33    PayloadTooLong { len: usize, max_len: usize },
34    /// I/O error.
35    Io(io::Error),
36    /// TLS error originating in [`native_tls`].
37    #[cfg(feature = "native-tls")]
38    NativeTls(native_tls::Error),
39    /// Attempted to connect to an invalid DNS name.
40    #[cfg(any(
41        feature = "rustls-webpki-roots",
42        feature = "rustls-native-roots",
43        feature = "rustls-platform-verifier",
44        feature = "rustls-bring-your-own-connector"
45    ))]
46    InvalidDNSName(InvalidDnsNameError),
47    /// A general rustls error.
48    #[cfg(any(
49        feature = "rustls-webpki-roots",
50        feature = "rustls-native-roots",
51        feature = "rustls-platform-verifier",
52        feature = "rustls-bring-your-own-connector"
53    ))]
54    Rustls(tokio_rustls::rustls::Error),
55    /// An unsupported, i.e. not `ws` or `wss`, or no URI scheme was specified.
56    #[cfg(feature = "client")]
57    UnsupportedScheme,
58    /// The HTTP/1.1 Upgrade failed.
59    #[cfg(any(feature = "client", feature = "server"))]
60    Upgrade(crate::upgrade::Error),
61    /// Rustls was enabled via crate features, but no crypto provider was
62    /// configured via
63    /// [`tokio_rustls::rustls::crypto::CryptoProvider::install_default`]
64    /// prior to connecting.
65    #[cfg(any(
66        feature = "rustls-webpki-roots",
67        feature = "rustls-native-roots",
68        feature = "rustls-platform-verifier"
69    ))]
70    NoCryptoProviderConfigured,
71    /// No native root certificates were found and no other root certificate
72    /// source was enabled.
73    #[cfg(all(
74        not(feature = "rustls-webpki-roots"),
75        feature = "rustls-native-roots",
76        not(feature = "rustls-platform-verifier"),
77    ))]
78    NoNativeRootCertificatesFound(Vec<rustls_native_certs::Error>),
79}
80
81#[cfg(feature = "native-tls")]
82impl From<native_tls::Error> for Error {
83    fn from(err: native_tls::Error) -> Self {
84        Self::NativeTls(err)
85    }
86}
87
88impl From<ProtocolError> for Error {
89    fn from(err: ProtocolError) -> Self {
90        Self::Protocol(err)
91    }
92}
93
94impl From<io::Error> for Error {
95    fn from(err: io::Error) -> Self {
96        Self::Io(err)
97    }
98}
99
100#[cfg(any(
101    feature = "rustls-webpki-roots",
102    feature = "rustls-native-roots",
103    feature = "rustls-platform-verifier",
104    feature = "rustls-bring-your-own-connector"
105))]
106impl From<InvalidDnsNameError> for Error {
107    fn from(err: InvalidDnsNameError) -> Self {
108        Self::InvalidDNSName(err)
109    }
110}
111
112#[cfg(any(
113    feature = "rustls-webpki-roots",
114    feature = "rustls-native-roots",
115    feature = "rustls-platform-verifier",
116    feature = "rustls-bring-your-own-connector"
117))]
118impl From<tokio_rustls::rustls::Error> for Error {
119    fn from(err: tokio_rustls::rustls::Error) -> Self {
120        Self::Rustls(err)
121    }
122}
123
124#[cfg(any(feature = "client", feature = "server"))]
125impl From<crate::upgrade::Error> for Error {
126    fn from(err: crate::upgrade::Error) -> Self {
127        Self::Upgrade(err)
128    }
129}
130
131impl fmt::Display for Error {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        match self {
134            Error::AlreadyClosed => {
135                f.write_str("attempted to send message after closing connection")
136            }
137            Error::CannotResolveHost => f.write_str("client DNS lookup failed"),
138            #[cfg(feature = "client")]
139            Error::NoUriConfigured => f.write_str("client has no URI configured"),
140            #[cfg(feature = "client")]
141            Error::DisallowedHeader => f.write_str("attempted to add disallowed header"),
142            Error::Protocol(e) => e.fmt(f),
143            Error::PayloadTooLong { len, max_len } => {
144                f.write_str("payload length of ")?;
145                len.fmt(f)?;
146                f.write_str(" exceeds the limit of ")?;
147                max_len.fmt(f)
148            }
149            Error::Io(e) => e.fmt(f),
150            #[cfg(feature = "native-tls")]
151            Error::NativeTls(e) => e.fmt(f),
152            #[cfg(any(
153                feature = "rustls-webpki-roots",
154                feature = "rustls-native-roots",
155                feature = "rustls-platform-verifier",
156                feature = "rustls-bring-your-own-connector"
157            ))]
158            Error::InvalidDNSName(_) => f.write_str("invalid DNS name"),
159            #[cfg(any(
160                feature = "rustls-webpki-roots",
161                feature = "rustls-native-roots",
162                feature = "rustls-platform-verifier",
163                feature = "rustls-bring-your-own-connector"
164            ))]
165            Error::Rustls(e) => e.fmt(f),
166            #[cfg(feature = "client")]
167            Error::UnsupportedScheme => f.write_str("unsupported or no URI scheme used"),
168            #[cfg(any(feature = "client", feature = "server"))]
169            Error::Upgrade(e) => e.fmt(f),
170            #[cfg(any(
171                feature = "rustls-webpki-roots",
172                feature = "rustls-native-roots",
173                feature = "rustls-platform-verifier"
174            ))]
175            Error::NoCryptoProviderConfigured => {
176                f.write_str("wss uri set but no tls connector was configured")
177            }
178            #[cfg(all(
179                not(feature = "rustls-webpki-roots"),
180                feature = "rustls-native-roots",
181                not(feature = "rustls-platform-verifier")
182            ))]
183            Error::NoNativeRootCertificatesFound(e) => {
184                f.write_str("no native root certificates were found, errors encountered: ")?;
185                std::fmt::Debug::fmt(e, f)
186            }
187        }
188    }
189}
190
191impl std::error::Error for Error {
192    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
193        match self {
194            Error::AlreadyClosed | Error::CannotResolveHost | Error::PayloadTooLong { .. } => None,
195            #[cfg(feature = "client")]
196            Error::NoUriConfigured | Error::DisallowedHeader => None,
197            #[cfg(any(
198                feature = "rustls-webpki-roots",
199                feature = "rustls-native-roots",
200                feature = "rustls-platform-verifier"
201            ))]
202            Error::NoCryptoProviderConfigured => None,
203            #[cfg(all(
204                not(feature = "rustls-webpki-roots"),
205                feature = "rustls-native-roots",
206                not(feature = "rustls-platform-verifier")
207            ))]
208            Error::NoNativeRootCertificatesFound(e) => Some(e.first()?),
209            #[cfg(feature = "client")]
210            Error::UnsupportedScheme => None,
211            Error::Protocol(e) => Some(e),
212            Error::Io(e) => Some(e),
213            #[cfg(feature = "native-tls")]
214            Error::NativeTls(e) => Some(e),
215            #[cfg(any(
216                feature = "rustls-webpki-roots",
217                feature = "rustls-native-roots",
218                feature = "rustls-platform-verifier",
219                feature = "rustls-bring-your-own-connector"
220            ))]
221            Error::InvalidDNSName(e) => Some(e),
222            #[cfg(any(
223                feature = "rustls-webpki-roots",
224                feature = "rustls-native-roots",
225                feature = "rustls-platform-verifier",
226                feature = "rustls-bring-your-own-connector"
227            ))]
228            Error::Rustls(e) => Some(e),
229            #[cfg(any(feature = "client", feature = "server"))]
230            Error::Upgrade(e) => Some(e),
231        }
232    }
233}