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 //! Definition of `HttpClientErrors` which includes errors that may occur in 15 //! this crate. 16 17 use core::fmt::{Debug, Display, Formatter}; 18 use std::error::Error; 19 20 /// The structure encapsulates errors that can be encountered when working with 21 /// the HTTP client. 22 pub struct HttpClientError { 23 kind: ErrorKind, 24 cause: Option<Box<dyn Error + Send + Sync>>, 25 } 26 27 impl HttpClientError { 28 /// Creates a `UserAborted` error. 29 /// 30 /// # Examples 31 /// 32 /// ``` 33 /// # use ylong_http_client::HttpClientError; 34 /// 35 /// let user_aborted = HttpClientError::user_aborted(); 36 /// ``` user_aborted() -> Self37 pub fn user_aborted() -> Self { 38 Self { 39 kind: ErrorKind::UserAborted, 40 cause: None, 41 } 42 } 43 44 /// Creates an `Other` error. 45 /// 46 /// # Examples 47 /// 48 /// ``` 49 /// # use ylong_http_client::HttpClientError; 50 /// 51 /// # fn error(error: std::io::Error) { 52 /// let other = HttpClientError::other(Some(error)); 53 /// # } 54 /// ``` other<T: Into<Box<dyn Error + Send + Sync>>>(cause: Option<T>) -> Self55 pub fn other<T: Into<Box<dyn Error + Send + Sync>>>(cause: Option<T>) -> Self { 56 Self { 57 kind: ErrorKind::Other, 58 cause: cause.map(|e| e.into()), 59 } 60 } 61 62 /// Gets the `ErrorKind` of this `HttpClientError`. 63 /// 64 /// # Examples 65 /// 66 /// ``` 67 /// # use ylong_http_client::{ErrorKind, HttpClientError}; 68 /// 69 /// let user_aborted = HttpClientError::user_aborted(); 70 /// assert_eq!(user_aborted.error_kind(), ErrorKind::UserAborted); 71 /// ``` error_kind(&self) -> ErrorKind72 pub fn error_kind(&self) -> ErrorKind { 73 self.kind 74 } 75 new_with_cause<T>(kind: ErrorKind, cause: Option<T>) -> Self where T: Into<Box<dyn Error + Send + Sync>>,76 pub(crate) fn new_with_cause<T>(kind: ErrorKind, cause: Option<T>) -> Self 77 where 78 T: Into<Box<dyn Error + Send + Sync>>, 79 { 80 Self { 81 kind, 82 cause: cause.map(|e| e.into()), 83 } 84 } 85 new_with_message(kind: ErrorKind, message: &str) -> Self86 pub(crate) fn new_with_message(kind: ErrorKind, message: &str) -> Self { 87 Self { 88 kind, 89 cause: Some(CauseMessage::new(message).into()), 90 } 91 } 92 } 93 94 impl Debug for HttpClientError { fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result95 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { 96 let mut builder = f.debug_struct("HttpClientError"); 97 builder.field("ErrorKind", &self.kind); 98 if let Some(ref cause) = self.cause { 99 builder.field("Cause", cause); 100 } 101 builder.finish() 102 } 103 } 104 105 impl Display for HttpClientError { fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result106 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { 107 f.write_str(self.kind.as_str())?; 108 109 if let Some(ref cause) = self.cause { 110 write!(f, ": {cause}")?; 111 } 112 Ok(()) 113 } 114 } 115 116 impl Error for HttpClientError {} 117 118 /// Error kinds which can indicate the type of a `HttpClientError`. 119 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 120 pub enum ErrorKind { 121 /// Errors for decoding response body. 122 BodyDecode, 123 124 /// Errors for transferring request body or response body. 125 BodyTransfer, 126 127 /// Errors for using various builder. 128 Build, 129 130 /// Errors for connecting to a server. 131 Connect, 132 133 /// Errors for upgrading a connection. 134 ConnectionUpgrade, 135 136 /// Other error kinds. 137 Other, 138 139 /// Errors for following redirect. 140 Redirect, 141 142 /// Errors for sending a request. 143 Request, 144 145 /// Errors for reaching a timeout. 146 Timeout, 147 148 /// User raised errors. 149 UserAborted, 150 } 151 152 impl ErrorKind { 153 /// Gets the string info of this `ErrorKind`. 154 /// 155 /// # Examples 156 /// 157 /// ``` 158 /// use ylong_http_client::ErrorKind; 159 /// 160 /// assert_eq!(ErrorKind::UserAborted.as_str(), "User Aborted Error"); 161 /// ``` as_str(&self) -> &'static str162 pub fn as_str(&self) -> &'static str { 163 match self { 164 Self::BodyDecode => "Body Decode Error", 165 Self::BodyTransfer => "Body Transfer Error", 166 Self::Build => "Build Error", 167 Self::Connect => "Connect Error", 168 Self::ConnectionUpgrade => "Connection Upgrade Error", 169 Self::Other => "Other Error", 170 Self::Redirect => "Redirect Error", 171 Self::Request => "Request Error", 172 Self::Timeout => "Timeout Error", 173 Self::UserAborted => "User Aborted Error", 174 } 175 } 176 } 177 178 /// Messages for summarizing the cause of the error 179 pub(crate) struct CauseMessage(String); 180 181 impl CauseMessage { new(message: &str) -> Self182 pub(crate) fn new(message: &str) -> Self { 183 Self(message.to_string()) 184 } 185 } 186 187 impl Debug for CauseMessage { fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result188 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { 189 f.write_str(self.0.as_str()) 190 } 191 } 192 193 impl Display for CauseMessage { fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result194 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { 195 f.write_str(self.0.as_str()) 196 } 197 } 198 199 impl Error for CauseMessage {} 200