Skip to content

StreamReadConstraints: add maxStringLen #864

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,24 @@ public class StreamReadConstraints
private static final long serialVersionUID = 1L;

/**
* Default setting for maximum length: see {@link Builder#maxNumberLength(int)} for details.
* Default setting for maximum number length: see {@link Builder#maxNumberLength(int)} for details.
*/
public static final int DEFAULT_MAX_NUM_LEN = 1000;

/**
* Default setting for maximum string length: see {@link Builder#maxStringLength(int)} for details.
*/
public static final int DEFAULT_MAX_STRING_LEN = 1000000;

protected final int _maxNumLen;
protected final int _maxStringLen;

private static final StreamReadConstraints DEFAULT =
new StreamReadConstraints(DEFAULT_MAX_NUM_LEN);
new StreamReadConstraints(DEFAULT_MAX_NUM_LEN, DEFAULT_MAX_STRING_LEN);

public static final class Builder {
private int maxNumLen;
private int maxStringLen;

/**
* Sets the maximum number length (in chars or bytes, depending on input context).
Expand All @@ -44,20 +51,42 @@ public Builder maxNumberLength(final int maxNumLen) {
return this;
}

/**
* Sets the maximum string length (in chars or bytes, depending on input context).
* The default is 1,000,000.
* Setting this value to lower than the {@link #maxNumberLength(int)} is not recommended.
*
* @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
*
* @since 2.15
*/
public Builder maxStringLength(final int maxStringLen) {
if (maxStringLen < 0) {
throw new IllegalArgumentException("Cannot set maxStringLen to a negative value");
}
this.maxStringLen = maxStringLen;
return this;
}

Builder() {
this(DEFAULT_MAX_NUM_LEN);
this(DEFAULT_MAX_NUM_LEN, DEFAULT_MAX_STRING_LEN);
}

Builder(int maxNumLen) {
Builder(final int maxNumLen, final int maxStringLen) {
this.maxNumLen = maxNumLen;
this.maxStringLen = maxStringLen;
}

Builder(StreamReadConstraints src) {
maxNumLen = src._maxNumLen;
maxStringLen = src._maxStringLen;
}

public StreamReadConstraints build() {
return new StreamReadConstraints(maxNumLen);
return new StreamReadConstraints(maxNumLen, maxStringLen);
}
}

Expand All @@ -67,8 +96,9 @@ public StreamReadConstraints build() {
/**********************************************************************
*/

StreamReadConstraints(int maxNumLen) {
StreamReadConstraints(final int maxNumLen, final int maxStringLen) {
_maxNumLen = maxNumLen;
_maxStringLen = maxStringLen;
}

public static Builder builder() {
Expand Down Expand Up @@ -103,6 +133,16 @@ 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;
}

/*
/**********************************************************************
/* Convenience methods for validation
Expand Down Expand Up @@ -146,4 +186,23 @@ public void validateIntegerLength(int length) throws NumberFormatException
length, _maxNumLen));
}
}

/**
* 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, an
* {@link IllegalStateException}
* is thrown.
*
* @param length Length of string in input units
*
* @throws IllegalStateException If length exceeds maximum
*/
public void validateStringLength(int length) throws IllegalStateException
{
if (length > _maxStringLen) {
throw new IllegalStateException(String.format("String length (%d) exceeds the maximum length (%d)",
length, _maxStringLen));
}
}
}
11 changes: 4 additions & 7 deletions src/main/java/com/fasterxml/jackson/core/base/ParserBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ protected ParserBase(IOContext ctxt, int features) {
super(features);
_ioContext = ctxt;
_streamReadConstraints = ctxt.streamReadConstraints();
_textBuffer = ctxt.constructTextBuffer();
_textBuffer = ctxt.constructReadConstrainedTextBuffer();
DupDetector dups = Feature.STRICT_DUPLICATE_DETECTION.enabledIn(features)
? DupDetector.rootDetector(this) : null;
_parsingContext = JsonReadContext.createRootContext(dups);
Expand Down Expand Up @@ -837,8 +837,7 @@ protected void _parseNumericValue(int expType) throws IOException
final int len = _intLength;
// First: optimization for simple int
if (len <= 9) {
int i = _textBuffer.contentsAsInt(_numberNegative);
_numberInt = i;
_numberInt = _textBuffer.contentsAsInt(_numberNegative);
_numTypesValid = NR_INT;
return;
}
Expand Down Expand Up @@ -919,16 +918,14 @@ private void _parseSlowFloat(int expType) throws IOException
_numberString = numStr;
_numTypesValid = NR_BIGDECIMAL;
} else if (expType == NR_FLOAT) {
_numberFloat = _textBuffer.contentsAsFloat(streamReadConstraints(),
isEnabled(Feature.USE_FAST_DOUBLE_PARSER));
_numberFloat = _textBuffer.contentsAsFloat(isEnabled(Feature.USE_FAST_DOUBLE_PARSER));
_numTypesValid = NR_FLOAT;
} else {
// Otherwise double has to do
// 04-Dec-2022, tatu: We can get all kinds of values here, NR_DOUBLE
// but also NR_INT or even NR_UNKNOWN. Shouldn't we try further
// deferring some typing?
_numberDouble = _textBuffer.contentsAsDouble(streamReadConstraints(),
isEnabled(Feature.USE_FAST_DOUBLE_PARSER));
_numberDouble = _textBuffer.contentsAsDouble(isEnabled(Feature.USE_FAST_DOUBLE_PARSER));
_numTypesValid = NR_DOUBLE;
}
} catch (NumberFormatException nex) {
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/fasterxml/jackson/core/io/IOContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.StreamReadConstraints;
import com.fasterxml.jackson.core.util.BufferRecycler;
import com.fasterxml.jackson.core.util.ReadConstrainedTextBuffer;
import com.fasterxml.jackson.core.util.TextBuffer;

/**
Expand Down Expand Up @@ -203,6 +204,10 @@ public TextBuffer constructTextBuffer() {
return new TextBuffer(_bufferRecycler);
}

public TextBuffer constructReadConstrainedTextBuffer() {
return new ReadConstrainedTextBuffer(_streamReadConstraints, _bufferRecycler);
}

/**
* Method for recycling or allocation byte buffer of "read I/O" type.
*<p>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.fasterxml.jackson.core.util;

import com.fasterxml.jackson.core.StreamReadConstraints;

public final class ReadConstrainedTextBuffer extends TextBuffer {

private final StreamReadConstraints _streamReadConstraints;

public ReadConstrainedTextBuffer(StreamReadConstraints streamReadConstraints, BufferRecycler bufferRecycler) {
super(bufferRecycler);
_streamReadConstraints = streamReadConstraints;
}

/*
/**********************************************************************
/* Convenience methods for validation
/**********************************************************************
*/

/**
* {@inheritDoc}
*/
@Override
protected void validateFPLength(int length) throws NumberFormatException
{
_streamReadConstraints.validateFPLength(length);
}

/**
* {@inheritDoc}
*/
@Override
protected void validateIntegerLength(int length) throws NumberFormatException
{
_streamReadConstraints.validateIntegerLength(length);
}


/**
* {@inheritDoc}
*/
@Override
protected void validateStringLength(int length) throws IllegalStateException
{
_streamReadConstraints.validateStringLength(length);
}
}
Loading