parity_ws/
result.rs

1use std::borrow::Cow;
2use std::convert::{From, Into};
3use std::error::Error as StdError;
4use std::fmt;
5use std::io;
6use std::result::Result as StdResult;
7use std::str::Utf8Error;
8
9use httparse;
10use mio;
11#[cfg(feature = "ssl")]
12use openssl::ssl::{Error as SslError, HandshakeError as SslHandshakeError};
13#[cfg(feature = "nativetls")]
14use native_tls::{Error as SslError, HandshakeError as SslHandshakeError};
15#[cfg(any(feature = "ssl", feature = "nativetls"))]
16type HandshakeError = SslHandshakeError<mio::tcp::TcpStream>;
17
18use communication::Command;
19
20pub type Result<T> = StdResult<T, Error>;
21
22/// The type of an error, which may indicate other kinds of errors as the underlying cause.
23#[derive(Debug)]
24pub enum Kind {
25    /// Indicates an internal application error.
26    /// If panic_on_internal is true, which is the default, then the application will panic.
27    /// Otherwise the WebSocket will automatically attempt to send an Error (1011) close code.
28    Internal,
29    /// Indicates a state where some size limit has been exceeded, such as an inability to accept
30    /// any more new connections.
31    /// If a Connection is active, the WebSocket will automatically attempt to send
32    /// a Size (1009) close code.
33    Capacity,
34    /// Indicates a violation of the WebSocket protocol.
35    /// The WebSocket will automatically attempt to send a Protocol (1002) close code, or if
36    /// this error occurs during a handshake, an HTTP 400 response will be generated.
37    Protocol,
38    /// Indicates that the WebSocket received data that should be utf8 encoded but was not.
39    /// The WebSocket will automatically attempt to send a Invalid Frame Payload Data (1007) close
40    /// code.
41    Encoding(Utf8Error),
42    /// Indicates an underlying IO Error.
43    /// This kind of error will result in a WebSocket Connection disconnecting.
44    Io(io::Error),
45    /// Indicates a failure to parse an HTTP message.
46    /// This kind of error should only occur during a WebSocket Handshake, and a HTTP 500 response
47    /// will be generated.
48    Http(httparse::Error),
49    /// Indicates a failure to send a signal on the internal EventLoop channel. This means that
50    /// the WebSocket is overloaded. In order to avoid this error, it is important to set
51    /// `Settings::max_connections` and `Settings:queue_size` high enough to handle the load.
52    /// If encountered, retuning from a handler method and waiting for the EventLoop to consume
53    /// the queue may relieve the situation.
54    Queue(mio::channel::SendError<Command>),
55    /// Indicates a failure to perform SSL encryption.
56    #[cfg(any(feature = "ssl", feature = "nativetls"))]
57    Ssl(SslError),
58    /// Indicates a failure to perform SSL encryption.
59    #[cfg(any(feature = "ssl", feature = "nativetls"))]
60    SslHandshake(HandshakeError),
61    /// A custom error kind for use by applications. This error kind involves extra overhead
62    /// because it will allocate the memory on the heap. The WebSocket ignores such errors by
63    /// default, simply passing them to the Connection Handler.
64    Custom(Box<dyn StdError + Send + Sync>),
65}
66
67/// A struct indicating the kind of error that has occurred and any precise details of that error.
68pub struct Error {
69    pub kind: Kind,
70    pub details: Cow<'static, str>,
71}
72
73impl Error {
74    pub fn new<I>(kind: Kind, details: I) -> Error
75    where
76        I: Into<Cow<'static, str>>,
77    {
78        Error {
79            kind,
80            details: details.into(),
81        }
82    }
83
84    pub fn into_box(self) -> Box<dyn StdError> {
85        match self.kind {
86            Kind::Custom(err) => err,
87            _ => Box::new(self),
88        }
89    }
90}
91
92impl fmt::Debug for Error {
93    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94        if self.details.len() > 0 {
95            write!(f, "WS Error <{:?}>: {}", self.kind, self.details)
96        } else {
97            write!(f, "WS Error <{:?}>", self.kind)
98        }
99    }
100}
101
102impl fmt::Display for Error {
103    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104        if self.details.len() > 0 {
105            write!(f, "{}: {}", self.description(), self.details)
106        } else {
107            write!(f, "{}", self.description())
108        }
109    }
110}
111
112impl StdError for Error {
113    fn description(&self) -> &str {
114        match self.kind {
115            Kind::Internal => "Internal Application Error",
116            Kind::Capacity => "WebSocket at Capacity",
117            Kind::Protocol => "WebSocket Protocol Error",
118            Kind::Encoding(ref err) => err.description(),
119            Kind::Io(ref err) => err.description(),
120            Kind::Http(_) => "Unable to parse HTTP",
121            #[cfg(any(feature = "ssl", feature = "nativetls"))]
122            Kind::Ssl(ref err) => err.description(),
123            #[cfg(any(feature = "ssl", feature = "nativetls"))]
124            Kind::SslHandshake(ref err) => err.description(),
125            Kind::Queue(_) => "Unable to send signal on event loop",
126            Kind::Custom(ref err) => err.description(),
127        }
128    }
129
130    fn cause(&self) -> Option<&dyn StdError> {
131        match self.kind {
132            Kind::Encoding(ref err) => Some(err),
133            Kind::Io(ref err) => Some(err),
134            #[cfg(any(feature = "ssl", feature = "nativetls"))]
135            Kind::Ssl(ref err) => Some(err),
136            #[cfg(any(feature = "ssl", feature = "nativetls"))]
137            Kind::SslHandshake(ref err) => err.cause(),
138            Kind::Custom(ref err) => Some(err.as_ref()),
139            _ => None,
140        }
141    }
142}
143
144impl From<io::Error> for Error {
145    fn from(err: io::Error) -> Error {
146        Error::new(Kind::Io(err), "")
147    }
148}
149
150impl From<httparse::Error> for Error {
151    fn from(err: httparse::Error) -> Error {
152        let details = match err {
153            httparse::Error::HeaderName => "Invalid byte in header name.",
154            httparse::Error::HeaderValue => "Invalid byte in header value.",
155            httparse::Error::NewLine => "Invalid byte in new line.",
156            httparse::Error::Status => "Invalid byte in Response status.",
157            httparse::Error::Token => "Invalid byte where token is required.",
158            httparse::Error::TooManyHeaders => {
159                "Parsed more headers than provided buffer can contain."
160            }
161            httparse::Error::Version => "Invalid byte in HTTP version.",
162        };
163
164        Error::new(Kind::Http(err), details)
165    }
166}
167
168impl From<mio::channel::SendError<Command>> for Error {
169    fn from(err: mio::channel::SendError<Command>) -> Error {
170        match err {
171            mio::channel::SendError::Io(err) => Error::from(err),
172            _ => Error::new(Kind::Queue(err), ""),
173        }
174    }
175}
176
177impl From<Utf8Error> for Error {
178    fn from(err: Utf8Error) -> Error {
179        Error::new(Kind::Encoding(err), "")
180    }
181}
182
183#[cfg(any(feature = "ssl", feature = "nativetls"))]
184impl From<SslError> for Error {
185    fn from(err: SslError) -> Error {
186        Error::new(Kind::Ssl(err), "")
187    }
188}
189
190#[cfg(any(feature = "ssl", feature = "nativetls"))]
191impl From<HandshakeError> for Error {
192    fn from(err: HandshakeError) -> Error {
193        Error::new(Kind::SslHandshake(err), "")
194    }
195}
196
197impl<B> From<Box<B>> for Error
198where
199    B: StdError + Send + Sync + 'static,
200{
201    fn from(err: Box<B>) -> Error {
202        Error::new(Kind::Custom(err), "")
203    }
204}