You've already forked json-iterator
mirror of
https://github.com/json-iterator/go.git
synced 2025-11-26 22:40:13 +02:00
Limit nesting depth
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"github.com/json-iterator/go"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -15,6 +16,243 @@ type Level2 struct {
|
||||
World string
|
||||
}
|
||||
|
||||
func Test_deep_nested(t *testing.T) {
|
||||
type unstructured interface{}
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
data []byte
|
||||
expectError string
|
||||
}{
|
||||
{
|
||||
name: "array under maxDepth",
|
||||
data: []byte(`{"a":` + strings.Repeat(`[`, 10000-1) + strings.Repeat(`]`, 10000-1) + `}`),
|
||||
expectError: "",
|
||||
},
|
||||
{
|
||||
name: "array over maxDepth",
|
||||
data: []byte(`{"a":` + strings.Repeat(`[`, 10000) + strings.Repeat(`]`, 10000) + `}`),
|
||||
expectError: "max depth",
|
||||
},
|
||||
{
|
||||
name: "object under maxDepth",
|
||||
data: []byte(`{"a":` + strings.Repeat(`{"a":`, 10000-1) + `0` + strings.Repeat(`}`, 10000-1) + `}`),
|
||||
expectError: "",
|
||||
},
|
||||
{
|
||||
name: "object over maxDepth",
|
||||
data: []byte(`{"a":` + strings.Repeat(`{"a":`, 10000) + `0` + strings.Repeat(`}`, 10000) + `}`),
|
||||
expectError: "max depth",
|
||||
},
|
||||
}
|
||||
|
||||
targets := []struct {
|
||||
name string
|
||||
new func() interface{}
|
||||
}{
|
||||
{
|
||||
name: "unstructured",
|
||||
new: func() interface{} {
|
||||
var v interface{}
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "typed named field",
|
||||
new: func() interface{} {
|
||||
v := struct {
|
||||
A interface{} `json:"a"`
|
||||
}{}
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "typed missing field",
|
||||
new: func() interface{} {
|
||||
v := struct {
|
||||
B interface{} `json:"b"`
|
||||
}{}
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "typed 1 field",
|
||||
new: func() interface{} {
|
||||
v := struct {
|
||||
A interface{} `json:"a"`
|
||||
}{}
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "typed 2 field",
|
||||
new: func() interface{} {
|
||||
v := struct {
|
||||
A interface{} `json:"a"`
|
||||
B interface{} `json:"b"`
|
||||
}{}
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "typed 3 field",
|
||||
new: func() interface{} {
|
||||
v := struct {
|
||||
A interface{} `json:"a"`
|
||||
B interface{} `json:"b"`
|
||||
C interface{} `json:"c"`
|
||||
}{}
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "typed 4 field",
|
||||
new: func() interface{} {
|
||||
v := struct {
|
||||
A interface{} `json:"a"`
|
||||
B interface{} `json:"b"`
|
||||
C interface{} `json:"c"`
|
||||
D interface{} `json:"d"`
|
||||
}{}
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "typed 5 field",
|
||||
new: func() interface{} {
|
||||
v := struct {
|
||||
A interface{} `json:"a"`
|
||||
B interface{} `json:"b"`
|
||||
C interface{} `json:"c"`
|
||||
D interface{} `json:"d"`
|
||||
E interface{} `json:"e"`
|
||||
}{}
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "typed 6 field",
|
||||
new: func() interface{} {
|
||||
v := struct {
|
||||
A interface{} `json:"a"`
|
||||
B interface{} `json:"b"`
|
||||
C interface{} `json:"c"`
|
||||
D interface{} `json:"d"`
|
||||
E interface{} `json:"e"`
|
||||
F interface{} `json:"f"`
|
||||
}{}
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "typed 7 field",
|
||||
new: func() interface{} {
|
||||
v := struct {
|
||||
A interface{} `json:"a"`
|
||||
B interface{} `json:"b"`
|
||||
C interface{} `json:"c"`
|
||||
D interface{} `json:"d"`
|
||||
E interface{} `json:"e"`
|
||||
F interface{} `json:"f"`
|
||||
G interface{} `json:"g"`
|
||||
}{}
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "typed 8 field",
|
||||
new: func() interface{} {
|
||||
v := struct {
|
||||
A interface{} `json:"a"`
|
||||
B interface{} `json:"b"`
|
||||
C interface{} `json:"c"`
|
||||
D interface{} `json:"d"`
|
||||
E interface{} `json:"e"`
|
||||
F interface{} `json:"f"`
|
||||
G interface{} `json:"g"`
|
||||
H interface{} `json:"h"`
|
||||
}{}
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "typed 9 field",
|
||||
new: func() interface{} {
|
||||
v := struct {
|
||||
A interface{} `json:"a"`
|
||||
B interface{} `json:"b"`
|
||||
C interface{} `json:"c"`
|
||||
D interface{} `json:"d"`
|
||||
E interface{} `json:"e"`
|
||||
F interface{} `json:"f"`
|
||||
G interface{} `json:"g"`
|
||||
H interface{} `json:"h"`
|
||||
I interface{} `json:"i"`
|
||||
}{}
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "typed 10 field",
|
||||
new: func() interface{} {
|
||||
v := struct {
|
||||
A interface{} `json:"a"`
|
||||
B interface{} `json:"b"`
|
||||
C interface{} `json:"c"`
|
||||
D interface{} `json:"d"`
|
||||
E interface{} `json:"e"`
|
||||
F interface{} `json:"f"`
|
||||
G interface{} `json:"g"`
|
||||
H interface{} `json:"h"`
|
||||
I interface{} `json:"i"`
|
||||
J interface{} `json:"j"`
|
||||
}{}
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "typed 11 field",
|
||||
new: func() interface{} {
|
||||
v := struct {
|
||||
A interface{} `json:"a"`
|
||||
B interface{} `json:"b"`
|
||||
C interface{} `json:"c"`
|
||||
D interface{} `json:"d"`
|
||||
E interface{} `json:"e"`
|
||||
F interface{} `json:"f"`
|
||||
G interface{} `json:"g"`
|
||||
H interface{} `json:"h"`
|
||||
I interface{} `json:"i"`
|
||||
J interface{} `json:"j"`
|
||||
K interface{} `json:"k"`
|
||||
}{}
|
||||
return &v
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
for _, target := range targets {
|
||||
t.Run(target.name, func(t *testing.T) {
|
||||
err := jsoniter.Unmarshal(tc.data, target.new())
|
||||
if len(tc.expectError) == 0 {
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
} else {
|
||||
if err == nil {
|
||||
t.Errorf("expected error, got none")
|
||||
} else if !strings.Contains(err.Error(), tc.expectError) {
|
||||
t.Errorf("expected error containing '%s', got: %v", tc.expectError, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_nested(t *testing.T) {
|
||||
iter := jsoniter.ParseString(jsoniter.ConfigDefault, `{"hello": [{"world": "value1"}, {"world": "value2"}]}`)
|
||||
l1 := Level1{}
|
||||
|
||||
Reference in New Issue
Block a user