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