[
https://issues.apache.org/jira/browse/CXF-8113?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Brian B updated CXF-8113:
-------------------------
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_:{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 SocketException.
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.
was:
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 SocketException.
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.
> 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 SocketException.
> 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
(v8.3.2#803003)