Skip to main content

leyline/h2/
error.rs

1use crate::core::session::decompress::BodyLimit;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4#[repr(u32)]
5#[non_exhaustive]
6pub enum ErrorCode {
7    NoError = 0x0,
8    ProtocolError = 0x1,
9    InternalError = 0x2,
10    FlowControlError = 0x3,
11    SettingsTimeout = 0x4,
12    StreamClosed = 0x5,
13    FrameSizeError = 0x6,
14    RefusedStream = 0x7,
15    Cancel = 0x8,
16    CompressionError = 0x9,
17    ConnectError = 0xa,
18    EnhanceYourCalm = 0xb,
19    InadequateSecurity = 0xc,
20    Http11Required = 0xd,
21}
22
23impl ErrorCode {
24    pub fn from_u32(val: u32) -> Self {
25        match val {
26            0x0 => Self::NoError,
27            0x1 => Self::ProtocolError,
28            0x2 => Self::InternalError,
29            0x3 => Self::FlowControlError,
30            0x4 => Self::SettingsTimeout,
31            0x5 => Self::StreamClosed,
32            0x6 => Self::FrameSizeError,
33            0x7 => Self::RefusedStream,
34            0x8 => Self::Cancel,
35            0x9 => Self::CompressionError,
36            0xa => Self::ConnectError,
37            0xb => Self::EnhanceYourCalm,
38            0xc => Self::InadequateSecurity,
39            0xd => Self::Http11Required,
40            _ => Self::InternalError,
41        }
42    }
43}
44
45#[derive(Debug, thiserror::Error)]
46#[non_exhaustive]
47pub enum H2Error {
48    #[error("connection error: {code:?} - {reason}")]
49    Connection { code: ErrorCode, reason: String },
50
51    #[error("stream {stream_id} error: {code:?}")]
52    Stream { stream_id: u32, code: ErrorCode },
53
54    #[error("io: {0}")]
55    Io(#[from] std::io::Error),
56
57    #[error("hpack: {0}")]
58    Hpack(String),
59
60    #[error("frame size {size} exceeds max {max}")]
61    FrameTooLarge { size: u32, max: u32 },
62
63    #[error("request body stream failed")]
64    RequestBody(#[source] std::io::Error),
65}
66
67fn copy_io(io: &std::io::Error) -> std::io::Error {
68    std::io::Error::new(io.kind(), io.to_string())
69}
70
71impl H2Error {
72    pub(crate) fn duplicate(&self) -> Self {
73        match self {
74            Self::Connection { code, reason } => Self::Connection {
75                code: *code,
76                reason: reason.clone(),
77            },
78            Self::Stream { stream_id, code } => Self::Stream {
79                stream_id: *stream_id,
80                code: *code,
81            },
82            Self::Io(io) => Self::Io(copy_io(io)),
83            Self::Hpack(message) => Self::Hpack(message.clone()),
84            Self::FrameTooLarge { size, max } => Self::FrameTooLarge {
85                size: *size,
86                max: *max,
87            },
88            Self::RequestBody(io) => Self::RequestBody(copy_io(io)),
89        }
90    }
91
92    pub(crate) fn connection_failed(&self) -> bool {
93        self.body_limit().is_none() && !matches!(self, Self::RequestBody(_))
94    }
95
96    pub(crate) fn body_limit(&self) -> Option<BodyLimit> {
97        match self {
98            Self::Io(io) => BodyLimit::of_io(io),
99            _ => None,
100        }
101    }
102}