https://bz.apache.org/bugzilla/show_bug.cgi?id=61003

            Bug ID: 61003
           Summary: Secure Websocket client hides Exception on error, and
                    throws an IllegalStateException instead
           Product: Tomcat 8
           Version: 8.5.11
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: WebSocket
          Assignee: dev@tomcat.apache.org
          Reporter: a...@activeviam.com
  Target Milestone: ----

Created attachment 34924
  --> https://bz.apache.org/bugzilla/attachment.cgi?id=34924&action=edit
The stack trace

We encounter the following exception (full stack attached) instead of a proper
exception, such as a time out:

java.lang.IllegalStateException: Concurrent write operations are not permitted
        at
org.apache.tomcat.websocket.AsyncChannelWrapperSecure.write(AsyncChannelWrapperSecure.java:116)

AsyncChannelWrapperSecure javadoc interestingly states "This needs a lot more
testing before it can be considered robust.", and indeed this class seems to be
the cause of the issue. More details about what I suspect is going on:


If you take a closer look at WsRemoteEndpointImplBase.sendMessageBlock line
313, you will find this section:

         for (MessagePart mp : messageParts) {
            writeMessagePart(mp);
            if (!bsh.getSendResult().isOK()) {
                messagePartInProgress.release();
                Throwable t = bsh.getSendResult().getException();
 // Bug alert!! Here we will write again, but may not have reset the writing
flag of AsyncChannelWrapperSecure to false 
                wsSession.doClose(new CloseReason(CloseCodes.GOING_AWAY,
t.getMessage()),
                        new CloseReason(CloseCodes.CLOSED_ABNORMALLY,
t.getMessage()));
                throw new IOException (t);
            }

which is problematic: The writeMessagePart method will eventually call doWrite
of WsRemoteEndpointImplClient, which will simply return in case of exceptions:

  try {
                channel.write(byteBuffer).get(timeout, TimeUnit.MILLISECONDS);
            } catch (InterruptedException | ExecutionException |
TimeoutException e) {
                handler.onResult(new SendResult(e));
                return;
            }

So here, when the get fails, the  WriteTask of AsyncChannelWrapperSecure, will
not have finished, and so will not have unset its write flag, meaning that the
wsSession.doClose call done in WsRemoteEndpointImplBase.sendMessageBlock will
fail to write. 
Moreover, the write flag of the WriteTask is not reset in the finally block,
meaning that any other exception thrown by the write task will cause the
completion of the future, but will not allow to write in the ws either, causing
another failure.

This will mean that it will fail to throw the actual cause of the exception
stored in the SendResult.


Side Note: the ReadTask seems to suffer of the same disease, not sure if it is
immune to it.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to