Generalize the logic to disallow nested objects and arrays as keys in objects.

Fixes #771.
This commit is contained in:
Éamonn McManus 2023-09-20 10:50:48 -07:00
parent 01727fd0ed
commit 661114c50d
3 changed files with 37 additions and 17 deletions

View File

@ -208,22 +208,14 @@ public class JSONObject {
throw x.syntaxError("A JSONObject text must begin with '{'");
}
for (;;) {
char prev = x.getPrevious();
c = x.nextClean();
switch (c) {
case 0:
throw x.syntaxError("A JSONObject text must end with '}'");
case '}':
return;
case '{':
case '[':
if(prev=='{') {
throw x.syntaxError("A JSON Object can not directly nest another JSON Object or JSON Array.");
}
// fall through
default:
x.back();
key = x.nextValue().toString();
key = x.nextSimpleValue(c).toString();
}
// The key is followed by ':'.
@ -1712,12 +1704,12 @@ public class JSONObject {
final Object result = method.invoke(bean);
if (result != null) {
// check cyclic dependency and throw error if needed
// the wrap and populateMap combination method is
// the wrap and populateMap combination method is
// itself DFS recursive
if (objectsRecord.contains(result)) {
throw recursivelyDefinedObjectException(key);
}
objectsRecord.add(result);
this.map.put(key, wrap(result, objectsRecord));
@ -1726,7 +1718,7 @@ public class JSONObject {
// we don't use the result anywhere outside of wrap
// if it's a resource we should be sure to close it
// after calling toString
// after calling toString
if (result instanceof Closeable) {
try {
((Closeable) result).close();

View File

@ -402,12 +402,7 @@ public class JSONTokener {
*/
public Object nextValue() throws JSONException {
char c = this.nextClean();
String string;
switch (c) {
case '"':
case '\'':
return this.nextString(c);
case '{':
this.back();
try {
@ -423,6 +418,21 @@ public class JSONTokener {
throw new JSONException("JSON Array or Object depth too large to process.", e);
}
}
return nextSimpleValue(c);
}
Object nextSimpleValue(char c) {
String string;
switch (c) {
case '"':
case '\'':
return this.nextString(c);
case '{':
throw syntaxError("Nested object not expected here.");
case '[':
throw syntaxError("Nested array not expected here.");
}
/*
* Handle unquoted text. This could be the values true, false, or

View File

@ -2224,6 +2224,24 @@ public class JSONObjectTest {
"Expected a ',' or '}' at 15 [character 16 line 1]",
e.getMessage());
}
try {
// key is a nested map
String str = "{{\"foo\": \"bar\"}: \"baz\"}";
assertNull("Expected an exception",new JSONObject(str));
} catch (JSONException e) {
assertEquals("Expecting an exception message",
"Nested object not expected here. at 2 [character 3 line 1]",
e.getMessage());
}
try {
// key is a nested array containing a map
String str = "{\"a\": 1, [{\"foo\": \"bar\"}]: \"baz\"}";
assertNull("Expected an exception",new JSONObject(str));
} catch (JSONException e) {
assertEquals("Expecting an exception message",
"Nested array not expected here. at 10 [character 11 line 1]",
e.getMessage());
}
try {
// \0 after ,
String str = "{\"myKey\":true, \0\"myOtherKey\":false}";