1 /* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 use std::error::Error; 17 use std::fmt::{Debug, Display, Formatter}; 18 19 /// Errors that may occur in this crate. 20 pub struct HttpClientError { 21 kind: ErrorKind, 22 cause: Option<Box<dyn Error + Send + Sync>>, 23 } 24 25 impl HttpClientError { 26 /// Creates a `UserAborted` error. 27 /// 28 /// # Examples 29 /// 30 /// ``` 31 /// # use ylong_http_client::HttpClientError; 32 /// 33 /// let user_aborted = HttpClientError::user_aborted(); 34 /// ``` user_aborted() -> Self35 pub fn user_aborted() -> Self { 36 Self { 37 kind: ErrorKind::UserAborted, 38 cause: None, 39 } 40 } 41 42 /// Creates an `Other` error. 43 /// 44 /// # Examples 45 /// 46 /// ``` 47 /// # use ylong_http_client::HttpClientError; 48 /// 49 /// let other = HttpClientError::user_aborted(); 50 /// ``` other<T: Into<Box<dyn Error + Send + Sync>>>(cause: Option<T>) -> Self51 pub fn other<T: Into<Box<dyn Error + Send + Sync>>>(cause: Option<T>) -> Self { 52 Self { 53 kind: ErrorKind::Other, 54 cause: cause.map(Into::into), 55 } 56 } 57 58 /// Gets the `ErrorKind` of this `HttpClientError`. 59 /// 60 /// # Examples 61 /// 62 /// ``` 63 /// # use ylong_http_client::{ErrorKind, HttpClientError}; 64 /// 65 /// let user_aborted = HttpClientError::user_aborted(); 66 /// assert_eq!(user_aborted.error_kind(), ErrorKind::UserAborted); 67 /// ``` error_kind(&self) -> ErrorKind68 pub fn error_kind(&self) -> ErrorKind { 69 self.kind 70 } 71 new(kind: ErrorKind) -> Self72 pub(crate) fn new(kind: ErrorKind) -> Self { 73 Self { kind, cause: None } 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(Into::into), 83 } 84 } 85 } 86 87 impl From<reqwest::Error> for HttpClientError { from(err: reqwest::Error) -> Self88 fn from(err: reqwest::Error) -> Self { 89 let kind = match &err { 90 e if e.is_builder() => ErrorKind::Build, 91 e if e.is_timeout() => ErrorKind::Timeout, 92 e if e.is_request() => ErrorKind::Request, 93 e if e.is_redirect() => ErrorKind::Redirect, 94 e if e.is_connect() => ErrorKind::Connect, 95 e if e.is_body() => ErrorKind::BodyTransfer, 96 e if e.is_decode() => ErrorKind::BodyDecode, 97 _ => ErrorKind::Other, 98 }; 99 Self { 100 kind, 101 cause: Some(Box::new(err)), 102 } 103 } 104 } 105 106 impl Debug for HttpClientError { fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result107 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 108 f.debug_struct("HttpClientError") 109 .field("kind", &self.kind.as_str()) 110 .field("cause", &self.cause) 111 .finish() 112 } 113 } 114 115 impl Display for HttpClientError { fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result116 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 117 f.write_str(self.kind.as_str())?; 118 if let Some(cause) = self.cause.as_ref() { 119 f.write_str(":")?; 120 return Display::fmt(cause, f); 121 } 122 Ok(()) 123 } 124 } 125 126 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 127 pub enum ErrorKind { 128 Build, 129 Connect, 130 Request, 131 Redirect, 132 BodyTransfer, 133 BodyDecode, 134 ConnectionUpgrade, 135 UserAborted, 136 Timeout, 137 Other, 138 } 139 140 impl ErrorKind { 141 /// Gets the string info of this `ErrorKind`. 142 /// 143 /// # Examples 144 /// 145 /// ``` 146 /// # use ylong_http_client::ErrorKind; 147 /// 148 /// assert_eq!(ErrorKind::UserAborted.as_str(), "User Aborted Error"); 149 /// ``` as_str(&self) -> &'static str150 pub fn as_str(&self) -> &'static str { 151 match self { 152 Self::Build => "Build Error", 153 Self::Connect => "Connect Error", 154 Self::Request => "Request Error", 155 Self::Redirect => "Redirect Error", 156 Self::BodyTransfer => "Body Transfer Error", 157 Self::BodyDecode => "Body Decode Error", 158 Self::ConnectionUpgrade => "Connection Upgrade Error", 159 Self::UserAborted => "User Aborted Error", 160 Self::Timeout => "Timeout Error", 161 Self::Other => "Other Error", 162 } 163 } 164 } 165