150 lines
4.4 KiB
Odin
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)
|
|
}
|