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> <properties>
<!-- versions --> <!-- versions -->
<bouncycastle.version>1.71</bouncycastle.version> <bouncycastle.version>1.72</bouncycastle.version>
</properties> </properties>
<dependencies> <dependencies>

View File

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

View File

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

View File

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

View File

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

View File

@ -162,6 +162,15 @@ public class JSONTokener {
return this.previous; 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); return this.nextString(c);
case '{': case '{':
this.back(); 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 '[': case '[':
this.back(); 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); throw syntaxError("Missing ';' in XML entity: &" + sb);
} }
} }
final String string = sb.toString(); return unescapeEntity(sb.toString());
final Object object = entity.get(string); }
return object != null ? object : ampersand + string + ";";
/**
* 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();
}
}