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