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

FTP improvements:

If EPSV, EPRT or LPRT is tried and doesn't work, it will not be retried on
the same server again even if a following request is made using a persistent
connection.

If a second request is made to a server, requesting a file from the same
directory as the previous request operated on, libcurl will no longer make
that long series of CWD commands just to end up on the same spot. Note that
this is only for *exactly* the same dir. There is still room for improvements
to optimize the CWD-sending when the dirs are only slightly different.

Added test 210, 211 and 212 to verify these changes. Had to improve the
test script too and added a new primitive to the test file format.
parent 5d94ff59
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -6,6 +6,22 @@

                                  Changelog

Daniel (25 November 2004)
- FTP improvements:

  If EPSV, EPRT or LPRT is tried and doesn't work, it will not be retried on
  the same server again even if a following request is made using a persistent
  connection.

  If a second request is made to a server, requesting a file from the same
  directory as the previous request operated on, libcurl will no longer make
  that long series of CWD commands just to end up on the same spot. Note that
  this is only for *exactly* the same dir. There is still room for improvements
  to optimize the CWD-sending when the dirs are only slightly different.

  Added test 210, 211 and 212 to verify these changes. Had to improve the
  test script too and added a new primitive to the test file format.

Daniel (24 November 2004)
- Andrés García fixed the configure script to detect select properly when run
  with Msys/Mingw on Windows.
+1 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ Curl and libcurl 7.12.3

This release includes the following changes:

 o persistent ftp request improvements
 o CURLOPT_IOCTLFUNCTION and CURLOPT_IOCTLDATA added. If your app uses HTTP
   Digest, NTLM or Negotiate authentication, you will most likely want to use
   these
+71 −13
Original line number Diff line number Diff line
@@ -764,6 +764,24 @@ CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)

  bool was_ctl_valid = ftp->ctl_valid;

  /* now store a copy of the directory we are in */
  if(ftp->prevpath)
    free(ftp->prevpath);
  {
    size_t flen = ftp->file?strlen(ftp->file):0;
    size_t dlen = conn->path?strlen(conn->path)-flen:0;
    if(dlen) {
      ftp->prevpath = malloc(dlen + 1);
      if(!ftp->prevpath)
        return CURLE_OUT_OF_MEMORY;
      memcpy(ftp->prevpath, conn->path, dlen);
      ftp->prevpath[dlen]=0; /* terminate */
      infof(data, "Remembering we are in dir %s\n", ftp->prevpath);
    }
    else
      ftp->prevpath = NULL; /* no path */
  }

  /* free the dir tree and file parts */
  freedirs(ftp);

@@ -1085,6 +1103,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
  unsigned char *pp;
  char portmsgbuf[1024], tmp[1024];

  enum ftpcommand { EPRT, LPRT, PORT, DONE } fcmd;
  const char *mode[] = { "EPRT", "LPRT", "PORT", NULL };
  char **modep;
  int rc;
