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