fix(net): cap market and bootstrap HTTP response bodies

Several HTTP fetches read a remote body into memory without a tight
bound. The price and exchange-ticker calls shared one large 16 MiB
metadata cap, and the bootstrap checksum download had no size limit at
all, so a hostile or MITM'd server streaming an unbounded (and
Content-Length-free) response could grow memory far past anything these
endpoints legitimately return.

- The HTTP GET helper now takes a per-call byte cap and redirect limit.
  The write callback refuses bytes past the cap, which aborts the
  transfer, and the same value is set as curl's max file size.
- The price call is capped at 256 KiB and the ticker list at 2 MiB,
  each sized to its real payload rather than the shared default.
- The bootstrap checksum fetch caps its body at 64 KiB in both the
  write callback and curl's max file size.

Tests cover the sink accept/abort boundary.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-10-13 19:24:12 -05:00
co-authored by Claude Opus 4.8
parent edbb98d9ec
commit f1b0ae5ce7
5 changed files with 44 additions and 8 deletions
+15
View File
@@ -855,6 +855,20 @@ void testSecureWipeAndRemove()
fs::remove_all(dir, ec);
}
void testHttpSinkAccept()
{
using dragonx::util::httpSinkAccept;
EXPECT_EQ(httpSinkAccept(0, 100, 1000), (size_t)100);
EXPECT_EQ(httpSinkAccept(900, 100, 1000), (size_t)100); // exactly at the cap is allowed
EXPECT_EQ(httpSinkAccept(901, 100, 1000), (size_t)0); // crossing the cap aborts
EXPECT_EQ(httpSinkAccept(0, 1001, 1000), (size_t)0);
EXPECT_EQ(httpSinkAccept(5000, 100, 0), (size_t)100); // cap <= 0 => unlimited
EXPECT_EQ(httpSinkAccept(5000, 100, -1), (size_t)100);
dragonx::util::HttpGetOptions o;
EXPECT_EQ(o.maxBytes, 16LL * 1024 * 1024);
EXPECT_EQ(o.maxRedirects, 5L);
}
void testClassifyUnlockFailure()
{
using dragonx::rpc::RpcError;
@@ -18283,6 +18297,7 @@ int main()
testConnectionConfig();
testClassifyRpcFailure();
testClassifyUnlockFailure();
testHttpSinkAccept();
testSecureWipeAndRemove();
testFormatHttpError();
testRpcFailureKindOf();