Return a 3xx without a Location instead of failing the redirect

With follow_location on, every 3xx was taken for a redirect, so a 304
Not Modified, or any 3xx without a Location, failed with Error::Unknown.
Follow a 3xx only when it has a Location, as curl does, and return the
others as the response, as curl, Go, requests and urllib3 do. Response
handlers and content receivers now get such a response too.
This commit is contained in:
yhirose committed 2026-10-18 12:41:23 -04:00
1 parent 906a7bf04e
commit 106edcf606
2 files changed
+81 -4

No files matched your search

+9 -4
View File
@@ -16128,6 +16128,12 @@ inline bool ChunkedDecoder::parse_trailers_into(Headers &dest,
return parse_trailers(lr, dest, src_headers);
}
// A 3xx without a Location, such as a 304, is a final response
inline bool is_redirect(const Response &res) {
return 300 < res.status && res.status < 400 &&
!res.get_header_value("Location").empty();
}
} // namespace detail
inline void
@@ -16185,7 +16191,7 @@ inline bool ClientImpl::handle_request(Stream &strm, Request &req,
}
}
if (300 < res.status && res.status < 400 && follow_location_) {
if (follow_location_ && detail::is_redirect(res)) {
req = std::move(req_save);
// The client that followed the redirect has answered any challenge it
// could. Retrying below would sign another host's challenge and send it
@@ -16931,9 +16937,8 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req,
}
}
auto redirect = 300 < res.status && res.status < 400 &&
res.status != StatusCode::NotModified_304 &&
follow_location_;
auto redirect = follow_location_ && detail::is_redirect(res) &&
res.status != StatusCode::NotModified_304;
if (req.response_handler && !redirect) {
if (!req.response_handler(res)) {