1use core::fmt;
2
3use crate::core::Status;
4use crate::ffi::*;
5
6#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
8pub struct HTTPStatus(pub ngx_uint_t);
9
10#[derive(Debug)]
15pub struct InvalidHTTPStatusCode {
16 _priv: (),
17}
18
19impl InvalidHTTPStatusCode {
20 fn new() -> InvalidHTTPStatusCode {
21 InvalidHTTPStatusCode { _priv: () }
22 }
23}
24
25impl fmt::Display for InvalidHTTPStatusCode {
26 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27 f.write_str("invalid status code")
28 }
29}
30
31#[cfg(feature = "std")]
32impl std::error::Error for InvalidHTTPStatusCode {}
33
34impl From<HTTPStatus> for Status {
35 fn from(val: HTTPStatus) -> Self {
36 Status(val.0 as ngx_int_t)
37 }
38}
39
40impl From<HTTPStatus> for ngx_uint_t {
41 fn from(val: HTTPStatus) -> Self {
42 val.0
43 }
44}
45
46impl fmt::Debug for HTTPStatus {
47 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48 fmt::Debug::fmt(&self.0, f)
49 }
50}
51
52impl HTTPStatus {
53 #[inline]
55 pub fn from_u16(src: u16) -> Result<HTTPStatus, InvalidHTTPStatusCode> {
56 if !(100..600).contains(&src) {
57 return Err(InvalidHTTPStatusCode::new());
58 }
59
60 Ok(HTTPStatus(src.into()))
61 }
62
63 pub fn from_bytes(src: &[u8]) -> Result<HTTPStatus, InvalidHTTPStatusCode> {
65 if src.len() != 3 {
66 return Err(InvalidHTTPStatusCode::new());
67 }
68
69 let a = src[0].wrapping_sub(b'0') as u16;
70 let b = src[1].wrapping_sub(b'0') as u16;
71 let c = src[2].wrapping_sub(b'0') as u16;
72
73 if a == 0 || a > 5 || b > 9 || c > 9 {
74 return Err(InvalidHTTPStatusCode::new());
75 }
76
77 let status = (a * 100) + (b * 10) + c;
78 Ok(HTTPStatus(status.into()))
79 }
80}
81
82macro_rules! http_status_codes {
83 (
84 $(
85 $(#[$docs:meta])*
86 ($num:expr, $konst:ident, $phrase:expr);
87 )+
88 ) => {
89 impl HTTPStatus {
90 $(
91 $(#[$docs])*
92 pub const $konst: HTTPStatus = HTTPStatus($num);
93 )+
94
95 }
96 }
97}
98
99http_status_codes! {
100 (100, CONTINUE, "Continue");
102 (101, SWITCHING_PROTOCOLS, "Switching Protocols");
104 (102, PROCESSING, "Processing");
106 (200, OK, "OK");
108 (201, CREATED, "Created");
110 (202, ACCEPTED, "Accepted");
112 (204, NO_CONTENT, "No Content");
114 (206, PARTIAL_CONTENT, "Partial Content");
116
117 (300, SPECIAL_RESPONSE, "SPECIAL_RESPONSE");
119 (301, MOVED_PERMANENTLY, "Moved Permanently");
121 (302, MOVED_TEMPORARILY, "Moved Temporarily");
123 (303, SEE_OTHER, "See Other");
125 (304, NOT_MODIFIED, "Not Modified");
127 (307, TEMPORARY_REDIRECT, "Temporary Redirect");
129 (308, PERMANENT_REDIRECT, "Permanent Redirect");
131
132 (400, BAD_REQUEST, "Bad Request");
134 (401, UNAUTHORIZED, "Unauthorized");
136 (403, FORBIDDEN, "Forbidden");
138 (404, NOT_FOUND, "Not Found");
140 (405, NOT_ALLOWED, "Method Not Allowed");
142 (408, REQUEST_TIME_OUT, "Request Time Out");
144 (409, CONFLICT, "Conflict");
146 (411, LENGTH_REQUIRED, "Length Required");
148 (412, PRECONDITION_FAILED, "Precondition Failed");
150 (413, REQUEST_ENTITY_TOO_LARGE, "Payload Too Large");
152 (414, REQUEST_URI_TOO_LARGE, "Request Uri Too Large");
154 (415, UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
156 (416, RANGE_NOT_SATISFIABLE, "Range Not Satisfiable");
158 (421, MISDIRECTED_REQUEST, "Misdirected Request");
160 (429, TOO_MANY_REQUESTS, "Too Many Requests");
162
163 (444, CLOSE, "CLOSE");
167
168 (494, NGINX_CODES, "NGINX_CODES");
170
171 (494, REQUEST_HEADER_TOO_LARGE, "REQUEST_HEADER_TOO_LARGE");
173
174 (495, HTTPS_CERT_ERROR, "NGX_HTTPS_CERT_ERROR");
176 (496, HTTPS_NO_CERT, "NGX_HTTPS_NO_CERT");
178
179 (497, TO_HTTPS, "TO_HTTPS");
185
186 (499, CLIENT_CLOSED_REQUEST, "CLIENT_CLOSED_REQUEST");
188
189 (500, INTERNAL_SERVER_ERROR, "INTERNAL_SERVER_ERROR");
191 (501, NOT_IMPLEMENTED, "NOT_IMPLEMENTED");
193 (502, BAD_GATEWAY, "BAD_GATEWAY");
195 (503, SERVICE_UNAVAILABLE, "SERVICE_UNAVAILABLE");
197 (504, GATEWAY_TIME_OUT, "GATEWAY_TIME_OUT");
199 (505, VERSION_NOT_SUPPORTED, "VERSION_NOT_SUPPORTED");
201 (507, INSUFFICIENT_STORAGE, "INSUFFICIENT_STORAGE");
203}