qiniu_http/
error.rs

1use super::response::{Metrics, ResponseInfo, ResponseParts};
2use anyhow::Error as AnyError;
3use http::uri::{Scheme, Uri};
4use std::{
5    error::Error as StdError,
6    fmt::{self, Debug, Display},
7    net::IpAddr,
8    num::NonZeroU16,
9};
10
11/// HTTP 响应错误类型
12#[derive(Debug, Copy, Clone, PartialEq, Eq)]
13#[non_exhaustive]
14pub enum ErrorKind {
15    /// 协议错误,该协议不能支持
16    ProtocolError,
17
18    /// 非法的请求 / 响应错误
19    InvalidRequestResponse,
20
21    /// 非法的 URL
22    InvalidUrl,
23
24    /// 非法的 HTTP 头
25    InvalidHeader,
26
27    /// 网络连接失败
28    ConnectError,
29
30    /// 代理连接失败
31    ProxyError,
32
33    /// DNS 服务器连接失败
34    DnsServerError,
35
36    /// 域名解析失败
37    UnknownHostError,
38
39    /// 发送失败
40    SendError,
41
42    /// 接受失败
43    ReceiveError,
44
45    /// 本地 IO 失败
46    LocalIoError,
47
48    /// 超时失败
49    TimeoutError,
50
51    /// SSL 客户端证书错误
52    ClientCertError,
53
54    /// SSL 服务器端证书错误
55    ServerCertError,
56
57    /// SSL 错误
58    SslError,
59
60    /// 重定向次数过多
61    TooManyRedirect,
62
63    /// 未知错误
64    UnknownError,
65
66    /// 回调函数返回错误
67    CallbackError,
68}
69
70/// HTTP 响应错误
71#[derive(Debug)]
72pub struct Error {
73    kind: ErrorKind,
74    error: AnyError,
75    response_info: ResponseInfo,
76}
77
78impl Error {
79    /// 创建 HTTP 响应错误构建器
80    #[inline]
81    pub fn builder(kind: ErrorKind, err: impl Into<AnyError>) -> ErrorBuilder {
82        ErrorBuilder::new(kind, err)
83    }
84
85    /// 创建 HTTP 响应错误构建器
86    #[inline]
87    pub fn builder_with_msg(kind: ErrorKind, err: impl Display + Debug + Send + Sync + 'static) -> ErrorBuilder {
88        ErrorBuilder::new_with_msg(kind, err)
89    }
90
91    /// 获取 HTTP 响应错误类型
92    #[inline]
93    pub fn kind(&self) -> ErrorKind {
94        self.kind
95    }
96
97    /// 转换为内部存储的实际响应错误
98    #[inline]
99    pub fn into_inner(self) -> AnyError {
100        self.error
101    }
102
103    /// 获取服务器 IP 地址
104    #[inline]
105    pub fn server_ip(&self) -> Option<IpAddr> {
106        self.response_info.server_ip()
107    }
108
109    /// 获取服务器端口号
110    #[inline]
111    pub fn server_port(&self) -> Option<NonZeroU16> {
112        self.response_info.server_port()
113    }
114
115    /// 获取响应指标信息
116    #[inline]
117    pub fn metrics(&self) -> Option<&Metrics> {
118        self.response_info.metrics()
119    }
120
121    /// 获取服务器 IP 地址的可变引用
122    #[inline]
123    pub fn server_ip_mut(&mut self) -> &mut Option<IpAddr> {
124        self.response_info.server_ip_mut()
125    }
126
127    /// 获取服务器端口号的可变引用
128    #[inline]
129    pub fn server_port_mut(&mut self) -> &mut Option<NonZeroU16> {
130        self.response_info.server_port_mut()
131    }
132
133    /// 获取响应指标信息的可变引用
134    #[inline]
135    pub fn metrics_mut(&mut self) -> &mut Option<Metrics> {
136        self.response_info.metrics_mut()
137    }
138}
139
140impl Display for Error {
141    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
142        Display::fmt(&self.error, f)
143    }
144}
145
146impl StdError for Error {
147    #[inline]
148    fn source(&self) -> Option<&(dyn StdError + 'static)> {
149        Some(self.error.as_ref())
150    }
151}
152
153/// HTTP 响应错误构建器
154#[derive(Debug)]
155pub struct ErrorBuilder {
156    inner: Error,
157}
158
159impl ErrorBuilder {
160    /// 创建 HTTP 响应错误构建器
161    #[inline]
162    fn new(kind: ErrorKind, err: impl Into<AnyError>) -> Self {
163        Self {
164            inner: Error {
165                kind,
166                error: err.into(),
167                response_info: Default::default(),
168            },
169        }
170    }
171
172    /// 创建 HTTP 响应错误构建器
173    #[inline]
174    fn new_with_msg(kind: ErrorKind, msg: impl Display + Debug + Send + Sync + 'static) -> Self {
175        Self {
176            inner: Error {
177                kind,
178                error: AnyError::msg(msg),
179                response_info: Default::default(),
180            },
181        }
182    }
183
184    /// 构建 HTTP 响应错误
185    #[inline]
186    pub fn build(self) -> Error {
187        self.inner
188    }
189
190    /// 设置 HTTP 响应的相关 URI 信息
191    #[must_use]
192    pub fn uri(mut self, uri: &Uri) -> Self {
193        if let Some(host) = uri.host() {
194            if let Ok(ip_addr) = host.parse::<IpAddr>() {
195                *self.inner.server_ip_mut() = Some(ip_addr);
196            }
197        }
198        if let Some(port) = uri.port_u16() {
199            *self.inner.server_port_mut() = NonZeroU16::new(port);
200        } else if let Some(scheme) = uri.scheme() {
201            if scheme == &Scheme::HTTP {
202                *self.inner.server_port_mut() = NonZeroU16::new(80);
203            } else if scheme == &Scheme::HTTPS {
204                *self.inner.server_port_mut() = NonZeroU16::new(443);
205            }
206        }
207        self
208    }
209
210    /// 设置 HTTP 响应的服务器 IP 地址
211    #[inline]
212    #[must_use]
213    pub fn server_ip(mut self, server_ip: IpAddr) -> Self {
214        *self.inner.server_ip_mut() = Some(server_ip);
215        self
216    }
217
218    /// 设置 HTTP 响应的服务器端口号
219    #[inline]
220    #[must_use]
221    pub fn server_port(mut self, server_port: NonZeroU16) -> Self {
222        *self.inner.server_port_mut() = Some(server_port);
223        self
224    }
225
226    /// 设置 HTTP 响应指标信息
227    #[inline]
228    #[must_use]
229    pub fn metrics(mut self, metrics: Metrics) -> Self {
230        *self.inner.metrics_mut() = Some(metrics);
231        self
232    }
233}
234
235/// 响应映射错误
236#[derive(Debug)]
237pub struct MapError<E> {
238    error: E,
239    parts: ResponseParts,
240}
241
242impl<E> MapError<E> {
243    pub(super) fn new(error: E, parts: ResponseParts) -> Self {
244        Self { error, parts }
245    }
246
247    /// 转换为响应映射错误的原始错误
248    #[inline]
249    pub fn into_inner(self) -> E {
250        self.error
251    }
252}
253
254impl<E: Into<AnyError>> MapError<E> {
255    /// 将响应映射错误转换为 HTTP 响应错误
256    pub fn into_response_error(self, kind: ErrorKind) -> Error {
257        Error {
258            kind,
259            error: self.error.into(),
260            response_info: self.parts.into_response_info(),
261        }
262    }
263}