#![cfg_attr(docsrs, feature(doc_cfg))]
#[doc(hidden)]
#[cfg(target_arch = "wasm32")]
mod wasm;
#[doc(hidden)]
#[cfg(not(target_arch = "wasm32"))]
mod native;
#[cfg(not(target_arch = "wasm32"))]
mod compression;
pub mod close;
#[cfg(not(target_arch = "wasm32"))]
pub mod codec;
pub mod frame;
#[doc(hidden)]
pub mod mask;
#[cfg(not(target_arch = "wasm32"))]
mod stream;
use thiserror::Error;
#[cfg(target_arch = "wasm32")]
pub use wasm::*;
#[cfg(not(target_arch = "wasm32"))]
pub use native::*;
pub type Result<T> = std::result::Result<T, WebSocketError>;
#[derive(Error, Debug)]
pub enum WebSocketError {
#[error("Invalid fragment")]
#[cfg(not(target_arch = "wasm32"))]
InvalidFragment,
#[error("Fragmented message timed out")]
#[cfg(not(target_arch = "wasm32"))]
FragmentTimeout,
#[error("Invalid UTF-8")]
InvalidUTF8,
#[error("Invalid continuation frame")]
#[cfg(not(target_arch = "wasm32"))]
InvalidContinuationFrame,
#[error("Invalid status code: {0}")]
#[cfg(not(target_arch = "wasm32"))]
InvalidStatusCode(u16),
#[error("Redirected with status code {status_code} to {location}")]
#[cfg(not(target_arch = "wasm32"))]
Redirected {
status_code: u16,
location: String,
},
#[error("Invalid upgrade header")]
#[cfg(not(target_arch = "wasm32"))]
InvalidUpgradeHeader,
#[error("Invalid connection header")]
#[cfg(not(target_arch = "wasm32"))]
InvalidConnectionHeader,
#[error("Connection is closed")]
ConnectionClosed,
#[error("Invalid close frame")]
#[cfg(not(target_arch = "wasm32"))]
InvalidCloseFrame,
#[error("Invalid close code")]
#[cfg(not(target_arch = "wasm32"))]
InvalidCloseCode,
#[error("Reserved bits are not zero")]
#[cfg(not(target_arch = "wasm32"))]
ReservedBitsNotZero,
#[error("Control frame must not be fragmented")]
#[cfg(not(target_arch = "wasm32"))]
ControlFrameFragmented,
#[error("Ping frame too large")]
#[cfg(not(target_arch = "wasm32"))]
PingFrameTooLarge,
#[error("Frame too large")]
#[cfg(not(target_arch = "wasm32"))]
FrameTooLarge,
#[error("Sec-Websocket-Version must be 13")]
#[cfg(not(target_arch = "wasm32"))]
InvalidSecWebsocketVersion,
#[error("Invalid opcode (byte={0})")]
InvalidOpCode(u8),
#[error("Sec-WebSocket-Key header is missing")]
#[cfg(not(target_arch = "wasm32"))]
MissingSecWebSocketKey,
#[error("Invalid http scheme")]
InvalidHttpScheme,
#[error("Received compressed frame on stream that doesn't support compression")]
#[cfg(not(target_arch = "wasm32"))]
CompressionNotSupported,
#[error(transparent)]
UrlParseError(#[from] url::ParseError),
#[cfg(not(target_arch = "wasm32"))]
#[error(transparent)]
IoError(#[from] std::io::Error),
#[cfg(not(target_arch = "wasm32"))]
#[error(transparent)]
HTTPError(#[from] hyper::Error),
#[cfg(target_arch = "wasm32")]
#[error("js value: {0:?}")]
Js(wasm_bindgen::JsValue),
#[error(transparent)]
#[cfg_attr(docsrs, doc(cfg(feature = "reqwest")))]
#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))]
Reqwest(#[from] reqwest::Error),
}
impl WebSocketError {
#[cfg(not(target_arch = "wasm32"))]
pub fn is_protocol_error(&self) -> bool {
matches!(
self,
Self::InvalidFragment
| Self::FragmentTimeout
| Self::InvalidContinuationFrame
| Self::InvalidCloseFrame
| Self::InvalidCloseCode
| Self::ReservedBitsNotZero
| Self::ControlFrameFragmented
| Self::PingFrameTooLarge
| Self::InvalidOpCode(_)
| Self::CompressionNotSupported
)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn is_handshake_error(&self) -> bool {
matches!(
self,
Self::InvalidStatusCode(_)
| Self::Redirected { .. }
| Self::InvalidUpgradeHeader
| Self::InvalidConnectionHeader
| Self::InvalidSecWebsocketVersion
| Self::MissingSecWebSocketKey
| Self::InvalidHttpScheme
)
}
pub fn is_closed(&self) -> bool {
matches!(self, Self::ConnectionClosed)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn is_data_error(&self) -> bool {
matches!(self, Self::InvalidUTF8 | Self::FrameTooLarge)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn is_io_error(&self) -> bool {
matches!(self, Self::IoError(_))
}
#[cfg(not(target_arch = "wasm32"))]
pub fn as_io_error(&self) -> Option<&std::io::Error> {
match self {
Self::IoError(e) => Some(e),
_ => None,
}
}
}