Commit ea81dd9e authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

Alexander Krasnostavsky's FTP third party transfer (proxy) support

parent 7dcb1027
Loading
Loading
Loading
Loading
+386 −175
Original line number Diff line number Diff line
@@ -119,6 +119,10 @@ static CURLcode ftp_cwd(struct connectdata *conn, char *path);
static CURLcode ftp_mkd(struct connectdata *conn, char *path);
static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path);
static CURLcode ftp_quit(struct connectdata *conn);
static CURLcode ftp_3rdparty_pretransfer(struct connectdata *conn);
static CURLcode ftp_3rdparty_transfer(struct connectdata *conn);
static CURLcode ftp_regular_transfer(struct connectdata *conn);
static CURLcode ftp_3rdparty(struct connectdata *conn);

/* easy-to-use macro: */
#define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
@@ -369,7 +373,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);
              Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline, conn->host.dispname);

            /*
             * We pass all response-lines to the callback function registered
@@ -844,8 +848,13 @@ CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
  ftp->no_transfer = FALSE;
  ftp->dont_check = FALSE;

  if (!result && conn->sec_conn) {   /* 3rd party transfer */
    /* "done" with the secondary connection */
    result = Curl_ftp_done(conn->sec_conn, status);
  }

  /* Send any post-transfer QUOTE strings? */
  if(!result && data->set.postquote)
  if(!status && !result && data->set.postquote)
    result = ftp_sendquote(conn, data->set.postquote);

  return result;
@@ -2334,116 +2343,15 @@ CURLcode ftp_perform(struct connectdata *conn,
 * parts etc as a wrapper to the actual DO function (ftp_perform).
 *
 * The input argument is already checked for validity.
 *
 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
 * Curl_ftp_done() function without finding any major problem.
 */
CURLcode Curl_ftp(struct connectdata *conn)
{
  CURLcode retcode = CURLE_OK;
  bool connected=0;
  struct SessionHandle *data = conn->data;
  struct FTP *ftp;

  char *slash_pos;  /* position of the first '/' char in curpos */
  char *cur_pos=conn->path; /* current position in ppath. point at the begin
                               of next path component */

  /* the ftp struct is already inited in ftp_connect() */
  ftp = conn->proto.ftp;
  ftp->ctl_valid = FALSE;
  conn->size = -1; /* make sure this is unknown at this point */

  Curl_pgrsSetUploadCounter(data, 0);
  Curl_pgrsSetDownloadCounter(data, 0);
  Curl_pgrsSetUploadSize(data, 0);
  Curl_pgrsSetDownloadSize(data, 0);

  ftp->dirdepth = 0;
  ftp->diralloc = 5; /* default dir depth to allocate */
  ftp->dirs = (char **)malloc(ftp->diralloc * sizeof(ftp->dirs[0]));
  if(!ftp->dirs)
    return CURLE_OUT_OF_MEMORY;
  ftp->dirs[0] = NULL; /* to start with */
  
  /* parse the URL path into separate path components */
  while((slash_pos=strchr(cur_pos, '/'))) {
    /* 1 or 0 to indicate absolute directory */
    bool absolute_dir = (cur_pos - conn->path > 0) && (ftp->dirdepth == 0);

    /* seek out the next path component */
    if (slash_pos-cur_pos) {
      /* we skip empty path components, like "x//y" since the FTP command CWD
         requires a parameter and a non-existant parameter a) doesn't work on
         many servers and b) has no effect on the others. */
      ftp->dirs[ftp->dirdepth] = curl_unescape(cur_pos - absolute_dir,
                                               slash_pos - cur_pos +
                                               absolute_dir);
    
      if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
        failf(data, "no memory");
        freedirs(ftp);
        return CURLE_OUT_OF_MEMORY;
      }
    }
    else {
      cur_pos = slash_pos + 1; /* jump to the rest of the string */
      continue;
    }

    if(!retcode) {
      cur_pos = slash_pos + 1; /* jump to the rest of the string */
      if(++ftp->dirdepth >= ftp->diralloc) {
        /* enlarge array */
        char *bigger;
        ftp->diralloc *= 2; /* double the size each time */
        bigger = realloc(ftp->dirs, ftp->diralloc * sizeof(ftp->dirs[0]));
        if(!bigger) {
          freedirs(ftp);
          return CURLE_OUT_OF_MEMORY;
        }
        ftp->dirs = (char **)bigger;
      }
    }
  }

  ftp->file = cur_pos;  /* the rest is the file name */

  if(*ftp->file) {
    ftp->file = curl_unescape(ftp->file, 0);
    if(NULL == ftp->file) {
      freedirs(ftp);
      failf(data, "no memory");
      return CURLE_OUT_OF_MEMORY;
    }
  }
  else
    ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
                       pointer */
  
  retcode = ftp_perform(conn, &connected);

  if(CURLE_OK == retcode) {
    if(connected)
      retcode = Curl_ftp_nextconnect(conn);

    if(retcode && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
      /* Failure detected, close the second socket if it was created already */
      sclose(conn->sock[SECONDARYSOCKET]);
      conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
    }

    if(ftp->no_transfer)
      /* no data to transfer */
      retcode=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);        
    else if(!connected)
      /* since we didn't connect now, we want do_more to get called */
      conn->bits.do_more = TRUE;
  }
  if (conn->sec_conn) /* 3rd party transfer */
    retcode = ftp_3rdparty(conn);
  else
    freedirs(ftp);

  ftp->ctl_valid = TRUE; /* seems good */
    retcode = ftp_regular_transfer(conn);

  return retcode;
}
@@ -2484,7 +2392,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
      break;

    if(conn->data->set.verbose)
      Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written);
      Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written, conn->host.dispname);

    if(bytes_written != (ssize_t)write_len) {
      write_len -= bytes_written;
@@ -2651,4 +2559,307 @@ static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
  return result;
}



