aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/ftp.c84
-rw-r--r--lib/url.c7
-rw-r--r--lib/urldata.h21
3 files changed, 94 insertions, 18 deletions
diff --git a/lib/ftp.c b/lib/ftp.c
index af42f3fb7..f083388c6 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -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: */
diff --git a/lib/url.c b/lib/url.c
index 1b15d6957..cfc791104 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -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:
@@ -1439,7 +1441,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
result = CURLE_FAILED_INIT; /* correct this */
break;
}
-
+
return result;
}
@@ -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" */
diff --git a/lib/urldata.h b/lib/urldata.h
index e161e8083..903f47a46 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -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 */