]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
ftp: fix prequotes for a directory in URL
authorBartosz Ruszczak <bruszczak48@gmail.com>
Fri, 14 Mar 2025 20:53:42 +0000 (21:53 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 20 Jun 2025 21:22:24 +0000 (23:22 +0200)
Allow prequotes to be sent after curl has changed the working directory,
just before the listing command if the URL is a directory.

FTP state machine is updated with the new FTP_LIST_PREQUOTE state and
FTP_RETR_LIST_TYPE type.

Test 754 verifies

Fixes #8602
Closes #17616

lib/ftp.c
lib/ftp.h
tests/data/Makefile.am
tests/data/test754 [new file with mode: 0644]

index 583e33a96756421800ece6ef25e879ab0c2320b0..aaf1e0e397100d44191137bf47d0eb1b9705f754 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -114,12 +114,14 @@ static const char * const ftp_state_names[]={
   "QUOTE",
   "RETR_PREQUOTE",
   "STOR_PREQUOTE",
+  "LIST_PREQUOTE",
   "POSTQUOTE",
   "CWD",
   "MKD",
   "MDTM",
   "TYPE",
   "LIST_TYPE",
+  "RETR_LIST_TYPE",
   "RETR_TYPE",
   "STOR_TYPE",
   "SIZE",
@@ -1459,6 +1461,14 @@ static CURLcode ftp_state_list(struct Curl_easy *data,
   return result;
 }
 
+static CURLcode ftp_state_list_prequote(struct Curl_easy *data,
+                                        struct ftp_conn *ftpc,
+                                        struct FTP *ftp)
+{
+  /* We have sent the TYPE, now we must send the list of prequote strings */
+  return ftp_state_quote(data, ftpc, ftp, TRUE, FTP_LIST_PREQUOTE);
+}
+
 static CURLcode ftp_state_retr_prequote(struct Curl_easy *data,
                                         struct ftp_conn *ftpc,
                                         struct FTP *ftp)
@@ -1647,6 +1657,7 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
     break;
   case FTP_RETR_PREQUOTE:
   case FTP_STOR_PREQUOTE:
+  case FTP_LIST_PREQUOTE:
     item = data->set.prequote;
     break;
   case FTP_POSTQUOTE:
@@ -1736,6 +1747,10 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
       break;
     case FTP_POSTQUOTE:
       break;
+    case FTP_LIST_PREQUOTE:
+      ftp_state(data, ftpc, FTP_LIST_TYPE);
+      result = ftp_state_list(data, ftpc, ftp);
+      break;
     }
   }
 
@@ -2209,6 +2224,8 @@ static CURLcode ftp_state_type_resp(struct Curl_easy *data,
     result = ftp_state_retr_prequote(data, ftpc, ftp);
   else if(instate == FTP_STOR_TYPE)
     result = ftp_state_stor_prequote(data, ftpc, ftp);
+  else if(instate == FTP_RETR_LIST_TYPE)
+    result = ftp_state_list_prequote(data, ftpc, ftp);
 
   return result;
 }
@@ -3013,6 +3030,7 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data,
     case FTP_POSTQUOTE:
     case FTP_RETR_PREQUOTE:
     case FTP_STOR_PREQUOTE:
