]> granicus.if.org Git - curl/commitdiff
FTP third transfer support overhaul. See CHANGES for details.
authorDaniel Stenberg <daniel@haxx.se>
Fri, 21 Jan 2005 09:32:32 +0000 (09:32 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 21 Jan 2005 09:32:32 +0000 (09:32 +0000)
18 files changed:
CHANGES
RELEASE-NOTES
docs/curl.1
docs/examples/ftp3rdparty.c
docs/libcurl/curl_easy_setopt.3
include/curl/curl.h
lib/ftp.c
lib/http.c
lib/sendf.c
lib/sendf.h
lib/transfer.c
lib/url.c
lib/urldata.h
src/main.c
tests/data/Makefile.am
tests/data/test230 [new file with mode: 0644]
tests/data/test231 [new file with mode: 0644]
tests/data/test232 [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 24db8ef7bf0fe20cd70830000806ae23d7d327ce..b5b5082a344242e6f72c54ee4aeb7cc854c8c0e7 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -7,6 +7,50 @@
                                   Changelog
 
 
+Daniel (21 January 2005)
+- Major FTP third party transfer overhaul.
+
+  These four options are now obsolete: CURLOPT_SOURCE_HOST,
+  CURLOPT_SOURCE_PATH, CURLOPT_SOURCE_PORT (this option didn't work before)
+  and CURLOPT_PASV_HOST.
+
+  These two options are added: CURLOPT_SOURCE_URL and CURLOPT_SOURCE_QUOTE.
+
+  The target-side didn't use the proper path with RETR, and thus this only
+  worked correctly in the login path (i.e without doing any CWD). The source-
+  side still uses a wrong path, but the fix for this will need to wait. Verify
+  the flaw by using a source URL with included %XX-codes.
+
+  Made CURLOPT_FTPPORT control weather the target operation should use PORT
+  (or not). The other side thus uses passive (PASV) mode.
+
+  Updated the ftp3rdparty.c example source to use the updated options.
+
+  Added support for a second FTP server in the test suite. Named... ftp2.
+  Added test cases 230, 231 and 232 as a few first basic tests of very simple
+  3rd party transfers.
+
+  Changed the debug output to include 'target' and 'source' when a 3rd party
+  is being made, to make it clearer what commands/responses came on what
+  connection.
+
+  Added three new command line options: --3p-url, --3p-user and --3p-quote.
+
+  Documented the command line options and the curl_easy_setopt options related
+  to third party transfers.
+
+  (Temporarily) disabled the ability to re-use an existing connection for the
+  source connection. This is because it needs to force a new in case the
+  source and target is the same host, and the host name check is trickier now
+  when the source is identified with a full URL instead of a plain host name
+  like before.
+
+  TODO (short-term) for 3rd party transfers: quote support. The options are
+  there, we need to add test cases to verify their functionality.
+
+  TODO (long-term) for 3rd party transfers: IPv6 support (EPRT and EPSV etc)
+  and SSL/TSL support.
+
 Daniel (20 January 2005)
 - Philippe Hameau found out that -Q "+[command]" didn't work, although some
   code was written for it. I fixed and added test case 227 to verify it.
index 47b789a38460ee449e25dcc0a79712b5486c05d7..19e672318169cc40fd2efae09240f7ab4d62e7f7 100644 (file)
@@ -1,8 +1,8 @@
-Curl and libcurl 7.12.4
+Curl and libcurl 7.13.0
 
  Public curl release number:               85
  Releases counted from the very beginning: 112
- Available command line options:           100
+ Available command line options:           103
  Available curl_easy_setopt() options:     123
  Number of public functions in libcurl:    46
  Amount of public web site mirrors:        14
@@ -10,6 +10,10 @@ Curl and libcurl 7.12.4
 
 This release includes the following changes:
 
+ o added CURLOPT_SOURCE_URL and CURLOPT_SOURCE_QUOTE
+ o obsoleted CURLOPT_SOURCE_HOST, CURLOPT_SOURCE_PATH, CURLOPT_SOURCE_PORT
+   and CURLOPT_PASV_HOST
+ o added --3p-url, --3p-user and --3p-quote
  o -Q "+[command]" was added
  o src/getpass.c license issue sorted (code was rewritten)
  o curl -w now supports 'http_connect' for the proxy's response to CONNECT
@@ -17,6 +21,7 @@ This release includes the following changes:
 
 This release includes the following bugfixes:
 
+ o FTP third party transfers was much improved
  o proxy environment variables are now ignored when built HTTP-disabled
  o CURLOPT_PROXY can now disable HTTP proxy even when built HTTP-disabled
  o "curl dictionary.com" no longer assumes DICT protocol
index f9faadbdaec0cfbe68af071715c646dec40a5689..3556d1ce6ba11daf75fae6bcc75879b30c67772c 100644 (file)
@@ -21,7 +21,7 @@
 .\" * $Id$
 .\" **************************************************************************
 .\"
-.TH curl 1 "20 Jan 2005" "Curl 7.12.4" "Curl Manual"
+.TH curl 1 "20 Jan 2005" "Curl 7.13.0" "Curl Manual"
 .SH NAME
 curl \- transfer a URL
 .SH SYNOPSIS
@@ -1065,6 +1065,17 @@ Forces curl to use SSL version 2 when negotiating with a remote SSL server.
 .IP "-3/--sslv3"
 (HTTPS)
 Forces curl to use SSL version 3 when negotiating with a remote SSL server.
+.IP "--3p-quote"
+(FTP) Specify arbitrary commands to send to the source server. See the
+\fI-Q/--quote\fP option for details. (Added in 7.13.0)
+.IP "--3p-url"
+(FTP) Activates a FTP 3rd party transfer. Specifies the source URL to get a
+file from, while the "normal" URL will be used as target URL, the file that
+will be written/created.
+
+Note that not all FTP server allow 3rd party transfers. (Added in 7.13.0)
+.IP "--3p-user"
+(FTP) Specify user:password for the source URL transfer. (Added in 7.13.0)
 .IP "-4/--ipv4"
 If libcurl is capable of resolving an address to multiple IP versions (which
 it is if it is ipv6-capable), this option tells libcurl to resolve names to
index 31391ba965ed7fea0998e232cc5789af8c7407af..b4756f58099d6cce138d68d138501ff5d0bdc956 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
  * $Id$
 
 /*
  * This is an example showing how to transfer a file between two remote hosts.
+ * 7.13.0 or later required.
  */
 
-
-
 int main(void)
 {
   CURL *curl;
   CURLcode res;
-  char sourceFileName[] = "/tmp/file";
-  char targetFileName[] = "/tmp/curlTargetTest.dat";
-  char sourceHost[] = "source";
-  char targetHost[] = "target";
+  char source_url[] = "ftp://remotehost.com/path/to/source";
+  char target_url[] = "ftp://aotherserver.com/path/to/dest";
+
   char sourceUserPass[] = "user:pass";
   char targetUserPass[] = "user:pass";
   char url[100];
-  
+
   struct curl_slist *source_pre_cmd = NULL;
   struct curl_slist *target_pre_cmd = NULL;
   struct curl_slist *source_post_cmd = NULL;
@@ -39,24 +37,25 @@ int main(void)
   char cmd[] = "PWD";   /* just to test */
 
   curl_global_init(CURL_GLOBAL_DEFAULT);
-  
+
   curl = curl_easy_init();
   if (curl) {
-    sprintf(url, "ftp://%s@%s/%s", targetUserPass, targetHost, targetFileName);
-    printf("%s\n", url);
-    curl_easy_setopt(curl, CURLOPT_URL, url);
+    /* The ordinary URL is the target when speaking 3rd party transfers */
+    curl_easy_setopt(curl, CURLOPT_URL, target_url);
 
-    /* Set a proxy host */
-    curl_easy_setopt(curl, CURLOPT_SOURCE_HOST, sourceHost);
+    /* Set a source URL */
+    curl_easy_setopt(curl, CURLOPT_SOURCE_URL, source_url);
 
-    /* Set a proxy user and password */
-    curl_easy_setopt(curl, CURLOPT_SOURCE_USERPWD, sourceUserPass);
+    /* Set target user and password */
+    curl_easy_setopt(curl, CURLOPT_USERPWD, targetUserPass);
 
-    /* Set a proxy full file name */
-    curl_easy_setopt(curl, CURLOPT_SOURCE_PATH, sourceFileName);
+    /* Set source user and password */
+    curl_easy_setopt(curl, CURLOPT_SOURCE_USERPWD, sourceUserPass);
 
-    /* Set a proxy passive host */
-    curl_easy_setopt(curl, CURLOPT_PASV_HOST, 0);   /* optional */
+#if 0
+    /* FTPPORT enables PORT on the target side, instead of PASV. */
+    curl_easy_setopt(curl, CURLOPT_FTPPORT, "");   /* optional */
+#endif
 
     /* build a list of commands to pass to libcurl */
     source_pre_cmd = curl_slist_append(source_pre_cmd, cmd);
@@ -77,7 +76,7 @@ int main(void)
     target_post_cmd = curl_slist_append(target_post_cmd, cmd);
     /* Set a post-quote command */
     curl_easy_setopt(curl, CURLOPT_POSTQUOTE, target_post_cmd);
-    
+
     /* Switch on full protocol/debug output */
     curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
 
index 7beecfd1e39ceded2ff835c86be7bc7823712774..776e3da9000e24821161d9c12a416edd4b38d310 100644 (file)
@@ -5,7 +5,7 @@
 .\" *                            | (__| |_| |  _ <| |___
 .\" *                             \___|\___/|_| \_\_____|
 .\" *
-.\" * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+.\" * Copyright (C) 1998 - 2005, 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
@@ -21,7 +21,7 @@
 .\" * $Id$
 .\" **************************************************************************
 .\"
-.TH curl_easy_setopt 3 "29 Nov 2004" "libcurl 7.12.3" "libcurl Manual"
+.TH curl_easy_setopt 3 "20 Jan 2005" "libcurl 7.12.4" "libcurl Manual"
 .SH NAME
 curl_easy_setopt - set options for a curl easy handle
 .SH SYNOPSIS
@@ -751,6 +751,18 @@ Try "AUTH SSL" first, and only if that fails try "AUTH TLS"
 .IP CURLFTPAUTH_TLS
 Try "AUTH TLS" first, and only if that fails try "AUTH SSL"
 .RE
+.IP CURLOPT_SOURCE_URL
+When set, it enables a FTP third party transfer, using the set URL as source,
+while \fICURLOPT_URL\fP is the target.
+.IP CURLOPT_SOURCE_USERPWD
+Set "username:password" to use for the source connection when doing FTP third
+party transfers.
+.IP CURLOPT_SOURCE_QUOTE
+Exactly like \fICURLOPT_QUOTE\fP, but for the source host.
+.IP CURLOPT_SOURCE_PREQUOTE
+Exactly like \fICURLOPT_PREQUOTE\fP, but for the source host.
+.IP CURLOPT_SOURCE_POSTQUOTE
+Exactly like \fICURLOPT_POSTQUOTE\fP, but for the source host.
 .SH PROTOCOL OPTIONS
 .IP CURLOPT_TRANSFERTEXT
 A non-zero parameter tells the library to use ASCII mode for ftp transfers,
index 2acf76f027da4010f6c09e4324e921e579cbd6b3..07c028b3bf10941632fc273147b6497e1df57a55 100644 (file)
@@ -712,7 +712,7 @@ typedef enum {
   CINIT(SSLENGINE_DEFAULT, LONG, 90),
 
   /* Non-zero value means to use the global dns cache */
-  CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* To become OBSOLETE soon */
+  CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* To becomeBSOLETE soon */
 
   /* DNS cache timeout */
   CINIT(DNS_CACHE_TIMEOUT, LONG, 92),
@@ -842,25 +842,15 @@ typedef enum {
   /* Enable/disable the TCP Nagle algorithm */
   CINIT(TCP_NODELAY, LONG, 121),
 
-  /* When doing 3rd party transfer, set the source host name with this */
-  CINIT(SOURCE_HOST, OBJECTPOINT, 122),
+  /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
 
   /* When doing 3rd party transfer, set the source user and password with
      this */
   CINIT(SOURCE_USERPWD, OBJECTPOINT, 123),
 
-  /* When doing 3rd party transfer, set the source file path with this */
-  CINIT(SOURCE_PATH, OBJECTPOINT, 124),
-
-  /* When doing 3rd party transfer, set the source server's port number
-     with this */
-  CINIT(SOURCE_PORT, LONG, 125),
-
-  /* When doing 3rd party transfer, decide which server that should get the
-     PASV command (and the other gets the PORT).
-     0 (default) - The target host issues PASV.
-     1           - The source host issues PASV */
-  CINIT(PASV_HOST, LONG, 126),
+  /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+  /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+  /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
 
   /* When doing 3rd party transfer, set the source pre-quote linked list
      of commands with this */
@@ -885,6 +875,13 @@ typedef enum {
   CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130),
   CINIT(IOCTLDATA, OBJECTPOINT, 131),
 
+  /* To make a 3rd party transfer, set the source URL with this */
+  CINIT(SOURCE_URL, OBJECTPOINT, 132),
+
+  /* When doing 3rd party transfer, set the source quote linked list of
+     commands with this */
+  CINIT(SOURCE_QUOTE, OBJECTPOINT, 133),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
@@ -910,6 +907,11 @@ typedef enum {
 #define CURLOPT_PASSWDDATA     -4
 #define CURLOPT_CLOSEFUNCTION  -5
 
+#define CURLOPT_SOURCE_HOST    -6
+#define CURLOPT_SOURCE_PATH    -7
+#define CURLOPT_SOURCE_PORT    -8
+#define CURLOPT_PASV_HOST      -9
+
 #else
 /* This is set if CURL_NO_OLDIES is defined at compile-time */
 #undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */
index ffec9c647d23c245bd69b92bfc7d2a6a7c2afc23..3f4b23fe781225e9bcef1c98d58c1e02cd068d44 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -368,7 +368,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
 
             /* output debug output if that is requested */
             if(data->set.verbose)
-              Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline, conn->host.dispname);
+              Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline, conn);
 
             /*
              * We pass all response-lines to the callback function registered
@@ -593,7 +593,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
   if(ftpcode == 530) {
     /* 530 User ... access denied
        (the server denies to log the specified user) */
-    failf(data, "Access denied: %s", &buf[4]);
+    failf(data, "Access denied: %03d", ftpcode);
     return CURLE_FTP_ACCESS_DENIED;
   }
   else if(ftpcode == 331) {
@@ -610,7 +610,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
       or
          530 Sorry, the maximum number of allowed users are already connected
       */
-      failf(data, "not logged in: %s", &buf[4]);
+      failf(data, "not logged in: %03d", ftpcode);
       return CURLE_FTP_USER_PASSWORD_INCORRECT;
     }
     else if(ftpcode/100 == 2) {
@@ -1594,7 +1594,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
     }
 
     if(!*str) {
-      failf(data, "Couldn't interpret this 227-reply: %s", buf);
+      failf(data, "Couldn't interpret the 227-reply");
       return CURLE_FTP_WEIRD_227_FORMAT;
     }
 
@@ -1828,7 +1828,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
       return result;
 
     if(ftpcode>=400) {
-      failf(data, "Failed FTP upload:%s", buf+3);
+      failf(data, "Failed FTP upload: %03d", ftpcode);
       /* oops, we never close the sockets! */
       return CURLE_FTP_COULDNT_STOR_FILE;
     }
@@ -2022,7 +2022,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
           return result;
 
         if(ftpcode != 350) {
-          failf(data, "Couldn't use REST: %s", buf+4);
+          failf(data, "Couldn't use REST: %03d", ftpcode);
           return CURLE_FTP_COULDNT_USE_REST;
         }
       }
@@ -2136,7 +2136,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
         ftp->no_transfer = TRUE; /* don't think we should download anything */
       }
       else {
-        failf(data, "%s", buf+4);
+        failf(data, "RETR failed: %03d", ftpcode);
         return CURLE_FTP_COULDNT_RETR_FILE;
       }
     }
@@ -2367,7 +2367,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
       break;
 
     if(conn->data->set.verbose)
-      Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written, conn->host.dispname);
+      Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written, conn);
 
     if(bytes_written != (ssize_t)write_len) {
       write_len -= bytes_written;
@@ -2553,6 +2553,9 @@ static CURLcode ftp_3rdparty_pretransfer(struct connectdata *conn)
   struct SessionHandle *data = conn->data;
   struct connectdata *sec_conn = conn->sec_conn;
 
+  conn->xfertype = TARGET3RD;
+  sec_conn->xfertype = SOURCE3RD;
+
   /* sets transfer type */
   result = ftp_transfertype(conn, data->set.ftp_ascii);
   if (result)
@@ -2596,7 +2599,7 @@ static CURLcode ftp_3rdparty_transfer(struct connectdata *conn)
   struct connectdata *pasv_conn;
   struct connectdata *port_conn;
 
-  if (data->set.pasvHost == CURL_TARGET_PASV) {
+  if (data->set.ftpport == NULL) {
     pasv_conn = conn;
     port_conn = sec_conn;
   }
@@ -2612,9 +2615,11 @@ static CURLcode ftp_3rdparty_transfer(struct connectdata *conn)
   /* sets the passive mode */
   FTPSENDF(pasv_conn, "%s", "PASV");
   result = Curl_GetFTPResponse(&nread, pasv_conn, &ftpcode);
-  if (result) return result;
+  if (result)
+    return result;
+
   if (ftpcode != 227) {
-    failf(data, "Odd return code after PASV:%s", buf + 3);
+    failf(data, "Odd return code after PASV: %03d", ftpcode);
     return CURLE_FTP_WEIRD_PASV_REPLY;
   }
 
@@ -2626,7 +2631,7 @@ static CURLcode ftp_3rdparty_transfer(struct connectdata *conn)
   }
 
   if (!*str) {
-    failf(pasv_conn->data, "Couldn't interpret this 227-reply: %s", buf);
+    failf(pasv_conn->data, "Couldn't interpret the 227-reply");
     return CURLE_FTP_WEIRD_227_FORMAT;
   }
 
@@ -2640,7 +2645,7 @@ static CURLcode ftp_3rdparty_transfer(struct connectdata *conn)
     return result;
 
   if (ftpcode != 200) {
-    failf(data, "PORT command attempts failed:%s", buf + 3);
+    failf(data, "PORT command attempts failed: %03d", ftpcode);
     return CURLE_FTP_PORT_FAILED;
   }
 
@@ -2648,41 +2653,44 @@ static CURLcode ftp_3rdparty_transfer(struct connectdata *conn)
   stor_cmd = data->set.ftp_append?"APPE":"STOR";
 
   /* transfers file between remote hosts */
-  FTPSENDF(sec_conn, "RETR %s", data->set.source_path);
+  /* FIX: this should send a series of CWD commands and then RETR only the
+     ftp->file file. The conn->path "full path" is not unescaped. Test case
+     230 tests this. */
+  FTPSENDF(sec_conn, "RETR %s", sec_conn->path);
 
-  if(data->set.pasvHost == CURL_TARGET_PASV) {
+  if(!data->set.ftpport) {
 
     result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
     if (result)
       return result;
 
-    if (ftpcode != 150) {
-      failf(data, "Failed RETR: %s", buf + 4);
+    if((ftpcode != 150) && (ftpcode != 125)) {
+      failf(data, "Failed RETR: %03d", ftpcode);
       return CURLE_FTP_COULDNT_RETR_FILE;
     }
 
-    result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->path);
+    result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->proto.ftp->file);
     if(CURLE_OK == result)
       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
     if (result)
       return result;
 
-    if (ftpcode != 150) {
-      failf(data, "Failed FTP upload: %s", buf + 4);
+    if (ftpcode >= 400) {
+      failf(data, "Failed FTP upload: %03d", ftpcode);
       return CURLE_FTP_COULDNT_STOR_FILE;
     }
 
   }
   else {
 
-    result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->path);
+    result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->proto.ftp->file);
     if(CURLE_OK == result)
       result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
     if (result)
       return result;
 
-    if (ftpcode != 150) {
-      failf(data, "Failed FTP upload: %s", buf + 4);
+    if (ftpcode >= 400) {
+      failf(data, "Failed FTP upload: %03d", ftpcode);
       return CURLE_FTP_COULDNT_STOR_FILE;
     }
 
@@ -2690,8 +2698,8 @@ static CURLcode ftp_3rdparty_transfer(struct connectdata *conn)
     if (result)
       return result;
 
-    if (ftpcode != 150) {
-      failf(data, "Failed FTP upload: %s", buf + 4);
+    if((ftpcode != 150) && (ftpcode != 125)) {
+      failf(data, "Failed FTP upload: %03d", ftpcode);
       return CURLE_FTP_COULDNT_STOR_FILE;
     }
   }
index 8e4ee7d828659a0f7971f1aa6acf7019c87ed4f6..2618c325f23af3a4d5b80087c7598a167ce0eb01 100644 (file)
@@ -858,8 +858,7 @@ CURLcode add_buffer_send(send_buffer *in,
 
     if(conn->data->set.verbose)
       /* this data _may_ contain binary stuff */
-      Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, amount,
-                 conn->host.dispname);
+      Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, amount, conn);
 
     *bytes_written += amount;
 
@@ -1140,7 +1139,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
               /* output debug if that is requested */
               if(data->set.verbose)
                 Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline,
-                           conn->host.dispname);
+                           conn);
 
               /* send the header to the callback */
               writetype = CLIENTWRITE_HEADER;
