use std::io;
use std::str::Utf8Error;
use std::error::Error;
use std::convert::From;
use std::fmt;
use hyper::Error as HttpError;
use url::ParseError;
use server::upgrade::HyperIntoWsError;
#[cfg(any(feature="sync-ssl", feature="async-ssl"))]
use native_tls::Error as TlsError;
#[cfg(any(feature="sync-ssl", feature="async-ssl"))]
use native_tls::HandshakeError as TlsHandshakeError;
pub type WebSocketResult<T> = Result<T, WebSocketError>;
#[cfg(feature="async")]
pub mod async {
use futures::Future;
use super::WebSocketError;
pub type WebSocketFuture<I> = Box<Future<Item = I, Error = WebSocketError>>;
}
#[derive(Debug)]
pub enum WebSocketError {
ProtocolError(&'static str),
RequestError(&'static str),
ResponseError(&'static str),
DataFrameError(&'static str),
NoDataAvailable,
IoError(io::Error),
HttpError(HttpError),
UrlError(ParseError),
WebSocketUrlError(WSUrlErrorKind),
#[cfg(any(feature="sync-ssl", feature="async-ssl"))]
TlsError(TlsError),
#[cfg(any(feature="sync-ssl", feature="async-ssl"))]
TlsHandshakeFailure,
#[cfg(any(feature="sync-ssl", feature="async-ssl"))]
TlsHandshakeInterruption,
Utf8Error(Utf8Error),
}
impl fmt::Display for WebSocketError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("WebSocketError: ")?;
fmt.write_str(self.description())?;
Ok(())
}
}
impl Error for WebSocketError {
fn description(&self) -> &str {
match *self {
WebSocketError::ProtocolError(_) => "WebSocket protocol error",
WebSocketError::RequestError(_) => "WebSocket request error",
WebSocketError::ResponseError(_) => "WebSocket response error",
WebSocketError::DataFrameError(_) => "WebSocket data frame error",
WebSocketError::NoDataAvailable => "No data available",
WebSocketError::IoError(_) => "I/O failure",
WebSocketError::HttpError(_) => "HTTP failure",
WebSocketError::UrlError(_) => "URL failure",
#[cfg(any(feature="sync-ssl", feature="async-ssl"))]
WebSocketError::TlsError(_) => "TLS failure",
#[cfg(any(feature="sync-ssl", feature="async-ssl"))]
WebSocketError::TlsHandshakeFailure => "TLS Handshake failure",
#[cfg(any(feature="sync-ssl", feature="async-ssl"))]
WebSocketError::TlsHandshakeInterruption => "TLS Handshake interrupted",
WebSocketError::Utf8Error(_) => "UTF-8 failure",
WebSocketError::WebSocketUrlError(_) => "WebSocket URL failure",
}
}
fn cause(&self) -> Option<&Error> {
match *self {
WebSocketError::IoError(ref error) => Some(error),
WebSocketError::HttpError(ref error) => Some(error),
WebSocketError::UrlError(ref error) => Some(error),
#[cfg(any(feature="sync-ssl", feature="async-ssl"))]
WebSocketError::TlsError(ref error) => Some(error),
WebSocketError::Utf8Error(ref error) => Some(error),
WebSocketError::WebSocketUrlError(ref error) => Some(error),
_ => None,
}
}
}
impl From<io::Error> for WebSocketError {
fn from(err: io::Error) -> WebSocketError {
if err.kind() == io::ErrorKind::UnexpectedEof {
return WebSocketError::NoDataAvailable;
}
WebSocketError::IoError(err)
}
}
impl From<HttpError> for WebSocketError {
fn from(err: HttpError) -> WebSocketError {
WebSocketError::HttpError(err)
}
}
impl From<ParseError> for WebSocketError {
fn from(err: ParseError) -> WebSocketError {
WebSocketError::UrlError(err)
}
}
#[cfg(any(feature="sync-ssl", feature="async-ssl"))]
impl From<TlsError> for WebSocketError {
fn from(err: TlsError) -> WebSocketError {
WebSocketError::TlsError(err)
}
}
#[cfg(any(feature="sync-ssl", feature="async-ssl"))]
impl<T> From<TlsHandshakeError<T>> for WebSocketError {
fn from(err: TlsHandshakeError<T>) -> WebSocketError {
match err {
TlsHandshakeError::Failure(_) => WebSocketError::TlsHandshakeFailure,
TlsHandshakeError::Interrupted(_) => WebSocketError::TlsHandshakeInterruption,
}
}
}
impl From<Utf8Error> for WebSocketError {
fn from(err: Utf8Error) -> WebSocketError {
WebSocketError::Utf8Error(err)
}
}
#[cfg(feature="async")]
impl From<::codec::http::HttpCodecError> for WebSocketError {
fn from(src: ::codec::http::HttpCodecError) -> Self {
match src {
::codec::http::HttpCodecError::Io(e) => WebSocketError::IoError(e),
::codec::http::HttpCodecError::Http(e) => WebSocketError::HttpError(e),
}
}
}
impl From<WSUrlErrorKind> for WebSocketError {
fn from(err: WSUrlErrorKind) -> WebSocketError {
WebSocketError::WebSocketUrlError(err)
}
}
impl From<HyperIntoWsError> for WebSocketError {
fn from(err: HyperIntoWsError) -> WebSocketError {
use self::HyperIntoWsError::*;
use WebSocketError::*;
match err {
Io(io) => IoError(io),
Parsing(err) => HttpError(err),
MethodNotGet => ProtocolError("Request method must be GET"),
UnsupportedHttpVersion => ProtocolError("Unsupported request HTTP version"),
UnsupportedWebsocketVersion => ProtocolError("Unsupported WebSocket version"),
NoSecWsKeyHeader => ProtocolError("Missing Sec-WebSocket-Key header"),
NoWsUpgradeHeader => ProtocolError("Invalid Upgrade WebSocket header"),
NoUpgradeHeader => ProtocolError("Missing Upgrade WebSocket header"),
NoWsConnectionHeader => ProtocolError("Invalid Connection WebSocket header"),
NoConnectionHeader => ProtocolError("Missing Connection WebSocket header"),
}
}
}
#[derive(Debug)]
pub enum WSUrlErrorKind {
CannotSetFragment,
InvalidScheme,
NoHostName,
}
impl fmt::Display for WSUrlErrorKind {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("WebSocket Url Error: ")?;
fmt.write_str(self.description())?;
Ok(())
}
}
impl Error for WSUrlErrorKind {
fn description(&self) -> &str {
match *self {
WSUrlErrorKind::CannotSetFragment => "WebSocket URL cannot set fragment",
WSUrlErrorKind::InvalidScheme => "WebSocket URL invalid scheme",
WSUrlErrorKind::NoHostName => "WebSocket URL no host name provided",
}
}
}