Freeman Fang commented on CXF-8113:

Yes, first glance it's a regression from httpcore-nio side, using latest CXF 
3.3.3 and httpcore-nio 4.4.9, your test can pass. 

> SocketTimeoutException when remote server closes connection after payload has 
> been delivered
> --------------------------------------------------------------------------------------------
>                 Key: CXF-8113
>                 URL: https://issues.apache.org/jira/browse/CXF-8113
>             Project: CXF
>          Issue Type: Bug
>    Affects Versions: 3.3.1
>            Reporter: Brian B
>            Priority: Major
>         Attachments: asyncbugtest.zip
> 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_:{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 - 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.

This message was sent by Atlassian Jira

Reply via email to