Add specific URL error types

pull/168/head
WiredSound 4 years ago
parent 7265a8560c
commit 34c6e63d87
  1. 14
      src/client.rs
  2. 34
      src/error.rs
  3. 8
      src/handshake/client.rs

@ -52,7 +52,7 @@ mod encryption {
use std::net::TcpStream; use std::net::TcpStream;
use crate::{ use crate::{
error::{Error, Result}, error::{Error, UrlErrorType, Result},
stream::Mode, stream::Mode,
}; };
@ -62,7 +62,7 @@ mod encryption {
pub fn wrap_stream(stream: TcpStream, _domain: &str, mode: Mode) -> Result<AutoStream> { pub fn wrap_stream(stream: TcpStream, _domain: &str, mode: Mode) -> Result<AutoStream> {
match mode { match mode {
Mode::Plain => Ok(stream), Mode::Plain => Ok(stream),
Mode::Tls => Err(Error::Url("TLS support not compiled in.".into())), Mode::Tls => Err(Error::Url(UrlErrorType::TlsFeatureNotEnabled)),
} }
} }
} }
@ -71,7 +71,7 @@ use self::encryption::wrap_stream;
pub use self::encryption::AutoStream; pub use self::encryption::AutoStream;
use crate::{ use crate::{
error::{Error, Result}, error::{Error, UrlErrorType, Result},
handshake::{client::ClientHandshake, HandshakeError}, handshake::{client::ClientHandshake, HandshakeError},
protocol::WebSocket, protocol::WebSocket,
stream::{Mode, NoDelay}, stream::{Mode, NoDelay},
@ -104,7 +104,7 @@ pub fn connect_with_config<Req: IntoClientRequest>(
let uri = request.uri(); let uri = request.uri();
let mode = uri_mode(uri)?; let mode = uri_mode(uri)?;
let host = let host =
request.uri().host().ok_or_else(|| Error::Url("No host name in the URL".into()))?; request.uri().host().ok_or_else(|| Error::Url(UrlErrorType::NoHostName))?;
let port = uri.port_u16().unwrap_or(match mode { let port = uri.port_u16().unwrap_or(match mode {
Mode::Plain => 80, Mode::Plain => 80,
Mode::Tls => 443, Mode::Tls => 443,
@ -166,7 +166,7 @@ pub fn connect<Req: IntoClientRequest>(request: Req) -> Result<(WebSocket<AutoSt
} }
fn connect_to_some(addrs: &[SocketAddr], uri: &Uri, mode: Mode) -> Result<AutoStream> { fn connect_to_some(addrs: &[SocketAddr], uri: &Uri, mode: Mode) -> Result<AutoStream> {
let domain = uri.host().ok_or_else(|| Error::Url("No host name in the URL".into()))?; let domain = uri.host().ok_or_else(|| Error::Url(UrlErrorType::NoHostName))?;
for addr in addrs { for addr in addrs {
debug!("Trying to contact {} at {}...", uri, addr); debug!("Trying to contact {} at {}...", uri, addr);
if let Ok(raw_stream) = TcpStream::connect(addr) { if let Ok(raw_stream) = TcpStream::connect(addr) {
@ -175,7 +175,7 @@ fn connect_to_some(addrs: &[SocketAddr], uri: &Uri, mode: Mode) -> Result<AutoSt
} }
} }
} }
Err(Error::Url(format!("Unable to connect to {}", uri).into())) Err(Error::Url(UrlErrorType::UnableToConnect(uri.to_string())))
} }
/// Get the mode of the given URL. /// Get the mode of the given URL.
@ -186,7 +186,7 @@ pub fn uri_mode(uri: &Uri) -> Result<Mode> {
match uri.scheme_str() { match uri.scheme_str() {
Some("ws") => Ok(Mode::Plain), Some("ws") => Ok(Mode::Plain),
Some("wss") => Ok(Mode::Tls), Some("wss") => Ok(Mode::Tls),
_ => Err(Error::Url("URL scheme not supported".into())), _ => Err(Error::Url(UrlErrorType::UnsupportedUrlScheme)),
} }
} }

@ -14,7 +14,7 @@ pub mod tls {
/// Result type of all Tungstenite library calls. /// Result type of all Tungstenite library calls.
pub type Result<T> = result::Result<T, Error>; pub type Result<T> = result::Result<T, Error>;
/// Possible WebSocket errors /// Possible WebSocket errors.
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// WebSocket connection closed normally. This informs you of the close. /// WebSocket connection closed normally. This informs you of the close.
@ -54,7 +54,7 @@ pub enum Error {
/// UTF coding error /// UTF coding error
Utf8, Utf8,
/// Invalid URL. /// Invalid URL.
Url(Cow<'static, str>), Url(UrlErrorType),
/// HTTP error. /// HTTP error.
Http(Response<Option<String>>), Http(Response<Option<String>>),
/// HTTP format error. /// HTTP format error.
@ -151,3 +151,33 @@ impl From<httparse::Error> for Error {
} }
} }
} }
/// Indicates the specific type/cause of URL error.
#[derive(Debug)]
pub enum UrlErrorType {
/// TLS is used despite not being compiled with the TLS feature enabled.
TlsFeatureNotEnabled,
/// The URL does not include a host name.
NoHostName,
/// Failed to connect with this URL.
UnableToConnect(String),
/// Unsupported URL scheme used (only `ws://` or `wss://` may be used).
UnsupportedUrlScheme,
/// The URL host name, though included, is empty.
EmptyHostName,
/// The URL does not include a path/query.
NoPathOrQuery
}
impl fmt::Display for UrlErrorType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
UrlErrorType::TlsFeatureNotEnabled => write!(f, "TLS support not compiled in"),
UrlErrorType::NoHostName => write!(f, "No host name in the URL"),
UrlErrorType::UnableToConnect(uri) => write!(f, "Unable to connect to {}", uri),
UrlErrorType::UnsupportedUrlScheme => write!(f, "URL scheme not supported"),
UrlErrorType::EmptyHostName => write!(f, "URL contains empty host name"),
UrlErrorType::NoPathOrQuery => write!(f, "No path/query in URL")
}
}
}

