Skip to content

Commit

Permalink
Merge pull request json-iterator#418 from bbrks/configurable_maxDepth
Browse files Browse the repository at this point in the history
Add MaxDepth as a config option
  • Loading branch information
taowen authored Nov 12, 2019
2 parents 028cdb7 + 91ce9d4 commit 67614f9
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 5 deletions.
42 changes: 41 additions & 1 deletion api_tests/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package test

import (
"encoding/json"
"fmt"
"strings"
"testing"

"github.com/json-iterator/go"
jsoniter "github.com/json-iterator/go"
"github.com/stretchr/testify/require"
)

Expand All @@ -24,6 +26,44 @@ func Test_customize_float_marshal(t *testing.T) {
should.Equal("1.234568", str)
}

func Test_max_depth(t *testing.T) {
deepJSON := func(depth int) []byte {
return []byte(strings.Repeat(`[`, depth) + strings.Repeat(`]`, depth))
}

tests := []struct {
jsonDepth int
cfgMaxDepth int
expectedErr string
}{
// Test the default depth
{jsonDepth: 10000, cfgMaxDepth: 0},
{jsonDepth: 10001, cfgMaxDepth: 0, expectedErr: "max depth"},
// Test max depth logic
{jsonDepth: 5, cfgMaxDepth: 6},
{jsonDepth: 5, cfgMaxDepth: 5},
{jsonDepth: 5, cfgMaxDepth: 4, expectedErr: "max depth"},
// Try a large depth without a limit
{jsonDepth: 128000, cfgMaxDepth: -1},
}

for _, test := range tests {
t.Run(fmt.Sprintf("jsonDepth:%v_cfgMaxDepth:%v", test.jsonDepth, test.cfgMaxDepth), func(t *testing.T) {
should := require.New(t)
cfg := jsoniter.Config{MaxDepth: test.cfgMaxDepth}.Froze()

var val interface{}
err := cfg.Unmarshal(deepJSON(test.jsonDepth), &val)
if test.expectedErr != "" {
should.Error(err)
should.Contains(err.Error(), test.expectedErr)
} else {
should.NoError(err)
}
})
}
}

func Test_customize_tag_key(t *testing.T) {

type TestObject struct {
Expand Down
10 changes: 10 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import (
"github.com/modern-go/reflect2"
)

// limit maximum depth of nesting, as allowed by https://tools.ietf.org/html/rfc7159#section-9
const defaultMaxDepth = 10000

// Config customize how the API should behave.
// The API is created from Config by Froze.
type Config struct {
Expand All @@ -25,6 +28,7 @@ type Config struct {
ValidateJsonRawMessage bool
ObjectFieldMustBeSimpleString bool
CaseSensitive bool
MaxDepth int
}

// API the public interface of this package.
Expand Down Expand Up @@ -56,6 +60,7 @@ var ConfigCompatibleWithStandardLibrary = Config{
EscapeHTML: true,
SortMapKeys: true,
ValidateJsonRawMessage: true,
MaxDepth: -1, // encoding/json has no max depth (stack overflow at 2581101)
}.Froze()

// ConfigFastest marshals float with only 6 digits precision
Expand All @@ -80,6 +85,7 @@ type frozenConfig struct {
streamPool *sync.Pool
iteratorPool *sync.Pool
caseSensitive bool
maxDepth int
}

func (cfg *frozenConfig) initCache() {
Expand Down Expand Up @@ -127,13 +133,17 @@ func addFrozenConfigToCache(cfg Config, frozenConfig *frozenConfig) {

// Froze forge API from config
func (cfg Config) Froze() API {
if cfg.MaxDepth == 0 {
cfg.MaxDepth = defaultMaxDepth
}
api := &frozenConfig{
sortMapKeys: cfg.SortMapKeys,
indentionStep: cfg.IndentionStep,
objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString,
onlyTaggedField: cfg.OnlyTaggedField,
disallowUnknownFields: cfg.DisallowUnknownFields,
caseSensitive: cfg.CaseSensitive,
maxDepth: cfg.MaxDepth,
}
api.streamPool = &sync.Pool{
New: func() interface{} {
Expand Down
5 changes: 1 addition & 4 deletions iter.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,12 +327,9 @@ func (iter *Iterator) Read() interface{} {
}
}

// limit maximum depth of nesting, as allowed by https://tools.ietf.org/html/rfc7159#section-9
const maxDepth = 10000

func (iter *Iterator) incrementDepth() (success bool) {
iter.depth++
if iter.depth <= maxDepth {
if iter.depth <= iter.cfg.maxDepth || iter.cfg.maxDepth < 0 {
return true
}
iter.ReportError("incrementDepth", "exceeded max depth")
Expand Down

0 comments on commit 67614f9

Please sign in to comment.