Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/main/java/tools/jackson/core/JsonGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,19 @@ protected JsonGenerator() { }
@Override
public abstract Version version();

/*
/**********************************************************************
/* Constraints violation checking
/**********************************************************************
*/

/**
* Get the constraints to apply when performing streaming writes.
*/
public StreamWriteConstraints streamWriteConstraints() {
return StreamWriteConstraints.defaults();
}

/*
/**********************************************************************
/* Public API, output configuration, state access
Expand Down
157 changes: 157 additions & 0 deletions src/main/java/tools/jackson/core/StreamWriteConstraints.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package tools.jackson.core;

import tools.jackson.core.exc.StreamConstraintsException;

/**
* The constraints to use for streaming writes: used to guard against problematic
* output by preventing processing of "too big" output constructs (values,
* structures).
* Constraints are registered with {@code TokenStreamFactory} (such as
* {@code JsonFactory}); if nothing explicitly specified, default
* constraints are used.
*<p>
* Currently constrained aspects, with default settings, are:
* <ul>
* <li>Maximum Nesting depth: default 1000 (see {@link #DEFAULT_MAX_DEPTH})
* </li>
* </ul>
*
* @since 2.16
*/
public class StreamWriteConstraints
implements java.io.Serializable
{
private static final long serialVersionUID = 1L;

/**
* Default setting for maximum depth: see {@link Builder#maxNestingDepth(int)} for details.
*/
public static final int DEFAULT_MAX_DEPTH = 1000;

protected final int _maxNestingDepth;

private static final StreamWriteConstraints DEFAULT =
new StreamWriteConstraints(DEFAULT_MAX_DEPTH);

public static final class Builder {
private int maxNestingDepth;

/**
* Sets the maximum nesting depth. The depth is a count of objects and arrays that have not
* been closed, `{` and `[` respectively.
*
* @param maxNestingDepth the maximum depth
*
* @return this builder
* @throws IllegalArgumentException if the maxNestingDepth is set to a negative value
*/
public Builder maxNestingDepth(final int maxNestingDepth) {
if (maxNestingDepth < 0) {
throw new IllegalArgumentException("Cannot set maxNestingDepth to a negative value");
}
this.maxNestingDepth = maxNestingDepth;
return this;
}

Builder() {
this(DEFAULT_MAX_DEPTH);
}

Builder(final int maxNestingDepth) {
this.maxNestingDepth = maxNestingDepth;
}

Builder(StreamWriteConstraints src) {
maxNestingDepth = src._maxNestingDepth;
}

public StreamWriteConstraints build() {
return new StreamWriteConstraints(maxNestingDepth);
}
}

/*
/**********************************************************************
/* Life-cycle
/**********************************************************************
*/

protected StreamWriteConstraints(final int maxNestingDepth) {
_maxNestingDepth = maxNestingDepth;
}

public static Builder builder() {
return new Builder();
}

public static StreamWriteConstraints defaults() {
return DEFAULT;
}

/**
* @return New {@link Builder} initialized with settings of this constraints
* instance
*/
public Builder rebuild() {
return new Builder(this);
}

/*
/**********************************************************************
/* Accessors
/**********************************************************************
*/

/**
* Accessor for maximum depth.
* see {@link Builder#maxNestingDepth(int)} for details.
*
* @return Maximum allowed depth
*/
public int getMaxNestingDepth() {
return _maxNestingDepth;
}

/*
/**********************************************************************
/* Convenience methods for validation, document limits
/**********************************************************************
*/

/**
* Convenience method that can be used to verify that the
* nesting depth does not exceed the maximum specified by this
* constraints object: if it does, a
* {@link StreamConstraintsException}
* is thrown.
*
* @param depth count of unclosed objects and arrays
*
* @throws StreamConstraintsException If depth exceeds maximum
*/
public void validateNestingDepth(int depth) throws StreamConstraintsException
{
if (depth > _maxNestingDepth) {
throw _constructException(
"Document nesting depth (%d) exceeds the maximum allowed (%d, from %s)",
depth, _maxNestingDepth,
_constrainRef("getMaxNestingDepth"));
}
}

/*
/**********************************************************************
/* Error reporting
/**********************************************************************
*/

// @since 2.16
protected StreamConstraintsException _constructException(String msgTemplate, Object... args) throws StreamConstraintsException {
throw new StreamConstraintsException(String.format(msgTemplate, args));
}

// @since 2.16
protected String _constrainRef(String method) {
return "`StreamWriteConstraints."+method+"()`";
}
}
7 changes: 7 additions & 0 deletions src/main/java/tools/jackson/core/TSFBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,18 @@ public abstract class TSFBuilder<F extends TokenStreamFactory,
*/
protected StreamReadConstraints _streamReadConstraints;

/**
* StreamWriteConstraints to use.
*/
protected StreamWriteConstraints _streamWriteConstraints;

