Skip to main content

torus_http/
status.rs

1//! Http status wrapper
2use std::fmt::Display;
3
4#[non_exhaustive]
5#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Debug)]
6/// # Wikipedia:
7///
8/// The status code is a three-digit, decimal, integer value that represents the disposition of the server's attempt to satisfy the client's request. Generally, a client handles a response primarily based on the status code and secondarily on response header fields. A client may not understand each status code that a server reports but it must understand the class as indicated by the first digit and treat an unrecognized code as equivalent to the `x00` code of that class.
9pub enum HttpStatus {
10    /// Status range 1xx - See `InformationalResponse` for more info
11    Informational(InformationalResponse),
12    /// Status range 2xx - See `SuccessResponse` for more info
13    Success(SuccessResponse),
14    /// Status range 3xx - See `RedirectionResponse` for more info
15    Redirection(RedirectionResponse),
16    /// Status range 4xx - See `ClientErrorResponse` for more info
17    ClientError(ClientErrorResponse),
18    /// Status range 5xx - See `ServerErrorResponse` for more info
19    ServerError(ServerErrorResponse),
20}
21
22#[allow(unused)]
23impl HttpStatus {
24    pub const INTERNAL_SERVER_ERROR: Self =
25        Self::ServerError(ServerErrorResponse::InternalServerError);
26    pub const UNAUTHORIZED: Self = Self::ClientError(ClientErrorResponse::Unauthorized);
27    pub const NOT_FOUND: Self = Self::ClientError(ClientErrorResponse::NotFound);
28    pub const FORBIDDEN: Self = Self::ClientError(ClientErrorResponse::Forbidden);
29    pub const BAD_REQUEST: Self = Self::ClientError(ClientErrorResponse::BadRequest);
30    pub const TOO_MANY_REQUESTS: Self = Self::ClientError(ClientErrorResponse::TooManyRequests);
31    pub const OK: Self = Self::Success(SuccessResponse::OK);
32    pub const MOVED_PERMANENTLY: Self = Self::Redirection(RedirectionResponse::MovedPermanently);
33}
34
35impl Default for HttpStatus {
36    fn default() -> Self {
37        Self::Success(SuccessResponse::OK)
38    }
39}
40
41#[non_exhaustive]
42#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Debug)]
43/// # Wikipedia:
44///
45/// an `InformationalResponse` (`1xx`) indicates that the request was received and understood and is being processed. It alerts the client to wait for a final response. The message does not contain a body. As the `HTTP/1.0` standard did not define any `1xx` status codes, servers must not send a `1xx` response to an `HTTP/1.0` compliant client except under experimental conditions.
46pub enum InformationalResponse {
47    /// Status 101
48    SwitchingProtocols = 101,
49    Processing = 102,
50    EarlyHints = 103,
51}
52#[non_exhaustive]
53#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Debug, Default)]
54/// # Wikipedia:
55///
56/// A `SuccessResponse` (`2xx`) indicates that the action requested by the client was received, understood, and accepted.
57pub enum SuccessResponse {
58    #[default]
59    OK = 200,
60    Created = 201,
61    Accepted = 202,
62    NonAuthoritativeInformation = 203,
63    NoContent = 204,
64    ResetContent = 205,
65    PartialContent = 206,
66    MultiStatus = 207,
67    AlreadyReported = 208,
68    IMUsed = 226,
69}
70#[non_exhaustive]
71#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Debug)]
72/// # Wikipedia:
73///
74/// A `RedirectionResponse` (`3xx`) status indicates that the client must take additional action, generally URL redirection, to complete the request. A user agent may carry out the additional action with no user interaction if the method used in the additional request is `GET` or `HEAD`. A user agent should prevent cyclical redirects.
75pub enum RedirectionResponse {
76    MultipleChoices = 300,
77    MovedPermanently = 301,
78    Found = 302,
79    SeeOther = 303,
80    NotModified = 304,
81    UseProxy = 305,
82    SwitchProxy = 306,
83    TemporaryRedirect = 307,
84    PermanentRedirect = 308,
85}
86#[non_exhaustive]
87#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Debug)]
88/// # Wikipedia:
89///
90/// A `ClientErrorResponse` (`4xx`) status code is for situations in which an error seems to have been caused by the client. Except when responding to a `HEAD` request, the server should include an entity containing an explanation of the error situation, and whether it is a temporary or permanent condition. These status codes are applicable to any request method. User agents should display any included entity to the user.
91pub enum ClientErrorResponse {
92    BadRequest = 400,
93    Unauthorized = 401,
94    PaymentRequired = 402,
95    Forbidden = 403,
96    NotFound = 404,
97    MethodNotAllowed = 405,
98    NotAcceptable = 406,
99    ProxyAuthenticationRequired = 407,
100    RequestTimeout = 408,
101    Conflict = 409,
102    Gone = 410,
103    LengthRequired = 411,
104    PreconditionFailed = 412,
105    PayloadTooLarge = 413,
106    URITooLong = 414,
107    UnsupportedMediaType = 415,
108    RangeNotSatisfiable = 416,
109    ExpectationFailed = 417,
110    ImATeapot = 418,
111    MisdirectedRequest = 421,
112    UnprocessableContent = 422,
113    Locked = 423,
114    FailedDependency = 424,
115    TooEarly = 425,
116    UpgradeRequired = 426,
117    PreconditionRequired = 428,
118    TooManyRequests = 429,
119    RequestHeaderFieldsTooLarge = 431,
120    UnavailableForLegalReasons = 451,
121}
122#[non_exhaustive]
123#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Debug)]
124/// # Wikipedia:
125///
126/// A `ServerErrorResponse` (`5xx`) status indicates that the server is aware that it has encountered an error or is otherwise incapable of performing the request. Except when responding to a `HEAD` request, the server should include an entity containing an explanation of the error situation, and indicate whether it is a temporary or permanent condition. Likewise, user agents should display any included entity to the user. These response codes are applicable to any request method.
127pub enum ServerErrorResponse {
128    InternalServerError = 500,
129    NotImplemented = 501,
130    BadGateway = 502,
131    ServiceUnavailable = 503,
132    GatewayTimeout = 504,
133    HTTPVersionNotSupported = 505,
134    VariantAlsoNegotiates = 506,
135    InsufficientStorage = 507,
136    LoopDetected = 508,
137    NotExtended = 510,
138    NetworkAuthenticationRequired = 511,
139}
140
141impl Display for HttpStatus {
142    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143        match self {
144            HttpStatus::Informational(informational_response) => {
145                write!(f, "{informational_response}")
146            }
147            HttpStatus::Success(success_response) => write!(f, "{success_response}"),
148            HttpStatus::Redirection(redirection_response) => write!(f, "{redirection_response}"),
149            HttpStatus::ClientError(client_error_response) => write!(f, "{client_error_response}"),
150            HttpStatus::ServerError(server_error_response) => write!(f, "{server_error_response}"),
151        }
152    }
153}
154
155impl Display for ServerErrorResponse {
156    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157        let (name, num) = match self {
158            ServerErrorResponse::InternalServerError => (
159                "InternalServerError",
160                ServerErrorResponse::InternalServerError as u16,
161            ),
162            ServerErrorResponse::NotImplemented => {
163                ("NotImplemented", ServerErrorResponse::NotImplemented as u16)
164            }
165            ServerErrorResponse::BadGateway => {
166                ("BadGateway", ServerErrorResponse::BadGateway as u16)
167            }
168            ServerErrorResponse::ServiceUnavailable => (
169                "ServiceUnavailable",
170                ServerErrorResponse::ServiceUnavailable as u16,
171            ),
172            ServerErrorResponse::GatewayTimeout => {
173                ("GatewayTimeout", ServerErrorResponse::GatewayTimeout as u16)
174            }
175            ServerErrorResponse::HTTPVersionNotSupported => (
176                "HTTPVersionNotSupported",
177                ServerErrorResponse::HTTPVersionNotSupported as u16,
178            ),
179            ServerErrorResponse::VariantAlsoNegotiates => (
180                "VariantAlsoNegotiates",
181                ServerErrorResponse::VariantAlsoNegotiates as u16,
182            ),
183            ServerErrorResponse::InsufficientStorage => (
184                "InsufficientStorage",
185                ServerErrorResponse::InsufficientStorage as u16,
186            ),
187            ServerErrorResponse::LoopDetected => {
188                ("LoopDetected", ServerErrorResponse::LoopDetected as u16)
189            }
190            ServerErrorResponse::NotExtended => {
191                ("NotExtended", ServerErrorResponse::NotExtended as u16)
192            }
193            ServerErrorResponse::NetworkAuthenticationRequired => (
194                "NetworkAuthenticationRequired",
195                ServerErrorResponse::NetworkAuthenticationRequired as u16,
196            ),
197        };
198        write!(f, "{num} {name}")
199    }
200}
201
202impl Display for ClientErrorResponse {
203    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204        let (name, num) = match self {
205            ClientErrorResponse::BadRequest => {
206                ("BadRequest", ClientErrorResponse::BadRequest as u16)
207            }
208            ClientErrorResponse::Unauthorized => {
209                ("Unauthorized", ClientErrorResponse::Unauthorized as u16)
210            }
211            ClientErrorResponse::PaymentRequired => (
212                "PaymentRequired",
213                ClientErrorResponse::PaymentRequired as u16,
214            ),
215            ClientErrorResponse::Forbidden => ("Forbidden", ClientErrorResponse::Forbidden as u16),
216            ClientErrorResponse::NotFound => ("NotFound", ClientErrorResponse::NotFound as u16),
217            ClientErrorResponse::MethodNotAllowed => (
218                "MethodNotAllowed",
219                ClientErrorResponse::MethodNotAllowed as u16,
220            ),
221            ClientErrorResponse::NotAcceptable => {
222                ("NotAcceptable", ClientErrorResponse::NotAcceptable as u16)
223            }
224            ClientErrorResponse::ProxyAuthenticationRequired => (
225                "ProxyAuthenticationRequired",
226                ClientErrorResponse::ProxyAuthenticationRequired as u16,
227            ),
228            ClientErrorResponse::RequestTimeout => {
229                ("RequestTimeout", ClientErrorResponse::RequestTimeout as u16)
230            }
231            ClientErrorResponse::Conflict => ("Conflict", ClientErrorResponse::Conflict as u16),
232            ClientErrorResponse::Gone => ("Gone", ClientErrorResponse::Gone as u16),
233            ClientErrorResponse::LengthRequired => {
234                ("LengthRequired", ClientErrorResponse::LengthRequired as u16)
235            }
236            ClientErrorResponse::PreconditionFailed => (
237                "PreconditionFailed",
238                ClientErrorResponse::PreconditionFailed as u16,
239            ),
240            ClientErrorResponse::PayloadTooLarge => (
241                "PayloadTooLarge",
242                ClientErrorResponse::PayloadTooLarge as u16,
243            ),
244            ClientErrorResponse::URITooLong => {
245                ("URITooLong", ClientErrorResponse::URITooLong as u16)
246            }
247            ClientErrorResponse::UnsupportedMediaType => (
248                "UnsupportedMediaType",
249                ClientErrorResponse::UnsupportedMediaType as u16,
250            ),
251            ClientErrorResponse::RangeNotSatisfiable => (
252                "RangeNotSatisfiable",
253                ClientErrorResponse::RangeNotSatisfiable as u16,
254            ),
255            ClientErrorResponse::ExpectationFailed => (
256                "ExpectationFailed",
257                ClientErrorResponse::ExpectationFailed as u16,
258            ),
259            ClientErrorResponse::ImATeapot => ("ImATeapot", ClientErrorResponse::ImATeapot as u16),
260            ClientErrorResponse::MisdirectedRequest => (
261                "MisdirectedRequest",
262                ClientErrorResponse::MisdirectedRequest as u16,
263            ),
264            ClientErrorResponse::UnprocessableContent => (
265                "UnprocessableContent",
266                ClientErrorResponse::UnprocessableContent as u16,
267            ),
268            ClientErrorResponse::Locked => ("Locked", ClientErrorResponse::Locked as u16),
269            ClientErrorResponse::FailedDependency => (
270                "FailedDependency",
271                ClientErrorResponse::FailedDependency as u16,
272            ),
273            ClientErrorResponse::TooEarly => ("TooEarly", ClientErrorResponse::TooEarly as u16),
274            ClientErrorResponse::UpgradeRequired => (
275                "UpgradeRequired",
276                ClientErrorResponse::UpgradeRequired as u16,
277            ),
278            ClientErrorResponse::PreconditionRequired => (
279                "PreconditionRequired",
280                ClientErrorResponse::PreconditionRequired as u16,
281            ),
282            ClientErrorResponse::TooManyRequests => (
283                "TooManyRequests",
284                ClientErrorResponse::TooManyRequests as u16,
285            ),
286            ClientErrorResponse::RequestHeaderFieldsTooLarge => (
287                "RequestHeaderFieldsTooLarge",
288                ClientErrorResponse::RequestHeaderFieldsTooLarge as u16,
289            ),
290            ClientErrorResponse::UnavailableForLegalReasons => (
291                "UnavailableForLegalReasons",
292                ClientErrorResponse::UnavailableForLegalReasons as u16,
293            ),
294        };
295        write!(f, "{num} {name}")
296    }
297}
298
299impl Display for RedirectionResponse {
300    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
301        let (name, num) = match self {
302            RedirectionResponse::MultipleChoices => (
303                "MultipleChoices",
304                RedirectionResponse::MultipleChoices as u16,
305            ),
306            RedirectionResponse::MovedPermanently => (
307                "MovedPermanently",
308                RedirectionResponse::MovedPermanently as u16,
309            ),
310            RedirectionResponse::Found => ("Found", RedirectionResponse::Found as u16),
311            RedirectionResponse::SeeOther => ("SeeOther", RedirectionResponse::SeeOther as u16),
312            RedirectionResponse::NotModified => {
313                ("NotModified", RedirectionResponse::NotModified as u16)
314            }
315            RedirectionResponse::UseProxy => ("UseProxy", RedirectionResponse::UseProxy as u16),
316            RedirectionResponse::SwitchProxy => {
317                ("SwitchProxy", RedirectionResponse::SwitchProxy as u16)
318            }
319            RedirectionResponse::TemporaryRedirect => (
320                "TemporaryRedirect",
321                RedirectionResponse::TemporaryRedirect as u16,
322            ),
323            RedirectionResponse::PermanentRedirect => (
324                "PermanentRedirect",
325                RedirectionResponse::PermanentRedirect as u16,
326            ),
327        };
328        write!(f, "{num} {name}")
329    }
330}
331
332impl Display for SuccessResponse {
333    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
334        let (name, num) = match self {
335            SuccessResponse::OK => ("OK", SuccessResponse::OK as u16),
336            SuccessResponse::Created => ("Created", SuccessResponse::Created as u16),
337            SuccessResponse::Accepted => ("Accepted", SuccessResponse::Accepted as u16),
338            SuccessResponse::NonAuthoritativeInformation => (
339                "NonAuthoritativeInformation",
340                SuccessResponse::NonAuthoritativeInformation as u16,
341            ),
342            SuccessResponse::NoContent => ("NoContent", SuccessResponse::NoContent as u16),
343            SuccessResponse::ResetContent => ("ResetContent", SuccessResponse::ResetContent as u16),
344            SuccessResponse::PartialContent => {
345                ("PartialContent", SuccessResponse::PartialContent as u16)
346            }
347            SuccessResponse::MultiStatus => ("MultiStatus", SuccessResponse::MultiStatus as u16),
348            SuccessResponse::AlreadyReported => {
349                ("AlreadyReported", SuccessResponse::AlreadyReported as u16)
350            }
351            SuccessResponse::IMUsed => ("IMUsed", SuccessResponse::IMUsed as u16),
352        };
353        write!(f, "{num} {name}")
354    }
355}
356
357impl Display for InformationalResponse {
358    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
359        match self {
360            InformationalResponse::SwitchingProtocols => write!(
361                f,
362                "{} SwitchingProtocols",
363                InformationalResponse::SwitchingProtocols
364            ),
365            InformationalResponse::Processing => {
366                write!(f, "{} Processing", InformationalResponse::Processing)
367            }
368            InformationalResponse::EarlyHints => {
369                write!(f, "{} EarlyHints", InformationalResponse::EarlyHints)
370            }
371        }
372    }
373}
374
375impl From<ClientErrorResponse> for HttpStatus {
376    fn from(val: ClientErrorResponse) -> Self {
377        HttpStatus::ClientError(val)
378    }
379}
380impl From<ServerErrorResponse> for HttpStatus {
381    fn from(val: ServerErrorResponse) -> Self {
382        HttpStatus::ServerError(val)
383    }
384}
385impl From<InformationalResponse> for HttpStatus {
386    fn from(val: InformationalResponse) -> Self {
387        HttpStatus::Informational(val)
388    }
389}
390impl From<RedirectionResponse> for HttpStatus {
391    fn from(val: RedirectionResponse) -> Self {
392        HttpStatus::Redirection(val)
393    }
394}
395impl From<SuccessResponse> for HttpStatus {
396    fn from(val: SuccessResponse) -> Self {
397        HttpStatus::Success(val)
398    }
399}