From bd51771193445d6981349223d100f5f16d9649d8 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Mon, 27 Jul 2026 14:03:52 +0100 Subject: [PATCH] SSE: allow Unicode line terminators (#1185) --- .../sse/ServerSentEventParserSpec.scala | 21 +++++++++++++++++++ .../sse/ServerSentEventParser.scala | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/unmarshalling/sse/ServerSentEventParserSpec.scala b/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/unmarshalling/sse/ServerSentEventParserSpec.scala index 855f43317f..bc23b40faa 100644 --- a/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/unmarshalling/sse/ServerSentEventParserSpec.scala +++ b/http-tests/src/test/scala/org/apache/pekko/http/scaladsl/unmarshalling/sse/ServerSentEventParserSpec.scala @@ -77,6 +77,27 @@ final class ServerSentEventParserSpec extends AsyncWordSpec with Matchers with B ServerSentEvent("event 3", None, Some("")), ServerSentEvent("event 4"))) } + "parse data values containing Unicode line terminators (U+0085, U+2028, U+2029)" in { + // WHATWG SSE spec: lines end only on CR/LF/CRLF; these Unicode chars are ordinary content + val nel = "\u0085" // NEL + val ls = "\u2028" // LINE SEPARATOR + val ps = "\u2029" // PARAGRAPH SEPARATOR + val input = Vector( + s"data: before${nel}after", + "", + s"data: before${ls}after", + "", + s"data: before${ps}after", + "") + Source(input) + .via(new ServerSentEventParser(1048576, emitEmptyEvents = false)) + .runWith(Sink.seq) + .map( + _ shouldBe Vector( + ServerSentEvent(s"before${nel}after"), + ServerSentEvent(s"before${ls}after"), + ServerSentEvent(s"before${ps}after"))) + } "parse ServerSentEvents correctly (and pass empty events)" in { val input = """|data: event 1 line 1 |data:event 1 line 2 diff --git a/http/src/main/scala/org/apache/pekko/http/scaladsl/unmarshalling/sse/ServerSentEventParser.scala b/http/src/main/scala/org/apache/pekko/http/scaladsl/unmarshalling/sse/ServerSentEventParser.scala index 6a9a8b0ed7..4f734e8c16 100644 --- a/http/src/main/scala/org/apache/pekko/http/scaladsl/unmarshalling/sse/ServerSentEventParser.scala +++ b/http/src/main/scala/org/apache/pekko/http/scaladsl/unmarshalling/sse/ServerSentEventParser.scala @@ -95,7 +95,7 @@ private object ServerSentEventParser { private final val Retry = "retry" - private val Field = """([^:]+): ?(.*)""".r + private val Field = """(?s)([^:]+): ?(.*)""".r } case class OversizedSseEvent(event: ServerSentEvent)