Alexander Krasnostavsky's FTP third party transfer (proxy) support
This commit is contained in:
parent
7dcb102733
commit
ea81dd9e2e
561
lib/ftp.c
561
lib/ftp.c
@ -1,8 +1,8 @@
|
|||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* _ _ ____ _
|
* _ _ ____ _
|
||||||
* Project ___| | | | _ \| |
|
* Project ___| | | | _ \| |
|
||||||
* / __| | | | |_) | |
|
* / __| | | | |_) | |
|
||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
@ -10,7 +10,7 @@
|
|||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||||
*
|
*
|
||||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||||
* copies of the Software, and permit persons to whom the Software is
|
* copies of the Software, and permit persons to whom the Software is
|
||||||
* furnished to do so, under the terms of the COPYING file.
|
* furnished to do so, under the terms of the COPYING file.
|
||||||
@ -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_mkd(struct connectdata *conn, char *path);
|
||||||
static CURLcode ftp_cwd_and_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_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: */
|
/* easy-to-use macro: */
|
||||||
#define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
|
#define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
|
||||||
@ -161,11 +165,11 @@ static CURLcode AllowServerConnect(struct connectdata *conn)
|
|||||||
long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000;
|
long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000;
|
||||||
long timeout = data->set.connecttimeout?data->set.connecttimeout:
|
long timeout = data->set.connecttimeout?data->set.connecttimeout:
|
||||||
(data->set.timeout?data->set.timeout: 0);
|
(data->set.timeout?data->set.timeout: 0);
|
||||||
|
|
||||||
FD_ZERO(&rdset);
|
FD_ZERO(&rdset);
|
||||||
|
|
||||||
FD_SET(sock, &rdset);
|
FD_SET(sock, &rdset);
|
||||||
|
|
||||||
if(timeout) {
|
if(timeout) {
|
||||||
timeout -= timespent;
|
timeout -= timespent;
|
||||||
if(timeout<=0) {
|
if(timeout<=0) {
|
||||||
@ -369,7 +373,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
|
|||||||
|
|
||||||
/* output debug output if that is requested */
|
/* output debug output if that is requested */
|
||||||
if(data->set.verbose)
|
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
|
* We pass all response-lines to the callback function registered
|
||||||
@ -380,7 +384,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
|
|||||||
line_start, perline);
|
line_start, perline);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
#define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
|
#define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
|
||||||
isdigit((int)line[2]) && (' ' == line[3]))
|
isdigit((int)line[2]) && (' ' == line[3]))
|
||||||
|
|
||||||
@ -560,7 +564,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send USER */
|
/* send USER */
|
||||||
FTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
|
FTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
|
||||||
|
|
||||||
@ -592,7 +596,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
|
|||||||
else if(ftpcode == 230) {
|
else if(ftpcode == 230) {
|
||||||
/* 230 User ... logged in.
|
/* 230 User ... logged in.
|
||||||
(user successfully logged in) */
|
(user successfully logged in) */
|
||||||
|
|
||||||
infof(data, "We have successfully logged in\n");
|
infof(data, "We have successfully logged in\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -611,7 +615,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
|
|||||||
*/
|
*/
|
||||||
if(conn->sec_complete)
|
if(conn->sec_complete)
|
||||||
Curl_sec_set_protection_level(conn);
|
Curl_sec_set_protection_level(conn);
|
||||||
|
|
||||||
/* We may need to issue a KAUTH here to have access to the files
|
/* We may need to issue a KAUTH here to have access to the files
|
||||||
* do it if user supplied a password
|
* do it if user supplied a password
|
||||||
*/
|
*/
|
||||||
@ -638,7 +642,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
|
|||||||
exchange (the TLS negotiation in this case)
|
exchange (the TLS negotiation in this case)
|
||||||
|
|
||||||
... (and on page 8):
|
... (and on page 8):
|
||||||
|
|
||||||
Thus the PBSZ command must still be issued, but must have a parameter
|
Thus the PBSZ command must still be issued, but must have a parameter
|
||||||
of '0' to indicate that no buffering is taking place and the data
|
of '0' to indicate that no buffering is taking place and the data
|
||||||
connection should not be encapsulated.
|
connection should not be encapsulated.
|
||||||
@ -659,7 +663,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
|
|||||||
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
|
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if(ftpcode == 200)
|
if(ftpcode == 200)
|
||||||
/* We have enabled SSL for the data connection! */
|
/* We have enabled SSL for the data connection! */
|
||||||
conn->ssl[SECONDARYSOCKET].use = TRUE;
|
conn->ssl[SECONDARYSOCKET].use = TRUE;
|
||||||
@ -684,7 +688,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
|
|||||||
|
|
||||||
if(!dir)
|
if(!dir)
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
|
||||||
/* Reply format is like
|
/* Reply format is like
|
||||||
257<space>"<directory-name>"<space><commentary> and the RFC959 says
|
257<space>"<directory-name>"<space><commentary> and the RFC959 says
|
||||||
|
|
||||||
@ -822,7 +826,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
|
|||||||
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
|
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
|
||||||
|
|
||||||
ftp->response_time = 3600; /* set this back to one hour waits */
|
ftp->response_time = 3600; /* set this back to one hour waits */
|
||||||
|
|
||||||
if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
|
if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
|
||||||
failf(data, "control connection looks dead");
|
failf(data, "control connection looks dead");
|
||||||
return result;
|
return result;
|
||||||
@ -842,10 +846,15 @@ CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
|
|||||||
|
|
||||||
/* clear these for next connection */
|
/* clear these for next connection */
|
||||||
ftp->no_transfer = FALSE;
|
ftp->no_transfer = FALSE;
|
||||||
ftp->dont_check = 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? */
|
/* Send any post-transfer QUOTE strings? */
|
||||||
if(!result && data->set.postquote)
|
if(!status && !result && data->set.postquote)
|
||||||
result = ftp_sendquote(conn, data->set.postquote);
|
result = ftp_sendquote(conn, data->set.postquote);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -859,7 +868,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
|
|||||||
* The quote list is passed as an argument.
|
* The quote list is passed as an argument.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static
|
static
|
||||||
CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
|
CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
|
||||||
{
|
{
|
||||||
struct curl_slist *item;
|
struct curl_slist *item;
|
||||||
@ -958,7 +967,7 @@ static CURLcode ftp_transfertype(struct connectdata *conn,
|
|||||||
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
|
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if(ftpcode != 200) {
|
if(ftpcode != 200) {
|
||||||
failf(data, "Couldn't set %s mode",
|
failf(data, "Couldn't set %s mode",
|
||||||
ascii?"ASCII":"binary");
|
ascii?"ASCII":"binary");
|
||||||
@ -1052,7 +1061,7 @@ ftp_pasv_verbose(struct connectdata *conn,
|
|||||||
/* Bjorn Reese (November 28 2001):
|
/* Bjorn Reese (November 28 2001):
|
||||||
The Tru64 man page on gethostbyaddr_r() says that
|
The Tru64 man page on gethostbyaddr_r() says that
|
||||||
the hostent struct must be filled with zeroes before the call to
|
the hostent struct must be filled with zeroes before the call to
|
||||||
gethostbyaddr_r().
|
gethostbyaddr_r().
|
||||||
|
|
||||||
... as must be struct hostent_data Craig Markwardt 19 Sep 2002. */
|
... as must be struct hostent_data Craig Markwardt 19 Sep 2002. */
|
||||||
|
|
||||||
@ -1065,7 +1074,7 @@ ftp_pasv_verbose(struct connectdata *conn,
|
|||||||
answer=NULL;
|
answer=NULL;
|
||||||
else
|
else
|
||||||
answer=(struct hostent *)hostent_buf;
|
answer=(struct hostent *)hostent_buf;
|
||||||
|
|
||||||
# endif
|
# endif
|
||||||
# ifdef HAVE_GETHOSTBYADDR_R_7
|
# ifdef HAVE_GETHOSTBYADDR_R_7
|
||||||
/* Solaris and IRIX */
|
/* Solaris and IRIX */
|
||||||
@ -1085,7 +1094,7 @@ ftp_pasv_verbose(struct connectdata *conn,
|
|||||||
&h_errnop))
|
&h_errnop))
|
||||||
answer=NULL; /* error */
|
answer=NULL; /* error */
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# else
|
# else
|
||||||
(void)hostent_buf; /* avoid compiler warning */
|
(void)hostent_buf; /* avoid compiler warning */
|
||||||
answer = gethostbyaddr((char *) &address, sizeof(address), AF_INET);
|
answer = gethostbyaddr((char *) &address, sizeof(address), AF_INET);
|
||||||
@ -1117,7 +1126,7 @@ ftp_pasv_verbose(struct connectdata *conn,
|
|||||||
snprintf(nbuf, sizeof(nbuf), "?");
|
snprintf(nbuf, sizeof(nbuf), "?");
|
||||||
snprintf(sbuf, sizeof(sbuf), "?");
|
snprintf(sbuf, sizeof(sbuf), "?");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
|
if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
|
||||||
hbuf, sizeof(hbuf), NULL, 0, 0)) {
|
hbuf, sizeof(hbuf), NULL, 0, 0)) {
|
||||||
infof(conn->data, "Connecting to %s (%s) port %s\n", nbuf, newhost, sbuf);
|
infof(conn->data, "Connecting to %s (%s) port %s\n", nbuf, newhost, sbuf);
|
||||||
@ -1178,7 +1187,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
|||||||
failf(data, "getsockname() returned %d\n", rc);
|
failf(data, "getsockname() returned %d\n", rc);
|
||||||
return CURLE_FTP_PORT_FAILED;
|
return CURLE_FTP_PORT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0,
|
rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0,
|
||||||
NIFLAGS);
|
NIFLAGS);
|
||||||
if(rc) {
|
if(rc) {
|
||||||
@ -1189,7 +1198,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
|||||||
memset(&hints, 0, sizeof(hints));
|
memset(&hints, 0, sizeof(hints));
|
||||||
hints.ai_family = sa->sa_family;
|
hints.ai_family = sa->sa_family;
|
||||||
/*hints.ai_family = ss.ss_family;
|
/*hints.ai_family = ss.ss_family;
|
||||||
this way can be used if sockaddr_storage is properly defined, as glibc
|
this way can be used if sockaddr_storage is properly defined, as glibc
|
||||||
2.1.X doesn't do*/
|
2.1.X doesn't do*/
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
hints.ai_flags = AI_PASSIVE;
|
hints.ai_flags = AI_PASSIVE;
|
||||||
@ -1199,7 +1208,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
|||||||
failf(data, "getaddrinfo() returned %d\n", rc);
|
failf(data, "getaddrinfo() returned %d\n", rc);
|
||||||
return CURLE_FTP_PORT_FAILED;
|
return CURLE_FTP_PORT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
portsock = CURL_SOCKET_BAD;
|
portsock = CURL_SOCKET_BAD;
|
||||||
error = 0;
|
error = 0;
|
||||||
for (ai = res; ai; ai = ai->ai_next) {
|
for (ai = res; ai; ai = ai->ai_next) {
|
||||||
@ -1221,14 +1230,14 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
|||||||
portsock = CURL_SOCKET_BAD;
|
portsock = CURL_SOCKET_BAD;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen(portsock, 1) < 0) {
|
if (listen(portsock, 1) < 0) {
|
||||||
error = Curl_ourerrno();
|
error = Curl_ourerrno();
|
||||||
sclose(portsock);
|
sclose(portsock);
|
||||||
portsock = CURL_SOCKET_BAD;
|
portsock = CURL_SOCKET_BAD;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
freeaddrinfo(res);
|
freeaddrinfo(res);
|
||||||
@ -1247,7 +1256,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
|||||||
modep && *modep; modep++) {
|
modep && *modep; modep++) {
|
||||||
int lprtaf, eprtaf;
|
int lprtaf, eprtaf;
|
||||||
int alen=0, plen=0;
|
int alen=0, plen=0;
|
||||||
|
|
||||||
switch (sa->sa_family) {
|
switch (sa->sa_family) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
ap = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_addr;
|
ap = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_addr;
|
||||||
@ -1314,45 +1323,45 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
|||||||
snprintf(tmp, sizeof(tmp), ",%u", ap[i]);
|
snprintf(tmp, sizeof(tmp), ",%u", ap[i]);
|
||||||
else
|
else
|
||||||
snprintf(tmp, sizeof(tmp), "%u", ap[i]);
|
snprintf(tmp, sizeof(tmp), "%u", ap[i]);
|
||||||
|
|
||||||
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
|
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
|
||||||
sizeof(portmsgbuf)) {
|
sizeof(portmsgbuf)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(*modep, "LPRT") == 0) {
|
if (strcmp(*modep, "LPRT") == 0) {
|
||||||
snprintf(tmp, sizeof(tmp), ",%d", plen);
|
snprintf(tmp, sizeof(tmp), ",%d", plen);
|
||||||
|
|
||||||
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf))
|
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < plen; i++) {
|
for (i = 0; i < plen; i++) {
|
||||||
snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
|
snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
|
||||||
|
|
||||||
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
|
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
|
||||||
sizeof(portmsgbuf)) {
|
sizeof(portmsgbuf)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result = Curl_ftpsendf(conn, "%s %s", *modep, portmsgbuf);
|
result = Curl_ftpsendf(conn, "%s %s", *modep, portmsgbuf);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
|
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if (ftpcode != 200) {
|
if (ftpcode != 200) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*modep) {
|
if (!*modep) {
|
||||||
sclose(portsock);
|
sclose(portsock);
|
||||||
failf(data, "PORT command attempts failed");
|
failf(data, "PORT command attempts failed");
|
||||||
@ -1362,7 +1371,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
|||||||
is only so that the cleanup function will close it in case
|
is only so that the cleanup function will close it in case
|
||||||
we fail before the true secondary stuff is made */
|
we fail before the true secondary stuff is made */
|
||||||
conn->sock[SECONDARYSOCKET] = portsock;
|
conn->sock[SECONDARYSOCKET] = portsock;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
*
|
*
|
||||||
@ -1403,7 +1412,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
|||||||
/* pick a suitable default here */
|
/* pick a suitable default here */
|
||||||
|
|
||||||
socklen_t sslen;
|
socklen_t sslen;
|
||||||
|
|
||||||
sslen = sizeof(sa);
|
sslen = sizeof(sa);
|
||||||
if (getsockname(conn->sock[FIRSTSOCKET],
|
if (getsockname(conn->sock[FIRSTSOCKET],
|
||||||
(struct sockaddr *)&sa, &sslen) < 0) {
|
(struct sockaddr *)&sa, &sslen) < 0) {
|
||||||
@ -1421,7 +1430,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
|||||||
if ( h || sa_filled_in) {
|
if ( h || sa_filled_in) {
|
||||||
if( (portsock = socket(AF_INET, SOCK_STREAM, 0)) != CURL_SOCKET_BAD ) {
|
if( (portsock = socket(AF_INET, SOCK_STREAM, 0)) != CURL_SOCKET_BAD ) {
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
/* we set the secondary socket variable to this for now, it
|
/* we set the secondary socket variable to this for now, it
|
||||||
is only so that the cleanup function will close it in case
|
is only so that the cleanup function will close it in case
|
||||||
we fail before the true secondary stuff is made */
|
we fail before the true secondary stuff is made */
|
||||||
@ -1438,7 +1447,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
|||||||
|
|
||||||
sa.sin_port = 0;
|
sa.sin_port = 0;
|
||||||
size = sizeof(sa);
|
size = sizeof(sa);
|
||||||
|
|
||||||
if(bind(portsock, (struct sockaddr *)&sa, size) >= 0) {
|
if(bind(portsock, (struct sockaddr *)&sa, size) >= 0) {
|
||||||
/* we succeeded to bind */
|
/* we succeeded to bind */
|
||||||
struct sockaddr_in add;
|
struct sockaddr_in add;
|
||||||
@ -1450,7 +1459,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
|||||||
return CURLE_FTP_PORT_FAILED;
|
return CURLE_FTP_PORT_FAILED;
|
||||||
}
|
}
|
||||||
porttouse = ntohs(add.sin_port);
|
porttouse = ntohs(add.sin_port);
|
||||||
|
|
||||||
if ( listen(portsock, 1) < 0 ) {
|
if ( listen(portsock, 1) < 0 ) {
|
||||||
failf(data, "listen(2) failed on socket");
|
failf(data, "listen(2) failed on socket");
|
||||||
return CURLE_FTP_PORT_FAILED;
|
return CURLE_FTP_PORT_FAILED;
|
||||||
@ -1492,7 +1501,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
|||||||
#endif
|
#endif
|
||||||
infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n",
|
infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n",
|
||||||
ip[0], ip[1], ip[2], ip[3], porttouse);
|
ip[0], ip[1], ip[2], ip[3], porttouse);
|
||||||
|
|
||||||
result=Curl_ftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d",
|
result=Curl_ftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d",
|
||||||
ip[0], ip[1], ip[2], ip[3],
|
ip[0], ip[1], ip[2], ip[3],
|
||||||
porttouse >> 8,
|
porttouse >> 8,
|
||||||
@ -1555,12 +1564,12 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
|
|||||||
int modeoff;
|
int modeoff;
|
||||||
unsigned short connectport; /* the local port connect() should use! */
|
unsigned short connectport; /* the local port connect() should use! */
|
||||||
unsigned short newport=0; /* remote port, not necessary the local one */
|
unsigned short newport=0; /* remote port, not necessary the local one */
|
||||||
|
|
||||||
/* newhost must be able to hold a full IP-style address in ASCII, which
|
/* newhost must be able to hold a full IP-style address in ASCII, which
|
||||||
in the IPv6 case means 5*8-1 = 39 letters */
|
in the IPv6 case means 5*8-1 = 39 letters */
|
||||||
char newhost[48];
|
char newhost[48];
|
||||||
char *newhostp=NULL;
|
char *newhostp=NULL;
|
||||||
|
|
||||||
for (modeoff = (data->set.ftp_use_epsv?0:1);
|
for (modeoff = (data->set.ftp_use_epsv?0:1);
|
||||||
mode[modeoff]; modeoff++) {
|
mode[modeoff]; modeoff++) {
|
||||||
result = Curl_ftpsendf(conn, "%s", mode[modeoff]);
|
result = Curl_ftpsendf(conn, "%s", mode[modeoff]);
|
||||||
@ -1592,7 +1601,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
|
|||||||
* "227 Data transfer will passively listen to 127,0,0,1,4,51"
|
* "227 Data transfer will passively listen to 127,0,0,1,4,51"
|
||||||
* "227 Entering passive mode. 127,0,0,1,4,51"
|
* "227 Entering passive mode. 127,0,0,1,4,51"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
while(*str) {
|
while(*str) {
|
||||||
if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
|
if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
|
||||||
&ip[0], &ip[1], &ip[2], &ip[3],
|
&ip[0], &ip[1], &ip[2], &ip[3],
|
||||||
@ -1639,7 +1648,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
|
|||||||
/* we should use the same host we already are connected to */
|
/* we should use the same host we already are connected to */
|
||||||
newhostp = conn->host.name;
|
newhostp = conn->host.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ptr=NULL;
|
ptr=NULL;
|
||||||
}
|
}
|
||||||
@ -1664,7 +1673,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
|
|||||||
rc = Curl_wait_for_resolv(conn, &addr);
|
rc = Curl_wait_for_resolv(conn, &addr);
|
||||||
|
|
||||||
connectport =
|
connectport =
|
||||||
(unsigned short)conn->port; /* we connect to the proxy's port */
|
(unsigned short)conn->port; /* we connect to the proxy's port */
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1679,7 +1688,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
|
|||||||
}
|
}
|
||||||
connectport = newport; /* we connect to the remote port */
|
connectport = newport; /* we connect to the remote port */
|
||||||
}
|
}
|
||||||
|
|
||||||
result = Curl_connecthost(conn,
|
result = Curl_connecthost(conn,
|
||||||
addr,
|
addr,
|
||||||
connectport,
|
connectport,
|
||||||
@ -1697,11 +1706,11 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
|
|||||||
* the 'connected' set to FALSE and thus we are now awaiting a non-blocking
|
* the 'connected' set to FALSE and thus we are now awaiting a non-blocking
|
||||||
* connect to connect and we should not be "hanging" here waiting.
|
* connect to connect and we should not be "hanging" here waiting.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(data->set.verbose)
|
if(data->set.verbose)
|
||||||
/* this just dumps information about this second connection */
|
/* this just dumps information about this second connection */
|
||||||
ftp_pasv_verbose(conn, conninfo, newhostp, connectport);
|
ftp_pasv_verbose(conn, conninfo, newhostp, connectport);
|
||||||
|
|
||||||
if(conn->bits.tunnel_proxy) {
|
if(conn->bits.tunnel_proxy) {
|
||||||
/* We want "seamless" FTP operations through HTTP proxy tunnel */
|
/* We want "seamless" FTP operations through HTTP proxy tunnel */
|
||||||
result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET,
|
result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET,
|
||||||
@ -1809,10 +1818,10 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
|
|||||||
|
|
||||||
/* no data to transfer */
|
/* no data to transfer */
|
||||||
result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
|
result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
|
||||||
|
|
||||||
/* Set no_transfer so that we won't get any error in
|
/* Set no_transfer so that we won't get any error in
|
||||||
* Curl_ftp_done() because we didn't transfer anything! */
|
* Curl_ftp_done() because we didn't transfer anything! */
|
||||||
ftp->no_transfer = TRUE;
|
ftp->no_transfer = TRUE;
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
@ -1867,7 +1876,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
|
|||||||
SECONDARYSOCKET, bytecountp);
|
SECONDARYSOCKET, bytecountp);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if(!conn->bits.no_body) {
|
else if(!conn->bits.no_body) {
|
||||||
/* Retrieve file or directory */
|
/* Retrieve file or directory */
|
||||||
@ -2016,7 +2025,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
|
|||||||
ftp->no_transfer = TRUE;
|
ftp->no_transfer = TRUE;
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set resume file transfer offset */
|
/* Set resume file transfer offset */
|
||||||
infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
|
infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
|
||||||
"\n",
|
"\n",
|
||||||
@ -2047,16 +2056,16 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
|
|||||||
A;
|
A;
|
||||||
150 Opening BINARY mode data connection for /etc/passwd (2241
|
150 Opening BINARY mode data connection for /etc/passwd (2241
|
||||||
bytes). (ok, the file is being transfered)
|
bytes). (ok, the file is being transfered)
|
||||||
|
|
||||||
B:
|
B:
|
||||||
150 Opening ASCII mode data connection for /bin/ls
|
150 Opening ASCII mode data connection for /bin/ls
|
||||||
|
|
||||||
C:
|
C:
|
||||||
150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
|
150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
|
||||||
|
|
||||||
D:
|
D:
|
||||||
150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
|
150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
|
||||||
|
|
||||||
E:
|
E:
|
||||||
125 Data connection already open; Transfer starting. */
|
125 Data connection already open; Transfer starting. */
|
||||||
|
|
||||||
@ -2104,7 +2113,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
|
|||||||
/* get the number! */
|
/* get the number! */
|
||||||
size = curlx_strtoofft(bytes, NULL, 0);
|
size = curlx_strtoofft(bytes, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(downloadsize > -1)
|
else if(downloadsize > -1)
|
||||||
@ -2147,7 +2156,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
|
|||||||
return CURLE_FTP_COULDNT_RETR_FILE;
|
return CURLE_FTP_COULDNT_RETR_FILE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
/* end of transfer */
|
/* end of transfer */
|
||||||
|
|
||||||
@ -2249,7 +2258,7 @@ CURLcode ftp_perform(struct connectdata *conn,
|
|||||||
int ftpcode;
|
int ftpcode;
|
||||||
|
|
||||||
ftp->no_transfer = TRUE; /* this means no actual transfer is made */
|
ftp->no_transfer = TRUE; /* this means no actual transfer is made */
|
||||||
|
|
||||||
/* Some servers return different sizes for different modes, and thus we
|
/* Some servers return different sizes for different modes, and thus we
|
||||||
must set the proper type before we check the size */
|
must set the proper type before we check the size */
|
||||||
result = ftp_transfertype(conn, data->set.ftp_ascii);
|
result = ftp_transfertype(conn, data->set.ftp_ascii);
|
||||||
@ -2322,7 +2331,7 @@ CURLcode ftp_perform(struct connectdata *conn,
|
|||||||
if(CURLE_OK == result && *connected)
|
if(CURLE_OK == result && *connected)
|
||||||
infof(data, "Connected the data stream with PASV!\n");
|
infof(data, "Connected the data stream with PASV!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2334,116 +2343,15 @@ CURLcode ftp_perform(struct connectdata *conn,
|
|||||||
* parts etc as a wrapper to the actual DO function (ftp_perform).
|
* parts etc as a wrapper to the actual DO function (ftp_perform).
|
||||||
*
|
*
|
||||||
* The input argument is already checked for validity.
|
* 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 Curl_ftp(struct connectdata *conn)
|
||||||
{
|
{
|
||||||
CURLcode retcode=CURLE_OK;
|
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 */
|
if (conn->sec_conn) /* 3rd party transfer */
|
||||||
char *cur_pos=conn->path; /* current position in ppath. point at the begin
|
retcode = ftp_3rdparty(conn);
|
||||||
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
|
else
|
||||||
ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
|
retcode = ftp_regular_transfer(conn);
|
||||||
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;
|
return retcode;
|
||||||
}
|
}
|
||||||
@ -2470,7 +2378,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
|
|||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vsnprintf(s, 250, fmt, ap);
|
vsnprintf(s, 250, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
strcat(s, "\r\n"); /* append a trailing CRLF */
|
strcat(s, "\r\n"); /* append a trailing CRLF */
|
||||||
|
|
||||||
bytes_written=0;
|
bytes_written=0;
|
||||||
@ -2484,7 +2392,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if(conn->data->set.verbose)
|
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) {
|
if(bytes_written != (ssize_t)write_len) {
|
||||||
write_len -= bytes_written;
|
write_len -= bytes_written;
|
||||||
@ -2502,7 +2410,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
|
|||||||
* ftp_quit()
|
* ftp_quit()
|
||||||
*
|
*
|
||||||
* This should be called before calling sclose() on an ftp control connection
|
* This should be called before calling sclose() on an ftp control connection
|
||||||
* (not data connections). We should then wait for the response from the
|
* (not data connections). We should then wait for the response from the
|
||||||
* server before returning. The calling code should then try to close the
|
* server before returning. The calling code should then try to close the
|
||||||
* connection.
|
* connection.
|
||||||
*
|
*
|
||||||
@ -2576,7 +2484,7 @@ static CURLcode ftp_mkd(struct connectdata *conn, char *path)
|
|||||||
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
|
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
switch(ftpcode) {
|
switch(ftpcode) {
|
||||||
case 257:
|
case 257:
|
||||||
/* success! */
|
/* success! */
|
||||||
@ -2604,13 +2512,13 @@ static CURLcode ftp_mkd(struct connectdata *conn, char *path)
|
|||||||
*
|
*
|
||||||
* This function does NOT call failf().
|
* This function does NOT call failf().
|
||||||
*/
|
*/
|
||||||
static
|
static
|
||||||
CURLcode ftp_cwd(struct connectdata *conn, char *path)
|
CURLcode ftp_cwd(struct connectdata *conn, char *path)
|
||||||
{
|
{
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
int ftpcode;
|
int ftpcode;
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
|
|
||||||
FTPSENDF(conn, "CWD %s", path);
|
FTPSENDF(conn, "CWD %s", path);
|
||||||
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
|
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
@ -2635,7 +2543,7 @@ CURLcode ftp_cwd(struct connectdata *conn, char *path)
|
|||||||
static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
|
static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
|
||||||
{
|
{
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
|
|
||||||
result = ftp_cwd(conn, path);
|
result = ftp_cwd(conn, path);
|
||||||
if (result) {
|
if (result) {
|
||||||
if(conn->data->set.ftp_create_missing_dirs) {
|
if(conn->data->set.ftp_create_missing_dirs) {
|
||||||
@ -2651,4 +2559,307 @@ static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
|
|||||||
return result;
|
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 */
|
#endif /* CURL_DISABLE_FTP */
|
||||||
|
@ -740,7 +740,8 @@ CURLcode add_buffer_send(send_buffer *in,
|
|||||||
|
|
||||||
if(conn->data->set.verbose)
|
if(conn->data->set.verbose)
|
||||||
/* this data _may_ contain binary stuff */
|
/* 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;
|
*bytes_written += amount;
|
||||||
|
|
||||||
@ -1044,7 +1045,8 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
|
|||||||
|
|
||||||
/* output debug output if that is requested */
|
/* output debug output if that is requested */
|
||||||
if(data->set.verbose)
|
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 */
|
/* send the header to the callback */
|
||||||
writetype = CLIENTWRITE_HEADER;
|
writetype = CLIENTWRITE_HEADER;
|
||||||
|
41
lib/sendf.c
41
lib/sendf.c
@ -1,8 +1,8 @@
|
|||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* _ _ ____ _
|
* _ _ ____ _
|
||||||
* Project ___| | | | _ \| |
|
* Project ___| | | | _ \| |
|
||||||
* / __| | | | |_) | |
|
* / __| | | | |_) | |
|
||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
@ -10,7 +10,7 @@
|
|||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||||
*
|
*
|
||||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||||
* copies of the Software, and permit persons to whom the Software is
|
* copies of the Software, and permit persons to whom the Software is
|
||||||
* furnished to do so, under the terms of the COPYING file.
|
* furnished to do so, under the terms of the COPYING file.
|
||||||
@ -123,7 +123,7 @@ void curl_slist_free_all(struct curl_slist *list)
|
|||||||
item = list;
|
item = list;
|
||||||
do {
|
do {
|
||||||
next = item->next;
|
next = item->next;
|
||||||
|
|
||||||
if (item->data) {
|
if (item->data) {
|
||||||
free(item->data);
|
free(item->data);
|
||||||
}
|
}
|
||||||
@ -142,7 +142,7 @@ void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
|
|||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vsnprintf(print_buffer, 1024, fmt, ap);
|
vsnprintf(print_buffer, 1024, fmt, ap);
|
||||||
va_end(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] = '\n';
|
||||||
data->set.errorbuffer[++len] = '\0';
|
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)
|
if(doneit)
|
||||||
/* cut off the newline again */
|
/* cut off the newline again */
|
||||||
data->set.errorbuffer[--len]=0;
|
data->set.errorbuffer[--len]=0;
|
||||||
@ -204,7 +204,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if(data->set.verbose)
|
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((size_t)bytes_written != write_len) {
|
||||||
/* if not all was written at once, we must advance the pointer, decrease
|
/* if not all was written at once, we must advance the pointer, decrease
|
||||||
@ -250,7 +250,7 @@ CURLcode Curl_write(struct connectdata *conn,
|
|||||||
|
|
||||||
if(rc < 0) {
|
if(rc < 0) {
|
||||||
err = SSL_get_error(conn->ssl[num].handle, rc);
|
err = SSL_get_error(conn->ssl[num].handle, rc);
|
||||||
|
|
||||||
switch(err) {
|
switch(err) {
|
||||||
case SSL_ERROR_WANT_READ:
|
case SSL_ERROR_WANT_READ:
|
||||||
case SSL_ERROR_WANT_WRITE:
|
case SSL_ERROR_WANT_WRITE:
|
||||||
@ -355,7 +355,7 @@ CURLcode Curl_client_write(struct SessionHandle *data,
|
|||||||
return CURLE_WRITE_ERROR;
|
return CURLE_WRITE_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,8 +440,8 @@ int Curl_read(struct connectdata *conn, /* connection data */
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* return 0 on success */
|
/* 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)
|
char *ptr, size_t size)
|
||||||
{
|
{
|
||||||
static const char * const s_infotype[CURLINFO_END] = {
|
static const char * const s_infotype[CURLINFO_END] = {
|
||||||
"* ", "< ", "> ", "{ ", "} " };
|
"* ", "< ", "> ", "{ ", "} " };
|
||||||
@ -462,3 +462,18 @@ int Curl_debug(struct SessionHandle *data, curl_infotype type,
|
|||||||
}
|
}
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
@ -50,7 +50,7 @@ CURLcode Curl_write(struct connectdata *conn,
|
|||||||
|
|
||||||
/* the function used to output verbose information */
|
/* the function used to output verbose information */
|
||||||
int Curl_debug(struct SessionHandle *handle, curl_infotype type,
|
int Curl_debug(struct SessionHandle *handle, curl_infotype type,
|
||||||
char *data, size_t size);
|
char *data, size_t size, char *host);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
130
lib/transfer.c
130
lib/transfer.c
@ -875,7 +875,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
|||||||
|
|
||||||
if(data->set.verbose)
|
if(data->set.verbose)
|
||||||
Curl_debug(data, CURLINFO_HEADER_IN,
|
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);
|
result = Curl_client_write(data, writetype, k->p, k->hbuflen);
|
||||||
if(result)
|
if(result)
|
||||||
@ -962,12 +962,12 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
|||||||
if(data->set.verbose) {
|
if(data->set.verbose) {
|
||||||
if(k->badheader) {
|
if(k->badheader) {
|
||||||
Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff,
|
Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff,
|
||||||
k->hbuflen);
|
k->hbuflen, conn->host.dispname);
|
||||||
if(k->badheader == HEADER_PARTHEADER)
|
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
|
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) {
|
if(conn->bits.chunk) {
|
||||||
@ -1187,7 +1187,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
|||||||
if(data->set.verbose)
|
if(data->set.verbose)
|
||||||
/* show the data before we change the pointer upload_fromhere */
|
/* show the data before we change the pointer upload_fromhere */
|
||||||
Curl_debug(data, CURLINFO_DATA_OUT, conn->upload_fromhere,
|
Curl_debug(data, CURLINFO_DATA_OUT, conn->upload_fromhere,
|
||||||
bytes_written);
|
bytes_written, conn->host.dispname);
|
||||||
|
|
||||||
if(conn->upload_present != bytes_written) {
|
if(conn->upload_present != bytes_written) {
|
||||||
/* we only wrote a part of the buffer (if anything), deal with it! */
|
/* we only wrote a part of the buffer (if anything), deal with it! */
|
||||||
@ -1919,6 +1919,50 @@ CURLcode Curl_follow(struct SessionHandle *data,
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CURLcode
|
||||||
|
Curl_connect_host(struct SessionHandle *data,
|
||||||
|
struct connectdata **conn)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
if(CURLE_OK == res)
|
||||||
|
/* Resolved, continue with the connection */
|
||||||
|
res = Curl_async_resolved(*conn);
|
||||||
|
}
|
||||||
|
if(res)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* If a callback (or something) has altered the URL we should use within
|
||||||
|
the Curl_connect(), we detect it here and act as if we are redirected
|
||||||
|
to the new URL */
|
||||||
|
urlchanged = data->change.url_changed;
|
||||||
|
if ((CURLE_OK == res) && urlchanged) {
|
||||||
|
res = Curl_done(conn, res);
|
||||||
|
if(CURLE_OK == res) {
|
||||||
|
char *gotourl = strdup(data->change.url);
|
||||||
|
res = Curl_follow(data, gotourl);
|
||||||
|
if(res)
|
||||||
|
free(gotourl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (urlchanged && res == CURLE_OK);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Curl_perform() is the internal high-level function that gets called by the
|
* 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
|
* external curl_easy_perform() function. It inits, performs and cleans up a
|
||||||
@ -1945,43 +1989,21 @@ CURLcode Curl_perform(struct SessionHandle *data)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
do {
|
do {
|
||||||
int urlchanged = FALSE;
|
res = Curl_connect_host(data, &conn); /* primary connection */
|
||||||
do {
|
|
||||||
bool async;
|
|
||||||
Curl_pgrsTime(data, TIMER_STARTSINGLE);
|
|
||||||
data->change.url_changed = FALSE;
|
|
||||||
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);
|
|
||||||
if(CURLE_OK == res)
|
|
||||||
/* Resolved, continue with the connection */
|
|
||||||
res = Curl_async_resolved(conn);
|
|
||||||
}
|
|
||||||
if(res)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* If a callback (or something) has altered the URL we should use within
|
|
||||||
the Curl_connect(), we detect it here and act as if we are redirected
|
|
||||||
to the new URL */
|
|
||||||
urlchanged = data->change.url_changed;
|
|
||||||
if ((CURLE_OK == res) && urlchanged) {
|
|
||||||
res = Curl_done(&conn, res);
|
|
||||||
if(CURLE_OK == res) {
|
|
||||||
char *gotourl = strdup(data->change.url);
|
|
||||||
res = Curl_follow(data, gotourl);
|
|
||||||
if(res)
|
|
||||||
free(gotourl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (urlchanged && res == CURLE_OK);
|
|
||||||
|
|
||||||
if(res == CURLE_OK) {
|
if(res == CURLE_OK) {
|
||||||
|
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);
|
res = Curl_do(&conn);
|
||||||
|
|
||||||
if(res == CURLE_OK) {
|
/* for non 3rd party transfer only */
|
||||||
|
if(res == CURLE_OK && !data->set.source_host) {
|
||||||
res = Transfer(conn); /* now fetch that URL please */
|
res = Transfer(conn); /* now fetch that URL please */
|
||||||
if(res == CURLE_OK) {
|
if(res == CURLE_OK) {
|
||||||
|
|
||||||
@ -2099,3 +2121,35 @@ Curl_Transfer(struct connectdata *c_conn, /* connection data */
|
|||||||
return CURLE_OK;
|
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;
|
||||||
|
}
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
CURLcode Curl_perform(struct SessionHandle *data);
|
CURLcode Curl_perform(struct SessionHandle *data);
|
||||||
CURLcode Curl_pretransfer(struct SessionHandle *data);
|
CURLcode Curl_pretransfer(struct SessionHandle *data);
|
||||||
|
CURLcode Curl_pretransfersec(struct connectdata *conn);
|
||||||
CURLcode Curl_posttransfer(struct SessionHandle *data);
|
CURLcode Curl_posttransfer(struct SessionHandle *data);
|
||||||
CURLcode Curl_follow(struct SessionHandle *data, char *newurl);
|
CURLcode Curl_follow(struct SessionHandle *data, char *newurl);
|
||||||
CURLcode Curl_readwrite(struct connectdata *conn, bool *done);
|
CURLcode Curl_readwrite(struct connectdata *conn, bool *done);
|
||||||
|
51
lib/url.c
51
lib/url.c
@ -1337,6 +1337,57 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
|
|||||||
data->set.tcp_nodelay = (bool)va_arg(param, long);
|
data->set.tcp_nodelay = (bool)va_arg(param, long);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/*********** 3rd party transfer options ***********/
|
||||||
|
case CURLOPT_SOURCE_HOST:
|
||||||
|
/*
|
||||||
|
* Use SOURCE HOST
|
||||||
|
*/
|
||||||
|
data->set.source_host = va_arg(param, char *);
|
||||||
|
data->set.printhost = (data->set.source_host != NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLOPT_SOURCE_PORT:
|
||||||
|
/*
|
||||||
|
* Use SOURCE PORT
|
||||||
|
*/
|
||||||
|
data->set.source_port = va_arg(param, char *);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLOPT_SOURCE_USERPWD:
|
||||||
|
/*
|
||||||
|
* Use SOURCE USER[:PASSWORD]
|
||||||
|
*/
|
||||||
|
data->set.source_userpwd = va_arg(param, char *);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLOPT_SOURCE_PATH:
|
||||||
|
/*
|
||||||
|
* Use SOURCE PATH
|
||||||
|
*/
|
||||||
|
data->set.source_path = va_arg(param, char *);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLOPT_PASV_HOST:
|
||||||
|
/*
|
||||||
|
* Indicates whether source or target host is passive
|
||||||
|
*/
|
||||||
|
data->set.pasvHost = va_arg(param, long)?CURL_SOURCE_PASV:CURL_TARGET_PASV;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLOPT_SOURCE_PREQUOTE:
|
||||||
|
/*
|
||||||
|
* List of RAW FTP commands to use before a transfer on the source host
|
||||||
|
*/
|
||||||
|
data->set.source_prequote = va_arg(param, struct curl_slist *);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLOPT_SOURCE_POSTQUOTE:
|
||||||
|
/*
|
||||||
|
* List of RAW FTP commands to use after a transfer on the source host
|
||||||
|
*/
|
||||||
|
data->set.source_postquote = va_arg(param, struct curl_slist *);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* unknown tag and its companion, just ignore: */
|
/* unknown tag and its companion, just ignore: */
|
||||||
return CURLE_FAILED_INIT; /* correct this */
|
return CURLE_FAILED_INIT; /* correct this */
|
||||||
|
@ -185,6 +185,12 @@ typedef enum {
|
|||||||
NTLMSTATE_LAST
|
NTLMSTATE_LAST
|
||||||
} curlntlm;
|
} curlntlm;
|
||||||
|
|
||||||
|
/* for 3rd party transfers to decide which side that issues PASV */
|
||||||
|
typedef enum {
|
||||||
|
CURL_TARGET_PASV,
|
||||||
|
CURL_SOURCE_PASV
|
||||||
|
} curl_pasv_side;
|
||||||
|
|
||||||
/* Struct used for NTLM challenge-response authentication */
|
/* Struct used for NTLM challenge-response authentication */
|
||||||
struct ntlmdata {
|
struct ntlmdata {
|
||||||
curlntlm state;
|
curlntlm state;
|
||||||
@ -601,6 +607,8 @@ struct connectdata {
|
|||||||
/* data used for the asynch name resolve callback */
|
/* data used for the asynch name resolve callback */
|
||||||
struct Curl_async async;
|
struct Curl_async async;
|
||||||
#endif
|
#endif
|
||||||
|
struct connectdata *sec_conn; /* secondary connection for 3rd party
|
||||||
|
transfer */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The end of connectdata. */
|
/* The end of connectdata. */
|
||||||
@ -845,7 +853,11 @@ struct UserDefined {
|
|||||||
bool crlf; /* convert crlf on ftp upload(?) */
|
bool crlf; /* convert crlf on ftp upload(?) */
|
||||||
struct curl_slist *quote; /* after connection is established */
|
struct curl_slist *quote; /* after connection is established */
|
||||||
struct curl_slist *postquote; /* after the transfer */
|
struct curl_slist *postquote; /* after the transfer */
|
||||||
struct curl_slist *prequote; /* before the transfer, after type (Wesley Laxton)*/
|
struct curl_slist *prequote; /* before the transfer, after type */
|
||||||
|
struct curl_slist *source_prequote; /* in 3rd party transfer mode - before
|
||||||
|
the transfer on source host */
|
||||||
|
struct curl_slist *source_postquote; /* in 3rd party transfer mode - after
|
||||||
|
the transfer on source host */
|
||||||
struct curl_slist *telnet_options; /* linked list of telnet options */
|
struct curl_slist *telnet_options; /* linked list of telnet options */
|
||||||
curl_TimeCond timecondition; /* kind of time/date comparison */
|
curl_TimeCond timecondition; /* kind of time/date comparison */
|
||||||
time_t timevalue; /* what time to compare with */
|
time_t timevalue; /* what time to compare with */
|
||||||
@ -874,10 +886,17 @@ struct UserDefined {
|
|||||||
|
|
||||||
curl_off_t max_filesize; /* Maximum file size to download */
|
curl_off_t max_filesize; /* Maximum file size to download */
|
||||||
|
|
||||||
|
char *source_host; /* for 3rd party transfer */
|
||||||
|
char *source_port; /* for 3rd party transfer */
|
||||||
|
char *source_userpwd; /* for 3rd party transfer */
|
||||||
|
char *source_path; /* for 3rd party transfer */
|
||||||
|
curl_pasv_side pasvHost; /* for 3rd party transfer indicates passive host */
|
||||||
|
|
||||||
/* 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. */
|
||||||
|
|
||||||
|
bool printhost; /* printing host name in debug info */
|
||||||
bool get_filetime;
|
bool get_filetime;
|
||||||
bool tunnel_thru_httpproxy;
|
bool tunnel_thru_httpproxy;
|
||||||
bool ftp_append;
|
bool ftp_append;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user