/***********************************************************************
 *
 * ftp_3rdparty_pretransfer()
 *
 * Preparation for 3rd party transfer.
 *
 */
static CURLcode ftp_3rdparty_pretransfer(struct connectdata *conn)
{
  CURLcode result = CURLE_OK;
  struct SessionHandle *data = conn->data;
  struct connectdata *sec_conn = conn->sec_conn;

  /* sets transfer type */
  result = ftp_transfertype(conn, data->set.ftp_ascii);
  if (result)
    return result;

  result = ftp_transfertype(sec_conn, data->set.ftp_ascii);
  if (result)
    return result;

  /* Send any PREQUOTE strings after transfer type is set? */
  if (data->set.source_prequote) {
    /* sends command(s) to source server before file transfer */
    result = ftp_sendquote(sec_conn, data->set.source_prequote);
  }
  if (!result && data->set.prequote)
    result = ftp_sendquote(conn, data->set.prequote);

  return result;
}



/***********************************************************************
 *
 * ftp_3rdparty_transfer()
 *
 * Performs 3rd party transfer.
 *
 */
static CURLcode ftp_3rdparty_transfer(struct connectdata *conn)
{
  CURLcode result = CURLE_OK;
  ssize_t nread;
  int ftpcode, ip[4], port[2];
  struct SessionHandle *data = conn->data;
  struct connectdata *sec_conn = conn->sec_conn;
  char *buf = data->state.buffer;   /* this is our buffer */
  char *str = buf;
  char pasv_port[50];
  const char *stor_cmd;
  struct connectdata *pasv_conn;
  struct connectdata *port_conn;

  if (data->set.pasvHost == CURL_TARGET_PASV) {
    pasv_conn = conn;
    port_conn = sec_conn;
  }
  else {
    pasv_conn = sec_conn;
    port_conn = conn;
  }

  /* sets the passive mode */
  FTPSENDF(pasv_conn, "%s", "PASV");
  result = Curl_GetFTPResponse(&nread, pasv_conn, &ftpcode);
  if (result) return result;
  if (ftpcode != 227) {
    failf(data, "Odd return code after PASV:%s", buf + 3);
    return CURLE_FTP_WEIRD_PASV_REPLY;
  }

  while (*str) {
    if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
                    &ip[0], &ip[1], &ip[2], &ip[3], &port[0], &port[1]))
      break;
    str++;
  }

  if (!*str) {
    failf(pasv_conn->data, "Couldn't interpret this 227-reply: %s", buf);
    return CURLE_FTP_WEIRD_227_FORMAT;
  }

  snprintf(pasv_port, sizeof(pasv_port), "%d,%d,%d,%d,%d,%d", ip[0], ip[1],
           ip[2], ip[3], port[0], port[1]);

  /* sets data connection between remote hosts */
  FTPSENDF(port_conn, "PORT %s", pasv_port);
  result = Curl_GetFTPResponse(&nread, port_conn, &ftpcode);
  if (result)
    return result;

  if (ftpcode != 200) {
    failf(data, "PORT command attempts failed:%s", buf + 3);
    return CURLE_FTP_PORT_FAILED;
  }

  /* we might append onto the file instead of overwriting it */
  stor_cmd = data->set.ftp_append?"APPE":"STOR";

  /* transfers file between remote hosts */
  FTPSENDF(sec_conn, "RETR %s", data->set.source_path);

  if(data->set.pasvHost == CURL_TARGET_PASV) {

    result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
    if (result)
      return result;

    if (ftpcode != 150) {
      failf(data, "Failed RETR: %s", buf + 4);
      return CURLE_FTP_COULDNT_RETR_FILE;
    }

    result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->path);
    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);
      return CURLE_FTP_COULDNT_STOR_FILE;
    }

  }
  else {

    result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->path);
    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);
      return CURLE_FTP_COULDNT_STOR_FILE;
    }

    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
    if (result)
      return result;

    if (ftpcode != 150) {
      failf(data, "Failed FTP upload: %s", buf + 4);
      return CURLE_FTP_COULDNT_STOR_FILE;
    }
  }

  return CURLE_OK;
}



