]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
cf-socket: fix listen pollset for FTP active mode
authorStefan Eissing <stefan@eissing.org>
Wed, 4 Sep 2024 14:06:16 +0000 (16:06 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 5 Sep 2024 09:00:55 +0000 (11:00 +0200)
Follow-up to a07ba37b5e88a89bf4bcc6b0c927f7a42d7ea4f2 which did not
solve the issue of corrent polling for FTP active data connections.

Added test cases for active up-/download.

Closes #14786

lib/cf-socket.c
tests/http/test_30_vsftpd.py
tests/http/test_31_vsftpds.py

index 0e5db5e3ec9e35f77cfec80e2de1cf49095cb4fa..729e38f88947bed391a49a7d16697fce41f2d6f7 100644 (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);
index 477b27affd6d129c109c8ccf3e8107c1f27ae07a..d90f84611c78af82212b0690e4a337a1342d833c 100644 (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):
index d575d89f5a8cae6054e1eaa4148a9df6c49de60c..95f3957cad6093906a3e71b74460a243c2b0739d 100644 (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):