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}