fix(node): count only values against the node-answer value cap

decodeCappedValues is documented to count JSON values, but it also
counted object keys and closing brackets, so a node's GUID-keyed online
and IP trees reached the cap at roughly half the stated number of
values, and the master then refused the whole report rather than the
excess.

Keys and closing brackets no longer count; every value, nested ones
included, still does.
This commit is contained in:
MHSanaei
2026-11-01 13:14:46 +01:00
parent 1d373cf67e
commit 93d1e63554
2 changed files with 34 additions and 4 deletions
+20 -4
View File
@@ -23,20 +23,36 @@ const (
var errRemoteListTooLong = json_util.ErrListTooLong
// decodeCappedValues unmarshals raw into v after checking it holds at most maxValues
// JSON values in all, nested ones included.
// JSON values in all, nested ones included; object keys and closing brackets are not values.
func decodeCappedValues(raw json.RawMessage, v any, maxValues int) error {
dec := json.NewDecoder(bytes.NewReader(raw))
for count := 0; ; count++ {
// One frame per open container; an object's strings alternate between key and value.
type frame struct{ object, wantKey bool }
var open []frame
count := 0
for {
tok, err := dec.Token()
if err != nil {
break
}
if delim, ok := tok.(json.Delim); ok && (delim == ']' || delim == '}') {
delim, isDelim := tok.(json.Delim)
if isDelim && (delim == ']' || delim == '}') {
open = open[:len(open)-1]
continue
}
if count > maxValues {
if top := len(open) - 1; top >= 0 && open[top].object {
if open[top].wantKey {
open[top].wantKey = false
continue
}
open[top].wantKey = true
}
if count++; count > maxValues {
return fmt.Errorf("%w (%d values)", errRemoteListTooLong, maxValues)
}
if isDelim {
open = append(open, frame{object: delim == '{', wantKey: delim == '{'})
}
}
return json.Unmarshal(raw, v)
}