/***********************************************************************
 *
 * ftp_regular_transfer()
 *
 * The input argument is already checked for validity.
 * Performs a regular transfer between local and remote hosts.
 *
 * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
 * Curl_ftp_done() function without finding any major problem.
 */
static
CURLcode ftp_regular_transfer(struct connectdata *conn)
{
  CURLcode retcode=CURLE_OK;
  bool connected=0;
  struct SessionHandle *data = conn->data;
  struct FTP *ftp;

  char *slash_pos;  /* position of the first '/' char in curpos */
  char *cur_pos=conn->path; /* current position in ppath. point at the begin
                               of next path component */

  /* the ftp struct is already inited in ftp_connect() */
  ftp = conn->proto.ftp;
  ftp->ctl_valid = FALSE;
  conn->size = -1; /* make sure this is unknown at this point */

  Curl_pgrsSetUploadCounter(data, 0);
  Curl_pgrsSetDownloadCounter(data, 0);
  Curl_pgrsSetUploadSize(data, 0);
  Curl_pgrsSetDownloadSize(data, 0);

  ftp->dirdepth = 0;
  ftp->diralloc = 5; /* default dir depth to allocate */
  ftp->dirs = (char **)malloc(ftp->diralloc * sizeof(ftp->dirs[0]));
  if(!ftp->dirs)
    return CURLE_OUT_OF_MEMORY;
  ftp->dirs[0] = NULL; /* to start with */

  /* parse the URL path into separate path components */
  while((slash_pos=strchr(cur_pos, '/'))) {
    /* 1 or 0 to indicate absolute directory */
    bool absolute_dir = (cur_pos - conn->path > 0) && (ftp->dirdepth == 0);

    /* seek out the next path component */
    if (slash_pos-cur_pos) {
      /* we skip empty path components, like "x//y" since the FTP command CWD
         requires a parameter and a non-existant parameter a) doesn't work on
         many servers and b) has no effect on the others. */
      ftp->dirs[ftp->dirdepth] = curl_unescape(cur_pos - absolute_dir,
                                               slash_pos - cur_pos +
                                               absolute_dir);

      if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
        failf(data, "no memory");
        freedirs(ftp);
        return CURLE_OUT_OF_MEMORY;
      }
    }
    else {
      cur_pos = slash_pos + 1; /* jump to the rest of the string */
      continue;
    }

    if(!retcode) {
      cur_pos = slash_pos + 1; /* jump to the rest of the string */
      if(++ftp->dirdepth >= ftp->diralloc) {
        /* enlarge array */
        char *bigger;
        ftp->diralloc *= 2; /* double the size each time */
        bigger = realloc(ftp->dirs, ftp->diralloc * sizeof(ftp->dirs[0]));
        if(!bigger) {
          freedirs(ftp);
          return CURLE_OUT_OF_MEMORY;
        }
        ftp->dirs = (char **)bigger;
      }
    }
  }

  ftp->file = cur_pos;  /* the rest is the file name */

  if(*ftp->file) {
    ftp->file = curl_unescape(ftp->file, 0);
    if(NULL == ftp->file) {
      freedirs(ftp);
      failf(data, "no memory");
      return CURLE_OUT_OF_MEMORY;
    }
  }
  else
    ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
                       pointer */

  retcode = ftp_perform(conn, &connected);

  if(CURLE_OK == retcode) {
    if(connected)
      retcode = Curl_ftp_nextconnect(conn);

    if(retcode && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
      /* Failure detected, close the second socket if it was created already */
      sclose(conn->sock[SECONDARYSOCKET]);
      conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
    }

    if(ftp->no_transfer)
      /* no data to transfer */
      retcode=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
    else if(!connected)
      /* since we didn't connect now, we want do_more to get called */
      conn->bits.do_more = TRUE;
  }
  else
    freedirs(ftp);

  ftp->ctl_valid = TRUE; /* seems good */

  return retcode;
}



