]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
fix handling of out of memory in the command line tool that afected
authorYang Tse <yangsita@gmail.com>
Wed, 16 Jan 2008 21:01:30 +0000 (21:01 +0000)
committerYang Tse <yangsita@gmail.com>
Wed, 16 Jan 2008 21:01:30 +0000 (21:01 +0000)
data url encoded HTTP POSTs when reading it from a file.

CHANGES
RELEASE-NOTES
src/main.c

diff --git a/CHANGES b/CHANGES
index 042c3b373e4feafd79d43d3dfa78d59d567118bd..8f382bf9b2f40465f93c45a564c1bc6dd821e2ed 100644 (file)
--- 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
index 81c65c14028baa0c147473c0df6e1a01f8fe8ad7..ba5ec528226b6c6f2a5205e730b92393b2a9516f 100644 (file)
@@ -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:
 
index 1b0036bcdb6a7c98c140ffe88c5bdae6c3554544..b7e06e4365ea28e1d2954cb7de8f0d48ace10ea8 100644 (file)
@@ -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);