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