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.
Suggestion cannot be applied right now. Please check back later.
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_recv
is called andsread
returns 15KB of TLS data.rustls_client_session_read_tls
is passed the 15KB of data and stores it.rustls_client_session_process_new_packets
is called but since the first TLS record isn't complete it does nothing.rustls_client_session_read
returns EOF because there is no plaintext data to read yet.cr_recv
returnsCURLE_AGAIN
cr_recv
is called andsread
returns 9KB of TLS data.rustls_client_session_read_tls
is passed the 9KB of data and stores it.rustls_client_session_process_new_packets
is called, and since both TLS records are complete, it processes them and extracts the 20KB of plaintext data.rustls_client_session_read
returns 16KB of plaintext, because that's the size of theplainbuf
passed tocr_recv
.cr_recv
returns 16KB.cr_recv
is called again andsread
returns EAGAIN since there are no more TCP segments to read.cr_recv
returnsCURLE_AGAIN
prematurely, 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: