small_http/
enums.rs

1/*
2 * Copyright (c) 2024-2025 Bastiaan van der Plaat
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7use std::error::Error;
8use std::fmt::{self, Display, Formatter};
9use std::str::FromStr;
10
11// MARK: Version
12#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
13pub(crate) enum Version {
14    Http1_0,
15    #[default]
16    Http1_1,
17}
18
19impl FromStr for Version {
20    type Err = ();
21
22    fn from_str(s: &str) -> Result<Self, Self::Err> {
23        match s {
24            "HTTP/1.0" => Ok(Version::Http1_0),
25            _ => Ok(Version::Http1_1),
26        }
27    }
28}
29
30impl Display for Version {
31    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
32        write!(
33            f,
34            "{}",
35            match self {
36                Version::Http1_0 => "HTTP/1.0",
37                Version::Http1_1 => "HTTP/1.1",
38            }
39        )
40    }
41}
42
43// MARK: Method
44/// HTTP method
45#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
46pub enum Method {
47    /// GET
48    #[default]
49    Get,
50    /// HEAD
51    Head,
52    /// POST
53    Post,
54    /// PUT
55    Put,
56    /// DELETE
57    Delete,
58    /// CONNECT
59    Connect,
60    /// OPTIONS
61    Options,
62    /// TRACE
63    Trace,
64    /// PATCH
65    Patch,
66}
67
68impl FromStr for Method {
69    type Err = InvalidMethodError;
70
71    fn from_str(s: &str) -> Result<Self, Self::Err> {
72        match s {
73            "GET" => Ok(Method::Get),
74            "HEAD" => Ok(Method::Head),
75            "POST" => Ok(Method::Post),
76            "PUT" => Ok(Method::Put),
77            "DELETE" => Ok(Method::Delete),
78            "CONNECT" => Ok(Method::Connect),
79            "OPTIONS" => Ok(Method::Options),
80            "TRACE" => Ok(Method::Trace),
81            "PATCH" => Ok(Method::Patch),
82            _ => Err(InvalidMethodError),
83        }
84    }
85}
86
87impl Display for Method {
88    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
89        write!(
90            f,
91            "{}",
92            match self {
93                Method::Get => "GET",
94                Method::Head => "HEAD",
95                Method::Post => "POST",
96                Method::Put => "PUT",
97                Method::Delete => "DELETE",
98                Method::Connect => "CONNECT",
99                Method::Options => "OPTIONS",
100                Method::Trace => "TRACE",
101                Method::Patch => "PATCH",
102            }
103        )
104    }
105}
106
107// MARK: InvalidMethodError
108#[derive(Debug)]
109pub struct InvalidMethodError;
110
111impl Display for InvalidMethodError {
112    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
113        write!(f, "Invalid HTTP method")
114    }
115}
116
117impl Error for InvalidMethodError {}
118
119// MARK: Status
120/// Http status
121#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
122pub enum Status {
123    /// 100 Continue
124    Continue = 100,
125    /// 101 Switching Protocols
126    SwitchingProtocols = 101,
127    /// 102 Processing
128    Processing = 102,
129    /// 200 OK
130    #[default]
131    Ok = 200,
132    /// 201 Created
133    Created = 201,
134    /// 202 Accepted
135    Accepted = 202,
136    /// 203 Non-Authoritative Information
137    NonAuthoritativeInformation = 203,
138    /// 204 No Content
139    NoContent = 204,
140    /// 205 Reset Content
141    ResetContent = 205,
142    /// 206 Partial Content
143    PartialContent = 206,
144    /// 207 Multi-Status
145    MultiStatus = 207,
146    /// 208 Already Reported
147    AlreadyReported = 208,
148    /// 226 IM Used
149    IMUsed = 226,
150    /// 300 Multiple Choices
151    MultipleChoices = 300,
152    /// 301 Moved Permanently
153    MovedPermanently = 301,
154    /// 302 Found
155    Found = 302,
156    /// 303 See Other
157    SeeOther = 303,
158    /// 304 Not Modified
159    NotModified = 304,
160    /// 305 Use Proxy
161    UseProxy = 305,
162    /// 307 Temporary Redirect
163    TemporaryRedirect = 307,
164    /// 308 Permanent Redirect
165    PermanentRedirect = 308,
166    /// 400 Bad Request
167    BadRequest = 400,
168    /// 401 Unauthorized
169    Unauthorized = 401,
170    /// 402 Payment Required
171    PaymentRequired = 402,
172    /// 403 Forbidden
173    Forbidden = 403,
174    /// 404 Not Found
175    NotFound = 404,
176    /// 405 Method Not Allowed
177    MethodNotAllowed = 405,
178    /// 406 Not Acceptable
179    NotAcceptable = 406,
180    /// 407 Proxy Authentication Required
181    ProxyAuthenticationRequired = 407,
182    /// 408 Request Timeout
183    RequestTimeout = 408,
184    /// 409 Conflict
185    Conflict = 409,
186    /// 410 Gone
187    Gone = 410,
188    /// 411 Length Required
189    LengthRequired = 411,
190    /// 412 Precondition Failed
191    PreconditionFailed = 412,
192    /// 413 Payload Too Large
193    PayloadTooLarge = 413,
194    /// 414 URI Too Long
195    URITooLong = 414,
196    /// 415 Unsupported Media Type
197    UnsupportedMediaType = 415,
198    /// 416 Range Not Satisfiable
199    RangeNotSatisfiable = 416,
200    /// 417 Expectation Failed
201    ExpectationFailed = 417,
202    /// 418 I'm a teapot
203    ImATeapot = 418,
204    /// 421 Misdirected Request
205    MisdirectedRequest = 421,
206    /// 422 Unprocessable Entity
207    UnprocessableEntity = 422,
208    /// 423 Locked
209    Locked = 423,
210    /// 424 Failed Dependency
211    FailedDependency = 424,
212    /// 425 Too Early
213    TooEarly = 425,
214    /// 426 Upgrade Required
215    UpgradeRequired = 426,
216    /// 428 Precondition Required
217    PreconditionRequired = 428,
218    /// 429 Too Many Requests
219    TooManyRequests = 429,
220    /// 431 Request Header Fields Too Large
221    RequestHeaderFieldsTooLarge = 431,
222    /// 451 Unavailable For Legal Reasons
223    UnavailableForLegalReasons = 451,
224    /// 500 Internal Server Error
225    InternalServerError = 500,
226    /// 501 Not Implemented
227    NotImplemented = 501,
228    /// 502 Bad Gateway
229    BadGateway = 502,
230    /// 503 Service Unavailable
231    ServiceUnavailable = 503,
232    /// 504 Gateway Timeout
233    GatewayTimeout = 504,
234    /// 505 HTTP Version Not Supported
235    HTTPVersionNotSupported = 505,
236    /// 506 Variant Also Negotiates
237    VariantAlsoNegotiates = 506,
238    /// 507 Insufficient Storage
239    InsufficientStorage = 507,
240    /// 508 Loop Detected
241    LoopDetected = 508,
242    /// 510 Not Extended
243    NotExtended = 510,
244    /// 511 Network Authentication Required
245    NetworkAuthenticationRequired = 511,
246}
247
248impl TryFrom<i32> for Status {
249    type Error = InvalidStatusError;
250
251    fn try_from(value: i32) -> Result<Self, Self::Error> {
252        match value {
253            100 => Ok(Status::Continue),
254            101 => Ok(Status::SwitchingProtocols),
255            102 => Ok(Status::Processing),
256            200 => Ok(Status::Ok),
257            201 => Ok(Status::Created),
258            202 => Ok(Status::Accepted),
259            203 => Ok(Status::NonAuthoritativeInformation),
260            204 => Ok(Status::NoContent),
261            205 => Ok(Status::ResetContent),
262            206 => Ok(Status::PartialContent),
263            207 => Ok(Status::MultiStatus),
264            208 => Ok(Status::AlreadyReported),
265            226 => Ok(Status::IMUsed),
266            300 => Ok(Status::MultipleChoices),
267            301 => Ok(Status::MovedPermanently),
268            302 => Ok(Status::Found),
269            303 => Ok(Status::SeeOther),
270            304 => Ok(Status::NotModified),
271            305 => Ok(Status::UseProxy),
272            307 => Ok(Status::TemporaryRedirect),
273            308 => Ok(Status::PermanentRedirect),
274            400 => Ok(Status::BadRequest),
275            401 => Ok(Status::Unauthorized),
276            402 => Ok(Status::PaymentRequired),
277            403 => Ok(Status::Forbidden),
278            404 => Ok(Status::NotFound),
279            405 => Ok(Status::MethodNotAllowed),
280            406 => Ok(Status::NotAcceptable),
281            407 => Ok(Status::ProxyAuthenticationRequired),
282            408 => Ok(Status::RequestTimeout),
283            409 => Ok(Status::Conflict),
284            410 => Ok(Status::Gone),
285            411 => Ok(Status::LengthRequired),
286            412 => Ok(Status::PreconditionFailed),
287            413 => Ok(Status::PayloadTooLarge),
288            414 => Ok(Status::URITooLong),
289            415 => Ok(Status::UnsupportedMediaType),
290            416 => Ok(Status::RangeNotSatisfiable),
291            417 => Ok(Status::ExpectationFailed),
292            418 => Ok(Status::ImATeapot),
293            421 => Ok(Status::MisdirectedRequest),
294            422 => Ok(Status::UnprocessableEntity),
295            423 => Ok(Status::Locked),
296            424 => Ok(Status::FailedDependency),
297            425 => Ok(Status::TooEarly),
298            426 => Ok(Status::UpgradeRequired),
299            428 => Ok(Status::PreconditionRequired),
300            429 => Ok(Status::TooManyRequests),
301            431 => Ok(Status::RequestHeaderFieldsTooLarge),
302            451 => Ok(Status::UnavailableForLegalReasons),
303            500 => Ok(Status::InternalServerError),
304            501 => Ok(Status::NotImplemented),
305            502 => Ok(Status::BadGateway),
306            503 => Ok(Status::ServiceUnavailable),
307            504 => Ok(Status::GatewayTimeout),
308            505 => Ok(Status::HTTPVersionNotSupported),
309            506 => Ok(Status::VariantAlsoNegotiates),
310            507 => Ok(Status::InsufficientStorage),
311            508 => Ok(Status::LoopDetected),
312            510 => Ok(Status::NotExtended),
313            511 => Ok(Status::NetworkAuthenticationRequired),
314            _ => Err(InvalidStatusError),
315        }
316    }
317}
318
319impl Display for Status {
320    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
321        write!(
322            f,
323            "{}",
324            match self {
325                Status::Continue => "100 Continue",
326                Status::SwitchingProtocols => "101 Switching Protocols",
327                Status::Processing => "102 Processing",
328                Status::Ok => "200 OK",
329                Status::Created => "201 Created",
330                Status::Accepted => "202 Accepted",
331                Status::NonAuthoritativeInformation => "203 Non-Authoritative Information",
332                Status::NoContent => "204 No Content",
333                Status::ResetContent => "205 Reset Content",
334                Status::PartialContent => "206 Partial Content",
335                Status::MultiStatus => "207 Multi-Status",
336                Status::AlreadyReported => "208 Already Reported",
337                Status::IMUsed => "226 IM Used",
338                Status::MultipleChoices => "300 Multiple Choices",
339                Status::MovedPermanently => "301 Moved Permanently",
340                Status::Found => "302 Found",
341                Status::SeeOther => "303 See Other",
342                Status::NotModified => "304 Not Modified",
343                Status::UseProxy => "305 Use Proxy",
344                Status::TemporaryRedirect => "307 Temporary Redirect",
345                Status::PermanentRedirect => "308 Permanent Redirect",
346                Status::BadRequest => "400 Bad Request",
347                Status::Unauthorized => "401 Unauthorized",
348                Status::PaymentRequired => "402 Payment Required",
349                Status::Forbidden => "403 Forbidden",
350                Status::NotFound => "404 Not Found",
351                Status::MethodNotAllowed => "405 Method Not Allowed",
352                Status::NotAcceptable => "406 Not Acceptable",
353                Status::ProxyAuthenticationRequired => "407 Proxy Authentication Required",
354                Status::RequestTimeout => "408 Request Timeout",
355                Status::Conflict => "409 Conflict",
356                Status::Gone => "410 Gone",
357                Status::LengthRequired => "411 Length Required",
358                Status::PreconditionFailed => "412 Precondition Failed",
359                Status::PayloadTooLarge => "413 Payload Too Large",
360                Status::URITooLong => "414 URI Too Long",
361                Status::UnsupportedMediaType => "415 Unsupported Media Type",
362                Status::RangeNotSatisfiable => "416 Range Not Satisfiable",
363                Status::ExpectationFailed => "417 Expectation Failed",
364                Status::ImATeapot => "418 I'm a teapot",
365                Status::MisdirectedRequest => "421 Misdirected Request",
366                Status::UnprocessableEntity => "422 Unprocessable Entity",
367                Status::Locked => "423 Locked",
368                Status::FailedDependency => "424 Failed Dependency",
369                Status::TooEarly => "425 Too Early",
370                Status::UpgradeRequired => "426 Upgrade Required",
371                Status::PreconditionRequired => "428 Precondition Required",
372                Status::TooManyRequests => "429 Too Many Requests",
373                Status::RequestHeaderFieldsTooLarge => "431 Request Header Fields Too Large",
374                Status::UnavailableForLegalReasons => "451 Unavailable For Legal Reasons",
375                Status::InternalServerError => "500 Internal Server Error",
376                Status::NotImplemented => "501 Not Implemented",
377                Status::BadGateway => "502 Bad Gateway",
378                Status::ServiceUnavailable => "503 Service Unavailable",
379                Status::GatewayTimeout => "504 Gateway Timeout",
380                Status::HTTPVersionNotSupported => "505 HTTP Version Not Supported",
381                Status::VariantAlsoNegotiates => "506 Variant Also Negotiates",
382                Status::InsufficientStorage => "507 Insufficient Storage",
383                Status::LoopDetected => "508 Loop Detected",
384                Status::NotExtended => "510 Not Extended",
385                Status::NetworkAuthenticationRequired => "511 Network Authentication Required",
386            }
387        )
388    }
389}
390
391// MARK: InvalidStatusError
392#[derive(Debug)]
393pub struct InvalidStatusError;
394
395impl Display for InvalidStatusError {
396    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
397        write!(f, "Invalid HTTP status")
398    }
399}
400
401impl Error for InvalidStatusError {}