ftp: flush pingpong before response

Fix FTP protocol to flush the pingpong's send buffer before receiving a
response from the server, as it may never come otherwise.

Fixes FTP/FTPS tests with `CURL_DBG_SOCK_WBLOCK=90` set.

Closes #14452
This commit is contained in:
Stefan Eissing 2024-08-08 13:12:53 +02:00 committed by Daniel Stenberg
parent badbd4eb46
commit a0ea955f80
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
3 changed files with 29 additions and 7 deletions

View File

@ -819,6 +819,8 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
int cache_skip = 0;
int value_to_be_ignored = 0;
CURL_TRC_FTP(data, "getFTPResponse start");
if(ftpcode)
*ftpcode = 0; /* 0 for errors */
else
@ -864,21 +866,27 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
*/
}
else if(!Curl_conn_data_pending(data, FIRSTSOCKET)) {
switch(SOCKET_READABLE(sockfd, interval_ms)) {
case -1: /* select() error, stop reading */
curl_socket_t wsock = Curl_pp_needs_flush(data, pp)?
sockfd : CURL_SOCKET_BAD;
int ev = Curl_socket_check(sockfd, CURL_SOCKET_BAD, wsock, interval_ms);
if(ev < 0) {
failf(data, "FTP response aborted due to select/poll error: %d",
SOCKERRNO);
return CURLE_RECV_ERROR;
case 0: /* timeout */
}
else if(ev == 0) {
if(Curl_pgrsUpdate(data))
return CURLE_ABORTED_BY_CALLBACK;
continue; /* just continue in our loop for the timeout duration */
default: /* for clarity */
break;
}
}
if(Curl_pp_needs_flush(data, pp)) {
result = Curl_pp_flushsend(data, pp);
if(result)
break;
}
result = ftp_readresp(data, FIRSTSOCKET, pp, ftpcode, &nread);
if(result)
break;
@ -897,6 +905,8 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
} /* while there is buffer left and loop is requested */
pp->pending_resp = FALSE;
CURL_TRC_FTP(data, "getFTPResponse -> result=%d, nread=%zd, ftpcode=%d",
result, *nreadp, *ftpcode);
return result;
}

View File

@ -395,6 +395,13 @@ int Curl_pp_getsock(struct Curl_easy *data,
return GETSOCK_READSOCK(0);
}
bool Curl_pp_needs_flush(struct Curl_easy *data,
struct pingpong *pp)
{
(void)data;
return pp->sendleft > 0;
}
CURLcode Curl_pp_flushsend(struct Curl_easy *data,
struct pingpong *pp)
{
@ -402,6 +409,9 @@ CURLcode Curl_pp_flushsend(struct Curl_easy *data,
size_t written;
CURLcode result;
if(!Curl_pp_needs_flush(data, pp))
return CURLE_OK;
result = Curl_conn_send(data, FIRSTSOCKET,
pp->sendthis + pp->sendsize - pp->sendleft,
pp->sendleft, FALSE, &written);

View File

@ -137,6 +137,8 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data,
int *code, /* return the server code if done */
size_t *size); /* size of the response */
bool Curl_pp_needs_flush(struct Curl_easy *data,
struct pingpong *pp);
CURLcode Curl_pp_flushsend(struct Curl_easy *data,
struct pingpong *pp);