mirror of
https://github.com/moparisthebest/curl
synced 2024-12-22 08:08:50 -05:00
curl tool: fix some OOM handling issues
This commit is contained in:
parent
fb3845a438
commit
fa775b56de
241
src/main.c
241
src/main.c
@ -4042,11 +4042,15 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
/* Here's looping around each globbed URL */
|
/* Here's looping around each globbed URL */
|
||||||
for(i = 0 ;; i++) {
|
for(i = 0 ;; i++) {
|
||||||
|
|
||||||
int infd = STDIN_FILENO;
|
int infd;
|
||||||
bool infdopen;
|
bool infdopen;
|
||||||
char *outfile;
|
char *outfile;
|
||||||
struct timeval retrystart;
|
struct timeval retrystart;
|
||||||
|
|
||||||
|
outfile = NULL;
|
||||||
|
infdopen = FALSE;
|
||||||
|
infd = STDIN_FILENO;
|
||||||
|
|
||||||
if(urls)
|
if(urls)
|
||||||
url = glob_next_url(urls);
|
url = glob_next_url(urls);
|
||||||
else if(!i)
|
else if(!i)
|
||||||
@ -4056,7 +4060,13 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
if(!url)
|
if(!url)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
outfile = outfiles?strdup(outfiles):NULL;
|
if(outfiles) {
|
||||||
|
outfile = strdup(outfiles);
|
||||||
|
if(!outfile) {
|
||||||
|
res = CURLE_OUT_OF_MEMORY;
|
||||||
|
goto show_error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if((urlnode->flags&GETOUT_USEREMOTE) ||
|
if((urlnode->flags&GETOUT_USEREMOTE) ||
|
||||||
(outfile && !curlx_strequal("-", outfile)) ) {
|
(outfile && !curlx_strequal("-", outfile)) ) {
|
||||||
@ -4071,19 +4081,16 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
outfile = get_url_file_name(url);
|
outfile = get_url_file_name(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");
|
||||||
Curl_safefree(url);
|
|
||||||
res = CURLE_WRITE_ERROR;
|
res = CURLE_WRITE_ERROR;
|
||||||
break;
|
goto quit_urls;
|
||||||
}
|
}
|
||||||
#if defined(MSDOS) || defined(WIN32)
|
#if defined(MSDOS) || defined(WIN32)
|
||||||
/* For DOS and WIN32, we do some major replacing of
|
/* For DOS and WIN32, we do some major replacing of
|
||||||
bad characters in the file name before using it */
|
bad characters in the file name before using it */
|
||||||
outfile = sanitize_dos_name(outfile);
|
outfile = sanitize_dos_name(outfile);
|
||||||
if(!outfile) {
|
if(!outfile) {
|
||||||
warnf(config, "out of memory\n");
|
|
||||||
Curl_safefree(url);
|
|
||||||
res = CURLE_OUT_OF_MEMORY;
|
res = CURLE_OUT_OF_MEMORY;
|
||||||
break;
|
goto show_error;
|
||||||
}
|
}
|
||||||
#endif /* MSDOS || WIN32 */
|
#endif /* MSDOS || WIN32 */
|
||||||
}
|
}
|
||||||
@ -4095,9 +4102,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
if(!outfile) {
|
if(!outfile) {
|
||||||
/* bad globbing */
|
/* bad globbing */
|
||||||
warnf(config, "bad output glob!\n");
|
warnf(config, "bad output glob!\n");
|
||||||
Curl_safefree(url);
|
|
||||||
res = CURLE_FAILED_INIT;
|
res = CURLE_FAILED_INIT;
|
||||||
break;
|
goto quit_urls;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4107,11 +4113,10 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
if(config->create_dirs) {
|
if(config->create_dirs) {
|
||||||
res = create_dir_hierarchy(outfile, config->errors);
|
res = create_dir_hierarchy(outfile, config->errors);
|
||||||
/* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */
|
/* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */
|
||||||
if(res == CURLE_OUT_OF_MEMORY)
|
if(res == CURLE_WRITE_ERROR)
|
||||||
warnf(config, "out of memory\n");
|
goto quit_urls;
|
||||||
if(res) {
|
if(res) {
|
||||||
Curl_safefree(url);
|
goto show_error;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4136,12 +4141,11 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
if(config->resume_from) {
|
if(config->resume_from) {
|
||||||
outs.init = config->resume_from;
|
outs.init = config->resume_from;
|
||||||
/* open file for output: */
|
/* open file for output: */
|
||||||
outs.stream=(FILE *) fopen(outfile, config->resume_from?"ab":"wb");
|
outs.stream = fopen(outfile, config->resume_from?"ab":"wb");
|
||||||
if(!outs.stream) {
|
if(!outs.stream) {
|
||||||
helpf(config->errors, "Can't open '%s'!\n", outfile);
|
helpf(config->errors, "Can't open '%s'!\n", outfile);
|
||||||
Curl_safefree(url);
|
|
||||||
res = CURLE_WRITE_ERROR;
|
res = CURLE_WRITE_ERROR;
|
||||||
break;
|
goto quit_urls;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -4149,7 +4153,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
outs.bytes = 0; /* reset byte counter */
|
outs.bytes = 0; /* reset byte counter */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
infdopen=FALSE;
|
|
||||||
if(uploadfile && !stdin_upload(uploadfile)) {
|
if(uploadfile && !stdin_upload(uploadfile)) {
|
||||||
/*
|
/*
|
||||||
* We have specified a file to upload and it isn't "-".
|
* We have specified a file to upload and it isn't "-".
|
||||||
@ -4158,9 +4162,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
|
|
||||||
url = add_file_name_to_url(curl, url, uploadfile);
|
url = add_file_name_to_url(curl, url, uploadfile);
|
||||||
if(!url) {
|
if(!url) {
|
||||||
helpf(config->errors, "out of memory\n");
|
|
||||||
res = CURLE_OUT_OF_MEMORY;
|
res = CURLE_OUT_OF_MEMORY;
|
||||||
break;
|
goto show_error;
|
||||||
}
|
}
|
||||||
/* VMS Note:
|
/* VMS Note:
|
||||||
*
|
*
|
||||||
@ -4177,28 +4180,17 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
* to be considered with one appended if implied CC
|
* to be considered with one appended if implied CC
|
||||||
*/
|
*/
|
||||||
|
|
||||||
infd= open(uploadfile, O_RDONLY | O_BINARY);
|
infd = open(uploadfile, O_RDONLY | O_BINARY);
|
||||||
if((infd == -1) || fstat(infd, &fileinfo)) {
|
if((infd == -1) || fstat(infd, &fileinfo)) {
|
||||||
helpf(config->errors, "Can't open '%s'!\n", uploadfile);
|
helpf(config->errors, "Can't open '%s'!\n", uploadfile);
|
||||||
if(infd != -1)
|
if(infd != -1) {
|
||||||
close(infd);
|
close(infd);
|
||||||
|
infd = STDIN_FILENO;
|
||||||
/* Free the list of remaining URLs and globbed upload files
|
|
||||||
* to force curl to exit immediately
|
|
||||||
*/
|
|
||||||
if(urls) {
|
|
||||||
glob_cleanup(urls);
|
|
||||||
urls = NULL;
|
|
||||||
}
|
}
|
||||||
if(inglob) {
|
|
||||||
glob_cleanup(inglob);
|
|
||||||
inglob = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = CURLE_READ_ERROR;
|
res = CURLE_READ_ERROR;
|
||||||
goto quit_urls;
|
goto quit_urls;
|
||||||
}
|
}
|
||||||
infdopen=TRUE;
|
infdopen = TRUE;
|
||||||
|
|
||||||
/* 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))
|
||||||
@ -4231,8 +4223,10 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
" file or a fixed auth type instead!\n");
|
" file or a fixed auth type instead!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUGASSERT(infdopen == FALSE);
|
||||||
|
DEBUGASSERT(infd == STDIN_FILENO);
|
||||||
|
|
||||||
SET_BINMODE(stdin);
|
SET_BINMODE(stdin);
|
||||||
infd = STDIN_FILENO;
|
|
||||||
if(curlx_strequal(uploadfile, ".")) {
|
if(curlx_strequal(uploadfile, ".")) {
|
||||||
if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
|
if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
|
||||||
warnf(config,
|
warnf(config,
|
||||||
@ -4258,12 +4252,12 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
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(url, "://");
|
||||||
char sep='?';
|
char sep = '?';
|
||||||
if(pc)
|
if(pc)
|
||||||
pc+=3;
|
pc += 3;
|
||||||
else
|
else
|
||||||
pc=url;
|
pc = url;
|
||||||
|
|
||||||
pc = strrchr(pc, '/'); /* check for a slash */
|
pc = strrchr(pc, '/'); /* check for a slash */
|
||||||
|
|
||||||
@ -4280,22 +4274,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
*/
|
*/
|
||||||
urlbuffer = malloc(strlen(url) + strlen(httpgetfields) + 3);
|
urlbuffer = malloc(strlen(url) + strlen(httpgetfields) + 3);
|
||||||
if(!urlbuffer) {
|
if(!urlbuffer) {
|
||||||
helpf(config->errors, "out of memory\n");
|
|
||||||
|
|
||||||
/* Free the list of remaining URLs and globbed upload files
|
|
||||||
* to force curl to exit immediately
|
|
||||||
*/
|
|
||||||
if(urls) {
|
|
||||||
glob_cleanup(urls);
|
|
||||||
urls = NULL;
|
|
||||||
}
|
|
||||||
if(inglob) {
|
|
||||||
glob_cleanup(inglob);
|
|
||||||
inglob = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = CURLE_OUT_OF_MEMORY;
|
res = CURLE_OUT_OF_MEMORY;
|
||||||
goto quit_urls;
|
goto show_error;
|
||||||
}
|
}
|
||||||
if(pc)
|
if(pc)
|
||||||
sprintf(urlbuffer, "%s%c%s", url, sep, httpgetfields);
|
sprintf(urlbuffer, "%s%c%s", url, sep, httpgetfields);
|
||||||
@ -4534,19 +4514,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
}
|
}
|
||||||
free(home);
|
free(home);
|
||||||
}
|
}
|
||||||
if(res) {
|
if(res)
|
||||||
/* Free the list of remaining URLs and globbed upload files
|
goto show_error;
|
||||||
* to force curl to exit immediately */
|
|
||||||
if(urls) {
|
|
||||||
glob_cleanup(urls);
|
|
||||||
urls = NULL;
|
|
||||||
}
|
|
||||||
if(inglob) {
|
|
||||||
glob_cleanup(inglob);
|
|
||||||
inglob = NULL;
|
|
||||||
}
|
|
||||||
goto quit_urls;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4780,7 +4749,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
res = curl_easy_perform(curl);
|
res = curl_easy_perform(curl);
|
||||||
if(!curl_slist_append(easysrc, "ret = curl_easy_perform(hnd);")) {
|
if(!curl_slist_append(easysrc, "ret = curl_easy_perform(hnd);")) {
|
||||||
res = CURLE_OUT_OF_MEMORY;
|
res = CURLE_OUT_OF_MEMORY;
|
||||||
break;
|
goto show_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(config->content_disposition && outs.stream && !config->mute &&
|
if(config->content_disposition && outs.stream && !config->mute &&
|
||||||
@ -4881,7 +4850,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
if(!config->mute)
|
if(!config->mute)
|
||||||
fprintf(config->errors,
|
fprintf(config->errors,
|
||||||
"failed to truncate, exiting\n");
|
"failed to truncate, exiting\n");
|
||||||
break;
|
res = CURLE_WRITE_ERROR;
|
||||||
|
goto quit_urls;
|
||||||
}
|
}
|
||||||
/* now seek to the end of the file, the position where we
|
/* now seek to the end of the file, the position where we
|
||||||
just truncated the file in a large file-safe way */
|
just truncated the file in a large file-safe way */
|
||||||
@ -4895,13 +4865,13 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
#endif
|
#endif
|
||||||
outs.bytes = 0; /* clear for next round */
|
outs.bytes = 0; /* clear for next round */
|
||||||
}
|
}
|
||||||
continue;
|
continue; /* curl_easy_perform loop */
|
||||||
}
|
}
|
||||||
} /* 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;
|
retry_sleep = retry_sleep_default;
|
||||||
break;
|
break; /* curl_easy_perform loop */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4918,55 +4888,82 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
ourWriteEnv(curl);
|
ourWriteEnv(curl);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Code within this loop may jump directly here to label 'show_error'
|
||||||
|
** in order to display an error message for CURLcode stored in 'res'
|
||||||
|
** variable and exit loop once that necessary writing and cleanup
|
||||||
|
** in label 'quit_urls' has been done.
|
||||||
|
*/
|
||||||
|
|
||||||
show_error:
|
show_error:
|
||||||
|
|
||||||
#ifdef __VMS
|
#ifdef __VMS
|
||||||
if(is_vms_shell()) {
|
if(is_vms_shell()) {
|
||||||
/* VMS DCL shell behavior */
|
/* VMS DCL shell behavior */
|
||||||
if(!config->showerror) {
|
if(!config->showerror)
|
||||||
vms_show = VMSSTS_HIDE;
|
vms_show = VMSSTS_HIDE;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
if(res && config->showerror) {
|
||||||
if((res!=CURLE_OK) && config->showerror) {
|
fprintf(config->errors, "curl: (%d) %s\n", res,
|
||||||
fprintf(config->errors, "curl: (%d) %s\n", res,
|
(errorbuffer[0]) ? errorbuffer: curl_easy_strerror(res));
|
||||||
errorbuffer[0]? errorbuffer:
|
if(res == CURLE_SSL_CACERT)
|
||||||
curl_easy_strerror((CURLcode)res));
|
fprintf(config->errors, "%s%s",
|
||||||
if(CURLE_SSL_CACERT == res) {
|
CURL_CA_CERT_ERRORMSG1, CURL_CA_CERT_ERRORMSG2);
|
||||||
fprintf(config->errors, "%s%s",
|
|
||||||
CURL_CA_CERT_ERRORMSG1,
|
|
||||||
CURL_CA_CERT_ERRORMSG2 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fall through comment to 'quit_urls' label */
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Upon error condition and always that a message has already been
|
||||||
|
** displayed, code within this loop may jump directly here to label
|
||||||
|
** 'quit_urls' otherwise it should jump to 'show_error' label above.
|
||||||
|
**
|
||||||
|
** When 'res' variable is _not_ CURLE_OK loop will exit once that
|
||||||
|
** all code following 'quit_urls' has been executed. Otherwise it
|
||||||
|
** will loop to the beginning from where it may exit if there are
|
||||||
|
** no more urls left.
|
||||||
|
*/
|
||||||
|
|
||||||
|
quit_urls:
|
||||||
|
|
||||||
|
/* Set file extended attributes */
|
||||||
|
if(!res && config->xattr &&
|
||||||
|
outfile && !curlx_strequal(outfile, "-") && outs.stream) {
|
||||||
|
int rc = fwrite_xattr(curl, fileno(outs.stream));
|
||||||
|
if(rc)
|
||||||
|
warnf(config, "Error setting extended attributes: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close the file */
|
||||||
if(outfile && !curlx_strequal(outfile, "-") && outs.stream) {
|
if(outfile && !curlx_strequal(outfile, "-") && outs.stream) {
|
||||||
int rc;
|
int rc = fclose(outs.stream);
|
||||||
|
|
||||||
if(config->xattr) {
|
|
||||||
rc = fwrite_xattr(curl, fileno(outs.stream) );
|
|
||||||
if(rc)
|
|
||||||
warnf(config, "Error setting extended attributes: %s\n",
|
|
||||||
strerror(errno) );
|
|
||||||
}
|
|
||||||
if(outs.alloc_filename)
|
|
||||||
Curl_safefree(outs.filename);
|
|
||||||
|
|
||||||
rc = fclose(outs.stream);
|
|
||||||
if(!res && rc) {
|
if(!res && rc) {
|
||||||
/* something went wrong in the writing process */
|
/* something went wrong in the writing process */
|
||||||
res = CURLE_WRITE_ERROR;
|
res = CURLE_WRITE_ERROR;
|
||||||
fprintf(config->errors, "(%d) Failed writing body\n", res);
|
fprintf(config->errors, "(%d) Failed writing body\n", res);
|
||||||
}
|
}
|
||||||
|
if(outs.alloc_filename)
|
||||||
|
Curl_safefree(outs.filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __AMIGA__
|
||||||
|
if(!res) {
|
||||||
|
/* Set the url (up to 80 chars) as comment for the file */
|
||||||
|
if(strlen(url) > 78)
|
||||||
|
url[79] = '\0';
|
||||||
|
SetComment( outs.filename, url);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_UTIME
|
#ifdef HAVE_UTIME
|
||||||
/* Important that we set the time _after_ the file has been
|
/* File time can only be set _after_ the file has been closed */
|
||||||
closed, as is done above here */
|
if(!res && config->remote_time &&
|
||||||
if(config->remote_time && outs.filename) {
|
outs.filename && !curlx_strequal("-", outs.filename)) {
|
||||||
/* ask libcurl if we got a time. Pretty please */
|
/* Ask libcurl if we got a remote file time */
|
||||||
long filetime;
|
long filetime = -1;
|
||||||
curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
|
curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
|
||||||
if(filetime >= 0) {
|
if(filetime >= 0) {
|
||||||
struct utimbuf times;
|
struct utimbuf times;
|
||||||
@ -4976,22 +4973,36 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef __AMIGA__
|
|
||||||
/* Set the url as comment for the file. (up to 80 chars are allowed)
|
|
||||||
*/
|
|
||||||
if(strlen(url) > 78)
|
|
||||||
url[79] = '\0';
|
|
||||||
|
|
||||||
SetComment( outs.filename, url);
|
/* Cleanup loop-local variables for next loop iteration or exit */
|
||||||
#endif
|
|
||||||
|
|
||||||
quit_urls:
|
|
||||||
Curl_safefree(url);
|
|
||||||
|
|
||||||
|
if(infdopen) {
|
||||||
|
close(infd);
|
||||||
|
infdopen = FALSE; /* not needed */
|
||||||
|
infd = STDIN_FILENO; /* not needed */
|
||||||
|
}
|
||||||
Curl_safefree(outfile);
|
Curl_safefree(outfile);
|
||||||
|
|
||||||
if(infdopen)
|
/* ... */
|
||||||
close(infd);
|
|
||||||
|
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 */
|
||||||
|
if(res)
|
||||||
|
break;
|
||||||
|
|
||||||
} /* loop to the next URL */
|
} /* loop to the next URL */
|
||||||
|
|
||||||
@ -5003,6 +5014,10 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
|
|||||||
|
|
||||||
Curl_safefree(uploadfile);
|
Curl_safefree(uploadfile);
|
||||||
|
|
||||||
|
/* upon error exit loop */
|
||||||
|
if(res)
|
||||||
|
break;
|
||||||
|
|
||||||
} /* loop to the next globbed upload file */
|
} /* loop to the next globbed upload file */
|
||||||
|
|
||||||
if(inglob) {
|
if(inglob) {
|
||||||
|
Loading…
Reference in New Issue
Block a user