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#[derive(Debug)]
24pub enum Kind {
25 Internal,
29 Capacity,
34 Protocol,
38 Encoding(Utf8Error),
42 Io(io::Error),
45 Http(httparse::Error),
49 Queue(mio::channel::SendError<Command>),
55 #[cfg(any(feature = "ssl", feature = "nativetls"))]
57 Ssl(SslError),
58 #[cfg(any(feature = "ssl", feature = "nativetls"))]
60 SslHandshake(HandshakeError),
61 Custom(Box<dyn StdError + Send + Sync>),
65}
66
67pub 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}