trillium_http/
status.rs

1// originally from https://github.com/http-rs/http-types/blob/main/src/status_code.rs
2use crate::Error;
3use std::fmt::{self, Debug, Display};
4
5/// HTTP response status codes.
6///
7/// As defined by [rfc7231 section 6](https://tools.ietf.org/html/rfc7231#section-6).
8/// [Read more](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
9#[repr(u16)]
10#[derive(Clone, Copy, Eq, PartialEq, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub enum Status {
13    /// 100 Continue
14    ///
15    /// This interim response indicates that everything so far is OK and that
16    /// the client should continue the request, or ignore the response if
17    /// the request is already finished.
18    Continue = 100,
19
20    /// 101 Switching Protocols
21    ///
22    /// This code is sent in response to an Upgrade request header from the
23    /// client, and indicates the protocol the server is switching to.
24    SwitchingProtocols = 101,
25
26    /// 103 Early Hints
27    ///
28    /// This status code is primarily intended to be used with the Link header,
29    /// letting the user agent start preloading resources while the server
30    /// prepares a response.
31    EarlyHints = 103,
32
33    /// 200 Ok
34    ///
35    /// The request has succeeded
36    Ok = 200,
37
38    /// 201 Created
39    ///
40    /// The request has succeeded and a new resource has been created as a
41    /// result. This is typically the response sent after POST requests, or
42    /// some PUT requests.
43    Created = 201,
44
45    /// 202 Accepted
46    ///
47    /// The request has been received but not yet acted upon. It is
48    /// noncommittal, since there is no way in HTTP to later send an
49    /// asynchronous response indicating the outcome of the request. It is
50    /// intended for cases where another process or server handles the request,
51    /// or for batch processing.
52    Accepted = 202,
53
54    /// 203 Non Authoritative Information
55    ///
56    /// This response code means the returned meta-information is not exactly
57    /// the same as is available from the origin server, but is collected
58    /// from a local or a third-party copy. This is mostly used for mirrors
59    /// or backups of another resource. Except for that specific case, the
60    /// "200 OK" response is preferred to this status.
61    NonAuthoritativeInformation = 203,
62
63    /// 204 No Content
64    ///
65    /// There is no content to send for this request, but the headers may be
66    /// useful. The user-agent may update its cached headers for this
67    /// resource with the new ones.
68    NoContent = 204,
69
70    /// 205 Reset Content
71    ///
72    /// Tells the user-agent to reset the document which sent this request.
73    ResetContent = 205,
74
75    /// 206 Partial Content
76    ///
77    /// This response code is used when the Range header is sent from the client
78    /// to request only part of a resource.
79    PartialContent = 206,
80
81    /// 207 Multi-Status
82    ///
83    /// A Multi-Status response conveys information about
84    /// multiple resources in situations where multiple
85    /// status codes might be appropriate.
86    MultiStatus = 207,
87
88    /// 226 Im Used
89    ///
90    /// The server has fulfilled a GET request for the resource, and the
91    /// response is a representation of the result of one or more
92    /// instance-manipulations applied to the current instance.
93    ImUsed = 226,
94
95    /// 300 Multiple Choice
96    ///
97    /// The request has more than one possible response. The user-agent or user
98    /// should choose one of them. (There is no standardized way of choosing
99    /// one of the responses, but HTML links to the possibilities are
100    /// recommended so the user can pick.)
101    MultipleChoice = 300,
102
103    /// 301 Moved Permanently
104    ///
105    /// The URL of the requested resource has been changed permanently. The new
106    /// URL is given in the response.
107    MovedPermanently = 301,
108
109    /// 302 Found
110    ///
111    /// This response code means that the URI of requested resource has been
112    /// changed temporarily. Further changes in the URI might be made in the
113    /// future. Therefore, this same URI should be used by the client in
114    /// future requests.
115    Found = 302,
116
117    /// 303 See Other
118    ///
119    /// The server sent this response to direct the client to get the requested
120    /// resource at another URI with a GET request.
121    SeeOther = 303,
122
123    /// 304 Not Modified
124    ///
125    /// This is used for caching purposes. It tells the client that the response
126    /// has not been modified, so the client can continue to use the same
127    /// cached version of the response.
128    NotModified = 304,
129
130    /// 307 Temporary Redirect
131    ///
132    /// The server sends this response to direct the client to get the requested
133    /// resource at another URI with same method that was used in the prior
134    /// request. This has the same semantics as the 302 Found HTTP response
135    /// code, with the exception that the user agent must not change the
136    /// HTTP method used: If a POST was used in the first request, a POST must
137    /// be used in the second request.
138    TemporaryRedirect = 307,
139
140    /// 308 Permanent Redirect
141    ///
142    /// This means that the resource is now permanently located at another URI,
143    /// specified by the Location: HTTP Response header. This has the same
144    /// semantics as the 301 Moved Permanently HTTP response code, with the
145    /// exception that the user agent must not change the HTTP method
146    /// used: If a POST was used in the first request, a POST must be used in
147    /// the second request.
148    PermanentRedirect = 308,
149
150    /// 400 Bad Request
151    ///
152    /// The server could not understand the request due to invalid syntax.
153    BadRequest = 400,
154
155    /// 401 Unauthorized
156    ///
157    /// Although the HTTP standard specifies "unauthorized", semantically this
158    /// response means "unauthenticated". That is, the client must
159    /// authenticate itself to get the requested response.
160    Unauthorized = 401,
161
162    /// 402 Payment Required
163    ///
164    /// This response code is reserved for future use. The initial aim for
165    /// creating this code was using it for digital payment systems, however
166    /// this status code is used very rarely and no standard convention
167    /// exists.
168    PaymentRequired = 402,
169
170    /// 403 Forbidden
171    ///
172    /// The client does not have access rights to the content; that is, it is
173    /// unauthorized, so the server is refusing to give the requested
174    /// resource. Unlike 401, the client's identity is known to the server.
175    Forbidden = 403,
176
177    /// 404 Not Found
178    ///
179    /// The server can not find requested resource. In the browser, this means
180    /// the URL is not recognized. In an API, this can also mean that the
181    /// endpoint is valid but the resource itself does not exist. Servers
182    /// may also send this response instead of 403 to hide the existence of
183    /// a resource from an unauthorized client. This response code is probably
184    /// the most famous one due to its frequent occurrence on the web.
185    NotFound = 404,
186
187    /// 405 Method Not Allowed
188    ///
189    /// The request method is known by the server but has been disabled and
190    /// cannot be used. For example, an API may forbid DELETE-ing a
191    /// resource. The two mandatory methods, GET and HEAD, must never be
192    /// disabled and should not return this error code.
193    MethodNotAllowed = 405,
194
195    /// 406 Not Acceptable
196    ///
197    /// This response is sent when the web server, after performing
198    /// server-driven content negotiation, doesn't find any content that
199    /// conforms to the criteria given by the user agent.
200    NotAcceptable = 406,
201
202    /// 407 Proxy Authentication Required
203    ///
204    /// This is similar to 401 but authentication is needed to be done by a
205    /// proxy.
206    ProxyAuthenticationRequired = 407,
207
208    /// 408 Request Timeout
209    ///
210    /// This response is sent on an idle connection by some servers, even
211    /// without any previous request by the client. It means that the server
212    /// would like to shut down this unused connection. This response is
213    /// used much more since some browsers, like Chrome, Firefox 27+,
214    /// or IE9, use HTTP pre-connection mechanisms to speed up surfing. Also
215    /// note that some servers merely shut down the connection without
216    /// sending this message.
217    RequestTimeout = 408,
218
219    /// 409 Conflict
220    ///
221    /// This response is sent when a request conflicts with the current state of
222    /// the server.
223    Conflict = 409,
224
225    /// 410 Gone
226    ///
227    /// This response is sent when the requested content has been permanently
228    /// deleted from server, with no forwarding address. Clients are
229    /// expected to remove their caches and links to the resource. The HTTP
230    /// specification intends this status code to be used for "limited-time,
231    /// promotional services". APIs should not feel compelled to indicate
232    /// resources that have been deleted with this status code.
233    Gone = 410,
234
235    /// 411 Length Required
236    ///
237    /// Server rejected the request because the Content-Length header field is
238    /// not defined and the server requires it.
239    LengthRequired = 411,
240
241    /// 412 Precondition Failed
242    ///
243    /// The client has indicated preconditions in its headers which the server
244    /// does not meet.
245    PreconditionFailed = 412,
246
247    /// 413 Payload Too Large
248    ///
249    /// Request entity is larger than limits defined by server; the server might
250    /// close the connection or return an Retry-After header field.
251    PayloadTooLarge = 413,
252
253    /// 414 URI Too Long
254    ///
255    /// The URI requested by the client is longer than the server is willing to
256    /// interpret.
257    UriTooLong = 414,
258
259    /// 415 Unsupported Media Type
260    ///
261    /// The media format of the requested data is not supported by the server,
262    /// so the server is rejecting the request.
263    UnsupportedMediaType = 415,
264
265    /// 416 Requested Range Not Satisfiable
266    ///
267    /// The range specified by the Range header field in the request can't be
268    /// fulfilled; it's possible that the range is outside the size of the
269    /// target URI's data.
270    RequestedRangeNotSatisfiable = 416,
271
272    /// 417 Expectation Failed
273    ///
274    /// This response code means the expectation indicated by the Expect request
275    /// header field can't be met by the server.
276    ExpectationFailed = 417,
277    ///
278    /// 418 I'm a teapot
279    ///
280    /// The server refuses the attempt to brew coffee with a teapot.
281    ImATeapot = 418,
282
283    /// 421 Misdirected Request
284    ///
285    /// The request was directed at a server that is not able to produce a
286    /// response. This can be sent by a server that is not configured to
287    /// produce responses for the combination of scheme and authority that
288    /// are included in the request URI.
289    MisdirectedRequest = 421,
290
291    /// 422 Unprocessable Entity
292    ///
293    /// The request was well-formed but was unable to be followed due to
294    /// semantic errors.
295    UnprocessableEntity = 422,
296
297    /// 423 Locked
298    ///
299    /// The resource that is being accessed is locked.
300    Locked = 423,
301
302    /// 424 Failed Dependency
303    ///
304    /// The request failed because it depended on another request and that
305    /// request failed (e.g., a PROPPATCH).
306    FailedDependency = 424,
307
308    /// 425 Too Early
309    ///
310    /// Indicates that the server is unwilling to risk processing a request that
311    /// might be replayed.
312    TooEarly = 425,
313
314    /// 426 Upgrade Required
315    ///
316    /// The server refuses to perform the request using the current protocol but
317    /// might be willing to do so after the client upgrades to a different
318    /// protocol. The server sends an Upgrade header in a 426 response to
319    /// indicate the required protocol(s).
320    UpgradeRequired = 426,
321
322    /// 428 Precondition Required
323    ///
324    /// The origin server requires the request to be conditional. This response
325    /// is intended to prevent the 'lost update' problem, where a client
326    /// GETs a resource's state, modifies it, and PUTs it back to the
327    /// server, when meanwhile a third party has modified the state on the
328    /// server, leading to a conflict.
329    PreconditionRequired = 428,
330
331    /// 429 Too Many Requests
332    ///
333    /// The user has sent too many requests in a given amount of time ("rate
334    /// limiting").
335    TooManyRequests = 429,
336
337    /// 431 Request Header Fields Too Large
338    ///
339    /// The server is unwilling to process the request because its header fields
340    /// are too large. The request may be resubmitted after reducing the
341    /// size of the request header fields.
342    RequestHeaderFieldsTooLarge = 431,
343
344    /// 451 Unavailable For Legal Reasons
345    ///
346    /// The user-agent requested a resource that cannot legally be provided,
347    /// such as a web page censored by a government.
348    UnavailableForLegalReasons = 451,
349
350    /// 500 Internal Server Error
351    ///
352    /// The server has encountered a situation it doesn't know how to handle.
353    InternalServerError = 500,
354
355    /// 501 Not Implemented
356    ///
357    /// The request method is not supported by the server and cannot be handled.
358    /// The only methods that servers are required to support (and therefore
359    /// that must not return this code) are GET and HEAD.
360    NotImplemented = 501,
361
362    /// 502 Bad Gateway
363    ///
364    /// This error response means that the server, while working as a gateway to
365    /// get a response needed to handle the request, got an invalid
366    /// response.
367    BadGateway = 502,
368
369    /// 503 Service Unavailable
370    ///
371    /// The server is not ready to handle the request. Common causes are a
372    /// server that is down for maintenance or that is overloaded. Note that
373    /// together with this response, a user-friendly page explaining the
374    /// problem should be sent. This responses should be used for temporary
375    /// conditions and the Retry-After: HTTP header should, if possible, contain
376    /// the estimated time before the recovery of the service. The webmaster
377    /// must also take care about the caching-related headers that are sent
378    /// along with this response, as these temporary condition responses
379    /// should usually not be cached.
380    ServiceUnavailable = 503,
381
382    /// 504 Gateway Timeout
383    ///
384    /// This error response is given when the server is acting as a gateway and
385    /// cannot get a response in time.
386    GatewayTimeout = 504,
387
388    /// 505 HTTP Version Not Supported
389    ///
390    /// The HTTP version used in the request is not supported by the server.
391    HttpVersionNotSupported = 505,
392
393    /// 506 Variant Also Negotiates
394    ///
395    /// The server has an internal configuration error: the chosen variant
396    /// resource is configured to engage in transparent content negotiation
397    /// itself, and is therefore not a proper end point in the negotiation
398    /// process.
399    VariantAlsoNegotiates = 506,
400
401    /// 507 Insufficient Storage
402    ///
403    /// The server is unable to store the representation needed to complete the
404    /// request.
405    InsufficientStorage = 507,
406
407    /// 508 Loop Detected
408    ///
409    /// The server detected an infinite loop while processing the request.
410    LoopDetected = 508,
411
412    /// 510 Not Extended
413    ///
414    /// Further extensions to the request are required for the server to fulfil
415    /// it.
416    NotExtended = 510,
417
418    /// 511 Network Authentication Required
419    ///
420    /// The 511 status code indicates that the client needs to authenticate to
421    /// gain network access.
422    NetworkAuthenticationRequired = 511,
423}
424
425impl Status {
426    /// Returns `true` if the status code is `1xx` range.
427    ///
428    /// If this returns `true` it indicates that the request was received,
429    /// continuing process.
430    pub fn is_informational(&self) -> bool {
431        let num: u16 = (*self).into();
432        (100..200).contains(&num)
433    }
434
435    /// Returns `true` if the status code is the `2xx` range.
436    ///
437    /// If this returns `true` it indicates that the request was successfully
438    /// received, understood, and accepted.
439    pub fn is_success(&self) -> bool {
440        let num: u16 = (*self).into();
441        (200..300).contains(&num)
442    }
443
444    /// Returns `true` if the status code is the `3xx` range.
445    ///
446    /// If this returns `true` it indicates that further action needs to be
447    /// taken in order to complete the request.
448    pub fn is_redirection(&self) -> bool {
449        let num: u16 = (*self).into();
450        (300..400).contains(&num)
451    }
452
453    /// Returns `true` if the status code is the `4xx` range.
454    ///
455    /// If this returns `true` it indicates that the request contains bad syntax
456    /// or cannot be fulfilled.
457    pub fn is_client_error(&self) -> bool {
458        let num: u16 = (*self).into();
459        (400..500).contains(&num)
460    }
461
462    /// Returns `true` if the status code is the `5xx` range.
463    ///
464    /// If this returns `true` it indicates that the server failed to fulfill an
465    /// apparently valid request.
466    pub fn is_server_error(&self) -> bool {
467        let num: u16 = (*self).into();
468        (500..600).contains(&num)
469    }
470
471    /// The canonical reason for a given status code
472    pub fn canonical_reason(&self) -> &'static str {
473        match self {
474            Status::Continue => "Continue",
475            Status::SwitchingProtocols => "Switching Protocols",
476            Status::EarlyHints => "Early Hints",
477            Status::Ok => "OK",
478            Status::Created => "Created",
479            Status::Accepted => "Accepted",
480            Status::NonAuthoritativeInformation => "Non Authoritative Information",
481            Status::NoContent => "No Content",
482            Status::ResetContent => "Reset Content",
483            Status::PartialContent => "Partial Content",
484            Status::MultiStatus => "Multi-Status",
485            Status::ImUsed => "Im Used",
486            Status::MultipleChoice => "Multiple Choice",
487            Status::MovedPermanently => "Moved Permanently",
488            Status::Found => "Found",
489            Status::SeeOther => "See Other",
490            Status::NotModified => "Not Modified",
491            Status::TemporaryRedirect => "Temporary Redirect",
492            Status::PermanentRedirect => "Permanent Redirect",
493            Status::BadRequest => "Bad Request",
494            Status::Unauthorized => "Unauthorized",
495            Status::PaymentRequired => "Payment Required",
496            Status::Forbidden => "Forbidden",
497            Status::NotFound => "Not Found",
498            Status::MethodNotAllowed => "Method Not Allowed",
499            Status::NotAcceptable => "Not Acceptable",
500            Status::ProxyAuthenticationRequired => "Proxy Authentication Required",
501            Status::RequestTimeout => "Request Timeout",
502            Status::Conflict => "Conflict",
503            Status::Gone => "Gone",
504            Status::LengthRequired => "Length Required",
505            Status::PreconditionFailed => "Precondition Failed",
506            Status::PayloadTooLarge => "Payload Too Large",
507            Status::UriTooLong => "URI Too Long",
508            Status::UnsupportedMediaType => "Unsupported Media Type",
509            Status::RequestedRangeNotSatisfiable => "Requested Range Not Satisfiable",
510            Status::ExpectationFailed => "Expectation Failed",
511            Status::ImATeapot => "I'm a teapot",
512            Status::MisdirectedRequest => "Misdirected Request",
513            Status::UnprocessableEntity => "Unprocessable Entity",
514            Status::Locked => "Locked",
515            Status::FailedDependency => "Failed Dependency",
516            Status::TooEarly => "Too Early",
517            Status::UpgradeRequired => "Upgrade Required",
518            Status::PreconditionRequired => "Precondition Required",
519            Status::TooManyRequests => "Too Many Requests",
520            Status::RequestHeaderFieldsTooLarge => "Request Header Fields Too Large",
521            Status::UnavailableForLegalReasons => "Unavailable For Legal Reasons",
522            Status::InternalServerError => "Internal Server Error",
523            Status::NotImplemented => "Not Implemented",
524            Status::BadGateway => "Bad Gateway",
525            Status::ServiceUnavailable => "Service Unavailable",
526            Status::GatewayTimeout => "Gateway Timeout",
527            Status::HttpVersionNotSupported => "HTTP Version Not Supported",
528            Status::VariantAlsoNegotiates => "Variant Also Negotiates",
529            Status::InsufficientStorage => "Insufficient Storage",
530            Status::LoopDetected => "Loop Detected",
531            Status::NotExtended => "Not Extended",
532            Status::NetworkAuthenticationRequired => "Network Authentication Required",
533        }
534    }
535}
536
537impl From<Status> for u16 {
538    fn from(code: Status) -> u16 {
539        code as u16
540    }
541}
542
543impl TryFrom<u16> for Status {
544    type Error = Error;
545
546    fn try_from(num: u16) -> Result<Self, Self::Error> {
547        match num {
548            100 => Ok(Status::Continue),
549            101 => Ok(Status::SwitchingProtocols),
550            103 => Ok(Status::EarlyHints),
551            200 => Ok(Status::Ok),
552            201 => Ok(Status::Created),
553            202 => Ok(Status::Accepted),
554            203 => Ok(Status::NonAuthoritativeInformation),
555            204 => Ok(Status::NoContent),
556            205 => Ok(Status::ResetContent),
557            206 => Ok(Status::PartialContent),
558            207 => Ok(Status::MultiStatus),
559            226 => Ok(Status::ImUsed),
560            300 => Ok(Status::MultipleChoice),
561            301 => Ok(Status::MovedPermanently),
562            302 => Ok(Status::Found),
563            303 => Ok(Status::SeeOther),
564            304 => Ok(Status::NotModified),
565            307 => Ok(Status::TemporaryRedirect),
566            308 => Ok(Status::PermanentRedirect),
567            400 => Ok(Status::BadRequest),
568            401 => Ok(Status::Unauthorized),
569            402 => Ok(Status::PaymentRequired),
570            403 => Ok(Status::Forbidden),
571            404 => Ok(Status::NotFound),
572            405 => Ok(Status::MethodNotAllowed),
573            406 => Ok(Status::NotAcceptable),
574            407 => Ok(Status::ProxyAuthenticationRequired),
575            408 => Ok(Status::RequestTimeout),
576            409 => Ok(Status::Conflict),
577            410 => Ok(Status::Gone),
578            411 => Ok(Status::LengthRequired),
579            412 => Ok(Status::PreconditionFailed),
580            413 => Ok(Status::PayloadTooLarge),
581            414 => Ok(Status::UriTooLong),
582            415 => Ok(Status::UnsupportedMediaType),
583            416 => Ok(Status::RequestedRangeNotSatisfiable),
584            417 => Ok(Status::ExpectationFailed),
585            418 => Ok(Status::ImATeapot),
586            421 => Ok(Status::MisdirectedRequest),
587            422 => Ok(Status::UnprocessableEntity),
588            423 => Ok(Status::Locked),
589            424 => Ok(Status::FailedDependency),
590            425 => Ok(Status::TooEarly),
591            426 => Ok(Status::UpgradeRequired),
592            428 => Ok(Status::PreconditionRequired),
593            429 => Ok(Status::TooManyRequests),
594            431 => Ok(Status::RequestHeaderFieldsTooLarge),
595            451 => Ok(Status::UnavailableForLegalReasons),
596            500 => Ok(Status::InternalServerError),
597            501 => Ok(Status::NotImplemented),
598            502 => Ok(Status::BadGateway),
599            503 => Ok(Status::ServiceUnavailable),
600            504 => Ok(Status::GatewayTimeout),
601            505 => Ok(Status::HttpVersionNotSupported),
602            506 => Ok(Status::VariantAlsoNegotiates),
603            507 => Ok(Status::InsufficientStorage),
604            508 => Ok(Status::LoopDetected),
605            510 => Ok(Status::NotExtended),
606            511 => Ok(Status::NetworkAuthenticationRequired),
607            n => Err(Error::UnrecognizedStatusCode(n)),
608        }
609    }
610}
611
612impl PartialEq<Status> for u16 {
613    fn eq(&self, other: &Status) -> bool {
614        *self == *other as u16
615    }
616}
617
618impl PartialEq<u16> for Status {
619    fn eq(&self, other: &u16) -> bool {
620        *self as u16 == *other
621    }
622}
623
624impl Debug for Status {
625    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
626        Debug::fmt(&(*self as u16), f)
627    }
628}
629
630impl Display for Status {
631    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
632        write!(f, "{} {}", *self as u16, self.canonical_reason())
633    }
634}