use std::fmt;
use std::fmt::Write;
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
#[derive(Clone, Debug, PartialEq, Eq, EnumIter)]
pub enum Http3Error {
NoError,
GeneralProtocolError,
InternalError,
StreamCreationError,
ClosedCriticalStream,
FrameUnexpected,
FrameError,
ExcessiveLoad,
IdError,
SettingsError,
MissingSettings,
RequestRejected,
RequestCancelled,
RequestIncomplete,
MessageError,
ConnectError,
VersionFallback,
QpackDecompressionFailed,
QpackEncoderStreamError,
QpackDecoderStreamError,
TransportError(crate::Error),
StreamBlocked,
Done,
}
impl Http3Error {
pub fn to_wire(&self) -> u64 {
match self {
Http3Error::NoError => 0x100,
Http3Error::GeneralProtocolError => 0x101,
Http3Error::InternalError => 0x102,
Http3Error::StreamCreationError => 0x103,
Http3Error::ClosedCriticalStream => 0x104,
Http3Error::FrameUnexpected => 0x105,
Http3Error::FrameError => 0x106,
Http3Error::ExcessiveLoad => 0x107,
Http3Error::IdError => 0x108,
Http3Error::SettingsError => 0x109,
Http3Error::MissingSettings => 0x10A,
Http3Error::RequestRejected => 0x10B,
Http3Error::RequestCancelled => 0x10C,
Http3Error::RequestIncomplete => 0x10D,
Http3Error::MessageError => 0x10E,
Http3Error::ConnectError => 0x10F,
Http3Error::VersionFallback => 0x110,
Http3Error::QpackDecompressionFailed => 0x200,
Http3Error::QpackEncoderStreamError => 0x201,
Http3Error::QpackDecoderStreamError => 0x202,
Http3Error::TransportError { .. } => 0x102,
Http3Error::StreamBlocked => 0x102,
Http3Error::Done { .. } => 0x102,
}
}
pub(crate) fn to_errno(&self) -> libc::ssize_t {
match self {
Http3Error::NoError => 0,
Http3Error::Done => -1,
Http3Error::GeneralProtocolError => -2,
Http3Error::InternalError => -3,
Http3Error::StreamCreationError => -4,
Http3Error::ClosedCriticalStream => -5,
Http3Error::FrameUnexpected => -6,
Http3Error::FrameError => -7,
Http3Error::ExcessiveLoad => -8,
Http3Error::IdError => -9,
Http3Error::SettingsError => -10,
Http3Error::MissingSettings => -11,
Http3Error::StreamBlocked => -13,
Http3Error::RequestRejected => -14,
Http3Error::RequestCancelled => -15,
Http3Error::RequestIncomplete => -16,
Http3Error::MessageError => -17,
Http3Error::ConnectError => -18,
Http3Error::VersionFallback => -19,
Http3Error::QpackDecompressionFailed => -20,
Http3Error::QpackEncoderStreamError => -21,
Http3Error::QpackDecoderStreamError => -22,
Http3Error::TransportError(quic_error) => quic_error.to_errno() - 1000,
}
}
}
impl std::fmt::Display for Http3Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
impl std::error::Error for Http3Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
impl std::convert::From<crate::error::Error> for Http3Error {
fn from(err: crate::error::Error) -> Self {
match err {
crate::error::Error::Done => Http3Error::Done,
_ => Http3Error::TransportError(err),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn error_to_wire() {
let mut found_internal_err = false;
for err in Http3Error::iter() {
assert!(err.to_wire() > 0);
if let Http3Error::TransportError(_) = err {
found_internal_err = true;
}
if found_internal_err {
assert_eq!(err.to_wire(), 0x102);
}
}
}
#[test]
fn error_to_errno() {
for err in Http3Error::iter() {
if err == Http3Error::NoError {
assert_eq!(err.to_errno(), 0);
} else {
assert!(err.to_errno() < 0);
}
}
}
#[test]
fn internal_error() {
let e = Http3Error::InternalError;
assert_eq!(format!("{}", e), "InternalError");
use std::error::Error;
assert!(e.source().is_none());
}
}