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