-
-
Notifications
You must be signed in to change notification settings - Fork 773
/
StreamReadConstraints.java
661 lines (606 loc) · 23.6 KB
/
StreamReadConstraints.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
package com.fasterxml.jackson.core;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
/**
* The constraints to use for streaming reads: used to guard against malicious
* input by preventing processing of "too big" input 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 Number value length: default 1000 (see {@link #DEFAULT_MAX_NUM_LEN})
* </li>
* <li>Maximum String value length: default 20_000_000 (see {@link #DEFAULT_MAX_STRING_LEN})
* </li>
* <li>Maximum Property name length: default 50_000 (see {@link #DEFAULT_MAX_NAME_LEN})
* </li>
* <li>Maximum Nesting depth: default 1000 (see {@link #DEFAULT_MAX_DEPTH})
* </li>
* <li>Maximum Document length: default {@code unlimited} (coded as {@code -1},
* (see {@link #DEFAULT_MAX_DOC_LEN})
* </li>
* <li>Maximum Token count: default {@code unlimited} (coded as {@code -1},
* (see {@link #DEFAULT_MAX_TOKEN_COUNT})
* </li>
* </ul>
*
* @since 2.15
*/
public class StreamReadConstraints
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;
/**
* Default setting for maximum document length:
* see {@link Builder#maxDocumentLength} for details.
*/
public static final long DEFAULT_MAX_DOC_LEN = -1L;
/**
* Default setting for maximum token count:
* see {@link Builder#maxTokenCount} for details.
*/
public static final long DEFAULT_MAX_TOKEN_COUNT = -1L;
/**
* @since 2.16
*/
public static final int DEFAULT_MAX_NUM_LEN = 1000;
/**
* Default setting for maximum string length: see {@link Builder#maxStringLength(int)}
* for details.
*<p>
* NOTE: Jackson 2.15.0 initially used a lower setting (5_000_000).
*/
public static final int DEFAULT_MAX_STRING_LEN = 20_000_000;
/**
* Default setting for maximum name length: see {@link Builder#maxNameLength(int)}
* for details.
*
* @since 2.16
*/
public static final int DEFAULT_MAX_NAME_LEN = 50_000;
/**
* Limit for the maximum magnitude of Scale of {@link java.math.BigDecimal} that can be
* converted to {@link java.math.BigInteger}.
*<p>
* "100k digits ought to be enough for anybody!"
*/
private static final int MAX_BIGINT_SCALE_MAGNITUDE = 100_000;
protected final int _maxNestingDepth;
protected final long _maxDocLen;
protected final long _maxTokenCount;
protected final int _maxNumLen;
protected final int _maxStringLen;
protected final int _maxNameLen;
private static StreamReadConstraints DEFAULT =
new StreamReadConstraints(DEFAULT_MAX_DEPTH,
DEFAULT_MAX_DOC_LEN,
DEFAULT_MAX_NUM_LEN, DEFAULT_MAX_STRING_LEN, DEFAULT_MAX_NAME_LEN);
/**
* Override the default StreamReadConstraints. These defaults are only used when {@link JsonFactory}
* instances are not configured with their own StreamReadConstraints.
* <p>
* Library maintainers should not set this as it will affect other code that uses Jackson.
* Library maintainers who want to configure StreamReadConstraints for the Jackson usage within their
* lib should create <code>ObjectMapper</code> instances that have a {@link JsonFactory} instance with
* the required StreamReadConstraints.
* <p>
* This method is meant for users delivering applications. If they use this, they set it when they start
* their application to avoid having other code initialize their mappers before the defaults are overridden.
*
* @param streamReadConstraints new default for StreamReadConstraints (a null value will reset to built-in default)
* @see #defaults()
* @see #builder()
* @since v2.15.2
*/
public static void overrideDefaultStreamReadConstraints(final StreamReadConstraints streamReadConstraints) {
if (streamReadConstraints == null) {
DEFAULT = new StreamReadConstraints(DEFAULT_MAX_DEPTH, DEFAULT_MAX_DOC_LEN,
DEFAULT_MAX_NUM_LEN, DEFAULT_MAX_STRING_LEN);
} else {
DEFAULT = streamReadConstraints;
}
}
public static final class Builder {
private long maxDocLen;
private long maxTokenCount;
private int maxNestingDepth;
private int maxNumLen;
private int maxStringLen;
private int maxNameLen;
/**
* 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;
}
/**
* Sets the maximum allowed document length (for positive values over 0) or
* indicate that any length is acceptable ({@code 0} or negative number).
* The length is in input units of the input source, that is, in
* {@code byte}s or {@code char}s.
*
* @param maxDocLen the maximum allowed document length if positive number above 0; otherwise
* ({@code 0} or negative number) means "unlimited".
*
* @return this builder
*
* @since 2.16
*/
public Builder maxDocumentLength(long maxDocLen) {
// Negative values and 0 mean "unlimited", mark with -1L
if (maxDocLen <= 0L) {
maxDocLen = -1L;
}
this.maxDocLen = maxDocLen;
return this;
}
/**
* Sets the maximum allowed token count (for positive values over 0) or
* indicate that any count is acceptable ({@code 0} or negative number).
*
* <p>
* A token is a single unit of input, such as a number, a string, an object
* start or end, or an array start or end.
* </p>
*
* @param maxTokenCount the maximum allowed token count if positive number above 0; otherwise
* ({@code 0} or negative number) means "unlimited".
*
* @return this builder
*
* @since 2.18
*/
public Builder maxTokenCount(long maxTokenCount) {
// Negative values and 0 mean "unlimited", mark with -1L
if (maxTokenCount <= 0L) {
maxTokenCount = -1L;
}
this.maxTokenCount = maxTokenCount;
return this;
}
/**
* Sets the maximum number length (in chars or bytes, depending on input context).
* The default is 1000.
*
* @param maxNumLen the maximum number length (in chars or bytes, depending on input context)
*
* @return this builder
* @throws IllegalArgumentException if the maxNumLen is set to a negative value
*/
public Builder maxNumberLength(final int maxNumLen) {
if (maxNumLen < 0) {
throw new IllegalArgumentException("Cannot set maxNumberLength to a negative value");
}
this.maxNumLen = maxNumLen;
return this;
}
/**
* Sets the maximum string length (in chars or bytes, depending on input context).
* The default is 20,000,000. This limit is not exact, the limit is applied when we increase
* internal buffer sizes and an exception will happen at sizes greater than this limit. Some
* text values that are a little bigger than the limit may be treated as valid but no text
* values with sizes less than or equal to this limit will be treated as invalid.
* <p>
* Setting this value to lower than the {@link #maxNumberLength(int)} is not recommended.
* </p>
*<p>
* NOTE: Jackson 2.15.0 initially used a lower setting (5_000_000).
*
* @param maxStringLen the maximum string length (in chars or bytes, depending on input context)
*
* @return this builder
* @throws IllegalArgumentException if the maxStringLen is set to a negative value
*/
public Builder maxStringLength(final int maxStringLen) {
if (maxStringLen < 0) {
throw new IllegalArgumentException("Cannot set maxStringLen to a negative value");
}
this.maxStringLen = maxStringLen;
return this;
}
/**
* Sets the maximum name length (in chars or bytes, depending on input context).
* The default is 50,000. This limit is not exact, the limit is applied when we increase
* internal buffer sizes and an exception will happen at sizes greater than this limit. Some
* text values that are a little bigger than the limit may be treated as valid but no text
* values with sizes less than or equal to this limit will be treated as invalid.
*
* @param maxNameLen the maximum string length (in chars or bytes, depending on input context)
*
* @return this builder
* @throws IllegalArgumentException if the maxStringLen is set to a negative value
* @since 2.16.0
*/
public Builder maxNameLength(final int maxNameLen) {
if (maxNameLen < 0) {
throw new IllegalArgumentException("Cannot set maxNameLen to a negative value");
}
this.maxNameLen = maxNameLen;
return this;
}
Builder() {
this(DEFAULT_MAX_DEPTH, DEFAULT_MAX_DOC_LEN, DEFAULT_MAX_TOKEN_COUNT,
DEFAULT_MAX_NUM_LEN, DEFAULT_MAX_STRING_LEN, DEFAULT_MAX_NAME_LEN);
}
Builder(final int maxNestingDepth, final long maxDocLen, final long maxTokenCount,
final int maxNumLen, final int maxStringLen, final int maxNameLen) {
this.maxNestingDepth = maxNestingDepth;
this.maxDocLen = maxDocLen;
this.maxTokenCount = maxTokenCount;
this.maxNumLen = maxNumLen;
this.maxStringLen = maxStringLen;
this.maxNameLen = maxNameLen;
}
Builder(StreamReadConstraints src) {
maxNestingDepth = src._maxNestingDepth;
maxDocLen = src._maxDocLen;
maxTokenCount = src._maxTokenCount;
maxNumLen = src._maxNumLen;
maxStringLen = src._maxStringLen;
maxNameLen = src._maxNameLen;
}
public StreamReadConstraints build() {
return new StreamReadConstraints(maxNestingDepth, maxDocLen,
maxNumLen, maxStringLen, maxNameLen, maxTokenCount);
}
}
/*
/**********************************************************************
/* Life-cycle
/**********************************************************************
*/
@Deprecated // since 2.16
protected StreamReadConstraints(final int maxNestingDepth, final long maxDocLen,
final int maxNumLen, final int maxStringLen) {
this(maxNestingDepth, maxDocLen,
maxNumLen, maxStringLen, DEFAULT_MAX_NAME_LEN, DEFAULT_MAX_TOKEN_COUNT);
}
/**
* @param maxNestingDepth Maximum input document nesting to allow
* @param maxDocLen Maximum input document length to allow
* @param maxNumLen Maximum number representation length to allow
* @param maxStringLen Maximum String value length to allow
* @param maxNameLen Maximum Object property name length to allow
*
* @since 2.16
*/
@Deprecated // since 2.18
protected StreamReadConstraints(final int maxNestingDepth, final long maxDocLen,
final int maxNumLen, final int maxStringLen, final int maxNameLen) {
this(maxNestingDepth, maxDocLen, maxNumLen, maxStringLen, maxNameLen, DEFAULT_MAX_TOKEN_COUNT);
}
/**
* @param maxNestingDepth Maximum input document nesting to allow
* @param maxDocLen Maximum input document length to allow
* @param maxNumLen Maximum number representation length to allow
* @param maxStringLen Maximum String value length to allow
* @param maxNameLen Maximum Object property name length to allow
* @param maxTokenCount Maximum number of tokens to allow
*
* @since 2.18
*/
protected StreamReadConstraints(final int maxNestingDepth, final long maxDocLen,
final int maxNumLen, final int maxStringLen, final int maxNameLen, final long maxTokenCount) {
_maxNestingDepth = maxNestingDepth;
_maxDocLen = maxDocLen;
_maxNumLen = maxNumLen;
_maxStringLen = maxStringLen;
_maxNameLen = maxNameLen;
_maxTokenCount = maxTokenCount;
}
public static Builder builder() {
return new Builder();
}
/**
* @return the default {@link StreamReadConstraints} (when none is set on the {@link JsonFactory} explicitly)
* @see #overrideDefaultStreamReadConstraints
*/
public static StreamReadConstraints 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;
}
/**
* Accessor for maximum document length.
* see {@link Builder#maxDocumentLength(long)} for details.
*
* @return Maximum allowed depth
*/
public long getMaxDocumentLength() {
return _maxDocLen;
}
/**
* Convenience method, basically same as:
*<pre>
* getMaxDocumentLength() > 0L
*</pre>
*
* @return {@code True} if this constraints instance has a limit for maximum
* document length to enforce; {@code false} otherwise.
*/
public boolean hasMaxDocumentLength() {
return _maxDocLen > 0L;
}
/**
* Accessor for maximum token count.
* see {@link Builder#maxTokenCount(long)} for details.
*
* @return Maximum allowed token count
* @since 2.18
*/
public long getMaxTokenCount() {
return _maxTokenCount;
}
/**
* Convenience method, basically same as:
*<pre>
* getMaxTokenCount() > 0L
*</pre>
*
* @return {@code True} if this constraints instance has a limit for maximum
* token count to enforce; {@code false} otherwise.
* @since 2.18
*/
public boolean hasMaxTokenCount() {
return _maxTokenCount > 0L;
}
/**
* Accessor for maximum length of numbers to decode.
* see {@link Builder#maxNumberLength(int)} for details.
*
* @return Maximum allowed number length
*/
public int getMaxNumberLength() {
return _maxNumLen;
}
/**
* Accessor for maximum length of strings to decode.
* see {@link Builder#maxStringLength(int)} for details.
*
* @return Maximum allowed string length
*/
public int getMaxStringLength() {
return _maxStringLen;
}
/**
* Accessor for maximum length of names to decode.
* see {@link Builder#maxNameLength(int)} for details.
*
* @return Maximum allowed name length
*/
public int getMaxNameLength() {
return _maxNameLen;
}
/*
/**********************************************************************
/* 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"));
}
}
/**
* Convenience method that can be used to verify that the
* document length does not exceed the maximum specified by this
* constraints object (if any): if it does, a
* {@link StreamConstraintsException}
* is thrown.
*
* @param len Current length of processed document content
*
* @throws StreamConstraintsException If length exceeds maximum
*
* @since 2.16
*/
public void validateDocumentLength(long len) throws StreamConstraintsException
{
if ((len > _maxDocLen)
// Note: -1L used as marker for "unlimited"
&& (_maxDocLen > 0L)) {
throw _constructException(
"Document length (%d) exceeds the maximum allowed (%d, from %s)",
len, _maxDocLen,
_constrainRef("getMaxDocumentLength"));
}
}
/**
* Convenience method that can be used to verify that the
* token count does not exceed the maximum specified by this
* constraints object (if any): if it does, a
* {@link StreamConstraintsException}
* is thrown.
*
* @param count Current token count for processed document content
*
* @throws StreamConstraintsException If length exceeds maximum
*
* @since 2.18
*/
public void validateTokenCount(long count) throws StreamConstraintsException
{
// for performance reasons, it is assumed that users check hasMaxTokenCount()
// before calling this method - this method will not work properly if hasMaxTokenCount() is false
if (count > _maxTokenCount) {
throw _constructException(
"Token count (%d) exceeds the maximum allowed (%d, from %s)",
count, _maxTokenCount,
_constrainRef("getMaxTokenCount"));
}
}
/*
/**********************************************************************
/* Convenience methods for validation, token lengths
/**********************************************************************
*/
/**
* Convenience method that can be used to verify that a floating-point
* number of specified length does not exceed maximum specified by this
* constraints object: if it does, a
* {@link StreamConstraintsException}
* is thrown.
*
* @param length Length of number in input units
*
* @throws StreamConstraintsException If length exceeds maximum
*/
public void validateFPLength(int length) throws StreamConstraintsException
{
if (length > _maxNumLen) {
throw _constructException(
"Number value length (%d) exceeds the maximum allowed (%d, from %s)",
length, _maxNumLen,
_constrainRef("getMaxNumberLength"));
}
}
/**
* Convenience method that can be used to verify that an integer
* number of specified length does not exceed maximum specific by this
* constraints object: if it does, a
* {@link StreamConstraintsException}
* is thrown.
*
* @param length Length of number in input units
*
* @throws StreamConstraintsException If length exceeds maximum
*/
public void validateIntegerLength(int length) throws StreamConstraintsException
{
if (length > _maxNumLen) {
throw _constructException(
"Number value length (%d) exceeds the maximum allowed (%d, from %s)",
length, _maxNumLen,
_constrainRef("getMaxNumberLength"));
}
}
/**
* Convenience method that can be used to verify that a String
* of specified length does not exceed maximum specific by this
* constraints object: if it does, a
* {@link StreamConstraintsException}
* is thrown.
*
* @param length Length of string in input units
*
* @throws StreamConstraintsException If length exceeds maximum
*/
public void validateStringLength(int length) throws StreamConstraintsException
{
if (length > _maxStringLen) {
throw _constructException(
"String value length (%d) exceeds the maximum allowed (%d, from %s)",
length, _maxStringLen,
_constrainRef("getMaxStringLength"));
}
}
/**
* Convenience method that can be used to verify that a name
* of specified length does not exceed maximum specific by this
* constraints object: if it does, a
* {@link StreamConstraintsException}
* is thrown.
*
* @param length Length of name in input units
*
* @throws StreamConstraintsException If length exceeds maximum
*/
public void validateNameLength(int length) throws StreamConstraintsException
{
if (length > _maxNameLen) {
throw _constructException(
"Name length (%d) exceeds the maximum allowed (%d, from %s)",
length, _maxNameLen,
_constrainRef("getMaxNameLength"));
}
}
/*
/**********************************************************************
/* Convenience methods for validation, other
/**********************************************************************
*/
/**
* Convenience method that can be used to verify that a conversion to
* {@link java.math.BigInteger}
* {@link StreamConstraintsException}
* is thrown.
*
* @param scale Scale (possibly negative) of {@link java.math.BigDecimal} to convert
*
* @throws StreamConstraintsException If magnitude (absolute value) of scale exceeds maximum
* allowed
*/
public void validateBigIntegerScale(int scale) throws StreamConstraintsException
{
final int absScale = Math.abs(scale);
final int limit = MAX_BIGINT_SCALE_MAGNITUDE;
if (absScale > limit) {
throw _constructException(
"BigDecimal scale (%d) magnitude exceeds the maximum allowed (%d)",
scale, limit);
}
}
/*
/**********************************************************************
/* 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 "`StreamReadConstraints."+method+"()`";
}
}