authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-18 17:22:56-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-18 17:26:55-07:00
log89c9282d346498e1b3ca9dfe26bf776311cd0ded
treeb3639864b9545ef68662ad16dbaf9a37fa0af593
parentb734d03340c0b120a7f6376000714b9765c5dbcc

std.http.Client: discard response body when reusing connection

When an error response was encountered, such as 404 not found, the body wasn't discarded, leading to the string "404 not found" being incorrectly interpreted as the next request's response. closes #24732

1 files changed, 24 insertions(+), 1 deletions(-)

lib/std/http/Client.zig+24-1
......@@ -787,6 +787,13 @@ pub const Request = struct {
787787 /// Standard headers that have default, but overridable, behavior.
788788 headers: Headers,
789789
790 /// Populated in `receiveHead`; used in `deinit` to determine whether to
791 /// discard the body to reuse the connection.
792 response_content_length: ?u64 = null,
793 /// Populated in `receiveHead`; used in `deinit` to determine whether to
794 /// discard the body to reuse the connection.
795 response_transfer_encoding: http.TransferEncoding = .none,
796
790797 /// These headers are kept including when following a redirect to a
791798 /// different domain.
792799 /// Externally-owned; must outlive the Request.
......@@ -860,7 +867,15 @@ pub const Request = struct {
860867 if (r.connection) |connection| {
861868 connection.closing = connection.closing or switch (r.reader.state) {
862869 .ready => false,
863 .received_head => r.method.requestHasBody(),
870 .received_head => c: {
871 if (r.method.requestHasBody()) break :c true;
872 if (!r.method.responseHasBody()) break :c false;
873 const reader = r.reader.bodyReader(&.{}, r.response_transfer_encoding, r.response_content_length);
874 _ = reader.discardRemaining() catch |err| switch (err) {
875 error.ReadFailed => break :c true,
876 };
877 break :c r.reader.state != .ready;
878 },
864879 else => true,
865880 };
866881 r.client.connection_pool.release(connection);
......@@ -1102,6 +1117,8 @@ pub const Request = struct {
11021117
11031118 if (head.status == .@"continue") {
11041119 if (r.handle_continue) continue;
1120 r.response_transfer_encoding = head.transfer_encoding;
1121 r.response_content_length = head.content_length;
11051122 return response; // we're not handling the 100-continue
11061123 }
11071124
......@@ -1113,6 +1130,8 @@ pub const Request = struct {
11131130 if (r.method == .CONNECT and head.status.class() == .success) {
11141131 // This connection is no longer doing HTTP.
11151132 connection.closing = false;
1133 r.response_transfer_encoding = head.transfer_encoding;
1134 r.response_content_length = head.content_length;
11161135 return response;
11171136 }
11181137
......@@ -1126,6 +1145,8 @@ pub const Request = struct {
11261145 if (r.method == .HEAD or head.status.class() == .informational or
11271146 head.status == .no_content or head.status == .not_modified)
11281147 {
1148 r.response_transfer_encoding = head.transfer_encoding;
1149 r.response_content_length = head.content_length;
11291150 return response;
11301151 }
11311152
......@@ -1146,6 +1167,8 @@ pub const Request = struct {
11461167 if (!r.accept_encoding[@intFromEnum(head.content_encoding)])
11471168 return error.HttpContentEncodingUnsupported;
11481169
1170 r.response_transfer_encoding = head.transfer_encoding;
1171 r.response_content_length = head.content_length;
11491172 return response;
11501173 }
11511174 }