lph-11/odin-http/status.odin
2025-03-13 18:14:21 +13:00

150 lines
4.4 KiB
Odin

package http
import "core:fmt"
import "core:strings"
Status :: enum {
Continue = 100,
Switching_Protocols = 101,
Processing = 102,
Early_Hints = 103,
OK = 200,
Created = 201,
Accepted = 202,
Non_Authoritative_Information = 203,
No_Content = 204,
Reset_Content = 205,
Partial_Content = 206,
Multi_Status = 207,
Already_Reported = 208,
IM_Used = 226,
Multiple_Choices = 300,
Moved_Permanently = 301,
Found = 302,
See_Other = 303,
Not_Modified = 304,
Use_Proxy = 305, // Deprecated.
Unused = 306, // Deprecated.
Temporary_Redirect = 307,
Permanent_Redirect = 308,
Bad_Request = 400,
Unauthorized = 401,
Payment_Required = 402,
Forbidden = 403,
Not_Found = 404,
Method_Not_Allowed = 405,
Not_Acceptable = 406,
Proxy_Authentication_Required = 407,
Request_Timeout = 408,
Conflict = 409,
Gone = 410,
Length_Required = 411,
Precondition_Failed = 412,
Payload_Too_Large = 413,
URI_Too_Long = 414,
Unsupported_Media_Type = 415,
Range_Not_Satisfiable = 416,
Expectation_Failed = 417,
Im_A_Teapot = 418,
Misdirected_Request = 421,
Unprocessable_Content = 422,
Locked = 423,
Failed_Dependency = 424,
Too_Early = 425,
Upgrade_Required = 426,
Precondition_Required = 428,
Too_Many_Requests = 429,
Request_Header_Fields_Too_Large = 431,
Unavailable_For_Legal_Reasons = 451,
Internal_Server_Error = 500,
Not_Implemented = 501,
Bad_Gateway = 502,
Service_Unavailable = 503,
Gateway_Timeout = 504,
HTTP_Version_Not_Supported = 505,
Variant_Also_Negotiates = 506,
Insufficient_Storage = 507,
Loop_Detected = 508,
Not_Extended = 510,
Network_Authentication_Required = 511,
}
_status_strings: [max(Status) + Status(1)]string
// Populates the status_strings like a map from status to their string representation.
// Where an empty string means an invalid code.
@(init, private)
status_strings_init :: proc() {
for field in Status {
name, ok := fmt.enum_value_to_string(field)
assert(ok)
b: strings.Builder
strings.write_int(&b, int(field))
strings.write_byte(&b, ' ')
// Some edge cases aside, replaces underscores in the enum name with spaces.
#partial switch field {
case .Non_Authoritative_Information: strings.write_string(&b, "Non-Authoritative Information")
case .Multi_Status: strings.write_string(&b, "Multi-Status")
case .Im_A_Teapot: strings.write_string(&b, "I'm a teapot")
case:
for c in name {
switch c {
case '_': strings.write_rune(&b, ' ')
case: strings.write_rune(&b, c)
}
}
}
_status_strings[field] = strings.to_string(b)
}
}
status_string :: proc(s: Status) -> string {
if s >= Status(0) && s <= max(Status) {
return _status_strings[s]
}
return ""
}
status_valid :: proc(s: Status) -> bool {
return status_string(s) != ""
}
status_from_string :: proc(s: string) -> (Status, bool) {
if len(s) < 3 do return {}, false
code_int := int(s[0]-'0')*100 + (int(s[1]-'0')*10) + int(s[2]-'0')
if !status_valid(Status(code_int)) {
return {}, false
}
return Status(code_int), true
}
status_is_informational :: proc(s: Status) -> bool {
return s >= Status(100) && s < Status(200)
}
status_is_success :: proc(s: Status) -> bool {
return s >= Status(200) && s < Status(300)
}
status_is_redirect :: proc(s: Status) -> bool {
return s >= Status(300) && s < Status(400)
}
status_is_client_error :: proc(s: Status) -> bool {
return s >= Status(400) && s < Status(500)
}
status_is_server_error :: proc(s: Status) -> bool {
return s >= Status(500) && s < Status(600)
}