use {
core::{
convert::TryFrom,
fmt::{self, Display, Formatter},
str::FromStr,
},
crate::Error,
};
const STATUS_CONTINUE: u16 = 100;
const STATUS_SWITCHING_PROTOCOLS: u16 = 101;
const STATUS_EARLY_HINTS: u16 = 103;
const STATUS_OK: u16 = 200;
const STATUS_CREATED: u16 = 201;
const STATUS_ACCEPTED: u16 = 202;
const STATUS_NON_AUTHORITATIVE_INFORMATION: u16 = 203;
const STATUS_NO_CONTENT: u16 = 204;
const STATUS_RESET_CONTENT: u16 = 205;
const STATUS_PARTIAL_CONTENT: u16 = 206;
const STATUS_MULTIPLE_CHOICES: u16 = 300;
const STATUS_MOVED_PERMANENTLY: u16 = 301;
const STATUS_FOUND: u16 = 302;
const STATUS_SEE_OTHER: u16 = 303;
const STATUS_NOT_MODIFIED: u16 = 304;
const STATUS_TEMPORARY_REDIRECT: u16 = 307;
const STATUS_PERMANENT_REDIRECT: u16 = 308;
const STATUS_BAD_REQUEST: u16 = 400;
const STATUS_UNAUTHORIZED: u16 = 401;
const STATUS_PAYMENT_REQUIRED: u16 = 402;
const STATUS_FORBIDDEN: u16 = 403;
const STATUS_NOT_FOUND: u16 = 404;
const STATUS_METHOD_NOT_ALLOWED: u16 = 405;
const STATUS_NOT_ACCEPTABLE: u16 = 406;
const STATUS_PROXY_AUTHENTICATION_REQUIRED: u16 = 407;
const STATUS_REQUEST_TIMEOUT: u16 = 408;
const STATUS_CONFLICT: u16 = 409;
const STATUS_GONE: u16 = 410;
const STATUS_LENGTH_REQUIRED: u16 = 411;
const STATUS_PRECONDITION_FAILED: u16 = 412;
const STATUS_PAYLOAD_TOO_LARGE: u16 = 413;
const STATUS_URI_TOO_LONG: u16 = 414;
const STATUS_UNSUPPORTED_MEDIA_TYPE: u16 = 415;
const STATUS_RANGE_NOT_SATISFIABLE: u16 = 416;
const STATUS_EXPECTATION_FAILED: u16 = 417;
const STATUS_IM_A_TEAPOT: u16 = 418;
const STATUS_UNPROCESSABLE_ENTITY: u16 = 422;
const STATUS_TOO_EARLY: u16 = 425;
const STATUS_UPGRADE_REQUIRED: u16 = 426;
const STATUS_PRECONDITION_REQUIRED: u16 = 428;
const STATUS_TOO_MANY_REQUESTS: u16 = 429;
const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE: u16 = 431;
const STATUS_UNAVAILABLE_FOR_LEGAL_REASONS: u16 = 451;
const STATUS_INTERNAL_SERVER_ERROR: u16 = 500;
const STATUS_NOT_IMPLEMENTED: u16 = 501;
const STATUS_BAD_GATEWAY: u16 = 502;
const STATUS_SERVICE_UNAVAILABLE: u16 = 503;
const STATUS_GATEWAY_TIMEOUT: u16 = 504;
const STATUS_HTTP_VERSION_NOT_SUPPORTED: u16 = 505;
const STATUS_NETWORK_AUTHENTICATION_REQUIRED: u16 = 511;
#[derive(Debug, Eq, PartialEq, Hash)]
pub enum Status {
Continue,
SwitchingProtocols,
EarlyHints,
Ok,
Created,
Accepted,
NonAuthoritativeInformation,
NoContent,
ResetContent,
PartialContent,
MultipleChoices,
MovedPermanently,
Found,
SeeOther,
NotModified,
TemporaryRedirect,
PermanentRedirect,
BadRequest,
Unauthorized,
PaymentRequired,
Forbidden,
NotFound,
MethodNotAllowed,
NotAcceptable,
ProxyAuthenticationRequired,
RequestTimeout,
Conflict,
Gone,
LengthRequired,
PreconditionFailed,
PayloadTooLarge,
UriTooLong,
UnsupportedMediaType,
RangeNotSatisfiable,
ExpectationFailed,
ImATeapot,
UnprocessableEntity,
TooEarly,
UpgradeRequired,
PreconditionRequired,
TooManyRequests,
RequestHeaderFieldsTooLarge,
UnavailableForLegalReasons,
InternalServerError,
NotImplemented,
BadGateway,
ServiceUnavailable,
GatewayTimeout,
HttpVersionNotSupported,
NetworkAuthenticationRequired,
}
impl Status {
pub fn code(&self) -> u16 {
match self {
Status::Continue => STATUS_CONTINUE,
Status::SwitchingProtocols => STATUS_SWITCHING_PROTOCOLS,
Status::EarlyHints => STATUS_EARLY_HINTS,
Status::Ok => STATUS_OK,
Status::Created => STATUS_CREATED,
Status::Accepted => STATUS_ACCEPTED,
Status::NonAuthoritativeInformation => STATUS_NON_AUTHORITATIVE_INFORMATION,
Status::NoContent => STATUS_NO_CONTENT,
Status::ResetContent => STATUS_RESET_CONTENT,
Status::PartialContent => STATUS_PARTIAL_CONTENT,
Status::MultipleChoices => STATUS_MULTIPLE_CHOICES,
Status::MovedPermanently => STATUS_MOVED_PERMANENTLY,
Status::Found => STATUS_FOUND,
Status::SeeOther => STATUS_SEE_OTHER,
Status::NotModified => STATUS_NOT_MODIFIED,
Status::TemporaryRedirect => STATUS_TEMPORARY_REDIRECT,
Status::PermanentRedirect => STATUS_PERMANENT_REDIRECT,
Status::BadRequest => STATUS_BAD_REQUEST,
Status::Unauthorized => STATUS_UNAUTHORIZED,
Status::PaymentRequired => STATUS_PAYMENT_REQUIRED,
Status::Forbidden => STATUS_FORBIDDEN,
Status::NotFound => STATUS_NOT_FOUND,
Status::MethodNotAllowed => STATUS_METHOD_NOT_ALLOWED,
Status::NotAcceptable => STATUS_NOT_ACCEPTABLE,
Status::ProxyAuthenticationRequired => STATUS_PROXY_AUTHENTICATION_REQUIRED,
Status::RequestTimeout => STATUS_REQUEST_TIMEOUT,
Status::Conflict => STATUS_CONFLICT,
Status::Gone => STATUS_GONE,
Status::LengthRequired => STATUS_LENGTH_REQUIRED,
Status::PreconditionFailed => STATUS_PRECONDITION_FAILED,
Status::PayloadTooLarge => STATUS_PAYLOAD_TOO_LARGE,
Status::UriTooLong => STATUS_URI_TOO_LONG,
Status::UnsupportedMediaType => STATUS_UNSUPPORTED_MEDIA_TYPE,
Status::RangeNotSatisfiable => STATUS_RANGE_NOT_SATISFIABLE,
Status::ExpectationFailed => STATUS_EXPECTATION_FAILED,
Status::ImATeapot => STATUS_IM_A_TEAPOT,
Status::UnprocessableEntity => STATUS_UNPROCESSABLE_ENTITY,
Status::TooEarly => STATUS_TOO_EARLY,
Status::UpgradeRequired => STATUS_UPGRADE_REQUIRED,
Status::PreconditionRequired => STATUS_PRECONDITION_REQUIRED,
Status::TooManyRequests => STATUS_TOO_MANY_REQUESTS,
Status::RequestHeaderFieldsTooLarge => STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE,
Status::UnavailableForLegalReasons => STATUS_UNAVAILABLE_FOR_LEGAL_REASONS,
Status::InternalServerError => STATUS_INTERNAL_SERVER_ERROR,
Status::NotImplemented => STATUS_NOT_IMPLEMENTED,
Status::BadGateway => STATUS_BAD_GATEWAY,
Status::ServiceUnavailable => STATUS_SERVICE_UNAVAILABLE,
Status::GatewayTimeout => STATUS_GATEWAY_TIMEOUT,
Status::HttpVersionNotSupported => STATUS_HTTP_VERSION_NOT_SUPPORTED,
Status::NetworkAuthenticationRequired => STATUS_NETWORK_AUTHENTICATION_REQUIRED,
}
}
}
impl Display for Status {
fn fmt(&self, f: &mut Formatter) -> core::result::Result<(), fmt::Error> {
f.write_str(match self {
Status::Continue => "Continue",
Status::SwitchingProtocols => "Switching Protocols",
Status::EarlyHints => "Early Hints",
Status::Ok => "OK",
Status::Created => "Created",
Status::Accepted => "Accepted",
Status::NonAuthoritativeInformation => "Non-Authoritative Information",
Status::NoContent => "No Content",
Status::ResetContent => "Reset Content",
Status::PartialContent => "Partial Content",
Status::MultipleChoices => "Multiple Choices",
Status::MovedPermanently => "Moved Permanently",
Status::Found => "Found",
Status::SeeOther => "See Other",
Status::NotModified => "Not Modified",
Status::TemporaryRedirect => "Temporary Redirect",
Status::PermanentRedirect => "Permanent Redirect",
Status::BadRequest => "Bad Request",
Status::Unauthorized => "Unauthorized",
Status::PaymentRequired => "Payment Required",
Status::Forbidden => "Forbidden",
Status::NotFound => "Not Found",
Status::MethodNotAllowed => "Method Not Allowed",
Status::NotAcceptable => "Not Acceptable",
Status::ProxyAuthenticationRequired => "Proxy Authentication Required",
Status::RequestTimeout => "Request Timeout",
Status::Conflict => "Conflict",
Status::Gone => "Gone",
Status::LengthRequired => "Length Required",
Status::PreconditionFailed => "Precondition Failed",
Status::PayloadTooLarge => "Payload Too Large",
Status::UriTooLong => "URI Too Long",
Status::UnsupportedMediaType => "Unsupported Media Type",
Status::RangeNotSatisfiable => "Range Not Satisfiable",
Status::ExpectationFailed => "Expectation Failed",
Status::ImATeapot => "I'm a teapot",
Status::UnprocessableEntity => "Unprocessable Entity",
Status::TooEarly => "Too Early",
Status::UpgradeRequired => "Upgrade Required",
Status::PreconditionRequired => "Precondition Required",
Status::TooManyRequests => "Too Many Requests",
Status::RequestHeaderFieldsTooLarge => "Request Header Fields Too Large",
Status::UnavailableForLegalReasons => "Unavailable For Legal Reasons",
Status::InternalServerError => "Internal Server Error",
Status::NotImplemented => "Not Implemented",
Status::BadGateway => "Bad Gateway",
Status::ServiceUnavailable => "Service Unavailable",
Status::GatewayTimeout => "Gateway Timeout",
Status::HttpVersionNotSupported => "HTTP Version Not Supported",
Status::NetworkAuthenticationRequired => "Network Authentication Required",
})
}
}
impl TryFrom<u16> for Status {
type Error = Error;
fn try_from(n: u16) -> Result<Self, Self::Error> {
match n {
STATUS_CONTINUE => Ok(Status::Continue),
STATUS_SWITCHING_PROTOCOLS => Ok(Status::SwitchingProtocols),
STATUS_EARLY_HINTS => Ok(Status::EarlyHints),
STATUS_OK => Ok(Status::Ok),
STATUS_CREATED => Ok(Status::Created),
STATUS_ACCEPTED => Ok(Status::Accepted),
STATUS_NON_AUTHORITATIVE_INFORMATION => Ok(Status::NonAuthoritativeInformation),
STATUS_NO_CONTENT => Ok(Status::NoContent),
STATUS_RESET_CONTENT => Ok(Status::ResetContent),
STATUS_PARTIAL_CONTENT => Ok(Status::PartialContent),
STATUS_MULTIPLE_CHOICES => Ok(Status::MultipleChoices),
STATUS_MOVED_PERMANENTLY => Ok(Status::MovedPermanently),
STATUS_FOUND => Ok(Status::Found),
STATUS_SEE_OTHER => Ok(Status::SeeOther),
STATUS_NOT_MODIFIED => Ok(Status::NotModified),
STATUS_TEMPORARY_REDIRECT => Ok(Status::TemporaryRedirect),
STATUS_PERMANENT_REDIRECT => Ok(Status::PermanentRedirect),
STATUS_BAD_REQUEST => Ok(Status::BadRequest),
STATUS_UNAUTHORIZED => Ok(Status::Unauthorized),
STATUS_PAYMENT_REQUIRED => Ok(Status::PaymentRequired),
STATUS_FORBIDDEN => Ok(Status::Forbidden),
STATUS_NOT_FOUND => Ok(Status::NotFound),
STATUS_METHOD_NOT_ALLOWED => Ok(Status::MethodNotAllowed),
STATUS_NOT_ACCEPTABLE => Ok(Status::NotAcceptable),
STATUS_PROXY_AUTHENTICATION_REQUIRED => Ok(Status::ProxyAuthenticationRequired),
STATUS_REQUEST_TIMEOUT => Ok(Status::RequestTimeout),
STATUS_CONFLICT => Ok(Status::Conflict),
STATUS_GONE => Ok(Status::Gone),
STATUS_LENGTH_REQUIRED => Ok(Status::LengthRequired),
STATUS_PRECONDITION_FAILED => Ok(Status::PreconditionFailed),
STATUS_PAYLOAD_TOO_LARGE => Ok(Status::PayloadTooLarge),
STATUS_URI_TOO_LONG => Ok(Status::UriTooLong),
STATUS_UNSUPPORTED_MEDIA_TYPE => Ok(Status::UnsupportedMediaType),
STATUS_RANGE_NOT_SATISFIABLE => Ok(Status::RangeNotSatisfiable),
STATUS_EXPECTATION_FAILED => Ok(Status::ExpectationFailed),
STATUS_IM_A_TEAPOT => Ok(Status::ImATeapot),
STATUS_UNPROCESSABLE_ENTITY => Ok(Status::UnprocessableEntity),
STATUS_TOO_EARLY => Ok(Status::TooEarly),
STATUS_UPGRADE_REQUIRED => Ok(Status::UpgradeRequired),
STATUS_PRECONDITION_REQUIRED => Ok(Status::PreconditionRequired),
STATUS_TOO_MANY_REQUESTS => Ok(Status::TooManyRequests),
STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE => Ok(Status::RequestHeaderFieldsTooLarge),
STATUS_UNAVAILABLE_FOR_LEGAL_REASONS => Ok(Status::UnavailableForLegalReasons),
STATUS_INTERNAL_SERVER_ERROR => Ok(Status::InternalServerError),
STATUS_NOT_IMPLEMENTED => Ok(Status::NotImplemented),
STATUS_BAD_GATEWAY => Ok(Status::BadGateway),
STATUS_SERVICE_UNAVAILABLE => Ok(Status::ServiceUnavailable),
STATUS_GATEWAY_TIMEOUT => Ok(Status::GatewayTimeout),
STATUS_HTTP_VERSION_NOT_SUPPORTED => Ok(Status::HttpVersionNotSupported),
STATUS_NETWORK_AUTHENTICATION_REQUIRED => Ok(Status::NetworkAuthenticationRequired),
other => Err(e!("Unknown status: {}", other)),
}
}
}
impl FromStr for Status {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from(u16::from_str(s).map_err(|_| e!("Invalid status: {:?}", s))?)
}
}
impl TryFrom<&[u8]> for Status {
type Error = Error;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let err = e!("Invalid status: {:?}", bytes);
if bytes.len() > 3 {
return Err(err);
}
let mut n: u16 = 0;
for (i, b) in bytes.iter().rev().enumerate() {
match b {
b'0'..=b'9' => n += u16::from(b - b'0') * 10_u16.pow(i as u32),
_ => return Err(err),
};
}
Self::try_from(n)
}
}