diff --git a/h3-quinn/src/datagram.rs b/h3-quinn/src/datagram.rs index 807eb56e..7b993ce0 100644 --- a/h3-quinn/src/datagram.rs +++ b/h3-quinn/src/datagram.rs @@ -92,6 +92,9 @@ fn convert_h3_error_to_datagram_error( ConnectionErrorIncoming::ApplicationClose { error_code } => { h3_datagram::ConnectionErrorIncoming::ApplicationClose { error_code } } + ConnectionErrorIncoming::ConnectionClosed { error_code } => { + h3_datagram::ConnectionErrorIncoming::ConnectionClosed { error_code } + } ConnectionErrorIncoming::Timeout => h3_datagram::ConnectionErrorIncoming::Timeout, ConnectionErrorIncoming::InternalError(err) => { h3_datagram::ConnectionErrorIncoming::InternalError(err) diff --git a/h3-quinn/src/lib.rs b/h3-quinn/src/lib.rs index 4ac8a2af..7eaa264e 100644 --- a/h3-quinn/src/lib.rs +++ b/h3-quinn/src/lib.rs @@ -112,19 +112,44 @@ fn convert_connection_error(e: quinn::ConnectionError) -> h3::quic::ConnectionEr error_code: application_close.error_code.into(), } } + quinn::ConnectionError::ConnectionClosed(connection_close) => { + ConnectionErrorIncoming::ConnectionClosed { + error_code: connection_close.error_code.into(), + } + } quinn::ConnectionError::TimedOut => ConnectionErrorIncoming::Timeout, error @ quinn::ConnectionError::VersionMismatch | error @ quinn::ConnectionError::Reset | error @ quinn::ConnectionError::LocallyClosed | error @ quinn::ConnectionError::CidsExhausted - | error @ quinn::ConnectionError::TransportError(_) - | error @ quinn::ConnectionError::ConnectionClosed(_) => { + | error @ quinn::ConnectionError::TransportError(_) => { ConnectionErrorIncoming::Undefined(Arc::new(error)) } } } +#[cfg(test)] +mod tests { + use super::convert_connection_error; + use h3::quic::ConnectionErrorIncoming; + use quinn::{ConnectionClose, ConnectionError, TransportErrorCode}; + + #[test] + fn connection_closed_is_mapped_to_structured_variant() { + let error = ConnectionError::ConnectionClosed(ConnectionClose { + error_code: TransportErrorCode::NO_ERROR, + frame_type: None, + reason: Default::default(), + }); + + assert!(matches!( + convert_connection_error(error), + ConnectionErrorIncoming::ConnectionClosed { error_code: 0 } + )); + } +} + impl quic::OpenStreams for Connection where B: Buf, diff --git a/h3/src/error/error.rs b/h3/src/error/error.rs index 91313f9e..2ece1a78 100644 --- a/h3/src/error/error.rs +++ b/h3/src/error/error.rs @@ -1,5 +1,5 @@ //! This is the public facing error types for the h3 crate -use crate::quic::ConnectionErrorIncoming; +use crate::quic::{ConnectionErrorIncoming, QUIC_NO_ERROR}; use super::{codes::Code, internal_error::InternalConnectionError}; @@ -51,6 +51,11 @@ impl ConnectionError { { true } + ConnectionError::Remote(ConnectionErrorIncoming::ConnectionClosed { error_code }) + if *error_code == QUIC_NO_ERROR => + { + true + } _ => false, } } diff --git a/h3/src/quic.rs b/h3/src/quic.rs index 923b46f8..21653870 100644 --- a/h3/src/quic.rs +++ b/h3/src/quic.rs @@ -13,6 +13,9 @@ use crate::error::Code; pub use crate::proto::stream::{InvalidStreamId, StreamId}; pub use crate::stream::WriteBuf; +/// QUIC transport close code indicating graceful shutdown. +pub const QUIC_NO_ERROR: u64 = 0; + /// Error type to communicate that the quic connection was closed /// /// This is used by to implement the quic abstraction traits @@ -23,6 +26,11 @@ pub enum ConnectionErrorIncoming { /// http3 error code error_code: u64, }, + /// QUIC connection was closed by peer + ConnectionClosed { + /// QUIC transport error code + error_code: u64, + }, /// Quic connection timeout Timeout, /// This variant can be used to signal, that an internal error occurred within the trait implementations @@ -42,6 +50,9 @@ impl Debug for ConnectionErrorIncoming { let error_code = Code::from(*error_code); write!(f, "ApplicationClose({})", error_code) } + Self::ConnectionClosed { error_code } => { + write!(f, "ConnectionClosed({:#x})", error_code) + } Self::Timeout => write!(f, "Timeout"), Self::InternalError(arg0) => f.debug_tuple("InternalError").field(arg0).finish(), Self::Undefined(arg0) => f.debug_tuple("Undefined").field(arg0).finish(), @@ -100,6 +111,9 @@ impl Display for ConnectionErrorIncoming { let error_code = Code::from(*error_code); write!(f, "ApplicationClose: {}", error_code) } + ConnectionErrorIncoming::ConnectionClosed { error_code } => { + write!(f, "ConnectionClosed: {:#x}", error_code) + } ConnectionErrorIncoming::Timeout => write!(f, "Timeout"), ConnectionErrorIncoming::InternalError(error) => { write!(