add exception for json

This commit is contained in:
Looly 2022-11-29 21:50:51 +08:00
parent bc808210fd
commit 68d28c4fd4
9 changed files with 137 additions and 21 deletions

View File

@ -18,7 +18,7 @@
<properties>
<!-- versions -->
<bouncycastle.version>1.71</bouncycastle.version>
<bouncycastle.version>1.72</bouncycastle.version>
</properties>
<dependencies>

View File

@ -20,10 +20,12 @@
<!-- versions -->
<c3p0.version>0.9.5.5</c3p0.version>
<dbcp2.version>2.9.0</dbcp2.version>
<tomcat-jdbc.version>10.0.20</tomcat-jdbc.version>
<druid.version>1.2.12</druid.version>
<!-- 固定10.0.x -->
<tomcat-jdbc.version>10.0.27</tomcat-jdbc.version>
<druid.version>1.2.15</druid.version>
<!-- 固定4.x -->
<hikariCP.version>4.0.3</hikariCP.version>
<sqlite.version>3.39.3.0</sqlite.version>
<sqlite.version>3.39.4.1</sqlite.version>
<!-- 此处固定2.5.x支持到JDK8 -->
<hsqldb.version>2.5.2</hsqldb.version>
</properties>
@ -79,7 +81,7 @@
<dependency>
<groupId>com.github.chris2018998</groupId>
<artifactId>beecp</artifactId>
<version>3.3.8</version>
<version>3.3.9</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
@ -135,7 +137,7 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.0</version>
<version>2.0.4</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -19,7 +19,7 @@
<properties>
<!-- versions -->
<velocity.version>2.3</velocity.version>
<beetl.version>3.10.0.RELEASE</beetl.version>
<beetl.version>3.13.0.RELEASE</beetl.version>
<rythm.version>1.4.1</rythm.version>
<freemarker.version>2.3.31</freemarker.version>
<enjoy.version>4.9.21</enjoy.version>
@ -31,7 +31,7 @@
<net.version>3.8.0</net.version>
<emoji-java.version>5.1.1</emoji-java.version>
<servlet-api.version>4.0.1</servlet-api.version>
<spring-boot.version>2.7.4</spring-boot.version>
<spring-boot.version>2.7.5</spring-boot.version>
<cglib.version>3.3.0</cglib.version>
</properties>
@ -430,7 +430,7 @@
<dependency>
<groupId>com.googlecode.aviator</groupId>
<artifactId>aviator</artifactId>
<version>5.3.2</version>
<version>5.3.3</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
@ -465,7 +465,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.3.23</version>
<version>5.3.24</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
@ -495,13 +495,13 @@
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>6.2.2</version>
<version>6.3.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.6</version>
<version>2.3.7</version>
<scope>provided</scope>
</dependency>
<dependency>

View File

@ -18,7 +18,7 @@
<properties>
<!-- versions -->
<bouncycastle.version>1.70</bouncycastle.version>
<bouncycastle.version>1.72</bouncycastle.version>
</properties>
<dependencies>

View File

@ -50,19 +50,26 @@ public class JSONParser {
public void parseTo(final JSONObject jsonObject, final Predicate<MutableEntry<String, Object>> predicate) {
final JSONTokener tokener = this.tokener;
char c;
String key;
if (tokener.nextClean() != '{') {
throw tokener.syntaxError("A JSONObject text must begin with '{'");
}
char prev;
char c;
String key;
while (true) {
prev = tokener.getPrevious();
c = tokener.nextClean();
switch (c) {
case 0:
throw tokener.syntaxError("A JSONObject text must end with '}'");
case '}':
return;
case '{':
case '[':
if(prev=='{') {
throw tokener.syntaxError("A JSONObject can not directly nest another JSONObject or JSONArray.");
}
default:
tokener.back();
key = tokener.nextValue().toString();

View File

@ -162,6 +162,15 @@ public class JSONTokener {
return this.previous;
}
/**
* Get the last character read from the input or '\0' if nothing has been read yet.
*
* @return the last character read from the input.
*/
protected char getPrevious() {
return this.previous;
}
/**
* 读取下一个字符并比对是否和指定字符匹配
*
@ -334,10 +343,18 @@ public class JSONTokener {
return this.nextString(c);
case '{':
this.back();
return new JSONObject(this, this.config);
try {
return new JSONObject(this, this.config);
} catch (final StackOverflowError e) {
throw new JSONException("JSONObject depth too large to process.", e);
}
case '[':
this.back();
return new JSONArray(this, this.config);
try {
return new JSONArray(this, this.config);
} catch (final StackOverflowError e) {
throw new JSONException("JSONArray depth too large to process.", e);
}
}
/*

View File

@ -113,9 +113,38 @@ public class XMLTokener extends JSONTokener {
throw syntaxError("Missing ';' in XML entity: &" + sb);
}
}
final String string = sb.toString();
final Object object = entity.get(string);
return object != null ? object : ampersand + string + ";";
return unescapeEntity(sb.toString());
}
/**
* Unescape an XML entity encoding;
*
* @param e entity (only the actual entity value, not the preceding & or ending ;
* @return Unescape str
*/
static String unescapeEntity(final String e) {
// validate
if (e == null || e.isEmpty()) {
return "";
}
// if our entity is an encoded unicode point, parse it.
if (e.charAt(0) == '#') {
final int cp;
if (e.charAt(1) == 'x' || e.charAt(1) == 'X') {
// hex encoded unicode
cp = Integer.parseInt(e.substring(2), 16);
} else {
// decimal encoded unicode
cp = Integer.parseInt(e.substring(1));
}
return new String(new int[]{cp}, 0, 1);
}
final Character knownEntity = entity.get(e);
if (knownEntity == null) {
// we don't know the entity so keep it encoded
return '&' + e + ';';
}
return knownEntity.toString();
}
/**

View File

@ -0,0 +1,24 @@
package cn.hutool.json;
import cn.hutool.core.text.StrUtil;
import org.junit.Assert;
import org.junit.Test;
public class Issue2746Test {
@Test
public void parseObjTest() {
final String str = StrUtil.repeat("{", 1500) + StrUtil.repeat("}", 1500);
try{
JSONUtil.parseObj(str);
} catch (final JSONException e){
Assert.assertTrue(e.getMessage().startsWith("A JSONObject can not directly nest another JSONObject or JSONArray"));
}
}
@Test(expected = JSONException.class)
public void parseTest() {
final String str = StrUtil.repeat("[", 1500) + StrUtil.repeat("]", 1500);
JSONUtil.parseArray(str);
}
}

View File

@ -0,0 +1,37 @@
package cn.hutool.json;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
/**
* https://github.com/dromara/hutool/issues/2749
* <p>
* 由于使用了递归方式解析和写出导致JSON太长的话容易栈溢出
*/
public class Issue2749Test {
@Test
@Ignore
public void jsonObjectTest() {
final Map<String, Object> map = new HashMap<>(1, 1f);
Map<String, Object> node = map;
for (int i = 0; i < 1000; i++) {
//noinspection unchecked
node = (Map<String, Object>) node.computeIfAbsent("a", k -> new HashMap<String, Object>(1, 1f));
}
node.put("a", 1);
final String jsonStr = JSONUtil.toJsonStr(map);
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
final JSONObject jsonObject = new JSONObject(jsonStr);
Assert.assertNotNull(jsonObject);
// 栈溢出
//noinspection ResultOfMethodCallIgnored
jsonObject.toString();
}
}