• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 //! [`Error Codes`] in [`HTTP/2`].
15 //!
16 //! [`Error Codes`]: https://httpwg.org/specs/rfc9113.html#ErrorCodes
17 //! [`HTTP/2`]: https://httpwg.org/specs/rfc9113.html
18 //!
19 //! # introduction
20 //! Error codes are 32-bit fields that are used in `RST_STREAM` and `GOAWAY`
21 //! frames to convey the reasons for the stream or connection error.
22 //!
23 //! Error codes share a common code space. Some error codes apply only to either
24 //! streams or the entire connection and have no defined semantics in the other
25 //! context.
26 
27 use std::convert::{Infallible, TryFrom};
28 
29 use super::frame::StreamId;
30 use crate::error::{ErrorKind, HttpError};
31 
32 /// The http2 error handle implementation
33 #[derive(Debug, Eq, PartialEq, Copy, Clone)]
34 pub enum H2Error {
35     /// [`Stream Error`] Handling.
36     ///
37     /// [`Stream Error`]: https://www.rfc-editor.org/rfc/rfc9113.html#name-stream-error-handling
38     StreamError(StreamId, ErrorCode),
39 
40     /// [`Connection Error`] Handling.
41     ///
42     /// [`Connection Error`]: https://www.rfc-editor.org/rfc/rfc9113.html#name-connection-error-handling
43     ConnectionError(ErrorCode),
44 }
45 
46 /// [`Error Codes`] implementation.
47 ///
48 /// [`Error Codes`]: https://httpwg.org/specs/rfc9113.html#ErrorCodes
49 #[derive(Debug, Eq, PartialEq, Copy, Clone)]
50 pub enum ErrorCode {
51     /// The associated condition is not a result of an error. For example,
52     /// a `GOAWAY` might include this code to indicate graceful shutdown of a
53     /// connection.
54     NoError = 0x00,
55 
56     /// The endpoint detected an unspecific protocol error. This error is for
57     /// use when a more specific error code is not available.
58     ProtocolError = 0x01,
59 
60     /// The endpoint encountered an unexpected internal error.
61     IntervalError = 0x02,
62 
63     /// The endpoint detected that its peer violated the flow-control protocol.
64     FlowControlError = 0x03,
65 
66     /// The endpoint sent a `SETTINGS` frame but did not receive a response in
67     /// a timely manner.
68     SettingsTimeout = 0x04,
69 
70     /// The endpoint received a frame after a stream was half-closed.
71     StreamClosed = 0x05,
72 
73     /// The endpoint received a frame with an invalid size.
74     FrameSizeError = 0x06,
75 
76     /// The endpoint refused the stream prior to performing any application
77     /// processing.
78     RefusedStream = 0x07,
79 
80     /// The endpoint uses this error code to indicate that the stream is no
81     /// longer needed.
82     Cancel = 0x08,
83 
84     /// The endpoint is unable to maintain the field section compression context
85     /// for the connection.
86     CompressionError = 0x09,
87 
88     /// The connection established in response to a `CONNECT` request was reset
89     /// or abnormally closed.
90     ConnectError = 0x0a,
91 
92     /// The endpoint detected that its peer is exhibiting a behavior that might
93     /// be generating excessive load.
94     EnhanceYourCalm = 0x0b,
95 
96     /// The underlying transport has properties that do not meet minimum
97     /// security requirements.
98     InadequateSecurity = 0x0c,
99 
100     /// The endpoint requires that HTTP/1.1 be used instead of HTTP/2.
101     Http1_1Required = 0x0d,
102 }
103 
104 impl ErrorCode {
105     /// Gets the error code of the `ErrorCode` enum.
into_code(self) -> u32106     pub fn into_code(self) -> u32 {
107         self as u32
108     }
109 }
110 
111 impl TryFrom<u32> for ErrorCode {
112     type Error = H2Error;
try_from(value: u32) -> Result<Self, Self::Error>113     fn try_from(value: u32) -> Result<Self, Self::Error> {
114         let err = match value {
115             0x00 => ErrorCode::NoError,
116             0x01 => ErrorCode::ProtocolError,
117             0x02 => ErrorCode::IntervalError,
118             0x03 => ErrorCode::FlowControlError,
119             0x04 => ErrorCode::SettingsTimeout,
120             0x05 => ErrorCode::StreamClosed,
121             0x06 => ErrorCode::FrameSizeError,
122             0x07 => ErrorCode::RefusedStream,
123             0x08 => ErrorCode::Cancel,
124             0x09 => ErrorCode::CompressionError,
125             0x0a => ErrorCode::ConnectError,
126             0x0b => ErrorCode::EnhanceYourCalm,
127             0x0c => ErrorCode::InadequateSecurity,
128             0x0d => ErrorCode::Http1_1Required,
129             _ => return Err(H2Error::ConnectionError(ErrorCode::ProtocolError)),
130         };
131         Ok(err)
132     }
133 }
134 
135 #[cfg(test)]
136 mod ut_h2_error {
137     use std::convert::TryInto;
138 
139     use super::*;
140 
141     /// Unit test cases for `ErrorCode::try_from`.
142     ///
143     /// # Brief
144     /// 1. Iterates over a range of valid u32 values that represent
145     ///    `ErrorCode`s.
146     /// 2. Attempts to convert each u32 value into an `ErrorCode` using
147     ///    `try_into`.
148     /// 3. Checks that the conversion is successful for each valid `ErrorCode`.
149     /// 4. Also attempts to convert an invalid u32 value into an `ErrorCode`.
150     /// 5. Checks that the conversion fails for the invalid value.
151     #[test]
ut_test_error_code_try_from()152     fn ut_test_error_code_try_from() {
153         // Test conversion from u32 to ErrorCode for valid error codes
154         for i in 0x00..=0x0d {
155             let error_code: Result<ErrorCode, _> = i.try_into();
156             assert!(error_code.is_ok());
157         }
158 
159         // Test conversion from u32 to ErrorCode for invalid error codes
160         let invalid_error_code: Result<ErrorCode, _> = 0x0e.try_into();
161         assert!(invalid_error_code.is_err());
162     }
163 }
164