Skip to content

Commit b60c7e8

Browse files
authored
Merge pull request #1131 from HubSpot/length-limit-tojson-filter
Add length-limiting to ToJsonFilter to avoid serializing too large a value
2 parents c34b97d + a6de2e2 commit b60c7e8

File tree

3 files changed

+64
-15
lines changed

3 files changed

+64
-15
lines changed

src/main/java/com/hubspot/jinjava/lib/filter/ToJsonFilter.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
package com.hubspot.jinjava.lib.filter;
22

3-
import com.fasterxml.jackson.core.JsonProcessingException;
43
import com.hubspot.jinjava.doc.annotations.JinjavaDoc;
54
import com.hubspot.jinjava.doc.annotations.JinjavaParam;
65
import com.hubspot.jinjava.doc.annotations.JinjavaSnippet;
76
import com.hubspot.jinjava.interpret.DeferredValueException;
87
import com.hubspot.jinjava.interpret.InvalidInputException;
98
import com.hubspot.jinjava.interpret.InvalidReason;
109
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
10+
import com.hubspot.jinjava.objects.serialization.LengthLimitingWriter;
11+
import com.hubspot.jinjava.objects.serialization.PyishObjectMapper;
12+
import java.io.CharArrayWriter;
13+
import java.io.IOException;
14+
import java.io.Writer;
15+
import java.util.concurrent.atomic.AtomicInteger;
1116

1217
@JinjavaDoc(
1318
value = "Writes object as a JSON string",
@@ -23,11 +28,21 @@ public class ToJsonFilter implements Filter {
2328
@Override
2429
public Object filter(Object var, JinjavaInterpreter interpreter, String... args) {
2530
try {
26-
return interpreter.getConfig().getObjectMapper().writeValueAsString(var);
27-
} catch (JsonProcessingException e) {
31+
if (interpreter.getConfig().getMaxOutputSize() > 0) {
32+
AtomicInteger remainingLength = new AtomicInteger(
33+
(int) Math.min(Integer.MAX_VALUE, interpreter.getConfig().getMaxOutputSize())
34+
);
35+
Writer writer = new LengthLimitingWriter(new CharArrayWriter(), remainingLength);
36+
interpreter.getConfig().getObjectMapper().writeValue(writer, var);
37+
return writer.toString();
38+
} else {
39+
return interpreter.getConfig().getObjectMapper().writeValueAsString(var);
40+
}
41+
} catch (IOException e) {
2842
if (e.getCause() instanceof DeferredValueException) {
2943
throw (DeferredValueException) e.getCause();
3044
}
45+
PyishObjectMapper.handleLengthLimitingException(e);
3146
throw new InvalidInputException(interpreter, this, InvalidReason.JSON_WRITE);
3247
}
3348
}

src/main/java/com/hubspot/jinjava/objects/serialization/PyishObjectMapper.java

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,22 +67,26 @@ private static String getAsPyishString(Object val, boolean forOutput) {
6767
try {
6868
return getAsPyishStringOrThrow(val, forOutput);
6969
} catch (IOException e) {
70-
Throwable unwrapped = e;
71-
if (e instanceof JsonMappingException) {
72-
unwrapped = unwrapped.getCause();
73-
}
74-
if (unwrapped instanceof LengthLimitingJsonProcessingException) {
75-
throw new OutputTooBigException(
76-
((LengthLimitingJsonProcessingException) unwrapped).getMaxSize(),
77-
((LengthLimitingJsonProcessingException) unwrapped).getAttemptedSize()
78-
);
79-
} else if (unwrapped instanceof OutputTooBigException) {
80-
throw (OutputTooBigException) unwrapped;
81-
}
70+
handleLengthLimitingException(e);
8271
return Objects.toString(val, "");
8372
}
8473
}
8574

75+
public static void handleLengthLimitingException(IOException e) {
76+
Throwable unwrapped = e;
77+
if (e instanceof JsonMappingException) {
78+
unwrapped = unwrapped.getCause();
79+
}
80+
if (unwrapped instanceof LengthLimitingJsonProcessingException) {
81+
throw new OutputTooBigException(
82+
((LengthLimitingJsonProcessingException) unwrapped).getMaxSize(),
83+
((LengthLimitingJsonProcessingException) unwrapped).getAttemptedSize()
84+
);
85+
} else if (unwrapped instanceof OutputTooBigException) {
86+
throw (OutputTooBigException) unwrapped;
87+
}
88+
}
89+
8690
public static String getAsPyishStringOrThrow(Object val) throws IOException {
8791
return getAsPyishStringOrThrow(val, false);
8892
}

src/test/java/com/hubspot/jinjava/lib/filter/ToJsonFilterTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
import static org.assertj.core.api.Java6Assertions.assertThat;
44

55
import com.hubspot.jinjava.BaseInterpretingTest;
6+
import com.hubspot.jinjava.Jinjava;
7+
import com.hubspot.jinjava.JinjavaConfig;
8+
import com.hubspot.jinjava.interpret.OutputTooBigException;
9+
import java.util.ArrayList;
610
import java.util.LinkedHashMap;
11+
import java.util.List;
712
import java.util.Map;
813
import org.junit.Before;
914
import org.junit.Test;
@@ -27,4 +32,29 @@ public void itWritesObjectAsString() {
2732
assertThat(filter.filter(testMap, interpreter))
2833
.isEqualTo("{\"testArray\":[4,1,2],\"testString\":\"testString\"}");
2934
}
35+
36+
@Test
37+
public void itLimitsLength() {
38+
List<List<?>> original = new ArrayList<>();
39+
List<List<?>> temp = original;
40+
for (int i = 0; i < 100; i++) {
41+
List<List<?>> nested = new ArrayList<>();
42+
temp.add(nested);
43+
temp = nested;
44+
}
45+
interpreter =
46+
new Jinjava(JinjavaConfig.newBuilder().withMaxOutputSize(500).build())
47+
.newInterpreter();
48+
assertThat(filter.filter(original, interpreter)).asString().contains("[[]]]]");
49+
for (int i = 0; i < 400; i++) {
50+
List<List<?>> nested = new ArrayList<>();
51+
temp.add(nested);
52+
temp = nested;
53+
}
54+
try {
55+
filter.filter(original, interpreter);
56+
} catch (Exception e) {
57+
assertThat(e).isInstanceOf(OutputTooBigException.class);
58+
}
59+
}
3060
}

0 commit comments

Comments
 (0)