Uploaded image for project: 'CXF'
  1. CXF
  2. CXF-8113

SocketTimeoutException when remote server closes connection after payload has been delivered

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Duplicate
    • 3.3.1
    • None
    • None
    • None
    • Unknown

    Description

      Similar to CXF-7831, when using the Asynchronous Client HTTP Transport to handle soap web services, we get a SocketTimeout exception when a remote server closes the connection after the payload has been delivered.

      From my research, I'm honestly not sure if this is a CXF issue or an httpcore-nio issue.  The fix in CXF-7831 to CXF's SharedInputBuffer, and the fact that I do not directly consume httpcore-nio led me here first.

      The problem occurs when the client receives a TLS close_notify after the payload has been received.  The payload must be larger than the allocated byte buffer receiving the decrypted payload (~16K in the default case). This results in decrypted data being available in the httpcore-nio library, but not immediately consumed. 

      When these conditions are met, the following section of code is invoked:
      org.apache.cxf.transport.http.asyncclient.SharedInputBuffer#consumeContent:111:

      if (!this.buffer.hasRemaining() && this.ioctrl != null && !this.endOfStream) {
          this.ioctrl.suspendInput();
      }
      

      The suspension of input when combined with the connection close and the following change introduced in httpcore-nio 4.4.10 (and it's revised 4.4.11 version here) truly removes the READ EventMask from the underlying IOSessionImpl:
      org.apache.http.nio.reactor.ssl.SSLIOSession#updateEventMask:402

      if (this.endOfStream && (this.appBufferStatus == null || !this.appBufferStatus.hasBufferedInput())) {
          newMask = newMask & ~EventMask.READ;
      }
      

      Once this happens, requests for input by SharedInputBuffer#waitForData(int) enter the updateEventMask method as expected, but the new httpcore-nio code above prevents the read operation from being reenabled despite the remainder of the decrypted payload being available in the SSLIOSession inPlain buffer.  The call ultimately fails with a SocketTimeoutException.

      I created a unit test to demonstrate the failure and attached it to the JIRA.  Given the complexity of the code and multiple buffers at play, I have not been able to come up with a fix beyond modifying the SSLIOSession code above to account for the buffered decrypted content - but I'm assuming that change was added for a reason and did not investigate the side effects of the modification.  Please let me know if there's anything else you need from me.

       

      Attachments

        1. asyncbugtest.zip
          12 kB
          Brian B

        Issue Links

          Activity

            People

              Unassigned Unassigned
              gujunlong Brian B
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: