Skip to content

Commit c7e1ec9

Browse files
authored
support deep nesting check - smile format (#362)
1 parent 71fa3a8 commit c7e1ec9

File tree

2 files changed

+122
-2
lines changed

2 files changed

+122
-2
lines changed

smile/src/main/java/com/fasterxml/jackson/dataformat/smile/SmileParser.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ public JsonToken nextToken() throws IOException
529529
}
530530
return _handleSharedString(((ch & 0x3) << 8) + (_inputBuffer[_inputPtr++] & 0xFF));
531531
case 0x18: // START_ARRAY
532-
_streamReadContext = _streamReadContext.createChildArrayContext(-1, -1);
532+
createChildArrayContext(-1, -1);
533533
return (_currToken = JsonToken.START_ARRAY);
534534
case 0x19: // END_ARRAY
535535
if (!_streamReadContext.inArray()) {
@@ -538,7 +538,7 @@ public JsonToken nextToken() throws IOException
538538
_streamReadContext = _streamReadContext.getParent();
539539
return (_currToken = JsonToken.END_ARRAY);
540540
case 0x1A: // START_OBJECT
541-
_streamReadContext = _streamReadContext.createChildObjectContext(-1, -1);
541+
createChildObjectContext(-1, -1);
542542
return (_currToken = JsonToken.START_OBJECT);
543543
case 0x1B: // not used in this mode; would be END_OBJECT
544544
_reportError("Invalid type marker byte 0xFB in value mode (would be END_OBJECT in key mode)");
@@ -3116,5 +3116,15 @@ private final JsonToken _eofAsNextToken() throws IOException {
31163116
close();
31173117
return (_currToken = null);
31183118
}
3119+
3120+
private void createChildArrayContext(final int lineNr, final int colNr) throws IOException {
3121+
_streamReadContext = _streamReadContext.createChildArrayContext(lineNr, colNr);
3122+
streamReadConstraints().validateNestingDepth(_streamReadContext.getNestingDepth());
3123+
}
3124+
3125+
private void createChildObjectContext(final int lineNr, final int colNr) throws IOException {
3126+
_streamReadContext = _streamReadContext.createChildObjectContext(lineNr, colNr);
3127+
streamReadConstraints().validateNestingDepth(_streamReadContext.getNestingDepth());
3128+
}
31193129
}
31203130

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package com.fasterxml.jackson.dataformat.smile.parse.dos;
2+
3+
import com.fasterxml.jackson.core.JsonGenerator;
4+
import com.fasterxml.jackson.core.JsonParser;
5+
import com.fasterxml.jackson.core.JsonToken;
6+
import com.fasterxml.jackson.core.StreamReadConstraints;
7+
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
8+
import com.fasterxml.jackson.dataformat.smile.BaseTestForSmile;
9+
import com.fasterxml.jackson.dataformat.smile.SmileFactory;
10+
11+
import java.io.ByteArrayOutputStream;
12+
import java.io.IOException;
13+
14+
/**
15+
* Unit tests for deeply nested JSON
16+
*/
17+
public class DeepNestingParserTest extends BaseTestForSmile
18+
{
19+
public void testDeeplyNestedObjects() throws Exception
20+
{
21+
final int depth = 1500;
22+
ByteArrayOutputStream out = new ByteArrayOutputStream();
23+
genDeepDoc(out, depth);
24+
try (JsonParser jp = _smileParser(out.toByteArray())) {
25+
JsonToken jt;
26+
while ((jt = jp.nextToken()) != null) {
27+
28+
}
29+
fail("expected StreamConstraintsException");
30+
} catch (StreamConstraintsException e) {
31+
assertEquals("Depth (1001) exceeds the maximum allowed nesting depth (1000)", e.getMessage());
32+
}
33+
}
34+
35+
public void testDeeplyNestedObjectsWithUnconstrainedMapper() throws Exception
36+
{
37+
final int depth = 1500;
38+
ByteArrayOutputStream out = new ByteArrayOutputStream();
39+
genDeepDoc(out, depth);
40+
SmileFactory smileFactory = SmileFactory.builder()
41+
.streamReadConstraints(StreamReadConstraints.builder().maxNestingDepth(Integer.MAX_VALUE).build())
42+
.build();
43+
try (JsonParser jp = _smileParser(smileFactory, out.toByteArray())) {
44+
JsonToken jt;
45+
while ((jt = jp.nextToken()) != null) {
46+
47+
}
48+
}
49+
}
50+
51+
public void testDeeplyNestedArrays() throws Exception
52+
{
53+
final int depth = 750;
54+
ByteArrayOutputStream out = new ByteArrayOutputStream();
55+
genDeepArrayDoc(out, depth);
56+
try (JsonParser jp = _smileParser(out.toByteArray())) {
57+
JsonToken jt;
58+
while ((jt = jp.nextToken()) != null) {
59+
60+
}
61+
fail("expected StreamConstraintsException");
62+
} catch (StreamConstraintsException e) {
63+
assertEquals("Depth (1001) exceeds the maximum allowed nesting depth (1000)", e.getMessage());
64+
}
65+
}
66+
67+
public void testDeeplyNestedArraysWithUnconstrainedMapper() throws Exception
68+
{
69+
final int depth = 750;
70+
ByteArrayOutputStream out = new ByteArrayOutputStream();
71+
genDeepArrayDoc(out, depth);
72+
SmileFactory smileFactory = SmileFactory.builder()
73+
.streamReadConstraints(StreamReadConstraints.builder().maxNestingDepth(Integer.MAX_VALUE).build())
74+
.build();
75+
try (JsonParser jp = _smileParser(smileFactory, out.toByteArray())) {
76+
JsonToken jt;
77+
while ((jt = jp.nextToken()) != null) {
78+
79+
}
80+
}
81+
}
82+
83+
private void genDeepDoc(final ByteArrayOutputStream out, final int depth) throws IOException {
84+
try (JsonGenerator gen = smileGenerator(out, true)) {
85+
for (int i = 0; i < depth; i++) {
86+
gen.writeStartObject();
87+
gen.writeFieldName("a");
88+
}
89+
gen.writeString("val");
90+
for (int i = 0; i < depth; i++) {
91+
gen.writeEndObject();
92+
}
93+
}
94+
}
95+
96+
private void genDeepArrayDoc(final ByteArrayOutputStream out, final int depth) throws IOException {
97+
try (JsonGenerator gen = smileGenerator(out, true)) {
98+
for (int i = 0; i < depth; i++) {
99+
gen.writeStartObject();
100+
gen.writeFieldName("a");
101+
gen.writeStartArray();
102+
}
103+
gen.writeString("val");
104+
for (int i = 0; i < depth; i++) {
105+
gen.writeEndArray();
106+
gen.writeEndObject();
107+
}
108+
}
109+
}
110+
}

0 commit comments

Comments
 (0)