Skip to content

Commit a3ab584

Browse files
Apply Jackson stream read constraints defaults at runtime (#16832) (#16845)
When Logstash 8.12.0 added increased Jackson stream read constraints to jvm.options, assumptions about the existence of that file's contents were invalidated. This led to issues like #16683. This change ensures Logstash applies defaults from config at runtime: - MAX_STRING_LENGTH: 200_000_000 - MAX_NUMBER_LENGTH: 10_000 - MAX_NESTING_DEPTH: 1_000 These match the jvm.options defaults and are applied even when config is missing. Config values still override these defaults when present. (cherry picked from commit cc608eb) Co-authored-by: Cas Donoghue <[email protected]>
1 parent 1931c32 commit a3ab584

File tree

2 files changed

+45
-6
lines changed

2 files changed

+45
-6
lines changed

logstash-core/src/main/java/org/logstash/jackson/StreamReadConstraintsUtil.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ public class StreamReadConstraintsUtil {
1818

1919
private StreamReadConstraints configuredStreamReadConstraints;
2020

21+
// Provide default values for Jackson constraints in the case they are
22+
// not specified in configuration file.
23+
private static final Map<Override, Integer> JACKSON_DEFAULTS = Map.of(
24+
Override.MAX_STRING_LENGTH, 200_000_000,
25+
Override.MAX_NUMBER_LENGTH, 10_000,
26+
Override.MAX_NESTING_DEPTH, 1_000
27+
);
28+
2129
enum Override {
2230
MAX_STRING_LENGTH(StreamReadConstraints.Builder::maxStringLength, StreamReadConstraints::getMaxStringLength),
2331
MAX_NUMBER_LENGTH(StreamReadConstraints.Builder::maxNumberLength, StreamReadConstraints::getMaxNumberLength),
@@ -78,6 +86,8 @@ StreamReadConstraints get() {
7886
if (configuredStreamReadConstraints == null) {
7987
final StreamReadConstraints.Builder builder = StreamReadConstraints.defaults().rebuild();
8088

89+
// Apply the Jackson defaults first, then the overrides from config
90+
JACKSON_DEFAULTS.forEach((override, value) -> override.applicator.apply(builder, value));
8191
eachOverride((override, value) -> override.applicator.apply(builder, value));
8292

8393
this.configuredStreamReadConstraints = builder.build();

logstash-core/src/test/java/org/logstash/jackson/StreamReadConstraintsUtilTest.java

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ public class StreamReadConstraintsUtilTest {
2626
private ListAppender listAppender;
2727
private Logger observedLogger;
2828

29+
private static final int DEFAULT_MAX_STRING_LENGTH = 200_000_000;
30+
private static final int DEFAULT_MAX_NUMBER_LENGTH = 10_000;
31+
private static final int DEFAULT_MAX_NESTING_DEPTH = 1_000;
32+
2933
@Before
3034
public void setUpLoggingListAppender() {
3135
int i = 1+16;
@@ -51,8 +55,8 @@ public void configuresMaxStringLength() {
5155
assertThat(configuredConstraints).as("inherited defaults")
5256
.returns(defaults.getMaxDocumentLength(), from(StreamReadConstraints::getMaxDocumentLength))
5357
.returns(defaults.getMaxNameLength(), from(StreamReadConstraints::getMaxNameLength))
54-
.returns(defaults.getMaxNestingDepth(), from(StreamReadConstraints::getMaxNestingDepth))
55-
.returns(defaults.getMaxNumberLength(), from(StreamReadConstraints::getMaxNumberLength));
58+
.returns(DEFAULT_MAX_NESTING_DEPTH, from(StreamReadConstraints::getMaxNestingDepth))
59+
.returns(DEFAULT_MAX_NUMBER_LENGTH, from(StreamReadConstraints::getMaxNumberLength));
5660

5761
assertThatThrownBy(configuredUtil::validateIsGlobalDefault).isInstanceOf(IllegalStateException.class).hasMessageContaining(MAX_STRING_LENGTH.propertyName);
5862

@@ -94,8 +98,8 @@ public void configuresMaxNumberLength() {
9498
assertThat(configuredConstraints).as("inherited defaults")
9599
.returns(defaults.getMaxDocumentLength(), from(StreamReadConstraints::getMaxDocumentLength))
96100
.returns(defaults.getMaxNameLength(), from(StreamReadConstraints::getMaxNameLength))
97-
.returns(defaults.getMaxNestingDepth(), from(StreamReadConstraints::getMaxNestingDepth))
98-
.returns(defaults.getMaxStringLength(), from(StreamReadConstraints::getMaxStringLength));
101+
.returns(DEFAULT_MAX_NESTING_DEPTH, from(StreamReadConstraints::getMaxNestingDepth))
102+
.returns(DEFAULT_MAX_STRING_LENGTH, from(StreamReadConstraints::getMaxStringLength));
99103

100104
assertThatThrownBy(configuredUtil::validateIsGlobalDefault).isInstanceOf(IllegalStateException.class).hasMessageContaining(MAX_NUMBER_LENGTH.propertyName);
101105

@@ -137,8 +141,8 @@ public void configuresMaxNestingDepth() {
137141
assertThat(configuredConstraints).as("inherited defaults")
138142
.returns(defaults.getMaxDocumentLength(), from(StreamReadConstraints::getMaxDocumentLength))
139143
.returns(defaults.getMaxNameLength(), from(StreamReadConstraints::getMaxNameLength))
140-
.returns(defaults.getMaxStringLength(), from(StreamReadConstraints::getMaxStringLength))
141-
.returns(defaults.getMaxNumberLength(), from(StreamReadConstraints::getMaxNumberLength));
144+
.returns(DEFAULT_MAX_STRING_LENGTH, from(StreamReadConstraints::getMaxStringLength))
145+
.returns(DEFAULT_MAX_NUMBER_LENGTH, from(StreamReadConstraints::getMaxNumberLength));
142146

143147
assertThatThrownBy(configuredUtil::validateIsGlobalDefault).isInstanceOf(IllegalStateException.class).hasMessageContaining(MAX_NESTING_DEPTH.propertyName);
144148

@@ -193,6 +197,31 @@ public void validatesApplication() {
193197
assertLogObserved(Level.WARN, "override `" + PROP_PREFIX + "unsupported-option1` is unknown and has been ignored");
194198
}
195199

200+
@Test
201+
public void usesJacksonDefaultsWhenNoConfig() {
202+
StreamReadConstraintsUtil util = new StreamReadConstraintsUtil(new Properties(), this.observedLogger);
203+
StreamReadConstraints constraints = util.get();
204+
205+
assertThat(constraints)
206+
.returns(DEFAULT_MAX_STRING_LENGTH, from(StreamReadConstraints::getMaxStringLength))
207+
.returns(DEFAULT_MAX_NUMBER_LENGTH, from(StreamReadConstraints::getMaxNumberLength))
208+
.returns(DEFAULT_MAX_NESTING_DEPTH, from(StreamReadConstraints::getMaxNestingDepth));
209+
}
210+
211+
@Test
212+
public void configOverridesDefault() {
213+
Properties props = new Properties();
214+
props.setProperty("logstash.jackson.stream-read-constraints.max-string-length", "100");
215+
216+
StreamReadConstraintsUtil util = new StreamReadConstraintsUtil(props, this.observedLogger);
217+
StreamReadConstraints constraints = util.get();
218+
219+
assertThat(constraints)
220+
.returns(100, from(StreamReadConstraints::getMaxStringLength))
221+
.returns(DEFAULT_MAX_NUMBER_LENGTH, from(StreamReadConstraints::getMaxNumberLength))
222+
.returns(DEFAULT_MAX_NESTING_DEPTH, from(StreamReadConstraints::getMaxNestingDepth));
223+
}
224+
196225
private void assertLogObserved(final Level level, final String... messageFragments) {
197226
List<LogEvent> logEvents = listAppender.getEvents();
198227
assertThat(logEvents)

0 commit comments

Comments
 (0)