From: Daniel Stenberg Date: Sat, 18 Oct 2025 09:58:36 +0000 (+0200) Subject: tool_formparse: rewrite the headers file parser X-Git-Tag: rc-8_17_0-2~33 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f847d2ed0244319ee6b5e9b054c39077e62388ad;p=thirdparty%2Fcurl.git tool_formparse: rewrite the headers file parser The -F option allows users to provide a file with a set of headers for a specific formpost section. This code used old handcrafted parsing logic that potentially could do wrong. Rewrite to use my_get_line() and dynbuf. Supports longer lines and should be more solid parsing code. Gets somewhat complicated by the (unwise) feature that allows "folding" of header lines in the file: if a line starts with a space it should be appended to the previous. The previous code trimmed spurious CR characters wherever they would occur in a line but this version does not. It does not seem like something we want or that users would expect. Test 646 uses this feature. Closes #19113 --- diff --git a/src/tool_formparse.c b/src/tool_formparse.c index 0f0962ce0d..004ad6ff4c 100644 --- a/src/tool_formparse.c +++ b/src/tool_formparse.c @@ -28,6 +28,7 @@ #include "tool_getparam.h" #include "tool_paramhlp.h" #include "tool_formparse.h" +#include "tool_parsecfg.h" #include "memdebug.h" /* keep this as LAST include */ @@ -417,65 +418,63 @@ static int slist_append(struct curl_slist **plist, const char *data) } /* Read headers from a file and append to list. */ -static int read_field_headers(const char *filename, FILE *fp, - struct curl_slist **pheaders) +static int read_field_headers(FILE *fp, struct curl_slist **pheaders) { - size_t hdrlen = 0; - size_t pos = 0; - bool incomment = FALSE; - int lineno = 1; - char hdrbuf[999] = ""; /* Max. header length + 1. */ - - for(;;) { - int c = getc(fp); - if(c == EOF || (!pos && !ISSPACE(c))) { - /* Strip and flush the current header. */ - while(hdrlen && ISSPACE(hdrbuf[hdrlen - 1])) - hdrlen--; - if(hdrlen) { - hdrbuf[hdrlen] = '\0'; - if(slist_append(pheaders, hdrbuf)) { - errorf("Out of memory for field headers"); - return -1; - } - hdrlen = 0; - } - } - - switch(c) { - case EOF: - if(ferror(fp)) { - char errbuf[STRERROR_LEN]; - errorf("Header file %s read error: %s", filename, - curlx_strerror(errno, errbuf, sizeof(errbuf))); - return -1; - } - return 0; /* Done. */ - case '\r': - continue; /* Ignore. */ - case '\n': - pos = 0; - incomment = FALSE; - lineno++; + struct dynbuf line; + bool error = FALSE; + int err = 0; + + curlx_dyn_init(&line, 8092); + while(my_get_line(fp, &line, &error)) { + const char *ptr = curlx_dyn_ptr(&line); + size_t len = curlx_dyn_len(&line); + bool folded = FALSE; + if(ptr[0] == '#') /* comment */ continue; - case '#': - if(!pos) - incomment = TRUE; - break; - } + else if(ptr[0] == ' ') /* a continuation from the line before */ + folded = TRUE; + /* trim off trailing CRLFs and whitespaces */ + while(len && (ISNEWLINE(ptr[len -1]) || ISBLANK(ptr[len - 1]))) + len--; - pos++; - if(!incomment) { - if(hdrlen == sizeof(hdrbuf) - 1) { - warnf("File %s line %d: header too long (truncated)", - filename, lineno); - c = ' '; + if(!len) + continue; + curlx_dyn_setlen(&line, len); /* set the new length */ + + if(folded && *pheaders) { + /* append this new line onto the previous line */ + struct dynbuf amend; + struct curl_slist *l = *pheaders; + curlx_dyn_init(&amend, 8092); + /* find the last node */ + while(l && l->next) + l = l->next; + /* add both parts */ + if(curlx_dyn_add(&amend, l->data) || curlx_dyn_addn(&amend, ptr, len)) { + err = -1; + break; } - if(hdrlen <= sizeof(hdrbuf) - 1) - hdrbuf[hdrlen++] = (char) c; + curl_free(l->data); + /* we use maprintf here to make it a libcurl alloc, to match the previous + curl_slist_append */ + l->data = curl_maprintf("%s", curlx_dyn_ptr(&amend)); + curlx_dyn_free(&amend); + if(!l->data) { + errorf("Out of memory for field headers"); + err = 1; + } + } + else { + err = slist_append(pheaders, ptr); + } + if(err) { + errorf("Out of memory for field headers"); + err = -1; + break; } } - /* NOTREACHED */ + curlx_dyn_free(&line); + return err; } static int get_param_part(char endchar, @@ -572,7 +571,7 @@ static int get_param_part(char endchar, curlx_strerror(errno, errbuf, sizeof(errbuf))); } else { - int i = read_field_headers(hdrfile, fp, &headers); + int i = read_field_headers(fp, &headers); curlx_fclose(fp); if(i) { diff --git a/tests/data/test646 b/tests/data/test646 index 4f26dbdf92..fe86e32775 100644 --- a/tests/data/test646 +++ b/tests/data/test646 @@ -42,7 +42,7 @@ It may contain any type of data. X-fileheader1: This is a header from a file # This line is another comment. It precedes a folded header. -X-fileheader2: This is #a +X-fileheader2: This is #a folded header