qiniu_http_client/client/response/
error.rs1use super::{
2 super::super::{EndpointParseError, RetriedStatsInfo, RetryDecision},
3 X_LOG_HEADER_NAME, X_REQ_ID_HEADER_NAME,
4};
5use anyhow::Error as AnyError;
6use assert_impl::assert_impl;
7use qiniu_http::{
8 Extensions, HeaderValue, Metrics, ResponseError as HttpResponseError, ResponseErrorKind as HttpResponseErrorKind,
9 ResponseParts as HttpResponseParts, StatusCode as HttpStatusCode,
10};
11use qiniu_upload_token::ToStringError;
12use serde_json::Error as JsonError;
13use std::{
14 error::Error as StdError,
15 fmt::{self, Debug, Display},
16 io::{Error as IoError, Read, Result as IOResult},
17 mem::take,
18 net::IpAddr,
19 num::NonZeroU16,
20};
21
22#[cfg(feature = "async")]
23use futures::{AsyncRead, AsyncReadExt};
24
25#[derive(Debug, Copy, Clone, PartialEq, Eq)]
27#[non_exhaustive]
28pub enum ErrorKind {
29 HttpError(HttpResponseErrorKind),
31
32 StatusCodeError(HttpStatusCode),
34
35 UnexpectedStatusCode(HttpStatusCode),
37
38 ParseResponseError,
40
41 UnexpectedEof,
43
44 MaliciousResponse,
46
47 SystemCallError,
49
50 NoTry,
52}
53
54#[derive(Debug)]
56pub struct Error {
57 kind: ErrorKind,
58 error: AnyError,
59 server_ip: Option<IpAddr>,
60 server_port: Option<NonZeroU16>,
61 metrics: Option<Metrics>,
62 x_headers: XHeaders,
63 response_body_sample: Vec<u8>,
64 retried: Option<RetriedStatsInfo>,
65 retry_decision: Option<RetryDecision>,
66 extensions: Extensions,
67}
68
69const RESPONSE_BODY_SAMPLE_LEN_LIMIT: u64 = 1024;
70
71impl Error {
72 #[inline]
74 pub fn new(kind: ErrorKind, err: impl Into<AnyError>) -> Self {
75 Error {
76 kind,
77 error: err.into(),
78 server_ip: Default::default(),
79 server_port: Default::default(),
80 metrics: Default::default(),
81 x_headers: Default::default(),
82 response_body_sample: Default::default(),
83 retried: Default::default(),
84 retry_decision: Default::default(),
85 extensions: Default::default(),
86 }
87 }
88
89 #[inline]
91 pub fn new_with_msg(kind: ErrorKind, msg: impl Display + Debug + Send + Sync + 'static) -> Self {
92 Error {
93 kind,
94 error: AnyError::msg(msg),
95 server_ip: Default::default(),
96 server_port: Default::default(),
97 metrics: Default::default(),
98 x_headers: Default::default(),
99 response_body_sample: Default::default(),
100 retried: Default::default(),
101 retry_decision: Default::default(),
102 extensions: Default::default(),
103 }
104 }
105
106 #[inline]
108 #[must_use]
109 pub fn retried(mut self, retried: &RetriedStatsInfo) -> Self {
110 self.retried = Some(retried.to_owned());
111 self
112 }
113
114 #[inline]
116 #[must_use]
117 pub fn set_retry_decision(mut self, retry_decision: RetryDecision) -> Self {
118 self.retry_decision = Some(retry_decision);
119 self
120 }
121
122 #[inline]
124 #[must_use]
125 pub fn response_parts(mut self, response_parts: &HttpResponseParts) -> Self {
126 self.server_ip = response_parts.server_ip();
127 self.server_port = response_parts.server_port();
128 self.metrics = extract_metrics_from_response_parts(response_parts);
129 self.x_headers = response_parts.into();
130 self
131 }
132
133 #[inline]
135 pub fn set_response_body_sample(mut self, body: Vec<u8>) -> Self {
136 self.response_body_sample = body;
137 self
138 }
139
140 #[inline]
144 pub fn read_response_body_sample<R: Read>(mut self, body: R) -> IOResult<Self> {
145 body.take(RESPONSE_BODY_SAMPLE_LEN_LIMIT)
146 .read_to_end(&mut self.response_body_sample)?;
147 Ok(self)
148 }
149
150 #[inline]
152 #[cfg(feature = "async")]
153 pub async fn async_read_response_body_sample<R: AsyncRead + Unpin>(mut self, body: R) -> IOResult<Self> {
154 body.take(RESPONSE_BODY_SAMPLE_LEN_LIMIT)
155 .read_to_end(&mut self.response_body_sample)
156 .await?;
157 Ok(self)
158 }
159
160 #[inline]
162 pub fn kind(&self) -> ErrorKind {
163 self.kind
164 }
165
166 #[inline]
168 pub fn retry_decision(&self) -> Option<RetryDecision> {
169 self.retry_decision
170 }
171
172 #[inline]
174 pub fn response_body_sample(&self) -> &[u8] {
175 &self.response_body_sample
176 }
177
178 #[inline]
180 pub fn server_ip(&self) -> Option<IpAddr> {
181 self.server_ip
182 }
183
184 #[inline]
186 pub fn server_port(&self) -> Option<NonZeroU16> {
187 self.server_port
188 }
189
190 #[inline]
192 pub fn metrics(&self) -> Option<&Metrics> {
193 self.metrics.as_ref()
194 }
195
196 #[inline]
198 pub fn x_log(&self) -> Option<&HeaderValue> {
199 self.x_headers.x_log.as_ref()
200 }
201
202 #[inline]
204 pub fn x_reqid(&self) -> Option<&HeaderValue> {
205 self.x_headers.x_reqid.as_ref()
206 }
207
208 #[inline]
210 pub fn extensions(&self) -> &Extensions {
211 &self.extensions
212 }
213
214 #[inline]
216 pub fn extensions_mut(&mut self) -> &mut Extensions {
217 &mut self.extensions
218 }
219
220 pub(in super::super) fn from_http_response_error(
221 mut err: HttpResponseError,
222 x_headers: XHeaders,
223 kind: Option<ErrorKind>,
224 ) -> Self {
225 Self {
226 x_headers,
227 server_ip: err.server_ip(),
228 server_port: err.server_port(),
229 metrics: take(err.metrics_mut()),
230 kind: kind.unwrap_or_else(|| err.kind().into()),
231 error: err.into_inner(),
232 response_body_sample: Default::default(),
233 retried: Default::default(),
234 retry_decision: Default::default(),
235 extensions: Default::default(),
236 }
237 }
238
239 pub(crate) fn from_endpoint_parse_error(error: EndpointParseError, parts: &HttpResponseParts) -> Self {
240 Self::new(ErrorKind::ParseResponseError, error).response_parts(parts)
241 }
242
243 #[allow(dead_code)]
244 fn assert() {
245 assert_impl!(Send: Self);
246 assert_impl!(Sync: Self);
247 }
248}
249
250#[derive(Debug, Default)]
251pub(in super::super) struct XHeaders {
252 x_log: Option<HeaderValue>,
253 x_reqid: Option<HeaderValue>,
254}
255
256impl From<&HttpResponseParts> for XHeaders {
257 #[inline]
258 fn from(parts: &HttpResponseParts) -> Self {
259 Self {
260 x_log: extract_x_log_from_response_parts(parts),
261 x_reqid: extract_x_reqid_from_response_parts(parts),
262 }
263 }
264}
265
266fn extract_x_log_from_response_parts(parts: &HttpResponseParts) -> Option<HeaderValue> {
267 parts.header(X_LOG_HEADER_NAME).cloned()
268}
269
270fn extract_x_reqid_from_response_parts(parts: &HttpResponseParts) -> Option<HeaderValue> {
271 parts.header(X_REQ_ID_HEADER_NAME).cloned()
272}
273
274fn extract_metrics_from_response_parts(parts: &HttpResponseParts) -> Option<Metrics> {
275 parts.metrics().cloned()
276}
277
278impl Display for Error {
279 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
280 write!(f, "[{:?}]", self.kind)?;
281 if let Some(retried) = self.retried.as_ref() {
282 write!(f, "[{retried}]")?;
283 }
284 if let Some(x_reqid) = self.x_headers.x_reqid.as_ref() {
285 write!(f, "[{x_reqid:?}]")?;
286 }
287 if let Some(x_log) = self.x_headers.x_log.as_ref() {
288 write!(f, "[{x_log:?}]")?;
289 }
290 write!(f, " {}", self.error)?;
291 if !self.response_body_sample.is_empty() {
292 write!(f, " [{}]", String::from_utf8_lossy(&self.response_body_sample))?;
293 }
294 Ok(())
295 }
296}
297
298impl StdError for Error {
299 #[inline]
300 fn source(&self) -> Option<&(dyn StdError + 'static)> {
301 Some(self.error.as_ref())
302 }
303}
304
305impl From<HttpResponseError> for Error {
306 #[inline]
307 fn from(error: HttpResponseError) -> Self {
308 Self::from_http_response_error(error, Default::default(), None)
309 }
310}
311
312impl From<HttpResponseErrorKind> for ErrorKind {
313 #[inline]
314 fn from(kind: HttpResponseErrorKind) -> Self {
315 ErrorKind::HttpError(kind)
316 }
317}
318
319impl From<JsonError> for Error {
320 #[inline]
321 fn from(error: JsonError) -> Self {
322 Self::new(ErrorKind::ParseResponseError, error)
323 }
324}
325
326impl From<IoError> for Error {
327 #[inline]
328 fn from(error: IoError) -> Self {
329 Self::new(ErrorKind::HttpError(HttpResponseErrorKind::LocalIoError), error)
330 }
331}
332
333impl From<ToStringError> for Error {
334 #[inline]
335 fn from(error: ToStringError) -> Self {
336 match error {
337 ToStringError::CredentialGetError(err) => err.into(),
338 ToStringError::CallbackError(err) => Self::new(HttpResponseErrorKind::CallbackError.into(), err),
339 err => Self::new(HttpResponseErrorKind::UnknownError.into(), err),
340 }
341 }
342}