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 }