mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-30 02:20:39 +00:00
test: Add JSON array size tests (#7592)
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
@@ -1979,7 +1980,7 @@ class STParsedJSON_test : public beast::unit_test::Suite
|
||||
json::Value j;
|
||||
json::Value obj(json::ValueType::Object);
|
||||
json::Value* current = &obj;
|
||||
for (int i = 0; i < 63; ++i)
|
||||
for (std::size_t i = 1; i < kMaxParsedJsonDepth; ++i)
|
||||
{
|
||||
json::Value const next(json::ValueType::Object);
|
||||
(*current)[sfTransactionMetaData] = next;
|
||||
@@ -1998,7 +1999,7 @@ class STParsedJSON_test : public beast::unit_test::Suite
|
||||
json::Value j;
|
||||
json::Value obj(json::ValueType::Object);
|
||||
json::Value* current = &obj;
|
||||
for (int i = 0; i < 64; ++i)
|
||||
for (std::size_t i = 1; i <= kMaxParsedJsonDepth; ++i)
|
||||
{
|
||||
json::Value const next(json::ValueType::Object);
|
||||
(*current)[sfTransactionMetaData] = next;
|
||||
@@ -2153,6 +2154,191 @@ class STParsedJSON_test : public beast::unit_test::Suite
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testArrayBoundsChecking()
|
||||
{
|
||||
testcase("Array bounds checking");
|
||||
|
||||
auto const limitStr = std::to_string(kMaxParsedJsonArraySize) + " elements per field.";
|
||||
|
||||
// parseArray rejects oversized STI_ARRAY (SignerEntries)
|
||||
{
|
||||
json::Value jv;
|
||||
json::Value entries(json::ValueType::Array);
|
||||
for (std::size_t i = 0; i <= kMaxParsedJsonArraySize; ++i)
|
||||
{
|
||||
json::Value entry;
|
||||
entry["SignerEntry"]["Account"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
|
||||
entry["SignerEntry"]["SignerWeight"] = 1;
|
||||
entries.append(entry);
|
||||
}
|
||||
jv[sfSignerEntries] = entries;
|
||||
|
||||
STParsedJSONObject parsed("test", jv);
|
||||
BEAST_EXPECT(!parsed.object);
|
||||
BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(
|
||||
parsed.error[jss::error_message] ==
|
||||
"Field 'test.SignerEntries' exceeds allowed JSON array size of " + limitStr);
|
||||
}
|
||||
|
||||
// parseObject rejects oversized STI_VECTOR256 (Amendments)
|
||||
{
|
||||
json::Value jv;
|
||||
json::Value amendments(json::ValueType::Array);
|
||||
std::string const hash(64, '0');
|
||||
for (std::size_t i = 0; i <= kMaxParsedJsonArraySize; ++i)
|
||||
amendments.append(hash);
|
||||
jv[sfAmendments] = amendments;
|
||||
|
||||
STParsedJSONObject parsed("test", jv);
|
||||
BEAST_EXPECT(!parsed.object);
|
||||
BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(
|
||||
parsed.error[jss::error_message] ==
|
||||
"Field 'test.Amendments' exceeds allowed JSON array size of " + limitStr);
|
||||
}
|
||||
|
||||
// parseObject accepts exactly kMaxParsedJsonArraySize STI_VECTOR256 (Amendments)
|
||||
{
|
||||
json::Value jv;
|
||||
json::Value amendments(json::ValueType::Array);
|
||||
std::string const hash(64, '0');
|
||||
for (std::size_t i = 0; i < kMaxParsedJsonArraySize; ++i)
|
||||
amendments.append(hash);
|
||||
jv[sfAmendments] = amendments;
|
||||
|
||||
STParsedJSONObject const parsed("test", jv);
|
||||
BEAST_EXPECT(parsed.object);
|
||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
|
||||
auto const arrSize = parsed.object->getFieldV256(sfAmendments).size();
|
||||
BEAST_EXPECT(arrSize == kMaxParsedJsonArraySize);
|
||||
}
|
||||
|
||||
// parseObject rejects oversized STI_PATHSET (outer array)
|
||||
{
|
||||
json::Value jv;
|
||||
json::Value paths(json::ValueType::Array);
|
||||
for (std::size_t i = 0; i <= kMaxParsedJsonArraySize; ++i)
|
||||
{
|
||||
json::Value path(json::ValueType::Array);
|
||||
json::Value hop;
|
||||
hop["account"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
|
||||
path.append(hop);
|
||||
paths.append(path);
|
||||
}
|
||||
jv[sfPaths] = paths;
|
||||
|
||||
STParsedJSONObject parsed("test", jv);
|
||||
BEAST_EXPECT(!parsed.object);
|
||||
BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(
|
||||
parsed.error[jss::error_message] ==
|
||||
"Field 'test.Paths' exceeds allowed JSON array size of " + limitStr);
|
||||
}
|
||||
|
||||
// parseObject accepts exactly kMaxParsedJsonArraySize STI_PATHSET (outer array)
|
||||
{
|
||||
json::Value jv;
|
||||
json::Value paths(json::ValueType::Array);
|
||||
for (std::size_t i = 0; i < kMaxParsedJsonArraySize; ++i)
|
||||
{
|
||||
json::Value path(json::ValueType::Array);
|
||||
json::Value hop;
|
||||
hop["account"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
|
||||
path.append(hop);
|
||||
paths.append(path);
|
||||
}
|
||||
jv[sfPaths] = paths;
|
||||
|
||||
STParsedJSONObject const parsed("test", jv);
|
||||
BEAST_EXPECT(parsed.object);
|
||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
|
||||
auto const arrSize = parsed.object->getFieldPathSet(sfPaths).size();
|
||||
BEAST_EXPECT(arrSize == kMaxParsedJsonArraySize);
|
||||
}
|
||||
|
||||
// parseObject rejects oversized STI_PATHSET (inner path hop array)
|
||||
{
|
||||
json::Value jv;
|
||||
json::Value paths(json::ValueType::Array);
|
||||
json::Value path(json::ValueType::Array);
|
||||
json::Value hop;
|
||||
hop["account"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
|
||||
for (std::size_t i = 0; i <= kMaxParsedJsonArraySize; ++i)
|
||||
path.append(hop);
|
||||
paths.append(path);
|
||||
jv[sfPaths] = paths;
|
||||
|
||||
STParsedJSONObject parsed("test", jv);
|
||||
BEAST_EXPECT(!parsed.object);
|
||||
BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(
|
||||
parsed.error[jss::error_message] ==
|
||||
"Field 'test.Paths[0]' exceeds allowed JSON array size of " + limitStr);
|
||||
}
|
||||
|
||||
// parseObject accepts exactly kMaxParsedJsonArraySize hops in a single STI_PATHSET path
|
||||
{
|
||||
json::Value jv;
|
||||
json::Value paths(json::ValueType::Array);
|
||||
json::Value path(json::ValueType::Array);
|
||||
json::Value hop;
|
||||
hop["account"] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
|
||||
for (std::size_t i = 0; i < kMaxParsedJsonArraySize; ++i)
|
||||
path.append(hop);
|
||||
paths.append(path);
|
||||
jv[sfPaths] = paths;
|
||||
|
||||
STParsedJSONObject const parsed("test", jv);
|
||||
BEAST_EXPECT(parsed.object);
|
||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
|
||||
auto const arrSize = parsed.object->getFieldPathSet(sfPaths)[0].size();
|
||||
BEAST_EXPECT(arrSize == kMaxParsedJsonArraySize);
|
||||
}
|
||||
|
||||
// parseArray accepts exactly kMaxParsedJsonArraySize Memos (boundary)
|
||||
{
|
||||
json::Value jv;
|
||||
json::Value memos(json::ValueType::Array);
|
||||
for (std::size_t i = 0; i < kMaxParsedJsonArraySize; ++i)
|
||||
{
|
||||
json::Value memo;
|
||||
memo["Memo"] = json::Value(json::ValueType::Object);
|
||||
memo["Memo"]["MemoData"] = "00";
|
||||
memos.append(memo);
|
||||
}
|
||||
jv[sfMemos] = memos;
|
||||
|
||||
STParsedJSONObject const parsed("test", jv);
|
||||
BEAST_EXPECT(parsed.object);
|
||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
|
||||
auto const arrSize = parsed.object->getFieldArray(sfMemos).size();
|
||||
BEAST_EXPECT(arrSize == kMaxParsedJsonArraySize);
|
||||
}
|
||||
|
||||
// parseArray rejects one more than kMaxParsedJsonArraySize Memos
|
||||
{
|
||||
json::Value jv;
|
||||
json::Value memos(json::ValueType::Array);
|
||||
for (std::size_t i = 0; i <= kMaxParsedJsonArraySize; ++i)
|
||||
{
|
||||
json::Value memo;
|
||||
memo["Memo"] = json::Value(json::ValueType::Object);
|
||||
memo["Memo"]["MemoData"] = "00";
|
||||
memos.append(memo);
|
||||
}
|
||||
jv[sfMemos] = memos;
|
||||
|
||||
STParsedJSONObject parsed("test", jv);
|
||||
BEAST_EXPECT(!parsed.object);
|
||||
BEAST_EXPECT(parsed.error[jss::error] == "invalidParams");
|
||||
BEAST_EXPECT(
|
||||
parsed.error[jss::error_message] ==
|
||||
"Field 'test.Memos' exceeds allowed JSON array size of " + limitStr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testEdgeCases()
|
||||
{
|
||||
@@ -2420,6 +2606,7 @@ class STParsedJSON_test : public beast::unit_test::Suite
|
||||
testNumber();
|
||||
testObject();
|
||||
testArray();
|
||||
testArrayBoundsChecking();
|
||||
testEdgeCases();
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user