mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-12 10:22:39 +00:00
Match Brotli and Zstandard content codings as whole tokens
is_brotli_encoding() and is_zstd_encoding() searched the Content-Encoding value for "br" and "zstd" as substrings, while is_zlib_encoding() beside them compared the whole value. So "fibre" and "librarian" were read as Brotli and "x-zstd-ish" as Zstandard, and "gzip, br" -- a value naming two codings, which cpp-httplib does not support -- was labeled Brotli and run through a Brotli decompressor over gzip data. RFC 9110 8.4.1 defines a content coding as a token, so compare the whole value case-insensitively as the zlib check already does. A value naming several codings no longer matches any of them and takes the pass-through path prepare_content_receiver() already documents for an unrecognized coding. contains_case_ignore() has no callers left.
This commit is contained in:
@@ -11049,6 +11049,52 @@ static const char GZIPPED_HELLO_WORLD[] = {
|
||||
// A content coding cpp-httplib recognizes but was not built with must be
|
||||
// reported as such. Handing the still-compressed payload back to the caller
|
||||
// would silently corrupt it.
|
||||
// A content coding is a whole token, not something the field value merely
|
||||
// contains. Matching "br" and "zstd" as substrings made unrelated values such
|
||||
// as "fibre" look like Brotli, and turned a multi-coding value like
|
||||
// "gzip, br" into a Brotli-labeled body, so a decompressor was run over data
|
||||
// it was never meant to see.
|
||||
TEST(ContentEncodingTest, SubstringOfACodingIsNotTheCoding) {
|
||||
const std::string body = "\xff\xd8\xff\xe0 not really a jpeg";
|
||||
|
||||
Server svr;
|
||||
|
||||
svr.Get("/fibre", [&](const Request & /*req*/, Response &res) {
|
||||
res.set_content(body, "image/jpeg");
|
||||
res.set_header("Content-Encoding", "fibre");
|
||||
});
|
||||
|
||||
svr.Get("/multi", [&](const Request & /*req*/, Response &res) {
|
||||
res.set_content(body, "image/jpeg");
|
||||
res.set_header("Content-Encoding", "gzip, br");
|
||||
});
|
||||
|
||||
svr.Get("/zstdish", [&](const Request & /*req*/, Response &res) {
|
||||
res.set_content(body, "image/jpeg");
|
||||
res.set_header("Content-Encoding", "x-zstd-ish");
|
||||
});
|
||||
|
||||
auto port = svr.bind_to_any_port(HOST);
|
||||
thread t = thread([&]() { svr.listen_after_bind(); });
|
||||
auto se = detail::scope_exit([&] {
|
||||
svr.stop();
|
||||
t.join();
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
svr.wait_until_ready();
|
||||
|
||||
Client cli(HOST, port);
|
||||
|
||||
for (const char *path : {"/fibre", "/multi", "/zstdish"}) {
|
||||
auto res = cli.Get(path);
|
||||
ASSERT_TRUE(res) << path << " -> " << to_string(res.error());
|
||||
EXPECT_EQ(StatusCode::OK_200, res->status) << path;
|
||||
// Not a coding we recognize, so the payload comes back untouched
|
||||
EXPECT_EQ(body, res->body) << path;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ContentEncodingTest, KnownEncodingWithoutSupportIsReported) {
|
||||
const std::string gzipped(GZIPPED_HELLO_WORLD, sizeof(GZIPPED_HELLO_WORLD));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user