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 crate::error::{ErrorKind, HttpError}; 30 31 /// The http2 error handle implementation 32 #[derive(Debug, Eq, PartialEq, Copy, Clone)] 33 pub enum H2Error { 34 /// [`Stream Error`] Handling. 35 /// 36 /// [`Stream Error`]: https://www.rfc-editor.org/rfc/rfc9113.html#name-stream-error-handling 37 StreamError(u32, ErrorCode), 38 39 /// [`Connection Error`] Handling. 40 /// 41 /// [`Connection Error`]: https://www.rfc-editor.org/rfc/rfc9113.html#name-connection-error-handling 42 ConnectionError(ErrorCode), 43 } 44 45 /// [`Error Codes`] implementation. 46 /// 47 /// [`Error Codes`]: https://httpwg.org/specs/rfc9113.html#ErrorCodes 48 #[derive(Debug, Eq, PartialEq, Copy, Clone)] 49 pub enum ErrorCode { 50 /// The associated condition is not a result of an error. For example, 51 /// a `GOAWAY` might include this code to indicate graceful shutdown of a 52 /// connection. 53 NoError = 0x00, 54 55 /// The endpoint detected an unspecific protocol error. This error is for 56 /// use when a more specific error code is not available. 57 ProtocolError = 0x01, 58 59 /// The endpoint encountered an unexpected internal error. 60 IntervalError = 0x02, 61 62 /// The endpoint detected that its peer violated the flow-control protocol. 63 FlowControlError = 0x03, 64 65 /// The endpoint sent a `SETTINGS` frame but did not receive a response in 66 /// a timely manner. 67 SettingsTimeout = 0x04, 68 69 /// The endpoint received a frame after a stream was half-closed. 70 StreamClosed = 0x05, 71 72 /// The endpoint received a frame with an invalid size. 73 FrameSizeError = 0x06, 74 75 /// The endpoint refused the stream prior to performing any application 76 /// processing. 77 RefusedStream = 0x07, 78 79 /// The endpoint uses this error code to indicate that the stream is no 80 /// longer needed. 81 Cancel = 0x08, 82 83 /// The endpoint is unable to maintain the field section compression context 84 /// for the connection. 85 CompressionError = 0x09, 86 87 /// The connection established in response to a `CONNECT` request was reset 88 /// or abnormally closed. 89 ConnectError = 0x0a, 90 91 /// The endpoint detected that its peer is exhibiting a behavior that might 92 /// be generating excessive load. 93 EnhanceYourCalm = 0x0b, 94 95 /// The underlying transport has properties that do not meet minimum 96 /// security requirements. 97 InadequateSecurity = 0x0c, 98 99 /// The endpoint requires that HTTP/1.1 be used instead of HTTP/2. 100 Http1_1Required = 0x0d, 101 } 102 103 impl ErrorCode { 104 /// Gets the error code of the `ErrorCode` enum. into_code(self) -> u32105 pub fn into_code(self) -> u32 { 106 self as u32 107 } 108 } 109 110 impl TryFrom<u32> for ErrorCode { 111 type Error = H2Error; try_from(value: u32) -> Result<Self, Self::Error>112 fn try_from(value: u32) -> Result<Self, Self::Error> { 113 let err = match value { 114 0x00 => ErrorCode::NoError, 115 0x01 => ErrorCode::ProtocolError, 116 0x02 => ErrorCode::IntervalError, 117 0x03 => ErrorCode::FlowControlError, 118 0x04 => ErrorCode::SettingsTimeout, 119 0x05 => ErrorCode::StreamClosed, 120 0x06 => ErrorCode::FrameSizeError, 121 0x07 => ErrorCode::RefusedStream, 122 0x08 => ErrorCode::Cancel, 123 0x09 => ErrorCode::CompressionError, 124 0x0a => ErrorCode::ConnectError, 125 0x0b => ErrorCode::EnhanceYourCalm, 126 0x0c => ErrorCode::InadequateSecurity, 127 0x0d => ErrorCode::Http1_1Required, 128 _ => return Err(H2Error::ConnectionError(ErrorCode::ProtocolError)), 129 }; 130 Ok(err) 131 } 132 } 133 134 #[cfg(test)] 135 mod ut_h2_error { 136 use std::convert::TryInto; 137 138 use super::*; 139 140 /// Unit test cases for `ErrorCode::try_from`. 141 /// 142 /// # Brief 143 /// 1. Iterates over a range of valid u32 values that represent 144 /// `ErrorCode`s. 145 /// 2. Attempts to convert each u32 value into an `ErrorCode` using 146 /// `try_into`. 147 /// 3. Checks that the conversion is successful for each valid `ErrorCode`. 148 /// 4. Also attempts to convert an invalid u32 value into an `ErrorCode`. 149 /// 5. Checks that the conversion fails for the invalid value. 150 #[test] ut_test_error_code_try_from()151 fn ut_test_error_code_try_from() { 152 // Test conversion from u32 to ErrorCode for valid error codes 153 for i in 0x00..=0x0d { 154 let error_code: Result<ErrorCode, _> = i.try_into(); 155 assert!(error_code.is_ok()); 156 } 157 158 // Test conversion from u32 to ErrorCode for invalid error codes 159 let invalid_error_code: Result<ErrorCode, _> = 0x0e.try_into(); 160 assert!(invalid_error_code.is_err()); 161 } 162 } 163