diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ftp.c | 84 | ||||
-rw-r--r-- | lib/url.c | 7 | ||||
-rw-r--r-- | lib/urldata.h | 21 |
3 files changed, 94 insertions, 18 deletions
@@ -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: */ @@ -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 */ |