1use crate::quic::ConnectionErrorIncoming;
3
4use super::{codes::Code, internal_error::InternalConnectionError};
5
6#[derive(Debug, Clone)]
12#[non_exhaustive]
13pub enum ConnectionError {
14 #[cfg_attr(
16 not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
17 non_exhaustive
18 )]
19 Local {
20 error: LocalError,
22 },
23 #[cfg_attr(
26 not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
27 non_exhaustive
28 )]
29 Remote(ConnectionErrorIncoming),
30 #[cfg_attr(
32 not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
33 non_exhaustive
34 )]
35 Timeout,
36}
37
38impl ConnectionError {
39 pub fn is_h3_no_error(&self) -> bool {
41 match self {
42 ConnectionError::Local {
43 error:
44 LocalError::Application {
45 code: Code::H3_NO_ERROR,
46 ..
47 },
48 } => true,
49 ConnectionError::Remote(ConnectionErrorIncoming::ApplicationClose { error_code })
50 if *error_code == Code::H3_NO_ERROR.value() =>
51 {
52 true
53 }
54 _ => false,
55 }
56 }
57}
58
59#[derive(Debug, Clone, Hash)]
61#[non_exhaustive]
62pub enum LocalError {
63 #[non_exhaustive]
64 Application {
66 code: Code,
68 reason: String,
70 },
71 #[non_exhaustive]
72 Closing,
74}
75
76#[derive(Debug)]
78#[non_exhaustive]
79pub enum StreamError {
80 #[cfg_attr(
82 not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
83 non_exhaustive
84 )]
85 StreamError {
86 code: Code,
88 reason: String,
90 },
91 #[cfg_attr(
95 not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
96 non_exhaustive
97 )]
98 RemoteTerminate {
99 code: Code,
101 },
102 #[cfg_attr(
104 not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
105 non_exhaustive
106 )]
107 ConnectionError(ConnectionError),
108 #[cfg_attr(
114 not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
115 non_exhaustive
116 )]
117 HeaderTooBig {
118 actual_size: u64,
120 max_size: u64,
122 },
123 #[cfg_attr(
127 not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
128 non_exhaustive
129 )]
130 RemoteClosing,
131 #[cfg_attr(
133 not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
134 non_exhaustive
135 )]
136 Undefined(Box<dyn std::error::Error + Send + Sync>),
137}
138
139impl StreamError {
140 pub fn is_h3_no_error(&self) -> bool {
142 match self {
143 StreamError::StreamError {
144 code: Code::H3_NO_ERROR,
145 ..
146 } => true,
147 StreamError::ConnectionError(conn_error) => conn_error.is_h3_no_error(),
148 _ => false,
149 }
150 }
151}
152
153impl From<InternalConnectionError> for LocalError {
154 fn from(err: InternalConnectionError) -> Self {
155 LocalError::Application {
156 code: err.code,
157 reason: err.message,
158 }
159 }
160}
161
162impl std::fmt::Display for ConnectionError {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 match self {
165 ConnectionError::Local { error } => write!(f, "Local error: {:?}", error),
166 ConnectionError::Remote(err) => write!(f, "Remote error: {}", err),
167 ConnectionError::Timeout => write!(f, "Timeout"),
168 }
169 }
170}
171
172impl std::error::Error for ConnectionError {}
173
174impl std::fmt::Display for StreamError {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self {
177 StreamError::StreamError { code, reason } => {
178 write!(f, "Stream error: {:?} - {}", code, reason)
179 }
180 StreamError::ConnectionError(err) => write!(f, "Connection error: {}", err),
181 StreamError::RemoteTerminate { code } => write!(f, "Remote reset: {}", code),
182 StreamError::HeaderTooBig {
183 actual_size,
184 max_size,
185 } => write!(
186 f,
187 "Header too big: actual size: {}, max size: {}",
188 actual_size, max_size
189 ),
190 StreamError::Undefined(err) => write!(f, "Undefined error: {}", err),
191 StreamError::RemoteClosing => write!(f, "Remote is closing the connection"),
192 }
193 }
194}
195
196impl std::error::Error for StreamError {}