new experimental "ftp method" code

This commit is contained in:
Daniel Stenberg 2005-11-28 23:06:00 +00:00
parent cdf4afbe50
commit 0fd282b078
5 changed files with 111 additions and 48 deletions

View File

@ -909,6 +909,9 @@ typedef enum {
control connection. */ control connection. */
CINIT(FTP_SKIP_PASV_IP, LONG, 137), CINIT(FTP_SKIP_PASV_IP, LONG, 137),
/* Select "file method" to use when doing FTP */
CINIT(FTP_FILEMETHOD, LONG, 138),
CURLOPT_LASTENTRY /* the last unused */ CURLOPT_LASTENTRY /* the last unused */
} CURLoption; } CURLoption;

111
lib/ftp.c
View File

@ -3642,8 +3642,6 @@ static CURLcode ftp_3rdparty_transfer(struct connectdata *conn)
return CURLE_OK; return CURLE_OK;
} }
/*********************************************************************** /***********************************************************************
* *
* ftp_parse_url_path() * ftp_parse_url_path()
@ -3667,58 +3665,87 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
ftp = conn->proto.ftp; ftp = conn->proto.ftp;
ftp->ctl_valid = FALSE; ftp->ctl_valid = FALSE;
ftp->dirdepth = 0; switch(data->set.ftp_filemethod) {
ftp->diralloc = 5; /* default dir depth to allocate */ case FTPFILE_NOCWD:
ftp->dirs = (char **)calloc(ftp->diralloc, sizeof(ftp->dirs[0])); /* fastest, but less standard-compliant */
if(!ftp->dirs) ftp->file = conn->path; /* this is a full file path */
return CURLE_OUT_OF_MEMORY; break;
/* parse the URL path into separate path components */ case FTPFILE_SINGLECWD:
while((slash_pos=strchr(cur_pos, '/'))) { /* get the last slash */
/* 1 or 0 to indicate absolute directory */ slash_pos=strrchr(cur_pos, '/');
bool absolute_dir = (cur_pos - conn->path > 0) && (ftp->dirdepth == 0); if(slash_pos) {
ftp->dirdepth = 1; /* we consider it to be a single dir */
ftp->dirs = (char **)calloc(1, sizeof(ftp->dirs[0]));
if(!ftp->dirs)
return CURLE_OUT_OF_MEMORY;
/* seek out the next path component */ ftp->dirs[0] = curl_unescape(cur_pos, slash_pos-cur_pos);
if (slash_pos-cur_pos) { if(!ftp->dirs[0]) {
/* we skip empty path components, like "x//y" since the FTP command CWD free(ftp->dirs);
requires a parameter and a non-existant parameter a) doesn't work on
many servers and b) has no effect on the others. */
int len = (int)(slash_pos - cur_pos + absolute_dir);
ftp->dirs[ftp->dirdepth] = curl_unescape(cur_pos - absolute_dir, len);
if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
failf(data, "no memory");
freedirs(ftp);
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
if (isBadFtpString(ftp->dirs[ftp->dirdepth])) { ftp->file = slash_pos+1; /* the rest is the file name */
freedirs(ftp);
return CURLE_URL_MALFORMAT;
}
}
else {
cur_pos = slash_pos + 1; /* jump to the rest of the string */
continue;
} }
else
ftp->file = cur_pos; /* this is a file name only */
break;
if(!retcode) { default: /* allow pretty much anything */
cur_pos = slash_pos + 1; /* jump to the rest of the string */ case FTPFILE_MULTICWD:
if(++ftp->dirdepth >= ftp->diralloc) { ftp->dirdepth = 0;
/* enlarge array */ ftp->diralloc = 5; /* default dir depth to allocate */
char *bigger; ftp->dirs = (char **)calloc(ftp->diralloc, sizeof(ftp->dirs[0]));
ftp->diralloc *= 2; /* double the size each time */ if(!ftp->dirs)
bigger = realloc(ftp->dirs, ftp->diralloc * sizeof(ftp->dirs[0])); return CURLE_OUT_OF_MEMORY;
if(!bigger) {
ftp->dirdepth--; /* 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. */
int len = (int)(slash_pos - cur_pos + absolute_dir);
ftp->dirs[ftp->dirdepth] = curl_unescape(cur_pos - absolute_dir, len);
if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
failf(data, "no memory");
freedirs(ftp); freedirs(ftp);
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
ftp->dirs = (char **)bigger; if (isBadFtpString(ftp->dirs[ftp->dirdepth])) {
freedirs(ftp);
return CURLE_URL_MALFORMAT;
}
}
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) {
ftp->dirdepth--;
freedirs(ftp);
return CURLE_OUT_OF_MEMORY;
}
ftp->dirs = (char **)bigger;
}
} }
} }
}
ftp->file = cur_pos; /* the rest is the file name */ ftp->file = cur_pos; /* the rest is the file name */
}
if(*ftp->file) { if(*ftp->file) {
ftp->file = curl_unescape(ftp->file, 0); ftp->file = curl_unescape(ftp->file, 0);

View File

@ -327,7 +327,7 @@ CURLcode Curl_open(struct SessionHandle **curl)
data->set.ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ 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_eprt = TRUE; /* FTP defaults to EPRT operations */
data->set.ftp_use_lprt = TRUE; /* FTP defaults to EPRT operations */ data->set.ftp_use_lprt = TRUE; /* FTP defaults to EPRT operations */
data->set.ftp_filemethod = FTPFILE_MULTICWD;
data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
/* make libcurl quiet by default: */ /* make libcurl quiet by default: */
@ -557,6 +557,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
*/ */
data->set.ftp_append = va_arg(param, long)?TRUE:FALSE; data->set.ftp_append = va_arg(param, long)?TRUE:FALSE;
break; break;
case CURLOPT_FTP_FILEMETHOD:
/*
* How do access files over FTP.
*/
data->set.ftp_filemethod = va_arg(param, long);
break;
case CURLOPT_NETRC: case CURLOPT_NETRC:
/* /*
* Parse the $HOME/.netrc file * Parse the $HOME/.netrc file

View File

@ -310,6 +310,12 @@ typedef enum {
FTP_LAST /* never used */ FTP_LAST /* never used */
} ftpstate; } ftpstate;
typedef enum {
FTPFILE_MULTICWD = 1, /* as defined by RFC1738 */
FTPFILE_NOCWD = 2, /* use SIZE / RETR / STOR on the full path */
FTPFILE_SINGLECWD = 3 /* make one CWD, then SIZE / RETR / STOR on the file */
} curl_ftpfile;
struct FTP { struct FTP {
curl_off_t *bytecountp; curl_off_t *bytecountp;
char *user; /* user name string */ char *user; /* user name string */
@ -424,10 +430,10 @@ struct ConnectBits {
LPRT doesn't work we disable it for the forthcoming LPRT doesn't work we disable it for the forthcoming
requests */ requests */
bool netrc; /* name+password provided by netrc */ bool netrc; /* name+password provided by netrc */
bool trailerHdrPresent; /* Set when Trailer: header found in HTTP response. bool trailerHdrPresent; /* Set when Trailer: header found in HTTP response.
Required to determine whether to look for trailers Required to determine whether to look for trailers
in case of Transfer-Encoding: chunking */ in case of Transfer-Encoding: chunking */
}; };
struct hostname { struct hostname {
@ -1035,6 +1041,8 @@ struct UserDefined {
char *source_url; /* for 3rd party transfer */ char *source_url; /* for 3rd party transfer */
char *source_userpwd; /* for 3rd party transfer */ char *source_userpwd; /* for 3rd party transfer */
curl_ftpfile ftp_filemethod; /* how to get to a file when FTP is used */
/* Here follows boolean settings that define how to behave during /* Here follows boolean settings that define how to behave during
this session. They are STATIC, set by libcurl users or at least initially this session. They are STATIC, set by libcurl users or at least initially
and they don't change during operations. */ and they don't change during operations. */

View File

@ -357,6 +357,7 @@ struct Configurable {
struct curl_slist *tp_postquote; struct curl_slist *tp_postquote;
struct curl_slist *tp_prequote; struct curl_slist *tp_prequote;
char *ftp_account; /* for ACCT */ char *ftp_account; /* for ACCT */
int ftp_filemethod;
bool ignorecl; /* --ignore-content-length */ bool ignorecl; /* --ignore-content-length */
}; };
@ -1244,6 +1245,18 @@ static ParameterError add2list(struct curl_slist **list,
return PARAM_OK; return PARAM_OK;
} }
static int ftpfilemethod(struct Configurable *config, char *str)
{
if(strequal("singlecwd", str))
return 3;
if(strequal("nocwd", str))
return 2;
if(strequal("multicwd", str))
return 1;
warnf(config, "unrecognized ftp file method '%s', using default\n", str);
return 1;
}
static ParameterError getparameter(char *flag, /* f or -long-flag */ static ParameterError getparameter(char *flag, /* f or -long-flag */
char *nextarg, /* NULL if unset */ char *nextarg, /* NULL if unset */
bool *usedarg, /* set to TRUE if the arg bool *usedarg, /* set to TRUE if the arg
@ -1316,6 +1329,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
{"$o", "trace-time", FALSE}, {"$o", "trace-time", FALSE},
{"$p", "ignore-content-length", FALSE}, {"$p", "ignore-content-length", FALSE},
{"$q", "ftp-skip-pasv-ip", FALSE}, {"$q", "ftp-skip-pasv-ip", FALSE},
{"$r", "ftp-method", TRUE},
{"0", "http1.0", FALSE}, {"0", "http1.0", FALSE},
{"1", "tlsv1", FALSE}, {"1", "tlsv1", FALSE},
@ -1726,6 +1740,9 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
case 'q': /* --ftp-skip-pasv-ip */ case 'q': /* --ftp-skip-pasv-ip */
config->ftp_skip_ip ^= TRUE; config->ftp_skip_ip ^= TRUE;
break; break;
case 'r': /* --ftp-method (undocumented at this point) */
config->ftp_filemethod = ftpfilemethod(config, nextarg);
break;
} }
break; break;
case '#': /* --progress-bar */ case '#': /* --progress-bar */
@ -3944,8 +3961,10 @@ operate(struct Configurable *config, int argc, char *argv[])
curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl); curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl);
/* curl 7.14.2 */ /* curl 7.14.2 */
curl_easy_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, curl_easy_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip);
config->ftp_skip_ip);
/* curl 7.15.1 */
curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod);
retry_numretries = config->req_retry; retry_numretries = config->req_retry;