fix: Bound and offload per-connection subscription cleanup

This commit is contained in:
Bart
2026-07-16 16:24:06 -04:00
committed by Ayaz Salikhov
parent 5ab95748d4
commit 1dcaf4b54e
12 changed files with 1301 additions and 214 deletions

View File

@@ -33,6 +33,7 @@ set(test_modules
shamap
tx
protocol_autogen
server
)
if(NOT WIN32)
list(APPEND test_modules net)

View File

@@ -0,0 +1,60 @@
#include <xrpl/server/InfoSub.h>
#include <gtest/gtest.h>
#include <cstddef>
#include <limits>
using namespace xrpl;
// The per-connection subscription cap is enforced by the pure predicate
// exceedsSubscriptionCap(current, additional). Testing it directly (rather than
// by subscribing the real cap through a WebSocket, which would exceed the frame
// limit and drop the connection before the check runs) lets the boundary be
// asserted exactly.
TEST(InfoSubSubscriptionCap, Boundary)
{
constexpr std::size_t cap = kMaxSubscriptionsPerConnection;
// Empty connection: anything up to the cap is admitted, cap+1 is not.
EXPECT_FALSE(exceedsSubscriptionCap(0, 0));
EXPECT_FALSE(exceedsSubscriptionCap(0, cap));
EXPECT_TRUE(exceedsSubscriptionCap(0, cap + 1));
// Exactly at the cap: zero more is fine, one more is rejected.
EXPECT_FALSE(exceedsSubscriptionCap(cap, 0));
EXPECT_TRUE(exceedsSubscriptionCap(cap, 1));
// One below the cap: exactly one more reaches the cap; two exceed it.
EXPECT_FALSE(exceedsSubscriptionCap(cap - 1, 1));
EXPECT_TRUE(exceedsSubscriptionCap(cap - 1, 2));
}
TEST(InfoSubSubscriptionCap, NoOverflow)
{
constexpr std::size_t cap = kMaxSubscriptionsPerConnection;
constexpr std::size_t max = std::numeric_limits<std::size_t>::max();
// current + additional must not wrap: a huge additional is rejected even
// when current is 0 (the additional > cap term guards the subtraction).
EXPECT_TRUE(exceedsSubscriptionCap(0, max));
EXPECT_TRUE(exceedsSubscriptionCap(cap, max));
}
TEST(InfoSubSubscriptionCap, ExplicitCap)
{
// A configured override is honored: the boundary tracks the passed cap, not
// the built-in default. This is the seam doSubscribe uses to enforce a
// per-connection cap set via [max_subscriptions_per_connection].
constexpr std::size_t cap = 5;
EXPECT_FALSE(exceedsSubscriptionCap(0, cap, cap));
EXPECT_TRUE(exceedsSubscriptionCap(0, cap + 1, cap));
EXPECT_FALSE(exceedsSubscriptionCap(cap, 0, cap));
EXPECT_TRUE(exceedsSubscriptionCap(cap, 1, cap));
EXPECT_FALSE(exceedsSubscriptionCap(cap - 1, 1, cap));
EXPECT_TRUE(exceedsSubscriptionCap(cap - 1, 2, cap));
// The overflow guard still holds with a small explicit cap.
EXPECT_TRUE(exceedsSubscriptionCap(0, std::numeric_limits<std::size_t>::max(), cap));
}