]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
paramhlp: fix CRLF-stripping files with "-d @file"
authorDaniel Stenberg <daniel@haxx.se>
Wed, 6 Mar 2024 14:39:09 +0000 (15:39 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 7 Mar 2024 07:14:45 +0000 (08:14 +0100)
All CR and LF bytes should be stripped, as documented, and all other
bytes are inluded in the data. Starting now, it also excludes null bytes
as they would otherwise also cut the data short.

Reported-by: Simon K
Fixes #13063
Closes #13064

docs/cmdline-opts/data.md
src/tool_paramhlp.c

index 71dd36e046cceabc86d43c64e9cea1d5d6785029..ebe2347d8686263f90d190a240110f761df2f98d 100644 (file)
@@ -40,8 +40,8 @@ data pieces specified are merged with a separating &-symbol. Thus, using
 If you start the data with the letter @, the rest should be a filename to read
 the data from, or - if you want curl to read the data from stdin. Posting data
 from a file named 'foobar' would thus be done with --data @foobar. When --data
-is told to read from a file like that, carriage returns and newlines are
-stripped out. If you do not want the @ character to have a special
+is told to read from a file like that, carriage returns, newlines and null
+bytes are stripped out. If you do not want the @ character to have a special
 interpretation use --data-raw instead.
 
 The data for this option is passed on to the server exactly as provided on the
index 2725815000dc95db2cb9443c87a9612f2033ec1a..c26f6bbefd775ce86096602f5a78b8fcec5d01ea 100644 (file)
@@ -63,6 +63,33 @@ struct getout *new_getout(struct OperationConfig *config)
   return node;
 }
 
+#define ISCRLF(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
+
+/* memcrlf() has two modes. Both operate on a given memory area with
+   a specified size.
+
+   countcrlf FALSE - return number of bytes from the start that DO NOT include
+   any CR or LF or NULL
+
+   countcrlf TRUE - return number of bytes from the start that are ONLY CR or
+   LF or NULL.
+
+*/
+static size_t memcrlf(char *orig,
+                      bool countcrlf, /* TRUE if we count CRLF, FALSE
+                                         if we count non-CRLF */
+                      size_t max)
+{
+  char *ptr = orig;
+  size_t total = max;
+  for(ptr = orig; max; max--, ptr++) {
+    bool crlf = ISCRLF(*ptr);
+    if(countcrlf ^ crlf)
+      return ptr - orig;
+  }
+  return total; /* no delimiter found */
+}
+
 #define MAX_FILE2STRING (256*1024*1024) /* big enough ? */
 
 ParameterError file2string(char **bufp, FILE *file)
@@ -71,18 +98,30 @@ ParameterError file2string(char **bufp, FILE *file)
   DEBUGASSERT(MAX_FILE2STRING < INT_MAX); /* needs to fit in an int later */
   curlx_dyn_init(&dyn, MAX_FILE2STRING);
   if(file) {
-    char buffer[256];
-
-    while(fgets(buffer, sizeof(buffer), file)) {
-      char *ptr = strchr(buffer, '\r');
-      if(ptr)
-        *ptr = '\0';
-      ptr = strchr(buffer, '\n');
-      if(ptr)
-        *ptr = '\0';
-      if(curlx_dyn_add(&dyn, buffer))
-        return PARAM_NO_MEM;
-    }
+    do {
+      char buffer[4096];
+      char *ptr;
+      size_t nread = fread(buffer, 1, sizeof(buffer), file);
+      if(ferror(file)) {
+        curlx_dyn_free(&dyn);
+        *bufp = NULL;
+        return PARAM_READ_ERROR;
+      }
+      ptr = buffer;
+      while(nread) {
+        size_t nlen = memcrlf(ptr, FALSE, nread);
+        if(curlx_dyn_addn(&dyn, ptr, nlen))
+          return PARAM_NO_MEM;
+        nread -= nlen;
+
+        if(nread) {
+          ptr += nlen;
+          nlen = memcrlf(ptr, TRUE, nread);
+          ptr += nlen;
+          nread -= nlen;
+        }
+      }
+    } while(!feof(file));
   }
   *bufp = curlx_dyn_ptr(&dyn);
   return PARAM_OK;