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 {...@@ -98,7 +98,7 @@ fn accept(context: *Context, connection: std.net.Server.Connection) void {
98 var connection_bw = stream_writer.interface().buffered(&send_buffer);98 var connection_bw = stream_writer.interface().buffered(&send_buffer);
99 var server = std.http.Server.init(&connection_br, &connection_bw);99 var server = std.http.Server.init(&connection_br, &connection_bw);
100100
101 while (server.state == .ready) {101 while (server.reader.state == .ready) {
102 var request = server.receiveHead() catch |err| switch (err) {102 var request = server.receiveHead() catch |err| switch (err) {
103 error.HttpConnectionClosing => return,103 error.HttpConnectionClosing => return,
104 else => {104 else => {
lib/std/http.zig+16-19
...@@ -334,11 +334,6 @@ pub const Reader = struct {...@@ -334,11 +334,6 @@ pub const Reader = struct {
334 /// Number of bytes of HTTP trailers. These are at the end of a334 /// Number of bytes of HTTP trailers. These are at the end of a
335 /// transfer-encoding: chunked message.335 /// transfer-encoding: chunked message.
336 trailers_len: usize = 0,336 trailers_len: usize = 0,
337 body_state: union {
338 none: void,
339 remaining_content_length: u64,
340 remaining_chunk_len: RemainingChunkLen,
341 },
342 body_err: ?BodyError = null,337 body_err: ?BodyError = null,
343 /// Stolen from `in`.338 /// Stolen from `in`.
344 head_buffer: []u8 = &.{},339 head_buffer: []u8 = &.{},
...@@ -361,12 +356,13 @@ pub const Reader = struct {...@@ -361,12 +356,13 @@ pub const Reader = struct {
361 }356 }
362 };357 };
363358
364 pub const State = enum {359 pub const State = union(enum) {
365 /// The stream is available to be used for the first time, or reused.360 /// The stream is available to be used for the first time, or reused.
366 ready,361 ready,
367 receiving_head,
368 received_head,362 received_head,
369 receiving_body,363 body_none: void,
364 body_remaining_content_length: u64,
365 body_remaining_chunk_len: RemainingChunkLen,
370 /// The stream would be eligible for another HTTP request, however the366 /// The stream would be eligible for another HTTP request, however the
371 /// client and server did not negotiate a persistent connection.367 /// client and server did not negotiate a persistent connection.
372 closing,368 closing,
...@@ -413,6 +409,7 @@ pub const Reader = struct {...@@ -413,6 +409,7 @@ pub const Reader = struct {
413 head_end += hp.feed(buf[head_end..]);409 head_end += hp.feed(buf[head_end..]);
414 if (hp.state == .finished) {410 if (hp.state == .finished) {
415 reader.head_buffer = in.steal(head_end);411 reader.head_buffer = in.steal(head_end);
412 reader.state = .received_head;
416 return;413 return;
417 }414 }
418 }415 }
...@@ -426,10 +423,9 @@ pub const Reader = struct {...@@ -426,10 +423,9 @@ pub const Reader = struct {
426 /// * `interfaceDecompressing`423 /// * `interfaceDecompressing`
427 pub fn bodyReader(reader: *Reader, transfer_encoding: TransferEncoding, content_length: ?u64) std.io.Reader {424 pub fn bodyReader(reader: *Reader, transfer_encoding: TransferEncoding, content_length: ?u64) std.io.Reader {
428 assert(reader.state == .received_head);425 assert(reader.state == .received_head);
429 reader.state = .receiving_body;
430 return switch (transfer_encoding) {426 return switch (transfer_encoding) {
431 .chunked => {427 .chunked => {
432 reader.body_state = .{ .remaining_chunk_len = .head };428 reader.state = .{ .body_remaining_chunk_len = .head };
433 return .{429 return .{
434 .context = reader,430 .context = reader,
435 .vtable = &.{431 .vtable = &.{
...@@ -441,7 +437,7 @@ pub const Reader = struct {...@@ -441,7 +437,7 @@ pub const Reader = struct {
441 },437 },
442 .none => {438 .none => {
443 if (content_length) |len| {439 if (content_length) |len| {
444 reader.body_state = .{ .remaining_content_length = len };440 reader.state = .{ .body_remaining_content_length = len };
445 return .{441 return .{
446 .context = reader,442 .context = reader,
447 .vtable = &.{443 .vtable = &.{
...@@ -451,6 +447,7 @@ pub const Reader = struct {...@@ -451,6 +447,7 @@ pub const Reader = struct {
451 },447 },
452 };448 };
453 } else {449 } else {
450 reader.state = .body_none;
454 return reader.in.reader();451 return reader.in.reader();
455 }452 }
456 },453 },
...@@ -473,7 +470,7 @@ pub const Reader = struct {...@@ -473,7 +470,7 @@ pub const Reader = struct {
473 ) std.io.Reader {470 ) std.io.Reader {
474 if (transfer_encoding == .none and content_length == null) {471 if (transfer_encoding == .none and content_length == null) {
475 assert(reader.state == .received_head);472 assert(reader.state == .received_head);
476 reader.state = .receiving_body;473 reader.state = .body_none;
477 switch (content_encoding) {474 switch (content_encoding) {
478 .identity => {475 .identity => {
479 return reader.in.reader();476 return reader.in.reader();
...@@ -503,7 +500,7 @@ pub const Reader = struct {...@@ -503,7 +500,7 @@ pub const Reader = struct {
503 limit: std.io.Reader.Limit,500 limit: std.io.Reader.Limit,
504 ) std.io.Reader.RwError!usize {501 ) std.io.Reader.RwError!usize {
505 const reader: *Reader = @alignCast(@ptrCast(ctx));502 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;
507 const remaining = remaining_content_length.*;504 const remaining = remaining_content_length.*;
508 if (remaining == 0) {505 if (remaining == 0) {
509 reader.state = .ready;506 reader.state = .ready;
...@@ -516,7 +513,7 @@ pub const Reader = struct {...@@ -516,7 +513,7 @@ pub const Reader = struct {
516513
517 fn contentLengthReadVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize {514 fn contentLengthReadVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize {
518 const reader: *Reader = @alignCast(@ptrCast(context));515 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;
520 const remaining = remaining_content_length.*;517 const remaining = remaining_content_length.*;
521 if (remaining == 0) {518 if (remaining == 0) {
522 reader.state = .ready;519 reader.state = .ready;
...@@ -529,7 +526,7 @@ pub const Reader = struct {...@@ -529,7 +526,7 @@ pub const Reader = struct {
529526
530 fn contentLengthDiscard(ctx: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize {527 fn contentLengthDiscard(ctx: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize {
531 const reader: *Reader = @alignCast(@ptrCast(ctx));528 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;
533 const remaining = remaining_content_length.*;530 const remaining = remaining_content_length.*;
534 if (remaining == 0) {531 if (remaining == 0) {
535 reader.state = .ready;532 reader.state = .ready;
...@@ -546,7 +543,7 @@ pub const Reader = struct {...@@ -546,7 +543,7 @@ pub const Reader = struct {
546 limit: std.io.Reader.Limit,543 limit: std.io.Reader.Limit,
547 ) std.io.Reader.RwError!usize {544 ) std.io.Reader.RwError!usize {
548 const reader: *Reader = @alignCast(@ptrCast(ctx));545 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;
550 const in = reader.in;547 const in = reader.in;
551 len: switch (chunk_len_ptr.*) {548 len: switch (chunk_len_ptr.*) {
552 .head => {549 .head => {
...@@ -594,7 +591,7 @@ pub const Reader = struct {...@@ -594,7 +591,7 @@ pub const Reader = struct {
594591
595 fn chunkedReadVec(ctx: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize {592 fn chunkedReadVec(ctx: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize {
596 const reader: *Reader = @alignCast(@ptrCast(ctx));593 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;
598 const in = reader.in;595 const in = reader.in;
599 var already_requested_more = false;596 var already_requested_more = false;
600 var amt_read: usize = 0;597 var amt_read: usize = 0;
...@@ -662,7 +659,7 @@ pub const Reader = struct {...@@ -662,7 +659,7 @@ pub const Reader = struct {
662659
663 fn chunkedDiscard(ctx: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize {660 fn chunkedDiscard(ctx: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize {
664 const reader: *Reader = @alignCast(@ptrCast(ctx));661 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;
666 const in = reader.in;663 const in = reader.in;
667 len: switch (chunk_len_ptr.*) {664 len: switch (chunk_len_ptr.*) {
668 .head => {665 .head => {
...@@ -719,7 +716,7 @@ pub const Reader = struct {...@@ -719,7 +716,7 @@ pub const Reader = struct {
719 try in.fill(trailers_len + 1);716 try in.fill(trailers_len + 1);
720 trailers_len += hp.feed(in.bufferContents()[trailers_len..]);717 trailers_len += hp.feed(in.bufferContents()[trailers_len..]);
721 if (hp.state == .finished) {718 if (hp.state == .finished) {
722 reader.body_state.remaining_chunk_len = .done;719 reader.state.body_remaining_chunk_len = .done;
723 reader.state = .ready;720 reader.state = .ready;
724 reader.trailers_len = trailers_len;721 reader.trailers_len = trailers_len;
725 return amt_read;722 return amt_read;
lib/std/http/Client.zig+1-2
...@@ -259,7 +259,7 @@ pub const Connection = struct {...@@ -259,7 +259,7 @@ pub const Connection = struct {
259 const host_buffer = base[@sizeOf(Plain)..][0..remote_host.len];259 const host_buffer = base[@sizeOf(Plain)..][0..remote_host.len];
260 const socket_read_buffer = host_buffer.ptr[host_buffer.len..][0..client.read_buffer_size];260 const socket_read_buffer = host_buffer.ptr[host_buffer.len..][0..client.read_buffer_size];
261 const socket_write_buffer = socket_read_buffer.ptr[socket_read_buffer.len..][0..client.write_buffer_size];261 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);
263 @memcpy(host_buffer, remote_host);263 @memcpy(host_buffer, remote_host);
264 const plain: *Plain = @ptrCast(base);264 const plain: *Plain = @ptrCast(base);
265 plain.* = .{265 plain.* = .{
...@@ -1545,7 +1545,6 @@ pub fn request(...@@ -1545,7 +1545,6 @@ pub fn request(
1545 .reader = .{1545 .reader = .{
1546 .in = &connection.reader,1546 .in = &connection.reader,
1547 .state = .ready,1547 .state = .ready,
1548 .body_state = undefined,
1549 },1548 },
1550 .keep_alive = options.keep_alive,1549 .keep_alive = options.keep_alive,
1551 .method = method,1550 .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 {...@@ -25,7 +25,6 @@ pub fn init(in: *std.io.BufferedReader, out: *std.io.BufferedWriter) Server {
25 .reader = .{25 .reader = .{
26 .in = in,26 .in = in,
27 .state = .ready,27 .state = .ready,
28 .body_state = undefined,
29 },28 },
30 .out = out,29 .out = out,
31 };30 };
...@@ -234,7 +233,6 @@ pub const Request = struct {...@@ -234,7 +233,6 @@ pub const Request = struct {
234 .reader = .{233 .reader = .{
235 .in = &br,234 .in = &br,
236 .state = .ready,235 .state = .ready,
237 .body_state = undefined,
238 },236 },
239 .out = undefined,237 .out = undefined,
240 };238 };
...@@ -522,7 +520,7 @@ pub const Request = struct {...@@ -522,7 +520,7 @@ pub const Request = struct {
522520
523 /// Returns whether the connection should remain persistent.521 /// Returns whether the connection should remain persistent.
524 ///522 ///
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
526 /// and returns false.524 /// and returns false.
527 fn discardBody(request: *Request, keep_alive: bool) bool {525 fn discardBody(request: *Request, keep_alive: bool) bool {
528 // Prepare to receive another request on the same connection.526 // Prepare to receive another request on the same connection.
...@@ -541,7 +539,7 @@ pub const Request = struct {...@@ -541,7 +539,7 @@ pub const Request = struct {
541 assert(r.state == .ready);539 assert(r.state == .ready);
542 return true;540 return true;
543 },541 },
544 .receiving_body, .ready => return true,542 .body_remaining_content_length, .body_remaining_chunk_len, .body_none, .ready => return true,
545 else => unreachable,543 else => unreachable,
546 };544 };
547545