Read Content-Encoding as the combined field value

RFC 9110 Section 5.3 makes a Content-Encoding spread over several field lines
the same message as the comma-joined one, so the two have to be read the same
way. Reading occurrence zero did not: a response carrying "gzip" on two field
lines was decoded as a single gzip coding, so a body the sender says was
encoded twice came back after one pass -- still compressed, but presented to
the caller as decoded. The same value written as "gzip, gzip" on one line took
the pass-through path instead.

Read the combined value at both sites. A value naming several codings matches
none of the ones cpp-httplib implements, so both representations now take the
pass-through path that prepare_content_receiver() already documents for an
unrecognized coding.

This does mean a sender that repeats "Content-Encoding: gzip" on two lines for
a body it gzipped once no longer has that body decoded. There is no way to tell
that sender apart from one that really did encode twice, and the conservative
reading is the one the field value states.
This commit is contained in:
yhirose committed 2026-08-18 22:01:14 -04:00
1 parent e8887d98e9
commit 3e3e4863b0
2 files changed
+44 -2

No files matched your search

+3 -2
View File
@@ -8087,7 +8087,7 @@ bool prepare_content_receiver(T &x, int &status,
bool decompress, size_t payload_max_length,
bool &exceed_payload_max_length, U callback) {
if (decompress) {
std::string encoding = x.get_header_value("Content-Encoding");
auto encoding = get_combined_header_value(x.headers, "Content-Encoding");
std::unique_ptr<decompressor> decompressor;
if (!encoding.empty()) {
@@ -14253,7 +14253,8 @@ ClientImpl::open_stream(const std::string &method, const std::string &path,
handle.body_reader_.chunked =
detail::is_chunked_transfer_encoding(handle.response->headers);
auto content_encoding = handle.response->get_header_value("Content-Encoding");
auto content_encoding = detail::get_combined_header_value(
handle.response->headers, "Content-Encoding");
if (!content_encoding.empty()) {
// Same policy as prepare_content_receiver(): reject a coding we know about
// but were not built with, pass an unrecognized one through as-is.