You've already forked cpp-httplib
Fix #1656
This commit is contained in:
12
README.md
12
README.md
@ -275,6 +275,18 @@ svr.set_logger([](const auto& req, const auto& res) {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can also set a pre-compression logger to capture request/response data before compression is applied. This is useful for debugging and monitoring purposes when you need to see the original, uncompressed response content:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
svr.set_pre_compression_logger([](const auto& req, const auto& res) {
|
||||||
|
// Log before compression - res.body contains uncompressed content
|
||||||
|
// Content-Encoding header is not yet set
|
||||||
|
your_pre_compression_logger(req, res);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
The pre-compression logger is only called when compression would be applied. For responses without compression, only the regular logger is called.
|
||||||
|
|
||||||
### Error handler
|
### Error handler
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
@ -1059,6 +1059,7 @@ public:
|
|||||||
|
|
||||||
Server &set_expect_100_continue_handler(Expect100ContinueHandler handler);
|
Server &set_expect_100_continue_handler(Expect100ContinueHandler handler);
|
||||||
Server &set_logger(Logger logger);
|
Server &set_logger(Logger logger);
|
||||||
|
Server &set_pre_compression_logger(Logger logger);
|
||||||
|
|
||||||
Server &set_address_family(int family);
|
Server &set_address_family(int family);
|
||||||
Server &set_tcp_nodelay(bool on);
|
Server &set_tcp_nodelay(bool on);
|
||||||
@ -1202,6 +1203,7 @@ private:
|
|||||||
Expect100ContinueHandler expect_100_continue_handler_;
|
Expect100ContinueHandler expect_100_continue_handler_;
|
||||||
|
|
||||||
Logger logger_;
|
Logger logger_;
|
||||||
|
Logger pre_compression_logger_;
|
||||||
|
|
||||||
int address_family_ = AF_UNSPEC;
|
int address_family_ = AF_UNSPEC;
|
||||||
bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
|
bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
|
||||||
@ -6913,6 +6915,11 @@ inline Server &Server::set_logger(Logger logger) {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Server &Server::set_pre_compression_logger(Logger logger) {
|
||||||
|
pre_compression_logger_ = std::move(logger);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
inline Server &
|
inline Server &
|
||||||
Server::set_expect_100_continue_handler(Expect100ContinueHandler handler) {
|
Server::set_expect_100_continue_handler(Expect100ContinueHandler handler) {
|
||||||
expect_100_continue_handler_ = std::move(handler);
|
expect_100_continue_handler_ = std::move(handler);
|
||||||
@ -7647,6 +7654,8 @@ inline void Server::apply_ranges(const Request &req, Response &res,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type != detail::EncodingType::None) {
|
if (type != detail::EncodingType::None) {
|
||||||
|
if (pre_compression_logger_) { pre_compression_logger_(req, res); }
|
||||||
|
|
||||||
std::unique_ptr<detail::compressor> compressor;
|
std::unique_ptr<detail::compressor> compressor;
|
||||||
std::string content_encoding;
|
std::string content_encoding;
|
||||||
|
|
||||||
|
137
test/test.cc
137
test/test.cc
@ -5901,6 +5901,143 @@ TEST_F(ServerTest, PutWithContentProviderWithZstd) {
|
|||||||
EXPECT_EQ("PUT", res->body);
|
EXPECT_EQ("PUT", res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pre-compression logging tests
|
||||||
|
TEST_F(ServerTest, PreCompressionLogging) {
|
||||||
|
// Test data for compression (matches the actual /compress endpoint content)
|
||||||
|
const std::string test_content = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
|
||||||
|
|
||||||
|
// Variables to capture logging data
|
||||||
|
std::string pre_compression_body;
|
||||||
|
std::string pre_compression_content_type;
|
||||||
|
std::string pre_compression_content_encoding;
|
||||||
|
|
||||||
|
std::string post_compression_body;
|
||||||
|
std::string post_compression_content_type;
|
||||||
|
std::string post_compression_content_encoding;
|
||||||
|
|
||||||
|
// Set up pre-compression logger
|
||||||
|
svr_.set_pre_compression_logger([&](const Request &req, const Response &res) {
|
||||||
|
pre_compression_body = res.body;
|
||||||
|
pre_compression_content_type = res.get_header_value("Content-Type");
|
||||||
|
pre_compression_content_encoding = res.get_header_value("Content-Encoding");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set up post-compression logger
|
||||||
|
svr_.set_logger([&](const Request &req, const Response &res) {
|
||||||
|
post_compression_body = res.body;
|
||||||
|
post_compression_content_type = res.get_header_value("Content-Type");
|
||||||
|
post_compression_content_encoding = res.get_header_value("Content-Encoding");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test with gzip compression
|
||||||
|
Headers headers;
|
||||||
|
headers.emplace("Accept-Encoding", "gzip");
|
||||||
|
|
||||||
|
auto res = cli_.Get("/compress", headers);
|
||||||
|
|
||||||
|
// Verify response was compressed
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(StatusCode::OK_200, res->status);
|
||||||
|
EXPECT_EQ("gzip", res->get_header_value("Content-Encoding"));
|
||||||
|
|
||||||
|
// Verify pre-compression logger captured uncompressed content
|
||||||
|
EXPECT_EQ(test_content, pre_compression_body);
|
||||||
|
EXPECT_EQ("text/plain", pre_compression_content_type);
|
||||||
|
EXPECT_TRUE(pre_compression_content_encoding.empty()); // No encoding header before compression
|
||||||
|
|
||||||
|
// Verify post-compression logger captured compressed content
|
||||||
|
EXPECT_NE(test_content, post_compression_body); // Should be different after compression
|
||||||
|
EXPECT_EQ("text/plain", post_compression_content_type);
|
||||||
|
EXPECT_EQ("gzip", post_compression_content_encoding);
|
||||||
|
|
||||||
|
// Verify compressed content is smaller
|
||||||
|
EXPECT_LT(post_compression_body.size(), pre_compression_body.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, PreCompressionLoggingWithBrotli) {
|
||||||
|
const std::string test_content = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
|
||||||
|
|
||||||
|
std::string pre_compression_body;
|
||||||
|
std::string post_compression_body;
|
||||||
|
|
||||||
|
svr_.set_pre_compression_logger([&](const Request &req, const Response &res) {
|
||||||
|
pre_compression_body = res.body;
|
||||||
|
});
|
||||||
|
|
||||||
|
svr_.set_logger([&](const Request &req, const Response &res) {
|
||||||
|
post_compression_body = res.body;
|
||||||
|
});
|
||||||
|
|
||||||
|
Headers headers;
|
||||||
|
headers.emplace("Accept-Encoding", "br");
|
||||||
|
|
||||||
|
auto res = cli_.Get("/compress", headers);
|
||||||
|
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(StatusCode::OK_200, res->status);
|
||||||
|
EXPECT_EQ("br", res->get_header_value("Content-Encoding"));
|
||||||
|
|
||||||
|
// Verify pre-compression content is uncompressed
|
||||||
|
EXPECT_EQ(test_content, pre_compression_body);
|
||||||
|
|
||||||
|
// Verify post-compression content is compressed
|
||||||
|
EXPECT_NE(test_content, post_compression_body);
|
||||||
|
EXPECT_LT(post_compression_body.size(), pre_compression_body.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, PreCompressionLoggingWithoutCompression) {
|
||||||
|
const std::string test_content = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
|
||||||
|
|
||||||
|
std::string pre_compression_body;
|
||||||
|
std::string post_compression_body;
|
||||||
|
|
||||||
|
svr_.set_pre_compression_logger([&](const Request &req, const Response &res) {
|
||||||
|
pre_compression_body = res.body;
|
||||||
|
});
|
||||||
|
|
||||||
|
svr_.set_logger([&](const Request &req, const Response &res) {
|
||||||
|
post_compression_body = res.body;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Request without compression (use /nocompress endpoint)
|
||||||
|
Headers headers;
|
||||||
|
auto res = cli_.Get("/nocompress", headers);
|
||||||
|
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(StatusCode::OK_200, res->status);
|
||||||
|
EXPECT_TRUE(res->get_header_value("Content-Encoding").empty());
|
||||||
|
|
||||||
|
// Pre-compression logger should not be called when no compression is applied
|
||||||
|
EXPECT_TRUE(pre_compression_body.empty()); // Pre-compression logger not called
|
||||||
|
EXPECT_EQ(test_content, post_compression_body); // Post-compression logger captures final content
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, PreCompressionLoggingOnlyPreLogger) {
|
||||||
|
const std::string test_content = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
|
||||||
|
|
||||||
|
std::string pre_compression_body;
|
||||||
|
bool pre_logger_called = false;
|
||||||
|
|
||||||
|
// Set only pre-compression logger
|
||||||
|
svr_.set_pre_compression_logger([&](const Request &req, const Response &res) {
|
||||||
|
pre_compression_body = res.body;
|
||||||
|
pre_logger_called = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
Headers headers;
|
||||||
|
headers.emplace("Accept-Encoding", "gzip");
|
||||||
|
|
||||||
|
auto res = cli_.Get("/compress", headers);
|
||||||
|
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(StatusCode::OK_200, res->status);
|
||||||
|
EXPECT_EQ("gzip", res->get_header_value("Content-Encoding"));
|
||||||
|
|
||||||
|
// Verify pre-compression logger was called
|
||||||
|
EXPECT_TRUE(pre_logger_called);
|
||||||
|
EXPECT_EQ(test_content, pre_compression_body);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ZstdDecompressor, ChunkedDecompression) {
|
TEST(ZstdDecompressor, ChunkedDecompression) {
|
||||||
std::string data;
|
std::string data;
|
||||||
for (size_t i = 0; i < 32 * 1024; ++i) {
|
for (size_t i = 0; i < 32 * 1024; ++i) {
|
||||||
|
Reference in New Issue
Block a user