index 4094c32396798ece909b2e89ccdb402abd8b98ab..95a88a27c307c3d3bddf3cdc87ae049e65854b8f 100644 (file)
@@ -204,8 +204,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
       break;
 
     if(data->set.verbose)
-      Curl_debug(data, CURLINFO_DATA_OUT, sptr, bytes_written,
-                 conn->host.dispname);
+      Curl_debug(data, CURLINFO_DATA_OUT, sptr, bytes_written, conn);
 
     if((size_t)bytes_written != write_len) {
       /* if not all was written at once, we must advance the pointer, decrease
@@ -468,18 +467,22 @@ static int showit(struct SessionHandle *data, curl_infotype type,
 }
 
 int Curl_debug(struct SessionHandle *data, curl_infotype type,
-               char *ptr, size_t size, char *host)
+               char *ptr, size_t size,
+               struct connectdata *conn)
 {
   int rc;
-  if(data->set.printhost && host) {
+  if(data->set.printhost && conn && conn->host.dispname) {
     char buffer[160];
     const char *t=NULL;
+    const char *w="Data";
     switch (type) {
     case CURLINFO_HEADER_IN:
+      w = "Header";
     case CURLINFO_DATA_IN:
       t = "from";
       break;
     case CURLINFO_HEADER_OUT:
+      w = "Header";
     case CURLINFO_DATA_OUT:
       t = "to";
       break;
@@ -488,7 +491,10 @@ int Curl_debug(struct SessionHandle *data, curl_infotype type,
     }
 
     if(t) {
-      snprintf(buffer, sizeof(buffer), "[Data %s %s]", t, host);
+      snprintf(buffer, sizeof(buffer), "[%s %s %s%s]", w, t,
+               conn->xfertype==NORMAL?"":
+               (conn->xfertype==SOURCE3RD?"source ":"target "),
+               conn->host.dispname);
       rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer));
       if(rc)
         return rc;
index 0cd342bd7d84cbef82f874e7ddad675d5574dcb3..77ff52e3aed4a3b0f4c2a63d0c68f7662863fedb 100644 (file)
@@ -62,7 +62,8 @@ CURLcode Curl_write(struct connectdata *conn,
 
 /* the function used to output verbose information */
 int Curl_debug(struct SessionHandle *handle, curl_infotype type,
-               char *data, size_t size, char *host);
+               char *data, size_t size,
+               struct connectdata *conn);
 
 
 #endif
