Skip to content

Commit 568c934

Browse files
committed
Improve ResponseBodyEmitter error handling
After send error, ignore calls to complete or completeWithError by the application in the same thread (e.g. try-catch block), to avoid a competing with an error callback from servlet container during which the same action is taken. Issue: SPR-16548
1 parent e206520 commit 568c934

File tree

1 file changed

+17
-0
lines changed

1 file changed

+17
-0
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitter.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ public class ResponseBodyEmitter {
7979
@Nullable
8080
private Throwable failure;
8181

82+
/**
83+
* After an IOException on send, the servlet container will provide an onError
84+
* callback that we'll handle as completeWithError (on container thread).
85+
* We use this flag to ignore competing attempts to completeWithError by
86+
* the application via try-catch. */
87+
private boolean sendFailed;
88+
8289
private final DefaultCallback timeoutCallback = new DefaultCallback();
8390

8491
private final ErrorCallback errorCallback = new ErrorCallback();
@@ -182,9 +189,11 @@ private void sendInternal(Object object, @Nullable MediaType mediaType) throws I
182189
this.handler.send(object, mediaType);
183190
}
184191
catch (IOException ex) {
192+
this.sendFailed = true;
185193
throw ex;
186194
}
187195
catch (Throwable ex) {
196+
this.sendFailed = true;
188197
throw new IllegalStateException("Failed to send " + object, ex);
189198
}
190199
}
@@ -202,6 +211,10 @@ private void sendInternal(Object object, @Nullable MediaType mediaType) throws I
202211
* related events such as an error while {@link #send(Object) sending}.
203212
*/
204213
public synchronized void complete() {
214+
// Ignore, after send failure
215+
if (this.sendFailed) {
216+
return;
217+
}
205218
this.complete = true;
206219
if (this.handler != null) {
207220
this.handler.complete();
@@ -220,6 +233,10 @@ public synchronized void complete() {
220233
* {@link #send(Object) sending}.
221234
*/
222235
public synchronized void completeWithError(Throwable ex) {
236+
// Ignore, after send failure
237+
if (this.sendFailed) {
238+
return;
239+
}
223240
this.complete = true;
224241
this.failure = ex;
225242
if (this.handler != null) {

0 commit comments

Comments
 (0)