1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum HttpStatus {
6 Continue = 100,
8 SwitchingProtocols = 101,
9 Processing = 102,
10 EarlyHints = 103,
11
12 Ok = 200,
14 Created = 201,
15 Accepted = 202,
16 NonAuthoritativeInformation = 203,
17 NoContent = 204,
18 ResetContent = 205,
19 PartialContent = 206,
20 MultiStatus = 207,
21 AlreadyReported = 208,
22 ImUsed = 226,
23
24 MultipleChoices = 300,
26 MovedPermanently = 301,
27 Found = 302,
28 SeeOther = 303,
29 NotModified = 304,
30 UseProxy = 305,
31 TemporaryRedirect = 307,
32 PermanentRedirect = 308,
33
34 BadRequest = 400,
36 Unauthorized = 401,
37 PaymentRequired = 402,
38 Forbidden = 403,
39 NotFound = 404,
40 MethodNotAllowed = 405,
41 NotAcceptable = 406,
42 ProxyAuthenticationRequired = 407,
43 RequestTimeout = 408,
44 Conflict = 409,
45 Gone = 410,
46 LengthRequired = 411,
47 PreconditionFailed = 412,
48 PayloadTooLarge = 413,
49 UriTooLong = 414,
50 UnsupportedMediaType = 415,
51 RangeNotSatisfiable = 416,
52 ExpectationFailed = 417,
53 ImATeapot = 418,
54 MisdirectedRequest = 421,
55 UnprocessableEntity = 422,
56 Locked = 423,
57 FailedDependency = 424,
58 TooEarly = 425,
59 UpgradeRequired = 426,
60 PreconditionRequired = 428,
61 TooManyRequests = 429,
62 RequestHeaderFieldsTooLarge = 431,
63 UnavailableForLegalReasons = 451,
64
65 InternalServerError = 500,
67 NotImplemented = 501,
68 BadGateway = 502,
69 ServiceUnavailable = 503,
70 GatewayTimeout = 504,
71 HttpVersionNotSupported = 505,
72 VariantAlsoNegotiates = 506,
73 InsufficientStorage = 507,
74 LoopDetected = 508,
75 NotExtended = 510,
76 NetworkAuthenticationRequired = 511,
77}
78
79impl HttpStatus {
80 pub fn code(&self) -> u16 {
82 *self as u16
83 }
84
85 pub fn reason(&self) -> &'static str {
87 match self {
88 HttpStatus::Continue => "Continue",
90 HttpStatus::SwitchingProtocols => "Switching Protocols",
91 HttpStatus::Processing => "Processing",
92 HttpStatus::EarlyHints => "Early Hints",
93
94 HttpStatus::Ok => "OK",
96 HttpStatus::Created => "Created",
97 HttpStatus::Accepted => "Accepted",
98 HttpStatus::NonAuthoritativeInformation => "Non-Authoritative Information",
99 HttpStatus::NoContent => "No Content",
100 HttpStatus::ResetContent => "Reset Content",
101 HttpStatus::PartialContent => "Partial Content",
102 HttpStatus::MultiStatus => "Multi-Status",
103 HttpStatus::AlreadyReported => "Already Reported",
104 HttpStatus::ImUsed => "IM Used",
105
106 HttpStatus::MultipleChoices => "Multiple Choices",
108 HttpStatus::MovedPermanently => "Moved Permanently",
109 HttpStatus::Found => "Found",
110 HttpStatus::SeeOther => "See Other",
111 HttpStatus::NotModified => "Not Modified",
112 HttpStatus::UseProxy => "Use Proxy",
113 HttpStatus::TemporaryRedirect => "Temporary Redirect",
114 HttpStatus::PermanentRedirect => "Permanent Redirect",
115
116 HttpStatus::BadRequest => "Bad Request",
118 HttpStatus::Unauthorized => "Unauthorized",
119 HttpStatus::PaymentRequired => "Payment Required",
120 HttpStatus::Forbidden => "Forbidden",
121 HttpStatus::NotFound => "Not Found",
122 HttpStatus::MethodNotAllowed => "Method Not Allowed",
123 HttpStatus::NotAcceptable => "Not Acceptable",
124 HttpStatus::ProxyAuthenticationRequired => "Proxy Authentication Required",
125 HttpStatus::RequestTimeout => "Request Timeout",
126 HttpStatus::Conflict => "Conflict",
127 HttpStatus::Gone => "Gone",
128 HttpStatus::LengthRequired => "Length Required",
129 HttpStatus::PreconditionFailed => "Precondition Failed",
130 HttpStatus::PayloadTooLarge => "Payload Too Large",
131 HttpStatus::UriTooLong => "URI Too Long",
132 HttpStatus::UnsupportedMediaType => "Unsupported Media Type",
133 HttpStatus::RangeNotSatisfiable => "Range Not Satisfiable",
134 HttpStatus::ExpectationFailed => "Expectation Failed",
135 HttpStatus::ImATeapot => "I'm a teapot",
136 HttpStatus::MisdirectedRequest => "Misdirected Request",
137 HttpStatus::UnprocessableEntity => "Unprocessable Entity",
138 HttpStatus::Locked => "Locked",
139 HttpStatus::FailedDependency => "Failed Dependency",
140 HttpStatus::TooEarly => "Too Early",
141 HttpStatus::UpgradeRequired => "Upgrade Required",
142 HttpStatus::PreconditionRequired => "Precondition Required",
143 HttpStatus::TooManyRequests => "Too Many Requests",
144 HttpStatus::RequestHeaderFieldsTooLarge => "Request Header Fields Too Large",
145 HttpStatus::UnavailableForLegalReasons => "Unavailable For Legal Reasons",
146
147 HttpStatus::InternalServerError => "Internal Server Error",
149 HttpStatus::NotImplemented => "Not Implemented",
150 HttpStatus::BadGateway => "Bad Gateway",
151 HttpStatus::ServiceUnavailable => "Service Unavailable",
152 HttpStatus::GatewayTimeout => "Gateway Timeout",
153 HttpStatus::HttpVersionNotSupported => "HTTP Version Not Supported",
154 HttpStatus::VariantAlsoNegotiates => "Variant Also Negotiates",
155 HttpStatus::InsufficientStorage => "Insufficient Storage",
156 HttpStatus::LoopDetected => "Loop Detected",
157 HttpStatus::NotExtended => "Not Extended",
158 HttpStatus::NetworkAuthenticationRequired => "Network Authentication Required",
159 }
160 }
161
162 pub fn is_informational(&self) -> bool {
164 (100..200).contains(&self.code())
165 }
166
167 pub fn is_success(&self) -> bool {
169 (200..300).contains(&self.code())
170 }
171
172 pub fn is_redirection(&self) -> bool {
174 (300..400).contains(&self.code())
175 }
176
177 pub fn is_client_error(&self) -> bool {
179 (400..500).contains(&self.code())
180 }
181
182 pub fn is_server_error(&self) -> bool {
184 (500..600).contains(&self.code())
185 }
186
187 pub fn is_error(&self) -> bool {
189 self.is_client_error() || self.is_server_error()
190 }
191
192 pub fn from_code(code: u16) -> Option<Self> {
194 match code {
195 100 => Some(HttpStatus::Continue),
197 101 => Some(HttpStatus::SwitchingProtocols),
198 102 => Some(HttpStatus::Processing),
199 103 => Some(HttpStatus::EarlyHints),
200
201 200 => Some(HttpStatus::Ok),
203 201 => Some(HttpStatus::Created),
204 202 => Some(HttpStatus::Accepted),
205 203 => Some(HttpStatus::NonAuthoritativeInformation),
206 204 => Some(HttpStatus::NoContent),
207 205 => Some(HttpStatus::ResetContent),
208 206 => Some(HttpStatus::PartialContent),
209 207 => Some(HttpStatus::MultiStatus),
210 208 => Some(HttpStatus::AlreadyReported),
211 226 => Some(HttpStatus::ImUsed),
212
213 300 => Some(HttpStatus::MultipleChoices),
215 301 => Some(HttpStatus::MovedPermanently),
216 302 => Some(HttpStatus::Found),
217 303 => Some(HttpStatus::SeeOther),
218 304 => Some(HttpStatus::NotModified),
219 305 => Some(HttpStatus::UseProxy),
220 307 => Some(HttpStatus::TemporaryRedirect),
221 308 => Some(HttpStatus::PermanentRedirect),
222
223 400 => Some(HttpStatus::BadRequest),
225 401 => Some(HttpStatus::Unauthorized),
226 402 => Some(HttpStatus::PaymentRequired),
227 403 => Some(HttpStatus::Forbidden),
228 404 => Some(HttpStatus::NotFound),
229 405 => Some(HttpStatus::MethodNotAllowed),
230 406 => Some(HttpStatus::NotAcceptable),
231 407 => Some(HttpStatus::ProxyAuthenticationRequired),
232 408 => Some(HttpStatus::RequestTimeout),
233 409 => Some(HttpStatus::Conflict),
234 410 => Some(HttpStatus::Gone),
235 411 => Some(HttpStatus::LengthRequired),
236 412 => Some(HttpStatus::PreconditionFailed),
237 413 => Some(HttpStatus::PayloadTooLarge),
238 414 => Some(HttpStatus::UriTooLong),
239 415 => Some(HttpStatus::UnsupportedMediaType),
240 416 => Some(HttpStatus::RangeNotSatisfiable),
241 417 => Some(HttpStatus::ExpectationFailed),
242 418 => Some(HttpStatus::ImATeapot),
243 421 => Some(HttpStatus::MisdirectedRequest),
244 422 => Some(HttpStatus::UnprocessableEntity),
245 423 => Some(HttpStatus::Locked),
246 424 => Some(HttpStatus::FailedDependency),
247 425 => Some(HttpStatus::TooEarly),
248 426 => Some(HttpStatus::UpgradeRequired),
249 428 => Some(HttpStatus::PreconditionRequired),
250 429 => Some(HttpStatus::TooManyRequests),
251 431 => Some(HttpStatus::RequestHeaderFieldsTooLarge),
252 451 => Some(HttpStatus::UnavailableForLegalReasons),
253
254 500 => Some(HttpStatus::InternalServerError),
256 501 => Some(HttpStatus::NotImplemented),
257 502 => Some(HttpStatus::BadGateway),
258 503 => Some(HttpStatus::ServiceUnavailable),
259 504 => Some(HttpStatus::GatewayTimeout),
260 505 => Some(HttpStatus::HttpVersionNotSupported),
261 506 => Some(HttpStatus::VariantAlsoNegotiates),
262 507 => Some(HttpStatus::InsufficientStorage),
263 508 => Some(HttpStatus::LoopDetected),
264 510 => Some(HttpStatus::NotExtended),
265 511 => Some(HttpStatus::NetworkAuthenticationRequired),
266
267 _ => None,
268 }
269 }
270}
271
272impl std::fmt::Display for HttpStatus {
273 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
274 write!(f, "{} {}", self.code(), self.reason())
275 }
276}
277
278impl From<HttpStatus> for u16 {
279 fn from(status: HttpStatus) -> Self {
280 status.code()
281 }
282}
283
284#[cfg(test)]
285mod tests {
286 use super::*;
287
288 #[test]
289 fn test_status_code() {
290 assert_eq!(HttpStatus::Ok.code(), 200);
291 assert_eq!(HttpStatus::NotFound.code(), 404);
292 assert_eq!(HttpStatus::InternalServerError.code(), 500);
293 }
294
295 #[test]
296 fn test_status_reason() {
297 assert_eq!(HttpStatus::Ok.reason(), "OK");
298 assert_eq!(HttpStatus::NotFound.reason(), "Not Found");
299 assert_eq!(
300 HttpStatus::InternalServerError.reason(),
301 "Internal Server Error"
302 );
303 }
304
305 #[test]
306 fn test_status_categories() {
307 assert!(HttpStatus::Ok.is_success());
308 assert!(HttpStatus::NotFound.is_client_error());
309 assert!(HttpStatus::InternalServerError.is_server_error());
310 assert!(HttpStatus::NotFound.is_error());
311 assert!(!HttpStatus::Ok.is_error());
312 }
313
314 #[test]
315 fn test_from_code() {
316 assert_eq!(HttpStatus::from_code(200), Some(HttpStatus::Ok));
317 assert_eq!(HttpStatus::from_code(404), Some(HttpStatus::NotFound));
318 assert_eq!(HttpStatus::from_code(999), None);
319 }
320
321 #[test]
322 fn test_display() {
323 assert_eq!(HttpStatus::Ok.to_string(), "200 OK");
324 assert_eq!(HttpStatus::NotFound.to_string(), "404 Not Found");
325 }
326}