Skip to content

Commit

Permalink
CBOR: support deep nesting constraints (#361)
Browse files Browse the repository at this point in the history
  • Loading branch information
pjfanning authored Mar 7, 2023
1 parent d938b4a commit 71fa3a8
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,7 @@ public JsonToken nextToken() throws IOException
if (!_tagValues.isEmpty()) {
return _handleTaggedArray(_tagValues, len);
}
_streamReadContext = _streamReadContext.createChildArrayContext(len);
createChildArrayContext(len);
}
return (_currToken = JsonToken.START_ARRAY);

Expand All @@ -940,7 +940,7 @@ public JsonToken nextToken() throws IOException
_currToken = JsonToken.START_OBJECT;
{
int len = _decodeExplicitLength(lowBits);
_streamReadContext = _streamReadContext.createChildObjectContext(len);
createChildObjectContext(len);
}
return _currToken;

Expand Down Expand Up @@ -1128,7 +1128,7 @@ protected JsonToken _handleTaggedArray(TagList tags, int len) throws IOException
// For simplicity, let's create matching array context -- in perfect
// world that wouldn't be necessarily, but in this one there are
// some constraints that make it necessary
_streamReadContext = _streamReadContext.createChildArrayContext(len);
createChildArrayContext(len);

// BigDecimal is the only thing we know for sure
if (!tags.contains(CBORConstants.TAG_DECIMAL_FRACTION)) {
Expand Down Expand Up @@ -1711,15 +1711,15 @@ public String nextTextValue() throws IOException
_currToken = JsonToken.START_ARRAY;
{
int len = _decodeExplicitLength(lowBits);
_streamReadContext = _streamReadContext.createChildArrayContext(len);
createChildArrayContext(len);
}
return null;

case 5: // Object
_currToken = JsonToken.START_OBJECT;
{
int len = _decodeExplicitLength(lowBits);
_streamReadContext = _streamReadContext.createChildObjectContext(len);
createChildObjectContext(len);
}
return null;

Expand Down Expand Up @@ -4060,4 +4060,14 @@ private final BigInteger _bigNegative(long l) {
BigInteger unsignedBase = _bigPositive(l);
return unsignedBase.negate().subtract(BigInteger.ONE);
}

private void createChildArrayContext(final int len) throws IOException {
_streamReadContext = _streamReadContext.createChildArrayContext(len);
streamReadConstraints().validateNestingDepth(_streamReadContext.getNestingDepth());
}

private void createChildObjectContext(final int len) throws IOException {
_streamReadContext = _streamReadContext.createChildObjectContext(len);
streamReadConstraints().validateNestingDepth(_streamReadContext.getNestingDepth());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public CBORReadContext(CBORReadContext parent, DupDetector dups,
_type = type;
_expEntryCount = expEntryCount;
_index = -1;
_nestingDepth = parent == null ? 0 : parent._nestingDepth + 1;
}

protected void reset(int type, int expEntryCount)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public abstract class CBORTestBase
protected CBORParser cborParser(ByteArrayOutputStream bytes) throws IOException {
return cborParser(bytes.toByteArray());
}
protected CBORParser cborParser(CBORFactory cborFactory, ByteArrayOutputStream bytes) throws IOException {
return cborParser(cborFactory, bytes.toByteArray());
}

protected CBORParser cborParser(byte[] input) throws IOException {
return cborParser(cborFactory(), input);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package com.fasterxml.jackson.dataformat.cbor.parse.dos;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.StreamReadConstraints;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
import com.fasterxml.jackson.dataformat.cbor.CBORTestBase;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
* Unit tests for deeply nested JSON
*/
public class DeepNestingParserTest extends CBORTestBase
{
public void testDeeplyNestedObjects() throws Exception
{
final int depth = 1500;
ByteArrayOutputStream out = new ByteArrayOutputStream();
genDeepDoc(out, depth);
try (JsonParser jp = cborParser(out)) {
JsonToken jt;
while ((jt = jp.nextToken()) != null) {

}
fail("expected StreamConstraintsException");
} catch (StreamConstraintsException e) {
assertEquals("Depth (1001) exceeds the maximum allowed nesting depth (1000)", e.getMessage());
}
}

public void testDeeplyNestedObjectsWithUnconstrainedMapper() throws Exception
{
final int depth = 1500;
ByteArrayOutputStream out = new ByteArrayOutputStream();
genDeepDoc(out, depth);
CBORFactory cborFactory = CBORFactory.builder()
.streamReadConstraints(StreamReadConstraints.builder().maxNestingDepth(Integer.MAX_VALUE).build())
.build();
try (JsonParser jp = cborParser(cborFactory, out)) {
JsonToken jt;
while ((jt = jp.nextToken()) != null) {

}
}
}

public void testDeeplyNestedArrays() throws Exception
{
final int depth = 750;
ByteArrayOutputStream out = new ByteArrayOutputStream();
genDeepArrayDoc(out, depth);
try (JsonParser jp = cborParser(out)) {
JsonToken jt;
while ((jt = jp.nextToken()) != null) {

}
fail("expected StreamConstraintsException");
} catch (StreamConstraintsException e) {
assertEquals("Depth (1001) exceeds the maximum allowed nesting depth (1000)", e.getMessage());
}
}

public void testDeeplyNestedArraysWithUnconstrainedMapper() throws Exception
{
final int depth = 750;
ByteArrayOutputStream out = new ByteArrayOutputStream();
genDeepArrayDoc(out, depth);
CBORFactory cborFactory = CBORFactory.builder()
.streamReadConstraints(StreamReadConstraints.builder().maxNestingDepth(Integer.MAX_VALUE).build())
.build();
try (JsonParser jp = cborParser(cborFactory, out)) {
JsonToken jt;
while ((jt = jp.nextToken()) != null) {

}
}
}

private void genDeepDoc(final ByteArrayOutputStream out, final int depth) throws IOException {
try (JsonGenerator gen = cborGenerator(out)) {
for (int i = 0; i < depth; i++) {
gen.writeStartObject();
gen.writeFieldName("a");
}
gen.writeString("val");
for (int i = 0; i < depth; i++) {
gen.writeEndObject();
}
}
}

private void genDeepArrayDoc(final ByteArrayOutputStream out, final int depth) throws IOException {
try (JsonGenerator gen = cborGenerator(out)) {
for (int i = 0; i < depth; i++) {
gen.writeStartObject();
gen.writeFieldName("a");
gen.writeStartArray();
}
gen.writeString("val");
for (int i = 0; i < depth; i++) {
gen.writeEndArray();
gen.writeEndObject();
}
}
}
}

0 comments on commit 71fa3a8

Please sign in to comment.