Skip to content

Commit 9140ed6

Browse files
committed
Fix SSE flushing in SseServerResponse
Prior to this commit, `SseServerResponse.send()` would flush the output stream returned by `getBody()`. Since gh-36385, `ServletServerHttpResponse` wraps this stream with a non-flushing decorator to avoid performance issues with `HttpMessageConverter` implementations that flush excessively. As a result, SSE events were no longer flushed to the client. This commit changes `send()` to call `outputMessage.flush()` instead of `body.flush()`, which properly delegates to the servlet response `flushBuffer()` and is not affected by the non-flushing wrapper. Fixes gh-36537
1 parent 6cea397 commit 9140ed6

2 files changed

Lines changed: 37 additions & 4 deletions

File tree

spring-webmvc/src/main/java/org/springframework/web/servlet/function/SseServerResponse.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.springframework.web.servlet.function;
1818

1919
import java.io.IOException;
20-
import java.io.OutputStream;
2120
import java.nio.charset.StandardCharsets;
2221
import java.time.Duration;
2322
import java.util.Collections;
@@ -137,9 +136,8 @@ public void send(Object object) throws IOException {
137136
public void send() throws IOException {
138137
this.builder.append('\n');
139138
try {
140-
OutputStream body = this.outputMessage.getBody();
141-
body.write(builderBytes());
142-
body.flush();
139+
this.outputMessage.getBody().write(builderBytes());
140+
this.outputMessage.flush();
143141
}
144142
catch (IOException ex) {
145143
this.sendFailed = true;

spring-webmvc/src/test/java/org/springframework/web/servlet/function/SseServerResponseTests.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,41 @@ void sendString() throws Exception {
7575
assertThat(this.mockResponse.getContentAsString()).isEqualTo(expected);
7676
}
7777

78+
@Test // gh-36537
79+
void sendStringFlushesResponse() throws Exception {
80+
ServerResponse response = ServerResponse.sse(sse -> {
81+
try {
82+
sse.send("foo bar");
83+
}
84+
catch (IOException ex) {
85+
throw new UncheckedIOException(ex);
86+
}
87+
});
88+
89+
ServerResponse.Context context = Collections::emptyList;
90+
91+
response.writeTo(this.mockRequest, this.mockResponse, context);
92+
assertThat(this.mockResponse.isCommitted()).isTrue();
93+
}
94+
95+
@Test // gh-36537
96+
void sendObjectFlushesResponse() throws Exception {
97+
Person person = new Person("John Doe", 42);
98+
ServerResponse response = ServerResponse.sse(sse -> {
99+
try {
100+
sse.send(person);
101+
}
102+
catch (IOException ex) {
103+
throw new UncheckedIOException(ex);
104+
}
105+
});
106+
107+
ServerResponse.Context context = () -> List.of(new JacksonJsonHttpMessageConverter());
108+
109+
response.writeTo(this.mockRequest, this.mockResponse, context);
110+
assertThat(this.mockResponse.isCommitted()).isTrue();
111+
}
112+
78113
@Test
79114
void sendObject() throws Exception {
80115
Person person = new Person("John Doe", 42);

0 commit comments

Comments
 (0)