curl tool: fix some OOM handling issues
This commit is contained in:
parent
5f0764870f
commit
081e289315
378
src/main.c
378
src/main.c
@ -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 */
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user