]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
ftp: add 'prefer_ascii' to the transfer state struct
authorDaniel Stenberg <daniel@haxx.se>
Mon, 8 Feb 2021 14:56:10 +0000 (15:56 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 9 Feb 2021 13:06:28 +0000 (14:06 +0100)
... and make sure the code never updates 'set.prefer_ascii' as it breaks
handle reuse which should use the setting as the user specified it.

Added test 1569 to verify: it first makes an FTP transfer with ';type=A'
and then another without type on the same handle and the second should
then use binary. Previously, curl failed this.

Closes #6578

lib/ftp.c
lib/http.c
lib/tftp.c
lib/transfer.c
lib/urldata.h
tests/data/Makefile.inc
tests/data/test1569 [new file with mode: 0644]
tests/libtest/Makefile.inc
tests/libtest/lib1569.c [new file with mode: 0644]

index c888b78583fdc5c6d798a26d4265dd2b0cc2ea8b..05bed5464a90080f9cca70515c4e0a64faa67a6a 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -1525,7 +1525,7 @@ static CURLcode ftp_state_type(struct Curl_easy *data)
      information. Which in FTP can't be much more than the file size and
      date. */
   if(data->set.opt_no_body && ftpc->file &&
-     ftp_need_type(conn, data->set.prefer_ascii)) {
+     ftp_need_type(conn, data->state.prefer_ascii)) {
     /* The SIZE command is _not_ RFC 959 specified, and therefore many servers
        may not support it! It is however the only way we have to get a file's
        size! */
@@ -1535,7 +1535,7 @@ static CURLcode ftp_state_type(struct Curl_easy *data)
 
     /* Some servers return different sizes for different modes, and thus we
        must set the proper type before we check the size */
-    result = ftp_nb_type(data, conn, data->set.prefer_ascii, FTP_TYPE);
+    result = ftp_nb_type(data, conn, data->state.prefer_ascii, FTP_TYPE);
     if(result)
       return result;
   }
@@ -1747,7 +1747,7 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
           result = ftp_state_retr(data, ftpc->known_filesize);
         }
         else {
-          if(data->set.ignorecl || data->set.prefer_ascii) {
+          if(data->set.ignorecl || data->state.prefer_ascii) {
             /* 'ignorecl' is used to support download of growing files.  It
                prevents the state machine from requesting the file size from
                the server.  With an unknown file size the download continues
@@ -2454,7 +2454,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
      */
 
     if((instate != FTP_LIST) &&
-       !data->set.prefer_ascii &&
+       !data->state.prefer_ascii &&
        (ftp->downloadsize < 1)) {
       /*
        * It seems directory listings either don't show the size or very
@@ -2493,7 +2493,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
 
     if(size > data->req.maxdownload && data->req.maxdownload > 0)
       size = data->req.size = data->req.maxdownload;
-    else if((instate != FTP_LIST) && (data->set.prefer_ascii))
+    else if((instate != FTP_LIST) && (data->state.prefer_ascii))
       size = -1; /* kludge for servers that understate ASCII mode file size */
 
     infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
@@ -3626,7 +3626,8 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
       }
     }
     else if(data->set.upload) {
-      result = ftp_nb_type(data, conn, data->set.prefer_ascii, FTP_STOR_TYPE);
+      result = ftp_nb_type(data, conn, data->state.prefer_ascii,
+                           FTP_STOR_TYPE);
       if(result)
         return result;
 
@@ -3661,7 +3662,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
         /* otherwise just fall through */
       }
       else {
-        result = ftp_nb_type(data, conn, data->set.prefer_ascii,
+        result = ftp_nb_type(data, conn, data->state.prefer_ascii,
                              FTP_RETR_TYPE);
         if(result)
           return result;
@@ -4351,7 +4352,7 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
 
     switch(command) {
     case 'A': /* ASCII mode */
-      data->set.prefer_ascii = TRUE;
+      data->state.prefer_ascii = TRUE;
       break;
 
     case 'D': /* directory mode */
@@ -4361,7 +4362,7 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
     case 'I': /* binary mode */
     default:
       /* switch off ASCII */
-      data->set.prefer_ascii = FALSE;
+      data->state.prefer_ascii = FALSE;
       break;
     }
   }
index 806f639dc93c0c237876e80ab625a56780834cc0..1141102f68bf11fc93aa65aef5b024d8db26e421 100644 (file)
@@ -1702,7 +1702,7 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
 
   if(
 #ifdef CURL_DO_LINEEND_CONV
-     (handle->set.prefer_ascii) ||
+     (handle->state.prefer_ascii) ||
 #endif
      (handle->set.crlf)) {
     /* \n will become \r\n later on */
@@ -2209,7 +2209,7 @@ CURLcode Curl_http_target(struct Curl_easy *data,
         }
         if(!type) {
           result = Curl_dyn_addf(r, ";type=%c",
-                                 data->set.prefer_ascii ? 'a' : 'i');
+                                 data->state.prefer_ascii ? 'a' : 'i');
           if(result)
             return result;
         }
index 3f1d1b51b7c731d0a9f68ccb5125841acee62897..defc9105e09dcaecd5999fe71addfdb1ab8236cb 100644 (file)
@@ -460,7 +460,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
   CURLcode result = CURLE_OK;
 
   /* Set ascii mode if -B flag was used */
-  if(data->set.prefer_ascii)
+  if(data->state.prefer_ascii)
     mode = "netascii";
 
   switch(event) {
@@ -1420,14 +1420,14 @@ static CURLcode tftp_setup_connection(struct Curl_easy *data,
     switch(command) {
     case 'A': /* ASCII mode */
     case 'N': /* NETASCII mode */
-      data->set.prefer_ascii = TRUE;
+      data->state.prefer_ascii = TRUE;
       break;
 
     case 'O': /* octet mode */
     case 'I': /* binary mode */
     default:
       /* switch off ASCII */
-      data->set.prefer_ascii = FALSE;
+      data->state.prefer_ascii = FALSE;
       break;
     }
   }
index 59f759600cfd6d13d6cae6c3d1192f531cb4b669..e63ad713375242535d568bf78856492ec9f6b4ce 100644 (file)
@@ -286,7 +286,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
      *        <DATA> CRLF
      */
     /* On non-ASCII platforms the <DATA> may or may not be
-       translated based on set.prefer_ascii while the protocol
+       translated based on state.prefer_ascii while the protocol
        portion must always be translated to the network encoding.
        To further complicate matters, line end conversion might be
        done later on, so we need to prevent CRLFs from becoming
@@ -301,7 +301,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
 
     if(
 #ifdef CURL_DO_LINEEND_CONV
-       (data->set.prefer_ascii) ||
+       (data->state.prefer_ascii) ||
 #endif
        (data->set.crlf)) {
       /* \n will become \r\n later on */
@@ -348,7 +348,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
     {
       CURLcode result;
       size_t length;
-      if(data->set.prefer_ascii)
+      if(data->state.prefer_ascii)
         /* translate the protocol and data */
         length = nread;
       else
@@ -389,7 +389,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
       nread += strlen(endofline_network); /* for the added end of line */
   }
 #ifdef CURL_DOES_CONVERSIONS
-  else if((data->set.prefer_ascii) && (!sending_http_headers)) {
+  else if((data->state.prefer_ascii) && (!sending_http_headers)) {
     CURLcode result;
     result = Curl_convert_to_network(data, data->req.upload_fromhere, nread);
     /* Curl_convert_to_network calls failf if unsuccessful */
@@ -1028,7 +1028,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
       if((!sending_http_headers) && (
 #ifdef CURL_DO_LINEEND_CONV
          /* always convert if we're FTPing in ASCII mode */
-         (data->set.prefer_ascii) ||
+         (data->state.prefer_ascii) ||
 #endif
          (data->set.crlf))) {
         /* Do we need to allocate a scratch buffer? */
@@ -1415,6 +1415,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
     }
   }
 
+  data->state.prefer_ascii = data->set.prefer_ascii;
   data->state.httpreq = data->set.method;
   data->change.url = data->set.str[STRING_SET_URL];
 
index 4d7ccd59e0e539466cf8fce83ab40b834e0bbeb3..00c7d407f48e272a819ad924557695154a8144a0 100644 (file)
@@ -1467,6 +1467,7 @@ struct UrlState {
   BIT(stream_depends_e); /* set or don't set the Exclusive bit */
   BIT(previouslypending); /* this transfer WAS in the multi->pending queue */
   BIT(cookie_engine);
+  BIT(prefer_ascii);     /* ASCII rather than binary */
 };
 
 
index 6762c8dcc133b39b3db5097d203a99ddb32550a0..228e93d80b964423a26a30605b98f273bf627365 100644 (file)
@@ -187,7 +187,7 @@ test1540 \
 \
 test1550 test1551 test1552 test1553 test1554 test1555 test1556 test1557 \
 test1558 test1559 test1560 test1561 test1562 test1563 test1564 test1565 \
-test1566 test1567 test1568 \
+test1566 test1567 test1568 test1569 \
 \
 test1590 test1591 test1592 test1593 test1594 test1595 test1596 \
 \
diff --git a/tests/data/test1569 b/tests/data/test1569
new file mode 100644 (file)
index 0000000..78f1dea
--- /dev/null
@@ -0,0 +1,73 @@
+<testcase>
+<info>
+<keywords>
+FTP
+PASV
+RETR
+</keywords>
+</info>
+# Server-side
+<reply>
+<data nocheck="yes">
+data
+    to
+      see
+that FTP
+works
+  so does it?
+</data>
+<servercmd>
+REPLY EPSV 500 no such command
+</servercmd>
+</reply>
+
+# Client-side
+<client>
+<server>
+ftp
+</server>
+ <name>
+FTP first type=A then regular URL
+ </name>
+<tool>
+lib1569
+</tool>
+<command>
+"ftp://%HOSTIP:%FTPPORT/1569;type=A" ftp://%HOSTIP:%FTPPORT/1569
+</command>
+
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+USER anonymous\r
+PASS ftp@example.com\r
+PWD\r
+EPSV\r
+PASV\r
+TYPE A\r
+RETR 1569\r
+PASV\r
+TYPE I\r
+SIZE 1569\r
+RETR 1569\r
+QUIT\r
+</protocol>
+</verify>
+<stdout>
+data
+    to
+      see
+that FTP
+works
+  so does it?
+data
+    to
+      see
+that FTP
+works
+  so does it?
+</stdout>
+
+</testcase>
index 5618952001fe8327e26d208bf66140d1eb17ab13..9f2ba8a91230bbcc89ea2d6ed978f1f478c5c442 100644 (file)
@@ -57,7 +57,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect                \
  lib1534 lib1535 lib1536 lib1537 lib1538 lib1539 \
  lib1540         \
  lib1550 lib1551 lib1552 lib1553 lib1554 lib1555 lib1556 lib1557 \
- lib1558 lib1559 lib1560 lib1564 lib1565 lib1567 lib1568 \
+ lib1558 lib1559 lib1560 lib1564 lib1565 lib1567 lib1568 lib1569 \
  lib1591 lib1592 lib1593 lib1594 lib1596 \
          lib1905 lib1906 lib1907 lib1908 lib1910 lib1911 lib1912 lib1913 \
          lib1915 lib1916 lib1917 lib1918 lib1933 lib1934 lib1935 lib1936 \
@@ -608,6 +608,9 @@ lib1567_CPPFLAGS = $(AM_CPPFLAGS)
 lib1568_SOURCES = lib1568.c $(SUPPORTFILES)
 lib1568_CPPFLAGS = $(AM_CPPFLAGS)
 
+lib1569_SOURCES = lib1569.c $(SUPPORTFILES)
+lib1569_CPPFLAGS = $(AM_CPPFLAGS)
+
 lib1591_SOURCES = lib1591.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
 lib1591_LDADD = $(TESTUTIL_LIBS)
 lib1591_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1591
diff --git a/tests/libtest/lib1569.c b/tests/libtest/lib1569.c
new file mode 100644 (file)
index 0000000..0aaba39
--- /dev/null
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "test.h"
+
+#include "testtrace.h"
+#include "memdebug.h"
+
+int test(char *URL)
+{
+  CURLcode ret;
+  CURL *hnd;
+  curl_global_init(CURL_GLOBAL_ALL);
+
+  hnd = curl_easy_init();
+  curl_easy_setopt(hnd, CURLOPT_URL, URL);
+  curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
+  curl_easy_setopt(hnd, CURLOPT_HEADER, 1L);
+
+  ret = curl_easy_perform(hnd);
+
+  curl_easy_setopt(hnd, CURLOPT_URL, libtest_arg2);
+  ret = curl_easy_perform(hnd);
+  curl_easy_cleanup(hnd);
+
+  curl_global_cleanup();
+  return (int)ret;
+}