Improve nested structure depth limit check
This commit is contained in:
parent
c35151b035
commit
ce214b000d
|
@ -70,6 +70,7 @@ type
|
||||||
line*: int
|
line*: int
|
||||||
lineStartPos: int
|
lineStartPos: int
|
||||||
tokenStart: int
|
tokenStart: int
|
||||||
|
depthLimit: int
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Private helpers
|
# Private helpers
|
||||||
|
@ -110,6 +111,16 @@ template requireNextChar(lex: JsonLexer): char =
|
||||||
lex.checkForUnexpectedEof()
|
lex.checkForUnexpectedEof()
|
||||||
lex.read()
|
lex.read()
|
||||||
|
|
||||||
|
template enterNestedStructure(lex: JsonLexer, action: untyped) {.dirty.} =
|
||||||
|
inc lex.depthLimit
|
||||||
|
if lex.conf.nestedDepthLimit > 0 and
|
||||||
|
lex.depthLimit > lex.conf.nestedDepthLimit:
|
||||||
|
lex.err = errNestedDepthLimit
|
||||||
|
action
|
||||||
|
|
||||||
|
template exitNestedStructure(lex: JsonLexer) =
|
||||||
|
dec lex.depthLimit
|
||||||
|
|
||||||
proc handleLF(lex: var JsonLexer) =
|
proc handleLF(lex: var JsonLexer) =
|
||||||
lex.advance
|
lex.advance
|
||||||
lex.line += 1
|
lex.line += 1
|
||||||
|
@ -564,7 +575,7 @@ proc scanString*[T](lex: var JsonLexer, val: var T, limit: int)
|
||||||
else:
|
else:
|
||||||
appendVal c
|
appendVal c
|
||||||
|
|
||||||
proc scanValue*[T](lex: var JsonLexer, val: var T, depthLimit: int = 0)
|
proc scanValue*[T](lex: var JsonLexer, val: var T)
|
||||||
{.gcsafe, raises: [IOError].}
|
{.gcsafe, raises: [IOError].}
|
||||||
|
|
||||||
template parseObjectImpl*(lex: JsonLexer,
|
template parseObjectImpl*(lex: JsonLexer,
|
||||||
|
@ -574,6 +585,8 @@ template parseObjectImpl*(lex: JsonLexer,
|
||||||
actionKey: untyped,
|
actionKey: untyped,
|
||||||
actionValue: untyped,
|
actionValue: untyped,
|
||||||
actionError: untyped) =
|
actionError: untyped) =
|
||||||
|
|
||||||
|
lex.enterNestedStructure(actionError)
|
||||||
actionInitial
|
actionInitial
|
||||||
lex.advance
|
lex.advance
|
||||||
|
|
||||||
|
@ -635,7 +648,9 @@ template parseObjectImpl*(lex: JsonLexer,
|
||||||
else:
|
else:
|
||||||
error(lex, errStringExpected, actionError)
|
error(lex, errStringExpected, actionError)
|
||||||
|
|
||||||
proc scanObject*[T](lex: var JsonLexer, val: var T, depthLimit: int)
|
lex.exitNestedStructure()
|
||||||
|
|
||||||
|
proc scanObject*[T](lex: var JsonLexer, val: var T)
|
||||||
{.gcsafe, raises: [IOError].} =
|
{.gcsafe, raises: [IOError].} =
|
||||||
when T isnot (string or JsonVoid or JsonObjectType):
|
when T isnot (string or JsonVoid or JsonObjectType):
|
||||||
{.fatal: "`scanObject` only accepts `string` or `JsonVoid` or `JsonObjectType`".}
|
{.fatal: "`scanObject` only accepts `string` or `JsonVoid` or `JsonObjectType`".}
|
||||||
|
@ -667,12 +682,12 @@ proc scanObject*[T](lex: var JsonLexer, val: var T, depthLimit: int)
|
||||||
# value action
|
# value action
|
||||||
when T is string:
|
when T is string:
|
||||||
val.add ':'
|
val.add ':'
|
||||||
lex.scanValue(val, depthLimit)
|
lex.scanValue(val)
|
||||||
elif T is JsonVoid:
|
elif T is JsonVoid:
|
||||||
lex.scanValue(val, depthLimit)
|
lex.scanValue(val)
|
||||||
else:
|
else:
|
||||||
var newVal: valueType(T)
|
var newVal: valueType(T)
|
||||||
lex.scanValue(newVal, depthLimit)
|
lex.scanValue(newVal)
|
||||||
if newVal.isNil.not:
|
if newVal.isNil.not:
|
||||||
val[key] = newVal
|
val[key] = newVal
|
||||||
do:
|
do:
|
||||||
|
@ -687,6 +702,7 @@ template parseArrayImpl*(lex: JsonLexer,
|
||||||
actionValue: untyped,
|
actionValue: untyped,
|
||||||
actionError: untyped) =
|
actionError: untyped) =
|
||||||
|
|
||||||
|
lex.enterNestedStructure(actionError)
|
||||||
actionInitial
|
actionInitial
|
||||||
lex.advance
|
lex.advance
|
||||||
|
|
||||||
|
@ -741,7 +757,9 @@ template parseArrayImpl*(lex: JsonLexer,
|
||||||
if not lex.ok: actionError
|
if not lex.ok: actionError
|
||||||
inc numElem
|
inc numElem
|
||||||
|
|
||||||
proc scanArray*[T](lex: var JsonLexer, val: var T, depthLimit: int)
|
lex.exitNestedStructure()
|
||||||
|
|
||||||
|
proc scanArray*[T](lex: var JsonLexer, val: var T)
|
||||||
{.gcsafe, raises: [IOError].} =
|
{.gcsafe, raises: [IOError].} =
|
||||||
when T isnot (string or JsonVoid or seq[JsonValueRef]):
|
when T isnot (string or JsonVoid or seq[JsonValueRef]):
|
||||||
{.fatal: "`scanArray` only accepts `string` or `JsonVoid` or `seq[JsonValueRef]`".}
|
{.fatal: "`scanArray` only accepts `string` or `JsonVoid` or `seq[JsonValueRef]`".}
|
||||||
|
@ -761,23 +779,19 @@ proc scanArray*[T](lex: var JsonLexer, val: var T, depthLimit: int)
|
||||||
do:
|
do:
|
||||||
# value action
|
# value action
|
||||||
when T is (string or JsonVoid):
|
when T is (string or JsonVoid):
|
||||||
lex.scanValue(val, depthLimit)
|
lex.scanValue(val)
|
||||||
else:
|
else:
|
||||||
val.setLen(numElem + 1)
|
val.setLen(numElem + 1)
|
||||||
lex.scanValue(val[numElem], depthLimit)
|
lex.scanValue(val[numElem])
|
||||||
do:
|
do:
|
||||||
# error action
|
# error action
|
||||||
return
|
return
|
||||||
|
|
||||||
proc scanValue*[T](lex: var JsonLexer, val: var T, depthLimit: int)
|
proc scanValue*[T](lex: var JsonLexer, val: var T)
|
||||||
{.gcsafe, raises: [IOError].} =
|
{.gcsafe, raises: [IOError].} =
|
||||||
when T isnot (string or JsonVoid or JsonValueRef):
|
when T isnot (string or JsonVoid or JsonValueRef):
|
||||||
{.fatal: "`scanValue` only accepts `string` or `JsonVoid` or `JsonValueRef`".}
|
{.fatal: "`scanValue` only accepts `string` or `JsonVoid` or `JsonValueRef`".}
|
||||||
|
|
||||||
if lex.conf.nestedDepthLimit > 0 and
|
|
||||||
depthLimit > lex.conf.nestedDepthLimit:
|
|
||||||
error errNestedDepthLimit
|
|
||||||
|
|
||||||
var c = lex.nonws()
|
var c = lex.nonws()
|
||||||
if not lex.ok: return
|
if not lex.ok: return
|
||||||
|
|
||||||
|
@ -803,16 +817,16 @@ proc scanValue*[T](lex: var JsonLexer, val: var T, depthLimit: int)
|
||||||
of '{':
|
of '{':
|
||||||
when T is JsonValueRef:
|
when T is JsonValueRef:
|
||||||
val = T(kind: JsonValueKind.Object)
|
val = T(kind: JsonValueKind.Object)
|
||||||
lex.scanObject(val.objVal, depthLimit+1)
|
lex.scanObject(val.objVal)
|
||||||
else:
|
else:
|
||||||
lex.scanObject(val, depthLimit+1)
|
lex.scanObject(val)
|
||||||
if not lex.ok: return
|
if not lex.ok: return
|
||||||
of '[':
|
of '[':
|
||||||
when T is JsonValueRef:
|
when T is JsonValueRef:
|
||||||
val = T(kind: JsonValueKind.Array)
|
val = T(kind: JsonValueKind.Array)
|
||||||
lex.scanArray(val.arrayVal, depthLimit+1)
|
lex.scanArray(val.arrayVal)
|
||||||
else:
|
else:
|
||||||
lex.scanArray(val, depthLimit+1)
|
lex.scanArray(val)
|
||||||
if not lex.ok: return
|
if not lex.ok: return
|
||||||
of 't', 'f':
|
of 't', 'f':
|
||||||
when T is JsonVoid:
|
when T is JsonVoid:
|
||||||
|
|
|
@ -115,7 +115,7 @@ template testScanValue(input: string, output: untyped,
|
||||||
value == output
|
value == output
|
||||||
lex.err == error
|
lex.err == error
|
||||||
|
|
||||||
suite "numbers test suite":
|
suite "lexer test suite":
|
||||||
test "scanInt string":
|
test "scanInt string":
|
||||||
testScanInt("1234567890", "1234567890")
|
testScanInt("1234567890", "1234567890")
|
||||||
testScanInt("01234567890", "0", error = errLeadingZero)
|
testScanInt("01234567890", "0", error = errLeadingZero)
|
||||||
|
@ -587,8 +587,8 @@ suite "numbers test suite":
|
||||||
testScanValue("[[[1]]]", "[[[1]]]")
|
testScanValue("[[[1]]]", "[[[1]]]")
|
||||||
|
|
||||||
conf.nestedDepthLimit = 3
|
conf.nestedDepthLimit = 3
|
||||||
testScanValue("[[[[1]]]]", "[[[[", error = errNestedDepthLimit, conf = conf)
|
testScanValue("[[[[1]]]]", "[[[", error = errNestedDepthLimit, conf = conf)
|
||||||
testScanValue("[ { \"a\": [ { \"b\": 3}] } ]", "[{\"a\":[{\"b\":",
|
testScanValue("[ { \"a\": [ { \"b\": 3}] } ]", "[{\"a\":[",
|
||||||
error = errNestedDepthLimit, conf = conf)
|
error = errNestedDepthLimit, conf = conf)
|
||||||
|
|
||||||
testScanValue("{ \"a\": 1234.567 // comments\n }",
|
testScanValue("{ \"a\": 1234.567 // comments\n }",
|
||||||
|
@ -781,9 +781,7 @@ suite "numbers test suite":
|
||||||
arrayVal: @[
|
arrayVal: @[
|
||||||
JsonValueRef[uint64](kind: JsonValueKind.Array,
|
JsonValueRef[uint64](kind: JsonValueKind.Array,
|
||||||
arrayVal: @[
|
arrayVal: @[
|
||||||
JsonValueRef[uint64](kind: JsonValueKind.Array, arrayVal: @[
|
JsonValueRef[uint64](kind: JsonValueKind.Array)
|
||||||
JsonValueRef[uint64](nil)
|
|
||||||
])
|
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
]), error = errNestedDepthLimit, conf = conf)
|
]), error = errNestedDepthLimit, conf = conf)
|
||||||
|
|
Loading…
Reference in New Issue