use crate::quic::ConnectionErrorIncoming;
use super::{codes::Code, internal_error::InternalConnectionError};
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum ConnectionError {
#[cfg_attr(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
non_exhaustive
)]
Local {
error: LocalError,
},
#[cfg_attr(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
non_exhaustive
)]
Remote(ConnectionErrorIncoming),
#[cfg_attr(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
non_exhaustive
)]
Timeout,
}
impl ConnectionError {
pub fn is_h3_no_error(&self) -> bool {
match self {
ConnectionError::Local {
error:
LocalError::Application {
code: Code::H3_NO_ERROR,
..
},
} => true,
ConnectionError::Remote(ConnectionErrorIncoming::ApplicationClose { error_code })
if *error_code == Code::H3_NO_ERROR.value() =>
{
true
}
_ => false,
}
}
}
#[derive(Debug, Clone, Hash)]
#[non_exhaustive]
pub enum LocalError {
#[non_exhaustive]
Application {
code: Code,
reason: String,
},
#[non_exhaustive]
Closing,
}
#[derive(Debug)]
#[non_exhaustive]
pub enum StreamError {
#[cfg_attr(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
non_exhaustive
)]
StreamError {
code: Code,
reason: String,
},
#[cfg_attr(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
non_exhaustive
)]
RemoteTerminate {
code: Code,
},
#[cfg_attr(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
non_exhaustive
)]
ConnectionError(ConnectionError),
#[cfg_attr(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
non_exhaustive
)]
HeaderTooBig {
actual_size: u64,
max_size: u64,
},
#[cfg_attr(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
non_exhaustive
)]
RemoteClosing,
#[cfg_attr(
not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
non_exhaustive
)]
Undefined(Box<dyn std::error::Error + Send + Sync>),
}
impl StreamError {
pub fn is_h3_no_error(&self) -> bool {
match self {
StreamError::StreamError {
code: Code::H3_NO_ERROR,
..
} => true,
StreamError::ConnectionError(conn_error) => conn_error.is_h3_no_error(),
_ => false,
}
}
}
impl From<InternalConnectionError> for LocalError {
fn from(err: InternalConnectionError) -> Self {
LocalError::Application {
code: err.code,
reason: err.message,
}
}
}
impl std::fmt::Display for ConnectionError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ConnectionError::Local { error } => write!(f, "Local error: {:?}", error),
ConnectionError::Remote(err) => write!(f, "Remote error: {}", err),
ConnectionError::Timeout => write!(f, "Timeout"),
}
}
}
impl std::error::Error for ConnectionError {}
impl std::fmt::Display for StreamError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
StreamError::StreamError { code, reason } => {
write!(f, "Stream error: {:?} - {}", code, reason)
}
StreamError::ConnectionError(err) => write!(f, "Connection error: {}", err),
StreamError::RemoteTerminate { code } => write!(f, "Remote reset: {}", code),
StreamError::HeaderTooBig {
actual_size,
max_size,
} => write!(
f,
"Header too big: actual size: {}, max size: {}",
actual_size, max_size
),
StreamError::Undefined(err) => write!(f, "Undefined error: {}", err),
StreamError::RemoteClosing => write!(f, "Remote is closing the connection"),
}
}
}
impl std::error::Error for StreamError {}