Brian B created HTTPCORE-600:
--------------------------------

             Summary: SocketTimeoutException when remote server closes 
connection after payload has been delivered
                 Key: HTTPCORE-600
                 URL: https://issues.apache.org/jira/browse/HTTPCORE-600
             Project: HttpComponents HttpCore
          Issue Type: Bug
          Components: HttpCore NIO
    Affects Versions: 4.4.12, 4.4.11, 4.4.10
            Reporter: Brian B
         Attachments: asyncbugtest.zip

Initially I created this under CXF (CXF-8113), but I think the consensus is it 
is an NIO issue.  The description from that Jira edited to remove CXF-specific 
changes:

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.

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_:{color:#0747a6}111{color}}}:
{code:java}
if (!this.buffer.hasRemaining() && this.ioctrl != null && !this.endOfStream) {
    this.ioctrl.suspendInput();
}
{code}
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_:{color:#0747a6}402{color}}}
{code:java}
if (this.endOfStream && (this.appBufferStatus == null || 
!this.appBufferStatus.hasBufferedInput())) {
    newMask = newMask & ~EventMask.READ;
}
{code}
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.  It seems in all cases where 
{{appBufferStatus.hasBufferedInput()}} is queried, {{inPlain.hasData()}} is 
also queried, with the exception of the {{updateEventMask}} code above.

Please let me know if there's anything else you need from me.

 



--
This message was sent by Atlassian Jira
(v8.3.2#803003)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@hc.apache.org
For additional commands, e-mail: dev-h...@hc.apache.org

Reply via email to