[Java] Don't call onClose when WebSocket connection is not open (#28004)

This commit is contained in:
Brennan 2020-11-23 11:40:58 -08:00 committed by GitHub
parent 4b46b26896
commit 4731c87476
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 18 deletions

View File

@ -30,7 +30,7 @@ class OkHttpWebSocketWrapper extends WebSocketWrapper {
private WebSocketOnClosedCallback onClose; private WebSocketOnClosedCallback onClose;
private CompletableSubject startSubject = CompletableSubject.create(); private CompletableSubject startSubject = CompletableSubject.create();
private CompletableSubject closeSubject = CompletableSubject.create(); private CompletableSubject closeSubject = CompletableSubject.create();
private final ReentrantLock closeLock = new ReentrantLock(); private final ReentrantLock stateLock = new ReentrantLock();
private final Logger logger = LoggerFactory.getLogger(OkHttpWebSocketWrapper.class); private final Logger logger = LoggerFactory.getLogger(OkHttpWebSocketWrapper.class);
@ -82,7 +82,12 @@ class OkHttpWebSocketWrapper extends WebSocketWrapper {
private class SignalRWebSocketListener extends WebSocketListener { private class SignalRWebSocketListener extends WebSocketListener {
@Override @Override
public void onOpen(WebSocket webSocket, Response response) { public void onOpen(WebSocket webSocket, Response response) {
startSubject.onComplete(); stateLock.lock();
try {
startSubject.onComplete();
} finally {
stateLock.unlock();
}
} }
@Override @Override
@ -97,39 +102,64 @@ class OkHttpWebSocketWrapper extends WebSocketWrapper {
@Override @Override
public void onClosing(WebSocket webSocket, int code, String reason) { public void onClosing(WebSocket webSocket, int code, String reason) {
onClose.invoke(code, reason); boolean isOpen = false;
stateLock.lock();
try { try {
closeLock.lock(); isOpen = startSubject.hasComplete();
} finally {
stateLock.unlock();
}
logger.info("WebSocket closing with status code '{}' and reason '{}'.", code, reason);
// Only call onClose if connection is open
if (isOpen) {
onClose.invoke(code, reason);
}
try {
stateLock.lock();
closeSubject.onComplete(); closeSubject.onComplete();
} }
finally { finally {
closeLock.unlock(); stateLock.unlock();
} }
checkStartFailure(); checkStartFailure(null);
} }
@Override @Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) { public void onFailure(WebSocket webSocket, Throwable t, Response response) {
logger.error("WebSocket closed from an error: {}.", t.getMessage()); logger.error("WebSocket closed from an error.", t);
boolean isOpen = false;
try { try {
closeLock.lock(); stateLock.lock();
if (!closeSubject.hasComplete()) { if (!closeSubject.hasComplete()) {
closeSubject.onError(new RuntimeException(t)); closeSubject.onError(new RuntimeException(t));
} }
isOpen = startSubject.hasComplete();
} }
finally { finally {
closeLock.unlock(); stateLock.unlock();
} }
onClose.invoke(null, t.getMessage()); // Only call onClose if connection is open
checkStartFailure(); if (isOpen) {
onClose.invoke(null, t.getMessage());
}
checkStartFailure(t);
} }
private void checkStartFailure() { private void checkStartFailure(Throwable t) {
// If the start task hasn't completed yet, then we need to complete it stateLock.lock();
// exceptionally. try {
if (!startSubject.hasComplete()) { // If the start task hasn't completed yet, then we need to complete it
startSubject.onError(new RuntimeException("There was an error starting the WebSocket transport.")); // exceptionally.
if (!startSubject.hasComplete()) {
startSubject.onError(new RuntimeException("There was an error starting the WebSocket transport.", t));
}
} finally {
stateLock.unlock();
} }
} }
} }

View File

@ -86,8 +86,6 @@ class WebSocketTransport implements Transport {
} }
void onClose(Integer code, String reason) { void onClose(Integer code, String reason) {
logger.info("WebSocket connection stopping with " +
"code {} and reason '{}'.", code, reason);
if (code == null || code != 1000) { if (code == null || code != 1000) {
onClose.invoke(reason); onClose.invoke(reason);
} }