From 6b3052200a2a476a3fdbc41dc4f3cbf2080dfc14 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 12 Jan 2022 16:35:42 +0100 Subject: [PATCH] Skip "data:" lines without content Closes gh-27923 --- .../ServerSentEventHttpMessageReader.java | 22 ++++++++------- ...ServerSentEventHttpMessageReaderTests.java | 28 ++++++++++--------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java index d21ec4fe61..f012b92839 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,6 +42,7 @@ import org.springframework.lang.Nullable; * * @author Sebastien Deleuze * @author Rossen Stoyanchev + * @author Juergen Hoeller * @since 5.0 */ public class ServerSentEventHttpMessageReader implements HttpMessageReader { @@ -140,22 +141,23 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader lines, ResolvableType valueType, boolean shouldWrap, Map hints) { - ServerSentEvent.Builder sseBuilder = shouldWrap ? ServerSentEvent.builder() : null; + ServerSentEvent.Builder sseBuilder = (shouldWrap ? ServerSentEvent.builder() : null); StringBuilder data = null; StringBuilder comment = null; for (String line : lines) { if (line.startsWith("data:")) { - data = (data != null ? data : new StringBuilder()); - if (line.charAt(5) != ' ') { - data.append(line, 5, line.length()); + int length = line.length(); + if (length > 5) { + int index = (line.charAt(5) != ' ' ? 5 : 6); + if (length > index) { + data = (data != null ? data : new StringBuilder()); + data.append(line, index, line.length()); + data.append('\n'); + } } - else { - data.append(line, 6, line.length()); - } - data.append('\n'); } - if (shouldWrap) { + else if (shouldWrap) { if (line.startsWith("id:")) { sseBuilder.id(line.substring(3).trim()); } diff --git a/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageReaderTests.java b/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageReaderTests.java index 82602a526e..9079ea3896 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageReaderTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageReaderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; * Unit tests for {@link ServerSentEventHttpMessageReader}. * * @author Sebastien Deleuze + * @author Juergen Hoeller */ public class ServerSentEventHttpMessageReaderTests extends AbstractLeakCheckingTests { @@ -66,7 +67,7 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractLeakCheckingT MockServerHttpRequest request = MockServerHttpRequest.post("/") .body(Mono.just(stringBuffer( "id:c42\nevent:foo\nretry:123\n:bla\n:bla bla\n:bla bla bla\ndata:bar\n\n" + - "id:c43\nevent:bar\nretry:456\ndata:baz\n\n"))); + "id:c43\nevent:bar\nretry:456\ndata:baz\n\ndata:\n\ndata: \n\n"))); Flux events = this.reader .read(ResolvableType.forClassWithGenerics(ServerSentEvent.class, String.class), @@ -87,6 +88,8 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractLeakCheckingT assertThat(event.comment()).isNull(); assertThat(event.data()).isEqualTo("baz"); }) + .consumeNextWith(event -> assertThat(event.data()).isNull()) + .consumeNextWith(event -> assertThat(event.data()).isNull()) .expectComplete() .verify(); } @@ -175,7 +178,7 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractLeakCheckingT .verify(); } - @Test // gh-24389 + @Test // gh-24389 void readPojoWithCommentOnly() { MockServerHttpRequest request = MockServerHttpRequest.post("/") .body(Flux.just(stringBuffer(":ping\n"), stringBuffer("\n"))); @@ -221,7 +224,6 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractLeakCheckingT @Test public void maxInMemoryLimit() { - this.reader.setMaxInMemorySize(17); MockServerHttpRequest request = MockServerHttpRequest.post("/") @@ -235,9 +237,8 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractLeakCheckingT .verify(); } - @Test // gh-24312 + @Test // gh-24312 public void maxInMemoryLimitAllowsReadingPojoLargerThanDefaultSize() { - int limit = this.jsonDecoder.getMaxInMemorySize(); String fooValue = getStringOfSize(limit) + "and then some more"; @@ -259,13 +260,6 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractLeakCheckingT .verify(); } - private static String getStringOfSize(long size) { - StringBuilder content = new StringBuilder("Aa"); - while (content.length() < size) { - content.append(content); - } - return content.toString(); - } private DataBuffer stringBuffer(String value) { byte[] bytes = value.getBytes(StandardCharsets.UTF_8); @@ -274,4 +268,12 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractLeakCheckingT return buffer; } + private static String getStringOfSize(long size) { + StringBuilder content = new StringBuilder("Aa"); + while (content.length() < size) { + content.append(content); + } + return content.toString(); + } + }