authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-05-02 19:46:05-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:28-07:00
log9ed20386bbabad2b458fe2f93a0a5a1ed06527cf
treeb961df5f268b119763077fd1024cd87cfdbeea98
parentb0d825948a77d0ec3de794680e168ffd0a29e1fe

std.http.Reader: simplify states


4 files changed, 20 insertions(+), 26 deletions(-)

lib/compiler/std-docs.zig+1-1
......@@ -98,7 +98,7 @@ fn accept(context: *Context, connection: std.net.Server.Connection) void {
9898 var connection_bw = stream_writer.interface().buffered(&send_buffer);
9999 var server = std.http.Server.init(&connection_br, &connection_bw);
100100
101 while (server.state == .ready) {
101 while (server.reader.state == .ready) {
102102 var request = server.receiveHead() catch |err| switch (err) {
103103 error.HttpConnectionClosing => return,
104104 else => {
lib/std/http.zig+16-19
......@@ -334,11 +334,6 @@ pub const Reader = struct {
334334 /// Number of bytes of HTTP trailers. These are at the end of a
335335 /// transfer-encoding: chunked message.
336336 trailers_len: usize = 0,
337 body_state: union {
338 none: void,
339 remaining_content_length: u64,
340 remaining_chunk_len: RemainingChunkLen,
341 },
342337 body_err: ?BodyError = null,
343338 /// Stolen from `in`.
344339 head_buffer: []u8 = &.{},
......@@ -361,12 +356,13 @@ pub const Reader = struct {
361356 }
362357 };
363358
364 pub const State = enum {
359 pub const State = union(enum) {
365360 /// The stream is available to be used for the first time, or reused.
366361 ready,
367 receiving_head,
368362 received_head,
369 receiving_body,
363 body_none: void,
364 body_remaining_content_length: u64,
365 body_remaining_chunk_len: RemainingChunkLen,
370366 /// The stream would be eligible for another HTTP request, however the
371367 /// client and server did not negotiate a persistent connection.
372368 closing,
......@@ -413,6 +409,7 @@ pub const Reader = struct {
413409 head_end += hp.feed(buf[head_end..]);
414410 if (hp.state == .finished) {
415411 reader.head_buffer = in.steal(head_end);
412 reader.state = .received_head;
416413 return;
417414 }
418415 }
......@@ -426,10 +423,9 @@ pub const Reader = struct {
426423 /// * `interfaceDecompressing`
427424 pub fn bodyReader(reader: *Reader, transfer_encoding: TransferEncoding, content_length: ?u64) std.io.Reader {
428425 assert(reader.state == .received_head);
429 reader.state = .receiving_body;
430426 return switch (transfer_encoding) {
431427 .chunked => {
432 reader.body_state = .{ .remaining_chunk_len = .head };
428 reader.state = .{ .body_remaining_chunk_len = .head };
433429 return .{
434430 .context = reader,
435431 .vtable = &.{
......@@ -441,7 +437,7 @@ pub const Reader = struct {
441437 },
442438 .none => {
443439 if (content_length) |len| {
444 reader.body_state = .{ .remaining_content_length = len };
440 reader.state = .{ .body_remaining_content_length = len };
445441 return .{
446442 .context = reader,
447443 .vtable = &.{
......@@ -451,6 +447,7 @@ pub const Reader = struct {
451447 },
452448 };
453449 } else {
450 reader.state = .body_none;
454451 return reader.in.reader();
455452 }
456453 },
......@@ -473,7 +470,7 @@ pub const Reader = struct {
473470 ) std.io.Reader {
474471 if (transfer_encoding == .none and content_length == null) {
475472 assert(reader.state == .received_head);
476 reader.state = .receiving_body;
473 reader.state = .body_none;
477474 switch (content_encoding) {
478475 .identity => {
479476 return reader.in.reader();
......@@ -503,7 +500,7 @@ pub const Reader = struct {
503500 limit: std.io.Reader.Limit,
504501 ) std.io.Reader.RwError!usize {
505502 const reader: *Reader = @alignCast(@ptrCast(ctx));
506 const remaining_content_length = &reader.body_state.remaining_content_length;
503 const remaining_content_length = &reader.state.body_remaining_content_length;
507504 const remaining = remaining_content_length.*;
508505 if (remaining == 0) {
509506 reader.state = .ready;
......@@ -516,7 +513,7 @@ pub const Reader = struct {
516513
517514 fn contentLengthReadVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize {
518515 const reader: *Reader = @alignCast(@ptrCast(context));
519 const remaining_content_length = &reader.body_state.remaining_content_length;
516 const remaining_content_length = &reader.state.body_remaining_content_length;
520517 const remaining = remaining_content_length.*;
521518 if (remaining == 0) {
522519 reader.state = .ready;
......@@ -529,7 +526,7 @@ pub const Reader = struct {
529526
530527 fn contentLengthDiscard(ctx: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize {
531528 const reader: *Reader = @alignCast(@ptrCast(ctx));
532 const remaining_content_length = &reader.body_state.remaining_content_length;
529 const remaining_content_length = &reader.state.body_remaining_content_length;
533530 const remaining = remaining_content_length.*;
534531 if (remaining == 0) {
535532 reader.state = .ready;
......@@ -546,7 +543,7 @@ pub const Reader = struct {
546543 limit: std.io.Reader.Limit,
547544 ) std.io.Reader.RwError!usize {
548545 const reader: *Reader = @alignCast(@ptrCast(ctx));
549 const chunk_len_ptr = &reader.body_state.remaining_chunk_len;
546 const chunk_len_ptr = &reader.state.body_remaining_chunk_len;
550547 const in = reader.in;
551548 len: switch (chunk_len_ptr.*) {
552549 .head => {
......@@ -594,7 +591,7 @@ pub const Reader = struct {
594591
595592 fn chunkedReadVec(ctx: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize {
596593 const reader: *Reader = @alignCast(@ptrCast(ctx));
597 const chunk_len_ptr = &reader.body_state.remaining_chunk_len;
594 const chunk_len_ptr = &reader.state.body_remaining_chunk_len;
598595 const in = reader.in;
599596 var already_requested_more = false;
600597 var amt_read: usize = 0;
......@@ -662,7 +659,7 @@ pub const Reader = struct {
662659
663660 fn chunkedDiscard(ctx: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize {
664661 const reader: *Reader = @alignCast(@ptrCast(ctx));
665 const chunk_len_ptr = &reader.body_state.remaining_chunk_len;
662 const chunk_len_ptr = &reader.state.body_remaining_chunk_len;
666663 const in = reader.in;
667664 len: switch (chunk_len_ptr.*) {
668665 .head => {
......@@ -719,7 +716,7 @@ pub const Reader = struct {
719716 try in.fill(trailers_len + 1);
720717 trailers_len += hp.feed(in.bufferContents()[trailers_len..]);
721718 if (hp.state == .finished) {
722 reader.body_state.remaining_chunk_len = .done;
719 reader.state.body_remaining_chunk_len = .done;
723720 reader.state = .ready;
724721 reader.trailers_len = trailers_len;
725722 return amt_read;
lib/std/http/Client.zig+1-2
......@@ -259,7 +259,7 @@ pub const Connection = struct {
259259 const host_buffer = base[@sizeOf(Plain)..][0..remote_host.len];
260260 const socket_read_buffer = host_buffer.ptr[host_buffer.len..][0..client.read_buffer_size];
261261 const socket_write_buffer = socket_read_buffer.ptr[socket_read_buffer.len..][0..client.write_buffer_size];
262 assert(base.ptr + alloc_len == socket_read_buffer.ptr + socket_read_buffer.len);
262 assert(base.ptr + alloc_len == socket_write_buffer.ptr + socket_write_buffer.len);
263263 @memcpy(host_buffer, remote_host);
264264 const plain: *Plain = @ptrCast(base);
265265 plain.* = .{
......@@ -1545,7 +1545,6 @@ pub fn request(
15451545 .reader = .{
15461546 .in = &connection.reader,
15471547 .state = .ready,
1548 .body_state = undefined,
15491548 },
15501549 .keep_alive = options.keep_alive,
15511550 .method = method,
lib/std/http/Server.zig+2-4
......@@ -25,7 +25,6 @@ pub fn init(in: *std.io.BufferedReader, out: *std.io.BufferedWriter) Server {
2525 .reader = .{
2626 .in = in,
2727 .state = .ready,
28 .body_state = undefined,
2928 },
3029 .out = out,
3130 };
......@@ -234,7 +233,6 @@ pub const Request = struct {
234233 .reader = .{
235234 .in = &br,
236235 .state = .ready,
237 .body_state = undefined,
238236 },
239237 .out = undefined,
240238 };
......@@ -522,7 +520,7 @@ pub const Request = struct {
522520
523521 /// Returns whether the connection should remain persistent.
524522 ///
525 /// If it would fail, it instead sets the Server state to `receiving_body`
523 /// If it would fail, it instead sets the Server state to receiving body
526524 /// and returns false.
527525 fn discardBody(request: *Request, keep_alive: bool) bool {
528526 // Prepare to receive another request on the same connection.
......@@ -541,7 +539,7 @@ pub const Request = struct {
541539 assert(r.state == .ready);
542540 return true;
543541 },
544 .receiving_body, .ready => return true,
542 .body_remaining_content_length, .body_remaining_chunk_len, .body_none, .ready => return true,
545543 else => unreachable,
546544 };
547545