Skip to content

Commit 6ec7dcf

Browse files
committed
Synchronize in WebAsyncManager onError/onTimeout
On connection loss, in a race between application thread and onError callback trying to set the DeferredResult and dispatch, the onError callback must not exit until dispatch completes. Currently, it may do so because the DeferredResult has checks to bypasses locking or even trying to dispatch if result is already set. Closes gh-34192
1 parent d94e04d commit 6ec7dcf

File tree

1 file changed

+10
-0
lines changed

1 file changed

+10
-0
lines changed

spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java

+10
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,11 @@ public void startDeferredResultProcessing(
427427
}
428428
try {
429429
interceptorChain.triggerAfterTimeout(this.asyncWebRequest, deferredResult);
430+
synchronized (WebAsyncManager.this) {
431+
// If application thread set the DeferredResult first in a race,
432+
// we must still not return until setConcurrentResultAndDispatch is done
433+
return;
434+
}
430435
}
431436
catch (Throwable ex) {
432437
setConcurrentResultAndDispatch(ex);
@@ -439,6 +444,11 @@ public void startDeferredResultProcessing(
439444
}
440445
try {
441446
interceptorChain.triggerAfterError(this.asyncWebRequest, deferredResult, ex);
447+
synchronized (WebAsyncManager.this) {
448+
// If application thread set the DeferredResult first in a race,
449+
// we must still not return until setConcurrentResultAndDispatch is done
450+
return;
451+
}
442452
}
443453
catch (Throwable interceptorEx) {
444454
setConcurrentResultAndDispatch(interceptorEx);

0 commit comments

Comments
 (0)