index 344413f0d20d63f76122745c191f5aef3c30be62..71338977d2987f22f010be09a9c1201721fba8eb 100644 (file)
@@ -935,7 +935,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
 
             if(data->set.verbose)
               Curl_debug(data, CURLINFO_HEADER_IN,
-                         k->p, k->hbuflen, conn->host.dispname);
+                         k->p, k->hbuflen, conn);
 
             result = Curl_client_write(data, writetype, k->p, k->hbuflen);
             if(result)
@@ -1032,14 +1032,12 @@ CURLcode Curl_readwrite(struct connectdata *conn,
           if(data->set.verbose) {
             if(k->badheader) {
               Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff,
-                         k->hbuflen, conn->host.dispname);
+                         k->hbuflen, conn);
               if(k->badheader == HEADER_PARTHEADER)
-                Curl_debug(data, CURLINFO_DATA_IN, k->str, nread,
-                           conn->host.dispname);
+                Curl_debug(data, CURLINFO_DATA_IN, k->str, nread, conn);
             }
             else
-              Curl_debug(data, CURLINFO_DATA_IN, k->str, nread,
-                         conn->host.dispname);
+              Curl_debug(data, CURLINFO_DATA_IN, k->str, nread, conn);
           }
 
 #ifndef CURL_DISABLE_HTTP
