Skip to content

Commit 9eefdb8

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 c50cb10 commit 9eefdb8

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
@@ -425,6 +425,11 @@ public void startDeferredResultProcessing(
425425
}
426426
try {
427427
interceptorChain.triggerAfterTimeout(this.asyncWebRequest, deferredResult);
428+
synchronized (WebAsyncManager.this) {
429+
// If application thread set the DeferredResult first in a race,
430+
// we must still not return until setConcurrentResultAndDispatch is done
431+
return;
432+
}
428433
}
429434
catch (Throwable ex) {
430435
setConcurrentResultAndDispatch(ex);
@@ -437,6 +442,11 @@ public void startDeferredResultProcessing(
437442
}
438443
try {
439444
interceptorChain.triggerAfterError(this.asyncWebRequest, deferredResult, ex);
445+
synchronized (WebAsyncManager.this) {
446+
// If application thread set the DeferredResult first in a race,
447+
// we must still not return until setConcurrentResultAndDispatch is done
448+
return;
449+
}
440450
}
441451
catch (Throwable interceptorEx) {
442452
setConcurrentResultAndDispatch(interceptorEx);

0 commit comments

Comments
 (0)