mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-02 19:25:05 +03:00
fe5d704d67
pushClientTraffics decoded the pushed list whole, and each "{}" became a
full traffic row, so a body under the size cap could cost the panel
close to a gigabyte. The list is now decoded entry by entry and refused
past 262144 entries. The capped decoder the node runtime already used
moves to json_util so both share it.
39 lines
1.0 KiB
Go
39 lines
1.0 KiB
Go
package json_util
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// ErrListTooLong is returned by DecodeCappedList for a list past its entry limit.
|
|
var ErrListTooLong = errors.New("list exceeds entry limit")
|
|
|
|
// DecodeCappedList decodes a JSON array entry by entry and stops at the first entry past
|
|
// maxEntries: each "{}" becomes a whole T, so a byte cap alone does not bound the result.
|
|
func DecodeCappedList[T any](raw []byte, maxEntries int) ([]T, error) {
|
|
raw = bytes.TrimSpace(raw)
|
|
if len(raw) == 0 || bytes.Equal(raw, []byte("null")) {
|
|
return nil, nil
|
|
}
|
|
dec := json.NewDecoder(bytes.NewReader(raw))
|
|
if tok, err := dec.Token(); err != nil {
|
|
return nil, err
|
|
} else if delim, ok := tok.(json.Delim); !ok || delim != '[' {
|
|
return nil, fmt.Errorf("expected a JSON array, got %v", tok)
|
|
}
|
|
var out []T
|
|
for dec.More() {
|
|
if len(out) >= maxEntries {
|
|
return nil, fmt.Errorf("%w (%d)", ErrListTooLong, maxEntries)
|
|
}
|
|
var item T
|
|
if err := dec.Decode(&item); err != nil {
|
|
return nil, err
|
|
}
|
|
out = append(out, item)
|
|
}
|
|
return out, nil
|
|
}
|