authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-11 22:19:41-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-23 02:37:11-07:00
log50e2a5f673d880515caf3497bfb6eb0114149de1
tree81e3aa0e6078f86f4669c3f2189dd54431938da2
parent06d0c58305a04d28da9a2caf510fc906e38a54ef

std.http: remove 'done' flag

This is a state machine that already has a `state` field. No need to additionally store "done" - it just makes things unnecessarily complicated and buggy.

4 files changed, 152 insertions(+), 85 deletions(-)

lib/std/http/Client.zig+12-10
...@@ -610,7 +610,7 @@ pub const Request = struct {...@@ -610,7 +610,7 @@ pub const Request = struct {
610 req.response.headers.deinit();610 req.response.headers.deinit();
611611
612 if (req.connection) |connection| {612 if (req.connection) |connection| {
613 if (!req.response.parser.done) {613 if (req.response.parser.state != .complete) {
614 // If the response wasn't fully read, then we need to close the connection.614 // If the response wasn't fully read, then we need to close the connection.
615 connection.closing = true;615 connection.closing = true;
616 }616 }
...@@ -624,7 +624,7 @@ pub const Request = struct {...@@ -624,7 +624,7 @@ pub const Request = struct {
624 // This function must deallocate all resources associated with the request, or keep those which will be used624 // This function must deallocate all resources associated with the request, or keep those which will be used
625 // This needs to be kept in sync with deinit and request625 // This needs to be kept in sync with deinit and request
626 fn redirect(req: *Request, uri: Uri) !void {626 fn redirect(req: *Request, uri: Uri) !void {
627 assert(req.response.parser.done);627 assert(req.response.parser.state == .complete);
628628
629 switch (req.response.compression) {629 switch (req.response.compression) {
630 .none => {},630 .none => {},
...@@ -794,12 +794,12 @@ pub const Request = struct {...@@ -794,12 +794,12 @@ pub const Request = struct {
794 }794 }
795795
796 fn transferRead(req: *Request, buf: []u8) TransferReadError!usize {796 fn transferRead(req: *Request, buf: []u8) TransferReadError!usize {
797 if (req.response.parser.done) return 0;797 if (req.response.parser.state == .complete) return 0;
798798
799 var index: usize = 0;799 var index: usize = 0;
800 while (index == 0) {800 while (index == 0) {
801 const amt = try req.response.parser.read(req.connection.?, buf[index..], req.response.skip);801 const amt = try req.response.parser.read(req.connection.?, buf[index..], req.response.skip);
802 if (amt == 0 and req.response.parser.done) break;802 if (amt == 0 and req.response.parser.state == .complete) break;
803 index += amt;803 index += amt;
804 }804 }
805805
...@@ -840,7 +840,7 @@ pub const Request = struct {...@@ -840,7 +840,7 @@ pub const Request = struct {
840 try req.response.parse(req.response.parser.get(), false);840 try req.response.parse(req.response.parser.get(), false);
841841
842 if (req.response.status == .@"continue") {842 if (req.response.status == .@"continue") {
843 req.response.parser.done = true; // we're done parsing the continue response, reset to prepare for the real response843 req.response.parser.state = .complete; // we're done parsing the continue response, reset to prepare for the real response
844 req.response.parser.reset();844 req.response.parser.reset();
845845
846 if (req.handle_continue)846 if (req.handle_continue)
...@@ -852,7 +852,7 @@ pub const Request = struct {...@@ -852,7 +852,7 @@ pub const Request = struct {
852 // we're switching protocols, so this connection is no longer doing http852 // we're switching protocols, so this connection is no longer doing http
853 if (req.method == .CONNECT and req.response.status.class() == .success) {853 if (req.method == .CONNECT and req.response.status.class() == .success) {
854 req.connection.?.closing = false;854 req.connection.?.closing = false;
855 req.response.parser.done = true;855 req.response.parser.state = .complete;
856856
857 return; // the connection is not HTTP past this point, return to the caller857 return; // the connection is not HTTP past this point, return to the caller
858 }858 }
...@@ -872,8 +872,10 @@ pub const Request = struct {...@@ -872,8 +872,10 @@ pub const Request = struct {
872 // Any response to a HEAD request and any response with a 1xx (Informational), 204 (No Content), or 304 (Not Modified)872 // Any response to a HEAD request and any response with a 1xx (Informational), 204 (No Content), or 304 (Not Modified)
873 // status code is always terminated by the first empty line after the header fields, regardless of the header fields873 // status code is always terminated by the first empty line after the header fields, regardless of the header fields
874 // present in the message874 // present in the message
875 if (req.method == .HEAD or req.response.status.class() == .informational or req.response.status == .no_content or req.response.status == .not_modified) {875 if (req.method == .HEAD or req.response.status.class() == .informational or
876 req.response.parser.done = true;876 req.response.status == .no_content or req.response.status == .not_modified)
877 {
878 req.response.parser.state = .complete;
877879
878 return; // the response is empty, no further setup or redirection is necessary880 return; // the response is empty, no further setup or redirection is necessary
879 }881 }
...@@ -889,7 +891,7 @@ pub const Request = struct {...@@ -889,7 +891,7 @@ pub const Request = struct {
889 } else if (req.response.content_length) |cl| {891 } else if (req.response.content_length) |cl| {
890 req.response.parser.next_chunk_length = cl;892 req.response.parser.next_chunk_length = cl;
891893
892 if (cl == 0) req.response.parser.done = true;894 if (cl == 0) req.response.parser.state = .complete;
893 } else {895 } else {
894 // read until the connection is closed896 // read until the connection is closed
895 req.response.parser.next_chunk_length = std.math.maxInt(u64);897 req.response.parser.next_chunk_length = std.math.maxInt(u64);
...@@ -947,7 +949,7 @@ pub const Request = struct {...@@ -947,7 +949,7 @@ pub const Request = struct {
947 try req.send(.{});949 try req.send(.{});
948 } else {950 } else {
949 req.response.skip = false;951 req.response.skip = false;
950 if (!req.response.parser.done) {952 if (req.response.parser.state != .complete) {
951 switch (req.response.transfer_compression) {953 switch (req.response.transfer_compression) {
952 .identity => req.response.compression = .none,954 .identity => req.response.compression = .none,
953 .compress, .@"x-compress" => return error.CompressionNotSupported,955 .compress, .@"x-compress" => return error.CompressionNotSupported,
lib/std/http/Server.zig+6-6
...@@ -395,7 +395,7 @@ pub const Response = struct {...@@ -395,7 +395,7 @@ pub const Response = struct {
395 return .reset;395 return .reset;
396 }396 }
397397
398 if (!res.request.parser.done) {398 if (res.request.parser.state != .complete) {
399 // If the response wasn't fully read, then we need to close the connection.399 // If the response wasn't fully read, then we need to close the connection.
400 res.connection.closing = true;400 res.connection.closing = true;
401 return .closing;401 return .closing;
...@@ -534,12 +534,12 @@ pub const Response = struct {...@@ -534,12 +534,12 @@ pub const Response = struct {
534 }534 }
535535
536 fn transferRead(res: *Response, buf: []u8) TransferReadError!usize {536 fn transferRead(res: *Response, buf: []u8) TransferReadError!usize {
537 if (res.request.parser.done) return 0;537 if (res.request.parser.state == .complete) return 0;
538538
539 var index: usize = 0;539 var index: usize = 0;
540 while (index == 0) {540 while (index == 0) {
541 const amt = try res.request.parser.read(&res.connection, buf[index..], false);541 const amt = try res.request.parser.read(&res.connection, buf[index..], false);
542 if (amt == 0 and res.request.parser.done) break;542 if (amt == 0 and res.request.parser.state == .complete) break;
543 index += amt;543 index += amt;
544 }544 }
545545
...@@ -596,12 +596,12 @@ pub const Response = struct {...@@ -596,12 +596,12 @@ pub const Response = struct {
596 } else if (res.request.content_length) |cl| {596 } else if (res.request.content_length) |cl| {
597 res.request.parser.next_chunk_length = cl;597 res.request.parser.next_chunk_length = cl;
598598
599 if (cl == 0) res.request.parser.done = true;599 if (cl == 0) res.request.parser.state = .complete;
600 } else {600 } else {
601 res.request.parser.done = true;601 res.request.parser.state = .complete;
602 }602 }
603603
604 if (!res.request.parser.done) {604 if (res.request.parser.state != .complete) {
605 switch (res.request.transfer_compression) {605 switch (res.request.transfer_compression) {
606 .identity => res.request.compression = .none,606 .identity => res.request.compression = .none,
607 .compress, .@"x-compress" => return error.CompressionNotSupported,607 .compress, .@"x-compress" => return error.CompressionNotSupported,
lib/std/http/protocol.zig+58-50
...@@ -14,7 +14,7 @@ pub const State = enum {...@@ -14,7 +14,7 @@ pub const State = enum {
14 seen_r,14 seen_r,
15 seen_rn,15 seen_rn,
16 seen_rnr,16 seen_rnr,
17 finished,17 headers_end,
18 /// Begin transfer-encoding: chunked parsing states.18 /// Begin transfer-encoding: chunked parsing states.
19 chunk_head_size,19 chunk_head_size,
20 chunk_head_ext,20 chunk_head_ext,
...@@ -22,46 +22,61 @@ pub const State = enum {...@@ -22,46 +22,61 @@ pub const State = enum {
22 chunk_data,22 chunk_data,
23 chunk_data_suffix,23 chunk_data_suffix,
24 chunk_data_suffix_r,24 chunk_data_suffix_r,
25 /// When the parser has finished parsing a complete message. A message is
26 /// only complete after the entire body has been read and any trailing
27 /// headers have been parsed.
28 complete,
2529
26 /// Returns true if the parser is in a content state (ie. not waiting for more headers).30 /// Returns true if the parser is in a content state (ie. not waiting for more headers).
27 pub fn isContent(self: State) bool {31 pub fn isContent(self: State) bool {
28 return switch (self) {32 return switch (self) {
29 .invalid, .start, .seen_n, .seen_r, .seen_rn, .seen_rnr => false,33 .invalid,
30 .finished, .chunk_head_size, .chunk_head_ext, .chunk_head_r, .chunk_data, .chunk_data_suffix, .chunk_data_suffix_r => true,34 .start,
35 .seen_n,
36 .seen_r,
37 .seen_rn,
38 .seen_rnr,
39 => false,
40
41 .headers_end,
42 .chunk_head_size,
43 .chunk_head_ext,
44 .chunk_head_r,
45 .chunk_data,
46 .chunk_data_suffix,
47 .chunk_data_suffix_r,
48 .complete,
49 => true,
31 };50 };
32 }51 }
33};52};
3453
35pub const HeadersParser = struct {54pub const HeadersParser = struct {
36 state: State = .start,55 state: State,
37 /// A fixed buffer of len `max_header_bytes`.56 /// A fixed buffer of len `max_header_bytes`.
38 /// Pointers into this buffer are not stable until after a message is complete.57 /// Pointers into this buffer are not stable until after a message is complete.
39 header_bytes_buffer: []u8,58 header_bytes_buffer: []u8,
40 header_bytes_len: u32,59 header_bytes_len: u32,
41 next_chunk_length: u64,60 next_chunk_length: u64,
42 /// Whether this parser is done parsing a complete message.
43 /// A message is only done when the entire payload has been read.
44 done: bool,
4561
46 /// Initializes the parser with a provided buffer `buf`.62 /// Initializes the parser with a provided buffer `buf`.
47 pub fn init(buf: []u8) HeadersParser {63 pub fn init(buf: []u8) HeadersParser {
48 return .{64 return .{
65 .state = .start,
49 .header_bytes_buffer = buf,66 .header_bytes_buffer = buf,
50 .header_bytes_len = 0,67 .header_bytes_len = 0,
51 .done = false,
52 .next_chunk_length = 0,68 .next_chunk_length = 0,
53 };69 };
54 }70 }
5571
56 /// Reinitialize the parser.72 /// Reinitialize the parser.
57 /// Asserts the parser is in the "done" state.73 /// Asserts the parser is in the `complete` state.
58 pub fn reset(hp: *HeadersParser) void {74 pub fn reset(hp: *HeadersParser) void {
59 assert(hp.done);75 assert(hp.state == .complete);
60 hp.* = .{76 hp.* = .{
61 .state = .start,77 .state = .start,
62 .header_bytes_buffer = hp.header_bytes_buffer,78 .header_bytes_buffer = hp.header_bytes_buffer,
63 .header_bytes_len = 0,79 .header_bytes_len = 0,
64 .done = false,
65 .next_chunk_length = 0,80 .next_chunk_length = 0,
66 };81 };
67 }82 }
...@@ -86,7 +101,8 @@ pub const HeadersParser = struct {...@@ -86,7 +101,8 @@ pub const HeadersParser = struct {
86 while (true) {101 while (true) {
87 switch (r.state) {102 switch (r.state) {
88 .invalid => unreachable,103 .invalid => unreachable,
89 .finished => return index,104 .complete => unreachable,
105 .headers_end => return index,
90 .start => switch (len - index) {106 .start => switch (len - index) {
91 0 => return index,107 0 => return index,
92 1 => {108 1 => {
...@@ -110,7 +126,7 @@ pub const HeadersParser = struct {...@@ -110,7 +126,7 @@ pub const HeadersParser = struct {
110126
111 switch (b16) {127 switch (b16) {
112 int16("\r\n") => r.state = .seen_rn,128 int16("\r\n") => r.state = .seen_rn,
113 int16("\n\n") => r.state = .finished,129 int16("\n\n") => r.state = .headers_end,
114 else => {},130 else => {},
115 }131 }
116132
...@@ -129,7 +145,7 @@ pub const HeadersParser = struct {...@@ -129,7 +145,7 @@ pub const HeadersParser = struct {
129145
130 switch (b16) {146 switch (b16) {
131 int16("\r\n") => r.state = .seen_rn,147 int16("\r\n") => r.state = .seen_rn,
132 int16("\n\n") => r.state = .finished,148 int16("\n\n") => r.state = .headers_end,
133 else => {},149 else => {},
134 }150 }
135151
...@@ -154,7 +170,7 @@ pub const HeadersParser = struct {...@@ -154,7 +170,7 @@ pub const HeadersParser = struct {
154170
155 switch (b16) {171 switch (b16) {
156 int16("\r\n") => r.state = .seen_rn,172 int16("\r\n") => r.state = .seen_rn,
157 int16("\n\n") => r.state = .finished,173 int16("\n\n") => r.state = .headers_end,
158 else => {},174 else => {},
159 }175 }
160176
...@@ -164,7 +180,7 @@ pub const HeadersParser = struct {...@@ -164,7 +180,7 @@ pub const HeadersParser = struct {
164 }180 }
165181
166 switch (b32) {182 switch (b32) {
167 int32("\r\n\r\n") => r.state = .finished,183 int32("\r\n\r\n") => r.state = .headers_end,
168 else => {},184 else => {},
169 }185 }
170186
...@@ -212,7 +228,7 @@ pub const HeadersParser = struct {...@@ -212,7 +228,7 @@ pub const HeadersParser = struct {
212228
213 switch (b16) {229 switch (b16) {
214 int16("\r\n") => r.state = .seen_rn,230 int16("\r\n") => r.state = .seen_rn,
215 int16("\n\n") => r.state = .finished,231 int16("\n\n") => r.state = .headers_end,
216 else => {},232 else => {},
217 }233 }
218 },234 },
...@@ -229,7 +245,7 @@ pub const HeadersParser = struct {...@@ -229,7 +245,7 @@ pub const HeadersParser = struct {
229245
230 switch (b16) {246 switch (b16) {
231 int16("\r\n") => r.state = .seen_rn,247 int16("\r\n") => r.state = .seen_rn,
232 int16("\n\n") => r.state = .finished,248 int16("\n\n") => r.state = .headers_end,
233 else => {},249 else => {},
234 }250 }
235251
...@@ -246,10 +262,10 @@ pub const HeadersParser = struct {...@@ -246,10 +262,10 @@ pub const HeadersParser = struct {
246 const b16 = intShift(u16, b32);262 const b16 = intShift(u16, b32);
247263
248 if (b32 == int32("\r\n\r\n")) {264 if (b32 == int32("\r\n\r\n")) {
249 r.state = .finished;265 r.state = .headers_end;
250 return index + i + 4;266 return index + i + 4;
251 } else if (b16 == int16("\n\n")) {267 } else if (b16 == int16("\n\n")) {
252 r.state = .finished;268 r.state = .headers_end;
253 return index + i + 2;269 return index + i + 2;
254 }270 }
255 }271 }
...@@ -266,7 +282,7 @@ pub const HeadersParser = struct {...@@ -266,7 +282,7 @@ pub const HeadersParser = struct {
266282
267 switch (b16) {283 switch (b16) {
268 int16("\r\n") => r.state = .seen_rn,284 int16("\r\n") => r.state = .seen_rn,
269 int16("\n\n") => r.state = .finished,285 int16("\n\n") => r.state = .headers_end,
270 else => {},286 else => {},
271 }287 }
272288
...@@ -286,7 +302,7 @@ pub const HeadersParser = struct {...@@ -286,7 +302,7 @@ pub const HeadersParser = struct {
286 0 => return index,302 0 => return index,
287 else => {303 else => {
288 switch (bytes[index]) {304 switch (bytes[index]) {
289 '\n' => r.state = .finished,305 '\n' => r.state = .headers_end,
290 else => r.state = .start,306 else => r.state = .start,
291 }307 }
292308
...@@ -318,7 +334,7 @@ pub const HeadersParser = struct {...@@ -318,7 +334,7 @@ pub const HeadersParser = struct {
318 switch (b16) {334 switch (b16) {
319 int16("\r\n") => r.state = .seen_rn,335 int16("\r\n") => r.state = .seen_rn,
320 int16("\n\r") => r.state = .seen_rnr,336 int16("\n\r") => r.state = .seen_rnr,
321 int16("\n\n") => r.state = .finished,337 int16("\n\n") => r.state = .headers_end,
322 else => {},338 else => {},
323 }339 }
324340
...@@ -337,12 +353,12 @@ pub const HeadersParser = struct {...@@ -337,12 +353,12 @@ pub const HeadersParser = struct {
337353
338 switch (b16) {354 switch (b16) {
339 int16("\r\n") => r.state = .seen_rn,355 int16("\r\n") => r.state = .seen_rn,
340 int16("\n\n") => r.state = .finished,356 int16("\n\n") => r.state = .headers_end,
341 else => {},357 else => {},
342 }358 }
343359
344 switch (b24) {360 switch (b24) {
345 int24("\n\r\n") => r.state = .finished,361 int24("\n\r\n") => r.state = .headers_end,
346 else => {},362 else => {},
347 }363 }
348364
...@@ -372,8 +388,8 @@ pub const HeadersParser = struct {...@@ -372,8 +388,8 @@ pub const HeadersParser = struct {
372 }388 }
373389
374 switch (b16) {390 switch (b16) {
375 int16("\r\n") => r.state = .finished,391 int16("\r\n") => r.state = .headers_end,
376 int16("\n\n") => r.state = .finished,392 int16("\n\n") => r.state = .headers_end,
377 else => {},393 else => {},
378 }394 }
379395
...@@ -385,7 +401,7 @@ pub const HeadersParser = struct {...@@ -385,7 +401,7 @@ pub const HeadersParser = struct {
385 0 => return index,401 0 => return index,
386 else => {402 else => {
387 switch (bytes[index]) {403 switch (bytes[index]) {
388 '\n' => r.state = .finished,404 '\n' => r.state = .headers_end,
389 else => r.state = .start,405 else => r.state = .start,
390 }406 }
391407
...@@ -486,13 +502,6 @@ pub const HeadersParser = struct {...@@ -486,13 +502,6 @@ pub const HeadersParser = struct {
486 return len;502 return len;
487 }503 }
488504
489 /// Returns whether or not the parser has finished parsing a complete
490 /// message. A message is only complete after the entire body has been read
491 /// and any trailing headers have been parsed.
492 pub fn isComplete(r: *HeadersParser) bool {
493 return r.done and r.state == .finished;
494 }
495
496 pub const CheckCompleteHeadError = error{HttpHeadersOversize};505 pub const CheckCompleteHeadError = error{HttpHeadersOversize};
497506
498 /// Pushes `in` into the parser. Returns the number of bytes consumed by507 /// Pushes `in` into the parser. Returns the number of bytes consumed by
...@@ -523,13 +532,12 @@ pub const HeadersParser = struct {...@@ -523,13 +532,12 @@ pub const HeadersParser = struct {
523 /// See `std.http.Client.Connection for an example of `conn`.532 /// See `std.http.Client.Connection for an example of `conn`.
524 pub fn read(r: *HeadersParser, conn: anytype, buffer: []u8, skip: bool) !usize {533 pub fn read(r: *HeadersParser, conn: anytype, buffer: []u8, skip: bool) !usize {
525 assert(r.state.isContent());534 assert(r.state.isContent());
526 if (r.done) return 0;
527
528 var out_index: usize = 0;535 var out_index: usize = 0;
529 while (true) {536 while (true) {
530 switch (r.state) {537 switch (r.state) {
538 .complete => return out_index,
531 .invalid, .start, .seen_n, .seen_r, .seen_rn, .seen_rnr => unreachable,539 .invalid, .start, .seen_n, .seen_r, .seen_rn, .seen_rnr => unreachable,
532 .finished => {540 .headers_end => {
533 const data_avail = r.next_chunk_length;541 const data_avail = r.next_chunk_length;
534542
535 if (skip) {543 if (skip) {
...@@ -539,7 +547,8 @@ pub const HeadersParser = struct {...@@ -539,7 +547,8 @@ pub const HeadersParser = struct {
539 conn.drop(@intCast(nread));547 conn.drop(@intCast(nread));
540 r.next_chunk_length -= nread;548 r.next_chunk_length -= nread;
541549
542 if (r.next_chunk_length == 0 or nread == 0) r.done = true;550 if (r.next_chunk_length == 0 or nread == 0)
551 r.state = .complete;
543552
544 return out_index;553 return out_index;
545 } else if (out_index < buffer.len) {554 } else if (out_index < buffer.len) {
...@@ -549,7 +558,8 @@ pub const HeadersParser = struct {...@@ -549,7 +558,8 @@ pub const HeadersParser = struct {
549 const nread = try conn.read(buffer[0..can_read]);558 const nread = try conn.read(buffer[0..can_read]);
550 r.next_chunk_length -= nread;559 r.next_chunk_length -= nread;
551560
552 if (r.next_chunk_length == 0 or nread == 0) r.done = true;561 if (r.next_chunk_length == 0 or nread == 0)
562 r.state = .complete;
553563
554 return nread;564 return nread;
555 } else {565 } else {
...@@ -566,14 +576,12 @@ pub const HeadersParser = struct {...@@ -566,14 +576,12 @@ pub const HeadersParser = struct {
566 .invalid => return error.HttpChunkInvalid,576 .invalid => return error.HttpChunkInvalid,
567 .chunk_data => if (r.next_chunk_length == 0) {577 .chunk_data => if (r.next_chunk_length == 0) {
568 if (std.mem.eql(u8, conn.peek(), "\r\n")) {578 if (std.mem.eql(u8, conn.peek(), "\r\n")) {
569 r.state = .finished;579 r.state = .complete;
570 r.done = true;
571 } else {580 } else {
572 // The trailer section is formatted identically to the header section.581 // The trailer section is formatted identically
582 // to the header section.
573 r.state = .seen_rn;583 r.state = .seen_rn;
574 }584 }
575 r.done = true;
576
577 return out_index;585 return out_index;
578 },586 },
579 else => return out_index,587 else => return out_index,
...@@ -611,21 +619,21 @@ pub const HeadersParser = struct {...@@ -611,21 +619,21 @@ pub const HeadersParser = struct {
611};619};
612620
613inline fn int16(array: *const [2]u8) u16 {621inline fn int16(array: *const [2]u8) u16 {
614 return @as(u16, @bitCast(array.*));622 return @bitCast(array.*);
615}623}
616624
617inline fn int24(array: *const [3]u8) u24 {625inline fn int24(array: *const [3]u8) u24 {
618 return @as(u24, @bitCast(array.*));626 return @bitCast(array.*);
619}627}
620628
621inline fn int32(array: *const [4]u8) u32 {629inline fn int32(array: *const [4]u8) u32 {
622 return @as(u32, @bitCast(array.*));630 return @bitCast(array.*);
623}631}
624632
625inline fn intShift(comptime T: type, x: anytype) T {633inline fn intShift(comptime T: type, x: anytype) T {
626 switch (@import("builtin").cpu.arch.endian()) {634 switch (@import("builtin").cpu.arch.endian()) {
627 .little => return @as(T, @truncate(x >> (@bitSizeOf(@TypeOf(x)) - @bitSizeOf(T)))),635 .little => return @truncate(x >> (@bitSizeOf(@TypeOf(x)) - @bitSizeOf(T))),
628 .big => return @as(T, @truncate(x)),636 .big => return @truncate(x),
629 }637 }
630}638}
631639
test/standalone/http.zig+76-19
...@@ -165,10 +165,11 @@ fn handleRequest(res: *Server.Response) !void {...@@ -165,10 +165,11 @@ fn handleRequest(res: *Server.Response) !void {
165var handle_new_requests = true;165var handle_new_requests = true;
166166
167fn runServer(srv: *Server) !void {167fn runServer(srv: *Server) !void {
168 var client_header_buffer: [1024]u8 = undefined;
168 outer: while (handle_new_requests) {169 outer: while (handle_new_requests) {
169 var res = try srv.accept(.{170 var res = try srv.accept(.{
170 .allocator = salloc,171 .allocator = salloc,
171 .header_strategy = .{ .dynamic = max_header_size },172 .client_header_buffer = &client_header_buffer,
172 });173 });
173 defer res.deinit();174 defer res.deinit();
174175
...@@ -244,7 +245,10 @@ pub fn main() !void {...@@ -244,7 +245,10 @@ pub fn main() !void {
244 const uri = try std.Uri.parse(location);245 const uri = try std.Uri.parse(location);
245246
246 log.info("{s}", .{location});247 log.info("{s}", .{location});
247 var req = try client.open(.GET, uri, h, .{});248 var server_header_buffer: [1024]u8 = undefined;
249 var req = try client.open(.GET, uri, h, .{
250 .server_header_buffer = &server_header_buffer,
251 });
248 defer req.deinit();252 defer req.deinit();
249253
250 try req.send(.{});254 try req.send(.{});
...@@ -269,7 +273,10 @@ pub fn main() !void {...@@ -269,7 +273,10 @@ pub fn main() !void {
269 const uri = try std.Uri.parse(location);273 const uri = try std.Uri.parse(location);
270274
271 log.info("{s}", .{location});275 log.info("{s}", .{location});
272 var req = try client.open(.GET, uri, h, .{});276 var server_header_buffer: [1024]u8 = undefined;
277 var req = try client.open(.GET, uri, h, .{
278 .server_header_buffer = &server_header_buffer,
279 });
273 defer req.deinit();280 defer req.deinit();
274281
275 try req.send(.{});282 try req.send(.{});
...@@ -293,7 +300,10 @@ pub fn main() !void {...@@ -293,7 +300,10 @@ pub fn main() !void {
293 const uri = try std.Uri.parse(location);300 const uri = try std.Uri.parse(location);
294301
295 log.info("{s}", .{location});302 log.info("{s}", .{location});
296 var req = try client.open(.HEAD, uri, h, .{});303 var server_header_buffer: [1024]u8 = undefined;
304 var req = try client.open(.HEAD, uri, h, .{
305 .server_header_buffer = &server_header_buffer,
306 });
297 defer req.deinit();307 defer req.deinit();
298308
299 try req.send(.{});309 try req.send(.{});
...@@ -319,7 +329,10 @@ pub fn main() !void {...@@ -319,7 +329,10 @@ pub fn main() !void {
319 const uri = try std.Uri.parse(location);329 const uri = try std.Uri.parse(location);
320330
321 log.info("{s}", .{location});331 log.info("{s}", .{location});
322 var req = try client.open(.GET, uri, h, .{});332 var server_header_buffer: [1024]u8 = undefined;
333 var req = try client.open(.GET, uri, h, .{
334 .server_header_buffer = &server_header_buffer,
335 });
323 defer req.deinit();336 defer req.deinit();
324337
325 try req.send(.{});338 try req.send(.{});
...@@ -344,7 +357,10 @@ pub fn main() !void {...@@ -344,7 +357,10 @@ pub fn main() !void {
344 const uri = try std.Uri.parse(location);357 const uri = try std.Uri.parse(location);
345358
346 log.info("{s}", .{location});359 log.info("{s}", .{location});
347 var req = try client.open(.HEAD, uri, h, .{});360 var server_header_buffer: [1024]u8 = undefined;
361 var req = try client.open(.HEAD, uri, h, .{
362 .server_header_buffer = &server_header_buffer,
363 });
348 defer req.deinit();364 defer req.deinit();
349365
350 try req.send(.{});366 try req.send(.{});
...@@ -370,7 +386,10 @@ pub fn main() !void {...@@ -370,7 +386,10 @@ pub fn main() !void {
370 const uri = try std.Uri.parse(location);386 const uri = try std.Uri.parse(location);
371387
372 log.info("{s}", .{location});388 log.info("{s}", .{location});
373 var req = try client.open(.GET, uri, h, .{});389 var server_header_buffer: [1024]u8 = undefined;
390 var req = try client.open(.GET, uri, h, .{
391 .server_header_buffer = &server_header_buffer,
392 });
374 defer req.deinit();393 defer req.deinit();
375394
376 try req.send(.{});395 try req.send(.{});
...@@ -397,7 +416,10 @@ pub fn main() !void {...@@ -397,7 +416,10 @@ pub fn main() !void {
397 const uri = try std.Uri.parse(location);416 const uri = try std.Uri.parse(location);
398417
399 log.info("{s}", .{location});418 log.info("{s}", .{location});
400 var req = try client.open(.POST, uri, h, .{});419 var server_header_buffer: [1024]u8 = undefined;
420 var req = try client.open(.POST, uri, h, .{
421 .server_header_buffer = &server_header_buffer,
422 });
401 defer req.deinit();423 defer req.deinit();
402424
403 req.transfer_encoding = .{ .content_length = 14 };425 req.transfer_encoding = .{ .content_length = 14 };
...@@ -429,7 +451,10 @@ pub fn main() !void {...@@ -429,7 +451,10 @@ pub fn main() !void {
429 const uri = try std.Uri.parse(location);451 const uri = try std.Uri.parse(location);
430452
431 log.info("{s}", .{location});453 log.info("{s}", .{location});
432 var req = try client.open(.GET, uri, h, .{});454 var server_header_buffer: [1024]u8 = undefined;
455 var req = try client.open(.GET, uri, h, .{
456 .server_header_buffer = &server_header_buffer,
457 });
433 defer req.deinit();458 defer req.deinit();
434459
435 try req.send(.{});460 try req.send(.{});
...@@ -456,7 +481,10 @@ pub fn main() !void {...@@ -456,7 +481,10 @@ pub fn main() !void {
456 const uri = try std.Uri.parse(location);481 const uri = try std.Uri.parse(location);
457482
458 log.info("{s}", .{location});483 log.info("{s}", .{location});
459 var req = try client.open(.POST, uri, h, .{});484 var server_header_buffer: [1024]u8 = undefined;
485 var req = try client.open(.POST, uri, h, .{
486 .server_header_buffer = &server_header_buffer,
487 });
460 defer req.deinit();488 defer req.deinit();
461489
462 req.transfer_encoding = .chunked;490 req.transfer_encoding = .chunked;
...@@ -486,7 +514,10 @@ pub fn main() !void {...@@ -486,7 +514,10 @@ pub fn main() !void {
486 const uri = try std.Uri.parse(location);514 const uri = try std.Uri.parse(location);
487515
488 log.info("{s}", .{location});516 log.info("{s}", .{location});
489 var req = try client.open(.GET, uri, h, .{});517 var server_header_buffer: [1024]u8 = undefined;
518 var req = try client.open(.GET, uri, h, .{
519 .server_header_buffer = &server_header_buffer,
520 });
490 defer req.deinit();521 defer req.deinit();
491522
492 try req.send(.{});523 try req.send(.{});
...@@ -510,7 +541,10 @@ pub fn main() !void {...@@ -510,7 +541,10 @@ pub fn main() !void {
510 const uri = try std.Uri.parse(location);541 const uri = try std.Uri.parse(location);
511542
512 log.info("{s}", .{location});543 log.info("{s}", .{location});
513 var req = try client.open(.GET, uri, h, .{});544 var server_header_buffer: [1024]u8 = undefined;
545 var req = try client.open(.GET, uri, h, .{
546 .server_header_buffer = &server_header_buffer,
547 });
514 defer req.deinit();548 defer req.deinit();
515549
516 try req.send(.{});550 try req.send(.{});
...@@ -534,7 +568,10 @@ pub fn main() !void {...@@ -534,7 +568,10 @@ pub fn main() !void {
534 const uri = try std.Uri.parse(location);568 const uri = try std.Uri.parse(location);
535569
536 log.info("{s}", .{location});570 log.info("{s}", .{location});
537 var req = try client.open(.GET, uri, h, .{});571 var server_header_buffer: [1024]u8 = undefined;
572 var req = try client.open(.GET, uri, h, .{
573 .server_header_buffer = &server_header_buffer,
574 });
538 defer req.deinit();575 defer req.deinit();
539576
540 try req.send(.{});577 try req.send(.{});
...@@ -558,7 +595,10 @@ pub fn main() !void {...@@ -558,7 +595,10 @@ pub fn main() !void {
558 const uri = try std.Uri.parse(location);595 const uri = try std.Uri.parse(location);
559596
560 log.info("{s}", .{location});597 log.info("{s}", .{location});
561 var req = try client.open(.GET, uri, h, .{});598 var server_header_buffer: [1024]u8 = undefined;
599 var req = try client.open(.GET, uri, h, .{
600 .server_header_buffer = &server_header_buffer,
601 });
562 defer req.deinit();602 defer req.deinit();
563603
564 try req.send(.{});604 try req.send(.{});
...@@ -580,7 +620,10 @@ pub fn main() !void {...@@ -580,7 +620,10 @@ pub fn main() !void {
580 const uri = try std.Uri.parse(location);620 const uri = try std.Uri.parse(location);
581621
582 log.info("{s}", .{location});622 log.info("{s}", .{location});
583 var req = try client.open(.GET, uri, h, .{});623 var server_header_buffer: [1024]u8 = undefined;
624 var req = try client.open(.GET, uri, h, .{
625 .server_header_buffer = &server_header_buffer,
626 });
584 defer req.deinit();627 defer req.deinit();
585628
586 try req.send(.{});629 try req.send(.{});
...@@ -628,7 +671,10 @@ pub fn main() !void {...@@ -628,7 +671,10 @@ pub fn main() !void {
628 const uri = try std.Uri.parse(location);671 const uri = try std.Uri.parse(location);
629672
630 log.info("{s}", .{location});673 log.info("{s}", .{location});
631 var req = try client.open(.POST, uri, h, .{});674 var server_header_buffer: [1024]u8 = undefined;
675 var req = try client.open(.POST, uri, h, .{
676 .server_header_buffer = &server_header_buffer,
677 });
632 defer req.deinit();678 defer req.deinit();
633679
634 req.transfer_encoding = .chunked;680 req.transfer_encoding = .chunked;
...@@ -659,7 +705,10 @@ pub fn main() !void {...@@ -659,7 +705,10 @@ pub fn main() !void {
659 const uri = try std.Uri.parse(location);705 const uri = try std.Uri.parse(location);
660706
661 log.info("{s}", .{location});707 log.info("{s}", .{location});
662 var req = try client.open(.POST, uri, h, .{});708 var server_header_buffer: [1024]u8 = undefined;
709 var req = try client.open(.POST, uri, h, .{
710 .server_header_buffer = &server_header_buffer,
711 });
663 defer req.deinit();712 defer req.deinit();
664713
665 req.transfer_encoding = .chunked;714 req.transfer_encoding = .chunked;
...@@ -678,9 +727,17 @@ pub fn main() !void {...@@ -678,9 +727,17 @@ pub fn main() !void {
678 var requests = try calloc.alloc(http.Client.Request, total_connections);727 var requests = try calloc.alloc(http.Client.Request, total_connections);
679 defer calloc.free(requests);728 defer calloc.free(requests);
680729
730 var header_bufs = std.ArrayList([]u8).init(calloc);
731 defer header_bufs.deinit();
732 defer for (header_bufs.items) |item| calloc.free(item);
733
681 for (0..total_connections) |i| {734 for (0..total_connections) |i| {
682 var req = try client.open(.GET, uri, .{ .allocator = calloc }, .{});735 const headers_buf = try calloc.alloc(u8, 1024);
683 req.response.parser.done = true;736 try header_bufs.append(headers_buf);
737 var req = try client.open(.GET, uri, .{ .allocator = calloc }, .{
738 .server_header_buffer = headers_buf,
739 });
740 req.response.parser.state = .complete;
684 req.connection.?.closing = false;741 req.connection.?.closing = false;
685 requests[i] = req;742 requests[i] = req;
686 }743 }