mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-26 12:24:46 +00:00
Do not reserve a response body by its claimed length
The client reserved what Content-Length claimed, up to payload_max_length, before any of the body arrived, and without a limit nothing bounded it. Reserve at most 1 MiB up front and let a longer body grow as it is read.
This commit is contained in:
1 parent
b270564c18
commit
672255619b
2 files changed
+31
-7
No files matched your search
@@ -16599,13 +16599,13 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req,
|
|||||||
output_error_log(error, &req);
|
output_error_log(error, &req);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Cap the reservation by payload_max_length_ to avoid OOM when a
|
// Content-Length is only the server's claim, so reserve no more than
|
||||||
// hostile or malformed server sends an enormous Content-Length.
|
// payload_max_length_ allows, nor more than 1 MiB before any of the
|
||||||
// The actual body read below is bounded by payload_max_length_,
|
// body has arrived. A longer body grows as it is read.
|
||||||
// so reserving more than that is never useful.
|
auto reserve_len =
|
||||||
auto reserve_len = static_cast<size_t>(len);
|
(std::min)(static_cast<size_t>(len), size_t(1024 * 1024));
|
||||||
if (payload_max_length_ > 0 && reserve_len > payload_max_length_) {
|
if (payload_max_length_ > 0) {
|
||||||
reserve_len = payload_max_length_;
|
reserve_len = (std::min)(reserve_len, payload_max_length_);
|
||||||
}
|
}
|
||||||
res.body.reserve(reserve_len);
|
res.body.reserve(reserve_len);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13382,6 +13382,30 @@ TEST_F(LargePayloadMaxLengthTest, NoContentLengthExceeds10MB) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ClientPayloadTest, DoesNotReserveTheClaimedLength) {
|
||||||
|
Server svr;
|
||||||
|
svr.Get("/", [](const Request &, Response &res) {
|
||||||
|
// Claims far more than it sends, then drops the connection.
|
||||||
|
res.set_content_provider(size_t(1) << 41, "text/plain",
|
||||||
|
[](size_t, size_t, DataSink &sink) {
|
||||||
|
sink.write("abc", 3);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
|
||||||
|
auto se = detail::scope_exit([&] {
|
||||||
|
svr.stop();
|
||||||
|
thread.join();
|
||||||
|
ASSERT_FALSE(svr.is_running());
|
||||||
|
});
|
||||||
|
svr.wait_until_ready();
|
||||||
|
|
||||||
|
Client cli(HOST, PORT);
|
||||||
|
cli.set_payload_max_length(0);
|
||||||
|
EXPECT_FALSE(cli.Get("/"));
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||||
// `payload_max_length` is not enforced on decompressed body in ContentReader
|
// `payload_max_length` is not enforced on decompressed body in ContentReader
|
||||||
// path.
|
// path.
|
||||||
|
|||||||
Reference in new issue
Block a user