// // // Construction

protected TSFBuilder(StreamReadConstraints src,
StreamWriteConstraints swc,
int formatReadF, int formatWriteF) {
_streamReadConstraints = src;
_streamWriteConstraints = swc;
_factoryFeatures = TokenStreamFactory.DEFAULT_FACTORY_FEATURE_FLAGS;
_streamReadFeatures = TokenStreamFactory.DEFAULT_STREAM_READ_FEATURE_FLAGS;
_streamWriteFeatures = TokenStreamFactory.DEFAULT_STREAM_WRITE_FEATURE_FLAGS;
Expand Down
17 changes: 15 additions & 2 deletions src/main/java/tools/jackson/core/TokenStreamFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ public static int collectDefaults() {
*/
protected final StreamReadConstraints _streamReadConstraints;

/**
* Active StreamWriteConstraints to use.
*/
protected final StreamWriteConstraints _streamWriteConstraints;

/*
/**********************************************************************
/* Construction
Expand All @@ -248,8 +253,10 @@ public static int collectDefaults() {
* @param formatWriteFeatures Bitmask of format-specific write features enabled
*/
protected TokenStreamFactory(StreamReadConstraints src,
StreamWriteConstraints swc,
int formatReadFeatures, int formatWriteFeatures) {
_streamReadConstraints = src;
_streamWriteConstraints = swc;
_factoryFeatures = DEFAULT_FACTORY_FEATURE_FLAGS;
_streamReadFeatures = DEFAULT_STREAM_READ_FEATURE_FLAGS;
_streamWriteFeatures = DEFAULT_STREAM_WRITE_FEATURE_FLAGS;
Expand All @@ -271,6 +278,7 @@ protected TokenStreamFactory(StreamReadConstraints src,
protected TokenStreamFactory(TSFBuilder<?,?> baseBuilder)
{
_streamReadConstraints = baseBuilder._streamReadConstraints;
_streamWriteConstraints = baseBuilder._streamWriteConstraints;
_factoryFeatures = baseBuilder.factoryFeaturesMask();
_streamReadFeatures = baseBuilder.streamReadFeaturesMask();
_streamWriteFeatures = baseBuilder.streamWriteFeaturesMask();
Expand All @@ -287,6 +295,7 @@ protected TokenStreamFactory(TSFBuilder<?,?> baseBuilder)
protected TokenStreamFactory(TokenStreamFactory src)
{
_streamReadConstraints = src._streamReadConstraints;
_streamWriteConstraints = src._streamWriteConstraints;
_factoryFeatures = src._factoryFeatures;
_streamReadFeatures = src._streamReadFeatures;
_streamWriteFeatures = src._streamWriteFeatures;
Expand Down Expand Up @@ -495,6 +504,8 @@ public final int getStreamWriteFeatures() {

public StreamReadConstraints streamReadConstraints() { return _streamReadConstraints; }

public StreamWriteConstraints streamWriteConstraints() { return _streamWriteConstraints; }

/*
/**********************************************************************
/* Factory methods for helper objects
Expand Down Expand Up @@ -1200,7 +1211,8 @@ public BufferRecycler _getBufferRecycler()
* @return Context constructed
*/
protected IOContext _createContext(ContentReference contentRef, boolean resourceManaged) {
return new IOContext(_streamReadConstraints, _getBufferRecycler(), contentRef,
return new IOContext(_streamReadConstraints, _streamWriteConstraints,
_getBufferRecycler(), contentRef,
resourceManaged, null);
}

Expand All @@ -1216,7 +1228,8 @@ protected IOContext _createContext(ContentReference contentRef, boolean resource
*/
protected IOContext _createContext(ContentReference contentRef, boolean resourceManaged,
JsonEncoding enc) {
return new IOContext(_streamReadConstraints, _getBufferRecycler(), contentRef,
return new IOContext(_streamReadConstraints, _streamWriteConstraints,
_getBufferRecycler(), contentRef,
resourceManaged, enc);
}

Expand Down
3 changes: 2 additions & 1 deletion src/main/java/tools/jackson/core/base/BinaryTSFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ public abstract class BinaryTSFactory
*/

protected BinaryTSFactory(StreamReadConstraints src,
StreamWriteConstraints swc,
int formatPF, int formatGF) {
super(src, formatPF, formatGF);
super(src, swc, formatPF, formatGF);
}

/**
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/tools/jackson/core/base/DecorableTSFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ public abstract static class DecorableTSFBuilder<F extends TokenStreamFactory,
// // // Construction

protected DecorableTSFBuilder(StreamReadConstraints src,
StreamWriteConstraints swc,
int formatPF, int formatGF) {
super(src, formatPF, formatGF);
super(src, swc, formatPF, formatGF);
_inputDecorator = null;
_outputDecorator = null;
}
Expand Down Expand Up @@ -101,8 +102,9 @@ public T outputDecorator(OutputDecorator dec) {
*/

protected DecorableTSFactory(StreamReadConstraints src,
StreamWriteConstraints swc,
int formatPF, int formatGF) {
super(src, formatPF, formatGF);
super(src, swc, formatPF, formatGF);
_inputDecorator = null;
_outputDecorator = null;
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/tools/jackson/core/base/TextualTSFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ public abstract class TextualTSFactory
*/

protected TextualTSFactory(StreamReadConstraints src,
StreamWriteConstraints swc,
int formatPF, int formatGF) {
super(src, formatPF, formatGF);
super(src, swc, formatPF, formatGF);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ protected TokenFilterContext(int type, TokenFilterContext parent,
super();
_type = type;
_parent = parent;
_nestingDepth = parent == null ? 0 : parent._nestingDepth + 1;
_filter = filter;
_index = -1;
_currentValue = currValue;
Expand Down
21 changes: 18 additions & 3 deletions src/main/java/tools/jackson/core/io/IOContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import tools.jackson.core.JsonEncoding;
import tools.jackson.core.StreamReadConstraints;
import tools.jackson.core.StreamWriteConstraints;
import tools.jackson.core.util.BufferRecycler;
import tools.jackson.core.util.TextBuffer;
import tools.jackson.core.util.ReadConstrainedTextBuffer;
Expand Down Expand Up @@ -54,6 +55,8 @@ public class IOContext

protected final StreamReadConstraints _streamReadConstraints;

protected final StreamWriteConstraints _streamWriteConstraints;

/**
* Reference to the allocated I/O buffer for low-level input reading,
* if any allocated.
Expand Down Expand Up @@ -104,16 +107,21 @@ public class IOContext
* Main constructor to use.
*
* @param streamReadConstraints constraints for streaming reads
* @param streamWriteConstraints constraints for streaming writes
* @param br BufferRecycler to use, if any ({@code null} if none)
* @param contentRef Input source reference for location reporting
* @param managedResource Whether input source is managed (owned) by Jackson library
* @param enc Encoding in use
*/
public IOContext(StreamReadConstraints streamReadConstraints, BufferRecycler br,
ContentReference contentRef, boolean managedResource,
public IOContext(StreamReadConstraints streamReadConstraints,
StreamWriteConstraints streamWriteConstraints,
BufferRecycler br, ContentReference contentRef, boolean managedResource,
JsonEncoding enc)
{
_streamReadConstraints = streamReadConstraints;
_streamReadConstraints = streamReadConstraints == null ?
StreamReadConstraints.defaults() : streamReadConstraints;
_streamWriteConstraints = streamWriteConstraints == null ?
StreamWriteConstraints.defaults() : streamWriteConstraints;;
_bufferRecycler = br;
_contentReference = contentRef;
_managedResource = managedResource;
Expand All @@ -127,6 +135,13 @@ public StreamReadConstraints streamReadConstraints() {
return _streamReadConstraints;
}

/**
* @return constraints for streaming writes
*/
public StreamWriteConstraints streamWriteConstraints() {
return _streamWriteConstraints;
}

public IOContext setEncoding(JsonEncoding enc) {
_encoding = enc;
return this;
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/tools/jackson/core/json/JsonFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public class JsonFactory
* factory instance.
*/
public JsonFactory() {
super(StreamReadConstraints.defaults(),
super(StreamReadConstraints.defaults(), StreamWriteConstraints.defaults(),
DEFAULT_JSON_PARSER_FEATURE_FLAGS, DEFAULT_JSON_GENERATOR_FEATURE_FLAGS);
_rootValueSeparator = DEFAULT_ROOT_VALUE_SEPARATOR;
_characterEscapes = null;
Expand Down Expand Up @@ -351,7 +351,7 @@ public JsonParser createNonBlockingByteBufferParser(ObjectReadContext readCtxt)
}

protected IOContext _createNonBlockingContext(Object srcRef) {
return new IOContext(_streamReadConstraints, _getBufferRecycler(),
return new IOContext(_streamReadConstraints, _streamWriteConstraints, _getBufferRecycler(),
ContentReference.rawReference(srcRef), false, JsonEncoding.UTF8);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class JsonFactoryBuilder extends DecorableTSFBuilder<JsonFactory, JsonFac

public JsonFactoryBuilder() {
super(StreamReadConstraints.defaults(),
StreamWriteConstraints.defaults(),
JsonFactory.DEFAULT_JSON_PARSER_FEATURE_FLAGS,
JsonFactory.DEFAULT_JSON_GENERATOR_FEATURE_FLAGS);
_rootValueSeparator = JsonFactory.DEFAULT_ROOT_VALUE_SEPARATOR;
Expand Down
Loading