1 module hunt.http.codec.http.model.HttpStatus;
2 
3 import hunt.util.traits;
4 import std.conv;
5 import std.format;
6 
7 alias HttpStatusCode = HttpStatus.Code;
8 
9 /**
10  * <p>
11  * Http Status Codes
12  * </p>
13  * 
14  * @see <a href="http://www.iana.org/assignments/http-status-codes/">IANA HTTP
15  *      Status Code Registry</a>
16  */
17 class HttpStatus {
18 	enum CONTINUE_100 = 100;
19 	enum SWITCHING_PROTOCOLS_101 = 101;
20 	enum PROCESSING_102 = 102;
21 
22 	enum OK_200 = 200;
23 	enum CREATED_201 = 201;
24 	enum ACCEPTED_202 = 202;
25 	enum NON_AUTHORITATIVE_INFORMATION_203 = 203;
26 	enum NO_CONTENT_204 = 204;
27 	enum RESET_CONTENT_205 = 205;
28 	enum PARTIAL_CONTENT_206 = 206;
29 	enum MULTI_STATUS_207 = 207;
30 
31 	enum MULTIPLE_CHOICES_300 = 300;
32 	enum MOVED_PERMANENTLY_301 = 301;
33 	enum MOVED_TEMPORARILY_302 = 302;
34 	enum FOUND_302 = 302;
35 	enum SEE_OTHER_303 = 303;
36 	enum NOT_MODIFIED_304 = 304;
37 	enum USE_PROXY_305 = 305;
38 	enum TEMPORARY_REDIRECT_307 = 307;
39 	enum PERMANENT_REDIRECT_308 = 308;
40 
41 	enum BAD_REQUEST_400 = 400;
42 	enum UNAUTHORIZED_401 = 401;
43 	enum PAYMENT_REQUIRED_402 = 402;
44 	enum FORBIDDEN_403 = 403;
45 	enum NOT_FOUND_404 = 404;
46 	enum METHOD_NOT_ALLOWED_405 = 405;
47 	enum NOT_ACCEPTABLE_406 = 406;
48 	enum PROXY_AUTHENTICATION_REQUIRED_407 = 407;
49 	enum REQUEST_TIMEOUT_408 = 408;
50 	enum CONFLICT_409 = 409;
51 	enum GONE_410 = 410;
52 	enum LENGTH_REQUIRED_411 = 411;
53 	enum PRECONDITION_FAILED_412 = 412;
54 	deprecated("")
55 	enum REQUEST_ENTITY_TOO_LARGE_413 = 413;
56 	enum PAYLOAD_TOO_LARGE_413 = 413;
57 	deprecated("")
58 	enum REQUEST_URI_TOO_LONG_414 = 414;
59 	enum URI_TOO_LONG_414 = 414;
60 	enum UNSUPPORTED_MEDIA_TYPE_415 = 415;
61 	deprecated("")
62 	enum REQUESTED_RANGE_NOT_SATISFIABLE_416 = 416;
63 	enum RANGE_NOT_SATISFIABLE_416 = 416;
64 	enum EXPECTATION_FAILED_417 = 417;
65 	enum IM_A_TEAPOT_418 = 418;
66 	enum ENHANCE_YOUR_CALM_420 = 420;
67 	enum MISDIRECTED_REQUEST_421 = 421;
68 	enum UNPROCESSABLE_ENTITY_422 = 422;
69 	enum LOCKED_423 = 423;
70 	enum FAILED_DEPENDENCY_424 = 424;
71 	enum UPGRADE_REQUIRED_426 = 426;
72 	enum PRECONDITION_REQUIRED_428 = 428;
73 	enum TOO_MANY_REQUESTS_429 = 429;
74 	enum REQUEST_HEADER_FIELDS_TOO_LARGE_431 = 431;
75 	enum UNAVAILABLE_FOR_LEGAL_REASONS_451 = 451;
76 
77 	enum INTERNAL_SERVER_ERROR_500 = 500;
78 	enum NOT_IMPLEMENTED_501 = 501;
79 	enum BAD_GATEWAY_502 = 502;
80 	enum SERVICE_UNAVAILABLE_503 = 503;
81 	enum GATEWAY_TIMEOUT_504 = 504;
82 	enum HTTP_VERSION_NOT_SUPPORTED_505 = 505;
83 	enum INSUFFICIENT_STORAGE_507 = 507;
84 	enum LOOP_DETECTED_508 = 508;
85 	enum NOT_EXTENDED_510 = 510;
86 	enum NETWORK_AUTHENTICATION_REQUIRED_511 = 511;
87 
88 	enum MAX_CODE = 511  + 1;
89 
90 	private __gshared Code[] codeMap; // = new Code[MAX_CODE + 1];
91 
92 	shared static this() {
93 		codeMap = new Code[MAX_CODE + 1];
94 		foreach (Code code ; Code.values()) {
95 			codeMap[code._code] = code;
96 		}
97 	}
98 
99 	struct Code {
100 		enum Code Null = Code(MAX_CODE, "");
101 		enum Code CONTINUE = Code(CONTINUE_100, "Continue");
102         enum Code SWITCHING_PROTOCOLS = Code(SWITCHING_PROTOCOLS_101, "Switching Protocols");
103         enum Code PROCESSING = Code(PROCESSING_102, "Processing");
104 
105 
106         enum Code OK = Code(OK_200, "OK");
107         enum Code CREATED = Code(CREATED_201, "Created");
108         enum Code ACCEPTED = Code(ACCEPTED_202, "Accepted");
109         enum Code NON_AUTHORITATIVE_INFORMATION = Code(NON_AUTHORITATIVE_INFORMATION_203, "Non Authoritative Information");
110         enum Code NO_CONTENT = Code(NO_CONTENT_204, "No Content");
111         enum Code RESET_CONTENT = Code(RESET_CONTENT_205, "Reset Content");
112         enum Code PARTIAL_CONTENT = Code(PARTIAL_CONTENT_206, "Partial Content");
113         enum Code MULTI_STATUS = Code(MULTI_STATUS_207, "Multi-Status");
114 
115         enum Code MULTIPLE_CHOICES = Code(MULTIPLE_CHOICES_300, "Multiple Choices");
116         enum Code MOVED_PERMANENTLY = Code(MOVED_PERMANENTLY_301, "Moved Permanently");
117         enum Code MOVED_TEMPORARILY = Code(MOVED_TEMPORARILY_302, "Moved Temporarily");
118         enum Code FOUND = Code(FOUND_302, "Found");
119         enum Code SEE_OTHER = Code(SEE_OTHER_303, "See Other");
120         enum Code NOT_MODIFIED = Code(NOT_MODIFIED_304, "Not Modified");
121         enum Code USE_PROXY = Code(USE_PROXY_305, "Use Proxy");
122         enum Code TEMPORARY_REDIRECT = Code(TEMPORARY_REDIRECT_307, "Temporary Redirect");
123         enum Code PERMANET_REDIRECT = Code(PERMANENT_REDIRECT_308, "Permanent Redirect");
124 
125         enum Code BAD_REQUEST = Code(BAD_REQUEST_400, "Bad Request");
126         enum Code UNAUTHORIZED = Code(UNAUTHORIZED_401, "Unauthorized");
127         enum Code PAYMENT_REQUIRED = Code(PAYMENT_REQUIRED_402, "Payment Required");
128         enum Code FORBIDDEN = Code(FORBIDDEN_403, "Forbidden");
129         enum Code NOT_FOUND = Code(NOT_FOUND_404, "Not Found");
130         enum Code METHOD_NOT_ALLOWED = Code(METHOD_NOT_ALLOWED_405, "Method Not Allowed");
131         enum Code NOT_ACCEPTABLE = Code(NOT_ACCEPTABLE_406, "Not Acceptable");
132         enum Code PROXY_AUTHENTICATION_REQUIRED = Code(PROXY_AUTHENTICATION_REQUIRED_407, "Proxy Authentication Required");
133         enum Code REQUEST_TIMEOUT = Code(REQUEST_TIMEOUT_408, "Request Timeout");
134         enum Code CONFLICT = Code(CONFLICT_409, "Conflict");
135         enum Code GONE = Code(GONE_410, "Gone");
136         enum Code LENGTH_REQUIRED = Code(LENGTH_REQUIRED_411, "Length Required");
137         enum Code PRECONDITION_FAILED = Code(PRECONDITION_FAILED_412, "Precondition Failed");
138         enum Code PAYLOAD_TOO_LARGE = Code(PAYLOAD_TOO_LARGE_413, "Payload Too Large");
139         enum Code URI_TOO_LONG = Code(URI_TOO_LONG_414, "URI Too Long");
140         enum Code UNSUPPORTED_MEDIA_TYPE = Code(UNSUPPORTED_MEDIA_TYPE_415, "Unsupported Media Type");
141         enum Code RANGE_NOT_SATISFIABLE = Code(RANGE_NOT_SATISFIABLE_416, "Range Not Satisfiable");
142         enum Code EXPECTATION_FAILED = Code(EXPECTATION_FAILED_417, "Expectation Failed");
143         enum Code IM_A_TEAPOT = Code(IM_A_TEAPOT_418, "I'm a Teapot");
144         enum Code ENHANCE_YOUR_CALM = Code(ENHANCE_YOUR_CALM_420, "Enhance your Calm");
145         enum Code MISDIRECTED_REQUEST = Code(MISDIRECTED_REQUEST_421, "Misdirected Request");
146         enum Code UNPROCESSABLE_ENTITY = Code(UNPROCESSABLE_ENTITY_422, "Unprocessable Entity");
147         enum Code LOCKED = Code(LOCKED_423, "Locked");
148         enum Code FAILED_DEPENDENCY = Code(FAILED_DEPENDENCY_424, "Failed Dependency");
149         enum Code UPGRADE_REQUIRED = Code(UPGRADE_REQUIRED_426, "Upgrade Required");
150         enum Code PRECONDITION_REQUIRED = Code(PRECONDITION_REQUIRED_428, "Precondition Required");
151         enum Code TOO_MANY_REQUESTS = Code(TOO_MANY_REQUESTS_429, "Too Many Requests");
152         enum Code REQUEST_HEADER_FIELDS_TOO_LARGE = Code(REQUEST_HEADER_FIELDS_TOO_LARGE_431, "Request Header Fields Too Large");
153         enum Code UNAVAILABLE_FOR_LEGAL_REASONS = Code(UNAVAILABLE_FOR_LEGAL_REASONS_451, "Unavailable for Legal Reason");
154 
155         enum Code INTERNAL_SERVER_ERROR = Code(INTERNAL_SERVER_ERROR_500, "Server Error");
156         enum Code NOT_IMPLEMENTED = Code(NOT_IMPLEMENTED_501, "Not Implemented");
157         enum Code BAD_GATEWAY = Code(BAD_GATEWAY_502, "Bad Gateway");
158         enum Code SERVICE_UNAVAILABLE = Code(SERVICE_UNAVAILABLE_503, "Service Unavailable");
159         enum Code GATEWAY_TIMEOUT = Code(GATEWAY_TIMEOUT_504, "Gateway Timeout");
160         enum Code HTTP_VERSION_NOT_SUPPORTED = Code(HTTP_VERSION_NOT_SUPPORTED_505, "HTTP Version Not Supported");
161         enum Code INSUFFICIENT_STORAGE = Code(INSUFFICIENT_STORAGE_507, "Insufficient Storage");
162         enum Code LOOP_DETECTED = Code(LOOP_DETECTED_508, "Loop Detected");
163         enum Code NOT_EXTENDED = Code(NOT_EXTENDED_510, "Not Extended");
164         enum Code NETWORK_AUTHENTICATION_REQUIRED = Code(NETWORK_AUTHENTICATION_REQUIRED_511, "Network Authentication Required");
165         
166 
167 		private int _code;
168 		private string _message;
169 
170 		private this(int code, string message) {
171 			this._code = code;
172 			_message = message;
173 		}
174 
175 		mixin GetConstantValues!(Code);
176 
177 		int getCode() {
178 			return _code;
179 		}
180 
181 		string getMessage() {
182 			return _message;
183 		}
184 
185 		bool equals(int code) {
186 			return (this._code == code);
187 		}
188 
189 		string toString() {
190 			return format("[%03d %s]", this._code, this._message);
191 		}
192 
193 		/**
194 		 * Simple test against an code to determine if it falls into the
195 		 * <code>Informational</code> message category as defined in the
196 		 * <a href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>,
197 		 * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 -
198 		 * HTTP/1.1</a>.
199 		 *
200 		 * @return true if within range of codes that belongs to
201 		 *         <code>Informational</code> messages.
202 		 */
203 		bool isInformational() {
204 			return HttpStatus.isInformational(this._code);
205 		}
206 
207 		/**
208 		 * Simple test against an code to determine if it falls into the
209 		 * <code>Success</code> message category as defined in the
210 		 * <a href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>,
211 		 * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 -
212 		 * HTTP/1.1</a>.
213 		 *
214 		 * @return true if within range of codes that belongs to
215 		 *         <code>Success</code> messages.
216 		 */
217 		bool isSuccess() {
218 			return HttpStatus.isSuccess(this._code);
219 		}
220 
221 		/**
222 		 * Simple test against an code to determine if it falls into the
223 		 * <code>Redirection</code> message category as defined in the
224 		 * <a href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>,
225 		 * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 -
226 		 * HTTP/1.1</a>.
227 		 *
228 		 * @return true if within range of codes that belongs to
229 		 *         <code>Redirection</code> messages.
230 		 */
231 		bool isRedirection() {
232 			return HttpStatus.isRedirection(this._code);
233 		}
234 
235 		/**
236 		 * Simple test against an code to determine if it falls into the
237 		 * <code>Client Error</code> message category as defined in the
238 		 * <a href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>,
239 		 * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 -
240 		 * HTTP/1.1</a>.
241 		 *
242 		 * @return true if within range of codes that belongs to
243 		 *         <code>Client Error</code> messages.
244 		 */
245 		bool isClientError() {
246 			return HttpStatus.isClientError(this._code);
247 		}
248 
249 		/**
250 		 * Simple test against an code to determine if it falls into the
251 		 * <code>Server Error</code> message category as defined in the
252 		 * <a href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>,
253 		 * and <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 -
254 		 * HTTP/1.1</a>.
255 		 *
256 		 * @return true if within range of codes that belongs to
257 		 *         <code>Server Error</code> messages.
258 		 */
259 		bool isServerError() {
260 			return HttpStatus.isServerError(this._code);
261 		}
262 	}
263 
264 	/**
265 	 * Get the HttpStatusCode for a specific code
266 	 *
267 	 * @param code
268 	 *            the code to lookup.
269 	 * @return the {@link HttpStatus} if found, or null if not found.
270 	 */
271 	static Code getCode(int code) {
272 		if (code <= MAX_CODE) {
273 			return codeMap[code];
274 		}
275 		return Code.Null;
276 	}
277 
278 	/**
279 	 * Get the status message for a specific code.
280 	 *
281 	 * @param code
282 	 *            the code to look up
283 	 * @return the specific message, or the code number itself if code does not
284 	 *         match known list.
285 	 */
286 	static string getMessage(int code) {
287 		Code codeEnum = getCode(code);
288 		if (codeEnum != Code.Null) {
289 			return codeEnum.getMessage();
290 		} else {
291 			return std.conv.to!(string)(code);
292 		}
293 	}
294 
295 	/**
296 	 * Simple test against an code to determine if it falls into the
297 	 * <code>Informational</code> message category as defined in the
298 	 * <a href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and
299 	 * <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>.
300 	 *
301 	 * @param code
302 	 *            the code to test.
303 	 * @return true if within range of codes that belongs to
304 	 *         <code>Informational</code> messages.
305 	 */
306 	static bool isInformational(int code) {
307 		return ((100 <= code) && (code <= 199));
308 	}
309 
310 	/**
311 	 * Simple test against an code to determine if it falls into the
312 	 * <code>Success</code> message category as defined in the
313 	 * <a href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and
314 	 * <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>.
315 	 *
316 	 * @param code
317 	 *            the code to test.
318 	 * @return true if within range of codes that belongs to
319 	 *         <code>Success</code> messages.
320 	 */
321 	static bool isSuccess(int code) {
322 		return ((200 <= code) && (code <= 299));
323 	}
324 
325 	/**
326 	 * Simple test against an code to determine if it falls into the
327 	 * <code>Redirection</code> message category as defined in the
328 	 * <a href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and
329 	 * <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>.
330 	 *
331 	 * @param code
332 	 *            the code to test.
333 	 * @return true if within range of codes that belongs to
334 	 *         <code>Redirection</code> messages.
335 	 */
336 	static bool isRedirection(int code) {
337 		return ((300 <= code) && (code <= 399));
338 	}
339 
340 	/**
341 	 * Simple test against an code to determine if it falls into the
342 	 * <code>Client Error</code> message category as defined in the
343 	 * <a href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and
344 	 * <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>.
345 	 *
346 	 * @param code
347 	 *            the code to test.
348 	 * @return true if within range of codes that belongs to
349 	 *         <code>Client Error</code> messages.
350 	 */
351 	static bool isClientError(int code) {
352 		return ((400 <= code) && (code <= 499));
353 	}
354 
355 	/**
356 	 * Simple test against an code to determine if it falls into the
357 	 * <code>Server Error</code> message category as defined in the
358 	 * <a href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and
359 	 * <a href="http://tools.ietf.org/html/rfc7231">RFC 7231 - HTTP/1.1</a>.
360 	 *
361 	 * @param code
362 	 *            the code to test.
363 	 * @return true if within range of codes that belongs to
364 	 *         <code>Server Error</code> messages.
365 	 */
366 	static bool isServerError(int code) {
367 		return ((500 <= code) && (code <= 599));
368 	}
369 }