This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch 4.1.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/4.1.x-fixes by this push:
new 9f5c37e2928 Apply the JSON depth limit to writes as well (#3152)
9f5c37e2928 is described below
commit 9f5c37e29287a5ed6be9cc1152056747e4951e2c
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Thu May 28 14:54:38 2026 +0100
Apply the JSON depth limit to writes as well (#3152)
(cherry picked from commit 51b7f0d087a075de17af044c87cf9ce6be002fe7)
---
.../json/basic/JsonMapObjectReaderWriter.java | 45 +++++++++++++++++-----
.../json/basic/JsonMapObjectReaderWriterTest.java | 16 ++++++++
2 files changed, 51 insertions(+), 10 deletions(-)
diff --git
a/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
b/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
index 7ea3ca1d926..f83e48ad3ad 100644
---
a/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
+++
b/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
@@ -75,13 +75,13 @@ public class JsonMapObjectReaderWriter {
public String toJson(Map<String, Object> map) {
StringBuilder sb = new StringBuilder();
- toJsonInternal(new StringBuilderOutput(sb), map);
+ toJsonInternal(new StringBuilderOutput(sb), map, 0);
return sb.toString();
}
public String toJson(List<Object> list) {
StringBuilder sb = new StringBuilder();
- toJsonInternal(new StringBuilderOutput(sb), list);
+ toJsonInternal(new StringBuilderOutput(sb), list, 0);
return sb.toString();
}
@@ -90,29 +90,49 @@ public class JsonMapObjectReaderWriter {
}
public void toJson(Map<String, Object> map, OutputStream os) {
- toJsonInternal(new StreamOutput(os), map);
+ toJsonInternal(new StreamOutput(os), map, 0);
}
protected void toJsonInternal(Output out, Map<String, Object> map) {
+ toJsonInternal(out, map, 0);
+ }
+
+ private void toJsonInternal(Output out, Map<String, Object> map, int
depth) {
+ if (depth > MAX_RECURSION_DEPTH) {
+ throw new UncheckedIOException(new IOException(
+ "JSON nesting depth exceeds maximum of " +
MAX_RECURSION_DEPTH));
+ }
out.append(OBJECT_START);
for (Iterator<Map.Entry<String, Object>> it =
map.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, Object> entry = it.next();
out.append(DQUOTE).append(escapeJson(entry.getKey())).append(DQUOTE);
out.append(COLON);
- toJsonInternal(out, entry.getValue(), it.hasNext());
+ toJsonInternal(out, entry.getValue(), it.hasNext(), depth);
}
out.append(OBJECT_END);
}
protected void toJsonInternal(Output out, Object[] array) {
- toJsonInternal(out, Arrays.asList(array));
+ toJsonInternal(out, array, 0);
+ }
+
+ private void toJsonInternal(Output out, Object[] array, int depth) {
+ toJsonInternal(out, Arrays.asList(array), depth);
}
protected void toJsonInternal(Output out, Collection<?> coll) {
+ toJsonInternal(out, coll, 0);
+ }
+
+ private void toJsonInternal(Output out, Collection<?> coll, int depth) {
+ if (depth > MAX_RECURSION_DEPTH) {
+ throw new UncheckedIOException(new IOException(
+ "JSON nesting depth exceeds maximum of " +
MAX_RECURSION_DEPTH));
+ }
out.append(ARRAY_START);
formatIfNeeded(out);
for (Iterator<?> iter = coll.iterator(); iter.hasNext();) {
- toJsonInternal(out, iter.next(), iter.hasNext());
+ toJsonInternal(out, iter.next(), iter.hasNext(), depth);
}
formatIfNeeded(out);
out.append(ARRAY_END);
@@ -120,16 +140,21 @@ public class JsonMapObjectReaderWriter {
@SuppressWarnings("unchecked")
protected void toJsonInternal(Output out, Object value, boolean hasNext) {
+ toJsonInternal(out, value, hasNext, 0);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void toJsonInternal(Output out, Object value, boolean hasNext, int
depth) {
if (value == null) {
out.append(null);
} else if (JsonMapObject.class.isAssignableFrom(value.getClass())) {
- out.append(toJson((JsonMapObject)value));
+ toJsonInternal(out, ((JsonMapObject)value).asMap(), depth + 1);
} else if (value.getClass().isArray()) {
- toJsonInternal(out, (Object[])value);
+ toJsonInternal(out, (Object[])value, depth + 1);
} else if (Collection.class.isAssignableFrom(value.getClass())) {
- toJsonInternal(out, (Collection<?>)value);
+ toJsonInternal(out, (Collection<?>)value, depth + 1);
} else if (Map.class.isAssignableFrom(value.getClass())) {
- toJsonInternal(out, (Map<String, Object>)value);
+ toJsonInternal(out, (Map<String, Object>)value, depth + 1);
} else {
boolean quotesNeeded = checkQuotesNeeded(value);
if (quotesNeeded) {
diff --git
a/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
b/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
index a8583cce40e..805f56b5c2f 100644
---
a/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
+++
b/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
@@ -430,4 +430,20 @@ public class JsonMapObjectReaderWriterTest {
new JsonMapObjectReaderWriter().fromJson(sb.toString());
}
+ @Test(expected = UncheckedIOException.class)
+ public void testWriterPathDeeplyNestedMapThrowsUncheckedIOException() {
+ new JsonMapObjectReaderWriter().toJson(createNestedMap(20000));
+ }
+
+ private Map<String, Object> createNestedMap(int depth) {
+ Map<String, Object> root = new HashMap<>();
+ Map<String, Object> current = root;
+ for (int i = 0; i < depth; i++) {
+ Map<String, Object> child = new HashMap<>();
+ current.put("k", child);
+ current = child;
+ }
+ return root;
+ }
+
}