From 256a6fe6cbf4c9aa827db4191a5a7189bc137a18 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Wed, 24 Oct 2018 16:54:07 +0200 Subject: [PATCH] Fix memory leak for ServerSentEventHttpMessageWriter This commit fixes a memory leak in ServerSentEventHttpMessageWriter that occurs when the input stream contains an error. Test added as well. Issue: SPR-17419 --- .../ServerSentEventHttpMessageWriter.java | 4 +-- ...ServerSentEventHttpMessageWriterTests.java | 27 ++++++++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java index f10a88c70c8..fba05c19414 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java @@ -180,8 +180,8 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter encodeText(CharSequence text, MediaType mediaType, DataBufferFactory bufferFactory) { Assert.notNull(mediaType.getCharset(), "Expected MediaType with charset"); byte[] bytes = text.toString().getBytes(mediaType.getCharset()); - DataBuffer buffer = bufferFactory.allocateBuffer(bytes.length).write(bytes); - return Mono.just(buffer); + return Mono.defer(() -> + Mono.just(bufferFactory.allocateBuffer(bytes.length).write(bytes))); } @Override diff --git a/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageWriterTests.java b/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageWriterTests.java index 6e392913653..340ae2526f2 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageWriterTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageWriterTests.java @@ -37,7 +37,7 @@ import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse; import static org.junit.Assert.*; -import static org.springframework.core.ResolvableType.*; +import static org.springframework.core.ResolvableType.forClass; /** * Unit tests for {@link ServerSentEventHttpMessageWriter}. @@ -81,6 +81,24 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll .verify(); } + @Test + @SuppressWarnings("rawtypes") + public void writeServerSentEventError() { + ServerSentEvent event = ServerSentEvent.builder().data("bar").id("c42").event("foo") + .comment("bla\nbla bla\nbla bla bla").retry(Duration.ofMillis(123L)).build(); + + Flux source = Flux.concat( + Flux.just(event), + Flux.error(new RuntimeException())); + MockServerHttpResponse outputMessage = new MockServerHttpResponse(); + + Mono result = this.messageWriter.write(source, forClass(ServerSentEvent.class), + MediaType.TEXT_EVENT_STREAM, outputMessage, HINTS); + + StepVerifier.create(result) + .verifyError(RuntimeException.class); + } + @Test public void writeString() { Flux source = Flux.just("foo", "bar"); @@ -172,8 +190,11 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll private void testWrite( Publisher source, MediaType mediaType, MockServerHttpResponse response, Class clazz) { - this.messageWriter.write(source, forClass(clazz), mediaType, response, HINTS) - .block(Duration.ofMillis(5000)); + Mono result = + this.messageWriter.write(source, forClass(clazz), mediaType, response, HINTS); + + StepVerifier.create(result) + .verifyComplete(); } }