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    /// No native root certificates were found and no other root certificate
62    /// source was enabled.
63    #[cfg(all(
64        not(feature = "rustls-webpki-roots"),
65        feature = "rustls-native-roots",
66        not(feature = "rustls-platform-verifier"),
67    ))]
68    NoNativeRootCertificatesFound(Vec<rustls_native_certs::Error>),
69}
70
71#[cfg(feature = "native-tls")]
72impl From<native_tls::Error> for Error {
73    fn from(err: native_tls::Error) -> Self {
74        Self::NativeTls(err)
75    }
76}
77
78impl From<ProtocolError> for Error {
79    fn from(err: ProtocolError) -> Self {
80        Self::Protocol(err)
81    }
82}
83
84impl From<io::Error> for Error {
85    fn from(err: io::Error) -> Self {
86        Self::Io(err)
87    }
88}
89
90#[cfg(any(
91    feature = "rustls-webpki-roots",
92    feature = "rustls-native-roots",
93    feature = "rustls-platform-verifier",
94    feature = "rustls-bring-your-own-connector"
95))]
96impl From<InvalidDnsNameError> for Error {
97    fn from(err: InvalidDnsNameError) -> Self {
98        Self::InvalidDNSName(err)
99    }
100}
101
102#[cfg(any(
103    feature = "rustls-webpki-roots",
104    feature = "rustls-native-roots",
105    feature = "rustls-platform-verifier",
106    feature = "rustls-bring-your-own-connector"
107))]
108impl From<tokio_rustls::rustls::Error> for Error {
109    fn from(err: tokio_rustls::rustls::Error) -> Self {
110        Self::Rustls(err)
111    }
112}
113
114#[cfg(any(feature = "client", feature = "server"))]
115impl From<crate::upgrade::Error> for Error {
116    fn from(err: crate::upgrade::Error) -> Self {
117        Self::Upgrade(err)
118    }
119}
120
121impl fmt::Display for Error {
122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123        match self {
124            Error::AlreadyClosed => {
125                f.write_str("attempted to send message after closing connection")
126            }
127            Error::CannotResolveHost => f.write_str("client DNS lookup failed"),
128            #[cfg(feature = "client")]
129            Error::NoUriConfigured => f.write_str("client has no URI configured"),
130            #[cfg(feature = "client")]
131            Error::DisallowedHeader => f.write_str("attempted to add disallowed header"),
132            Error::Protocol(e) => e.fmt(f),
133            Error::PayloadTooLong { len, max_len } => {
134                f.write_str("payload length of ")?;
135                len.fmt(f)?;
136                f.write_str(" exceeds the limit of ")?;
137                max_len.fmt(f)
138            }
139            Error::Io(e) => e.fmt(f),
140            #[cfg(feature = "native-tls")]
141            Error::NativeTls(e) => e.fmt(f),
142            #[cfg(any(
143                feature = "rustls-webpki-roots",
144                feature = "rustls-native-roots",
145                feature = "rustls-platform-verifier",
146                feature = "rustls-bring-your-own-connector"
147            ))]
148            Error::InvalidDNSName(_) => f.write_str("invalid DNS name"),
149            #[cfg(any(
150                feature = "rustls-webpki-roots",
151                feature = "rustls-native-roots",
152                feature = "rustls-platform-verifier",
153                feature = "rustls-bring-your-own-connector"
154            ))]
155            Error::Rustls(e) => e.fmt(f),
156            #[cfg(feature = "client")]
157            Error::UnsupportedScheme => f.write_str("unsupported or no URI scheme used"),
158            #[cfg(any(feature = "client", feature = "server"))]
159            Error::Upgrade(e) => e.fmt(f),
160            #[cfg(all(
161                not(feature = "rustls-webpki-roots"),
162                feature = "rustls-native-roots",
163                not(feature = "rustls-platform-verifier")
164            ))]
165            Error::NoNativeRootCertificatesFound(e) => {
166                f.write_str("no native root certificates were found, errors encountered: ")?;
167                std::fmt::Debug::fmt(e, f)
168            }
169        }
170    }
171}
172
173impl std::error::Error for Error {
174    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
175        match self {
176            Error::AlreadyClosed | Error::CannotResolveHost | Error::PayloadTooLong { .. } => None,
177            #[cfg(feature = "client")]
178            Error::NoUriConfigured | Error::DisallowedHeader => None,
179            #[cfg(all(
180                not(feature = "rustls-webpki-roots"),
181                feature = "rustls-native-roots",
182                not(feature = "rustls-platform-verifier")
183            ))]
184            Error::NoNativeRootCertificatesFound(e) => Some(e.first()?),
185            #[cfg(feature = "client")]
186            Error::UnsupportedScheme => None,
187            Error::Protocol(e) => Some(e),
188            Error::Io(e) => Some(e),
189            #[cfg(feature = "native-tls")]
190            Error::NativeTls(e) => Some(e),
191            #[cfg(any(
192                feature = "rustls-webpki-roots",
193                feature = "rustls-native-roots",
194                feature = "rustls-platform-verifier",
195                feature = "rustls-bring-your-own-connector"
196            ))]
197            Error::InvalidDNSName(e) => Some(e),
198            #[cfg(any(
199                feature = "rustls-webpki-roots",
200                feature = "rustls-native-roots",
201                feature = "rustls-platform-verifier",
202                feature = "rustls-bring-your-own-connector"
203            ))]
204            Error::Rustls(e) => Some(e),
205            #[cfg(any(feature = "client", feature = "server"))]
206            Error::Upgrade(e) => Some(e),
207        }
208    }
209}