@@ -1270,7 +1268,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
         if(data->set.verbose)
           /* show the data before we change the pointer upload_fromhere */
           Curl_debug(data, CURLINFO_DATA_OUT, conn->upload_fromhere,
-                     bytes_written, conn->host.dispname);
+                     bytes_written, conn);
 
         if(conn->upload_present != bytes_written) {
           /* we only wrote a part of the buffer (if anything), deal with it! */
@@ -2094,7 +2092,7 @@ CURLcode Curl_perform(struct SessionHandle *data)
     res = Curl_connect_host(data, &conn);   /* primary connection */
 
     if(res == CURLE_OK) {
-      if (data->set.source_host) /* 3rd party transfer */
+      if (data->set.source_url) /* 3rd party transfer */
         res = Curl_pretransfersec(conn);
       else
         conn->sec_conn = NULL;
@@ -2105,7 +2103,7 @@ CURLcode Curl_perform(struct SessionHandle *data)
       res = Curl_do(&conn);
 
       /* for non 3rd party transfer only */
-      if(res == CURLE_OK && !data->set.source_host) {
+      if(res == CURLE_OK && !data->set.source_url) {
         res = Transfer(conn); /* now fetch that URL please */
         if(res == CURLE_OK) {
 
@@ -2236,28 +2234,26 @@ CURLcode Curl_pretransfersec(struct connectdata *conn)
   CURLcode status = CURLE_OK;
   struct SessionHandle *data = conn->data;
   struct connectdata *sec_conn = NULL;   /* secondary connection */
-  bool reuse_fresh_tmp = data->set.reuse_fresh;
-
-  /* update data with source host options */
-  char *url = aprintf( "%s://%s/", conn->protostr, data->set.source_host);
-
-  if(!url)
-    return CURLE_OUT_OF_MEMORY;
+  bool backup_reuse_fresh = data->set.reuse_fresh;
+  char *backup_userpwd = data->set.userpwd;
 
   if(data->change.url_alloc)
     free(data->change.url);
 
-  data->change.url_alloc = TRUE;
-  data->change.url = url;
-  data->set.ftpport = data->set.source_port;
-  data->set.userpwd = data->set.source_userpwd;
+  data->change.url_alloc = FALSE;
+  data->change.url = data->set.source_url;
+
+  /* We must never actually alter 'data->set' properties, so we restore the
+     backed up values afterwards! */
 
+#if 0
   /* if both remote hosts are the same host - create new connection */
   if (strequal(conn->host.dispname, data->set.source_host))
-    /* NOTE: this is restored back to the original value after the connect is
-       done */
+#endif
     data->set.reuse_fresh = TRUE;
 
+  data->set.userpwd = data->set.source_userpwd;
+
   /* secondary connection */
   status = Curl_connect_host(data, &sec_conn);
   if(CURLE_OK == status) {
@@ -2267,7 +2263,8 @@ CURLcode Curl_pretransfersec(struct connectdata *conn)
     conn->sec_conn = sec_conn;
   }
 
-  data->set.reuse_fresh = reuse_fresh_tmp;
+  data->set.reuse_fresh = backup_reuse_fresh;
+  data->set.userpwd = backup_userpwd;
 
   return status;
 }
index df2011ec6ea6427b066d7184c398f7949ae3b291..8b433f606e6a7a6d17d06ff02f4fe713dd3f252e 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -1360,19 +1360,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
     break;
 
   /*********** 3rd party transfer options ***********/
-  case CURLOPT_SOURCE_HOST:
+  case CURLOPT_SOURCE_URL:
     /*
-     * Use SOURCE HOST
+     * SOURCE URL
      */
-    data->set.source_host = va_arg(param, char *);
-    data->set.printhost = (data->set.source_host != NULL);
-    break;
-
-  case CURLOPT_SOURCE_PORT:
-    /*
-     * Use SOURCE PORT
-     */
-    data->set.source_port = va_arg(param, char *);
+    data->set.source_url = va_arg(param, char *);
+    data->set.printhost = (data->set.source_url != NULL);
     break;
 
   case CURLOPT_SOURCE_USERPWD:
@@ -1382,18 +1375,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
     data->set.source_userpwd = va_arg(param, char *);
     break;
 
-  case CURLOPT_SOURCE_PATH:
-    /*
-     * Use SOURCE PATH
-     */
-    data->set.source_path = va_arg(param, char *);
-    break;
-
-  case CURLOPT_PASV_HOST:
+  case CURLOPT_SOURCE_QUOTE:
     /*
-     * Indicates whether source or target host is passive
+     * List of RAW FTP commands to use after a connect
      */
-    data->set.pasvHost = va_arg(param, long)?CURL_SOURCE_PASV:CURL_TARGET_PASV;
+    data->set.source_quote = va_arg(param, struct curl_slist *);
     break;
 
   case CURLOPT_SOURCE_PREQUOTE:
index 311149d016bd5ab093724f746bd106e59edad2b5..0cabdf23cf288e1efa08929fccd3c3ea149d264f 100644 (file)
@@ -188,12 +188,6 @@ typedef enum {
   NTLMSTATE_LAST
 } curlntlm;
 
-/* for 3rd party transfers to decide which side that issues PASV */
-typedef enum {
-  CURL_TARGET_PASV,
-  CURL_SOURCE_PASV
-} curl_pasv_side;
-
 /* Struct used for NTLM challenge-response authentication */
 struct ntlmdata {
   curlntlm state;
@@ -614,6 +608,8 @@ struct connectdata {
 #endif
   struct connectdata *sec_conn;   /* secondary connection for 3rd party
                                      transfer */
+
+  enum { NORMAL, SOURCE3RD, TARGET3RD } xfertype;
 };
 
 /* The end of connectdata. */
@@ -869,6 +865,7 @@ struct UserDefined {
   struct curl_slist *quote;     /* after connection is established */
   struct curl_slist *postquote; /* after the transfer */
   struct curl_slist *prequote; /* before the transfer, after type */
+  struct curl_slist *source_quote;  /* 3rd party quote */
   struct curl_slist *source_prequote;  /* in 3rd party transfer mode - before
                                           the transfer on source host */
   struct curl_slist *source_postquote; /* in 3rd party transfer mode - after
@@ -901,11 +898,8 @@ struct UserDefined {
 
   curl_off_t max_filesize; /* Maximum file size to download */
 
-  char *source_host;     /* for 3rd party transfer */
-  char *source_port;     /* for 3rd party transfer */
+  char *source_url;     /* for 3rd party transfer */
   char *source_userpwd;  /* for 3rd party transfer */
-  char *source_path;     /* for 3rd party transfer */
-  curl_pasv_side pasvHost; /* for 3rd party transfer indicates passive host */
 
 /* Here follows boolean settings that define how to behave during
    this session. They are STATIC, set by libcurl users or at least initially
index bcf2cd2b4b45503e4d38609cfcb8a0937bc73aff..708b8124d1b6b540a7be5dae334bbe895f0f4feb 100644 (file)
@@ -400,13 +400,12 @@ static void help(void)
     "    --socks <host[:port]> Use SOCKS5 proxy on given host + port",
     "    --stderr <file> Where to redirect stderr. - means stdout",
     " -t/--telnet-option <OPT=val> Set telnet option",
-    "    --trace <file>  Dump a network/debug trace to the given file",
+    "    --trace <file>  Write a debug trace to the given file",
     "    --trace-ascii <file> Like --trace but without the hex output",
-    " -T/--upload-file <file> Transfer/upload <file> to remote site",
-    "    --url <URL>     Another way to specify URL to work with",
-    " -u/--user <user[:password]> Specify user and password to use",
-    "                    Overrides -n and --netrc-optional",
-    " -U/--proxy-user <user[:password]> Specify Proxy authentication",
+    " -T/--upload-file <file> Transfer <file> to remote site",
+    "    --url <URL>     Spet URL to work with",
+    " -u/--user <user[:password]> Set server user and password",
+    " -U/--proxy-user <user[:password]> Set proxy user and password",
     " -v/--verbose       Make the operation more talkative",
     " -V/--version       Show version number and quit",
 #ifdef __DJGPP__
@@ -422,6 +421,9 @@ static void help(void)
     " -1/--tlsv1         Use TLSv1 (SSL)",
     " -2/--sslv2         Use SSLv2 (SSL)",
     " -3/--sslv3         Use SSLv3 (SSL)",
+    "    --3p-quote      like -Q for the source URL for 3rd party transfer (F)",
+    "    --3p-url        source URL to activate 3rd party transfer (F)",
+    "    --3p-user       user and password for source 3rd party transfer (F)",
     " -4/--ipv4          Resolve name to IPv4 address",
     " -6/--ipv6          Resolve name to IPv6 address",
     " -#/--progress-bar  Display transfer progress as a progress bar",
@@ -540,6 +542,13 @@ struct Configurable {
   long req_retry;   /* number of retries */
   long retry_delay; /* delay between retries (in seconds) */
   long retry_maxtime; /* maximum time to keep retrying */
+
+  char *tp_url; /* third party URL */
+  char *tp_user; /* third party userpwd */
+  struct curl_slist *tp_quote;
+  struct curl_slist *tp_postquote;
+  struct curl_slist *tp_prequote;
+
 };
 
 /* global variable to hold info about libcurl */
@@ -1240,6 +1249,11 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
     {"$g", "retry",      TRUE},
     {"$h", "retry-delay", TRUE},
     {"$i", "retry-max-time", TRUE},
+
+    {"$j", "3p-url", TRUE},
+    {"$k", "3p-user", TRUE},
+    {"$l", "3p-quote", TRUE},
+
     {"0", "http1.0",     FALSE},
     {"1", "tlsv1",       FALSE},
     {"2", "sslv2",       FALSE},
@@ -1586,6 +1600,36 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
       case 'i': /* --retry-max-time */
         if(str2num(&config->retry_maxtime, nextarg))
           return PARAM_BAD_NUMERIC;
+        break;
+
+      case 'j': /* --3p-url */
+        GetStr(&config->tp_url, nextarg);
+        break;
+      case 'k': /* --3p-user */
+        GetStr(&config->tp_user, nextarg);
+        break;
+      case 'l': /* --3p-quote */
+        /* QUOTE commands to send to source FTP server */
+        err = PARAM_OK;
+        switch(nextarg[0]) {
+        case '-':
+          /* prefixed with a dash makes it a POST TRANSFER one */
+          nextarg++;
+          err = add2list(&config->tp_postquote, nextarg);
+          break;
+        case '+':
+          /* prefixed with a plus makes it a just-before-transfer one */
+          nextarg++;
+          err = add2list(&config->tp_prequote, nextarg);
+          break;
+        default:
+          err = add2list(&config->tp_quote, nextarg);
+          break;
+        }
+        if(err)
+          return err;
+
+        break;
         /* break */
       }
       break;
@@ -2782,10 +2826,17 @@ static void free_config_fields(struct Configurable *config)
     free(config->capath);
   if(config->cookiejar)
     free(config->cookiejar);
+  if(config->tp_url)
+    free(config->tp_url);
+  if(config->tp_user)
+    free(config->tp_user);
 
   curl_slist_free_all(config->quote); /* checks for config->quote == NULL */
   curl_slist_free_all(config->prequote);
   curl_slist_free_all(config->postquote);
+  curl_slist_free_all(config->tp_quote);
+  curl_slist_free_all(config->tp_prequote);
+  curl_slist_free_all(config->tp_postquote);
   curl_slist_free_all(config->headers);
 }
 
@@ -3604,6 +3655,13 @@ operate(struct Configurable *config, int argc, char *argv[])
           curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
         }
 
+        /* curl 7.12.4 */
+        curl_easy_setopt(curl, CURLOPT_SOURCE_URL, config->tp_url);
+        curl_easy_setopt(curl, CURLOPT_SOURCE_USERPWD, config->tp_user);
+        curl_easy_setopt(curl, CURLOPT_SOURCE_PREQUOTE, config->tp_prequote);
+        curl_easy_setopt(curl, CURLOPT_SOURCE_POSTQUOTE, config->tp_postquote);
+        curl_easy_setopt(curl, CURLOPT_SOURCE_QUOTE, config->tp_quote);
+
         retry_numretries = config->req_retry;
 
         retrystart = curlx_tvnow();
index 4f8b3d670a082833b7fadf57e3d22c45ef4b1b37..7fe4a1818f23dd083637bef6ada1e27dd9da8812 100644 (file)
@@ -31,7 +31,7 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46        \
  test517 test518 test210 test211 test212 test220 test221 test222       \
  test223 test224 test206 test207 test208 test209 test213 test240       \
  test241 test242 test519 test214 test215 test216 test217 test218       \
- test199 test225 test226 test227
+ test199 test225 test226 test227 test230 test231 test232
 
 # The following tests have been removed from the dist since they no longer
 # work. We need to fix the test suite's FTPS server first, then bring them
diff --git a/tests/data/test230 b/tests/data/test230
new file mode 100644 (file)
index 0000000..8ae9edf
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# Server-side
+<reply>
+<data nocheck=1>
+contents of source file 230
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+ftp
+ftp2
+</server>
+ <name>
+FTP 3rd party transfer
+ </name>
+ <command>
+ftp://%HOSTIP:%FTPPORT/dest/destpath/230 -u daniel:stenberg --3p-url ftp://%HOSTIP:%FTP2PORT/source/sourcepath/230 --3p-user daniel2:stenberg2
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+# target-side protocol check
+<protocol>
+USER daniel\r
+PASS stenberg\r
+PWD\r
+TYPE I\r
+CWD dest\r
+CWD destpath\r
+PASV\r
+STOR 230\r
+QUIT\r
+</protocol>
+<stripfile>
+s/^(PORT 127,0,0,1).*/$1/
+</stripfile>
+<file name="log/server2.input">
+USER daniel2\r
+PASS stenberg2\r
+PWD\r
+TYPE I\r
+PORT 127,0,0,1
+RETR source/sourcepath/230\r
+QUIT\r
+</file>
+</verify>
diff --git a/tests/data/test231 b/tests/data/test231
new file mode 100644 (file)
index 0000000..10ab24c
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# Server-side
+<reply>
+<data nocheck=1>
+contents of source file 231
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+ftp
+ftp2
+</server>
+ <name>
+FTP 3rd party transfer, make target use PORT
+ </name>
+ <command>
+ftp://%HOSTIP:%FTPPORT/dest/destpath/231 -u daniel:stenberg --3p-url ftp://%HOSTIP:%FTP2PORT/source/sourcepath/231 --3p-user daniel2:stenberg2 -P -
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+# target-side protocol check
+<strippart>>
+s/^(PORT 127,0,0,1).*/$1/
+</strippart>
+<protocol>
+USER daniel\r
+PASS stenberg\r
+PWD\r
+TYPE I\r
+CWD dest\r
+CWD destpath\r
+PORT 127,0,0,1
+STOR 231\r
+QUIT\r
+</protocol>
+<file name="log/server2.input">
+USER daniel2\r
+PASS stenberg2\r
+PWD\r
+TYPE I\r
+PASV\r
+RETR source/sourcepath/231\r
+QUIT\r
+</file>
+</verify>
diff --git a/tests/data/test232 b/tests/data/test232
new file mode 100644 (file)
index 0000000..2c584ef
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# Server-side
+<reply>
+<data nocheck=1>
+contents of source file 232
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+ftp
+ftp2
+</server>
+ <name>
+FTP 3rd party transfer, anonymous user
+ </name>
+ <command>
+ftp://%HOSTIP:%FTPPORT/dest/destpath/232 --3p-url ftp://%HOSTIP:%FTP2PORT/source/sourcepath/232
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+# target-side protocol check
+<protocol>
+USER anonymous\r
+PASS curl_by_daniel@haxx.se\r
+PWD\r
+TYPE I\r
+CWD dest\r
+CWD destpath\r
+PASV\r
+STOR 232\r
+QUIT\r
+</protocol>
+<stripfile>
+s/^(PORT 127,0,0,1).*/$1/
+</stripfile>
+<file name="log/server2.input">
+USER anonymous\r
+PASS curl_by_daniel@haxx.se\r
+PWD\r
+TYPE I\r
+PORT 127,0,0,1
+RETR source/sourcepath/232\r
+QUIT\r
+</file>
+</verify>