authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-04-27 21:04:15-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:28-07:00
logd8cea032455228a12e3413068aff46b06fb02a59
tree83d5ffae07991b7286ab9f7852129cd607cad94f
parentab3a947bef0b167665068ab40232609e4d9b656c

std.http: more update


4 files changed, 99 insertions(+), 90 deletions(-)

lib/std/http.zig+53-10
...@@ -331,9 +331,18 @@ pub const Reader = struct {...@@ -331,9 +331,18 @@ pub const Reader = struct {
331 body_err: ?BodyError = null,331 body_err: ?BodyError = null,
332 /// Stolen from `in`.332 /// Stolen from `in`.
333 head_buffer: []u8 = &.{},333 head_buffer: []u8 = &.{},
334 compression: Compression,
334335
335 pub const max_chunk_header_len = 22;336 pub const max_chunk_header_len = 22;
336337
338 pub const Compression = union(enum) {
339 deflate: std.compress.zlib.Decompressor,
340 gzip: std.compress.gzip.Decompressor,
341 // https://github.com/ziglang/zig/issues/18937
342 //zstd: std.compress.zstd.Decompressor,
343 none: void,
344 };
345
337 pub const RemainingChunkLen = enum(u64) {346 pub const RemainingChunkLen = enum(u64) {
338 head = 0,347 head = 0,
339 n = 1,348 n = 1,
...@@ -408,13 +417,18 @@ pub const Reader = struct {...@@ -408,13 +417,18 @@ pub const Reader = struct {
408 }417 }
409418
410 /// Asserts only called once and after `receiveHead`.419 /// Asserts only called once and after `receiveHead`.
411 pub fn interface(reader: *Reader, transfer_encoding: TransferEncoding, content_length: ?u64) std.io.Reader {420 pub fn interface(
421 reader: *Reader,
422 transfer_encoding: TransferEncoding,
423 content_length: ?u64,
424 content_encoding: ContentEncoding,
425 ) std.io.Reader {
412 assert(reader.state == .received_head);426 assert(reader.state == .received_head);
413 reader.state = .receiving_body;427 reader.state = .receiving_body;
414 switch (transfer_encoding) {428 reader.transfer_br.unbuffered_reader = switch (transfer_encoding) {
415 .chunked => {429 .chunked => r: {
416 reader.body_state = .{ .remaining_chunk_len = .head };430 reader.body_state = .{ .remaining_chunk_len = .head };
417 return .{431 break :r .{
418 .context = reader,432 .context = reader,
419 .vtable = &.{433 .vtable = &.{
420 .read = &chunkedRead,434 .read = &chunkedRead,
...@@ -423,10 +437,10 @@ pub const Reader = struct {...@@ -423,10 +437,10 @@ pub const Reader = struct {
423 },437 },
424 };438 };
425 },439 },
426 .none => {440 .none => r: {
427 if (content_length) |len| {441 if (content_length) |len| {
428 reader.body_state = .{ .remaining_content_length = len };442 reader.body_state = .{ .remaining_content_length = len };
429 return .{443 break :r .{
430 .context = reader,444 .context = reader,
431 .vtable = &.{445 .vtable = &.{
432 .read = &contentLengthRead,446 .read = &contentLengthRead,
...@@ -434,10 +448,39 @@ pub const Reader = struct {...@@ -434,10 +448,39 @@ pub const Reader = struct {
434 .discard = &contentLengthDiscard,448 .discard = &contentLengthDiscard,
435 },449 },
436 };450 };
437 } else {451 } else switch (content_encoding) {
438 return reader.in.reader();452 .identity => {
453 reader.compression = .none;
454 return reader.in.reader();
455 },
456 .deflate => {
457 reader.compression = .{ .deflate = .init(reader.in) };
458 return reader.compression.deflate.reader();
459 },
460 .gzip, .@"x-gzip" => {
461 reader.compression = .{ .gzip = .init(reader.in) };
462 return reader.compression.gzip.reader();
463 },
464 .compress, .@"x-compress" => unreachable,
465 .zstd => unreachable, // https://github.com/ziglang/zig/issues/18937
439 }466 }
440 },467 },
468 };
469 switch (content_encoding) {
470 .identity => {
471 reader.compression = .none;
472 return reader.transfer_br.unbuffered_reader;
473 },
474 .deflate => {
475 reader.compression = .{ .deflate = .init(&reader.transfer_br) };
476 return reader.compression.deflate.reader();
477 },
478 .gzip, .@"x-gzip" => {
479 reader.compression = .{ .gzip = .init(&reader.transfer_br) };
480 return reader.compression.gzip.reader();
481 },
482 .compress, .@"x-compress" => unreachable,
483 .zstd => unreachable, // https://github.com/ziglang/zig/issues/18937
441 }484 }
442 }485 }
443486
...@@ -731,7 +774,7 @@ pub const BodyWriter = struct {...@@ -731,7 +774,7 @@ pub const BodyWriter = struct {
731 /// BodyWriter is mid-chunk.774 /// BodyWriter is mid-chunk.
732 pub fn flush(w: *BodyWriter) WriteError!void {775 pub fn flush(w: *BodyWriter) WriteError!void {
733 switch (w.state) {776 switch (w.state) {
734 .none, .content_length => return w.http_protocol_output.flush(),777 .end, .none, .content_length => return w.http_protocol_output.flush(),
735 .chunked => |*chunked| switch (chunked.*) {778 .chunked => |*chunked| switch (chunked.*) {
736 .offset => |*offset| {779 .offset => |*offset| {
737 try w.http_protocol_output.flushLimit(.limited(w.http_protocol_output.end - offset.*));780 try w.http_protocol_output.flushLimit(.limited(w.http_protocol_output.end - offset.*));
...@@ -1018,7 +1061,7 @@ pub const BodyWriter = struct {...@@ -1018,7 +1061,7 @@ pub const BodyWriter = struct {
1018 }1061 }
1019 }1062 }
10201063
1021 pub fn interface(w: *BodyWriter) std.io.Writer {1064 pub fn writer(w: *BodyWriter) std.io.Writer {
1022 return .{1065 return .{
1023 .context = w,1066 .context = w,
1024 .vtable = switch (w.state) {1067 .vtable = switch (w.state) {
lib/std/http/Client.zig+30-66
...@@ -116,7 +116,7 @@ pub const ConnectionPool = struct {...@@ -116,7 +116,7 @@ pub const ConnectionPool = struct {
116 /// `allocator` must be the same one used to create `connection`.116 /// `allocator` must be the same one used to create `connection`.
117 ///117 ///
118 /// Threadsafe.118 /// Threadsafe.
119 pub fn release(pool: *ConnectionPool, allocator: Allocator, connection: *Connection) void {119 pub fn release(pool: *ConnectionPool, connection: *Connection) void {
120 if (connection.closing) return connection.destroy();120 if (connection.closing) return connection.destroy();
121121
122 pool.mutex.lock();122 pool.mutex.lock();
...@@ -130,8 +130,7 @@ pub const ConnectionPool = struct {...@@ -130,8 +130,7 @@ pub const ConnectionPool = struct {
130 const popped: *Connection = @fieldParentPtr("pool_node", pool.free.popFirst().?);130 const popped: *Connection = @fieldParentPtr("pool_node", pool.free.popFirst().?);
131 pool.free_len -= 1;131 pool.free_len -= 1;
132132
133 popped.close(allocator);133 popped.destroy();
134 allocator.destroy(popped);
135 }134 }
136135
137 if (connection.proxied) {136 if (connection.proxied) {
...@@ -434,20 +433,6 @@ pub const Connection = struct {...@@ -434,20 +433,6 @@ pub const Connection = struct {
434 }433 }
435};434};
436435
437/// The decompressor for response messages.
438pub const Compression = union(enum) {
439 pub const DeflateDecompressor = std.compress.zlib.Decompressor;
440 pub const GzipDecompressor = std.compress.gzip.Decompressor;
441 // https://github.com/ziglang/zig/issues/18937
442 //pub const ZstdDecompressor = std.compress.zstd.DecompressStream(.{});
443
444 deflate: DeflateDecompressor,
445 gzip: GzipDecompressor,
446 // https://github.com/ziglang/zig/issues/18937
447 //zstd: ZstdDecompressor,
448 none: void,
449};
450
451pub const Response = struct {436pub const Response = struct {
452 request: *Request,437 request: *Request,
453 /// Pointers in this struct are invalidated with the next call to438 /// Pointers in this struct are invalidated with the next call to
...@@ -469,9 +454,7 @@ pub const Response = struct {...@@ -469,9 +454,7 @@ pub const Response = struct {
469 content_length: ?u64 = null,454 content_length: ?u64 = null,
470455
471 transfer_encoding: http.TransferEncoding = .none,456 transfer_encoding: http.TransferEncoding = .none,
472 transfer_compression: http.ContentEncoding = .identity,457 content_encoding: http.ContentEncoding = .identity,
473
474 compression: Compression = .none,
475458
476 pub const ParseError = error{459 pub const ParseError = error{
477 HttpHeadersInvalid,460 HttpHeadersInvalid,
...@@ -554,8 +537,8 @@ pub const Response = struct {...@@ -554,8 +537,8 @@ pub const Response = struct {
554 const trimmed_second = mem.trim(u8, second, " ");537 const trimmed_second = mem.trim(u8, second, " ");
555538
556 if (std.meta.stringToEnum(http.ContentEncoding, trimmed_second)) |transfer| {539 if (std.meta.stringToEnum(http.ContentEncoding, trimmed_second)) |transfer| {
557 if (res.transfer_compression != .identity) return error.HttpHeadersInvalid; // double compression is not supported540 if (res.content_encoding != .identity) return error.HttpHeadersInvalid; // double compression is not supported
558 res.transfer_compression = transfer;541 res.content_encoding = transfer;
559 } else {542 } else {
560 return error.HttpTransferEncodingUnsupported;543 return error.HttpTransferEncodingUnsupported;
561 }544 }
...@@ -569,12 +552,12 @@ pub const Response = struct {...@@ -569,12 +552,12 @@ pub const Response = struct {
569552
570 res.content_length = content_length;553 res.content_length = content_length;
571 } else if (std.ascii.eqlIgnoreCase(header_name, "content-encoding")) {554 } else if (std.ascii.eqlIgnoreCase(header_name, "content-encoding")) {
572 if (res.transfer_compression != .identity) return error.HttpHeadersInvalid;555 if (res.content_encoding != .identity) return error.HttpHeadersInvalid;
573556
574 const trimmed = mem.trim(u8, header_value, " ");557 const trimmed = mem.trim(u8, header_value, " ");
575558
576 if (std.meta.stringToEnum(http.ContentEncoding, trimmed)) |ce| {559 if (std.meta.stringToEnum(http.ContentEncoding, trimmed)) |ce| {
577 res.transfer_compression = ce;560 res.content_encoding = ce;
578 } else {561 } else {
579 return error.HttpTransferEncodingUnsupported;562 return error.HttpTransferEncodingUnsupported;
580 }563 }
...@@ -592,7 +575,7 @@ pub const Response = struct {...@@ -592,7 +575,7 @@ pub const Response = struct {
592 "TRansfer-encoding:\tdeflate, chunked \r\n" ++575 "TRansfer-encoding:\tdeflate, chunked \r\n" ++
593 "connectioN:\t keep-alive \r\n\r\n";576 "connectioN:\t keep-alive \r\n\r\n";
594577
595 const head = Head.parse(response_bytes);578 const head = try Head.parse(response_bytes);
596579
597 try testing.expectEqual(.@"HTTP/1.1", head.version);580 try testing.expectEqual(.@"HTTP/1.1", head.version);
598 try testing.expectEqualStrings("OK", head.reason);581 try testing.expectEqualStrings("OK", head.reason);
...@@ -605,7 +588,7 @@ pub const Response = struct {...@@ -605,7 +588,7 @@ pub const Response = struct {
605 try testing.expectEqual(true, head.keep_alive);588 try testing.expectEqual(true, head.keep_alive);
606 try testing.expectEqual(10, head.content_length.?);589 try testing.expectEqual(10, head.content_length.?);
607 try testing.expectEqual(.chunked, head.transfer_encoding);590 try testing.expectEqual(.chunked, head.transfer_encoding);
608 try testing.expectEqual(.deflate, head.transfer_compression);591 try testing.expectEqual(.deflate, head.content_encoding);
609 }592 }
610593
611 pub fn iterateHeaders(h: Head) http.HeaderIterator {594 pub fn iterateHeaders(h: Head) http.HeaderIterator {
...@@ -621,19 +604,8 @@ pub const Response = struct {...@@ -621,19 +604,8 @@ pub const Response = struct {
621 "TRansfer-encoding:\tdeflate, chunked \r\n" ++604 "TRansfer-encoding:\tdeflate, chunked \r\n" ++
622 "connectioN:\t keep-alive \r\n\r\n";605 "connectioN:\t keep-alive \r\n\r\n";
623606
624 var header_buffer: [1024]u8 = undefined;607 const head = try Head.parse(response_bytes);
625 var res = Response{608 var it = head.iterateHeaders();
626 .status = undefined,
627 .reason = undefined,
628 .version = undefined,
629 .keep_alive = false,
630 .parser = .init(&header_buffer),
631 };
632
633 @memcpy(header_buffer[0..response_bytes.len], response_bytes);
634 res.parser.header_bytes_len = response_bytes.len;
635
636 var it = res.iterateHeaders();
637 {609 {
638 const header = it.next().?;610 const header = it.next().?;
639 try testing.expectEqualStrings("LOcation", header.name);611 try testing.expectEqualStrings("LOcation", header.name);
...@@ -695,7 +667,7 @@ pub const Response = struct {...@@ -695,7 +667,7 @@ pub const Response = struct {
695 /// Asserts that this function is only called once.667 /// Asserts that this function is only called once.
696 pub fn reader(response: *Response) std.io.Reader {668 pub fn reader(response: *Response) std.io.Reader {
697 const head = &response.head;669 const head = &response.head;
698 return response.request.reader.interface(head.transfer_encoding, head.content_length);670 return response.request.reader.interface(head.transfer_encoding, head.content_length, head.content_encoding);
699 }671 }
700};672};
701673
...@@ -778,16 +750,16 @@ pub const Request = struct {...@@ -778,16 +750,16 @@ pub const Request = struct {
778 }750 }
779 };751 };
780752
781 /// Frees all resources associated with the request.753 /// Returns the request's `Connection` back to the pool of the `Client`.
782 pub fn deinit(req: *Request) void {754 pub fn deinit(r: *Request) void {
783 if (req.connection) |connection| {755 if (r.connection) |connection| {
784 if (!req.response.parser.done) {756 if (r.reader.state != .ready) {
785 // If the response wasn't fully read, then we need to close the connection.757 // Connection cannot be reused.
786 connection.closing = true;758 connection.closing = true;
787 }759 }
788 req.client.connection_pool.release(req.client.allocator, connection);760 r.client.connection_pool.release(connection);
789 }761 }
790 req.* = undefined;762 r.* = undefined;
791 }763 }
792764
793 /// Sends and flushes a complete request as only HTTP head, no body.765 /// Sends and flushes a complete request as only HTTP head, no body.
...@@ -810,12 +782,12 @@ pub const Request = struct {...@@ -810,12 +782,12 @@ pub const Request = struct {
810 try sendHead(r);782 try sendHead(r);
811 return .{783 return .{
812 .http_protocol_output = &r.connection.?.writer,784 .http_protocol_output = &r.connection.?.writer,
813 .transfer_encoding = if (r.transfer_encoding) |te| switch (te) {785 .state = switch (r.transfer_encoding) {
814 .chunked => .{ .chunked = .init },786 .chunked => .{ .chunked = .init },
815 .content_length => |len| .{ .content_length = len },787 .content_length => |len| .{ .content_length = len },
816 .none => .none,788 .none => .none,
817 } else .{ .chunked = .init },789 },
818 .elide_body = false,790 .elide = false,
819 };791 };
820 }792 }
821793
...@@ -912,7 +884,7 @@ pub const Request = struct {...@@ -912,7 +884,7 @@ pub const Request = struct {
912 try w.writeAll("\r\n");884 try w.writeAll("\r\n");
913 }885 }
914886
915 pub const ReceiveHeadError = http.Reader.HeadError || error{887 pub const ReceiveHeadError = std.io.Writer.Error || http.Reader.HeadError || error{
916 /// Server sent headers that did not conform to the HTTP protocol.888 /// Server sent headers that did not conform to the HTTP protocol.
917 ///889 ///
918 /// To find out more detailed diagnostics, `http.Reader.head_buffer` can be890 /// To find out more detailed diagnostics, `http.Reader.head_buffer` can be
...@@ -956,7 +928,7 @@ pub const Request = struct {...@@ -956,7 +928,7 @@ pub const Request = struct {
956928
957 if (head.status == .@"continue") {929 if (head.status == .@"continue") {
958 if (r.handle_continue) continue;930 if (r.handle_continue) continue;
959 return; // we're not handling the 100-continue931 return response; // we're not handling the 100-continue
960 }932 }
961933
962 // This while loop is for handling redirects, which means the request's934 // This while loop is for handling redirects, which means the request's
...@@ -987,25 +959,17 @@ pub const Request = struct {...@@ -987,25 +959,17 @@ pub const Request = struct {
987 if (r.redirect_behavior == .not_allowed) return error.TooManyHttpRedirects;959 if (r.redirect_behavior == .not_allowed) return error.TooManyHttpRedirects;
988 const location = head.location orelse return error.HttpRedirectLocationMissing;960 const location = head.location orelse return error.HttpRedirectLocationMissing;
989 try r.redirect(location, &aux_buf);961 try r.redirect(location, &aux_buf);
990 try r.send();962 try r.sendBodiless();
991 continue;963 continue;
992 }964 }
993965
994 switch (head.transfer_compression) {966 switch (head.content_encoding) {
995 .identity => response.compression = .none,967 .identity, .deflate, .gzip, .@"x-gzip" => {},
996 .compress, .@"x-compress" => return error.CompressionUnsupported,968 .compress, .@"x-compress" => return error.CompressionUnsupported,
997 .deflate => response.compression = .{
998 .deflate = std.compress.zlib.decompressor(r.transferReader()),
999 },
1000 .gzip, .@"x-gzip" => response.compression = .{
1001 .gzip = std.compress.gzip.decompressor(r.transferReader()),
1002 },
1003 // https://github.com/ziglang/zig/issues/18937969 // https://github.com/ziglang/zig/issues/18937
1004 //.zstd => response.compression = .{
1005 // .zstd = std.compress.zstd.decompressStream(r.client.allocator, r.transferReader()),
1006 //},
1007 .zstd => return error.CompressionUnsupported,970 .zstd => return error.CompressionUnsupported,
1008 }971 }
972
1009 return response;973 return response;
1010 }974 }
1011 }975 }
...@@ -1050,7 +1014,7 @@ pub const Request = struct {...@@ -1050,7 +1014,7 @@ pub const Request = struct {
1050 std.ascii.eqlIgnoreCase(r.uri.scheme, new_uri.scheme) and1014 std.ascii.eqlIgnoreCase(r.uri.scheme, new_uri.scheme) and
1051 sameParentDomain(old_host, new_host);1015 sameParentDomain(old_host, new_host);
10521016
1053 r.client.connection_pool.release(r.client.allocator, old_connection);1017 r.client.connection_pool.release(old_connection);
1054 r.connection = null;1018 r.connection = null;
10551019
1056 if (!keep_privileged_headers) {1020 if (!keep_privileged_headers) {
...@@ -1327,7 +1291,7 @@ pub fn connectTunnel(...@@ -1327,7 +1291,7 @@ pub fn connectTunnel(
1327 const conn = try client.connectTcp(proxy.host, proxy.port, proxy.protocol);1291 const conn = try client.connectTcp(proxy.host, proxy.port, proxy.protocol);
1328 errdefer {1292 errdefer {
1329 conn.closing = true;1293 conn.closing = true;
1330 client.connection_pool.release(client.allocator, conn);1294 client.connection_pool.release(conn);
1331 }1295 }
13321296
1333 var buffer: [8096]u8 = undefined;1297 var buffer: [8096]u8 = undefined;
lib/std/http/Server.zig+5-2
...@@ -242,9 +242,12 @@ pub const Request = struct {...@@ -242,9 +242,12 @@ pub const Request = struct {
242 br.initFixed(&read_buffer);242 br.initFixed(&read_buffer);
243243
244 var server: Server = .{244 var server: Server = .{
245 .in = &br,245 .reader = .{
246 .in = &br,
247 .state = .ready,
248 .body_state = undefined,
249 },
246 .out = undefined,250 .out = undefined,
247 .state = .ready,
248 };251 };
249252
250 var request: Request = .{253 var request: Request = .{
lib/std/http/test.zig+11-12
...@@ -24,10 +24,10 @@ test "trailers" {...@@ -24,10 +24,10 @@ test "trailers" {
24 var connection_bw = stream_writer.interface().buffered(&send_buffer);24 var connection_bw = stream_writer.interface().buffered(&send_buffer);
25 var server = http.Server.init(&connection_br, &connection_bw);25 var server = http.Server.init(&connection_br, &connection_bw);
2626
27 try expectEqual(.ready, server.state);27 try expectEqual(.ready, server.reader.state);
28 var request = try server.receiveHead();28 var request = try server.receiveHead();
29 try serve(&request);29 try serve(&request);
30 try expectEqual(.ready, server.state);30 try expectEqual(.ready, server.reader.state);
31 }31 }
32 }32 }
3333
...@@ -72,7 +72,7 @@ test "trailers" {...@@ -72,7 +72,7 @@ test "trailers" {
7272
73 try expectEqualStrings("Hello, World!\n", body);73 try expectEqualStrings("Hello, World!\n", body);
7474
75 var it = response.iterateHeaders();75 var it = response.head.iterateHeaders();
76 {76 {
77 const header = it.next().?;77 const header = it.next().?;
78 try expect(!it.is_trailer);78 try expect(!it.is_trailer);
...@@ -174,7 +174,7 @@ test "echo content server" {...@@ -174,7 +174,7 @@ test "echo content server" {
174 var connection_bw = stream_writer.interface().buffered(&send_buffer);174 var connection_bw = stream_writer.interface().buffered(&send_buffer);
175 var http_server = http.Server.init(&connection_br, &connection_bw);175 var http_server = http.Server.init(&connection_br, &connection_bw);
176176
177 while (http_server.state == .ready) {177 while (http_server.reader.state == .ready) {
178 var request = http_server.receiveHead() catch |err| switch (err) {178 var request = http_server.receiveHead() catch |err| switch (err) {
179 error.HttpConnectionClosing => continue :accept,179 error.HttpConnectionClosing => continue :accept,
180 else => |e| return e,180 else => |e| return e,
...@@ -401,7 +401,7 @@ test "general client/server API coverage" {...@@ -401,7 +401,7 @@ test "general client/server API coverage" {
401 var connection_bw = stream_writer.interface().buffered(&send_buffer);401 var connection_bw = stream_writer.interface().buffered(&send_buffer);
402 var http_server = http.Server.init(&connection_br, &connection_bw);402 var http_server = http.Server.init(&connection_br, &connection_bw);
403403
404 while (http_server.state == .ready) {404 while (http_server.reader.state == .ready) {
405 var request = http_server.receiveHead() catch |err| switch (err) {405 var request = http_server.receiveHead() catch |err| switch (err) {
406 error.HttpConnectionClosing => continue :outer,406 error.HttpConnectionClosing => continue :outer,
407 else => |e| return e,407 else => |e| return e,
...@@ -618,7 +618,7 @@ test "general client/server API coverage" {...@@ -618,7 +618,7 @@ test "general client/server API coverage" {
618 defer gpa.free(body);618 defer gpa.free(body);
619619
620 try expectEqualStrings("", body);620 try expectEqualStrings("", body);
621 try expectEqualStrings("text/plain", response.content_type.?);621 try expectEqualStrings("text/plain", response.head.content_type.?);
622 try expectEqual(14, response.head.content_length.?);622 try expectEqual(14, response.head.content_length.?);
623 }623 }
624624
...@@ -962,11 +962,10 @@ test "Server streams both reading and writing" {...@@ -962,11 +962,10 @@ test "Server streams both reading and writing" {
962 var body_writer = try req.sendBody();962 var body_writer = try req.sendBody();
963 var response = try req.receiveHead(&redirect_buffer);963 var response = try req.receiveHead(&redirect_buffer);
964964
965 var w = body_writer.interface().unbuffered();965 var w = body_writer.writer().unbuffered();
966 try w.writeAll("one ");966 try w.writeAll("one ");
967 try w.writeAll("fish");967 try w.writeAll("fish");
968968 try body_writer.end();
969 try req.finish();
970969
971 const body = try response.reader().readRemainingAlloc(std.testing.allocator, .limited(8192));970 const body = try response.reader().readRemainingAlloc(std.testing.allocator, .limited(8192));
972 defer std.testing.allocator.free(body);971 defer std.testing.allocator.free(body);
...@@ -994,7 +993,7 @@ fn echoTests(client: *http.Client, port: u16) !void {...@@ -994,7 +993,7 @@ fn echoTests(client: *http.Client, port: u16) !void {
994 req.transfer_encoding = .{ .content_length = 14 };993 req.transfer_encoding = .{ .content_length = 14 };
995994
996 var body_writer = try req.sendBody();995 var body_writer = try req.sendBody();
997 var w = body_writer.interface().unbuffered();996 var w = body_writer.writer().unbuffered();
998 try w.writeAll("Hello, ");997 try w.writeAll("Hello, ");
999 try w.writeAll("World!\n");998 try w.writeAll("World!\n");
1000 try body_writer.end();999 try body_writer.end();
...@@ -1028,7 +1027,7 @@ fn echoTests(client: *http.Client, port: u16) !void {...@@ -1028,7 +1027,7 @@ fn echoTests(client: *http.Client, port: u16) !void {
1028 req.transfer_encoding = .chunked;1027 req.transfer_encoding = .chunked;
10291028
1030 var body_writer = try req.sendBody();1029 var body_writer = try req.sendBody();
1031 var w = body_writer.interface().unbuffered();1030 var w = body_writer.writer().unbuffered();
1032 try w.writeAll("Hello, ");1031 try w.writeAll("Hello, ");
1033 try w.writeAll("World!\n");1032 try w.writeAll("World!\n");
1034 try body_writer.end();1033 try body_writer.end();
...@@ -1082,7 +1081,7 @@ fn echoTests(client: *http.Client, port: u16) !void {...@@ -1082,7 +1081,7 @@ fn echoTests(client: *http.Client, port: u16) !void {
1082 req.transfer_encoding = .chunked;1081 req.transfer_encoding = .chunked;
10831082
1084 var body_writer = try req.sendBody();1083 var body_writer = try req.sendBody();
1085 var w = body_writer.interface().unbuffered();1084 var w = body_writer.writer().unbuffered();
1086 try w.writeAll("Hello, ");1085 try w.writeAll("Hello, ");
1087 try w.writeAll("World!\n");1086 try w.writeAll("World!\n");
1088 try body_writer.end();1087 try body_writer.end();