blob bb06bb1c (10608B) - Raw
1 pub const Client = @import("http/Client.zig"); 2 pub const Server = @import("http/Server.zig"); 3 pub const protocol = @import("http/protocol.zig"); 4 const headers = @import("http/Headers.zig"); 5 6 pub const Headers = headers.Headers; 7 pub const Field = headers.Field; 8 9 pub const Version = enum { 10 @"HTTP/1.0", 11 @"HTTP/1.1", 12 }; 13 14 /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods 15 /// https://datatracker.ietf.org/doc/html/rfc7231#section-4 Initial definiton 16 /// https://datatracker.ietf.org/doc/html/rfc5789#section-2 PATCH 17 pub const Method = enum { 18 GET, 19 HEAD, 20 POST, 21 PUT, 22 DELETE, 23 CONNECT, 24 OPTIONS, 25 TRACE, 26 PATCH, 27 28 /// Returns true if a request of this method is allowed to have a body 29 /// Actual behavior from servers may vary and should still be checked 30 pub fn requestHasBody(self: Method) bool { 31 return switch (self) { 32 .POST, .PUT, .PATCH => true, 33 .GET, .HEAD, .DELETE, .CONNECT, .OPTIONS, .TRACE => false, 34 }; 35 } 36 37 /// Returns true if a response to this method is allowed to have a body 38 /// Actual behavior from clients may vary and should still be checked 39 pub fn responseHasBody(self: Method) bool { 40 return switch (self) { 41 .GET, .POST, .DELETE, .CONNECT, .OPTIONS, .PATCH => true, 42 .HEAD, .PUT, .TRACE => false, 43 }; 44 } 45 46 /// An HTTP method is safe if it doesn't alter the state of the server. 47 /// https://developer.mozilla.org/en-US/docs/Glossary/Safe/HTTP 48 /// https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.1 49 pub fn safe(self: Method) bool { 50 return switch (self) { 51 .GET, .HEAD, .OPTIONS, .TRACE => true, 52 .POST, .PUT, .DELETE, .CONNECT, .PATCH => false, 53 }; 54 } 55 56 /// An HTTP method is idempotent if an identical request can be made once or several times in a row with the same effect while leaving the server in the same state. 57 /// https://developer.mozilla.org/en-US/docs/Glossary/Idempotent 58 /// https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.2 59 pub fn idempotent(self: Method) bool { 60 return switch (self) { 61 .GET, .HEAD, .PUT, .DELETE, .OPTIONS, .TRACE => true, 62 .CONNECT, .POST, .PATCH => false, 63 }; 64 } 65 66 /// A cacheable response is an HTTP response that can be cached, that is stored to be retrieved and used later, saving a new request to the server. 67 /// https://developer.mozilla.org/en-US/docs/Glossary/cacheable 68 /// https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.3 69 pub fn cacheable(self: Method) bool { 70 return switch (self) { 71 .GET, .HEAD => true, 72 .POST, .PUT, .DELETE, .CONNECT, .OPTIONS, .TRACE, .PATCH => false, 73 }; 74 } 75 }; 76 77 /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status 78 pub const Status = enum(u10) { 79 @"continue" = 100, // RFC7231, Section 6.2.1 80 switching_protocols = 101, // RFC7231, Section 6.2.2 81 processing = 102, // RFC2518 82 early_hints = 103, // RFC8297 83 84 ok = 200, // RFC7231, Section 6.3.1 85 created = 201, // RFC7231, Section 6.3.2 86 accepted = 202, // RFC7231, Section 6.3.3 87 non_authoritative_info = 203, // RFC7231, Section 6.3.4 88 no_content = 204, // RFC7231, Section 6.3.5 89 reset_content = 205, // RFC7231, Section 6.3.6 90 partial_content = 206, // RFC7233, Section 4.1 91 multi_status = 207, // RFC4918 92 already_reported = 208, // RFC5842 93 im_used = 226, // RFC3229 94 95 multiple_choice = 300, // RFC7231, Section 6.4.1 96 moved_permanently = 301, // RFC7231, Section 6.4.2 97 found = 302, // RFC7231, Section 6.4.3 98 see_other = 303, // RFC7231, Section 6.4.4 99 not_modified = 304, // RFC7232, Section 4.1 100 use_proxy = 305, // RFC7231, Section 6.4.5 101 temporary_redirect = 307, // RFC7231, Section 6.4.7 102 permanent_redirect = 308, // RFC7538 103 104 bad_request = 400, // RFC7231, Section 6.5.1 105 unauthorized = 401, // RFC7235, Section 3.1 106 payment_required = 402, // RFC7231, Section 6.5.2 107 forbidden = 403, // RFC7231, Section 6.5.3 108 not_found = 404, // RFC7231, Section 6.5.4 109 method_not_allowed = 405, // RFC7231, Section 6.5.5 110 not_acceptable = 406, // RFC7231, Section 6.5.6 111 proxy_auth_required = 407, // RFC7235, Section 3.2 112 request_timeout = 408, // RFC7231, Section 6.5.7 113 conflict = 409, // RFC7231, Section 6.5.8 114 gone = 410, // RFC7231, Section 6.5.9 115 length_required = 411, // RFC7231, Section 6.5.10 116 precondition_failed = 412, // RFC7232, Section 4.2][RFC8144, Section 3.2 117 payload_too_large = 413, // RFC7231, Section 6.5.11 118 uri_too_long = 414, // RFC7231, Section 6.5.12 119 unsupported_media_type = 415, // RFC7231, Section 6.5.13][RFC7694, Section 3 120 range_not_satisfiable = 416, // RFC7233, Section 4.4 121 expectation_failed = 417, // RFC7231, Section 6.5.14 122 teapot = 418, // RFC 7168, 2.3.3 123 misdirected_request = 421, // RFC7540, Section 9.1.2 124 unprocessable_entity = 422, // RFC4918 125 locked = 423, // RFC4918 126 failed_dependency = 424, // RFC4918 127 too_early = 425, // RFC8470 128 upgrade_required = 426, // RFC7231, Section 6.5.15 129 precondition_required = 428, // RFC6585 130 too_many_requests = 429, // RFC6585 131 request_header_fields_too_large = 431, // RFC6585 132 unavailable_for_legal_reasons = 451, // RFC7725 133 134 internal_server_error = 500, // RFC7231, Section 6.6.1 135 not_implemented = 501, // RFC7231, Section 6.6.2 136 bad_gateway = 502, // RFC7231, Section 6.6.3 137 service_unavailable = 503, // RFC7231, Section 6.6.4 138 gateway_timeout = 504, // RFC7231, Section 6.6.5 139 http_version_not_supported = 505, // RFC7231, Section 6.6.6 140 variant_also_negotiates = 506, // RFC2295 141 insufficient_storage = 507, // RFC4918 142 loop_detected = 508, // RFC5842 143 not_extended = 510, // RFC2774 144 network_authentication_required = 511, // RFC6585 145 146 _, 147 148 pub fn phrase(self: Status) ?[]const u8 { 149 return switch (self) { 150 // 1xx statuses 151 .@"continue" => "Continue", 152 .switching_protocols => "Switching Protocols", 153 .processing => "Processing", 154 .early_hints => "Early Hints", 155 156 // 2xx statuses 157 .ok => "OK", 158 .created => "Created", 159 .accepted => "Accepted", 160 .non_authoritative_info => "Non-Authoritative Information", 161 .no_content => "No Content", 162 .reset_content => "Reset Content", 163 .partial_content => "Partial Content", 164 .multi_status => "Multi-Status", 165 .already_reported => "Already Reported", 166 .im_used => "IM Used", 167 168 // 3xx statuses 169 .multiple_choice => "Multiple Choice", 170 .moved_permanently => "Moved Permanently", 171 .found => "Found", 172 .see_other => "See Other", 173 .not_modified => "Not Modified", 174 .use_proxy => "Use Proxy", 175 .temporary_redirect => "Temporary Redirect", 176 .permanent_redirect => "Permanent Redirect", 177 178 // 4xx statuses 179 .bad_request => "Bad Request", 180 .unauthorized => "Unauthorized", 181 .payment_required => "Payment Required", 182 .forbidden => "Forbidden", 183 .not_found => "Not Found", 184 .method_not_allowed => "Method Not Allowed", 185 .not_acceptable => "Not Acceptable", 186 .proxy_auth_required => "Proxy Authentication Required", 187 .request_timeout => "Request Timeout", 188 .conflict => "Conflict", 189 .gone => "Gone", 190 .length_required => "Length Required", 191 .precondition_failed => "Precondition Failed", 192 .payload_too_large => "Payload Too Large", 193 .uri_too_long => "URI Too Long", 194 .unsupported_media_type => "Unsupported Media Type", 195 .range_not_satisfiable => "Range Not Satisfiable", 196 .expectation_failed => "Expectation Failed", 197 .teapot => "I'm a teapot", 198 .misdirected_request => "Misdirected Request", 199 .unprocessable_entity => "Unprocessable Entity", 200 .locked => "Locked", 201 .failed_dependency => "Failed Dependency", 202 .too_early => "Too Early", 203 .upgrade_required => "Upgrade Required", 204 .precondition_required => "Precondition Required", 205 .too_many_requests => "Too Many Requests", 206 .request_header_fields_too_large => "Request Header Fields Too Large", 207 .unavailable_for_legal_reasons => "Unavailable For Legal Reasons", 208 209 // 5xx statuses 210 .internal_server_error => "Internal Server Error", 211 .not_implemented => "Not Implemented", 212 .bad_gateway => "Bad Gateway", 213 .service_unavailable => "Service Unavailable", 214 .gateway_timeout => "Gateway Timeout", 215 .http_version_not_supported => "HTTP Version Not Supported", 216 .variant_also_negotiates => "Variant Also Negotiates", 217 .insufficient_storage => "Insufficient Storage", 218 .loop_detected => "Loop Detected", 219 .not_extended => "Not Extended", 220 .network_authentication_required => "Network Authentication Required", 221 222 else => return null, 223 }; 224 } 225 226 pub const Class = enum { 227 informational, 228 success, 229 redirect, 230 client_error, 231 server_error, 232 }; 233 234 pub fn class(self: Status) Class { 235 return switch (@enumToInt(self)) { 236 100...199 => .informational, 237 200...299 => .success, 238 300...399 => .redirect, 239 400...499 => .client_error, 240 else => .server_error, 241 }; 242 } 243 244 test { 245 try std.testing.expectEqualStrings("OK", Status.ok.phrase().?); 246 try std.testing.expectEqualStrings("Not Found", Status.not_found.phrase().?); 247 } 248 249 test { 250 try std.testing.expectEqual(@as(?Status.Class, Status.Class.success), Status.ok.class()); 251 try std.testing.expectEqual(@as(?Status.Class, Status.Class.client_error), Status.not_found.class()); 252 } 253 }; 254 255 pub const TransferEncoding = enum { 256 chunked, 257 // compression is intentionally omitted here, as std.http.Client stores it as content-encoding 258 }; 259 260 pub const ContentEncoding = enum { 261 compress, 262 deflate, 263 gzip, 264 zstd, 265 }; 266 267 pub const Connection = enum { 268 keep_alive, 269 close, 270 }; 271 272 const std = @import("std.zig"); 273 274 test { 275 _ = Client; 276 _ = Method; 277 _ = Status; 278 _ = @import("http/test.zig"); 279 }