@ -16,7 +16,7 @@ use super::{
HandshakeRole, MidHandshake, ProcessingResult, HandshakeRole, MidHandshake, ProcessingResult,
}; };
use crate::{ use crate::{
error::{Error, Result}, error::{Error, UrlErrorType, Result},
protocol::{Role, WebSocket, WebSocketConfig}, protocol::{Role, WebSocket, WebSocketConfig},
}; };
@ -98,7 +98,7 @@ fn generate_request(request: Request, key: &str) -> Result<Vec<u8>> {
let uri = request.uri(); let uri = request.uri();
let authority = let authority =
uri.authority().ok_or_else(|| Error::Url("No host name in the URL".into()))?.as_str(); uri.authority().ok_or_else(|| Error::Url(UrlErrorType::NoHostName))?.as_str();
let host = if let Some(idx) = authority.find('@') { let host = if let Some(idx) = authority.find('@') {
// handle possible name:password@ // handle possible name:password@
authority.split_at(idx + 1).1 authority.split_at(idx + 1).1
@ -106,7 +106,7 @@ fn generate_request(request: Request, key: &str) -> Result<Vec<u8>> {
authority authority
}; };
if authority.is_empty() { if authority.is_empty() {
return Err(Error::Url("URL contains empty host name".into())); return Err(Error::Url(UrlErrorType::EmptyHostName));
} }
write!( write!(
@ -121,7 +121,7 @@ fn generate_request(request: Request, key: &str) -> Result<Vec<u8>> {
version = request.version(), version = request.version(),
host = host, host = host,
path = path =
uri.path_and_query().ok_or_else(|| Error::Url("No path/query in URL".into()))?.as_str(), uri.path_and_query().ok_or_else(|| Error::Url(UrlErrorType::NoPathOrQuery))?.as_str(),
key = key key = key
) )
.unwrap(); .unwrap();

Loading…
Cancel
Save