authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2022-05-11 12:43:18-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-11 15:43:18-04:00
log3a64693db30d0a9d72dcc34d3ae053f25927f5ec
tree169e131ef728a8bee06a6396420e2d23780f1781
parent19003de64cfc6ea0b760998acee340c893075882
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

std: add http definitions for Method and Status (#10661)


4 files changed, 256 insertions(+), 0 deletions(-)

lib/std/http.zig created+8
......@@ -0,0 +1,8 @@
1const std = @import("std.zig");
2
3pub const Method = @import("http/method.zig").Method;
4pub const Status = @import("http/status.zig").Status;
5
6test {
7 std.testing.refAllDecls(@This());
8}
lib/std/http/method.zig created+65
......@@ -0,0 +1,65 @@
1//! HTTP Methods
2//! https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
3
4// Style guide is violated here so that @tagName can be used effectively
5/// https://datatracker.ietf.org/doc/html/rfc7231#section-4 Initial definiton
6/// https://datatracker.ietf.org/doc/html/rfc5789#section-2 PATCH
7pub const Method = enum {
8 GET,
9 HEAD,
10 POST,
11 PUT,
12 DELETE,
13 CONNECT,
14 OPTIONS,
15 TRACE,
16 PATCH,
17
18 /// Returns true if a request of this method is allowed to have a body
19 /// Actual behavior from servers may vary and should still be checked
20 pub fn requestHasBody(self: Method) bool {
21 return switch (self) {
22 .POST, .PUT, .PATCH => true,
23 .GET, .HEAD, .DELETE, .CONNECT, .OPTIONS, .TRACE => false,
24 };
25 }
26
27 /// Returns true if a response to this method is allowed to have a body
28 /// Actual behavior from clients may vary and should still be checked
29 pub fn responseHasBody(self: Method) bool {
30 return switch (self) {
31 .GET, .POST, .DELETE, .CONNECT, .OPTIONS, .PATCH => true,
32 .HEAD, .PUT, .TRACE => false,
33 };
34 }
35
36 /// An HTTP method is safe if it doesn't alter the state of the server.
37 /// https://developer.mozilla.org/en-US/docs/Glossary/Safe/HTTP
38 /// https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.1
39 pub fn safe(self: Method) bool {
40 return switch (self) {
41 .GET, .HEAD, .OPTIONS, .TRACE => true,
42 .POST, .PUT, .DELETE, .CONNECT, .PATCH => false,
43 };
44 }
45
46 /// 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.
47 /// https://developer.mozilla.org/en-US/docs/Glossary/Idempotent
48 /// https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.2
49 pub fn idempotent(self: Method) bool {
50 return switch (self) {
51 .GET, .HEAD, .PUT, .DELETE, .OPTIONS, .TRACE => true,
52 .CONNECT, .POST, .PATCH => false,
53 };
54 }
55
56 /// 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.
57 /// https://developer.mozilla.org/en-US/docs/Glossary/cacheable
58 /// https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.3
59 pub fn cacheable(self: Method) bool {
60 return switch (self) {
61 .GET, .HEAD => true,
62 .POST, .PUT, .DELETE, .CONNECT, .OPTIONS, .TRACE, .PATCH => false,
63 };
64 }
65};
lib/std/http/status.zig created+182
......@@ -0,0 +1,182 @@
1//! HTTP Status
2//! https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
3
4const std = @import("../std.zig");
5
6pub const Status = enum(u10) {
7 @"continue" = 100, // RFC7231, Section 6.2.1
8 switching_protcols = 101, // RFC7231, Section 6.2.2
9 processing = 102, // RFC2518
10 early_hints = 103, // RFC8297
11
12 ok = 200, // RFC7231, Section 6.3.1
13 created = 201, // RFC7231, Section 6.3.2
14 accepted = 202, // RFC7231, Section 6.3.3
15 non_authoritative_info = 203, // RFC7231, Section 6.3.4
16 no_content = 204, // RFC7231, Section 6.3.5
17 reset_content = 205, // RFC7231, Section 6.3.6
18 partial_content = 206, // RFC7233, Section 4.1
19 multi_status = 207, // RFC4918
20 already_reported = 208, // RFC5842
21 im_used = 226, // RFC3229
22
23 multiple_choice = 300, // RFC7231, Section 6.4.1
24 moved_permanently = 301, // RFC7231, Section 6.4.2
25 found = 302, // RFC7231, Section 6.4.3
26 see_other = 303, // RFC7231, Section 6.4.4
27 not_modified = 304, // RFC7232, Section 4.1
28 use_proxy = 305, // RFC7231, Section 6.4.5
29 temporary_redirect = 307, // RFC7231, Section 6.4.7
30 permanent_redirect = 308, // RFC7538
31
32 bad_request = 400, // RFC7231, Section 6.5.1
33 unauthorized = 401, // RFC7235, Section 3.1
34 payment_required = 402, // RFC7231, Section 6.5.2
35 forbidden = 403, // RFC7231, Section 6.5.3
36 not_found = 404, // RFC7231, Section 6.5.4
37 method_not_allowed = 405, // RFC7231, Section 6.5.5
38 not_acceptable = 406, // RFC7231, Section 6.5.6
39 proxy_auth_required = 407, // RFC7235, Section 3.2
40 request_timeout = 408, // RFC7231, Section 6.5.7
41 conflict = 409, // RFC7231, Section 6.5.8
42 gone = 410, // RFC7231, Section 6.5.9
43 length_required = 411, // RFC7231, Section 6.5.10
44 precondition_failed = 412, // RFC7232, Section 4.2][RFC8144, Section 3.2
45 payload_too_large = 413, // RFC7231, Section 6.5.11
46 uri_too_long = 414, // RFC7231, Section 6.5.12
47 unsupported_media_type = 415, // RFC7231, Section 6.5.13][RFC7694, Section 3
48 range_not_satisfiable = 416, // RFC7233, Section 4.4
49 expectation_failed = 417, // RFC7231, Section 6.5.14
50 teapot = 418, // RFC 7168, 2.3.3
51 misdirected_request = 421, // RFC7540, Section 9.1.2
52 unprocessable_entity = 422, // RFC4918
53 locked = 423, // RFC4918
54 failed_dependency = 424, // RFC4918
55 too_early = 425, // RFC8470
56 upgrade_required = 426, // RFC7231, Section 6.5.15
57 precondition_required = 428, // RFC6585
58 too_many_requests = 429, // RFC6585
59 header_fields_too_large = 431, // RFC6585
60 unavailable_for_legal_reasons = 451, // RFC7725
61
62 internal_server_error = 500, // RFC7231, Section 6.6.1
63 not_implemented = 501, // RFC7231, Section 6.6.2
64 bad_gateway = 502, // RFC7231, Section 6.6.3
65 service_unavailable = 503, // RFC7231, Section 6.6.4
66 gateway_timeout = 504, // RFC7231, Section 6.6.5
67 http_version_not_supported = 505, // RFC7231, Section 6.6.6
68 variant_also_negotiates = 506, // RFC2295
69 insufficient_storage = 507, // RFC4918
70 loop_detected = 508, // RFC5842
71 not_extended = 510, // RFC2774
72 network_authentication_required = 511, // RFC6585
73
74 _,
75
76 pub fn phrase(self: Status) ?[]const u8 {
77 return switch (self) {
78 // 1xx statuses
79 .@"continue" => "Continue",
80 .switching_protcols => "Switching Protocols",
81 .processing => "Processing",
82 .early_hints => "Early Hints",
83
84 // 2xx statuses
85 .ok => "OK",
86 .created => "Created",
87 .accepted => "Accepted",
88 .non_authoritative_info => "Non-Authoritative Information",
89 .no_content => "No Content",
90 .reset_content => "Reset Content",
91 .partial_content => "Partial Content",
92 .multi_status => "Multi-Status",
93 .already_reported => "Already Reported",
94 .im_used => "IM Used",
95
96 // 3xx statuses
97 .multiple_choice => "Multiple Choice",
98 .moved_permanently => "Moved Permanently",
99 .found => "Found",
100 .see_other => "See Other",
101 .not_modified => "Not Modified",
102 .use_proxy => "Use Proxy",
103 .temporary_redirect => "Temporary Redirect",
104 .permanent_redirect => "Permanent Redirect",
105
106 // 4xx statuses
107 .bad_request => "Bad Request",
108 .unauthorized => "Unauthorized",
109 .payment_required => "Payment Required",
110 .forbidden => "Forbidden",
111 .not_found => "Not Found",
112 .method_not_allowed => "Method Not Allowed",
113 .not_acceptable => "Not Acceptable",
114 .proxy_auth_required => "Proxy Authentication Required",
115 .request_timeout => "Request Timeout",
116 .conflict => "Conflict",
117 .gone => "Gone",
118 .length_required => "Length Required",
119 .precondition_failed => "Precondition Failed",
120 .payload_too_large => "Payload Too Large",
121 .uri_too_long => "URI Too Long",
122 .unsupported_media_type => "Unsupported Media Type",
123 .range_not_satisfiable => "Range Not Satisfiable",
124 .expectation_failed => "Expectation Failed",
125 .teapot => "I'm a teapot",
126 .misdirected_request => "Misdirected Request",
127 .unprocessable_entity => "Unprocessable Entity",
128 .locked => "Locked",
129 .failed_dependency => "Failed Dependency",
130 .too_early => "Too Early",
131 .upgrade_required => "Upgrade Required",
132 .precondition_required => "Precondition Required",
133 .too_many_requests => "Too Many Requests",
134 .header_fields_too_large => "Request Header Fields Too Large",
135 .unavailable_for_legal_reasons => "Unavailable For Legal Reasons",
136
137 // 5xx statuses
138 .internal_server_error => "Internal Server Error",
139 .not_implemented => "Not Implemented",
140 .bad_gateway => "Bad Gateway",
141 .service_unavailable => "Service Unavailable",
142 .gateway_timeout => "Gateway Timeout",
143 .http_version_not_supported => "HTTP Version Not Supported",
144 .variant_also_negotiates => "Variant Also Negotiates",
145 .insufficient_storage => "Insufficient Storage",
146 .loop_detected => "Loop Detected",
147 .not_extended => "Not Extended",
148 .network_authentication_required => "Network Authentication Required",
149
150 else => return null,
151 };
152 }
153
154 pub const Class = enum {
155 informational,
156 success,
157 redirect,
158 client_error,
159 server_error,
160 };
161
162 pub fn class(self: Status) ?Class {
163 return switch (@enumToInt(self)) {
164 100...199 => .informational,
165 200...299 => .success,
166 300...399 => .redirect,
167 400...499 => .client_error,
168 500...599 => .server_error,
169 else => null,
170 };
171 }
172};
173
174test {
175 try std.testing.expectEqualStrings("OK", Status.ok.phrase().?);
176 try std.testing.expectEqualStrings("Not Found", Status.not_found.phrase().?);
177}
178
179test {
180 try std.testing.expectEqual(@as(?Status.Class, Status.Class.success), Status.ok.class());
181 try std.testing.expectEqual(@as(?Status.Class, Status.Class.client_error), Status.not_found.class());
182}
lib/std/std.zig+1
......@@ -65,6 +65,7 @@ pub const fs = @import("fs.zig");
6565pub const hash = @import("hash.zig");
6666pub const hash_map = @import("hash_map.zig");
6767pub const heap = @import("heap.zig");
68pub const http = @import("http.zig");
6869pub const io = @import("io.zig");
6970pub const json = @import("json.zig");
7071pub const leb = @import("leb128.zig");