curl tool: fix some OOM handling issues

This commit is contained in:
Yang Tse 2011-09-24 05:32:51 +02:00
parent 5f0764870f
commit 081e289315
3 changed files with 227 additions and 183 deletions

View File

@ -3408,8 +3408,8 @@ int my_trace(CURL *handle, curl_infotype type,
return 0; return 0;
} }
#define RETRY_SLEEP_DEFAULT 1000 /* ms */ #define RETRY_SLEEP_DEFAULT 1000L /* ms */
#define RETRY_SLEEP_MAX 600000 /* ms == 10 minutes */ #define RETRY_SLEEP_MAX 600000L /* ms == 10 minutes */
static bool static bool
output_expected(const char* url, const char* uploadfile) output_expected(const char* url, const char* uploadfile)
@ -3684,66 +3684,57 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
char errorbuffer[CURL_ERROR_SIZE]; char errorbuffer[CURL_ERROR_SIZE];
struct ProgressData progressbar; struct ProgressData progressbar;
struct getout *urlnode; struct getout *urlnode;
struct getout *nextnode;
struct OutStruct outs; struct OutStruct outs;
struct OutStruct heads; struct OutStruct heads;
struct InStruct input;
URLGlob *urls=NULL; CURL *curl = NULL;
URLGlob *inglob=NULL; char *httpgetfields = NULL;
int urlnum;
int infilenum;
char *uploadfile=NULL; /* a single file, never a glob */
curl_off_t uploadfilesize; /* -1 means unknown */ bool stillflags;
bool stillflags=TRUE;
char *httpgetfields=NULL;
CURL *curl;
int res = 0; int res = 0;
int i; int i;
long retry_sleep_default;
long retry_sleep;
char *env;
errorbuffer[0] = '\0';
memset(&outs, 0, sizeof(struct OutStruct));
memset(&heads, 0, sizeof(struct OutStruct)); memset(&heads, 0, sizeof(struct OutStruct));
memory_tracking_init(); memory_tracking_init();
/* Initialize curl library - do not call any libcurl functions before. /*
Note that the memory_tracking_init() magic above is an exception, but ** Initialize curl library - do not call any libcurl functions before
then that's not part of the official public API. ** this point. Note that the memory_tracking_init() magic above is an
** exception, but then that's not part of the official public API.
*/ */
if(main_init() != CURLE_OK) { if(main_init() != CURLE_OK) {
helpf(config->errors, "error initializing curl library\n"); helpf(config->errors, "error initializing curl library\n");
return CURLE_FAILED_INIT; return CURLE_FAILED_INIT;
} }
/* /* Get libcurl info right away */
* Get a curl handle to use for all forthcoming curl transfers. Cleanup if(get_libcurl_info() != CURLE_OK) {
* when all transfers are done. helpf(config->errors, "error retrieving curl library information\n");
*/ main_free();
return CURLE_FAILED_INIT;
}
/* Get a curl handle to use for all forthcoming curl transfers */
curl = curl_easy_init(); curl = curl_easy_init();
if(!curl) { if(!curl) {
clean_getout(config); helpf(config->errors, "error initializing curl easy handle\n");
main_free();
return CURLE_FAILED_INIT; return CURLE_FAILED_INIT;
} }
config->easy = curl; config->easy = curl;
memset(&outs,0,sizeof(outs)); /* Store a pointer to our 'outs' struct used for output writing */
config->outs = &outs; config->outs = &outs;
/* we get libcurl info right away */ /*
if(get_libcurl_info() != CURLE_OK) { ** Beyond this point no return'ing from this function allowed.
clean_getout(config); ** Jump to label 'quit_curl' in order to abandon this function
return CURLE_FAILED_INIT; ** from outside of nested loops further down below.
} */
errorbuffer[0]=0; /* prevent junk from being output */
/* setup proper locale from environment */ /* setup proper locale from environment */
#ifdef HAVE_SETLOCALE #ifdef HAVE_SETLOCALE
@ -3752,9 +3743,9 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
/* inits */ /* inits */
config->postfieldsize = -1; config->postfieldsize = -1;
config->showerror=TRUE; config->showerror = TRUE;
config->use_httpget=FALSE; config->use_httpget = FALSE;
config->create_dirs=FALSE; config->create_dirs = FALSE;
config->maxredirs = DEFAULT_MAXREDIRS; config->maxredirs = DEFAULT_MAXREDIRS;
config->proto = CURLPROTO_ALL; /* FIXME: better to read from library */ config->proto = CURLPROTO_ALL; /* FIXME: better to read from library */
config->proto_present = FALSE; config->proto_present = FALSE;
@ -3762,7 +3753,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
CURLPROTO_ALL & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */ CURLPROTO_ALL & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */
config->proto_redir_present = FALSE; config->proto_redir_present = FALSE;
if(argc>1 && if((argc > 1) &&
(!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) && (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
strchr(argv[1], 'q')) { strchr(argv[1], 'q')) {
/* /*
@ -3777,25 +3768,26 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
if((argc < 2) && !config->url_list) { if((argc < 2) && !config->url_list) {
helpf(config->errors, NULL); helpf(config->errors, NULL);
return CURLE_FAILED_INIT; res = CURLE_FAILED_INIT;
goto quit_curl;
} }
/* Parse options */ /* Parse options */
for(i = 1; i < argc; i++) { for(i = 1, stillflags = TRUE; i < argc; i++) {
if(stillflags && if(stillflags &&
('-' == argv[i][0])) { ('-' == argv[i][0])) {
char *nextarg; char *nextarg;
bool passarg; bool passarg;
char *origopt=argv[i]; char *origopt = argv[i];
char *flag = argv[i]; char *flag = argv[i];
if(curlx_strequal("--", argv[i])) if(curlx_strequal("--", argv[i]))
/* this indicates the end of the flags and thus enables the /* this indicates the end of the flags and thus enables the
following (URL) argument to start with -. */ following (URL) argument to start with -. */
stillflags=FALSE; stillflags = FALSE;
else { else {
nextarg= (i < argc - 1)? argv[i+1]: NULL; nextarg = (i < (argc-1)) ? argv[i+1] : NULL;
res = getparameter(flag, nextarg, &passarg, config); res = getparameter(flag, nextarg, &passarg, config);
if(res) { if(res) {
@ -3805,8 +3797,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
helpf(config->errors, "option %s: %s\n", origopt, reason); helpf(config->errors, "option %s: %s\n", origopt, reason);
retval = CURLE_FAILED_INIT; retval = CURLE_FAILED_INIT;
} }
clean_getout(config); res = retval;
return retval; goto quit_curl;
} }
if(passarg) /* we're supposed to skip this */ if(passarg) /* we're supposed to skip this */
@ -3818,24 +3810,20 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
/* just add the URL please */ /* just add the URL please */
res = getparameter((char *)"--url", argv[i], &used, config); res = getparameter((char *)"--url", argv[i], &used, config);
if(res) if(res)
return res; goto quit_curl;
} }
} }
retry_sleep_default = config->retry_delay?
config->retry_delay*1000:RETRY_SLEEP_DEFAULT; /* ms */
retry_sleep = retry_sleep_default;
if((!config->url_list || !config->url_list->url) && !config->list_engines) { if((!config->url_list || !config->url_list->url) && !config->list_engines) {
clean_getout(config);
helpf(config->errors, "no URL specified!\n"); helpf(config->errors, "no URL specified!\n");
return CURLE_FAILED_INIT; res = CURLE_FAILED_INIT;
goto quit_curl;
} }
if(!config->useragent) if(!config->useragent)
config->useragent = my_useragent(); config->useragent = my_useragent();
if(!config->useragent) { if(!config->useragent) {
clean_getout(config); helpf(config->errors, "out of memory\n");
res = CURLE_OUT_OF_MEMORY; res = CURLE_OUT_OF_MEMORY;
goto quit_curl; goto quit_curl;
} }
@ -3852,12 +3840,14 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
if(!config->cacert && if(!config->cacert &&
!config->capath && !config->capath &&
!config->insecure_ok) { !config->insecure_ok) {
char *env;
env = curlx_getenv("CURL_CA_BUNDLE"); env = curlx_getenv("CURL_CA_BUNDLE");
if(env) { if(env) {
config->cacert = strdup(env); config->cacert = strdup(env);
if(!config->cacert) { if(!config->cacert) {
clean_getout(config);
curl_free(env); curl_free(env);
helpf(config->errors, "out of memory\n");
res = CURLE_OUT_OF_MEMORY;
goto quit_curl; goto quit_curl;
} }
} }
@ -3866,8 +3856,9 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
if(env) { if(env) {
config->capath = strdup(env); config->capath = strdup(env);
if(!config->capath) { if(!config->capath) {
clean_getout(config);
curl_free(env); curl_free(env);
helpf(config->errors, "out of memory\n");
res = CURLE_OUT_OF_MEMORY;
goto quit_curl; goto quit_curl;
} }
} }
@ -3876,8 +3867,9 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
if(env) { if(env) {
config->cacert = strdup(env); config->cacert = strdup(env);
if(!config->cacert) { if(!config->cacert) {
clean_getout(config);
curl_free(env); curl_free(env);
helpf(config->errors, "out of memory\n");
res = CURLE_OUT_OF_MEMORY;
goto quit_curl; goto quit_curl;
} }
} }
@ -3889,10 +3881,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
#ifdef WIN32 #ifdef WIN32
else { else {
res = FindWin32CACert(config, "curl-ca-bundle.crt"); res = FindWin32CACert(config, "curl-ca-bundle.crt");
if(res) { if(res)
clean_getout(config);
goto quit_curl; goto quit_curl;
}
} }
#endif #endif
} }
@ -3905,27 +3895,28 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
if(SetHTTPrequest(config, if(SetHTTPrequest(config,
(config->no_body?HTTPREQ_HEAD:HTTPREQ_GET), (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
&config->httpreq)) { &config->httpreq)) {
Curl_safefree(httpgetfields); res = PARAM_BAD_USE;
return PARAM_BAD_USE; goto quit_curl;
} }
} }
else { else {
if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq)) if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq)) {
return PARAM_BAD_USE; res = PARAM_BAD_USE;
goto quit_curl;
}
} }
} }
/* This is the first entry added to easysrc and it initializes the slist */ /* This is the first entry added to easysrc and it initializes the slist */
easysrc = curl_slist_append(easysrc, "CURL *hnd = curl_easy_init();"); easysrc = curl_slist_append(easysrc, "CURL *hnd = curl_easy_init();");
if(!easysrc) { if(!easysrc) {
clean_getout(config); helpf(config->errors, "out of memory\n");
res = CURLE_OUT_OF_MEMORY; res = CURLE_OUT_OF_MEMORY;
goto quit_curl; goto quit_curl;
} }
if(config->list_engines) { if(config->list_engines) {
struct curl_slist *engines = NULL; struct curl_slist *engines = NULL;
curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines); curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines);
list_engines(engines); list_engines(engines);
curl_slist_free_all(engines); curl_slist_free_all(engines);
@ -3933,44 +3924,58 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
goto quit_curl; goto quit_curl;
} }
/* After this point, we should call curl_easy_cleanup() if we decide to bail /* Single header file for all URLs */
* out from this function! */
urlnode = config->url_list;
if(config->headerfile) { if(config->headerfile) {
/* open file for output: */ /* open file for output: */
if(strcmp(config->headerfile,"-")) { if(strcmp(config->headerfile, "-")) {
heads.filename = config->headerfile; FILE *newfile = fopen(config->headerfile, "wb");
heads.alloc_filename = FALSE; if(!newfile) {
warnf(config, "Failed to open %s\n", config->headerfile);
res = CURLE_WRITE_ERROR;
goto quit_curl;
}
else {
heads.filename = config->headerfile;
heads.alloc_filename = FALSE;
heads.stream = newfile;
heads.config = config;
}
}
else {
heads.filename = config->headerfile; /* "-" */
heads.alloc_filename = FALSE;
heads.stream = stdout;
heads.config = config;
} }
else
heads.stream=stdout;
heads.config = config;
} }
/*
** Nested loops start here.
*/
/* loop through the list of given URLs */ /* loop through the list of given URLs */
while(urlnode) {
for(urlnode = config->url_list; urlnode; urlnode = urlnode->next) {
int up; /* upload file counter within a single upload glob */ int up; /* upload file counter within a single upload glob */
char *dourl;
char *url;
char *infiles; /* might be a glob pattern */ char *infiles; /* might be a glob pattern */
char *outfiles=NULL; char *outfiles;
int infilenum;
URLGlob *inglob;
/* get the full URL (it might be NULL) */ outfiles = NULL;
dourl=urlnode->url; infilenum = 0;
inglob = NULL;
url = dourl; /* urlnode->url is the full URL (it might be NULL) */
if(NULL == url) { if(!urlnode->url) {
/* This node had no URL, skip it and continue to the next */ /* This node has no URL. Free node data without destroying the
node itself nor modifying next pointer and continue to next */
Curl_safefree(urlnode->outfile); Curl_safefree(urlnode->outfile);
Curl_safefree(urlnode->infile);
/* move on to the next URL */ urlnode->flags = 0;
nextnode=urlnode->next; continue; /* next URL please */
Curl_safefree(urlnode); /* free the node */
urlnode = nextnode;
continue; /* next please */
} }
/* default output stream is stdout */ /* default output stream is stdout */
@ -3983,7 +3988,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
if(urlnode->outfile) { if(urlnode->outfile) {
outfiles = strdup(urlnode->outfile); outfiles = strdup(urlnode->outfile);
if(!outfiles) { if(!outfiles) {
clean_getout(config); helpf(config->errors, "out of memory\n");
res = CURLE_OUT_OF_MEMORY;
break; break;
} }
} }
@ -3994,8 +4000,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
/* Unless explicitly shut off */ /* Unless explicitly shut off */
res = glob_url(&inglob, infiles, &infilenum, res = glob_url(&inglob, infiles, &infilenum,
config->showerror?config->errors:NULL); config->showerror?config->errors:NULL);
if(res != CURLE_OK) { if(res) {
clean_getout(config);
Curl_safefree(outfiles); Curl_safefree(outfiles);
break; break;
} }
@ -4005,8 +4010,15 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
single globbed string. If no upload, we enter the loop once anyway. */ single globbed string. If no upload, we enter the loop once anyway. */
for(up = 0 ;; up++) { for(up = 0 ;; up++) {
long retry_numretries; char *uploadfile; /* a single file, never a glob */
int separator; int separator;
URLGlob *urls;
int urlnum;
uploadfile = NULL;
separator = 0;
urls = NULL;
urlnum = 0;
if(!up && !infiles) if(!up && !infiles)
Curl_nop_stmt; Curl_nop_stmt;
@ -4021,15 +4033,13 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
break; break;
} }
separator = 0;
uploadfilesize = -1;
if(!config->globoff) { if(!config->globoff) {
/* Unless explicitly shut off, we expand '{...}' and '[...]' /* Unless explicitly shut off, we expand '{...}' and '[...]'
expressions and return total number of URLs in pattern set */ expressions and return total number of URLs in pattern set */
res = glob_url(&urls, dourl, &urlnum, res = glob_url(&urls, urlnode->url, &urlnum,
config->showerror?config->errors:NULL); config->showerror?config->errors:NULL);
if(res != CURLE_OK) { if(res) {
Curl_safefree(uploadfile);
break; break;
} }
} }
@ -4045,19 +4055,27 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
int infd; int infd;
bool infdopen; bool infdopen;
char *outfile; char *outfile;
struct InStruct input;
struct timeval retrystart; struct timeval retrystart;
curl_off_t uploadfilesize;
long retry_numretries;
long retry_sleep_default;
long retry_sleep;
char *this_url;
outfile = NULL; outfile = NULL;
infdopen = FALSE; infdopen = FALSE;
infd = STDIN_FILENO; infd = STDIN_FILENO;
uploadfilesize = -1; /* -1 means unknown */
if(urls) if(urls)
url = glob_next_url(urls); this_url = glob_next_url(urls);
else if(!i) else if(!i) {
url = strdup(url); this_url = strdup(urlnode->url);
}
else else
url = NULL; this_url = NULL;
if(!url) if(!this_url)
break; break;
if(outfiles) { if(outfiles) {
@ -4078,7 +4096,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
if(!outfile) { if(!outfile) {
/* extract the file name from the URL */ /* extract the file name from the URL */
outfile = get_url_file_name(url); outfile = get_url_file_name(this_url);
if((!outfile || !*outfile) && !config->content_disposition) { if((!outfile || !*outfile) && !config->content_disposition) {
helpf(config->errors, "Remote file name has no length!\n"); helpf(config->errors, "Remote file name has no length!\n");
res = CURLE_WRITE_ERROR; res = CURLE_WRITE_ERROR;
@ -4160,8 +4178,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
*/ */
struct_stat fileinfo; struct_stat fileinfo;
url = add_file_name_to_url(curl, url, uploadfile); this_url = add_file_name_to_url(curl, this_url, uploadfile);
if(!url) { if(!this_url) {
res = CURLE_OUT_OF_MEMORY; res = CURLE_OUT_OF_MEMORY;
goto show_error; goto show_error;
} }
@ -4194,7 +4212,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
/* we ignore file size for char/block devices, sockets, etc. */ /* we ignore file size for char/block devices, sockets, etc. */
if(S_ISREG(fileinfo.st_mode)) if(S_ISREG(fileinfo.st_mode))
uploadfilesize=fileinfo.st_size; uploadfilesize = fileinfo.st_size;
} }
else if(uploadfile && stdin_upload(uploadfile)) { else if(uploadfile && stdin_upload(uploadfile)) {
@ -4237,7 +4255,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
if(uploadfile && config->resume_from_current) if(uploadfile && config->resume_from_current)
config->resume_from = -1; /* -1 will then force get-it-yourself */ config->resume_from = -1; /* -1 will then force get-it-yourself */
if(output_expected(url, uploadfile) if(output_expected(this_url, uploadfile)
&& outs.stream && isatty(fileno(outs.stream))) && outs.stream && isatty(fileno(outs.stream)))
/* we send the output to a tty, therefore we switch off the progress /* we send the output to a tty, therefore we switch off the progress
meter */ meter */
@ -4245,19 +4263,19 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
if(urlnum > 1 && !(config->mute)) { if(urlnum > 1 && !(config->mute)) {
fprintf(config->errors, "\n[%d/%d]: %s --> %s\n", fprintf(config->errors, "\n[%d/%d]: %s --> %s\n",
i+1, urlnum, url, outfile ? outfile : "<stdout>"); i+1, urlnum, this_url, outfile ? outfile : "<stdout>");
if(separator) if(separator)
printf("%s%s\n", CURLseparator, url); printf("%s%s\n", CURLseparator, this_url);
} }
if(httpgetfields) { if(httpgetfields) {
char *urlbuffer; char *urlbuffer;
/* Find out whether the url contains a file name */ /* Find out whether the url contains a file name */
const char *pc = strstr(url, "://"); const char *pc = strstr(this_url, "://");
char sep = '?'; char sep = '?';
if(pc) if(pc)
pc += 3; pc += 3;
else else
pc = url; pc = this_url;
pc = strrchr(pc, '/'); /* check for a slash */ pc = strrchr(pc, '/'); /* check for a slash */
@ -4272,21 +4290,21 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
/* /*
* Then append ? followed by the get fields to the url. * Then append ? followed by the get fields to the url.
*/ */
urlbuffer = malloc(strlen(url) + strlen(httpgetfields) + 3); urlbuffer = malloc(strlen(this_url) + strlen(httpgetfields) + 3);
if(!urlbuffer) { if(!urlbuffer) {
res = CURLE_OUT_OF_MEMORY; res = CURLE_OUT_OF_MEMORY;
goto show_error; goto show_error;
} }
if(pc) if(pc)
sprintf(urlbuffer, "%s%c%s", url, sep, httpgetfields); sprintf(urlbuffer, "%s%c%s", this_url, sep, httpgetfields);
else else
/* Append / before the ? to create a well-formed url /* Append / before the ? to create a well-formed url
if the url contains a hostname only if the url contains a hostname only
*/ */
sprintf(urlbuffer, "%s/?%s", url, httpgetfields); sprintf(urlbuffer, "%s/?%s", this_url, httpgetfields);
Curl_safefree(url); /* free previous URL */ Curl_safefree(this_url); /* free previous URL */
url = urlbuffer; /* use our new URL instead! */ this_url = urlbuffer; /* use our new URL instead! */
} }
if(!config->errors) if(!config->errors)
@ -4312,7 +4330,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
my_setopt(curl, CURLOPT_READDATA, &input); my_setopt(curl, CURLOPT_READDATA, &input);
/* what call to read */ /* what call to read */
if((outfile && !curlx_strequal("-", outfile)) || if((outfile && !curlx_strequal("-", outfile)) ||
!checkprefix("telnet:", url)) !checkprefix("telnet:", this_url))
my_setopt(curl, CURLOPT_READFUNCTION, my_fread); my_setopt(curl, CURLOPT_READFUNCTION, my_fread);
/* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
@ -4328,7 +4346,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
/* size of uploaded file: */ /* size of uploaded file: */
if(uploadfilesize != -1) if(uploadfilesize != -1)
my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize); my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
my_setopt_str(curl, CURLOPT_URL, url); /* what to fetch */ my_setopt_str(curl, CURLOPT_URL, this_url); /* what to fetch */
my_setopt(curl, CURLOPT_NOPROGRESS, config->noprogress); my_setopt(curl, CURLOPT_NOPROGRESS, config->noprogress);
if(config->no_body) { if(config->no_body) {
my_setopt(curl, CURLOPT_NOBODY, 1); my_setopt(curl, CURLOPT_NOBODY, 1);
@ -4741,8 +4759,12 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION, my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION,
config->gssapi_delegation); config->gssapi_delegation);
retry_numretries = config->req_retry; /* initialize retry vars for loop below */
retry_sleep_default = (config->retry_delay) ?
config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
retry_numretries = config->req_retry;
retry_sleep = retry_sleep_default; /* ms */
retrystart = cutil_tvnow(); retrystart = cutil_tvnow();
for(;;) { for(;;) {
@ -4761,7 +4783,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
if(retry_numretries && if(retry_numretries &&
(!config->retry_maxtime || (!config->retry_maxtime ||
(cutil_tvdiff(cutil_tvnow(), retrystart)< (cutil_tvdiff(cutil_tvnow(), retrystart)<
config->retry_maxtime*1000)) ) { config->retry_maxtime*1000L)) ) {
enum { enum {
RETRY_NO, RETRY_NO,
RETRY_TIMEOUT, RETRY_TIMEOUT,
@ -4779,10 +4801,10 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
/* If it returned OK. _or_ failonerror was enabled and it /* If it returned OK. _or_ failonerror was enabled and it
returned due to such an error, check for HTTP transient returned due to such an error, check for HTTP transient
errors to retry on. */ errors to retry on. */
char *this_url=NULL; char *effective_url = NULL;
curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &this_url); curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
if(this_url && if(effective_url &&
checkprefix("http", this_url)) { checkprefix("http", effective_url)) {
/* This was HTTP(S) */ /* This was HTTP(S) */
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
@ -4825,7 +4847,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
warnf(config, "Transient problem: %s " warnf(config, "Transient problem: %s "
"Will retry in %ld seconds. " "Will retry in %ld seconds. "
"%ld retries left.\n", "%ld retries left.\n",
m[retry], retry_sleep/1000, retry_numretries); m[retry], retry_sleep/1000L, retry_numretries);
go_sleep(retry_sleep); go_sleep(retry_sleep);
retry_numretries--; retry_numretries--;
@ -4870,7 +4892,6 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
} /* if retry_numretries */ } /* if retry_numretries */
/* In all ordinary cases, just break out of loop here */ /* In all ordinary cases, just break out of loop here */
retry_sleep = retry_sleep_default;
break; /* curl_easy_perform loop */ break; /* curl_easy_perform loop */
} }
@ -4974,30 +4995,15 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
} }
#endif #endif
/* Cleanup loop-local variables for next loop iteration or exit */ /* Free loop-local allocated memory and close loop-local opened fd */
Curl_safefree(outfile);
Curl_safefree(this_url);
if(infdopen) { if(infdopen) {
close(infd); close(infd);
infdopen = FALSE; /* not needed */ infdopen = FALSE;
infd = STDIN_FILENO; /* not needed */ infd = STDIN_FILENO;
}
Curl_safefree(outfile);
/* ... */
Curl_safefree(url);
if(res) {
/* Free list of remaining URLs */
if(urls) {
glob_cleanup(urls);
urls = NULL;
}
/* Free list of globbed upload files */
if(inglob) {
glob_cleanup(inglob);
inglob = NULL;
}
} }
/* upon error exit loop */ /* upon error exit loop */
@ -5006,52 +5012,84 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
} /* loop to the next URL */ } /* loop to the next URL */
/* Free loop-local allocated memory and close loop-local opened fd */
Curl_safefree(uploadfile);
if(urls) { if(urls) {
/* cleanup memory used for URL globbing patterns */ /* Free list of remaining URLs */
glob_cleanup(urls); glob_cleanup(urls);
urls = NULL; urls = NULL;
} }
Curl_safefree(uploadfile);
/* upon error exit loop */ /* upon error exit loop */
if(res) if(res)
break; break;
} /* loop to the next globbed upload file */ } /* loop to the next globbed upload file */
/* Free loop-local allocated memory and close loop-local opened fd */
Curl_safefree(outfiles);
if(inglob) { if(inglob) {
/* Free list of globbed upload files */
glob_cleanup(inglob); glob_cleanup(inglob);
inglob = NULL; inglob = NULL;
} }
Curl_safefree(outfiles); /* Free this URL node data without destroying the
the node itself nor modifying next pointer. */
/* empty this urlnode struct */
Curl_safefree(urlnode->url); Curl_safefree(urlnode->url);
Curl_safefree(urlnode->outfile); Curl_safefree(urlnode->outfile);
Curl_safefree(urlnode->infile); Curl_safefree(urlnode->infile);
urlnode->flags = 0;
/* move on to the next URL */ /*
nextnode=urlnode->next; ** Bail out upon critical errors
Curl_safefree(urlnode); /* free the node */ */
urlnode = nextnode; switch(res) {
case CURLE_FAILED_INIT:
case CURLE_OUT_OF_MEMORY:
case CURLE_FUNCTION_NOT_FOUND:
case CURLE_BAD_FUNCTION_ARGUMENT:
goto quit_curl;
default:
/* Merrily loop to next URL */
break;
}
} /* while-loop through all URLs */ } /* for-loop through all URLs */
/*
** Nested loops end here.
*/
quit_curl: quit_curl:
/* Free function-local referenced allocated memory */
Curl_safefree(httpgetfields); Curl_safefree(httpgetfields);
Curl_safefree(config->engine); /* Free list of given URLs */
clean_getout(config);
/* cleanup the curl handle! */ /* Cleanup the curl handle now that our
curl_easy_cleanup(curl); progressbar struct is still in scope */
config->easy = NULL; /* cleanup now */ if(curl) {
curl_easy_cleanup(curl);
config->easy = curl = NULL;
}
if(easysrc) if(easysrc)
curl_slist_append(easysrc, "curl_easy_cleanup(hnd);"); curl_slist_append(easysrc, "curl_easy_cleanup(hnd);");
if(heads.stream && (heads.stream != stdout)) /* Close function-local opened file descriptors */
fclose(heads.stream);
if(config->headerfile) {
if(strcmp(heads.filename, "-") && heads.stream)
fclose(heads.stream);
if(heads.alloc_filename)
Curl_safefree(heads.filename);
}
if(config->trace_fopened && config->trace_stream) if(config->trace_fopened && config->trace_stream)
fclose(config->trace_stream); fclose(config->trace_stream);
@ -5061,7 +5099,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
so not everything can be closed and cleaned before this is called */ so not everything can be closed and cleaned before this is called */
dumpeasysrc(config); dumpeasysrc(config);
if(config->errors_fopened) if(config->errors_fopened && config->errors)
fclose(config->errors); fclose(config->errors);
main_free(); /* cleanup */ main_free(); /* cleanup */

View File

@ -31,6 +31,8 @@
void free_config_fields(struct Configurable *config) void free_config_fields(struct Configurable *config)
{ {
struct getout *urlnode;
if(config->easy) { if(config->easy) {
curl_easy_cleanup(config->easy); curl_easy_cleanup(config->easy);
config->easy = NULL; config->easy = NULL;
@ -65,10 +67,19 @@ void free_config_fields(struct Configurable *config)
Curl_safefree(config->netrc_file); Curl_safefree(config->netrc_file);
/* config->url_list not handled */ urlnode = config->url_list;
/* config->url_last not handled */ while(urlnode) {
/* config->url_get not handled */ struct getout *next = urlnode->next;
/* config->url_out not handled */ Curl_safefree(urlnode->url);
Curl_safefree(urlnode->outfile);
Curl_safefree(urlnode->infile);
Curl_safefree(urlnode);
urlnode = next;
}
config->url_list = NULL;
config->url_last = NULL;
config->url_get = NULL;
config->url_out = NULL;
Curl_safefree(config->cipher_list); Curl_safefree(config->cipher_list);
Curl_safefree(config->cert); Curl_safefree(config->cert);
@ -81,18 +92,17 @@ void free_config_fields(struct Configurable *config)
Curl_safefree(config->key_passwd); Curl_safefree(config->key_passwd);
Curl_safefree(config->pubkey); Curl_safefree(config->pubkey);
Curl_safefree(config->hostpubmd5); Curl_safefree(config->hostpubmd5);
Curl_safefree(config->engine);
/* config->engine not handled */
Curl_safefree(config->customrequest); Curl_safefree(config->customrequest);
Curl_safefree(config->krblevel); Curl_safefree(config->krblevel);
Curl_safefree(config->trace_dump); Curl_safefree(config->trace_dump);
/* config->trace_stream not handled */ config->trace_stream = NULL; /* closed elsewhere when appropriate */
Curl_safefree(config->writeout); Curl_safefree(config->writeout);
/* config->errors not handled */ config->errors = NULL; /* closed elsewhere when appropriate */
curl_slist_free_all(config->quote); curl_slist_free_all(config->quote);
curl_slist_free_all(config->postquote); curl_slist_free_all(config->postquote);
@ -118,7 +128,6 @@ void free_config_fields(struct Configurable *config)
Curl_safefree(config->libcurl); Curl_safefree(config->libcurl);
/* config->outs not handled */ config->outs = NULL; /* closed elsewhere when appropriate */
} }

View File

@ -58,9 +58,6 @@ struct OutStruct {
* or a file descriptor as returned from an 'open' call for some file. * or a file descriptor as returned from an 'open' call for some file.
* *
* 'config' member is a pointer to associated 'Configurable' struct. * 'config' member is a pointer to associated 'Configurable' struct.
*
* TODO: evaluate if an additional struct member should be added to
* allow easier handling of 'stdin' vs other 'file' descriptors.
*/ */
struct InStruct { struct InStruct {