1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-21 23:58:49 -05:00

Alexander Krasnostavsky's FTP third party transfer (proxy) support

This commit is contained in:
Daniel Stenberg 2004-06-03 11:41:05 +00:00
parent 7dcb102733
commit ea81dd9e2e
8 changed files with 583 additions and 230 deletions

427
lib/ftp.c
View 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_cwd_and_mkd(struct connectdata *conn, char *path);
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: */
#define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
@ -369,7 +373,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
/* output debug output if that is requested */
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
@ -844,8 +848,13 @@ CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
ftp->no_transfer = 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? */
if(!result && data->set.postquote)
if(!status && !result && data->set.postquote)
result = ftp_sendquote(conn, data->set.postquote);
return result;
@ -2334,116 +2343,15 @@ CURLcode ftp_perform(struct connectdata *conn,
* parts etc as a wrapper to the actual DO function (ftp_perform).
*
* 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 retcode=CURLE_OK;
bool connected=0;
struct SessionHandle *data = conn->data;
struct FTP *ftp;
CURLcode retcode = CURLE_OK;
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;
}
}
if (conn->sec_conn) /* 3rd party transfer */
retcode = ftp_3rdparty(conn);
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 */
retcode = ftp_regular_transfer(conn);
return retcode;
}
@ -2484,7 +2392,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
break;
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) {
write_len -= bytes_written;
@ -2651,4 +2559,307 @@ static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
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 */

View File

@ -740,7 +740,8 @@ CURLcode add_buffer_send(send_buffer *in,
if(conn->data->set.verbose)
/* 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;
@ -1044,7 +1045,8 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
/* output debug output if that is requested */
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 */
writetype = CLIENTWRITE_HEADER;

View File

@ -142,7 +142,7 @@ void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
va_start(ap, fmt);
vsnprintf(print_buffer, 1024, fmt, 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] = '\0';
}
Curl_debug(data, CURLINFO_TEXT, data->set.errorbuffer, len);
Curl_debug(data, CURLINFO_TEXT, data->set.errorbuffer, len, NULL);
if(doneit)
/* cut off the newline again */
data->set.errorbuffer[--len]=0;
@ -204,7 +204,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
break;
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 not all was written at once, we must advance the pointer, decrease
@ -440,7 +440,7 @@ int Curl_read(struct connectdata *conn, /* connection data */
}
/* 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)
{
static const char * const s_infotype[CURLINFO_END] = {
@ -462,3 +462,18 @@ int Curl_debug(struct SessionHandle *data, curl_infotype type,
}
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;
}

View File

@ -50,7 +50,7 @@ CURLcode Curl_write(struct connectdata *conn,
/* the function used to output verbose information */
int Curl_debug(struct SessionHandle *handle, curl_infotype type,
char *data, size_t size);
char *data, size_t size, char *host);
#endif

View File

@ -875,7 +875,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(data->set.verbose)
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);
if(result)
@ -962,12 +962,12 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(data->set.verbose) {
if(k->badheader) {
Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff,
k->hbuflen);
k->hbuflen, conn->host.dispname);
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
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) {
@ -1187,7 +1187,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(data->set.verbose)
/* show the data before we change the pointer upload_fromhere */
Curl_debug(data, CURLINFO_DATA_OUT, conn->upload_fromhere,
bytes_written);
bytes_written, conn->host.dispname);
if(conn->upload_present != bytes_written) {
/* 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;
}
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
* external curl_easy_perform() function. It inits, performs and cleans up a
@ -1945,43 +1989,21 @@ CURLcode Curl_perform(struct SessionHandle *data)
*/
do {
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);
res = Curl_connect_host(data, &conn); /* primary connection */
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);
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 */
if(res == CURLE_OK) {
@ -2099,3 +2121,35 @@ Curl_Transfer(struct connectdata *c_conn, /* connection data */
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;
}

View File

@ -24,6 +24,7 @@
***************************************************************************/
CURLcode Curl_perform(struct SessionHandle *data);
CURLcode Curl_pretransfer(struct SessionHandle *data);
CURLcode Curl_pretransfersec(struct connectdata *conn);
CURLcode Curl_posttransfer(struct SessionHandle *data);
CURLcode Curl_follow(struct SessionHandle *data, char *newurl);
CURLcode Curl_readwrite(struct connectdata *conn, bool *done);

View File

@ -1337,6 +1337,57 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
data->set.tcp_nodelay = (bool)va_arg(param, long);
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:
/* unknown tag and its companion, just ignore: */
return CURLE_FAILED_INIT; /* correct this */

View File

@ -185,6 +185,12 @@ typedef enum {
NTLMSTATE_LAST
} 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 ntlmdata {
curlntlm state;
@ -601,6 +607,8 @@ struct connectdata {
/* data used for the asynch name resolve callback */
struct Curl_async async;
#endif
struct connectdata *sec_conn; /* secondary connection for 3rd party
transfer */
};
/* The end of connectdata. */
@ -845,7 +853,11 @@ struct UserDefined {
bool crlf; /* convert crlf on ftp upload(?) */
struct curl_slist *quote; /* after connection is established */
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 */
curl_TimeCond timecondition; /* kind of time/date comparison */
time_t timevalue; /* what time to compare with */
@ -874,10 +886,17 @@ struct UserDefined {
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
this session. They are STATIC, set by libcurl users or at least initially
and they don't change during operations. */
bool printhost; /* printing host name in debug info */
bool get_filetime;
bool tunnel_thru_httpproxy;
bool ftp_append;