End the stream at the header section for HEAD, 204 and 304 in open_stream (#2636)

ClientImpl::open_stream built the body reader from Content-Length and Transfer-Encoding whatever the method or status, so a stream on a response that RFC 9112 6.3 ends at its header section was read on: with a keep-alive server read() blocked until the read timeout, and when the server closed it reported a read error for a complete response. stream::Head() against cpp-httplib's own server, which puts the GET body's Content-Length on a HEAD response, hit it every time.

open_stream_() now returns with the body reader at its end for a response to HEAD and for a 204 or 304, as the buffered path skips the body for them. Content-Encoding is skipped too, so a coding the build lacks no longer fails such a stream.
This commit is contained in:
metsw24-max authored and GitHub committed 2026-10-20 17:31:45 -04:00
1 parent 41c85c0733
commit 67b88030e8
2 files changed
+51 -9

No files matched your search

+14 -9
View File
@@ -15939,20 +15939,25 @@ inline ClientImpl::StreamHandle ClientImpl::open_stream_(Request &req) {
return handle;
}
// Same framing check as ClientImpl::process_request(). A HEAD or bodyless
// (204/304) response legitimately carries framing headers with no body.
if (req.method != "HEAD" &&
handle.response->status != StatusCode::NoContent_204 &&
handle.response->status != StatusCode::NotModified_304 &&
detail::has_conflicting_content_length(handle.response->headers)) {
handle.body_reader_.stream = handle.stream_;
handle.body_reader_.payload_max_length = payload_max_length_;
// RFC 9112 6.3: a response to HEAD, and a 204 or 304 response, ends with its
// header section, so none of its framing or coding headers apply.
if (req.method == "HEAD" ||
handle.response->status == StatusCode::NoContent_204 ||
handle.response->status == StatusCode::NotModified_304) {
handle.body_reader_.eof = true;
return handle;
}
// Same framing check as ClientImpl::process_request()
if (detail::has_conflicting_content_length(handle.response->headers)) {
handle.error = Error::Read;
handle.response.reset();
return handle;
}
handle.body_reader_.stream = handle.stream_;
handle.body_reader_.payload_max_length = payload_max_length_;
if (handle.response->has_header("Content-Length")) {
bool is_invalid = false;
auto content_length = detail::get_header_value_u64(