wtransport_lightyear_patch/
error.rs1use crate::driver::utils::varint_q2w;
2use crate::driver::DriverError;
3use std::fmt::Display;
4use wtransport_proto::error::ErrorCode;
5use wtransport_proto::varint::VarInt;
6
7#[derive(thiserror::Error, Debug)]
9pub enum ConnectionError {
10 #[error("Connection aborted by peer: {0}")]
12 ConnectionClosed(ConnectionClose),
13
14 #[error("Connection closed by peer: {0}")]
16 ApplicationClosed(ApplicationClose),
17
18 #[error("Connection locally closed")]
20 LocallyClosed,
21
22 #[error("Connection locally aborted: {0}")]
24 LocalH3Error(H3Error),
25
26 #[error("Connection timed out")]
28 TimedOut,
29
30 #[error("QUIC protocol error: {0}")]
32 QuicProto(QuicProtoError),
33}
34
35impl ConnectionError {
36 pub(crate) fn with_driver_error(
37 driver_error: DriverError,
38 quic_connection: &quinn::Connection,
39 ) -> Self {
40 match driver_error {
41 DriverError::Proto(error_code) => Self::local_h3_error(error_code),
42 DriverError::NotConnected => Self::no_connect(quic_connection),
43 }
44 }
45
46 pub(crate) fn no_connect(quic_connection: &quinn::Connection) -> Self {
47 quic_connection
48 .close_reason()
49 .expect("QUIC connection is still alive on close-cast")
50 .into()
51 }
52
53 pub(crate) fn local_h3_error(error_code: ErrorCode) -> Self {
54 ConnectionError::LocalH3Error(H3Error { code: error_code })
55 }
56}
57
58#[derive(thiserror::Error, Debug)]
60pub enum ConnectingError {
61 #[error("Invalid URL: {0}")]
63 InvalidUrl(String),
64
65 #[error("Cannot resolve domain: {0}")]
67 DnsLookup(std::io::Error),
68
69 #[error("No domain found for dns resolution")]
71 DnsNotFound,
72
73 #[error(transparent)]
75 ConnectionError(ConnectionError),
76
77 #[error("Server rejected WebTransport session request")]
79 SessionRejected,
80
81 #[error("Additional header '{0}' is reserved")]
83 ReservedHeader(String),
84}
85
86impl ConnectingError {
87 pub(crate) fn with_no_connection(quic_connection: &quinn::Connection) -> Self {
88 ConnectingError::ConnectionError(
89 quic_connection
90 .close_reason()
91 .expect("QUIC connection is still alive on close-cast")
92 .into(),
93 )
94 }
95}
96
97#[derive(thiserror::Error, Debug)]
99pub enum StreamWriteError {
100 #[error("Not connected")]
102 NotConnected,
103
104 #[error("Stream stopped (code: {0})")]
106 Stopped(VarInt),
107
108 #[error("QUIC protocol error")]
110 QuicProto,
111}
112
113#[derive(thiserror::Error, Debug)]
115pub enum StreamReadError {
116 #[error("Not connected")]
118 NotConnected,
119
120 #[error("Stream reset (code: {0})")]
122 Reset(VarInt),
123
124 #[error("QUIC protocol error")]
126 QuicProto,
127}
128
129#[derive(thiserror::Error, Debug)]
131pub enum StreamReadExactError {
132 #[error("Stream finished too early")]
134 FinishedEarly,
135
136 #[error(transparent)]
138 Read(StreamReadError),
139}
140
141#[derive(thiserror::Error, Debug)]
143pub enum SendDatagramError {
144 #[error("Not connected")]
146 NotConnected,
147
148 #[error("Peer does not support datagrams")]
150 UnsupportedByPeer,
151
152 #[error("Datagram payload too large")]
154 TooLarge,
155}
156
157#[derive(thiserror::Error, Debug)]
159pub enum StreamOpeningError {
160 #[error("Not connected")]
162 NotConnected,
163
164 #[error("Opening stream refused")]
166 Refused,
167}
168
169#[derive(Debug)]
171pub struct ApplicationClose {
172 code: VarInt,
173 reason: Box<[u8]>,
174}
175
176impl Display for ApplicationClose {
177 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178 if self.reason.is_empty() {
179 self.code.fmt(f)?;
180 } else {
181 f.write_str(&String::from_utf8_lossy(&self.reason))?;
182 f.write_str(" (code ")?;
183 self.code.fmt(f)?;
184 f.write_str(")")?;
185 }
186 Ok(())
187 }
188}
189
190#[derive(Debug)]
192pub struct ConnectionClose(quinn::ConnectionClose);
193
194impl Display for ConnectionClose {
195 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
196 self.0.fmt(f)
197 }
198}
199
200#[derive(Debug)]
202pub struct H3Error {
203 code: ErrorCode,
204}
205
206impl Display for H3Error {
207 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208 self.code.fmt(f)
209 }
210}
211
212impl From<quinn::ConnectionError> for ConnectionError {
213 fn from(error: quinn::ConnectionError) -> Self {
214 match error {
215 quinn::ConnectionError::VersionMismatch => ConnectionError::QuicProto(QuicProtoError {
216 code: None,
217 reason: "QUIC protocol version mismatched".to_string(),
218 }),
219 quinn::ConnectionError::TransportError(e) => {
220 ConnectionError::QuicProto(QuicProtoError {
221 code: VarInt::try_from_u64(e.code.into()).ok(),
222 reason: e.reason,
223 })
224 }
225 quinn::ConnectionError::ConnectionClosed(close) => {
226 ConnectionError::ConnectionClosed(ConnectionClose(close))
227 }
228 quinn::ConnectionError::ApplicationClosed(close) => {
229 ConnectionError::ApplicationClosed(ApplicationClose {
230 code: varint_q2w(close.error_code),
231 reason: close.reason.to_vec().into_boxed_slice(),
232 })
233 }
234 quinn::ConnectionError::Reset => ConnectionError::QuicProto(QuicProtoError {
235 code: None,
236 reason: "Connection has been reset".to_string(),
237 }),
238 quinn::ConnectionError::TimedOut => ConnectionError::TimedOut,
239 quinn::ConnectionError::LocallyClosed => ConnectionError::LocallyClosed,
240 }
241 }
242}
243
244#[derive(Debug)]
246pub struct QuicProtoError {
247 code: Option<VarInt>,
248 reason: String,
249}
250
251impl Display for QuicProtoError {
252 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
253 let code = self
254 .code
255 .map(|code| format!(" (code: {})", code))
256 .unwrap_or_default();
257
258 f.write_fmt(format_args!("{}{}", self.reason, code))
259 }
260}