Avoid deadlock between SockJS heartbeat and XHR polling
Issue: SPR-14833
This commit is contained in:
parent
bf9083d60f
commit
72e1f7e898
|
@ -51,6 +51,7 @@ import org.springframework.web.socket.sockjs.transport.SockJsServiceConfig;
|
|||
*/
|
||||
public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession {
|
||||
|
||||
private final Queue<String> messageCache;
|
||||
|
||||
private volatile URI uri;
|
||||
|
||||
|
@ -64,20 +65,13 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession {
|
|||
|
||||
private volatile String acceptedProtocol;
|
||||
|
||||
|
||||
private volatile ServerHttpResponse response;
|
||||
|
||||
private volatile SockJsFrameFormat frameFormat;
|
||||
|
||||
|
||||
private volatile ServerHttpAsyncRequestControl asyncRequestControl;
|
||||
|
||||
private final Object responseLock = new Object();
|
||||
|
||||
private volatile boolean readyToSend;
|
||||
|
||||
|
||||
private final Queue<String> messageCache;
|
||||
private boolean readyToSend;
|
||||
|
||||
|
||||
public AbstractHttpSockJsSession(String id, SockJsServiceConfig config,
|
||||
|
@ -209,14 +203,10 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession {
|
|||
this.frameFormat = frameFormat;
|
||||
this.asyncRequestControl = request.getAsyncRequestControl(response);
|
||||
this.asyncRequestControl.start(-1);
|
||||
|
||||
disableShallowEtagHeaderFilter(request);
|
||||
|
||||
// Let "our" handler know before sending the open frame to the remote handler
|
||||
delegateConnectionEstablished();
|
||||
|
||||
handleRequestInternal(request, response, true);
|
||||
|
||||
// Request might have been reset (e.g. polling sessions do after writing)
|
||||
this.readyToSend = isActive();
|
||||
}
|
||||
|
@ -252,9 +242,7 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession {
|
|||
this.frameFormat = frameFormat;
|
||||
this.asyncRequestControl = request.getAsyncRequestControl(response);
|
||||
this.asyncRequestControl.start(-1);
|
||||
|
||||
disableShallowEtagHeaderFilter(request);
|
||||
|
||||
handleRequestInternal(request, response, false);
|
||||
this.readyToSend = isActive();
|
||||
}
|
||||
|
@ -318,14 +306,11 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession {
|
|||
|
||||
protected void resetRequest() {
|
||||
synchronized (this.responseLock) {
|
||||
|
||||
ServerHttpAsyncRequestControl control = this.asyncRequestControl;
|
||||
this.asyncRequestControl = null;
|
||||
this.readyToSend = false;
|
||||
this.response = null;
|
||||
|
||||
updateLastActiveTime();
|
||||
|
||||
if (control != null && !control.isCompleted()) {
|
||||
if (control.isStarted()) {
|
||||
try {
|
||||
|
|
|
@ -91,6 +91,8 @@ public abstract class AbstractSockJsSession implements SockJsSession {
|
|||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected final Object responseLock = new Object();
|
||||
|
||||
private final String id;
|
||||
|
||||
private final SockJsServiceConfig config;
|
||||
|
@ -109,8 +111,6 @@ public abstract class AbstractSockJsSession implements SockJsSession {
|
|||
|
||||
private HeartbeatTask heartbeatTask;
|
||||
|
||||
private final Object heartbeatLock = new Object();
|
||||
|
||||
private volatile boolean heartbeatDisabled;
|
||||
|
||||
|
||||
|
@ -250,7 +250,7 @@ public abstract class AbstractSockJsSession implements SockJsSession {
|
|||
}
|
||||
|
||||
protected void sendHeartbeat() throws SockJsTransportFailureException {
|
||||
synchronized (this.heartbeatLock) {
|
||||
synchronized (this.responseLock) {
|
||||
if (isActive() && !this.heartbeatDisabled) {
|
||||
writeFrame(SockJsFrame.heartbeatFrame());
|
||||
scheduleHeartbeat();
|
||||
|
@ -262,7 +262,7 @@ public abstract class AbstractSockJsSession implements SockJsSession {
|
|||
if (this.heartbeatDisabled) {
|
||||
return;
|
||||
}
|
||||
synchronized (this.heartbeatLock) {
|
||||
synchronized (this.responseLock) {
|
||||
cancelHeartbeat();
|
||||
if (!isActive()) {
|
||||
return;
|
||||
|
@ -277,7 +277,7 @@ public abstract class AbstractSockJsSession implements SockJsSession {
|
|||
}
|
||||
|
||||
protected void cancelHeartbeat() {
|
||||
synchronized (this.heartbeatLock) {
|
||||
synchronized (this.responseLock) {
|
||||
if (this.heartbeatFuture != null) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Cancelling heartbeat in session " + getId());
|
||||
|
@ -445,7 +445,7 @@ public abstract class AbstractSockJsSession implements SockJsSession {
|
|||
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (heartbeatLock) {
|
||||
synchronized (responseLock) {
|
||||
if (!this.expired) {
|
||||
try {
|
||||
sendHeartbeat();
|
||||
|
|
Loading…
Reference in New Issue