Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FtpGateway: Unexpected ABORTED suffixes in %Ss #267

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

eduard-bagdasaryan
Copy link

@eduard-bagdasaryan eduard-bagdasaryan commented Oct 2, 2024

While downloading/uploading files using HTTP GET/PUT requests with ftp
URI scheme, Squid completed these transactions successfully but
sometimes logged the ABORTED suffix, e.g., TCP_MISS_ABORTED. This
happened because Squid postponed completing the corresponding StoreEntry
until getting 221 reply from FTP server, even though the server has sent
all response bytes already. So if the client chanced to close the
client-to-Squid connection before that, the cleanup code in
ConnStateData::terminateAll() would finish the transaction which logged
as 'ABORTED' because the StoreEntry was still in the STORE_PENDING
state.

Now we complete the entry as soon as all FTP response bytes have been
received. Similar cases (where Ftp::Gateway generates the final response
itself) were fixed as well.

Also added some missing markStoredReplyAsWhole() calls where FTP code
generates replies. Without this, FwdState cleanup code called
completeTruncated() for the entry and %err_detail logged 'WITH_CLIENT'.

While downloading/uploading files using HTTP GET/PUT requests with ftp
URI scheme, Squid completes these transactions successfully but
sometimes logs the ABORTED suffix, e.g., TCP_MISS_ABORTED.  This happens
because Squid postpones completing the corresponding StoreEntry until
getting 221 reply from FTP server, even though the server has sent all
response bytes already. So if the client closes the client-to-Squid
connection before that, the cleanup code in
ConnStateData::terminateAll() finishes the transaction which is logged
as 'ABORTED' because the StoreEntry is still in the STORE_PENDING state.

Now we complete the entry, calling Ftp::Gateway::completeForwarding() as
soon as Squid got all FTP response bytes.
@@ -1008,6 +1008,11 @@ Ftp::Gateway::processReplyBody()

entry->flush();

if (theSize >= 0 && data.payloadSeen >= theSize) {
markParsedVirginReplyAsWhole("whole virgin body");
completeForwarding();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes 'ABORTED' for ftp 'GET' transactions. We cannot add this to ftpReadTransferDone() similarly as to ftpWriteTransferDone() for 'PUT' transactions because for 'GET' transactions 226/250 response may come after Squid sends the whole downloaded file to the client (and client may have closed the connection before 226/250). Note that this does not happen for 'PUT' transactions, because ftpWriteTransferDone() initiates the response itself, i.e., the client receives the response only after Squid gets 226/250.

Copy link

@rousskov rousskov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be best for focus on the "virgin vs adapted" change request first. Addressing it may render all other change requests stale/irrelevant.

src/clients/FtpGateway.cc Outdated Show resolved Hide resolved
src/clients/FtpClient.h Outdated Show resolved Hide resolved
src/clients/FtpGateway.cc Outdated Show resolved Hide resolved
Another method (serverDataComplete) is called instead to take care about
doneWithAdaptation() condition.
Also serverDataComplete() for all other ftpSendReply() cases, such as
ftpReadMkdir().
Partially undone 74cf59a (serverDataComplete() method).
markStoredReplyAsWhole() is a common place for marking the
reply as complete for both adaptation and non-adaptation cases.
Special care should be taken about not calling complete() twice.
Before this fix, the (fully completed) entry was
completeTruncated() instead, 'WITH_CLIENT' (a kind of error
indicator) was logged in err_detail.

Also undone branch adjustments in FwdState::completed():
there can be scenarios when the entry status != STORE_OK
(e.g., due to reforward() depending on many factors).
@@ -1257,6 +1263,7 @@ Ftp::Gateway::loginFailed()

// add it to the store entry for response....
entry->replaceHttpReply(newrep);
fwd->markStoredReplyAsWhole("loginFailed");
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes the 'entry->completeTruncated()' problem and adding 'WITH_CLIENT' to err_detail. I fixed other cases in FtpGateway as well.

if (e->store_status == STORE_OK) {
debugs(17, 3, "No, the entry is STORE_OK already");
return 0;
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked that FwdState::completed() would hit the 'e->store_status == STORE_OK' assertion (added in e322b47) and removed that assertion. In that test (where server responds with an HTTP 502 reply) I adjusted the code so that reforward() would return 'true' when called the first time (so that markStoredReplyAsWhole() does not complete the entry). Also note that this scenario should never happen in FTP because reforward() always returns false (FTP code never sets ENTRY_FWD_HDR_WAIT).

src/clients/FtpClient.h Outdated Show resolved Hide resolved
src/clients/FtpClient.h Outdated Show resolved Hide resolved
src/clients/FtpGateway.cc Outdated Show resolved Hide resolved
src/clients/FtpGateway.cc Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants