From 3d55877764c787a3ba14525b8a3b2f71b8cc40eb Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Wed, 16 Jan 2008 21:01:30 +0000 Subject: [PATCH] fix handling of out of memory in the command line tool that afected data url encoded HTTP POSTs when reading it from a file. --- CHANGES | 4 ++ RELEASE-NOTES | 1 + src/main.c | 169 +++++++++++++++++++++++++++++++++------------------------- 3 files changed, 100 insertions(+), 74 deletions(-) diff --git a/CHANGES b/CHANGES index 042c3b3..8f382bf 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,10 @@ Changelog +Yang Tse (16 Jan 2008) +- Improved handling of out of memory in the command line tool that afected + data url encoded HTTP POSTs when reading it from a file. + Daniel S (16 Jan 2008) - Dmitry Kurochkin worked a lot on improving the HTTP Pipelining support that previously had a number of flaws, perhaps most notably when an application diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 81c65c1..ba5ec52 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -55,6 +55,7 @@ This release includes the following bugfixes: o libcurl hang with huge POST request and request-body read from callback o removed extra newlines from many error messages o improved pipelining + o improved OOM handling for data url encoded HTTP POSTs when read from a file This release includes the following known bugs: diff --git a/src/main.c b/src/main.c index 1b0036b..b7e06e4 100644 --- a/src/main.c +++ b/src/main.c @@ -803,71 +803,6 @@ static void GetStr(char **string, *string = NULL; } -static char *file2string(FILE *file) -{ - char buffer[256]; - char *ptr; - char *string=NULL; - size_t len=0; - size_t stringlen; - - if(file) { - while(fgets(buffer, sizeof(buffer), file)) { - ptr= strchr(buffer, '\r'); - if(ptr) - *ptr=0; - ptr= strchr(buffer, '\n'); - if(ptr) - *ptr=0; - stringlen=strlen(buffer); - if(string) - string = realloc(string, len+stringlen+1); - else - string = malloc(stringlen+1); - - strcpy(string+len, buffer); - - len+=stringlen; - } - return string; - } - else - return NULL; /* no string */ -} - -static char *file2memory(FILE *file, long *size) -{ - char buffer[1024]; - char *string=NULL; - char *newstring=NULL; - size_t len=0; - long stringlen=0; - - if(file) { - while((len = fread(buffer, 1, sizeof(buffer), file))) { - if(string) { - newstring = realloc(string, len+stringlen+1); - if(newstring) - string = newstring; - else - break; /* no more strings attached! :-) */ - } - else - string = malloc(len+1); - memcpy(&string[stringlen], buffer, len); - stringlen+=len; - } - if (string) { - /* NUL terminate the buffer in case it's treated as a string later */ - string[stringlen] = 0; - } - *size = stringlen; - return string; - } - else - return NULL; /* no string */ -} - static void clean_getout(struct Configurable *config) { struct getout *node=config->url_list; @@ -1310,6 +1245,82 @@ static const char *param2text(int res) } } +static ParameterError file2string(char **bufp, FILE *file) +{ + char buffer[256]; + char *ptr; + char *string = NULL; + size_t stringlen = 0; + size_t buflen; + + if(file) { + while(fgets(buffer, sizeof(buffer), file)) { + if((ptr = strchr(buffer, '\r')) != NULL) + *ptr = '\0'; + if((ptr = strchr(buffer, '\n')) != NULL) + *ptr = '\0'; + buflen = strlen(buffer); + if((ptr = realloc(string, stringlen+buflen+1)) == NULL) { + if(string) + free(string); + return PARAM_NO_MEM; + } + string = ptr; + strcpy(string+stringlen, buffer); + stringlen += buflen; + } + } + *bufp = string; + return PARAM_OK; +} + +static ParameterError file2memory(char **bufp, size_t *size, FILE *file) +{ + char *newbuf; + char *buffer = NULL; + size_t alloc = 512; + size_t nused = 0; + size_t nread; + + if(file) { + do { + if(!buffer || (alloc == nused)) { + /* size_t overflow detection for huge files */ + if(alloc+1 > ((size_t)-1)/2) { + if(buffer) + free(buffer); + return PARAM_NO_MEM; + } + alloc *= 2; + /* allocate an extra char, reserved space, for null termination */ + if((newbuf = realloc(buffer, alloc+1)) == NULL) { + if(buffer) + free(buffer); + return PARAM_NO_MEM; + } + buffer = newbuf; + } + nread = fread(buffer+nused, 1, alloc-nused, file); + nused += nread; + } while(nread); + /* null terminate the buffer in case it's used as a string later */ + buffer[nused] = '\0'; + /* free trailing slack space, if possible */ + if(alloc != nused) { + if((newbuf = realloc(buffer, nused+1)) != NULL) + buffer = newbuf; + } + /* discard buffer if nothing was read */ + if(!nused) { + free(buffer); + buffer = NULL; /* no string */ + } + } + *size = nused; + *bufp = buffer; + return PARAM_OK; +} + static void cleanarg(char *str) { #ifdef HAVE_WRITABLE_ARGV @@ -2158,7 +2169,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ * the content. */ char *p = strchr(nextarg, '='); - long size = 0; + size_t size = 0; size_t nlen; char is_file; if(!p) @@ -2188,14 +2199,16 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ "an empty POST.\n", nextarg); } - postdata = file2memory(file, &size); + err = file2memory(&postdata, &size, file); if(file && (file != stdin)) fclose(file); + if(err) + return err; } else { GetStr(&postdata, p); - size = (long)strlen(postdata); + size = strlen(postdata); } if(!postdata) { @@ -2229,6 +2242,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ } } else if('@' == *nextarg) { + size_t size = 0; /* the data begins with a '@' letter, it means that a file name or - (stdin) follows */ nextarg++; /* pass the @ */ @@ -2245,13 +2259,18 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ "an empty POST.\n", nextarg); } - if(subletter == 'b') /* forced binary */ - postdata = file2memory(file, &config->postfieldsize); + if(subletter == 'b') { + /* forced binary */ + err = file2memory(&postdata, &size, file); + config->postfieldsize = size; + } else - postdata = file2string(file); + err = file2string(&postdata, file); if(file && (file != stdin)) fclose(file); + if(err) + return err; if(!postdata) { /* no data from the file, point to a zero byte string to make this @@ -2714,11 +2733,13 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ file = stdin; else file = fopen(nextarg, "r"); - config->writeout = file2string(file); - if(!config->writeout) - warnf(config, "Failed to read %s", file); + err = file2string(&config->writeout, file); if(file && (file != stdin)) fclose(file); + if(err) + return err; + if(!config->writeout) + warnf(config, "Failed to read %s", file); } else GetStr(&config->writeout, nextarg); -- 2.7.4