1use std::fmt;
3use std::cmp::Ordering;
4
5#[derive(Debug, Hash)]
32pub enum StatusCode {
33 Continue,
36 SwitchingProtocols,
39 Processing,
42
43 Ok,
46 Created,
49 Accepted,
52 NonAuthoritativeInformation,
55 NoContent,
58 ResetContent,
61 PartialContent,
64 MultiStatus,
67 AlreadyReported,
70
71 ImUsed,
74
75 MultipleChoices,
78 MovedPermanently,
81 Found,
84 SeeOther,
87 NotModified,
90 UseProxy,
93 TemporaryRedirect,
96 PermanentRedirect,
99
100 BadRequest,
103 Unauthorized,
106 PaymentRequired,
109 Forbidden,
112 NotFound,
115 MethodNotAllowed,
118 NotAcceptable,
121 ProxyAuthenticationRequired,
124 RequestTimeout,
127 Conflict,
130 Gone,
133 LengthRequired,
136 PreconditionFailed,
139 PayloadTooLarge,
142 UriTooLong,
145 UnsupportedMediaType,
148 RangeNotSatisfiable,
151 ExpectationFailed,
154 ImATeapot,
157
158 MisdirectedRequest,
161 UnprocessableEntity,
164 Locked,
167 FailedDependency,
170
171 UpgradeRequired,
174
175 PreconditionRequired,
178 TooManyRequests,
181
182 RequestHeaderFieldsTooLarge,
185
186 UnavailableForLegalReasons,
189
190 InternalServerError,
193 NotImplemented,
196 BadGateway,
199 ServiceUnavailable,
202 GatewayTimeout,
205 HttpVersionNotSupported,
208 VariantAlsoNegotiates,
211 InsufficientStorage,
214 LoopDetected,
217
218 NotExtended,
221 NetworkAuthenticationRequired,
224
225 Unregistered(u16),
228}
229
230impl StatusCode {
231
232 #[doc(hidden)]
233 pub fn from_u16(n: u16) -> StatusCode {
234 match n {
235 100 => StatusCode::Continue,
236 101 => StatusCode::SwitchingProtocols,
237 102 => StatusCode::Processing,
238 200 => StatusCode::Ok,
239 201 => StatusCode::Created,
240 202 => StatusCode::Accepted,
241 203 => StatusCode::NonAuthoritativeInformation,
242 204 => StatusCode::NoContent,
243 205 => StatusCode::ResetContent,
244 206 => StatusCode::PartialContent,
245 207 => StatusCode::MultiStatus,
246 208 => StatusCode::AlreadyReported,
247 226 => StatusCode::ImUsed,
248 300 => StatusCode::MultipleChoices,
249 301 => StatusCode::MovedPermanently,
250 302 => StatusCode::Found,
251 303 => StatusCode::SeeOther,
252 304 => StatusCode::NotModified,
253 305 => StatusCode::UseProxy,
254 307 => StatusCode::TemporaryRedirect,
255 308 => StatusCode::PermanentRedirect,
256 400 => StatusCode::BadRequest,
257 401 => StatusCode::Unauthorized,
258 402 => StatusCode::PaymentRequired,
259 403 => StatusCode::Forbidden,
260 404 => StatusCode::NotFound,
261 405 => StatusCode::MethodNotAllowed,
262 406 => StatusCode::NotAcceptable,
263 407 => StatusCode::ProxyAuthenticationRequired,
264 408 => StatusCode::RequestTimeout,
265 409 => StatusCode::Conflict,
266 410 => StatusCode::Gone,
267 411 => StatusCode::LengthRequired,
268 412 => StatusCode::PreconditionFailed,
269 413 => StatusCode::PayloadTooLarge,
270 414 => StatusCode::UriTooLong,
271 415 => StatusCode::UnsupportedMediaType,
272 416 => StatusCode::RangeNotSatisfiable,
273 417 => StatusCode::ExpectationFailed,
274 418 => StatusCode::ImATeapot,
275 421 => StatusCode::MisdirectedRequest,
276 422 => StatusCode::UnprocessableEntity,
277 423 => StatusCode::Locked,
278 424 => StatusCode::FailedDependency,
279 426 => StatusCode::UpgradeRequired,
280 428 => StatusCode::PreconditionRequired,
281 429 => StatusCode::TooManyRequests,
282 431 => StatusCode::RequestHeaderFieldsTooLarge,
283 451 => StatusCode::UnavailableForLegalReasons,
284 500 => StatusCode::InternalServerError,
285 501 => StatusCode::NotImplemented,
286 502 => StatusCode::BadGateway,
287 503 => StatusCode::ServiceUnavailable,
288 504 => StatusCode::GatewayTimeout,
289 505 => StatusCode::HttpVersionNotSupported,
290 506 => StatusCode::VariantAlsoNegotiates,
291 507 => StatusCode::InsufficientStorage,
292 508 => StatusCode::LoopDetected,
293 510 => StatusCode::NotExtended,
294 511 => StatusCode::NetworkAuthenticationRequired,
295 _ => StatusCode::Unregistered(n),
296 }
297 }
298
299 #[doc(hidden)]
300 pub fn to_u16(&self) -> u16 {
301 match *self {
302 StatusCode::Continue => 100,
303 StatusCode::SwitchingProtocols => 101,
304 StatusCode::Processing => 102,
305 StatusCode::Ok => 200,
306 StatusCode::Created => 201,
307 StatusCode::Accepted => 202,
308 StatusCode::NonAuthoritativeInformation => 203,
309 StatusCode::NoContent => 204,
310 StatusCode::ResetContent => 205,
311 StatusCode::PartialContent => 206,
312 StatusCode::MultiStatus => 207,
313 StatusCode::AlreadyReported => 208,
314 StatusCode::ImUsed => 226,
315 StatusCode::MultipleChoices => 300,
316 StatusCode::MovedPermanently => 301,
317 StatusCode::Found => 302,
318 StatusCode::SeeOther => 303,
319 StatusCode::NotModified => 304,
320 StatusCode::UseProxy => 305,
321 StatusCode::TemporaryRedirect => 307,
322 StatusCode::PermanentRedirect => 308,
323 StatusCode::BadRequest => 400,
324 StatusCode::Unauthorized => 401,
325 StatusCode::PaymentRequired => 402,
326 StatusCode::Forbidden => 403,
327 StatusCode::NotFound => 404,
328 StatusCode::MethodNotAllowed => 405,
329 StatusCode::NotAcceptable => 406,
330 StatusCode::ProxyAuthenticationRequired => 407,
331 StatusCode::RequestTimeout => 408,
332 StatusCode::Conflict => 409,
333 StatusCode::Gone => 410,
334 StatusCode::LengthRequired => 411,
335 StatusCode::PreconditionFailed => 412,
336 StatusCode::PayloadTooLarge => 413,
337 StatusCode::UriTooLong => 414,
338 StatusCode::UnsupportedMediaType => 415,
339 StatusCode::RangeNotSatisfiable => 416,
340 StatusCode::ExpectationFailed => 417,
341 StatusCode::ImATeapot => 418,
342 StatusCode::MisdirectedRequest => 421,
343 StatusCode::UnprocessableEntity => 422,
344 StatusCode::Locked => 423,
345 StatusCode::FailedDependency => 424,
346 StatusCode::UpgradeRequired => 426,
347 StatusCode::PreconditionRequired => 428,
348 StatusCode::TooManyRequests => 429,
349 StatusCode::RequestHeaderFieldsTooLarge => 431,
350 StatusCode::UnavailableForLegalReasons => 451,
351 StatusCode::InternalServerError => 500,
352 StatusCode::NotImplemented => 501,
353 StatusCode::BadGateway => 502,
354 StatusCode::ServiceUnavailable => 503,
355 StatusCode::GatewayTimeout => 504,
356 StatusCode::HttpVersionNotSupported => 505,
357 StatusCode::VariantAlsoNegotiates => 506,
358 StatusCode::InsufficientStorage => 507,
359 StatusCode::LoopDetected => 508,
360 StatusCode::NotExtended => 510,
361 StatusCode::NetworkAuthenticationRequired => 511,
362 StatusCode::Unregistered(n) => n,
363 }
364 }
365
366 pub fn canonical_reason(&self) -> Option<&'static str> {
377 match *self {
378 StatusCode::Continue => Some("Continue"),
379 StatusCode::SwitchingProtocols => Some("Switching Protocols"),
380 StatusCode::Processing => Some("Processing"),
381
382 StatusCode::Ok => Some("OK"),
383 StatusCode::Created => Some("Created"),
384 StatusCode::Accepted => Some("Accepted"),
385 StatusCode::NonAuthoritativeInformation => Some("Non-Authoritative Information"),
386 StatusCode::NoContent => Some("No Content"),
387 StatusCode::ResetContent => Some("Reset Content"),
388 StatusCode::PartialContent => Some("Partial Content"),
389 StatusCode::MultiStatus => Some("Multi-Status"),
390 StatusCode::AlreadyReported => Some("Already Reported"),
391
392 StatusCode::ImUsed => Some("IM Used"),
393
394 StatusCode::MultipleChoices => Some("Multiple Choices"),
395 StatusCode::MovedPermanently => Some("Moved Permanently"),
396 StatusCode::Found => Some("Found"),
397 StatusCode::SeeOther => Some("See Other"),
398 StatusCode::NotModified => Some("Not Modified"),
399 StatusCode::UseProxy => Some("Use Proxy"),
400
401 StatusCode::TemporaryRedirect => Some("Temporary Redirect"),
402 StatusCode::PermanentRedirect => Some("Permanent Redirect"),
403
404 StatusCode::BadRequest => Some("Bad Request"),
405 StatusCode::Unauthorized => Some("Unauthorized"),
406 StatusCode::PaymentRequired => Some("Payment Required"),
407 StatusCode::Forbidden => Some("Forbidden"),
408 StatusCode::NotFound => Some("Not Found"),
409 StatusCode::MethodNotAllowed => Some("Method Not Allowed"),
410 StatusCode::NotAcceptable => Some("Not Acceptable"),
411 StatusCode::ProxyAuthenticationRequired => Some("Proxy Authentication Required"),
412 StatusCode::RequestTimeout => Some("Request Timeout"),
413 StatusCode::Conflict => Some("Conflict"),
414 StatusCode::Gone => Some("Gone"),
415 StatusCode::LengthRequired => Some("Length Required"),
416 StatusCode::PreconditionFailed => Some("Precondition Failed"),
417 StatusCode::PayloadTooLarge => Some("Payload Too Large"),
418 StatusCode::UriTooLong => Some("URI Too Long"),
419 StatusCode::UnsupportedMediaType => Some("Unsupported Media Type"),
420 StatusCode::RangeNotSatisfiable => Some("Range Not Satisfiable"),
421 StatusCode::ExpectationFailed => Some("Expectation Failed"),
422 StatusCode::ImATeapot => Some("I'm a teapot"),
423
424 StatusCode::MisdirectedRequest => Some("Misdirected Request"),
425 StatusCode::UnprocessableEntity => Some("Unprocessable Entity"),
426 StatusCode::Locked => Some("Locked"),
427 StatusCode::FailedDependency => Some("Failed Dependency"),
428
429 StatusCode::UpgradeRequired => Some("Upgrade Required"),
430
431 StatusCode::PreconditionRequired => Some("Precondition Required"),
432 StatusCode::TooManyRequests => Some("Too Many Requests"),
433
434 StatusCode::RequestHeaderFieldsTooLarge => Some("Request Header Fields Too Large"),
435
436 StatusCode::UnavailableForLegalReasons => Some("Unavailable For Legal Reasons"),
437
438 StatusCode::InternalServerError => Some("Internal Server Error"),
439 StatusCode::NotImplemented => Some("Not Implemented"),
440 StatusCode::BadGateway => Some("Bad Gateway"),
441 StatusCode::ServiceUnavailable => Some("Service Unavailable"),
442 StatusCode::GatewayTimeout => Some("Gateway Timeout"),
443 StatusCode::HttpVersionNotSupported => Some("HTTP Version Not Supported"),
444 StatusCode::VariantAlsoNegotiates => Some("Variant Also Negotiates"),
445 StatusCode::InsufficientStorage => Some("Insufficient Storage"),
446 StatusCode::LoopDetected => Some("Loop Detected"),
447
448 StatusCode::NotExtended => Some("Not Extended"),
449 StatusCode::NetworkAuthenticationRequired => Some("Network Authentication Required"),
450 StatusCode::Unregistered(..) => None
451 }
452 }
453
454 pub fn class(&self) -> StatusClass {
456 match self.to_u16() {
457 100...199 => StatusClass::Informational,
458 200...299 => StatusClass::Success,
459 300...399 => StatusClass::Redirection,
460 400...499 => StatusClass::ClientError,
461 500...599 => StatusClass::ServerError,
462 _ => StatusClass::NoClass,
463 }
464 }
465
466 pub fn is_informational(&self) -> bool {
468 self.class() == StatusClass::Informational
469 }
470
471 pub fn is_success(&self) -> bool {
473 self.class() == StatusClass::Success
474 }
475
476 pub fn is_redirection(&self) -> bool {
478 self.class() == StatusClass::Redirection
479 }
480
481 pub fn is_client_error(&self) -> bool {
483 self.class() == StatusClass::ClientError
484 }
485
486 pub fn is_server_error(&self) -> bool {
488 self.class() == StatusClass::ServerError
489 }
490
491 pub fn is_strange_status(&self) -> bool {
493 self.class() == StatusClass::NoClass
494 }
495}
496
497impl Copy for StatusCode {}
498
499impl fmt::Display for StatusCode {
508 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
509 write!(f, "{} {}", self.to_u16(),
510 self.canonical_reason().unwrap_or("<unknown status code>"))
511 }
512}
513
514impl PartialEq for StatusCode {
515 #[inline]
516 fn eq(&self, other: &StatusCode) -> bool {
517 self.to_u16() == other.to_u16()
518 }
519}
520
521impl Eq for StatusCode {}
522
523impl Clone for StatusCode {
524 #[inline]
525 fn clone(&self) -> StatusCode {
526 *self
527 }
528}
529
530impl PartialOrd for StatusCode {
531 #[inline]
532 fn partial_cmp(&self, other: &StatusCode) -> Option<Ordering> {
533 self.to_u16().partial_cmp(&(other.to_u16()))
534 }
535}
536
537impl Ord for StatusCode {
538 #[inline]
539 fn cmp(&self, other: &StatusCode) -> Ordering {
540 if *self < *other {
541 Ordering::Less
542 } else if *self > *other {
543 Ordering::Greater
544 } else {
545 Ordering::Equal
546 }
547 }
548}
549
550#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
576pub enum StatusClass {
577 Informational,
579
580 Success,
582
583 Redirection,
585
586 ClientError,
588
589 ServerError,
591
592 NoClass,
594}
595
596impl StatusClass {
597 pub fn default_code(&self) -> StatusCode {
645 match *self {
646 StatusClass::Informational => StatusCode::Continue,
647 StatusClass::Success => StatusCode::Ok,
648 StatusClass::Redirection => StatusCode::MultipleChoices,
649 StatusClass::ClientError => StatusCode::BadRequest,
650 StatusClass::ServerError => StatusCode::InternalServerError,
651 StatusClass::NoClass => StatusCode::Ok,
652 }
653 }
654}
655
656#[cfg(test)]
657mod tests {
658 use super::*;
659 use super::StatusCode::*;
660
661 fn validate(num: u16, status_code: StatusCode, default_code: StatusCode, reason: Option<&str>) {
667 assert_eq!(StatusCode::from_u16(num), status_code);
668 assert_eq!(status_code.to_u16(), num);
669 assert_eq!(status_code.class().default_code(), default_code);
670 assert_eq!(status_code.canonical_reason(), reason);
671 }
672
673 #[test]
674 fn test_status_code() {
675 validate(99, Unregistered(99), Ok, None);
676
677 validate(100, Continue, Continue, Some("Continue"));
678 validate(101, SwitchingProtocols, Continue, Some("Switching Protocols"));
679 validate(102, Processing, Continue, Some("Processing"));
680
681 validate(200, Ok, Ok, Some("OK"));
682 validate(201, Created, Ok, Some("Created"));
683 validate(202, Accepted, Ok, Some("Accepted"));
684 validate(203, NonAuthoritativeInformation, Ok, Some("Non-Authoritative Information"));
685 validate(204, NoContent, Ok, Some("No Content"));
686 validate(205, ResetContent, Ok, Some("Reset Content"));
687 validate(206, PartialContent, Ok, Some("Partial Content"));
688 validate(207, MultiStatus, Ok, Some("Multi-Status"));
689 validate(208, AlreadyReported, Ok, Some("Already Reported"));
690 validate(226, ImUsed, Ok, Some("IM Used"));
691
692 validate(300, MultipleChoices, MultipleChoices, Some("Multiple Choices"));
693 validate(301, MovedPermanently, MultipleChoices, Some("Moved Permanently"));
694 validate(302, Found, MultipleChoices, Some("Found"));
695 validate(303, SeeOther, MultipleChoices, Some("See Other"));
696 validate(304, NotModified, MultipleChoices, Some("Not Modified"));
697 validate(305, UseProxy, MultipleChoices, Some("Use Proxy"));
698 validate(307, TemporaryRedirect, MultipleChoices, Some("Temporary Redirect"));
699 validate(308, PermanentRedirect, MultipleChoices, Some("Permanent Redirect"));
700
701 validate(400, BadRequest, BadRequest, Some("Bad Request"));
702 validate(401, Unauthorized, BadRequest, Some("Unauthorized"));
703 validate(402, PaymentRequired, BadRequest, Some("Payment Required"));
704 validate(403, Forbidden, BadRequest, Some("Forbidden"));
705 validate(404, NotFound, BadRequest, Some("Not Found"));
706 validate(405, MethodNotAllowed, BadRequest, Some("Method Not Allowed"));
707 validate(406, NotAcceptable, BadRequest, Some("Not Acceptable"));
708 validate(407, ProxyAuthenticationRequired, BadRequest,
709 Some("Proxy Authentication Required"));
710 validate(408, RequestTimeout, BadRequest, Some("Request Timeout"));
711 validate(409, Conflict, BadRequest, Some("Conflict"));
712 validate(410, Gone, BadRequest, Some("Gone"));
713 validate(411, LengthRequired, BadRequest, Some("Length Required"));
714 validate(412, PreconditionFailed, BadRequest, Some("Precondition Failed"));
715 validate(413, PayloadTooLarge, BadRequest, Some("Payload Too Large"));
716 validate(414, UriTooLong, BadRequest, Some("URI Too Long"));
717 validate(415, UnsupportedMediaType, BadRequest, Some("Unsupported Media Type"));
718 validate(416, RangeNotSatisfiable, BadRequest, Some("Range Not Satisfiable"));
719 validate(417, ExpectationFailed, BadRequest, Some("Expectation Failed"));
720 validate(418, ImATeapot, BadRequest, Some("I'm a teapot"));
721 validate(421, MisdirectedRequest, BadRequest, Some("Misdirected Request"));
722 validate(422, UnprocessableEntity, BadRequest, Some("Unprocessable Entity"));
723 validate(423, Locked, BadRequest, Some("Locked"));
724 validate(424, FailedDependency, BadRequest, Some("Failed Dependency"));
725 validate(426, UpgradeRequired, BadRequest, Some("Upgrade Required"));
726 validate(428, PreconditionRequired, BadRequest, Some("Precondition Required"));
727 validate(429, TooManyRequests, BadRequest, Some("Too Many Requests"));
728 validate(431, RequestHeaderFieldsTooLarge, BadRequest,
729 Some("Request Header Fields Too Large"));
730 validate(451, UnavailableForLegalReasons, BadRequest,
731 Some("Unavailable For Legal Reasons"));
732
733 validate(500, InternalServerError, InternalServerError, Some("Internal Server Error"));
734 validate(501, NotImplemented, InternalServerError, Some("Not Implemented"));
735 validate(502, BadGateway, InternalServerError, Some("Bad Gateway"));
736 validate(503, ServiceUnavailable, InternalServerError, Some("Service Unavailable"));
737 validate(504, GatewayTimeout, InternalServerError, Some("Gateway Timeout"));
738 validate(505, HttpVersionNotSupported, InternalServerError,
739 Some("HTTP Version Not Supported"));
740 validate(506, VariantAlsoNegotiates, InternalServerError, Some("Variant Also Negotiates"));
741 validate(507, InsufficientStorage, InternalServerError, Some("Insufficient Storage"));
742 validate(508, LoopDetected, InternalServerError, Some("Loop Detected"));
743 validate(510, NotExtended, InternalServerError, Some("Not Extended"));
744 validate(511, NetworkAuthenticationRequired, InternalServerError,
745 Some("Network Authentication Required"));
746
747 }
748}