feat(json_family): Add json_nesting_depth_limit flag (#4444)

* feat: Add json_nesting_depth_limit flag

Signed-off-by: Stepan Bagritsevich <stefan@dragonflydb.io>

* refactor: address comments

Signed-off-by: Stepan Bagritsevich <stefan@dragonflydb.io>

---------

Signed-off-by: Stepan Bagritsevich <stefan@dragonflydb.io>
This commit is contained in:
Stepan Bagritsevich 2025-01-20 17:49:04 +01:00 committed by GitHub
parent 99c4ab8abe
commit 5d3e3146d3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 47 additions and 5 deletions

View file

@ -343,7 +343,7 @@ OpResult<DbSlice::AddOrFindResult> SetJson(const OpArgs& op_args, string_view ke
std::optional<JsonType> parsed_json = ShardJsonFromString(json_str);
if (!parsed_json) {
VLOG(1) << "got invalid JSON string '" << json_str << "' cannot be saved";
return OpStatus::INVALID_VALUE;
return OpStatus::INVALID_JSON;
}
if (JsonEnconding() == kEncodingJsonFlat) {
@ -1345,7 +1345,7 @@ OpResult<bool> OpSet(const OpArgs& op_args, string_view key, string_view path,
optional<JsonType> parsed_json = ShardJsonFromString(json_str);
if (!parsed_json) {
VLOG(1) << "got invalid JSON string '" << json_str << "' cannot be saved";
return OpStatus::INVALID_VALUE;
return OpStatus::INVALID_JSON;
}
const JsonType& new_json = parsed_json.value();
@ -1444,7 +1444,7 @@ OpStatus OpMerge(const OpArgs& op_args, string_view key, string_view path,
std::optional<JsonType> parsed_json = ShardJsonFromString(json_str);
if (!parsed_json) {
VLOG(1) << "got invalid JSON string '" << json_str << "' cannot be saved";
return OpStatus::SYNTAX_ERR;
return OpStatus::INVALID_JSON;
}
auto cb = [&](std::optional<std::string_view> cur_path, JsonType* val) -> MutateCallbackResult<> {

View file

@ -3017,4 +3017,33 @@ TEST_F(JsonFamilyTest, GetString) {
EXPECT_THAT(resp, ErrArg("WRONGTYPE"));
}
TEST_F(JsonFamilyTest, MaxNestingJsonDepth) {
auto generate_nested_json = [](int depth) -> std::string {
std::string json = "{";
for (int i = 0; i < depth - 1; ++i) {
json += R"("key": {)";
}
json += R"("key": "value")"; // Innermost value
for (int i = 0; i < depth - 1; ++i) {
json += "}";
}
json += "}";
return json;
};
// Generate JSON with maximum allowed depth (256)
/* std::string valid_json = generate_nested_json(255);
// Test with valid JSON at depth 256
auto resp = Run({"JSON.SET", "valid_json", ".", valid_json});
EXPECT_THAT(resp, "OK"); */
// Generate JSON exceeding maximum depth (257)
std::string invalid_json = generate_nested_json(257);
// Test with invalid JSON at depth 257
auto resp = Run({"JSON.SET", "invalid_json", ".", invalid_json});
EXPECT_THAT(resp, ErrArg("failed to parse JSON"));
}
} // namespace dfly