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