qbase/frame/
error.rs

1use nom::error::ErrorKind as NomErrorKind;
2use thiserror::Error;
3
4use super::FrameType;
5use crate::{
6    error::{ErrorKind as TransportErrorKind, QuicError as TransportError},
7    packet::r#type::Type,
8    varint::VarInt,
9};
10
11/// Parse errors when decoding QUIC frames.
12#[derive(Debug, Clone, Eq, PartialEq, Error)]
13pub enum Error {
14    #[error("A packet containing no frames")]
15    NoFrames,
16    #[error("Incomplete frame type: {0}")]
17    IncompleteType(String),
18    #[error("Invalid frame type from {0}")]
19    InvalidType(VarInt),
20    #[error("Wrong frame type {0:?}")]
21    WrongType(FrameType, Type),
22    #[error("Incomplete frame {0:?}: {1}")]
23    IncompleteFrame(FrameType, String),
24    #[error("Error occurred when parsing frame {0:?}: {1}")]
25    ParseError(FrameType, String),
26}
27
28impl From<Error> for TransportError {
29    fn from(e: Error) -> Self {
30        tracing::error!("   Cause by: parse frame error {e}");
31        match e {
32            // An endpoint MUST treat receipt of a packet containing no frames as a connection error of type PROTOCOL_VIOLATION.
33            Error::NoFrames => {
34                Self::with_default_fty(TransportErrorKind::ProtocolViolation, e.to_string())
35            }
36            Error::IncompleteType(_) => {
37                Self::with_default_fty(TransportErrorKind::FrameEncoding, e.to_string())
38            }
39            Error::InvalidType(_) => {
40                Self::with_default_fty(TransportErrorKind::FrameEncoding, e.to_string())
41            }
42            Error::WrongType(fty, _) => {
43                Self::new(TransportErrorKind::FrameEncoding, fty.into(), e.to_string())
44            }
45            Error::IncompleteFrame(fty, _) => {
46                Self::new(TransportErrorKind::FrameEncoding, fty.into(), e.to_string())
47            }
48            Error::ParseError(fty, _) => {
49                Self::new(TransportErrorKind::FrameEncoding, fty.into(), e.to_string())
50            }
51        }
52    }
53}
54
55impl From<nom::Err<Error>> for Error {
56    fn from(error: nom::Err<Error>) -> Self {
57        tracing::error!("   Cause by: nom error {error}");
58        match error {
59            nom::Err::Incomplete(_needed) => {
60                unreachable!("Because the parsing of QUIC packets and frames is not stream-based.")
61            }
62            nom::Err::Error(err) | nom::Err::Failure(err) => err,
63        }
64    }
65}
66
67impl nom::error::ParseError<&[u8]> for Error {
68    fn from_error_kind(_input: &[u8], _kind: NomErrorKind) -> Self {
69        debug_assert_eq!(_kind, NomErrorKind::ManyTill);
70        unreachable!("QUIC frame parser must always consume")
71    }
72
73    fn append(_input: &[u8], _kind: NomErrorKind, source: Self) -> Self {
74        // 在解析帧时遇到了source错误,many_till期望通过ManyTill的错误类型告知
75        // 这里,源错误更有意义,所以直接返回源错误
76        debug_assert_eq!(_kind, NomErrorKind::ManyTill);
77        source
78    }
79}
80
81// TODO: conver DecodingError to quic error
82
83#[cfg(test)]
84mod tests {
85    use nom::error::ParseError;
86
87    use super::*;
88    use crate::packet::r#type::{
89        Type,
90        long::{Type::V1, Ver1},
91    };
92
93    #[test]
94    fn test_error_conversion_to_transport_error() {
95        let cases = vec![
96            (Error::NoFrames, TransportErrorKind::ProtocolViolation),
97            (
98                Error::IncompleteType("test".to_string()),
99                TransportErrorKind::FrameEncoding,
100            ),
101            (
102                Error::InvalidType(VarInt::from_u32(0x1f)),
103                TransportErrorKind::FrameEncoding,
104            ),
105            (
106                Error::WrongType(FrameType::Ping, Type::Long(V1(Ver1::INITIAL))),
107                TransportErrorKind::FrameEncoding,
108            ),
109            (
110                Error::IncompleteFrame(FrameType::Ping, "incomplete".to_string()),
111                TransportErrorKind::FrameEncoding,
112            ),
113            (
114                Error::ParseError(FrameType::Ping, "parse error".to_string()),
115                TransportErrorKind::FrameEncoding,
116            ),
117        ];
118
119        for (error, expected_kind) in cases {
120            let transport_error: TransportError = error.into();
121            assert_eq!(transport_error.kind(), expected_kind);
122        }
123    }
124
125    #[test]
126    fn test_nom_error_conversion() {
127        let error = Error::NoFrames;
128        let nom_error = nom::Err::Error(error.clone());
129        let converted: Error = nom_error.into();
130        assert_eq!(converted, error);
131
132        let nom_failure = nom::Err::Failure(error.clone());
133        let converted: Error = nom_failure.into();
134        assert_eq!(converted, error);
135    }
136
137    #[test]
138    fn test_parse_error_impl() {
139        let error = Error::ParseError(FrameType::Ping, "test error".to_string());
140        let appended = Error::append(&[], NomErrorKind::ManyTill, error.clone());
141        assert_eq!(appended, error);
142    }
143
144    #[test]
145    #[should_panic(expected = "QUIC frame parser must always consume")]
146    fn test_parse_error_unreachable() {
147        Error::from_error_kind(&[], NomErrorKind::ManyTill);
148    }
149
150    #[test]
151    fn test_error_display() {
152        let error = Error::NoFrames;
153        assert_eq!(error.to_string(), "A packet containing no frames");
154
155        let error = Error::IncompleteType("test".to_string());
156        assert_eq!(error.to_string(), "Incomplete frame type: test");
157
158        let error = Error::InvalidType(VarInt::from_u32(0x1f));
159        assert_eq!(error.to_string(), "Invalid frame type from 31");
160    }
161}