1use crate::coding;
2
3#[derive(thiserror::Error, Debug, Clone)]
5#[non_exhaustive]
6pub enum Error {
7 #[error("transport error")]
8 Transport,
9
10 #[error("decode error")]
11 Decode,
12
13 #[error("unsupported versions")]
15 Version,
16
17 #[error("extension required")]
19 RequiredExtension,
20
21 #[error("unexpected stream type")]
23 UnexpectedStream,
24
25 #[error("varint bounds exceeded")]
27 BoundsExceeded,
28
29 #[error("duplicate")]
32 Duplicate,
33
34 #[error("cancelled")]
36 Cancel,
37
38 #[error("timeout")]
40 Timeout,
41
42 #[error("old")]
44 Old,
45
46 #[error("app code={0}")]
48 App(u16),
49
50 #[error("not found")]
51 NotFound,
52
53 #[error("wrong frame size")]
54 WrongSize,
55
56 #[error("protocol violation")]
57 ProtocolViolation,
58
59 #[error("unauthorized")]
60 Unauthorized,
61
62 #[error("unexpected message")]
63 UnexpectedMessage,
64
65 #[error("unsupported")]
66 Unsupported,
67
68 #[error("too large")]
69 TooLarge,
70
71 #[error("too many parameters")]
72 TooManyParameters,
73
74 #[error("invalid role")]
75 InvalidRole,
76
77 #[error("unknown ALPN: {0}")]
78 UnknownAlpn(String),
79}
80
81impl Error {
82 pub fn to_code(&self) -> u32 {
84 match self {
85 Self::Cancel => 0,
86 Self::RequiredExtension => 1,
87 Self::Old => 2,
88 Self::Timeout => 3,
89 Self::Transport => 4,
90 Self::Decode => 5,
91 Self::Unauthorized => 6,
92 Self::Version => 9,
93 Self::UnexpectedStream => 10,
94 Self::BoundsExceeded => 11,
95 Self::Duplicate => 12,
96 Self::NotFound => 13,
97 Self::WrongSize => 14,
98 Self::ProtocolViolation => 15,
99 Self::UnexpectedMessage => 16,
100 Self::Unsupported => 17,
101 Self::TooLarge => 18,
102 Self::TooManyParameters => 19,
103 Self::InvalidRole => 20,
104 Self::UnknownAlpn(_) => 21,
105 Self::App(app) => *app as u32 + 64,
106 }
107 }
108
109 pub fn from_code(code: u32) -> Self {
111 match code {
112 0 => Self::Cancel,
113 1 => Self::RequiredExtension,
114 2 => Self::Old,
115 3 => Self::Timeout,
116 4 => Self::Transport,
117 5 => Self::Decode,
118 6 => Self::Unauthorized,
119 9 => Self::Version,
120 10 => Self::UnexpectedStream,
121 11 => Self::BoundsExceeded,
122 12 => Self::Duplicate,
123 13 => Self::NotFound,
124 14 => Self::WrongSize,
125 15 => Self::ProtocolViolation,
126 16 => Self::UnexpectedMessage,
127 17 => Self::Unsupported,
128 18 => Self::TooLarge,
129 19 => Self::TooManyParameters,
130 20 => Self::InvalidRole,
131 code if code >= 64 => match u16::try_from(code - 64) {
132 Ok(app) => Self::App(app),
133 Err(_) => Self::ProtocolViolation,
134 },
135 _ => Self::ProtocolViolation,
136 }
137 }
138
139 pub fn from_transport(err: impl web_transport_trait::Error) -> Self {
141 if let Some(code) = err.stream_error() {
142 return Self::from_code(code);
143 }
144
145 tracing::warn!(%err, "transport error");
146 Self::Transport
147 }
148}
149
150impl From<coding::DecodeError> for Error {
151 fn from(err: coding::DecodeError) -> Self {
152 tracing::warn!(%err, "decode error");
153 Error::Decode
154 }
155}
156
157impl From<coding::BoundsExceeded> for Error {
158 fn from(err: coding::BoundsExceeded) -> Self {
159 tracing::warn!(%err, "bounds exceeded");
160 Error::BoundsExceeded
161 }
162}
163
164pub type Result<T> = std::result::Result<T, Error>;