When I was using SseEventBuilder in spring mvc 5.3.x, I noticed that no spaces were added when constructing "data:" in the data method of the SseEventBuilderImpl implementation class. As a result, when the output is in markdown format, when the content that starts with a space appears in the segmented interception, the space will be lost on the front end. When reviewing the protocol standards of SSE, it was found that when a space appears after ":" in the content, the space is removed. See server-sent-events 9.2.6, which references
If the line starts with a U+003A COLON character (:) Ignore the line. If the line contains a U+003A COLON character (:) Collect the characters on the line before the first U+003A COLON character (:), and let be that string.field Collect the characters on the line after the first U+003A COLON character (:), and let be that string. If starts with a U+0020 SPACE character, remove it from .valuevaluevalue
So I suggest modifying append("data:")
in the SseEventBuilderImpl.data
method of spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/SseEmitter.java
to append("data: ");
The other versions are modified in the same way
Comment From: quaff
According to the reference, data:value
is same to data: value
, why do you think data:value
is not standards compliant?
Comment From: bclozel
Spring Framework is sending valid SSE chunks. In this case, I think the application is responsible for encoding/escaping the payloads to account for this.
Comment From: icguy
the application is responsible for encoding/escaping the payloads to account for this
I believe this is incorrect. Spring is sending valid SSE chunks but they do not contain the supplied payload. I've implemented a minimal reproduction: https://github.com/icguy/spring33963
val payloads = listOf("These", " words", " should", " arrive", " with", " spaces", " between", " them")
val emitter = SseEmitter()
thread {
for (p in payloads) {
val event = SseEmitter.event().data(p).build()
emitter.send(event)
}
emitter.complete()
}
return emitter
As you can see the payload for most events starts with a space character.
This is the raw response:
data:These
data: words
data: should
data: arrive
data: with
data: spaces
data: between
data: them
But according to the spec during parsing on the client side if value starts with a U+0020 SPACE character, remove it from value.
This is the behavior of the minimal client I wrote to demonstrate the issue (also in the repository) which simply concatenates the values received via an EventSource object:
So in conclusion: no, Spring doesn't send the payload in a standard compliant manner unless the intention was to implicitly drop a leading space from the payload.
Comment From: bclozel
@icguy SseEmitter
can accept many types as data. If you are providing such strings directly, I would argue that managing the space character here should be done by your implementation.
Comment From: icguy
I don't think it's unreasonable for an API consumer to expect to receive on the client side exactly what they specified on the server side.
Is there a particular reason against the originally proposed solution of replacing data:
with data:
?
Comment From: bclozel
I'd say that both are completely standard, but if we make this behavior change we might break existing applications that already take this into account. Other contributors could say that data:
is perfectly valid and is the minimum that the server side should do, and by forcing data:
we take away an application choice.