use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum ErrorCode {
NoError = 0x0,
ProtocolError = 0x1,
InternalError = 0x2,
FlowControlError = 0x3,
SettingsTimeout = 0x4,
StreamClosed = 0x5,
FrameSizeError = 0x6,
RefusedStream = 0x7,
Cancel = 0x8,
CompressionError = 0x9,
ConnectError = 0xa,
EnhanceYourCalm = 0xb,
InadequateSecurity = 0xc,
Http11Required = 0xd,
}
impl ErrorCode {
#[must_use]
pub fn from_u32(v: u32) -> Self {
match v {
0x0 => Self::NoError,
0x1 => Self::ProtocolError,
0x2 => Self::InternalError,
0x3 => Self::FlowControlError,
0x4 => Self::SettingsTimeout,
0x5 => Self::StreamClosed,
0x6 => Self::FrameSizeError,
0x7 => Self::RefusedStream,
0x8 => Self::Cancel,
0x9 => Self::CompressionError,
0xa => Self::ConnectError,
0xb => Self::EnhanceYourCalm,
0xc => Self::InadequateSecurity,
0xd => Self::Http11Required,
_ => Self::InternalError,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Http2Error {
ShortFrameHeader,
ShortPayload,
FrameTooLarge {
got: u32,
max: u32,
},
UnknownFrameType(u8),
BadPreface,
InvalidState,
StreamIdZero,
StreamIdNonZero,
FlowControlExceeded,
Protocol(ErrorCode),
}
impl fmt::Display for Http2Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::ShortFrameHeader => f.write_str("short frame header (< 9 bytes)"),
Self::ShortPayload => f.write_str("short frame payload"),
Self::FrameTooLarge { got, max } => write!(f, "frame too large: {got} > {max}"),
Self::UnknownFrameType(t) => write!(f, "unknown frame type 0x{t:x}"),
Self::BadPreface => f.write_str("bad connection preface"),
Self::InvalidState => f.write_str("invalid stream state for frame"),
Self::StreamIdZero => f.write_str("stream id 0 not allowed"),
Self::StreamIdNonZero => f.write_str("stream id must be 0"),
Self::FlowControlExceeded => f.write_str("flow control window exceeded"),
Self::Protocol(e) => write!(f, "protocol error: {e:?}"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for Http2Error {}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn from_u32_round_trip() {
for code in [
ErrorCode::NoError,
ErrorCode::ProtocolError,
ErrorCode::InternalError,
ErrorCode::FlowControlError,
ErrorCode::SettingsTimeout,
ErrorCode::StreamClosed,
ErrorCode::FrameSizeError,
ErrorCode::RefusedStream,
ErrorCode::Cancel,
ErrorCode::CompressionError,
ErrorCode::ConnectError,
ErrorCode::EnhanceYourCalm,
ErrorCode::InadequateSecurity,
ErrorCode::Http11Required,
] {
assert_eq!(ErrorCode::from_u32(code as u32), code);
}
}
#[test]
fn unknown_code_maps_to_internal_error() {
assert_eq!(ErrorCode::from_u32(0xffff), ErrorCode::InternalError);
}
#[test]
fn error_display_does_not_panic() {
let _ = alloc::format!("{}", Http2Error::ShortFrameHeader);
let _ = alloc::format!("{}", Http2Error::FrameTooLarge { got: 1, max: 0 });
}
}