diff --git a/lib/std/http/Client.zig b/lib/std/http/Client.zig index 14bd96a68b..8438a7bbd3 100644 --- a/lib/std/http/Client.zig +++ b/lib/std/http/Client.zig @@ -821,13 +821,15 @@ pub const Request = struct { if (req.handle_continue) continue; - break; + return; // we're not handling the 100-continue, return to the caller } // we're switching protocols, so this connection is no longer doing http - if (req.response.status == .switching_protocols or (req.method == .CONNECT and req.response.status == .ok)) { + if (req.method == .CONNECT and req.response.status.class() == .success) { req.connection.?.closing = false; req.response.parser.done = true; + + return; // the connection is not HTTP past this point, return to the caller } // we default to using keep-alive if not provided in the client if the server asks for it @@ -842,6 +844,15 @@ pub const Request = struct { req.connection.?.closing = true; } + // Any response to a HEAD request and any response with a 1xx (Informational), 204 (No Content), or 304 (Not Modified) + // status code is always terminated by the first empty line after the header fields, regardless of the header fields + // present in the message + if (req.method == .HEAD or req.response.status.class() == .informational or req.response.status == .no_content or req.response.status == .not_modified) { + req.response.parser.done = true; + + return; // the response is empty, no further setup or redirection is necessary + } + if (req.response.transfer_encoding != .none) { switch (req.response.transfer_encoding) { .none => unreachable, @@ -855,12 +866,8 @@ pub const Request = struct { if (cl == 0) req.response.parser.done = true; } else { - req.response.parser.done = true; - } - - // HEAD requests have no body - if (req.method == .HEAD) { - req.response.parser.done = true; + // read until the connection is closed + req.response.parser.next_chunk_length = std.math.maxInt(u64); } if (req.response.status.class() == .redirect and req.handle_redirects) { diff --git a/lib/std/http/protocol.zig b/lib/std/http/protocol.zig index 227b376ed3..0ccafd2ee5 100644 --- a/lib/std/http/protocol.zig +++ b/lib/std/http/protocol.zig @@ -524,7 +524,7 @@ pub const HeadersParser = struct { /// /// If `skip` is true, the buffer will be unused and the body will be skipped. /// - /// See `std.http.Client.BufferedConnection for an example of `conn`. + /// See `std.http.Client.Connection for an example of `conn`. pub fn read(r: *HeadersParser, conn: anytype, buffer: []u8, skip: bool) !usize { assert(r.state.isContent()); if (r.done) return 0; @@ -543,7 +543,7 @@ pub const HeadersParser = struct { conn.drop(@intCast(nread)); r.next_chunk_length -= nread; - if (r.next_chunk_length == 0) r.done = true; + if (r.next_chunk_length == 0 or nread == 0) r.done = true; return out_index; } else if (out_index < buffer.len) { @@ -553,7 +553,7 @@ pub const HeadersParser = struct { const nread = try conn.read(buffer[0..can_read]); r.next_chunk_length -= nread; - if (r.next_chunk_length == 0) r.done = true; + if (r.next_chunk_length == 0 or nread == 0) r.done = true; return nread; } else {