question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ServerSentEvent support for data being a multi-line string and possible other ServerSentEvent enhancements

See original GitHub issue

For server sent events data can be multi-line and in that case multiple data: lines should be sent as outlined here https://html.spec.whatwg.org/multipage/server-sent-events.html

The current implementation only sends a single data: line followed by the entire data string. So if that data string

final case class ServerSentEvent(
    data: String,
    eventType: Option[String] = None,
    id: Option[EventId] = None,
    retry: Option[Long] = None
) extends Renderable {
  def render(writer: Writer): writer.type = {
    writer << "data: " << data << "\n"
    eventType.foreach(writer << "event: " << _ << "\n")
    id match {
      case None =>
      case Some(EventId.reset) => writer << "id\n"
      case Some(EventId(id)) => writer << "id: " << id << "\n"
    }
    retry.foreach(writer << "retry: " << _ << "\n")
    writer << "\n"
  }

  override def toString: String =
    s"ServerSentEvent($data,$eventType,$id,$retry)"
}

Here is the fix we are using in production noting it does a few more things than just fix the multi-line data issue that are worth considering i.e. comments and data is not required which allow for being a more complete sse implementation.

If these look good (or just the data fix only) I am happy to put together an MR. Noting sending comment lines is the idiomatic ping for sse so it is critical for any robust real world implementation of SSE.

data changing from String to Option[String] is likely a breaking change but a worthwhile one to do now to get a complete ServerSentEvent implementation. The change in http4s’s internals appears trivial (only a few places) clients using it though will break so it may be best to time that change with a larger version change.


  final case class ServerSentEvent(
      data: Option[String] = None,
      comment: Option[String] = None,
      eventType: Option[String] = None,
      id: Option[EventId] = None,
      retry: Option[FiniteDuration] = None
  ) extends Renderable {
    def render(writer: Writer): writer.type = {
      data.foreach ( _.linesIterator.foreach { dataLine =>
        writer << "data: " << dataLine << "\n"
      })
      comment.foreach(_.linesIterator.foreach { commentLine =>
        writer << ": " << commentLine << "\n"
      })
      eventType.foreach(writer << "event: " << _ << "\n")
      id match {
        case None =>
        case Some(EventId.reset) => writer << "id\n"
        case Some(EventId(id)) => writer << "id: " << id << "\n"
      }
      retry.foreach(writer << "retry: " << _.toMillis << "\n")
      writer << "\n"
    }

    override def toString: String =
      s"ServerSentEvent($data,$eventType,$id,$retry)"
  }

thoughts !?!?!

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
fizzy33commented, May 26, 2021

Now that we have added comment to ServerSentEvent we will need to apply the multi-line fix to that as well.

Noting this is mainly waiting on https://github.com/typelevel/fs2/pull/2418 to work it’s way out. As one can’t properly decode a server sent events response / protocol without the actual line endings. The fact that we assume a line is terminated by \n without really knowing causes some corner cases in the unit tests that will get cleaned up if/when we switch to the ultimate fs2.text.linesWithEndings solution

0reactions
rossabakercommented, May 26, 2021

Mostly done in #4888, but leaving open to track the nuance of preserving carriage returns.

Read more comments on GitHub >

github_iconTop Results From Across the Web

added fs2.text.linesWithEndings by fizzy33 · Pull Request #2418
ServerSentEvent support for data being a multi-line string and possible other ServerSentEvent enhancements http4s/http4s#4865.
Read more >
ServerSentEvent.Builder (Spring Framework 6.0.2 API)
If the data argument is a multi-line String , it will be turned into multiple data field lines as defined in the Server-Sent...
Read more >
How to create a server sent event using spring web-flux
Typically Server Sent Events are used to subscribe to continuous stream of data. In your case this is just a single call to...
Read more >
Server Sent Events - The Modern JavaScript Tutorial
The Server-Sent Events specification describes a built-in class EventSource , that keeps connection with the server and allows to receive ...
Read more >
Using server-sent events - Web APIs | MDN
The server-sent event API is contained in the EventSource interface; ... of course, have any string data; it doesn't have to be JSON....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found