Skip to content

Commit

Permalink
support overriding the codePointLimit (#339)
Browse files Browse the repository at this point in the history
  • Loading branch information
pjfanning committed Sep 24, 2022
1 parent 7baf4cc commit 444e62c
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;

import org.yaml.snakeyaml.DumperOptions;

Expand All @@ -11,14 +10,13 @@
import com.fasterxml.jackson.core.format.MatchStrength;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.dataformat.yaml.util.StringQuotingChecker;
import org.yaml.snakeyaml.LoaderOptions;

@SuppressWarnings("resource")
public class YAMLFactory extends JsonFactory
{
private static final long serialVersionUID = 1L;

protected final static Charset UTF8 = Charset.forName("UTF-8");

/**
* Name used to identify YAML format.
* (and returned by {@link #getFormatName()}
Expand Down Expand Up @@ -66,6 +64,20 @@ public class YAMLFactory extends JsonFactory
*/
protected final StringQuotingChecker _quotingChecker;

/**
* Configuration for underlying parser to follow, if specified;
* left as {@code null} for backwards compatibility (which means
* whatever default settings {@code SnakeYAML} deems best).
* <p>
* If you need to support parsing YAML files that are larger than 3Mb,
* it is recommended that you provide a LoaderOptions instance where
* you set the Codepoint Limit to a larger value than its 3Mb default.
* </p>
*
* @since 2.14
*/
protected final LoaderOptions _loaderOptions;

/*
/**********************************************************************
/* Factory construction, configuration
Expand Down Expand Up @@ -94,6 +106,7 @@ public YAMLFactory(ObjectCodec oc)
//_version = DumperOptions.Version.V1_1;
_version = null;
_quotingChecker = StringQuotingChecker.Default.instance();
_loaderOptions = null;
}

/**
Expand All @@ -106,6 +119,7 @@ public YAMLFactory(YAMLFactory src, ObjectCodec oc)
_yamlGeneratorFeatures = src._yamlGeneratorFeatures;
_version = src._version;
_quotingChecker = src._quotingChecker;
_loaderOptions = src._loaderOptions;
}

/**
Expand All @@ -119,6 +133,7 @@ protected YAMLFactory(YAMLFactoryBuilder b)
_yamlGeneratorFeatures = b.formatGeneratorFeaturesMask();
_version = b.yamlVersionToWrite();
_quotingChecker = b.stringQuotingChecker();
_loaderOptions = b.loaderOptions();
}

@Override
Expand Down Expand Up @@ -462,28 +477,28 @@ public JsonGenerator createGenerator(File f, JsonEncoding enc) throws IOExceptio

@Override
protected YAMLParser _createParser(InputStream in, IOContext ctxt) throws IOException {
return new YAMLParser(ctxt, _getBufferRecycler(), _parserFeatures, _yamlParserFeatures,
_objectCodec, _createReader(in, null, ctxt));
return new YAMLParser(ctxt, _parserFeatures, _yamlParserFeatures,
_loaderOptions, _objectCodec, _createReader(in, null, ctxt));
}

@Override
protected YAMLParser _createParser(Reader r, IOContext ctxt) throws IOException {
return new YAMLParser(ctxt, _getBufferRecycler(), _parserFeatures, _yamlParserFeatures,
_objectCodec, r);
return new YAMLParser(ctxt, _parserFeatures, _yamlParserFeatures,
_loaderOptions, _objectCodec, r);
}

// since 2.4
@Override
protected YAMLParser _createParser(char[] data, int offset, int len, IOContext ctxt,
boolean recyclable) throws IOException {
return new YAMLParser(ctxt, _getBufferRecycler(), _parserFeatures, _yamlParserFeatures,
_objectCodec, new CharArrayReader(data, offset, len));
return new YAMLParser(ctxt, _parserFeatures, _yamlParserFeatures,
_loaderOptions, _objectCodec, new CharArrayReader(data, offset, len));
}

@Override
protected YAMLParser _createParser(byte[] data, int offset, int len, IOContext ctxt) throws IOException {
return new YAMLParser(ctxt, _getBufferRecycler(), _parserFeatures, _yamlParserFeatures,
_objectCodec, _createReader(data, offset, len, null, ctxt));
return new YAMLParser(ctxt, _parserFeatures, _yamlParserFeatures,
_loaderOptions, _objectCodec, _createReader(data, offset, len, null, ctxt));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import com.fasterxml.jackson.core.TSFBuilder;
import com.fasterxml.jackson.dataformat.yaml.util.StringQuotingChecker;
import org.yaml.snakeyaml.LoaderOptions;

/**
* {@link com.fasterxml.jackson.core.TSFBuilder}
Expand All @@ -18,8 +19,6 @@ public class YAMLFactoryBuilder extends TSFBuilder<YAMLFactory, YAMLFactoryBuild
/**********************************************************
*/

// protected int _formatParserFeatures;

/**
* Set of {@link YAMLGenerator.Feature}s enabled, as bitmask.
*/
Expand All @@ -40,6 +39,20 @@ public class YAMLFactoryBuilder extends TSFBuilder<YAMLFactory, YAMLFactoryBuild
*/
protected DumperOptions.Version _version;

/**
* Configuration for underlying parser to follow, if specified;
* left as {@code null} for backwards compatibility (which means
* whatever default settings {@code SnakeYAML} deems best).
* <p>
* If you need to support parsing YAML files that are larger than 3Mb,
* it is recommended that you provide a LoaderOptions instance where
* you set the Codepoint Limit to a larger value than its 3Mb default.
* </p>
*
* @since 2.14
*/
protected LoaderOptions _loaderOptions;

/*
/**********************************************************
/* Life cycle
Expand Down Expand Up @@ -132,6 +145,25 @@ public YAMLFactoryBuilder yamlVersionToWrite(DumperOptions.Version v) {
return this;
}

/**
* Configuration for underlying parser to follow, if specified;
* left as {@code null} for backwards compatibility (which means
* whatever default settings {@code SnakeYAML} deems best).
* <p>
* If you need to support parsing YAML files that are larger than 3Mb,
* it is recommended that you provide a LoaderOptions instance where
* you set the Codepoint Limit to a larger value than its 3Mb default.
* </p>
*
* @param loaderOptions the {@code SnakeYAML} configuration to use when parsing YAML
* @return This builder instance, to allow chaining
* @since 2.14
*/
public YAMLFactoryBuilder loaderOptions(LoaderOptions loaderOptions) {
_loaderOptions = loaderOptions;
return this;
}

/*
/**********************************************************
/* Accessors
Expand All @@ -152,6 +184,23 @@ public StringQuotingChecker stringQuotingChecker() {
return StringQuotingChecker.Default.instance();
}

/**
* Configuration for underlying parser to follow, if specified;
* left as {@code null} for backwards compatibility (which means
* whatever default settings {@code SnakeYAML} deems best).
* <p>
* If you need to support parsing YAML files that are larger than 3Mb,
* it is recommended that you provide a LoaderOptions instance where
* you set the Codepoint Limit to a larger value than its 3Mb default.
* </p>
*
* @return the {@code SnakeYAML} configuration to use when parsing YAML
* @since 2.14
*/
public LoaderOptions loaderOptions() {
return _loaderOptions;
}

@Override
public YAMLFactory build() {
return new YAMLFactory(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.math.BigInteger;

import com.fasterxml.jackson.core.io.NumberInput;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.error.Mark;
import org.yaml.snakeyaml.events.*;
import org.yaml.snakeyaml.nodes.NodeId;
Expand Down Expand Up @@ -166,16 +167,31 @@ private Feature(boolean defaultState) {
/* Life-cycle
/**********************************************************************
*/



/**
* @deprecated since 2.14, use other constructor
*/
@Deprecated
public YAMLParser(IOContext ctxt, BufferRecycler br,
int parserFeatures, int formatFeatures,
ObjectCodec codec, Reader reader)
{
super(ctxt, parserFeatures);
this(ctxt, parserFeatures, formatFeatures, null, codec, reader);
}

public YAMLParser(IOContext ctxt, int parserFeatures, int formatFeatures,
LoaderOptions loaderOptions, ObjectCodec codec, Reader reader)
{
super(ctxt, parserFeatures);
_objectCodec = codec;
_formatFeatures = formatFeatures;
_reader = reader;
_yamlParser = new ParserImpl(new StreamReader(reader));
if (loaderOptions == null) {
_yamlParser = new ParserImpl(new StreamReader(reader));
} else {
_yamlParser = new ParserImpl(new StreamReader(reader), loaderOptions);
}
_cfgEmptyStringsToNull = Feature.EMPTY_STRING_AS_NULL.enabledIn(formatFeatures);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

import com.fasterxml.jackson.dataformat.yaml.JacksonYAMLParseException;
import com.fasterxml.jackson.dataformat.yaml.ModuleTestBase;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLParser;
import org.yaml.snakeyaml.LoaderOptions;

/**
* Unit tests for checking functioning of the underlying
Expand Down Expand Up @@ -597,4 +599,29 @@ public void testTimeLikeValues() throws Exception
assertNull(p.nextToken());
p.close();
}

public void testYamlParseFailsWhenCodePointLimitVerySmall() throws Exception
{
final String YAML = "---\n"
+"content:\n"
+" uri: \"http://javaone.com/keynote.mpg\"\n"
+" title: \"Javaone Keynote\"\n"
+" width: 640\n"
+" height: 480\n"
+" persons:\n"
+" - \"Foo Bar\"\n"
+" - \"Max Power\"\n"
;
LoaderOptions loaderOptions = new LoaderOptions();
loaderOptions.setCodePointLimit(5); //5 bytes
YAMLFactory yamlFactory = YAMLFactory.builder()
.loaderOptions(loaderOptions)
.build();
try (JsonParser p = yamlFactory.createParser(YAML)) {
assertToken(JsonToken.START_OBJECT, p.nextToken());
fail("expected to fail by now");
} catch (JacksonYAMLParseException e) {
assertTrue(e.getMessage().startsWith("The incoming YAML document exceeds the limit: 5 code points."));
}
}
}

0 comments on commit 444e62c

Please sign in to comment.