+    case FTP_LIST_PREQUOTE:
       if((ftpcode >= 400) && !ftpc->count2) {
         /* failure response code, and not allowed to fail */
         failf(data, "QUOT command failed with %03d", ftpcode);
@@ -3082,6 +3100,7 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data,
     case FTP_LIST_TYPE:
     case FTP_RETR_TYPE:
     case FTP_STOR_TYPE:
+    case FTP_RETR_LIST_TYPE:
       result = ftp_state_type_resp(data, ftpc, ftp, ftpcode, ftpc->state);
       break;
 
@@ -3686,7 +3705,8 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
 
       if(result)
         ;
-      else if(data->state.list_only || !ftpc->file) {
+      else if((data->state.list_only || !ftpc->file) &&
+              !(data->set.prequote)) {
         /* The specified path ends with a slash, and therefore we think this
            is a directory that is requested, use LIST. But before that we
            need to set ASCII transfer mode. */
@@ -3700,8 +3720,14 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
         /* otherwise just fall through */
       }
       else {
-        result = ftp_nb_type(data, ftpc, ftp, data->state.prefer_ascii,
-                             FTP_RETR_TYPE);
+        if(data->set.prequote && !ftpc->file) {
+          result = ftp_nb_type(data, ftpc, ftp, TRUE,
+                               FTP_RETR_LIST_TYPE);
+        }
+        else {
+          result = ftp_nb_type(data, ftpc, ftp, data->state.prefer_ascii,
+                               FTP_RETR_TYPE);
+        }
         if(result)
           return result;
       }
index c31aa9328617b93e0ce899e83f4142666fadc2e6..52661981ef332af2a90328b21500b48a6a496623 100644 (file)
--- a/lib/ftp.h
+++ b/lib/ftp.h
@@ -62,12 +62,14 @@ enum {
   FTP_QUOTE, /* waiting for a response to a command sent in a quote list */
   FTP_RETR_PREQUOTE,
   FTP_STOR_PREQUOTE,
+  FTP_LIST_PREQUOTE,
   FTP_POSTQUOTE,
   FTP_CWD,  /* change dir */
   FTP_MKD,  /* if the dir did not exist */
   FTP_MDTM, /* to figure out the datestamp */
   FTP_TYPE, /* to set type when doing a head-like request */
   FTP_LIST_TYPE, /* set type when about to do a dir list */
+  FTP_RETR_LIST_TYPE,
   FTP_RETR_TYPE, /* set type when about to RETR a file */
   FTP_STOR_TYPE, /* set type when about to STOR a file */
   FTP_SIZE, /* get the remote file's size for head-like request */
index 7b519da8ae0464b639b16f641aee29c190d9bf78..3986eca6f137cb9bb7443a1e1c936b052bf66b7c 100644 (file)
@@ -108,7 +108,7 @@ test718 test719 test720 test721 test722 test723 test724 test725 test726 \
 test727 test728 test729 test730 test731 test732 test733 test734 test735 \
 test736 test737 test738 test739 test740 test741 test742 test743 test744 \
 test745 test746 test747 test748 test749 test750 test751 test752 test753 \
-\
+test754 \
 test780 test781 test782 test783 test784 test785 test786 test787 test788 \
 test789 test790 test791 \
 \
diff --git a/tests/data/test754 b/tests/data/test754
new file mode 100644 (file)
index 0000000..9253d9f
--- /dev/null
@@ -0,0 +1,64 @@
+<testcase>
+<info>
+<keywords>
+FTP
+list
+post-quote
+pre-quote
+</keywords>
+</info>
+# Server-side
+<reply>
+<data mode="text">
+total 20
+drwxr-xr-x   8 98       98           512 Oct 22 13:06 .
+drwxr-xr-x   8 98       98           512 Oct 22 13:06 ..
+drwxr-xr-x   2 98       98           512 May  2  1996 .NeXT
+-r--r--r--   1 0        1             35 Jul 16  1996 README
+lrwxrwxrwx   1 0        1              7 Dec  9  1999 bin -> usr/bin
+dr-xr-xr-x   2 0        1            512 Oct  1  1997 dev
+drwxrwxrwx   2 98       98           512 May 29 16:04 download.html
+dr-xr-xr-x   2 0        1            512 Nov 30  1995 etc
+drwxrwxrwx   2 98       1            512 Oct 30 14:33 pub
+dr-xr-xr-x   5 0        1            512 Oct  1  1997 usr
+</data>
+<servercmd>
+REPLY FAIL 500 this might not be a failure!
+</servercmd>
+</reply>
+
+# Client-side
+<client>
+<server>
+ftp
+</server>
+<name>
+FTP list with quote ops
+</name>
+<command>
+ftp://%HOSTIP:%FTPPORT/path/ -Q "NOOP 1" -Q "+NOOP 2" -Q "-NOOP 3" -Q "*FAIL" -Q "+*FAIL HARD"
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+QUIT
+</strip>
+<protocol>
+USER anonymous\r
+PASS ftp@example.com\r
+PWD\r
+NOOP 1\r
+FAIL\r
+CWD path\r
+EPSV\r
+TYPE A\r
+NOOP 2\r
+FAIL HARD\r
+LIST\r
+NOOP 3\r
+QUIT\r
+</protocol>
+</verify>
+</testcase>