agentic_tools_utils/
http.rs1use reqwest::Error as ReqwestError;
7use reqwest::StatusCode;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum HttpKind {
12 Unauthorized,
14 Forbidden,
16 NotFound,
18 RateLimited,
20 ClientError,
22 ServerError,
24 Timeout,
26 Network,
28 Unknown,
30}
31
32#[derive(Debug, Clone)]
34pub struct HttpErrorSummary {
35 pub kind: HttpKind,
37 pub status: Option<u16>,
39 pub message: String,
41}
42
43pub fn classify_status(status: StatusCode) -> HttpKind {
45 match status {
46 StatusCode::UNAUTHORIZED => HttpKind::Unauthorized,
47 StatusCode::FORBIDDEN => HttpKind::Forbidden,
48 StatusCode::NOT_FOUND => HttpKind::NotFound,
49 StatusCode::TOO_MANY_REQUESTS => HttpKind::RateLimited,
50 s if s.is_client_error() => HttpKind::ClientError,
51 s if s.is_server_error() => HttpKind::ServerError,
52 _ => HttpKind::Unknown,
53 }
54}
55
56pub fn summarize_reqwest_error(err: &ReqwestError) -> HttpErrorSummary {
58 if err.is_timeout() {
59 return HttpErrorSummary {
60 kind: HttpKind::Timeout,
61 status: None,
62 message: err.to_string(),
63 };
64 }
65
66 if err.is_connect() {
67 return HttpErrorSummary {
68 kind: HttpKind::Network,
69 status: None,
70 message: err.to_string(),
71 };
72 }
73
74 if let Some(status) = err.status() {
75 let kind = classify_status(status);
76 return HttpErrorSummary {
77 kind,
78 status: Some(status.as_u16()),
79 message: err.to_string(),
80 };
81 }
82
83 HttpErrorSummary {
84 kind: HttpKind::Unknown,
85 status: None,
86 message: err.to_string(),
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn classify_status_unauthorized() {
96 assert_eq!(
97 classify_status(StatusCode::UNAUTHORIZED),
98 HttpKind::Unauthorized
99 );
100 }
101
102 #[test]
103 fn classify_status_forbidden() {
104 assert_eq!(classify_status(StatusCode::FORBIDDEN), HttpKind::Forbidden);
105 }
106
107 #[test]
108 fn classify_status_not_found() {
109 assert_eq!(classify_status(StatusCode::NOT_FOUND), HttpKind::NotFound);
110 }
111
112 #[test]
113 fn classify_status_rate_limited() {
114 assert_eq!(
115 classify_status(StatusCode::TOO_MANY_REQUESTS),
116 HttpKind::RateLimited
117 );
118 }
119
120 #[test]
121 fn classify_status_other_client_error() {
122 assert_eq!(
123 classify_status(StatusCode::BAD_REQUEST),
124 HttpKind::ClientError
125 );
126 assert_eq!(classify_status(StatusCode::CONFLICT), HttpKind::ClientError);
127 }
128
129 #[test]
130 fn classify_status_server_error() {
131 assert_eq!(
132 classify_status(StatusCode::INTERNAL_SERVER_ERROR),
133 HttpKind::ServerError
134 );
135 assert_eq!(
136 classify_status(StatusCode::BAD_GATEWAY),
137 HttpKind::ServerError
138 );
139 assert_eq!(
140 classify_status(StatusCode::SERVICE_UNAVAILABLE),
141 HttpKind::ServerError
142 );
143 }
144
145 #[test]
146 fn classify_status_ok_is_unknown() {
147 assert_eq!(classify_status(StatusCode::OK), HttpKind::Unknown);
149 }
150}