Loading lib/ftp.c +386 −175 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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; 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; } if (conn->sec_conn) /* 3rd party transfer */ retcode = ftp_3rdparty(conn); else freedirs(ftp); ftp->ctl_valid = TRUE; /* seems good */ retcode = ftp_regular_transfer(conn); return retcode; } Loading Loading @@ -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; Loading Loading @@ -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 */ lib/http.c +4 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading lib/sendf.c +28 −13 Original line number Diff line number Diff line Loading @@ -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); } } Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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] = { Loading @@ -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; } lib/sendf.h +1 −1 Original line number Diff line number Diff line Loading @@ -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 lib/transfer.c +92 −38 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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) { Loading Loading @@ -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! */ Loading Loading @@ -1919,46 +1919,26 @@ CURLcode Curl_follow(struct SessionHandle *data, return CURLE_OK; } /* * 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 * single file transfer. */ CURLcode Curl_perform(struct SessionHandle *data) static CURLcode Curl_connect_host(struct SessionHandle *data, struct connectdata **conn) { CURLcode res; CURLcode res2; struct connectdata *conn=NULL; char *newurl = NULL; /* possibly a new URL to follow to! */ data->state.used_interface = Curl_if_easy; res = Curl_pretransfer(data); if(res) return res; /* * It is important that there is NO 'return' from this function at any other * place than falling down to the end of the function! This is because we * have cleanup stuff that must be done before we get back, and that is only * performed after this do-while loop. */ do { 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); 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); res = Curl_wait_for_resolv(*conn, NULL); if(CURLE_OK == res) /* Resolved, continue with the connection */ res = Curl_async_resolved(conn); res = Curl_async_resolved(*conn); } if(res) break; Loading @@ -1968,7 +1948,7 @@ CURLcode Curl_perform(struct SessionHandle *data) to the new URL */ urlchanged = data->change.url_changed; if ((CURLE_OK == res) && urlchanged) { res = Curl_done(&conn, res); res = Curl_done(conn, res); if(CURLE_OK == res) { char *gotourl = strdup(data->change.url); res = Curl_follow(data, gotourl); Loading @@ -1978,10 +1958,52 @@ CURLcode Curl_perform(struct SessionHandle *data) } } 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 * single file transfer. */ CURLcode Curl_perform(struct SessionHandle *data) { CURLcode res; CURLcode res2; struct connectdata *conn=NULL; char *newurl = NULL; /* possibly a new URL to follow to! */ data->state.used_interface = Curl_if_easy; res = Curl_pretransfer(data); if(res) return res; /* * It is important that there is NO 'return' from this function at any other * place than falling down to the end of the function! This is because we * have cleanup stuff that must be done before we get back, and that is only * performed after this do-while loop. */ do { res = Curl_connect_host(data, &conn); /* primary connection */ if(res == CURLE_OK) { res = Curl_do(&conn); 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); /* 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) { Loading Loading @@ -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; } Loading
lib/ftp.c +386 −175 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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; 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; } if (conn->sec_conn) /* 3rd party transfer */ retcode = ftp_3rdparty(conn); else freedirs(ftp); ftp->ctl_valid = TRUE; /* seems good */ retcode = ftp_regular_transfer(conn); return retcode; } Loading Loading @@ -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; Loading Loading @@ -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 */
lib/http.c +4 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading
lib/sendf.c +28 −13 Original line number Diff line number Diff line Loading @@ -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); } } Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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] = { Loading @@ -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; }
lib/sendf.h +1 −1 Original line number Diff line number Diff line Loading @@ -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
lib/transfer.c +92 −38 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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) { Loading Loading @@ -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! */ Loading Loading @@ -1919,46 +1919,26 @@ CURLcode Curl_follow(struct SessionHandle *data, return CURLE_OK; } /* * 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 * single file transfer. */ CURLcode Curl_perform(struct SessionHandle *data) static CURLcode Curl_connect_host(struct SessionHandle *data, struct connectdata **conn) { CURLcode res; CURLcode res2; struct connectdata *conn=NULL; char *newurl = NULL; /* possibly a new URL to follow to! */ data->state.used_interface = Curl_if_easy; res = Curl_pretransfer(data); if(res) return res; /* * It is important that there is NO 'return' from this function at any other * place than falling down to the end of the function! This is because we * have cleanup stuff that must be done before we get back, and that is only * performed after this do-while loop. */ do { 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); 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); res = Curl_wait_for_resolv(*conn, NULL); if(CURLE_OK == res) /* Resolved, continue with the connection */ res = Curl_async_resolved(conn); res = Curl_async_resolved(*conn); } if(res) break; Loading @@ -1968,7 +1948,7 @@ CURLcode Curl_perform(struct SessionHandle *data) to the new URL */ urlchanged = data->change.url_changed; if ((CURLE_OK == res) && urlchanged) { res = Curl_done(&conn, res); res = Curl_done(conn, res); if(CURLE_OK == res) { char *gotourl = strdup(data->change.url); res = Curl_follow(data, gotourl); Loading @@ -1978,10 +1958,52 @@ CURLcode Curl_perform(struct SessionHandle *data) } } 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 * single file transfer. */ CURLcode Curl_perform(struct SessionHandle *data) { CURLcode res; CURLcode res2; struct connectdata *conn=NULL; char *newurl = NULL; /* possibly a new URL to follow to! */ data->state.used_interface = Curl_if_easy; res = Curl_pretransfer(data); if(res) return res; /* * It is important that there is NO 'return' from this function at any other * place than falling down to the end of the function! This is because we * have cleanup stuff that must be done before we get back, and that is only * performed after this do-while loop. */ do { res = Curl_connect_host(data, &conn); /* primary connection */ if(res == CURLE_OK) { res = Curl_do(&conn); 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); /* 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) { Loading Loading @@ -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; }