mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-17 10:59:39 +00:00
Add Brotli compression support and corresponding tests
This commit is contained in:
1 parent
4978f26f86
commit
ec1ffbc27d
2 files changed
+80
-24
No files matched your search
@@ -6862,6 +6862,21 @@ create_decompressor(const std::string &encoding) {
|
|||||||
return decompressor;
|
return decompressor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the best available compressor and its Content-Encoding name.
|
||||||
|
// Priority: Brotli > Gzip > Zstd (matches server-side preference).
|
||||||
|
inline std::pair<std::unique_ptr<compressor>, const char *>
|
||||||
|
create_compressor() {
|
||||||
|
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||||
|
return {detail::make_unique<brotli_compressor>(), "br"};
|
||||||
|
#elif defined(CPPHTTPLIB_ZLIB_SUPPORT)
|
||||||
|
return {detail::make_unique<gzip_compressor>(), "gzip"};
|
||||||
|
#elif defined(CPPHTTPLIB_ZSTD_SUPPORT)
|
||||||
|
return {detail::make_unique<zstd_compressor>(), "zstd"};
|
||||||
|
#else
|
||||||
|
return {nullptr, nullptr};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
inline bool is_prohibited_header_name(const std::string &name) {
|
inline bool is_prohibited_header_name(const std::string &name) {
|
||||||
using udl::operator""_t;
|
using udl::operator""_t;
|
||||||
|
|
||||||
@@ -13015,14 +13030,9 @@ inline bool ClientImpl::write_content_with_provider(Stream &strm,
|
|||||||
auto is_shutting_down = []() { return false; };
|
auto is_shutting_down = []() { return false; };
|
||||||
|
|
||||||
if (req.is_chunked_content_provider_) {
|
if (req.is_chunked_content_provider_) {
|
||||||
// TODO: Brotli support
|
auto compressor = compress_ ? detail::create_compressor().first
|
||||||
std::unique_ptr<detail::compressor> compressor;
|
: std::unique_ptr<detail::compressor>();
|
||||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
if (!compressor) {
|
||||||
if (compress_) {
|
|
||||||
compressor = detail::make_unique<detail::gzip_compressor>();
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
compressor = detail::make_unique<detail::nocompressor>();
|
compressor = detail::make_unique<detail::nocompressor>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13253,14 +13263,15 @@ ClientImpl::send_with_content_provider_and_receiver(
|
|||||||
Error &error) {
|
Error &error) {
|
||||||
if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
|
if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
auto enc = compress_
|
||||||
if (compress_) { req.set_header("Content-Encoding", "gzip"); }
|
? detail::create_compressor()
|
||||||
#endif
|
: std::pair<std::unique_ptr<detail::compressor>, const char *>(
|
||||||
|
nullptr, nullptr);
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
if (enc.second) { req.set_header("Content-Encoding", enc.second); }
|
||||||
if (compress_ && !content_provider_without_length) {
|
|
||||||
// TODO: Brotli support
|
if (enc.first && !content_provider_without_length) {
|
||||||
detail::gzip_compressor compressor;
|
auto &compressor = enc.first;
|
||||||
|
|
||||||
if (content_provider) {
|
if (content_provider) {
|
||||||
auto ok = true;
|
auto ok = true;
|
||||||
@@ -13271,7 +13282,7 @@ ClientImpl::send_with_content_provider_and_receiver(
|
|||||||
if (ok) {
|
if (ok) {
|
||||||
auto last = offset + data_len == content_length;
|
auto last = offset + data_len == content_length;
|
||||||
|
|
||||||
auto ret = compressor.compress(
|
auto ret = compressor->compress(
|
||||||
data, data_len, last,
|
data, data_len, last,
|
||||||
[&](const char *compressed_data, size_t compressed_data_len) {
|
[&](const char *compressed_data, size_t compressed_data_len) {
|
||||||
req.body.append(compressed_data, compressed_data_len);
|
req.body.append(compressed_data, compressed_data_len);
|
||||||
@@ -13295,19 +13306,17 @@ ClientImpl::send_with_content_provider_and_receiver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!compressor.compress(body, content_length, true,
|
if (!compressor->compress(body, content_length, true,
|
||||||
[&](const char *data, size_t data_len) {
|
[&](const char *data, size_t data_len) {
|
||||||
req.body.append(data, data_len);
|
req.body.append(data, data_len);
|
||||||
return true;
|
return true;
|
||||||
})) {
|
})) {
|
||||||
error = Error::Compression;
|
error = Error::Compression;
|
||||||
output_error_log(error, &req);
|
output_error_log(error, &req);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (content_provider) {
|
if (content_provider) {
|
||||||
req.content_length_ = content_length;
|
req.content_length_ = content_length;
|
||||||
req.content_provider_ = std::move(content_provider);
|
req.content_provider_ = std::move(content_provider);
|
||||||
|
|||||||
@@ -5745,7 +5745,13 @@ TEST_F(ServerTest, PutLargeFileWithGzip2) {
|
|||||||
// depending on the zlib library.
|
// depending on the zlib library.
|
||||||
EXPECT_LT(res.get_request_header_value_u64("Content-Length"),
|
EXPECT_LT(res.get_request_header_value_u64("Content-Length"),
|
||||||
static_cast<uint64_t>(10 * 1024 * 1024));
|
static_cast<uint64_t>(10 * 1024 * 1024));
|
||||||
|
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||||
|
EXPECT_EQ("br", res.get_request_header_value("Content-Encoding"));
|
||||||
|
#elif defined(CPPHTTPLIB_ZLIB_SUPPORT)
|
||||||
EXPECT_EQ("gzip", res.get_request_header_value("Content-Encoding"));
|
EXPECT_EQ("gzip", res.get_request_header_value("Content-Encoding"));
|
||||||
|
#elif defined(CPPHTTPLIB_ZSTD_SUPPORT)
|
||||||
|
EXPECT_EQ("zstd", res.get_request_header_value("Content-Encoding"));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ServerTest, PutContentWithDeflate) {
|
TEST_F(ServerTest, PutContentWithDeflate) {
|
||||||
@@ -5955,6 +5961,47 @@ TEST_F(ServerTest, GetStreamedChunkedWithBrotli2) {
|
|||||||
EXPECT_EQ(StatusCode::OK_200, res->status);
|
EXPECT_EQ(StatusCode::OK_200, res->status);
|
||||||
EXPECT_EQ(std::string("123456789"), res->body);
|
EXPECT_EQ(std::string("123456789"), res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, PutWithContentProviderWithBrotli) {
|
||||||
|
cli_.set_compress(true);
|
||||||
|
auto res = cli_.Put(
|
||||||
|
"/put", 3,
|
||||||
|
[](size_t /*offset*/, size_t /*length*/, DataSink &sink) {
|
||||||
|
sink.os << "PUT";
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
"text/plain");
|
||||||
|
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(StatusCode::OK_200, res->status);
|
||||||
|
EXPECT_EQ("PUT", res->body);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, PutWithContentProviderWithoutLengthWithBrotli) {
|
||||||
|
cli_.set_compress(true);
|
||||||
|
auto res = cli_.Put(
|
||||||
|
"/put",
|
||||||
|
[](size_t /*offset*/, DataSink &sink) {
|
||||||
|
sink.os << "PUT";
|
||||||
|
sink.done();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
"text/plain");
|
||||||
|
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(StatusCode::OK_200, res->status);
|
||||||
|
EXPECT_EQ("PUT", res->body);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, PutLargeFileWithBrotli) {
|
||||||
|
cli_.set_compress(true);
|
||||||
|
auto res = cli_.Put("/put-large", LARGE_DATA, "text/plain");
|
||||||
|
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(StatusCode::OK_200, res->status);
|
||||||
|
EXPECT_EQ(LARGE_DATA, res->body);
|
||||||
|
EXPECT_EQ("br", res.get_request_header_value("Content-Encoding"));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TEST_F(ServerTest, Patch) {
|
TEST_F(ServerTest, Patch) {
|
||||||
|
|||||||
Reference in new issue
Block a user