@@ -1165,11 +1184,18 @@ CURLcode ftp_use_port(struct connectdata *conn)
    return CURLE_FTP_PORT_FAILED;
  }

  for (modep = (char **)(data->set.ftp_use_eprt?&mode[0]:&mode[2]);
       modep && *modep; modep++) {
  for (fcmd = EPRT; fcmd != DONE; fcmd++) {
    int lprtaf, eprtaf;
    int alen=0, plen=0;

    if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
      /* if disabled, goto next */
      continue;

    if(!conn->bits.ftp_use_lprt && (LPRT == fcmd))
      /* if disabled, goto next */
      continue;

    switch (sa->sa_family) {
    case AF_INET:
      ap = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_addr;
@@ -1193,7 +1219,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
      break;
    }

    if (strcmp(*modep, "EPRT") == 0) {
    if (EPRT == fcmd) {
      if (eprtaf < 0)
        continue;
      if (getnameinfo((struct sockaddr *)&ss, sslen,
@@ -1208,22 +1234,21 @@ CURLcode ftp_use_port(struct connectdata *conn)
          *q = '\0';
      }

      result = Curl_ftpsendf(conn, "%s |%d|%s|%s|", *modep, eprtaf,
      result = Curl_ftpsendf(conn, "%s |%d|%s|%s|", mode[fcmd], eprtaf,
                             portmsgbuf, tmp);
      if(result)
        return result;
    }
    else if (strcmp(*modep, "LPRT") == 0 ||
             strcmp(*modep, "PORT") == 0) {
    else if ((LPRT == fcmd) || (PORT == fcmd)) {
      int i;

      if (strcmp(*modep, "LPRT") == 0 && lprtaf < 0)
      if ((LPRT == fcmd) && lprtaf < 0)
        continue;
      if (strcmp(*modep, "PORT") == 0 && sa->sa_family != AF_INET)
      if ((PORT == fcmd) && sa->sa_family != AF_INET)
        continue;

      portmsgbuf[0] = '\0';
      if (strcmp(*modep, "LPRT") == 0) {
      if (LPRT == fcmd) {
        snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen);
        if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
            sizeof(portmsgbuf)) {
@@ -1243,7 +1268,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
        }
      }

      if (strcmp(*modep, "LPRT") == 0) {
      if (LPRT == fcmd) {
        snprintf(tmp, sizeof(tmp), ",%d", plen);

        if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf))
@@ -1259,7 +1284,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
        }
      }

      result = Curl_ftpsendf(conn, "%s %s", *modep, portmsgbuf);
      result = Curl_ftpsendf(conn, "%s %s", mode[fcmd], portmsgbuf);
      if(result)
        return result;
    }
@@ -1269,13 +1294,21 @@ CURLcode ftp_use_port(struct connectdata *conn)
      return result;

    if (ftpcode != 200) {
      if (EPRT == fcmd) {
        infof(data, "disabling EPRT usage\n");
        conn->bits.ftp_use_eprt = FALSE;
      }
      else if (LPRT == fcmd) {
        infof(data, "disabling LPRT usage\n");
        conn->bits.ftp_use_lprt = FALSE;
      }
      continue;
    }
    else
      break;
  }

  if (!*modep) {
  if (fcmd == DONE) {
    sclose(portsock);
    failf(data, "PORT command attempts failed");
    return CURLE_FTP_PORT_FAILED;
@@ -1479,7 +1512,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
  char newhost[48];
  char *newhostp=NULL;

  for (modeoff = (data->set.ftp_use_epsv?0:1);
  for (modeoff = (conn->bits.ftp_use_epsv?0:1);
       mode[modeoff]; modeoff++) {
    result = Curl_ftpsendf(conn, "%s", mode[modeoff]);
    if(result)
@@ -1489,6 +1522,12 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
      return result;
    if (ftpcode == results[modeoff])
      break;

    if(modeoff == 0) {
      /* EPSV is not supported, disable it for next transfer */
      conn->bits.ftp_use_epsv = FALSE;
      infof(data, "disabling EPSV usage\n");
    }
  }

  if (!mode[modeoff]) {
@@ -2362,6 +2401,8 @@ CURLcode Curl_ftp_disconnect(struct connectdata *conn)
      ftp->cache = NULL;
    }
    freedirs(ftp);
    if(ftp->prevpath)
      free(ftp->prevpath);
  }
  return CURLE_OK;
}
@@ -2707,6 +2748,19 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
    ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
                       pointer */

  ftp->cwddone = FALSE; /* default to not done */
  {
    size_t dlen = conn->path?strlen(conn->path):0;
    if(dlen && ftp->prevpath) {
      dlen -= ftp->file?strlen(ftp->file):0;
      if((dlen == strlen(ftp->prevpath)) &&
         curl_strnequal(conn->path, ftp->prevpath, dlen)) {
        infof(data, "Request has same path as previous transfer\n");
        ftp->cwddone = TRUE;
      }
    }
  }

  return retcode;
}

@@ -2727,6 +2781,10 @@ CURLcode ftp_cwd_and_create_path(struct connectdata *conn)
  struct FTP *ftp = conn->proto.ftp;
  int i;

  if(ftp->cwddone)
    /* already done and fine */
    return CURLE_OK;

  /* This is a re-used connection. Since we change directory to where the
     transfer is taking place, we must now get back to the original dir
     where we ended up after login: */
+6 −1
Original line number Diff line number Diff line
@@ -321,6 +321,7 @@ CURLcode Curl_open(struct SessionHandle **curl)
    data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */
    data->set.ftp_use_epsv = TRUE;   /* FTP defaults to EPSV operations */
    data->set.ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
    data->set.ftp_use_lprt = TRUE;   /* FTP defaults to EPRT operations */

    data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */

@@ -911,6 +912,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)

  case CURLOPT_FTP_USE_EPRT:
    data->set.ftp_use_eprt = va_arg(param, long)?TRUE:FALSE;
    data->set.ftp_use_lprt = data->set.ftp_use_eprt;
    break;

  case CURLOPT_FTP_USE_EPSV:
@@ -2262,6 +2264,9 @@ static CURLcode CreateConnection(struct SessionHandle *data,
  conn->bits.proxy_user_passwd = data->set.proxyuserpwd?1:0;
  conn->bits.no_body = data->set.opt_no_body;
  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
  conn->bits.ftp_use_lprt = data->set.ftp_use_lprt;

  /* This initing continues below, see the comment "Continue connectdata
   * initialization here" */
+17 −4
Original line number Diff line number Diff line
@@ -268,10 +268,12 @@ struct FTP {
  long response_time; /* When no timeout is given, this is the amount of
                         seconds we await for an FTP response. Initialized
                         in Curl_ftp_connect() */
  bool ctl_valid;     /* Tells Curl_ftp_quit() whether or not to do
                         anything. If the connection has timed out or
                         been closed, this should be FALSE when it gets
                         to Curl_ftp_quit() */
  bool ctl_valid;   /* Tells Curl_ftp_quit() whether or not to do anything. If
                       the connection has timed out or been closed, this
                       should be FALSE when it gets to Curl_ftp_quit() */
  bool cwddone;     /* if it has been determined that the proper CWD combo
                       already has been done */
  char *prevpath;   /* conn->path from the previous transfer */
};

/****************************************************************************
@@ -327,6 +329,16 @@ struct ConnectBits {
                          though it will be discarded. When the whole send
                          operation is done, we must call the data rewind
                          callback. */
  bool ftp_use_epsv;  /* As set with CURLOPT_FTP_USE_EPSV, but if we find out
                         EPSV doesn't work we disable it for the forthcoming
                         requests */

  bool ftp_use_eprt;  /* As set with CURLOPT_FTP_USE_EPRT, but if we find out
                         EPRT doesn't work we disable it for the forthcoming
                         requests */
  bool ftp_use_lprt;  /* As set with CURLOPT_FTP_USE_EPRT, but if we find out
                         LPRT doesn't work we disable it for the forthcoming
                         requests */
};

struct hostname {
@@ -931,6 +943,7 @@ struct UserDefined {
  bool expect100header;  /* TRUE if we added Expect: 100-continue */
  bool ftp_use_epsv;     /* if EPSV is to be attempted or not */
  bool ftp_use_eprt;     /* if EPRT is to be attempted or not */
  bool ftp_use_lprt;     /* if LPRT is to be attempted or not */
  curl_ftpssl ftp_ssl;   /* if AUTH TLS is to be attempted etc */
  curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */
  bool no_signal;        /* do not use any signal/alarm handler */
Loading