/***********************************************************************
 *
 * ftp_3rdparty()
 *
 * The input argument is already checked for validity.
 * Performs a 3rd party transfer between two remote hosts.
 */
static CURLcode ftp_3rdparty(struct connectdata *conn)
{
  CURLcode retcode = CURLE_OK;

  conn->proto.ftp->ctl_valid = conn->sec_conn->proto.ftp->ctl_valid = TRUE;
  conn->size = conn->sec_conn->size = -1;

  retcode = ftp_3rdparty_pretransfer(conn);
  if (!retcode)
    retcode = ftp_3rdparty_transfer(conn);

  return retcode;
}

#endif /* CURL_DISABLE_FTP */
+4 −2
Original line number Diff line number Diff line
@@ -740,7 +740,8 @@ 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);
      Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, amount,
                 conn->host.dispname);

    *bytes_written += amount;

@@ -1044,7 +1045,8 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,

              /* output debug output if that is requested */
              if(data->set.verbose)
                Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline);
                Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline,
                           conn->host.dispname);

              /* send the header to the callback */
              writetype = CLIENTWRITE_HEADER;
+28 −13
Original line number Diff line number Diff line
@@ -142,7 +142,7 @@ void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
    va_start(ap, fmt);
    vsnprintf(print_buffer, 1024, fmt, ap);
    va_end(ap);
    Curl_debug(data, CURLINFO_TEXT, print_buffer, strlen(print_buffer));
    Curl_debug(data, CURLINFO_TEXT, print_buffer, strlen(print_buffer), NULL);
  }
}

@@ -166,7 +166,7 @@ void Curl_failf(struct SessionHandle *data, const char *fmt, ...)
        data->set.errorbuffer[len] = '\n';
        data->set.errorbuffer[++len] = '\0';
      }
      Curl_debug(data, CURLINFO_TEXT, data->set.errorbuffer, len);
      Curl_debug(data, CURLINFO_TEXT, data->set.errorbuffer, len, NULL);
      if(doneit)
        /* cut off the newline again */
        data->set.errorbuffer[--len]=0;
@@ -204,7 +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);
      Curl_debug(data, CURLINFO_DATA_OUT, sptr, bytes_written, conn->host.dispname);

    if((size_t)bytes_written != write_len) {
      /* if not all was written at once, we must advance the pointer, decrease
@@ -440,7 +440,7 @@ int Curl_read(struct connectdata *conn, /* connection data */
}

/* return 0 on success */
int Curl_debug(struct SessionHandle *data, curl_infotype type,
static int showit(struct SessionHandle *data, curl_infotype type,
                  char *ptr, size_t size)
{
  static const char * const s_infotype[CURLINFO_END] = {
@@ -462,3 +462,18 @@ int Curl_debug(struct SessionHandle *data, curl_infotype type,
  }
  return 0;
}

int Curl_debug(struct SessionHandle *data, curl_infotype type,
               char *ptr, size_t size, char *host)
{
  int rc;
  if(data->set.printhost && host) {
    char buffer[160];
    snprintf(buffer, sizeof(buffer), "[Chunk to/from %s]", host);
    rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer));
    if(rc)
      return rc;
  }
  rc = showit(data, type, ptr, size);
  return rc;
}
+1 −1
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ 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 *data, size_t size, char *host);


#endif
+92 −38
Original line number Diff line number Diff line
@@ -875,7 +875,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,

            if(data->set.verbose)
              Curl_debug(data, CURLINFO_HEADER_IN,
                         k->p, k->hbuflen);
                         k->p, k->hbuflen, conn->host.dispname);

            result = Curl_client_write(data, writetype, k->p, k->hbuflen);
            if(result)
