cf-socket: fix listen pollset for FTP active mode

Follow-up to a07ba37b5e which did not
solve the issue of corrent polling for FTP active data connections.

Added test cases for active up-/download.

Closes #14786
This commit is contained in:
Stefan Eissing 2024-09-04 16:06:16 +02:00 committed by Daniel Stenberg
parent 464d466aea
commit db5eae1127
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
3 changed files with 65 additions and 11 deletions

View File

@ -1409,17 +1409,19 @@ static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
struct cf_socket_ctx *ctx = cf->ctx;
if(ctx->sock != CURL_SOCKET_BAD) {
if(!cf->connected) {
if(ctx->listening) {
Curl_pollset_set_in_only(data, ps, ctx->sock);
CURL_TRC_CF(data, cf, "adjust_pollset, listening, POLLIN fd=%"
FMT_SOCKET_T, ctx->sock);
}
else {
Curl_pollset_set_out_only(data, ps, ctx->sock);
CURL_TRC_CF(data, cf, "adjust_pollset, !connected, POLLOUT fd=%"
FMT_SOCKET_T, ctx->sock);
}
/* A listening socket filter needs to be connected before the accept
* for some weird FTP interaction. This should be rewritten, so that
* FTP no longer does the socket checks and accept calls and delegates
* all that to the filter. TODO. */
if(ctx->listening) {
Curl_pollset_set_in_only(data, ps, ctx->sock);
CURL_TRC_CF(data, cf, "adjust_pollset, listening, POLLIN fd=%"
FMT_SOCKET_T, ctx->sock);
}
else if(!cf->connected) {
Curl_pollset_set_out_only(data, ps, ctx->sock);
CURL_TRC_CF(data, cf, "adjust_pollset, !connected, POLLOUT fd=%"
FMT_SOCKET_T, ctx->sock);
}
else if(!ctx->active) {
Curl_pollset_add_in(data, ps, ctx->sock);

View File

@ -163,6 +163,32 @@ class TestVsFTPD:
assert r.tcpdump
assert len(r.tcpdump.stats) == 0, f'Unexpected TCP RSTs packets'
def test_30_08_active_download(self, env: Env, vsftpd: VsFTPD):
docname = 'data-10k'
curl = CurlClient(env=env)
srcfile = os.path.join(vsftpd.docs_dir, f'{docname}')
count = 1
url = f'ftp://{env.ftp_domain}:{vsftpd.port}/{docname}?[0-{count-1}]'
r = curl.ftp_get(urls=[url], with_stats=True, extra_args=[
'--ftp-port', '127.0.0.1'
])
r.check_stats(count=count, http_status=226)
self.check_downloads(curl, srcfile, count)
def test_30_09_active_upload(self, env: Env, vsftpd: VsFTPD):
docname = 'upload-1k'
curl = CurlClient(env=env)
srcfile = os.path.join(env.gen_dir, docname)
dstfile = os.path.join(vsftpd.docs_dir, docname)
self._rmf(dstfile)
count = 1
url = f'ftp://{env.ftp_domain}:{vsftpd.port}/'
r = curl.ftp_upload(urls=[url], fupload=f'{srcfile}', with_stats=True, extra_args=[
'--ftp-port', '127.0.0.1'
])
r.check_stats(count=count, http_status=226)
self.check_upload(env, vsftpd, docname=docname)
def check_downloads(self, client, srcfile: str, count: int,
complete: bool = True):
for i in range(count):

View File

@ -194,6 +194,32 @@ class TestVsFTPD:
f'expected source with {newlines} lines to be that much larger,'\
f'instead srcsize={srcsize}, upload size={dstsize}, diff={dstsize-srcsize}'
def test_31_08_active_download(self, env: Env, vsftpds: VsFTPD):
docname = 'data-10k'
curl = CurlClient(env=env)
srcfile = os.path.join(vsftpds.docs_dir, f'{docname}')
count = 1
url = f'ftp://{env.ftp_domain}:{vsftpds.port}/{docname}?[0-{count-1}]'
r = curl.ftp_ssl_get(urls=[url], with_stats=True, extra_args=[
'--ftp-port', '127.0.0.1'
])
r.check_stats(count=count, http_status=226)
self.check_downloads(curl, srcfile, count)
def test_31_09_active_upload(self, env: Env, vsftpds: VsFTPD):
docname = 'upload-1k'
curl = CurlClient(env=env)
srcfile = os.path.join(env.gen_dir, docname)
dstfile = os.path.join(vsftpds.docs_dir, docname)
self._rmf(dstfile)
count = 1
url = f'ftp://{env.ftp_domain}:{vsftpds.port}/'
r = curl.ftp_ssl_upload(urls=[url], fupload=f'{srcfile}', with_stats=True, extra_args=[
'--ftp-port', '127.0.0.1'
])
r.check_stats(count=count, http_status=226)
self.check_upload(env, vsftpds, docname=docname)
def check_downloads(self, client, srcfile: str, count: int,
complete: bool = True):
for i in range(count):