/ curl Public
rustls: only return CURLE_AGAIN when TLS session is fully drained #6894
Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes. Only one suggestion per line can be applied in a batch. Add this suggestion to a batch that can be applied as a single commit. Applying suggestions on deleted lines is not supported. You must change the existing code in this line in order to create a valid suggestion. Outdated suggestions cannot be applied. This suggestion has been applied or marked resolved. Suggestions cannot be applied from pending reviews. Suggestions cannot be applied on multi-line comments. Suggestions cannot be applied while the pull request is queued to merge.
The code in cr_recv was returning prematurely as soon as the socket reported no more data to read. However, this could be leaving some unread plaintext data in the rustls session from a previous call, causing the transfer to hang if the socket never receives further data. We need to ensure that the session is fully drained of plaintext data before returning CURLE_AGAIN to the caller.
To illustrate the problem, consider the following sequence of events as an example:
cr_recvis called and
sreadreturns 15KB of TLS data.
rustls_client_session_read_tlsis passed the 15KB of data and stores it.
rustls_client_session_process_new_packetsis called but since the first TLS record isn't complete it does nothing.
rustls_client_session_readreturns EOF because there is no plaintext data to read yet.
cr_recvis called and
sreadreturns 9KB of TLS data.
rustls_client_session_read_tlsis passed the 9KB of data and stores it.
rustls_client_session_process_new_packetsis called, and since both TLS records are complete, it processes them and extracts the 20KB of plaintext data.
rustls_client_session_readreturns 16KB of plaintext, because that's the size of the
cr_recvis called again and
sreadreturns EAGAIN since there are no more TCP segments to read.
CURLE_AGAINprematurely, even though there are still 4KB of plaintext to be read from the session.
I don't have an easy repro for you, but the problem manifests very frequently in our internal application. These are the corresponding curl trace logs with some additional logs that I added for debugging: