blob: ef95c909215901bc0f29fd38cf1c9a42271e6b3d [file] [log] [blame]
//! HTTP status codes
//!
//! This module contains HTTP-status code related structs an errors. The main
//! type in this module is `StatusCode` which is not intended to be used through
//! this module but rather the `http::StatusCode` type.
//!
//! # Examples
//!
//! ```
//! use http::StatusCode;
//!
//! assert_eq!(StatusCode::from_u16(200).unwrap(), StatusCode::OK);
//! assert_eq!(StatusCode::NOT_FOUND, 404);
//! assert!(StatusCode::OK.is_success());
//! ```
use std::fmt;
use std::error::Error;
use std::str::FromStr;
use HttpTryFrom;
/// An HTTP status code (`status-code` in RFC 7230 et al.).
///
/// This type contains constants for all common status codes.
/// It allows status codes in the range [100, 599].
///
/// IANA maintain the [Hypertext Transfer Protocol (HTTP) Status Code
/// Registry](http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml) which is
/// the source for this enum (with one exception, 418 I'm a teapot, which is
/// inexplicably not in the register).
///
/// # Examples
///
/// ```
/// use http::StatusCode;
///
/// assert_eq!(StatusCode::from_u16(200).unwrap(), StatusCode::OK);
/// assert_eq!(StatusCode::NOT_FOUND.as_u16(), 404);
/// assert!(StatusCode::OK.is_success());
/// ```
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StatusCode(u16);
/// A possible error value when converting a `StatusCode` from a `u16` or `&str`
///
/// This error indicates that the supplied input was not a valid number, was less
/// than 100, or was greater than 599.
pub struct InvalidStatusCode {
_priv: (),
}
impl StatusCode {
/// Converts a u16 to a status code.
///
/// The function validates the correctness of the supplied u16. It must be
/// greater or equal to 100 but less than 600.
///
/// # Example
///
/// ```
/// use http::StatusCode;
///
/// let ok = StatusCode::from_u16(200).unwrap();
/// assert_eq!(ok, StatusCode::OK);
///
/// let err = StatusCode::from_u16(99);
/// assert!(err.is_err());
/// ```
#[inline]
pub fn from_u16(src: u16) -> Result<StatusCode, InvalidStatusCode> {
if src < 100 || src >= 600 {
return Err(InvalidStatusCode::new());
}
Ok(StatusCode(src))
}
/// Converts a &[u8] to a status code
pub fn from_bytes(src: &[u8]) -> Result<StatusCode, InvalidStatusCode> {
if src.len() != 3 {
return Err(InvalidStatusCode::new());
}
let a = src[0].wrapping_sub(b'0') as u16;
let b = src[1].wrapping_sub(b'0') as u16;
let c = src[2].wrapping_sub(b'0') as u16;
if a == 0 || a > 5 || b > 9 || c > 9 {
return Err(InvalidStatusCode::new());
}
let status = (a * 100) + (b * 10) + c;
Ok(StatusCode(status))
}
/// Returns the `u16` corresponding to this `StatusCode`.
///
/// # Note
///
/// This is the same as the `From<StatusCode>` implementation, but
/// included as an inherent method because that implementation doesn't
/// appear in rustdocs, as well as a way to force the type instead of
/// relying on inference.
///
/// # Example
///
/// ```
/// let status = http::StatusCode::OK;
/// assert_eq!(status.as_u16(), 200);
/// ```
#[inline]
pub fn as_u16(&self) -> u16 {
(*self).into()
}
/// Returns a &str representation of the `StatusCode`
///
/// The return value only includes a numerical representation of the
/// status code. The canonical reason is not included.
///
/// # Example
///
/// ```
/// let status = http::StatusCode::OK;
/// assert_eq!(status.as_str(), "200");
/// ```
#[inline]
pub fn as_str(&self) -> &str {
CODES_AS_STR[(self.0 - 100) as usize]
}
/// Get the standardised `reason-phrase` for this status code.
///
/// This is mostly here for servers writing responses, but could potentially have application
/// at other times.
///
/// The reason phrase is defined as being exclusively for human readers. You should avoid
/// deriving any meaning from it at all costs.
///
/// Bear in mind also that in HTTP/2.0 the reason phrase is abolished from transmission, and so
/// this canonical reason phrase really is the only reason phrase you’ll find.
///
/// # Example
///
/// ```
/// let status = http::StatusCode::OK;
/// assert_eq!(status.canonical_reason(), Some("OK"));
/// ```
pub fn canonical_reason(&self) -> Option<&'static str> {
canonical_reason(self.0)
}
/// Check if status is within 100-199.
#[inline]
pub fn is_informational(&self) -> bool {
200 > self.0 && self.0 >= 100
}
/// Check if status is within 200-299.
#[inline]
pub fn is_success(&self) -> bool {
300 > self.0 && self.0 >= 200
}
/// Check if status is within 300-399.
#[inline]
pub fn is_redirection(&self) -> bool {
400 > self.0 && self.0 >= 300
}
/// Check if status is within 400-499.
#[inline]
pub fn is_client_error(&self) -> bool {
500 > self.0 && self.0 >= 400
}
/// Check if status is within 500-599.
#[inline]
pub fn is_server_error(&self) -> bool {
600 > self.0 && self.0 >= 500
}
}
impl fmt::Debug for StatusCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
/// Formats the status code, *including* the canonical reason.
///
/// # Example
///
/// ```
/// # use http::StatusCode;
/// assert_eq!(format!("{}", StatusCode::OK), "200 OK");
/// ```
impl fmt::Display for StatusCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", u16::from(*self),
self.canonical_reason().unwrap_or("<unknown status code>"))
}
}
impl Default for StatusCode {
#[inline]
fn default() -> StatusCode {
StatusCode::OK
}
}
impl PartialEq<u16> for StatusCode {
#[inline]
fn eq(&self, other: &u16) -> bool {
self.as_u16() == *other
}
}
impl PartialEq<StatusCode> for u16 {
#[inline]
fn eq(&self, other: &StatusCode) -> bool {
*self == other.as_u16()
}
}
impl From<StatusCode> for u16 {
#[inline]
fn from(status: StatusCode) -> u16 {
status.0
}
}
impl FromStr for StatusCode {
type Err = InvalidStatusCode;
fn from_str(s: &str) -> Result<StatusCode, InvalidStatusCode> {
StatusCode::from_bytes(s.as_ref())
}
}
impl<'a> From<&'a StatusCode> for StatusCode {
#[inline]
fn from(t: &'a StatusCode) -> Self {
t.clone()
}
}
impl<'a> HttpTryFrom<&'a StatusCode> for StatusCode {
type Error = ::error::Never;
#[inline]
fn try_from(t: &'a StatusCode) -> Result<Self, Self::Error> {
Ok(t.clone())
}
}
impl<'a> HttpTryFrom<&'a [u8]> for StatusCode {
type Error = InvalidStatusCode;
#[inline]
fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
StatusCode::from_bytes(t)
}
}
impl<'a> HttpTryFrom<&'a str> for StatusCode {
type Error = InvalidStatusCode;
#[inline]
fn try_from(t: &'a str) -> Result<Self, Self::Error> {
t.parse()
}
}
impl HttpTryFrom<u16> for StatusCode {
type Error = InvalidStatusCode;
#[inline]
fn try_from(t: u16) -> Result<Self, Self::Error> {
StatusCode::from_u16(t)
}
}
macro_rules! status_codes {
(
$(
$(#[$docs:meta])*
($num:expr, $konst:ident, $phrase:expr);
)+
) => {
impl StatusCode {
$(
$(#[$docs])*
pub const $konst: StatusCode = StatusCode($num);
)+
}
fn canonical_reason(num: u16) -> Option<&'static str> {
match num {
$(
$num => Some($phrase),
)+
_ => None
}
}
}
}
status_codes! {
/// 100 Continue
/// [[RFC7231, Section 6.2.1](https://tools.ietf.org/html/rfc7231#section-6.2.1)]
(100, CONTINUE, "Continue");
/// 101 Switching Protocols
/// [[RFC7231, Section 6.2.2](https://tools.ietf.org/html/rfc7231#section-6.2.2)]
(101, SWITCHING_PROTOCOLS, "Switching Protocols");
/// 102 Processing
/// [[RFC2518](https://tools.ietf.org/html/rfc2518)]
(102, PROCESSING, "Processing");
/// 200 OK
/// [[RFC7231, Section 6.3.1](https://tools.ietf.org/html/rfc7231#section-6.3.1)]
(200, OK, "OK");
/// 201 Created
/// [[RFC7231, Section 6.3.2](https://tools.ietf.org/html/rfc7231#section-6.3.2)]
(201, CREATED, "Created");
/// 202 Accepted
/// [[RFC7231, Section 6.3.3](https://tools.ietf.org/html/rfc7231#section-6.3.3)]
(202, ACCEPTED, "Accepted");
/// 203 Non-Authoritative Information
/// [[RFC7231, Section 6.3.4](https://tools.ietf.org/html/rfc7231#section-6.3.4)]
(203, NON_AUTHORITATIVE_INFORMATION, "Non Authoritative Information");
/// 204 No Content
/// [[RFC7231, Section 6.3.5](https://tools.ietf.org/html/rfc7231#section-6.3.5)]
(204, NO_CONTENT, "No Content");
/// 205 Reset Content
/// [[RFC7231, Section 6.3.6](https://tools.ietf.org/html/rfc7231#section-6.3.6)]
(205, RESET_CONTENT, "Reset Content");
/// 206 Partial Content
/// [[RFC7233, Section 4.1](https://tools.ietf.org/html/rfc7233#section-4.1)]
(206, PARTIAL_CONTENT, "Partial Content");
/// 207 Multi-Status
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(207, MULTI_STATUS, "Multi-Status");
/// 208 Already Reported
/// [[RFC5842](https://tools.ietf.org/html/rfc5842)]
(208, ALREADY_REPORTED, "Already Reported");
/// 226 IM Used
/// [[RFC3229](https://tools.ietf.org/html/rfc3229)]
(226, IM_USED, "IM Used");
/// 300 Multiple Choices
/// [[RFC7231, Section 6.4.1](https://tools.ietf.org/html/rfc7231#section-6.4.1)]
(300, MULTIPLE_CHOICES, "Multiple Choices");
/// 301 Moved Permanently
/// [[RFC7231, Section 6.4.2](https://tools.ietf.org/html/rfc7231#section-6.4.2)]
(301, MOVED_PERMANENTLY, "Moved Permanently");
/// 302 Found
/// [[RFC7231, Section 6.4.3](https://tools.ietf.org/html/rfc7231#section-6.4.3)]
(302, FOUND, "Found");
/// 303 See Other
/// [[RFC7231, Section 6.4.4](https://tools.ietf.org/html/rfc7231#section-6.4.4)]
(303, SEE_OTHER, "See Other");
/// 304 Not Modified
/// [[RFC7232, Section 4.1](https://tools.ietf.org/html/rfc7232#section-4.1)]
(304, NOT_MODIFIED, "Not Modified");
/// 305 Use Proxy
/// [[RFC7231, Section 6.4.5](https://tools.ietf.org/html/rfc7231#section-6.4.5)]
(305, USE_PROXY, "Use Proxy");
/// 307 Temporary Redirect
/// [[RFC7231, Section 6.4.7](https://tools.ietf.org/html/rfc7231#section-6.4.7)]
(307, TEMPORARY_REDIRECT, "Temporary Redirect");
/// 308 Permanent Redirect
/// [[RFC7238](https://tools.ietf.org/html/rfc7238)]
(308, PERMANENT_REDIRECT, "Permanent Redirect");
/// 400 Bad Request
/// [[RFC7231, Section 6.5.1](https://tools.ietf.org/html/rfc7231#section-6.5.1)]
(400, BAD_REQUEST, "Bad Request");
/// 401 Unauthorized
/// [[RFC7235, Section 3.1](https://tools.ietf.org/html/rfc7235#section-3.1)]
(401, UNAUTHORIZED, "Unauthorized");
/// 402 Payment Required
/// [[RFC7231, Section 6.5.2](https://tools.ietf.org/html/rfc7231#section-6.5.2)]
(402, PAYMENT_REQUIRED, "Payment Required");
/// 403 Forbidden
/// [[RFC7231, Section 6.5.3](https://tools.ietf.org/html/rfc7231#section-6.5.3)]
(403, FORBIDDEN, "Forbidden");
/// 404 Not Found
/// [[RFC7231, Section 6.5.4](https://tools.ietf.org/html/rfc7231#section-6.5.4)]
(404, NOT_FOUND, "Not Found");
/// 405 Method Not Allowed
/// [[RFC7231, Section 6.5.5](https://tools.ietf.org/html/rfc7231#section-6.5.5)]
(405, METHOD_NOT_ALLOWED, "Method Not Allowed");
/// 406 Not Acceptable
/// [[RFC7231, Section 6.5.6](https://tools.ietf.org/html/rfc7231#section-6.5.6)]
(406, NOT_ACCEPTABLE, "Not Acceptable");
/// 407 Proxy Authentication Required
/// [[RFC7235, Section 3.2](https://tools.ietf.org/html/rfc7235#section-3.2)]
(407, PROXY_AUTHENTICATION_REQUIRED, "Proxy Authentication Required");
/// 408 Request Timeout
/// [[RFC7231, Section 6.5.7](https://tools.ietf.org/html/rfc7231#section-6.5.7)]
(408, REQUEST_TIMEOUT, "Request Timeout");
/// 409 Conflict
/// [[RFC7231, Section 6.5.8](https://tools.ietf.org/html/rfc7231#section-6.5.8)]
(409, CONFLICT, "Conflict");
/// 410 Gone
/// [[RFC7231, Section 6.5.9](https://tools.ietf.org/html/rfc7231#section-6.5.9)]
(410, GONE, "Gone");
/// 411 Length Required
/// [[RFC7231, Section 6.5.10](https://tools.ietf.org/html/rfc7231#section-6.5.10)]
(411, LENGTH_REQUIRED, "Length Required");
/// 412 Precondition Failed
/// [[RFC7232, Section 4.2](https://tools.ietf.org/html/rfc7232#section-4.2)]
(412, PRECONDITION_FAILED, "Precondition Failed");
/// 413 Payload Too Large
/// [[RFC7231, Section 6.5.11](https://tools.ietf.org/html/rfc7231#section-6.5.11)]
(413, PAYLOAD_TOO_LARGE, "Payload Too Large");
/// 414 URI Too Long
/// [[RFC7231, Section 6.5.12](https://tools.ietf.org/html/rfc7231#section-6.5.12)]
(414, URI_TOO_LONG, "URI Too Long");
/// 415 Unsupported Media Type
/// [[RFC7231, Section 6.5.13](https://tools.ietf.org/html/rfc7231#section-6.5.13)]
(415, UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
/// 416 Range Not Satisfiable
/// [[RFC7233, Section 4.4](https://tools.ietf.org/html/rfc7233#section-4.4)]
(416, RANGE_NOT_SATISFIABLE, "Range Not Satisfiable");
/// 417 Expectation Failed
/// [[RFC7231, Section 6.5.14](https://tools.ietf.org/html/rfc7231#section-6.5.14)]
(417, EXPECTATION_FAILED, "Expectation Failed");
/// 418 I'm a teapot
/// [curiously not registered by IANA but [RFC2324](https://tools.ietf.org/html/rfc2324)]
(418, IM_A_TEAPOT, "I'm a teapot");
/// 421 Misdirected Request
/// [RFC7540, Section 9.1.2](http://tools.ietf.org/html/rfc7540#section-9.1.2)
(421, MISDIRECTED_REQUEST, "Misdirected Request");
/// 422 Unprocessable Entity
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(422, UNPROCESSABLE_ENTITY, "Unprocessable Entity");
/// 423 Locked
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(423, LOCKED, "Locked");
/// 424 Failed Dependency
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(424, FAILED_DEPENDENCY, "Failed Dependency");
/// 426 Upgrade Required
/// [[RFC7231, Section 6.5.15](https://tools.ietf.org/html/rfc7231#section-6.5.15)]
(426, UPGRADE_REQUIRED, "Upgrade Required");
/// 428 Precondition Required
/// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
(428, PRECONDITION_REQUIRED, "Precondition Required");
/// 429 Too Many Requests
/// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
(429, TOO_MANY_REQUESTS, "Too Many Requests");
/// 431 Request Header Fields Too Large
/// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
(431, REQUEST_HEADER_FIELDS_TOO_LARGE, "Request Header Fields Too Large");
/// 451 Unavailable For Legal Reasons
/// [[RFC7725](http://tools.ietf.org/html/rfc7725)]
(451, UNAVAILABLE_FOR_LEGAL_REASONS, "Unavailable For Legal Reasons");
/// 500 Internal Server Error
/// [[RFC7231, Section 6.6.1](https://tools.ietf.org/html/rfc7231#section-6.6.1)]
(500, INTERNAL_SERVER_ERROR, "Internal Server Error");
/// 501 Not Implemented
/// [[RFC7231, Section 6.6.2](https://tools.ietf.org/html/rfc7231#section-6.6.2)]
(501, NOT_IMPLEMENTED, "Not Implemented");
/// 502 Bad Gateway
/// [[RFC7231, Section 6.6.3](https://tools.ietf.org/html/rfc7231#section-6.6.3)]
(502, BAD_GATEWAY, "Bad Gateway");
/// 503 Service Unavailable
/// [[RFC7231, Section 6.6.4](https://tools.ietf.org/html/rfc7231#section-6.6.4)]
(503, SERVICE_UNAVAILABLE, "Service Unavailable");
/// 504 Gateway Timeout
/// [[RFC7231, Section 6.6.5](https://tools.ietf.org/html/rfc7231#section-6.6.5)]
(504, GATEWAY_TIMEOUT, "Gateway Timeout");
/// 505 HTTP Version Not Supported
/// [[RFC7231, Section 6.6.6](https://tools.ietf.org/html/rfc7231#section-6.6.6)]
(505, HTTP_VERSION_NOT_SUPPORTED, "HTTP Version Not Supported");
/// 506 Variant Also Negotiates
/// [[RFC2295](https://tools.ietf.org/html/rfc2295)]
(506, VARIANT_ALSO_NEGOTIATES, "Variant Also Negotiates");
/// 507 Insufficient Storage
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(507, INSUFFICIENT_STORAGE, "Insufficient Storage");
/// 508 Loop Detected
/// [[RFC5842](https://tools.ietf.org/html/rfc5842)]
(508, LOOP_DETECTED, "Loop Detected");
/// 510 Not Extended
/// [[RFC2774](https://tools.ietf.org/html/rfc2774)]
(510, NOT_EXTENDED, "Not Extended");
/// 511 Network Authentication Required
/// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
(511, NETWORK_AUTHENTICATION_REQUIRED, "Network Authentication Required");
}
impl InvalidStatusCode {
fn new() -> InvalidStatusCode {
InvalidStatusCode {
_priv: (),
}
}
}
impl fmt::Debug for InvalidStatusCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("InvalidStatusCode")
// skip _priv noise
.finish()
}
}
impl fmt::Display for InvalidStatusCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.description())
}
}
impl Error for InvalidStatusCode {
fn description(&self) -> &str {
"invalid status code"
}
}
macro_rules! status_code_strs {
($($num:expr,)+) => {
const CODES_AS_STR: [&'static str; 500] = [ $( stringify!($num), )+ ];
}
}
status_code_strs!(
100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259,
260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279,
280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299,
300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319,
320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339,
340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359,
360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379,
380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399,
400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419,
420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439,
440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459,
460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479,
480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499,
500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519,
520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539,
540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559,
560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579,
580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599,
);