authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-26 01:00:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-26 13:42:01-08:00
log1b79a42da096fcdeac22b56f17f82b0c7ec22a9b
tree7df640a5a17a41efd0dd743690c8a3a9469e448c
parent81aa74e7e1acc07872fafcd399f047a4652e3ec6

std.http.Server: fix use case of streaming both reading and writing


2 files changed, 70 insertions(+), 3 deletions(-)

lib/std/http/Server.zig+7-3
...@@ -716,10 +716,14 @@ pub const Request = struct {...@@ -716,10 +716,14 @@ pub const Request = struct {
716 },716 },
717 .receiving_body, .ready => return true,717 .receiving_body, .ready => return true,
718 else => unreachable,718 else => unreachable,
719 } else {719 };
720 s.state = .closing;720
721 return false;721 // Avoid clobbering the state in case a reading stream already exists.
722 switch (s.state) {
723 .received_head => s.state = .closing,
724 else => {},
722 }725 }
726 return false;
723 }727 }
724};728};
725729
lib/std/http/test.zig+63
...@@ -884,6 +884,69 @@ test "general client/server API coverage" {...@@ -884,6 +884,69 @@ test "general client/server API coverage" {
884 }884 }
885}885}
886886
887test "Server streams both reading and writing" {
888 const test_server = try createTestServer(struct {
889 fn run(net_server: *std.net.Server) anyerror!void {
890 var header_buffer: [1024]u8 = undefined;
891 const conn = try net_server.accept();
892 defer conn.stream.close();
893
894 var server = http.Server.init(conn, &header_buffer);
895 var request = try server.receiveHead();
896 const reader = try request.reader();
897
898 var send_buffer: [777]u8 = undefined;
899 var response = request.respondStreaming(.{
900 .send_buffer = &send_buffer,
901 .respond_options = .{
902 .transfer_encoding = .none, // Causes keep_alive=false
903 },
904 });
905 const writer = response.writer();
906
907 while (true) {
908 try response.flush();
909 var buf: [100]u8 = undefined;
910 const n = try reader.read(&buf);
911 if (n == 0) break;
912 const sub_buf = buf[0..n];
913 for (sub_buf) |*b| b.* = std.ascii.toUpper(b.*);
914 try writer.writeAll(sub_buf);
915 }
916 try response.end();
917 }
918 });
919 defer test_server.destroy();
920
921 var client: http.Client = .{ .allocator = std.testing.allocator };
922 defer client.deinit();
923
924 var server_header_buffer: [555]u8 = undefined;
925 var req = try client.open(.POST, .{
926 .scheme = "http",
927 .host = "127.0.0.1",
928 .port = test_server.port(),
929 .path = "/",
930 }, .{
931 .server_header_buffer = &server_header_buffer,
932 });
933 defer req.deinit();
934
935 req.transfer_encoding = .chunked;
936 try req.send(.{});
937 try req.wait();
938
939 try req.writeAll("one ");
940 try req.writeAll("fish");
941
942 try req.finish();
943
944 const body = try req.reader().readAllAlloc(std.testing.allocator, 8192);
945 defer std.testing.allocator.free(body);
946
947 try expectEqualStrings("ONE FISH", body);
948}
949
887fn echoTests(client: *http.Client, port: u16) !void {950fn echoTests(client: *http.Client, port: u16) !void {
888 const gpa = std.testing.allocator;951 const gpa = std.testing.allocator;
889 var location_buffer: [100]u8 = undefined;952 var location_buffer: [100]u8 = undefined;