Fix buffer leak in Jackson2 decoders

Prior to this commit, the Jackson2 decoders (JSON, Smile, CBOR) could
leak buffers in case the decoding operation times out or is cancelled
and some buffers are still in flight.

This commit ensures that buffers are released on cancel signals.

Fixes gh-33731
This commit is contained in:
Brian Clozel
2024-10-18 10:51:38 +02:00
parent a55701588e
commit 912c067e23
2 changed files with 21 additions and 10 deletions

View File

@@ -116,7 +116,7 @@ class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonDecoder>
}
@Test // SPR-15866
public void canDecodeWithProvidedMimeType() {
void canDecodeWithProvidedMimeType() {
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
Jackson2JsonDecoder decoder = new Jackson2JsonDecoder(new ObjectMapper(), textJavascript);
@@ -222,7 +222,7 @@ class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonDecoder>
}
@Test // gh-22042
public void decodeWithNullLiteral() {
void decodeWithNullLiteral() {
Flux<Object> result = this.decoder.decode(Flux.concat(stringBuffer("null")),
ResolvableType.forType(Pojo.class), MediaType.APPLICATION_JSON, Collections.emptyMap());
@@ -230,7 +230,7 @@ class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonDecoder>
}
@Test // gh-27511
public void noDefaultConstructor() {
void noDefaultConstructor() {
Flux<DataBuffer> input = Flux.from(stringBuffer("{\"property1\":\"foo\",\"property2\":\"bar\"}"));
testDecode(input, BeanWithNoDefaultConstructor.class, step -> step
@@ -251,7 +251,7 @@ class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonDecoder>
}
@Test // SPR-15975
public void customDeserializer() {
void customDeserializer() {
Mono<DataBuffer> input = stringBuffer("{\"test\": 1}");
testDecode(input, TestObject.class, step -> step
@@ -272,7 +272,7 @@ class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonDecoder>
@Test
@SuppressWarnings("unchecked")
public void decodeNonUtf8Encoding() {
void decodeNonUtf8Encoding() {
Mono<DataBuffer> input = stringBuffer("{\"foo\":\"bar\"}", StandardCharsets.UTF_16);
ResolvableType type = ResolvableType.forType(new ParameterizedTypeReference<Map<String, String>>() {});
@@ -285,7 +285,7 @@ class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonDecoder>
@Test
@SuppressWarnings("unchecked")
public void decodeNonUnicode() {
void decodeNonUnicode() {
Flux<DataBuffer> input = Flux.concat(stringBuffer("{\"føø\":\"bår\"}", StandardCharsets.ISO_8859_1));
ResolvableType type = ResolvableType.forType(new ParameterizedTypeReference<Map<String, String>>() {});
@@ -298,7 +298,7 @@ class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonDecoder>
@Test
@SuppressWarnings("unchecked")
public void decodeMonoNonUtf8Encoding() {
void decodeMonoNonUtf8Encoding() {
Mono<DataBuffer> input = stringBuffer("{\"foo\":\"bar\"}", StandardCharsets.UTF_16);
ResolvableType type = ResolvableType.forType(new ParameterizedTypeReference<Map<String, String>>() {});
@@ -311,7 +311,7 @@ class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonDecoder>
@Test
@SuppressWarnings("unchecked")
public void decodeAscii() {
void decodeAscii() {
Flux<DataBuffer> input = Flux.concat(stringBuffer("{\"foo\":\"bar\"}", StandardCharsets.US_ASCII));
ResolvableType type = ResolvableType.forType(new ParameterizedTypeReference<Map<String, String>>() {});
@@ -322,6 +322,15 @@ class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonDecoder>
null);
}
@Test
void cancelWhileDecoding() {
Flux<DataBuffer> input = Flux.just(
stringBuffer("[{\"bar\":\"b1\",\"foo\":\"f1\"},").block(),
stringBuffer("{\"bar\":\"b2\",\"foo\":\"f2\"}]").block());
testDecodeCancel(input, ResolvableType.forClass(Pojo.class), null, null);
}
private Mono<DataBuffer> stringBuffer(String value) {
return stringBuffer(value, StandardCharsets.UTF_8);