#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HttpStatus {
Continue = 100,
SwitchingProtocols = 101,
Processing = 102,
EarlyHints = 103,
Ok = 200,
Created = 201,
Accepted = 202,
NonAuthoritativeInformation = 203,
NoContent = 204,
ResetContent = 205,
PartialContent = 206,
MultiStatus = 207,
AlreadyReported = 208,
ImUsed = 226,
MultipleChoices = 300,
MovedPermanently = 301,
Found = 302,
SeeOther = 303,
NotModified = 304,
UseProxy = 305,
TemporaryRedirect = 307,
PermanentRedirect = 308,
BadRequest = 400,
Unauthorized = 401,
PaymentRequired = 402,
Forbidden = 403,
NotFound = 404,
MethodNotAllowed = 405,
NotAcceptable = 406,
ProxyAuthenticationRequired = 407,
RequestTimeout = 408,
Conflict = 409,
Gone = 410,
LengthRequired = 411,
PreconditionFailed = 412,
PayloadTooLarge = 413,
UriTooLong = 414,
UnsupportedMediaType = 415,
RangeNotSatisfiable = 416,
ExpectationFailed = 417,
ImATeapot = 418,
MisdirectedRequest = 421,
UnprocessableEntity = 422,
Locked = 423,
FailedDependency = 424,
TooEarly = 425,
UpgradeRequired = 426,
PreconditionRequired = 428,
TooManyRequests = 429,
RequestHeaderFieldsTooLarge = 431,
UnavailableForLegalReasons = 451,
InternalServerError = 500,
NotImplemented = 501,
BadGateway = 502,
ServiceUnavailable = 503,
GatewayTimeout = 504,
HttpVersionNotSupported = 505,
VariantAlsoNegotiates = 506,
InsufficientStorage = 507,
LoopDetected = 508,
NotExtended = 510,
NetworkAuthenticationRequired = 511,
}
impl HttpStatus {
pub fn code(&self) -> u16 {
*self as u16
}
pub fn reason(&self) -> &'static str {
match self {
HttpStatus::Continue => "Continue",
HttpStatus::SwitchingProtocols => "Switching Protocols",
HttpStatus::Processing => "Processing",
HttpStatus::EarlyHints => "Early Hints",
HttpStatus::Ok => "OK",
HttpStatus::Created => "Created",
HttpStatus::Accepted => "Accepted",
HttpStatus::NonAuthoritativeInformation => "Non-Authoritative Information",
HttpStatus::NoContent => "No Content",
HttpStatus::ResetContent => "Reset Content",
HttpStatus::PartialContent => "Partial Content",
HttpStatus::MultiStatus => "Multi-Status",
HttpStatus::AlreadyReported => "Already Reported",
HttpStatus::ImUsed => "IM Used",
HttpStatus::MultipleChoices => "Multiple Choices",
HttpStatus::MovedPermanently => "Moved Permanently",
HttpStatus::Found => "Found",
HttpStatus::SeeOther => "See Other",
HttpStatus::NotModified => "Not Modified",
HttpStatus::UseProxy => "Use Proxy",
HttpStatus::TemporaryRedirect => "Temporary Redirect",
HttpStatus::PermanentRedirect => "Permanent Redirect",
HttpStatus::BadRequest => "Bad Request",
HttpStatus::Unauthorized => "Unauthorized",
HttpStatus::PaymentRequired => "Payment Required",
HttpStatus::Forbidden => "Forbidden",
HttpStatus::NotFound => "Not Found",
HttpStatus::MethodNotAllowed => "Method Not Allowed",
HttpStatus::NotAcceptable => "Not Acceptable",
HttpStatus::ProxyAuthenticationRequired => "Proxy Authentication Required",
HttpStatus::RequestTimeout => "Request Timeout",
HttpStatus::Conflict => "Conflict",
HttpStatus::Gone => "Gone",
HttpStatus::LengthRequired => "Length Required",
HttpStatus::PreconditionFailed => "Precondition Failed",
HttpStatus::PayloadTooLarge => "Payload Too Large",
HttpStatus::UriTooLong => "URI Too Long",
HttpStatus::UnsupportedMediaType => "Unsupported Media Type",
HttpStatus::RangeNotSatisfiable => "Range Not Satisfiable",
HttpStatus::ExpectationFailed => "Expectation Failed",
HttpStatus::ImATeapot => "I'm a teapot",
HttpStatus::MisdirectedRequest => "Misdirected Request",
HttpStatus::UnprocessableEntity => "Unprocessable Entity",
HttpStatus::Locked => "Locked",
HttpStatus::FailedDependency => "Failed Dependency",
HttpStatus::TooEarly => "Too Early",
HttpStatus::UpgradeRequired => "Upgrade Required",
HttpStatus::PreconditionRequired => "Precondition Required",
HttpStatus::TooManyRequests => "Too Many Requests",
HttpStatus::RequestHeaderFieldsTooLarge => "Request Header Fields Too Large",
HttpStatus::UnavailableForLegalReasons => "Unavailable For Legal Reasons",
HttpStatus::InternalServerError => "Internal Server Error",
HttpStatus::NotImplemented => "Not Implemented",
HttpStatus::BadGateway => "Bad Gateway",
HttpStatus::ServiceUnavailable => "Service Unavailable",
HttpStatus::GatewayTimeout => "Gateway Timeout",
HttpStatus::HttpVersionNotSupported => "HTTP Version Not Supported",
HttpStatus::VariantAlsoNegotiates => "Variant Also Negotiates",
HttpStatus::InsufficientStorage => "Insufficient Storage",
HttpStatus::LoopDetected => "Loop Detected",
HttpStatus::NotExtended => "Not Extended",
HttpStatus::NetworkAuthenticationRequired => "Network Authentication Required",
}
}
pub fn is_informational(&self) -> bool {
(100..200).contains(&self.code())
}
pub fn is_success(&self) -> bool {
(200..300).contains(&self.code())
}
pub fn is_redirection(&self) -> bool {
(300..400).contains(&self.code())
}
pub fn is_client_error(&self) -> bool {
(400..500).contains(&self.code())
}
pub fn is_server_error(&self) -> bool {
(500..600).contains(&self.code())
}
pub fn is_error(&self) -> bool {
self.is_client_error() || self.is_server_error()
}
pub fn from_code(code: u16) -> Option<Self> {
match code {
100 => Some(HttpStatus::Continue),
101 => Some(HttpStatus::SwitchingProtocols),
102 => Some(HttpStatus::Processing),
103 => Some(HttpStatus::EarlyHints),
200 => Some(HttpStatus::Ok),
201 => Some(HttpStatus::Created),
202 => Some(HttpStatus::Accepted),
203 => Some(HttpStatus::NonAuthoritativeInformation),
204 => Some(HttpStatus::NoContent),
205 => Some(HttpStatus::ResetContent),
206 => Some(HttpStatus::PartialContent),
207 => Some(HttpStatus::MultiStatus),
208 => Some(HttpStatus::AlreadyReported),
226 => Some(HttpStatus::ImUsed),
300 => Some(HttpStatus::MultipleChoices),
301 => Some(HttpStatus::MovedPermanently),
302 => Some(HttpStatus::Found),
303 => Some(HttpStatus::SeeOther),
304 => Some(HttpStatus::NotModified),
305 => Some(HttpStatus::UseProxy),
307 => Some(HttpStatus::TemporaryRedirect),
308 => Some(HttpStatus::PermanentRedirect),
400 => Some(HttpStatus::BadRequest),
401 => Some(HttpStatus::Unauthorized),
402 => Some(HttpStatus::PaymentRequired),
403 => Some(HttpStatus::Forbidden),
404 => Some(HttpStatus::NotFound),
405 => Some(HttpStatus::MethodNotAllowed),
406 => Some(HttpStatus::NotAcceptable),
407 => Some(HttpStatus::ProxyAuthenticationRequired),
408 => Some(HttpStatus::RequestTimeout),
409 => Some(HttpStatus::Conflict),
410 => Some(HttpStatus::Gone),
411 => Some(HttpStatus::LengthRequired),
412 => Some(HttpStatus::PreconditionFailed),
413 => Some(HttpStatus::PayloadTooLarge),
414 => Some(HttpStatus::UriTooLong),
415 => Some(HttpStatus::UnsupportedMediaType),
416 => Some(HttpStatus::RangeNotSatisfiable),
417 => Some(HttpStatus::ExpectationFailed),
418 => Some(HttpStatus::ImATeapot),
421 => Some(HttpStatus::MisdirectedRequest),
422 => Some(HttpStatus::UnprocessableEntity),
423 => Some(HttpStatus::Locked),
424 => Some(HttpStatus::FailedDependency),
425 => Some(HttpStatus::TooEarly),
426 => Some(HttpStatus::UpgradeRequired),
428 => Some(HttpStatus::PreconditionRequired),
429 => Some(HttpStatus::TooManyRequests),
431 => Some(HttpStatus::RequestHeaderFieldsTooLarge),
451 => Some(HttpStatus::UnavailableForLegalReasons),
500 => Some(HttpStatus::InternalServerError),
501 => Some(HttpStatus::NotImplemented),
502 => Some(HttpStatus::BadGateway),
503 => Some(HttpStatus::ServiceUnavailable),
504 => Some(HttpStatus::GatewayTimeout),
505 => Some(HttpStatus::HttpVersionNotSupported),
506 => Some(HttpStatus::VariantAlsoNegotiates),
507 => Some(HttpStatus::InsufficientStorage),
508 => Some(HttpStatus::LoopDetected),
510 => Some(HttpStatus::NotExtended),
511 => Some(HttpStatus::NetworkAuthenticationRequired),
_ => None,
}
}
}
impl std::fmt::Display for HttpStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {}", self.code(), self.reason())
}
}
impl From<HttpStatus> for u16 {
fn from(status: HttpStatus) -> Self {
status.code()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_status_code() {
assert_eq!(HttpStatus::Ok.code(), 200);
assert_eq!(HttpStatus::NotFound.code(), 404);
assert_eq!(HttpStatus::InternalServerError.code(), 500);
}
#[test]
fn test_status_reason() {
assert_eq!(HttpStatus::Ok.reason(), "OK");
assert_eq!(HttpStatus::NotFound.reason(), "Not Found");
assert_eq!(
HttpStatus::InternalServerError.reason(),
"Internal Server Error"
);
}
#[test]
fn test_status_categories() {
assert!(HttpStatus::Ok.is_success());
assert!(HttpStatus::NotFound.is_client_error());
assert!(HttpStatus::InternalServerError.is_server_error());
assert!(HttpStatus::NotFound.is_error());
assert!(!HttpStatus::Ok.is_error());
}
#[test]
fn test_from_code() {
assert_eq!(HttpStatus::from_code(200), Some(HttpStatus::Ok));
assert_eq!(HttpStatus::from_code(404), Some(HttpStatus::NotFound));
assert_eq!(HttpStatus::from_code(999), None);
}
#[test]
fn test_display() {
assert_eq!(HttpStatus::Ok.to_string(), "200 OK");
assert_eq!(HttpStatus::NotFound.to_string(), "404 Not Found");
}
}