fix: limit the nesting depth

This commit is contained in:
Cleydyr de Albuquerque 2023-01-31 17:32:34 +01:00
parent 5920eca2d7
commit f566a1d9ee
4 changed files with 110 additions and 3 deletions

View File

@ -232,7 +232,7 @@ public class XML {
* @return true if the close tag is processed.
* @throws JSONException
*/
private static boolean parse(XMLTokener x, JSONObject context, String name, XMLParserConfiguration config)
private static boolean parse(XMLTokener x, JSONObject context, String name, XMLParserConfiguration config, int currentNestingDepth)
throws JSONException {
char c;
int i;
@ -402,7 +402,11 @@ public class XML {
} else if (token == LT) {
// Nested element
if (parse(x, jsonObject, tagName, config)) {
if (currentNestingDepth == config.getMaxNestingDepth()) {
throw x.syntaxError("Maximum nesting depth of " + config.getMaxNestingDepth() + " reached");
}
if (parse(x, jsonObject, tagName, config, currentNestingDepth + 1)) {
if (config.getForceList().contains(tagName)) {
// Force the value to be an array
if (jsonObject.length() == 0) {
@ -644,6 +648,10 @@ public class XML {
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to
* numbers but will instead be the exact value as seen in the XML document.
*
* This method can parse documents with a maximum nesting depth of 256. If you
* need to parse documents with a nesting depth greater than 256, you should use
*
*
* @param reader The XML source reader.
* @param config Configuration options for the parser
* @return A JSONObject containing the structured data from the XML string.
@ -655,7 +663,7 @@ public class XML {
while (x.more()) {
x.skipPast("<");
if(x.more()) {
parse(x, jo, null, config);
parse(x, jo, null, config, 0);
}
}
return jo;

View File

@ -16,6 +16,12 @@ import java.util.Set;
*/
@SuppressWarnings({""})
public class XMLParserConfiguration {
/**
* Used to indicate there's no defined limit to the maximum nesting depth when parsing a XML
* document to JSON.
*/
public static final int UNDEFINED_MAXIMUM_NESTING_DEPTH = -1;
/** Original Configuration of the XML Parser. */
public static final XMLParserConfiguration ORIGINAL
= new XMLParserConfiguration();
@ -54,6 +60,12 @@ public class XMLParserConfiguration {
*/
private Set<String> forceList;
/**
* When parsing the XML into JSON, specifies the tags whose values should be converted
* to arrays
*/
private int maxNestingDepth = UNDEFINED_MAXIMUM_NESTING_DEPTH;
/**
* Default parser configuration. Does not keep strings (tries to implicitly convert
* values), and the CDATA Tag Name is "content".
@ -297,4 +309,33 @@ public class XMLParserConfiguration {
newConfig.forceList = Collections.unmodifiableSet(cloneForceList);
return newConfig;
}
/**
* The maximum nesting depth that the parser will descend before throwing an exception
* when parsing the XML into JSON.
* @return the maximum nesting depth set for this configuration
*/
public int getMaxNestingDepth() {
return maxNestingDepth;
}
/**
* Defines the maximum nesting depth that the parser will descend before throwing an exception
* when parsing the XML into JSON. The default max nesting depth is undefined, which means the
* parser will go as deep as the maximum call stack size allows. Using any negative value as a
* parameter is equivalent to setting no limit to the nesting depth.
* @param maxNestingDepth the maximum nesting depth allowed to the XML parser
* @return The existing configuration will not be modified. A new configuration is returned.
*/
public XMLParserConfiguration withMaxNestingDepth(int maxNestingDepth) {
XMLParserConfiguration newConfig = this.clone();
if (maxNestingDepth > UNDEFINED_MAXIMUM_NESTING_DEPTH) {
newConfig.maxNestingDepth = maxNestingDepth;
} else {
newConfig.maxNestingDepth = UNDEFINED_MAXIMUM_NESTING_DEPTH;
}
return newConfig;
}
}

View File

@ -1051,6 +1051,29 @@ public class XMLConfigurationTest {
Util.compareActualVsExpectedJsonObjects(jsonObject, expetedJsonObject);
}
@Test
public void testMaxNestingDepthIsSet() {
XMLParserConfiguration xmlParserConfiguration = XMLParserConfiguration.ORIGINAL;
assertEquals(xmlParserConfiguration.getMaxNestingDepth(), XMLParserConfiguration.UNDEFINED_MAXIMUM_NESTING_DEPTH);
xmlParserConfiguration = xmlParserConfiguration.withMaxNestingDepth(42);
assertEquals(xmlParserConfiguration.getMaxNestingDepth(), 42);
xmlParserConfiguration = xmlParserConfiguration.withMaxNestingDepth(0);
assertEquals(xmlParserConfiguration.getMaxNestingDepth(), 0);
xmlParserConfiguration = xmlParserConfiguration.withMaxNestingDepth(-31415926);
assertEquals(xmlParserConfiguration.getMaxNestingDepth(), XMLParserConfiguration.UNDEFINED_MAXIMUM_NESTING_DEPTH);
xmlParserConfiguration = xmlParserConfiguration.withMaxNestingDepth(Integer.MIN_VALUE);
assertEquals(xmlParserConfiguration.getMaxNestingDepth(), XMLParserConfiguration.UNDEFINED_MAXIMUM_NESTING_DEPTH);
}
/**
* Convenience method, given an input string and expected result,

File diff suppressed because one or more lines are too long