Skip to content

Commit 04e6edf

Browse files
committed
add StreamWriteConstraints
Update TokenFilterContext.java make stream write constraints accessible Update FilteringGeneratorDelegate.java police nesting depth in json generators Update JsonGeneratorImpl.java add test that should fail fix test test issue more tests revert changes in FilteringGeneratorDelegate Update FilteringGeneratorDelegate.java
1 parent 09e4f6a commit 04e6edf

14 files changed

+407
-7
lines changed

src/main/java/com/fasterxml/jackson/core/JsonFactory.java

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,14 @@ public static int collectDefaults() {
279279
*/
280280
protected StreamReadConstraints _streamReadConstraints;
281281

282+
/**
283+
* Write constraints to use for {@link JsonGenerator}s constructed using
284+
* this factory.
285+
*
286+
* @since 2.16
287+
*/
288+
protected StreamWriteConstraints _streamWriteConstraints;
289+
282290
/**
283291
* Optional helper object that may decorate input sources, to do
284292
* additional processing on input during parsing.
@@ -339,6 +347,7 @@ public JsonFactory(ObjectCodec oc) {
339347
_objectCodec = oc;
340348
_quoteChar = DEFAULT_QUOTE_CHAR;
341349
_streamReadConstraints = StreamReadConstraints.defaults();
350+
_streamWriteConstraints = StreamWriteConstraints.defaults();
342351
}
343352

344353
/**
@@ -361,6 +370,8 @@ protected JsonFactory(JsonFactory src, ObjectCodec codec)
361370
_outputDecorator = src._outputDecorator;
362371
_streamReadConstraints = src._streamReadConstraints == null ?
363372
StreamReadConstraints.defaults() : src._streamReadConstraints;
373+
_streamWriteConstraints = src._streamWriteConstraints == null ?
374+
StreamWriteConstraints.defaults() : src._streamWriteConstraints;
364375

365376
// JSON-specific
366377
_characterEscapes = src._characterEscapes;
@@ -387,6 +398,8 @@ public JsonFactory(JsonFactoryBuilder b) {
387398
_outputDecorator = b._outputDecorator;
388399
_streamReadConstraints = b._streamReadConstraints == null ?
389400
StreamReadConstraints.defaults() : b._streamReadConstraints;
401+
_streamWriteConstraints = b._streamWriteConstraints == null ?
402+
StreamWriteConstraints.defaults() : b._streamWriteConstraints;
390403

391404
// JSON-specific
392405
_characterEscapes = b._characterEscapes;
@@ -413,6 +426,8 @@ protected JsonFactory(TSFBuilder<?,?> b, boolean bogus) {
413426
_outputDecorator = b._outputDecorator;
414427
_streamReadConstraints = b._streamReadConstraints == null ?
415428
StreamReadConstraints.defaults() : b._streamReadConstraints;
429+
_streamWriteConstraints = b._streamWriteConstraints == null ?
430+
StreamWriteConstraints.defaults() : b._streamWriteConstraints;
416431

417432
// JSON-specific: need to assign even if not really used
418433
_characterEscapes = null;
@@ -779,6 +794,11 @@ public StreamReadConstraints streamReadConstraints() {
779794
return _streamReadConstraints;
780795
}
781796

797+
@Override
798+
public StreamWriteConstraints streamWriteConstraints() {
799+
return _streamWriteConstraints;
800+
}
801+
782802
/**
783803
* Method for overriding {@link StreamReadConstraints} defined for
784804
* this factory.
@@ -799,6 +819,26 @@ public JsonFactory setStreamReadConstraints(StreamReadConstraints src) {
799819
return this;
800820
}
801821

822+
/**
823+
* Method for overriding {@link StreamWriteConstraints} defined for
824+
* this factory.
825+
*<p>
826+
* NOTE: the preferred way to set constraints is by using
827+
* {@link JsonFactoryBuilder#streamWriteConstraints}: this method is only
828+
* provided to support older non-builder-based construction.
829+
* In Jackson 3.x this method will not be available.
830+
*
831+
* @param swc Constraints
832+
*
833+
* @return This factory instance (to allow call chaining)
834+
*
835+
* @since 2.16
836+
*/
837+
public JsonFactory setStreamWriteConstraints(StreamWriteConstraints swc) {
838+
_streamWriteConstraints = Objects.requireNonNull(swc);
839+
return this;
840+
}
841+
802842
/*
803843
/**********************************************************
804844
/* Configuration, parser configuration
@@ -2034,7 +2074,8 @@ protected IOContext _createContext(ContentReference contentRef, boolean resource
20342074
if (contentRef == null) {
20352075
contentRef = ContentReference.unknown();
20362076
}
2037-
return new IOContext(_streamReadConstraints, _getBufferRecycler(), contentRef, resourceManaged);
2077+
return new IOContext(_streamReadConstraints, _streamWriteConstraints,
2078+
_getBufferRecycler(), contentRef, resourceManaged);
20382079
}
20392080

20402081
/**
@@ -2049,7 +2090,8 @@ protected IOContext _createContext(ContentReference contentRef, boolean resource
20492090
*/
20502091
@Deprecated // @since 2.13
20512092
protected IOContext _createContext(Object rawContentRef, boolean resourceManaged) {
2052-
return new IOContext(_streamReadConstraints, _getBufferRecycler(),
2093+
return new IOContext(_streamReadConstraints, _streamWriteConstraints,
2094+
_getBufferRecycler(),
20532095
_createContentReference(rawContentRef),
20542096
resourceManaged);
20552097
}
@@ -2067,7 +2109,8 @@ protected IOContext _createContext(Object rawContentRef, boolean resourceManaged
20672109
protected IOContext _createNonBlockingContext(Object srcRef) {
20682110
// [jackson-core#479]: allow recycling for non-blocking parser again
20692111
// now that access is thread-safe
2070-
return new IOContext(_streamReadConstraints, _getBufferRecycler(),
2112+
return new IOContext(_streamReadConstraints, _streamWriteConstraints,
2113+
_getBufferRecycler(),
20712114
_createContentReference(srcRef),
20722115
false);
20732116
}

src/main/java/com/fasterxml/jackson/core/JsonGenerator.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,15 @@ protected JsonGenerator() { }
341341
*/
342342
public abstract ObjectCodec getCodec();
343343

344+
/**
345+
* Get the constraints to apply when performing streaming writes.
346+
*
347+
* @since 2.16
348+
*/
349+
public StreamWriteConstraints streamWriteConstraints() {
350+
return StreamWriteConstraints.defaults();
351+
}
352+
344353
/**
345354
* Accessor for finding out version of the bundle that provided this generator instance.
346355
*
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
package com.fasterxml.jackson.core;
2+
3+
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
4+
5+
/**
6+
* The constraints to use for streaming writes: used to guard against problematic
7+
* output by preventing processing of "too big" output constructs (values,
8+
* structures).
9+
* Constraints are registered with {@code TokenStreamFactory} (such as
10+
* {@code JsonFactory}); if nothing explicitly specified, default
11+
* constraints are used.
12+
*<p>
13+
* Currently constrained aspects, with default settings, are:
14+
* <ul>
15+
* <li>Maximum Nesting depth: default 1000 (see {@link #DEFAULT_MAX_DEPTH})
16+
* </li>
17+
* </ul>
18+
*
19+
* @since 2.16
20+
*/
21+
public class StreamWriteConstraints
22+
implements java.io.Serializable
23+
{
24+
private static final long serialVersionUID = 1L;
25+
26+
/**
27+
* Default setting for maximum depth: see {@link Builder#maxNestingDepth(int)} for details.
28+
*/
29+
public static final int DEFAULT_MAX_DEPTH = 1000;
30+
31+
protected final int _maxNestingDepth;
32+
33+
private static final StreamWriteConstraints DEFAULT =
34+
new StreamWriteConstraints(DEFAULT_MAX_DEPTH);
35+
36+
public static final class Builder {
37+
private int maxNestingDepth;
38+
39+
/**
40+
* Sets the maximum nesting depth. The depth is a count of objects and arrays that have not
41+
* been closed, `{` and `[` respectively.
42+
*
43+
* @param maxNestingDepth the maximum depth
44+
*
45+
* @return this builder
46+
* @throws IllegalArgumentException if the maxNestingDepth is set to a negative value
47+
*/
48+
public Builder maxNestingDepth(final int maxNestingDepth) {
49+
if (maxNestingDepth < 0) {
50+
throw new IllegalArgumentException("Cannot set maxNestingDepth to a negative value");
51+
}
52+
this.maxNestingDepth = maxNestingDepth;
53+
return this;
54+
}
55+
56+
Builder() {
57+
this(DEFAULT_MAX_DEPTH);
58+
}
59+
60+
Builder(final int maxNestingDepth) {
61+
this.maxNestingDepth = maxNestingDepth;
62+
}
63+
64+
Builder(StreamWriteConstraints src) {
65+
maxNestingDepth = src._maxNestingDepth;
66+
}
67+
68+
public StreamWriteConstraints build() {
69+
return new StreamWriteConstraints(maxNestingDepth);
70+
}
71+
}
72+
73+
/*
74+
/**********************************************************************
75+
/* Life-cycle
76+
/**********************************************************************
77+
*/
78+
79+
protected StreamWriteConstraints(final int maxNestingDepth) {
80+
_maxNestingDepth = maxNestingDepth;
81+
}
82+
83+
public static Builder builder() {
84+
return new Builder();
85+
}
86+
87+
public static StreamWriteConstraints defaults() {
88+
return DEFAULT;
89+
}
90+
91+
/**
92+
* @return New {@link Builder} initialized with settings of this constraints
93+
* instance
94+
*/
95+
public Builder rebuild() {
96+
return new Builder(this);
97+
}
98+
99+
/*
100+
/**********************************************************************
101+
/* Accessors
102+
/**********************************************************************
103+
*/
104+
105+
/**
106+
* Accessor for maximum depth.
107+
* see {@link Builder#maxNestingDepth(int)} for details.
108+
*
109+
* @return Maximum allowed depth
110+
*/
111+
public int getMaxNestingDepth() {
112+
return _maxNestingDepth;
113+
}
114+
115+
/*
116+
/**********************************************************************
117+
/* Convenience methods for validation, document limits
118+
/**********************************************************************
119+
*/
120+
121+
/**
122+
* Convenience method that can be used to verify that the
123+
* nesting depth does not exceed the maximum specified by this
124+
* constraints object: if it does, a
125+
* {@link StreamConstraintsException}
126+
* is thrown.
127+
*
128+
* @param depth count of unclosed objects and arrays
129+
*
130+
* @throws StreamConstraintsException If depth exceeds maximum
131+
*/
132+
public void validateNestingDepth(int depth) throws StreamConstraintsException
133+
{
134+
if (depth > _maxNestingDepth) {
135+
throw _constructException(
136+
"Document nesting depth (%d) exceeds the maximum allowed (%d, from %s)",
137+
depth, _maxNestingDepth,
138+
_constrainRef("getMaxNestingDepth"));
139+
}
140+
}
141+
142+
/*
143+
/**********************************************************************
144+
/* Error reporting
145+
/**********************************************************************
146+
*/
147+
148+
// @since 2.16
149+
protected StreamConstraintsException _constructException(String msgTemplate, Object... args) throws StreamConstraintsException {
150+
throw new StreamConstraintsException(String.format(msgTemplate, args));
151+
}
152+
153+
// @since 2.16
154+
protected String _constrainRef(String method) {
155+
return "`StreamWriteConstraints."+method+"()`";
156+
}
157+
}

src/main/java/com/fasterxml/jackson/core/TSFBuilder.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,19 @@ public abstract class TSFBuilder<F extends JsonFactory,
7878
protected OutputDecorator _outputDecorator;
7979

8080
/**
81-
* Optional StreamReadConfig.
81+
* Optional StreamReadConstraints.
8282
*
8383
* @since 2.15
8484
*/
8585
protected StreamReadConstraints _streamReadConstraints;
8686

87+
/**
88+
* Optional StreamWriteConstraints.
89+
*
90+
* @since 2.16
91+
*/
92+
protected StreamWriteConstraints _streamWriteConstraints;
93+
8794
/*
8895
/**********************************************************************
8996
/* Construction
@@ -282,6 +289,18 @@ public B streamReadConstraints(StreamReadConstraints streamReadConstraints) {
282289
return _this();
283290
}
284291

292+
/**
293+
* Sets the constraints for streaming writes.
294+
*
295+
* @param streamWriteConstraints constraints for streaming reads
296+
* @return this factory
297+
* @since 2.16
298+
*/
299+
public B streamWriteConstraints(StreamWriteConstraints streamWriteConstraints) {
300+
_streamWriteConstraints = streamWriteConstraints;
301+
return _this();
302+
}
303+
285304
// // // Other methods
286305

287306
/**

src/main/java/com/fasterxml/jackson/core/TokenStreamFactory.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,16 @@ public abstract class TokenStreamFactory
153153
*/
154154
public abstract StreamReadConstraints streamReadConstraints();
155155

156+
/**
157+
* Get the constraints to apply when performing streaming writes.
158+
*
159+
* @return Constraints to apply to reads done by {@link JsonGenerator}s constructed
160+
* by this factory.
161+
*
162+
* @since 2.16
163+
*/
164+
public abstract StreamWriteConstraints streamWriteConstraints();
165+
156166
/*
157167
/**********************************************************************
158168
/* Factory methods, parsers

src/main/java/com/fasterxml/jackson/core/filter/TokenFilterContext.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ protected TokenFilterContext(int type, TokenFilterContext parent,
7171
super();
7272
_type = type;
7373
_parent = parent;
74+
_nestingDepth = parent == null ? 0 : parent._nestingDepth + 1;
7475
_filter = filter;
7576
_index = -1;
7677
_startHandled = startHandled;

0 commit comments

Comments
 (0)