typespec/http/status_code.rs
1// cspell:disable
2//
3// The MIT License (MIT)
4//
5// Copyright (c) 2019 Yoshua Wuyts
6// Copyright (c) 2017 http-rs authors
7// Copyright (c) 2020 Jacob Brown
8// Copyright (c) 2016-2018 Michael Tilli (Pyfisch) & `httpdate` contributors
9//
10// Permission is hereby granted, free of charge, to any person obtaining a copy
11// of this software and associated documentation files (the "Software"), to deal
12// in the Software without restriction, including without limitation the rights
13// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14// copies of the Software, and to permit persons to whom the Software is
15// furnished to do so, subject to the following conditions:
16//
17// The above copyright notice and this permission notice shall be included in all
18// copies or substantial portions of the Software.
19//
20// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26// SOFTWARE.
27//
28// Modifications:
29//
30// Copyright (c) Microsoft Corporation. All rights reserved.
31// Licensed under the MIT License.
32
33use std::{
34 borrow::Cow,
35 fmt::{self, Display},
36 ops::Deref,
37};
38
39/// HTTP response status codes.
40///
41/// As defined by [rfc7231 section 6](https://tools.ietf.org/html/rfc7231#section-6).
42/// [Read more](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
43#[repr(u16)]
44#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
45#[non_exhaustive]
46pub enum StatusCode {
47 /// 100 Continue
48 ///
49 /// This interim response indicates that everything so far is OK and that
50 /// the client should continue the request, or ignore the response if
51 /// the request is already finished.
52 Continue = 100,
53
54 /// 101 Switching Protocols
55 ///
56 /// This code is sent in response to an Upgrade request header from the
57 /// client, and indicates the protocol the server is switching to.
58 SwitchingProtocols = 101,
59
60 /// 103 Early Hints
61 ///
62 /// This status code is primarily intended to be used with the Link header,
63 /// letting the user agent start preloading resources while the server
64 /// prepares a response.
65 EarlyHints = 103,
66
67 /// 200 Ok
68 ///
69 /// The request has succeeded
70 Ok = 200,
71
72 /// 201 Created
73 ///
74 /// The request has succeeded and a new resource has been created as a
75 /// result. This is typically the response sent after POST requests, or
76 /// some PUT requests.
77 Created = 201,
78
79 /// 202 Accepted
80 ///
81 /// The request has been received but not yet acted upon. It is
82 /// noncommittal, since there is no way in HTTP to later send an
83 /// asynchronous response indicating the outcome of the request. It is
84 /// intended for cases where another process or server handles the request,
85 /// or for batch processing.
86 Accepted = 202,
87
88 /// 203 Non Authoritative Information
89 ///
90 /// This response code means the returned meta-information is not exactly
91 /// the same as is available from the origin server, but is collected
92 /// from a local or a third-party copy. This is mostly used for mirrors
93 /// or backups of another resource. Except for that specific case, the
94 /// "200 OK" response is preferred to this status.
95 NonAuthoritativeInformation = 203,
96
97 /// 204 No Content
98 ///
99 /// There is no content to send for this request, but the headers may be
100 /// useful. The user-agent may update its cached headers for this
101 /// resource with the new ones.
102 NoContent = 204,
103
104 /// 205 Reset Content
105 ///
106 /// Tells the user-agent to reset the document which sent this request.
107 ResetContent = 205,
108
109 /// 206 Partial Content
110 ///
111 /// This response code is used when the Range header is sent from the client
112 /// to request only part of a resource.
113 PartialContent = 206,
114
115 /// 207 Multi-Status
116 ///
117 /// A Multi-Status response conveys information about
118 /// multiple resources in situations where multiple
119 /// status codes might be appropriate.
120 MultiStatus = 207,
121
122 /// 226 Im Used
123 ///
124 /// The server has fulfilled a GET request for the resource, and the
125 /// response is a representation of the result of one or more
126 /// instance-manipulations applied to the current instance.
127 ImUsed = 226,
128
129 /// 300 Multiple Choice
130 ///
131 /// The request has more than one possible response. The user-agent or user
132 /// should choose one of them. (There is no standardized way of choosing
133 /// one of the responses, but HTML links to the possibilities are
134 /// recommended so the user can pick.)
135 MultipleChoice = 300,
136
137 /// 301 Moved Permanently
138 ///
139 /// The URL of the requested resource has been changed permanently. The new
140 /// URL is given in the response.
141 MovedPermanently = 301,
142
143 /// 302 Found
144 ///
145 /// This response code means that the URI of requested resource has been
146 /// changed temporarily. Further changes in the URI might be made in the
147 /// future. Therefore, this same URI should be used by the client in
148 /// future requests.
149 Found = 302,
150
151 /// 303 See Other
152 ///
153 /// The server sent this response to direct the client to get the requested
154 /// resource at another URI with a GET request.
155 SeeOther = 303,
156
157 /// 304 Not Modified
158 ///
159 /// This is used for caching purposes. It tells the client that the response
160 /// has not been modified, so the client can continue to use the same
161 /// cached version of the response.
162 NotModified = 304,
163
164 /// 307 Temporary Redirect
165 ///
166 /// The server sends this response to direct the client to get the requested
167 /// resource at another URI with same method that was used in the prior
168 /// request. This has the same semantics as the 302 Found HTTP response
169 /// code, with the exception that the user agent must not change the
170 /// HTTP method used: If a POST was used in the first request, a POST must
171 /// be used in the second request.
172 TemporaryRedirect = 307,
173
174 /// 308 Permanent Redirect
175 ///
176 /// This means that the resource is now permanently located at another URI,
177 /// specified by the Location: HTTP Response header. This has the same
178 /// semantics as the 301 Moved Permanently HTTP response code, with the
179 /// exception that the user agent must not change the HTTP method
180 /// used: If a POST was used in the first request, a POST must be used in
181 /// the second request.
182 PermanentRedirect = 308,
183
184 /// 400 Bad Request
185 ///
186 /// The server could not understand the request due to invalid syntax.
187 BadRequest = 400,
188
189 /// 401 Unauthorized
190 ///
191 /// Although the HTTP standard specifies "unauthorized", semantically this
192 /// response means "unauthenticated". That is, the client must
193 /// authenticate itself to get the requested response.
194 Unauthorized = 401,
195
196 /// 402 Payment Required
197 ///
198 /// This response code is reserved for future use. The initial aim for
199 /// creating this code was using it for digital payment systems, however
200 /// this status code is used very rarely and no standard convention
201 /// exists.
202 PaymentRequired = 402,
203
204 /// 403 Forbidden
205 ///
206 /// The client does not have access rights to the content; that is, it is
207 /// unauthorized, so the server is refusing to give the requested
208 /// resource. Unlike 401, the client's identity is known to the server.
209 Forbidden = 403,
210
211 /// 404 Not Found
212 ///
213 /// The server can not find requested resource. In the browser, this means
214 /// the URL is not recognized. In an API, this can also mean that the
215 /// endpoint is valid but the resource itself does not exist. Servers
216 /// may also send this response instead of 403 to hide the existence of
217 /// a resource from an unauthorized client. This response code is probably
218 /// the most famous one due to its frequent occurrence on the web.
219 NotFound = 404,
220
221 /// 405 Method Not Allowed
222 ///
223 /// The request method is known by the server but has been disabled and
224 /// cannot be used. For example, an API may forbid DELETE-ing a
225 /// resource. The two mandatory methods, GET and HEAD, must never be
226 /// disabled and should not return this error code.
227 MethodNotAllowed = 405,
228
229 /// 406 Not Acceptable
230 ///
231 /// This response is sent when the web server, after performing
232 /// server-driven content negotiation, doesn't find any content that
233 /// conforms to the criteria given by the user agent.
234 NotAcceptable = 406,
235
236 /// 407 Proxy Authentication Required
237 ///
238 /// This is similar to 401 but authentication is needed to be done by a
239 /// proxy.
240 ProxyAuthenticationRequired = 407,
241
242 /// 408 Request Timeout
243 ///
244 /// This response is sent on an idle connection by some servers, even
245 /// without any previous request by the client. It means that the server
246 /// would like to shut down this unused connection. This response is
247 /// used much more since some browsers, like Chrome, Firefox 27+,
248 /// or IE9, use HTTP pre-connection mechanisms to speed up surfing. Also
249 /// note that some servers merely shut down the connection without
250 /// sending this message.
251 RequestTimeout = 408,
252
253 /// 409 Conflict
254 ///
255 /// This response is sent when a request conflicts with the current state of
256 /// the server.
257 Conflict = 409,
258
259 /// 410 Gone
260 ///
261 /// This response is sent when the requested content has been permanently
262 /// deleted from server, with no forwarding address. Clients are
263 /// expected to remove their caches and links to the resource. The HTTP
264 /// specification intends this status code to be used for "limited-time,
265 /// promotional services". APIs should not feel compelled to indicate
266 /// resources that have been deleted with this status code.
267 Gone = 410,
268
269 /// 411 Length Required
270 ///
271 /// Server rejected the request because the Content-Length header field is
272 /// not defined and the server requires it.
273 LengthRequired = 411,
274
275 /// 412 Precondition Failed
276 ///
277 /// The client has indicated preconditions in its headers which the server
278 /// does not meet.
279 PreconditionFailed = 412,
280
281 /// 413 Payload Too Large
282 ///
283 /// Request entity is larger than limits defined by server; the server might
284 /// close the connection or return an Retry-After header field.
285 PayloadTooLarge = 413,
286
287 /// 414 URI Too Long
288 ///
289 /// The URI requested by the client is longer than the server is willing to
290 /// interpret.
291 UriTooLong = 414,
292
293 /// 415 Unsupported Media Type
294 ///
295 /// The media format of the requested data is not supported by the server,
296 /// so the server is rejecting the request.
297 UnsupportedMediaType = 415,
298
299 /// 416 Requested Range Not Satisfiable
300 ///
301 /// The range specified by the Range header field in the request can't be
302 /// fulfilled; it's possible that the range is outside the size of the
303 /// target URI's data.
304 RequestedRangeNotSatisfiable = 416,
305
306 /// 417 Expectation Failed
307 ///
308 /// This response code means the expectation indicated by the Expect request
309 /// header field can't be met by the server.
310 ExpectationFailed = 417,
311 ///
312 /// 418 I'm a teapot
313 ///
314 /// The server refuses the attempt to brew coffee with a teapot.
315 ImATeapot = 418,
316
317 /// 421 Misdirected Request
318 ///
319 /// The request was directed at a server that is not able to produce a
320 /// response. This can be sent by a server that is not configured to
321 /// produce responses for the combination of scheme and authority that
322 /// are included in the request URI.
323 MisdirectedRequest = 421,
324
325 /// 422 Unprocessable Entity
326 ///
327 /// The request was well-formed but was unable to be followed due to
328 /// semantic errors.
329 UnprocessableEntity = 422,
330
331 /// 423 Locked
332 ///
333 /// The resource that is being accessed is locked.
334 Locked = 423,
335
336 /// 424 Failed Dependency
337 ///
338 /// The request failed because it depended on another request and that
339 /// request failed (e.g., a PROPPATCH).
340 FailedDependency = 424,
341
342 /// 425 Too Early
343 ///
344 /// Indicates that the server is unwilling to risk processing a request that
345 /// might be replayed.
346 TooEarly = 425,
347
348 /// 426 Upgrade Required
349 ///
350 /// The server refuses to perform the request using the current protocol but
351 /// might be willing to do so after the client upgrades to a different
352 /// protocol. The server sends an Upgrade header in a 426 response to
353 /// indicate the required protocol(s).
354 UpgradeRequired = 426,
355
356 /// 428 Precondition Required
357 ///
358 /// The origin server requires the request to be conditional. This response
359 /// is intended to prevent the 'lost update' problem, where a client
360 /// GETs a resource's state, modifies it, and PUTs it back to the
361 /// server, when meanwhile a third party has modified the state on the
362 /// server, leading to a conflict.
363 PreconditionRequired = 428,
364
365 /// 429 Too Many Requests
366 ///
367 /// The user has sent too many requests in a given amount of time ("rate
368 /// limiting").
369 TooManyRequests = 429,
370
371 /// 431 Request Header Fields Too Large
372 ///
373 /// The server is unwilling to process the request because its header fields
374 /// are too large. The request may be resubmitted after reducing the
375 /// size of the request header fields.
376 RequestHeaderFieldsTooLarge = 431,
377
378 /// 451 Unavailable For Legal Reasons
379 ///
380 /// The user-agent requested a resource that cannot legally be provided,
381 /// such as a web page censored by a government.
382 UnavailableForLegalReasons = 451,
383
384 /// 500 Internal Server Error
385 ///
386 /// The server has encountered a situation it doesn't know how to handle.
387 InternalServerError = 500,
388
389 /// 501 Not Implemented
390 ///
391 /// The request method is not supported by the server and cannot be handled.
392 /// The only methods that servers are required to support (and therefore
393 /// that must not return this code) are GET and HEAD.
394 NotImplemented = 501,
395
396 /// 502 Bad Gateway
397 ///
398 /// This error response means that the server, while working as a gateway to
399 /// get a response needed to handle the request, got an invalid
400 /// response.
401 BadGateway = 502,
402
403 /// 503 Service Unavailable
404 ///
405 /// The server is not ready to handle the request. Common causes are a
406 /// server that is down for maintenance or that is overloaded. Note that
407 /// together with this response, a user-friendly page explaining the
408 /// problem should be sent. This responses should be used for temporary
409 /// conditions and the Retry-After: HTTP header should, if possible, contain
410 /// the estimated time before the recovery of the service. The webmaster
411 /// must also take care about the caching-related headers that are sent
412 /// along with this response, as these temporary condition responses
413 /// should usually not be cached.
414 ServiceUnavailable = 503,
415
416 /// 504 Gateway Timeout
417 ///
418 /// This error response is given when the server is acting as a gateway and
419 /// cannot get a response in time.
420 GatewayTimeout = 504,
421
422 /// 505 HTTP Version Not Supported
423 ///
424 /// The HTTP version used in the request is not supported by the server.
425 HttpVersionNotSupported = 505,
426
427 /// 506 Variant Also Negotiates
428 ///
429 /// The server has an internal configuration error: the chosen variant
430 /// resource is configured to engage in transparent content negotiation
431 /// itself, and is therefore not a proper end point in the negotiation
432 /// process.
433 VariantAlsoNegotiates = 506,
434
435 /// 507 Insufficient Storage
436 ///
437 /// The server is unable to store the representation needed to complete the
438 /// request.
439 InsufficientStorage = 507,
440
441 /// 508 Loop Detected
442 ///
443 /// The server detected an infinite loop while processing the request.
444 LoopDetected = 508,
445
446 /// 510 Not Extended
447 ///
448 /// Further extensions to the request are required for the server to fulfil
449 /// it.
450 NotExtended = 510,
451
452 /// 511 Network Authentication Required
453 ///
454 /// The 511 status code indicates that the client needs to authenticate to
455 /// gain network access.
456 NetworkAuthenticationRequired = 511,
457
458 /// A status code not defined by `StatusCode`.
459 UnknownValue(u16),
460}
461
462impl StatusCode {
463 /// Returns `true` if the status code is `1xx` range.
464 ///
465 /// If this returns `true` it indicates that the request was received,
466 /// continuing process.
467 pub fn is_informational(&self) -> bool {
468 let num: u16 = (*self).into();
469 (100..200).contains(&num)
470 }
471
472 /// Returns `true` if the status code is the `2xx` range.
473 ///
474 /// If this returns `true` it indicates that the request was successfully
475 /// received, understood, and accepted.
476 pub fn is_success(&self) -> bool {
477 let num: u16 = (*self).into();
478 (200..300).contains(&num)
479 }
480
481 /// Returns `true` if the status code is the `3xx` range.
482 ///
483 /// If this returns `true` it indicates that further action needs to be
484 /// taken in order to complete the request.
485 pub fn is_redirection(&self) -> bool {
486 let num: u16 = (*self).into();
487 (300..400).contains(&num)
488 }
489
490 /// Returns `true` if the status code is the `4xx` range.
491 ///
492 /// If this returns `true` it indicates that the request contains bad syntax
493 /// or cannot be fulfilled.
494 pub fn is_client_error(&self) -> bool {
495 let num: u16 = (*self).into();
496 (400..500).contains(&num)
497 }
498
499 /// Returns `true` if the status code is the `5xx` range.
500 ///
501 /// If this returns `true` it indicates that the server failed to fulfill an
502 /// apparently valid request.
503 pub fn is_server_error(&self) -> bool {
504 let num: u16 = (*self).into();
505 (500..600).contains(&num)
506 }
507
508 /// The canonical reason for a given status code
509 pub fn canonical_reason(&self) -> Cow<'static, str> {
510 match self {
511 StatusCode::Continue => Cow::Borrowed("Continue"),
512 StatusCode::SwitchingProtocols => Cow::Borrowed("Switching Protocols"),
513 StatusCode::EarlyHints => Cow::Borrowed("Early Hints"),
514 StatusCode::Ok => Cow::Borrowed("OK"),
515 StatusCode::Created => Cow::Borrowed("Created"),
516 StatusCode::Accepted => Cow::Borrowed("Accepted"),
517 StatusCode::NonAuthoritativeInformation => {
518 Cow::Borrowed("Non Authoritative Information")
519 }
520 StatusCode::NoContent => Cow::Borrowed("No Content"),
521 StatusCode::ResetContent => Cow::Borrowed("Reset Content"),
522 StatusCode::PartialContent => Cow::Borrowed("Partial Content"),
523 StatusCode::MultiStatus => Cow::Borrowed("Multi-Status"),
524 StatusCode::ImUsed => Cow::Borrowed("Im Used"),
525 StatusCode::MultipleChoice => Cow::Borrowed("Multiple Choice"),
526 StatusCode::MovedPermanently => Cow::Borrowed("Moved Permanently"),
527 StatusCode::Found => Cow::Borrowed("Found"),
528 StatusCode::SeeOther => Cow::Borrowed("See Other"),
529 StatusCode::NotModified => Cow::Borrowed("Modified"),
530 StatusCode::TemporaryRedirect => Cow::Borrowed("Temporary Redirect"),
531 StatusCode::PermanentRedirect => Cow::Borrowed("Permanent Redirect"),
532 StatusCode::BadRequest => Cow::Borrowed("Bad Request"),
533 StatusCode::Unauthorized => Cow::Borrowed("Unauthorized"),
534 StatusCode::PaymentRequired => Cow::Borrowed("Payment Required"),
535 StatusCode::Forbidden => Cow::Borrowed("Forbidden"),
536 StatusCode::NotFound => Cow::Borrowed("Not Found"),
537 StatusCode::MethodNotAllowed => Cow::Borrowed("Method Not Allowed"),
538 StatusCode::NotAcceptable => Cow::Borrowed("Not Acceptable"),
539 StatusCode::ProxyAuthenticationRequired => {
540 Cow::Borrowed("Proxy Authentication Required")
541 }
542 StatusCode::RequestTimeout => Cow::Borrowed("Request Timeout"),
543 StatusCode::Conflict => Cow::Borrowed("Conflict"),
544 StatusCode::Gone => Cow::Borrowed("Gone"),
545 StatusCode::LengthRequired => Cow::Borrowed("Length Required"),
546 StatusCode::PreconditionFailed => Cow::Borrowed("Precondition Failed"),
547 StatusCode::PayloadTooLarge => Cow::Borrowed("Payload Too Large"),
548 StatusCode::UriTooLong => Cow::Borrowed("URI Too Long"),
549 StatusCode::UnsupportedMediaType => Cow::Borrowed("Unsupported Media Type"),
550 StatusCode::RequestedRangeNotSatisfiable => {
551 Cow::Borrowed("Requested Range Not Satisfiable")
552 }
553 StatusCode::ExpectationFailed => Cow::Borrowed("Expectation Failed"),
554 StatusCode::ImATeapot => Cow::Borrowed("I'm a teapot"),
555 StatusCode::MisdirectedRequest => Cow::Borrowed("Misdirected Request"),
556 StatusCode::UnprocessableEntity => Cow::Borrowed("Unprocessable Entity"),
557 StatusCode::Locked => Cow::Borrowed("Locked"),
558 StatusCode::FailedDependency => Cow::Borrowed("Failed Dependency"),
559 StatusCode::TooEarly => Cow::Borrowed("Too Early"),
560 StatusCode::UpgradeRequired => Cow::Borrowed("Upgrade Required"),
561 StatusCode::PreconditionRequired => Cow::Borrowed("Precondition Required"),
562 StatusCode::TooManyRequests => Cow::Borrowed("Too Many Requests"),
563 StatusCode::RequestHeaderFieldsTooLarge => {
564 Cow::Borrowed("Request Header Fields Too Large")
565 }
566 StatusCode::UnavailableForLegalReasons => {
567 Cow::Borrowed("Unavailable For Legal Reasons")
568 }
569 StatusCode::InternalServerError => Cow::Borrowed("Internal Server Error"),
570 StatusCode::NotImplemented => Cow::Borrowed("Not Implemented"),
571 StatusCode::BadGateway => Cow::Borrowed("Bad Gateway"),
572 StatusCode::ServiceUnavailable => Cow::Borrowed("Service Unavailable"),
573 StatusCode::GatewayTimeout => Cow::Borrowed("Gateway Timeout"),
574 StatusCode::HttpVersionNotSupported => Cow::Borrowed("HTTP Version Not Supported"),
575 StatusCode::VariantAlsoNegotiates => Cow::Borrowed("Variant Also Negotiates"),
576 StatusCode::InsufficientStorage => Cow::Borrowed("Insufficient Storage"),
577 StatusCode::LoopDetected => Cow::Borrowed("Loop Detected"),
578 StatusCode::NotExtended => Cow::Borrowed("Not Extended"),
579 StatusCode::NetworkAuthenticationRequired => {
580 Cow::Borrowed("Network Authentication Required")
581 }
582 StatusCode::UnknownValue(code) => Cow::Owned(format!("HTTP {code}")),
583 }
584 }
585}
586
587#[cfg(feature = "json")]
588mod serde {
589 use super::StatusCode;
590 use ::serde::{
591 de::{Error as DeError, Visitor},
592 Deserialize, Deserializer, Serialize, Serializer,
593 };
594 use std::fmt;
595
596 impl Serialize for StatusCode {
597 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
598 where
599 S: Serializer,
600 {
601 let value: u16 = **self;
602 serializer.serialize_u16(value)
603 }
604 }
605
606 struct StatusCodeU16Visitor;
607
608 impl Visitor<'_> for StatusCodeU16Visitor {
609 type Value = StatusCode;
610
611 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
612 write!(formatter, "a u16 representing the status code")
613 }
614
615 fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
616 where
617 E: DeError,
618 {
619 self.visit_u16(v as u16)
620 }
621
622 fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
623 where
624 E: DeError,
625 {
626 self.visit_u16(v as u16)
627 }
628
629 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
630 where
631 E: DeError,
632 {
633 self.visit_u16(v as u16)
634 }
635
636 fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
637 where
638 E: DeError,
639 {
640 Ok(StatusCode::from(v))
641 }
642
643 fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
644 where
645 E: DeError,
646 {
647 self.visit_u16(v as u16)
648 }
649
650 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
651 where
652 E: DeError,
653 {
654 self.visit_u16(v as u16)
655 }
656 }
657
658 impl<'de> Deserialize<'de> for StatusCode {
659 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
660 where
661 D: Deserializer<'de>,
662 {
663 deserializer.deserialize_any(StatusCodeU16Visitor)
664 }
665 }
666}
667
668impl Deref for StatusCode {
669 type Target = u16;
670
671 fn deref(&self) -> &Self::Target {
672 if let Self::UnknownValue(code) = self {
673 return code;
674 }
675
676 unsafe { std::mem::transmute_copy(&self) }
677 }
678}
679
680impl From<StatusCode> for u16 {
681 fn from(code: StatusCode) -> u16 {
682 match code {
683 StatusCode::UnknownValue(code) => code,
684 _ => *code,
685 }
686 }
687}
688
689impl From<u16> for StatusCode {
690 fn from(num: u16) -> Self {
691 match num {
692 100 => StatusCode::Continue,
693 101 => StatusCode::SwitchingProtocols,
694 103 => StatusCode::EarlyHints,
695 200 => StatusCode::Ok,
696 201 => StatusCode::Created,
697 202 => StatusCode::Accepted,
698 203 => StatusCode::NonAuthoritativeInformation,
699 204 => StatusCode::NoContent,
700 205 => StatusCode::ResetContent,
701 206 => StatusCode::PartialContent,
702 207 => StatusCode::MultiStatus,
703 226 => StatusCode::ImUsed,
704 300 => StatusCode::MultipleChoice,
705 301 => StatusCode::MovedPermanently,
706 302 => StatusCode::Found,
707 303 => StatusCode::SeeOther,
708 304 => StatusCode::NotModified,
709 307 => StatusCode::TemporaryRedirect,
710 308 => StatusCode::PermanentRedirect,
711 400 => StatusCode::BadRequest,
712 401 => StatusCode::Unauthorized,
713 402 => StatusCode::PaymentRequired,
714 403 => StatusCode::Forbidden,
715 404 => StatusCode::NotFound,
716 405 => StatusCode::MethodNotAllowed,
717 406 => StatusCode::NotAcceptable,
718 407 => StatusCode::ProxyAuthenticationRequired,
719 408 => StatusCode::RequestTimeout,
720 409 => StatusCode::Conflict,
721 410 => StatusCode::Gone,
722 411 => StatusCode::LengthRequired,
723 412 => StatusCode::PreconditionFailed,
724 413 => StatusCode::PayloadTooLarge,
725 414 => StatusCode::UriTooLong,
726 415 => StatusCode::UnsupportedMediaType,
727 416 => StatusCode::RequestedRangeNotSatisfiable,
728 417 => StatusCode::ExpectationFailed,
729 418 => StatusCode::ImATeapot,
730 421 => StatusCode::MisdirectedRequest,
731 422 => StatusCode::UnprocessableEntity,
732 423 => StatusCode::Locked,
733 424 => StatusCode::FailedDependency,
734 425 => StatusCode::TooEarly,
735 426 => StatusCode::UpgradeRequired,
736 428 => StatusCode::PreconditionRequired,
737 429 => StatusCode::TooManyRequests,
738 431 => StatusCode::RequestHeaderFieldsTooLarge,
739 451 => StatusCode::UnavailableForLegalReasons,
740 500 => StatusCode::InternalServerError,
741 501 => StatusCode::NotImplemented,
742 502 => StatusCode::BadGateway,
743 503 => StatusCode::ServiceUnavailable,
744 504 => StatusCode::GatewayTimeout,
745 505 => StatusCode::HttpVersionNotSupported,
746 506 => StatusCode::VariantAlsoNegotiates,
747 507 => StatusCode::InsufficientStorage,
748 508 => StatusCode::LoopDetected,
749 510 => StatusCode::NotExtended,
750 511 => StatusCode::NetworkAuthenticationRequired,
751 _ => StatusCode::UnknownValue(num),
752 }
753 }
754}
755
756impl PartialEq<StatusCode> for u16 {
757 fn eq(&self, other: &StatusCode) -> bool {
758 self == other as &u16
759 }
760}
761
762impl PartialEq<u16> for StatusCode {
763 fn eq(&self, other: &u16) -> bool {
764 self as &u16 == other
765 }
766}
767
768impl Display for StatusCode {
769 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
770 write!(f, "{}", *(self as &u16))
771 }
772}
773
774#[cfg(test)]
775mod test {
776 use super::StatusCode;
777
778 #[test]
779 fn status_code_from() {
780 assert_eq!(StatusCode::from(204), 204);
781 assert_eq!(StatusCode::from(700), 700);
782 }
783
784 #[test]
785 fn display() {
786 assert_eq!(StatusCode::from(204).to_string(), "204");
787 assert_eq!(StatusCode::from(700).to_string(), "700");
788 }
789
790 #[test]
791 fn canonical_reason() {
792 assert_eq!(StatusCode::from(204).canonical_reason(), "No Content");
793 assert_eq!(StatusCode::from(700).canonical_reason(), "HTTP 700");
794 }
795
796 #[cfg(feature = "json")]
797 #[test]
798 fn serde_as_u16() -> Result<(), serde_json::Error> {
799 let status_code: StatusCode = serde_json::from_str("202")?;
800 assert_eq!(StatusCode::Accepted, status_code);
801 assert_eq!(
802 Some(202),
803 serde_json::to_value(StatusCode::Accepted)?.as_u64()
804 );
805 Ok(())
806 }
807}