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}