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