@@ -962,12 +962,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);
                         k->hbuflen, conn->host.dispname);
              if(k->badheader == HEADER_PARTHEADER)
                Curl_debug(data, CURLINFO_DATA_IN, k->str, nread);
                Curl_debug(data, CURLINFO_DATA_IN, k->str, nread, conn->host.dispname);
            }
            else
              Curl_debug(data, CURLINFO_DATA_IN, k->str, nread);
              Curl_debug(data, CURLINFO_DATA_IN, k->str, nread, conn->host.dispname);
          }

          if(conn->bits.chunk) {
@@ -1187,7 +1187,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);
                     bytes_written, conn->host.dispname);

        if(conn->upload_present != bytes_written) {
          /* we only wrote a part of the buffer (if anything), deal with it! */
@@ -1919,46 +1919,26 @@ CURLcode Curl_follow(struct SessionHandle *data,
  return CURLE_OK;
}

/*
 * Curl_perform() is the internal high-level function that gets called by the
 * external curl_easy_perform() function. It inits, performs and cleans up a
 * single file transfer.
 */
CURLcode Curl_perform(struct SessionHandle *data)
static CURLcode
Curl_connect_host(struct SessionHandle *data,
                  struct connectdata **conn)
{
  CURLcode res;
  CURLcode res2;
  struct connectdata *conn=NULL;
  char *newurl = NULL; /* possibly a new URL to follow to! */

  data->state.used_interface = Curl_if_easy;

  res = Curl_pretransfer(data);
  if(res)
    return res;

  /*
   * It is important that there is NO 'return' from this function at any other
   * place than falling down to the end of the function! This is because we
   * have cleanup stuff that must be done before we get back, and that is only
   * performed after this do-while loop.
   */

  do {
  CURLcode res = CURLE_OK;
  int urlchanged = FALSE;

  do {
    bool async;
    Curl_pgrsTime(data, TIMER_STARTSINGLE);
    data->change.url_changed = FALSE;
      res = Curl_connect(data, &conn, &async);
    res = Curl_connect(data, conn, &async);

    if((CURLE_OK == res) && async) {
      /* Now, if async is TRUE here, we need to wait for the name
         to resolve */
        res = Curl_wait_for_resolv(conn, NULL);
      res = Curl_wait_for_resolv(*conn, NULL);
      if(CURLE_OK == res)
        /* Resolved, continue with the connection */
          res = Curl_async_resolved(conn);
        res = Curl_async_resolved(*conn);
    }
    if(res)
      break;
@@ -1968,7 +1948,7 @@ CURLcode Curl_perform(struct SessionHandle *data)
       to the new URL */
    urlchanged = data->change.url_changed;
    if ((CURLE_OK == res) && urlchanged) {
        res = Curl_done(&conn, res);
      res = Curl_done(conn, res);
      if(CURLE_OK == res) {
        char *gotourl = strdup(data->change.url);
        res = Curl_follow(data, gotourl);
@@ -1978,10 +1958,52 @@ CURLcode Curl_perform(struct SessionHandle *data)
    }
  } while (urlchanged && res == CURLE_OK);

  return res;
}



/*
 * Curl_perform() is the internal high-level function that gets called by the
 * external curl_easy_perform() function. It inits, performs and cleans up a
 * single file transfer.
 */
CURLcode Curl_perform(struct SessionHandle *data)
{
  CURLcode res;
  CURLcode res2;
  struct connectdata *conn=NULL;
  char *newurl = NULL; /* possibly a new URL to follow to! */

  data->state.used_interface = Curl_if_easy;

  res = Curl_pretransfer(data);
  if(res)
    return res;

  /*
   * It is important that there is NO 'return' from this function at any other
   * place than falling down to the end of the function! This is because we
   * have cleanup stuff that must be done before we get back, and that is only
   * performed after this do-while loop.
   */

  do {
    res = Curl_connect_host(data, &conn);   /* primary connection */

    if(res == CURLE_OK) {
      res = Curl_do(&conn);
      if (data->set.source_host) /* 3rd party transfer */
        res = Curl_pretransfersec(conn);
      else
        conn->sec_conn = NULL;
    }

    if(res == CURLE_OK) {

      res = Curl_do(&conn);

      /* for non 3rd party transfer only */
      if(res == CURLE_OK && !data->set.source_host) {
        res = Transfer(conn); /* now fetch that URL please */
        if(res == CURLE_OK) {

@@ -2099,3 +2121,35 @@ Curl_Transfer(struct connectdata *c_conn, /* connection data */
  return CURLE_OK;

}

/*
 * Curl_pretransfersec() prepares the secondary connection (used for 3rd party
 * FTP transfers).
 */
CURLcode Curl_pretransfersec(struct connectdata *conn)
{
  CURLcode status = CURLE_OK;
  struct SessionHandle *data = conn->data;
  struct connectdata *sec_conn = NULL;   /* secondary connection */

  /* update data with source host options */
  char *url = aprintf( "%s://%s/", conn->protostr, data->set.source_host);

  if(!url)
    return CURLE_OUT_OF_MEMORY;

  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;

  /* secondary connection */
  status = Curl_connect_host(data, &sec_conn);
  sec_conn->data = data;
  conn->sec_conn = sec_conn;

  return status;
}
Loading