|
|
9a9096 |
--- java/org/apache/tomcat/websocket/WsSession.java.org 2017-03-09 14:51:41.000000000 +0100
|
|
|
9a9096 |
+++ java/org/apache/tomcat/websocket/WsSession.java 2018-07-18 17:37:46.853657200 +0200
|
|
|
9a9096 |
@@ -595,8 +595,8 @@
|
|
|
9a9096 |
localEndpoint.onError(this, e);
|
|
|
9a9096 |
}
|
|
|
9a9096 |
}
|
|
|
9a9096 |
-
|
|
|
9a9096 |
-
|
|
|
9a9096 |
+
|
|
|
9a9096 |
+
|
|
|
9a9096 |
/**
|
|
|
9a9096 |
* Use protected so unit tests can access this method directly.
|
|
|
9a9096 |
*/
|
|
|
9a9096 |
@@ -635,29 +635,48 @@
|
|
|
9a9096 |
* {@link FutureToSendHandler} completes.
|
|
|
9a9096 |
*/
|
|
|
9a9096 |
protected void registerFuture(FutureToSendHandler f2sh) {
|
|
|
9a9096 |
- boolean fail = false;
|
|
|
9a9096 |
- synchronized (stateLock) {
|
|
|
9a9096 |
- // If the session has already been closed the any registered futures
|
|
|
9a9096 |
- // will have been processed so the failure result for this future
|
|
|
9a9096 |
- // needs to be set here.
|
|
|
9a9096 |
- if (state == State.OPEN || f2sh.isCloseMessage()) {
|
|
|
9a9096 |
- // WebSocket session is open or this is the close message
|
|
|
9a9096 |
- futures.put(f2sh, f2sh);
|
|
|
9a9096 |
- } else if (f2sh.isDone()) {
|
|
|
9a9096 |
- // NO-OP. The future completed before the session closed so no
|
|
|
9a9096 |
- // need to register in case the session closes before it
|
|
|
9a9096 |
- // completes.
|
|
|
9a9096 |
- } else {
|
|
|
9a9096 |
- // Construct the exception outside of the sync block
|
|
|
9a9096 |
- fail = true;
|
|
|
9a9096 |
- }
|
|
|
9a9096 |
+ // Ideally, this code should sync on stateLock so that the correct
|
|
|
9a9096 |
+ // action is taken based on the current state of the connection.
|
|
|
9a9096 |
+ // However, a sync on stateLock can't be used here as it will create the
|
|
|
9a9096 |
+ // possibility of a dead-lock. See BZ 61183.
|
|
|
9a9096 |
+ // Therefore, a slightly less efficient approach is used.
|
|
|
9a9096 |
+
|
|
|
9a9096 |
+ // Always register the future.
|
|
|
9a9096 |
+ futures.put(f2sh, f2sh);
|
|
|
9a9096 |
+
|
|
|
9a9096 |
+ if (state == State.OPEN || f2sh.isCloseMessage()) {
|
|
|
9a9096 |
+ // The session is open. The future has been registered with the open
|
|
|
9a9096 |
+ // session. Normal processing continues.
|
|
|
9a9096 |
+ return;
|
|
|
9a9096 |
}
|
|
|
9a9096 |
|
|
|
9a9096 |
- if (fail) {
|
|
|
9a9096 |
- IOException ioe = new IOException(sm.getString("wsSession.messageFailed"));
|
|
|
9a9096 |
- SendResult sr = new SendResult(ioe);
|
|
|
9a9096 |
- f2sh.onResult(sr);
|
|
|
9a9096 |
+ // The session is closed. The future may or may not have been registered
|
|
|
9a9096 |
+ // in time for it to be processed during session closure.
|
|
|
9a9096 |
+
|
|
|
9a9096 |
+ if (f2sh.isDone()) {
|
|
|
9a9096 |
+ // The future has completed. It is not known if the future was
|
|
|
9a9096 |
+ // completed normally by the I/O layer or in error by doClose(). It
|
|
|
9a9096 |
+ // doesn't matter which. There is nothing more to do here.
|
|
|
9a9096 |
+ return;
|
|
|
9a9096 |
}
|
|
|
9a9096 |
+
|
|
|
9a9096 |
+ // The session is closed. The Future had not completed when last checked.
|
|
|
9a9096 |
+ // There is a small timing window that means the Future may have been
|
|
|
9a9096 |
+ // completed since the last check. There is also the possibility that
|
|
|
9a9096 |
+ // the Future was not registered in time to be cleaned up during session
|
|
|
9a9096 |
+ // close.
|
|
|
9a9096 |
+ // Attempt to complete the Future with an error result as this ensures
|
|
|
9a9096 |
+ // that the Future completes and any client code waiting on it does not
|
|
|
9a9096 |
+ // hang. It is slightly inefficient since the Future may have been
|
|
|
9a9096 |
+ // completed in another thread or another thread may be about to
|
|
|
9a9096 |
+ // complete the Future but knowing if this is the case requires the sync
|
|
|
9a9096 |
+ // on stateLock (see above).
|
|
|
9a9096 |
+ // Note: If multiple attempts are made to complete the Future, the
|
|
|
9a9096 |
+ // second and subsequent attempts are ignored.
|
|
|
9a9096 |
+
|
|
|
9a9096 |
+ IOException ioe = new IOException(sm.getString("wsSession.messageFailed"));
|
|
|
9a9096 |
+ SendResult sr = new SendResult(ioe);
|
|
|
9a9096 |
+ f2sh.onResult(sr);
|
|
|
9a9096 |
}
|
|
|
9a9096 |
|
|
|
9a9096 |
|