← Commit list

fe7703a0b3

Patrick Monnerat
Patrick Monnerat
2025-12-04
SUCCESS Duration: 366s

Subject

formdata: use struct bufref for maybe-dynamic fields.

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/formdata.c+130 -182
@@ -37,6 +37,7 @@ struct Curl_easy;
#include "sendf.h"
#include "strdup.h"
#include "rand.h"
+#include "bufref.h"
#include "curlx/fopen.h"
#include "curlx/warnless.h"
@@ -66,23 +67,23 @@ static struct curl_httppost *AddHttpPost(struct FormInfo *src,
{
struct curl_httppost *post;
size_t namelength = src->namelength;
- if(!namelength && src->name)
- namelength = strlen(src->name);
+ if(!namelength && Curl_bufref_ptr(&src->name))
+ namelength = strlen(Curl_bufref_ptr(&src->name));
if((src->bufferlength > LONG_MAX) || (namelength > LONG_MAX))
/* avoid overflow in typecasts below */
return NULL;
post = curlx_calloc(1, sizeof(struct curl_httppost));
if(post) {
- post->name = src->name;
+ post->name = CURL_UNCONST(Curl_bufref_ptr(&src->name));
post->namelength = (long)namelength;
- post->contents = src->value;
+ post->contents = CURL_UNCONST(Curl_bufref_ptr(&src->value));
post->contentlen = src->contentslength;
post->buffer = src->buffer;
post->bufferlength = (long)src->bufferlength;
- post->contenttype = src->contenttype;
+ post->contenttype = CURL_UNCONST(Curl_bufref_ptr(&src->contenttype));
post->flags = src->flags | CURL_HTTPPOST_LARGE;
post->contentheader = src->contentheader;
- post->showfilename = src->showfilename;
+ post->showfilename = CURL_UNCONST(Curl_bufref_ptr(&src->showfilename));
post->userp = src->userp;
}
else
@@ -107,60 +108,63 @@ static struct curl_httppost *AddHttpPost(struct FormInfo *src,
return post;
}
+/* Allocate and initialize a new FormInfo structure. */
+static struct FormInfo *NewFormInfo(void)
+{
+ struct FormInfo *form_info = curlx_calloc(1, sizeof(struct FormInfo));
+
+ if(form_info) {
+ Curl_bufref_init(&form_info->name);
+ Curl_bufref_init(&form_info->value);
+ Curl_bufref_init(&form_info->contenttype);
+ Curl_bufref_init(&form_info->showfilename);
+ }
+
+ return form_info;
+}
+
+/* Replace the target field data by a dynamic copy of it. */
+static CURLcode FormInfoCopyField(struct bufref *field, size_t len)
+{
+ const char *value = Curl_bufref_ptr(field);
+ CURLcode result = CURLE_OK;
+
+ if(value) {
+ if(!len)
+ len = strlen(value);
+ result = Curl_bufref_memdup(field, value, len);
+ }
+
+ return result;
+}
+
/***************************************************************************
*
* AddFormInfo()
*
- * Adds a FormInfo structure to the list presented by parent_form_info.
- *
- * Returns newly allocated FormInfo on success and NULL if malloc failed/
- * parent_form_info is NULL.
+ * Adds a FormInfo structure to the list presented by parent.
*
***************************************************************************/
-static struct FormInfo *AddFormInfo(char *value,
- char *contenttype,
- struct FormInfo *parent_form_info)
+static void AddFormInfo(struct FormInfo *form_info, struct FormInfo *parent)
{
- struct FormInfo *form_info;
- form_info = curlx_calloc(1, sizeof(struct FormInfo));
- if(!form_info)
- return NULL;
- if(value)
- form_info->value = value;
- if(contenttype)
- form_info->contenttype = contenttype;
- form_info->flags = HTTPPOST_FILENAME;
+ form_info->flags |= HTTPPOST_FILENAME;
- if(parent_form_info) {
+ if(parent) {
/* now, point our 'more' to the original 'more' */
- form_info->more = parent_form_info->more;
+ form_info->more = parent->more;
/* then move the original 'more' to point to ourselves */
- parent_form_info->more = form_info;
+ parent->more = form_info;
}
-
- return form_info;
}
static void free_formlist(struct FormInfo *ptr)
{
for(; ptr != NULL; ptr = ptr->more) {
- if(ptr->name_alloc) {
- Curl_safefree(ptr->name);
- ptr->name_alloc = FALSE;
- }
- if(ptr->value_alloc) {
- Curl_safefree(ptr->value);
- ptr->value_alloc = FALSE;
- }
- if(ptr->contenttype_alloc) {
- Curl_safefree(ptr->contenttype);
- ptr->contenttype_alloc = FALSE;
- }
- if(ptr->showfilename_alloc) {
- Curl_safefree(ptr->showfilename);
- ptr->showfilename_alloc = FALSE;
- }
+ Curl_bufref_free(&ptr->name);
+ Curl_bufref_free(&ptr->value);
+ Curl_bufref_free(&ptr->contenttype);
+ Curl_bufref_free(&ptr->showfilename);
}
}
@@ -227,7 +231,9 @@ static CURLFORMcode FormAddCheck(struct FormInfo *first_form,
* alright add the HttpPost item otherwise set retval accordingly */
for(form = first_form; form != NULL; form = form->more) {
- if(((!form->name || !form->value) && !post) ||
+ const char *name = Curl_bufref_ptr(&form->name);
+
+ if(((!name || !Curl_bufref_ptr(&form->value)) && !post) ||
(form->contentslength &&
(form->flags & HTTPPOST_FILENAME)) ||
((form->flags & HTTPPOST_FILENAME) &&
@@ -244,62 +250,42 @@ static CURLFORMcode FormAddCheck(struct FormInfo *first_form,
}
if(((form->flags & HTTPPOST_FILENAME) ||
(form->flags & HTTPPOST_BUFFER)) &&
- !form->contenttype) {
- char *f = (form->flags & HTTPPOST_BUFFER) ?
- form->showfilename : form->value;
- char const *type;
- type = Curl_mime_contenttype(f);
+ !Curl_bufref_ptr(&form->contenttype)) {
+ const char *f = Curl_bufref_ptr((form->flags & HTTPPOST_BUFFER) ?
+ &form->showfilename : &form->value);
+ const char *type = Curl_mime_contenttype(f);
if(!type)
type = prevtype;
if(!type)
type = FILE_CONTENTTYPE_DEFAULT;
/* our contenttype is missing */
- form->contenttype = curlx_strdup(type);
- if(!form->contenttype)
+ if(Curl_bufref_memdup(&form->contenttype, type, strlen(type)))
return CURL_FORMADD_MEMORY;
-
- form->contenttype_alloc = TRUE;
}
- if(form->name && form->namelength) {
- if(memchr(form->name, 0, form->namelength))
+ if(name && form->namelength) {
+ if(memchr(name, 0, form->namelength))
return CURL_FORMADD_NULL;
}
- if(!(form->flags & HTTPPOST_PTRNAME) && form->name) {
+ if(!(form->flags & HTTPPOST_PTRNAME)) {
/* Note that there is small risk that form->name is NULL here if the app
passed in a bad combo, so we check for that. */
-
- /* copy name (without strdup; possibly not null-terminated) */
- char *dupname = Curl_memdup0(form->name, form->namelength ?
- form->namelength : strlen(form->name));
- if(!dupname)
+ if(FormInfoCopyField(&form->name, form->namelength))
return CURL_FORMADD_MEMORY;
-
- form->name = dupname;
- form->name_alloc = TRUE;
}
if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
- HTTPPOST_CALLBACK)) && form->value) {
- /* copy value (without strdup; possibly contains null characters) */
- size_t clen = (size_t)form->contentslength;
- if(!clen)
- clen = strlen(form->value) + 1;
-
- form->value = Curl_memdup(form->value, clen);
-
- if(!form->value)
+ HTTPPOST_CALLBACK))) {
+ if(FormInfoCopyField(&form->value, (size_t) form->contentslength))
return CURL_FORMADD_MEMORY;
-
- form->value_alloc = TRUE;
}
post = AddHttpPost(form, post, httppost, last_post);
if(!post)
return CURL_FORMADD_MEMORY;
- if(form->contenttype)
- prevtype = form->contenttype;
+ if(Curl_bufref_ptr(&form->contenttype))
+ prevtype = Curl_bufref_ptr(&form->contenttype);
}
return CURL_FORMADD_OK;
@@ -329,15 +315,17 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
struct curl_httppost *newchain = NULL;
struct curl_httppost *lastnode = NULL;
- /* This is a state variable, that if TRUE means that we are parsing an
- array that we got passed to us. If FALSE we are parsing the input
- va_list arguments. */
- bool array_state = FALSE;
+#define form_ptr_arg(t) (forms ? (t) (void *) avalue : va_arg(params, t))
+#ifdef HAVE_STDINT_H
+#define form_int_arg(t) (forms ? (t) (uintptr_t) avalue : va_arg(params, t))
+#else
+#define form_int_arg(t) (forms ? (t) (void *) avalue : va_arg(params, t))
+#endif
/*
* We need to allocate the first struct to fill in.
*/
- first_form = curlx_calloc(1, sizeof(struct FormInfo));
+ first_form = NewFormInfo();
if(!first_form)
return CURL_FORMADD_MEMORY;
@@ -349,7 +337,7 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
while(retval == CURL_FORMADD_OK) {
/* first see if we have more parts of the array param */
- if(array_state && forms) {
+ if(forms) {
/* get the upcoming option from the given array */
option = forms->option;
avalue = (char *)CURL_UNCONST(forms->value);
@@ -357,7 +345,7 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
forms++; /* advance this to next entry */
if(CURLFORM_END == option) {
/* end of array state */
- array_state = FALSE;
+ forms = NULL;
continue;
}
}
@@ -372,14 +360,12 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
switch(option) {
case CURLFORM_ARRAY:
- if(array_state)
+ if(forms)
/* we do not support an array from within an array */
retval = CURL_FORMADD_ILLEGAL_ARRAY;
else {
forms = va_arg(params, struct curl_forms *);
- if(forms)
- array_state = TRUE;
- else
+ if(!forms)
retval = CURL_FORMADD_NULL;
}
break;
@@ -388,17 +374,15 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
* Set the Name property.
*/
case CURLFORM_PTRNAME:
- curr->flags |= HTTPPOST_PTRNAME; /* fall through */
-
+ curr->flags |= HTTPPOST_PTRNAME;
FALLTHROUGH();
case CURLFORM_COPYNAME:
- if(curr->name)
+ if(Curl_bufref_ptr(&curr->name))
retval = CURL_FORMADD_OPTION_TWICE;
else {
- if(!array_state)
- avalue = va_arg(params, char *);
+ avalue = form_ptr_arg(char *);
if(avalue)
- curr->name = avalue; /* store for the moment */
+ Curl_bufref_set(&curr->name, avalue, 0, NULL); /* No copy yet. */
else
retval = CURL_FORMADD_NULL;
}
@@ -407,8 +391,7 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
if(curr->namelength)
retval = CURL_FORMADD_OPTION_TWICE;
else
- curr->namelength =
- array_state ? (size_t)avalue : (size_t)va_arg(params, long);
+ curr->namelength = (size_t) form_int_arg(long);
break;
/*
@@ -418,26 +401,23 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
curr->flags |= HTTPPOST_PTRCONTENTS;
FALLTHROUGH();
case CURLFORM_COPYCONTENTS:
- if(curr->value)
+ if(Curl_bufref_ptr(&curr->value))
retval = CURL_FORMADD_OPTION_TWICE;
else {
- if(!array_state)
- avalue = va_arg(params, char *);
+ avalue = form_ptr_arg(char *);
if(avalue)
- curr->value = avalue; /* store for the moment */
+ Curl_bufref_set(&curr->value, avalue, 0, NULL); /* No copy yet. */
else
retval = CURL_FORMADD_NULL;
}
break;
case CURLFORM_CONTENTSLENGTH:
- curr->contentslength =
- array_state ? (size_t)avalue : (size_t)va_arg(params, long);
+ curr->contentslength = (curl_off_t)(size_t) form_int_arg(long);
break;
case CURLFORM_CONTENTLEN:
curr->flags |= CURL_HTTPPOST_LARGE;
- curr->contentslength =
- array_state ? (curl_off_t)(size_t)avalue : va_arg(params, curl_off_t);
+ curr->contentslength = form_int_arg(curl_off_t);
break;
/* Get contents from a given filename */
@@ -445,16 +425,12 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
if(curr->flags & (HTTPPOST_PTRCONTENTS | HTTPPOST_READFILE))
retval = CURL_FORMADD_OPTION_TWICE;
else {
- if(!array_state)
- avalue = va_arg(params, char *);
+ avalue = form_ptr_arg(char *);
if(avalue) {
- curr->value = curlx_strdup(avalue);
- if(!curr->value)
+ if(Curl_bufref_memdup(&curr->value, avalue, strlen(avalue)))
retval = CURL_FORMADD_MEMORY;
- else {
+ else
curr->flags |= HTTPPOST_READFILE;
- curr->value_alloc = TRUE;
- }
}
else
retval = CURL_FORMADD_NULL;
@@ -463,26 +439,20 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
/* We upload a file */
case CURLFORM_FILE:
- if(!array_state)
- avalue = va_arg(params, char *);
-
- if(curr->value) {
+ avalue = form_ptr_arg(char *);
+ if(Curl_bufref_ptr(&curr->value)) {
if(curr->flags & HTTPPOST_FILENAME) {
if(avalue) {
- char *fname = curlx_strdup(avalue);
- if(!fname)
+ form = NewFormInfo();
+ if(!form ||
+ Curl_bufref_memdup(&form->value, avalue, strlen(avalue))) {
+ curlx_free(form);
retval = CURL_FORMADD_MEMORY;
+ }
else {
- form = AddFormInfo(fname, NULL, curr);
- if(!form) {
- curlx_free(fname);
- retval = CURL_FORMADD_MEMORY;
- }
- else {
- form->value_alloc = TRUE;
- curr = form;
- form = NULL;
- }
+ AddFormInfo(form, curr);
+ curr = form;
+ form = NULL;
}
}
else
@@ -493,13 +463,10 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
}
else {
if(avalue) {
- curr->value = curlx_strdup(avalue);
- if(!curr->value)
+ if(Curl_bufref_memdup(&curr->value, avalue, strlen(avalue)))
retval = CURL_FORMADD_MEMORY;
- else {
+ else
curr->flags |= HTTPPOST_FILENAME;
- curr->value_alloc = TRUE;
- }
}
else
retval = CURL_FORMADD_NULL;
@@ -511,12 +478,11 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
if(curr->buffer)
retval = CURL_FORMADD_OPTION_TWICE;
else {
- if(!array_state)
- avalue = va_arg(params, char *);
+ avalue = form_ptr_arg(char *);
if(avalue) {
curr->buffer = avalue; /* store for the moment */
- curr->value = avalue; /* make it non-NULL to be accepted
- as fine */
+ /* Make value non-NULL to be accepted as fine */
+ Curl_bufref_set(&curr->value, avalue, 0, NULL);
}
else
retval = CURL_FORMADD_NULL;
@@ -527,8 +493,7 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
if(curr->bufferlength)
retval = CURL_FORMADD_OPTION_TWICE;
else
- curr->bufferlength =
- array_state ? (size_t)avalue : (size_t)va_arg(params, long);
+ curr->bufferlength = (size_t) form_int_arg(long);
break;
case CURLFORM_STREAM:
@@ -536,14 +501,13 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
if(curr->userp)
retval = CURL_FORMADD_OPTION_TWICE;
else {
- if(!array_state)
- avalue = va_arg(params, char *);
+ avalue = form_ptr_arg(char *);
if(avalue) {
curr->userp = avalue;
- curr->value = avalue; /* this is not strictly true but we derive a
- value from this later on and we need this
- non-NULL to be accepted as a fine form
- part */
+ /* The following line is not strictly true but we derive a value
+ from this later on and we need this non-NULL to be accepted as
+ a fine form part */
+ Curl_bufref_set(&curr->value, avalue, 0, NULL);
}
else
retval = CURL_FORMADD_NULL;
@@ -551,25 +515,20 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
break;
case CURLFORM_CONTENTTYPE:
- if(!array_state)
- avalue = va_arg(params, char *);
- if(curr->contenttype) {
+ avalue = form_ptr_arg(char *);
+ if(Curl_bufref_ptr(&curr->contenttype)) {
if(curr->flags & HTTPPOST_FILENAME) {
if(avalue) {
- char *type = curlx_strdup(avalue);
- if(!type)
+ form = NewFormInfo();
+ if(!form || Curl_bufref_memdup(&form->contenttype, avalue,
+ strlen(avalue))) {
+ curlx_free(form);
retval = CURL_FORMADD_MEMORY;
+ }
else {
- form = AddFormInfo(NULL, type, curr);
- if(!form) {
- curlx_free(type);
- retval = CURL_FORMADD_MEMORY;
- }
- else {
- form->contenttype_alloc = TRUE;
- curr = form;
- form = NULL;
- }
+ AddFormInfo(form, curr);
+ curr = form;
+ form = NULL;
}
}
else
@@ -578,25 +537,18 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
else
retval = CURL_FORMADD_OPTION_TWICE;
}
- else {
- if(avalue) {
- curr->contenttype = curlx_strdup(avalue);
- if(!curr->contenttype)
- retval = CURL_FORMADD_MEMORY;
- else
- curr->contenttype_alloc = TRUE;
- }
- else
- retval = CURL_FORMADD_NULL;
+ else if(avalue) {
+ if(Curl_bufref_memdup(&curr->contenttype, avalue, strlen(avalue)))
+ retval = CURL_FORMADD_MEMORY;
}
+ else
+ retval = CURL_FORMADD_NULL;
break;
case CURLFORM_CONTENTHEADER: {
/* this "cast increases required alignment of target type" but
we consider it OK anyway */
- struct curl_slist *list = array_state ?
- (struct curl_slist *)(void *)avalue :
- va_arg(params, struct curl_slist *);
+ struct curl_slist *list = form_ptr_arg(struct curl_slist *);
if(curr->contentheader)
retval = CURL_FORMADD_OPTION_TWICE;
@@ -607,17 +559,11 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
}
case CURLFORM_FILENAME:
case CURLFORM_BUFFER:
- if(!array_state)
- avalue = va_arg(params, char *);
- if(curr->showfilename)
+ avalue = form_ptr_arg(char *);
+ if(Curl_bufref_ptr(&curr->showfilename))
retval = CURL_FORMADD_OPTION_TWICE;
- else {
- curr->showfilename = curlx_strdup(avalue);
- if(!curr->showfilename)
- retval = CURL_FORMADD_MEMORY;
- else
- curr->showfilename_alloc = TRUE;
- }
+ else if(Curl_bufref_memdup(&curr->showfilename, avalue, strlen(avalue)))
+ retval = CURL_FORMADD_MEMORY;
break;
default:
@@ -656,6 +602,8 @@ static CURLFORMcode FormAdd(struct curl_httppost **httppost,
free_chain(newchain);
return retval;
+#undef form_ptr_arg
+#undef form_int_arg
}
/*
lib/formdata.h+11 -13
@@ -28,25 +28,23 @@
#ifndef CURL_DISABLE_FORM_API
+#include "bufref.h"
+
/* used by FormAdd for temporary storage */
struct FormInfo {
- char *name;
- size_t namelength;
- char *value;
- curl_off_t contentslength;
- char *contenttype;
+ struct bufref name;
+ struct bufref value;
+ struct bufref contenttype;
+ struct bufref showfilename; /* The filename to show. If not set, the actual
+ filename will be used */
char *buffer; /* pointer to existing buffer used for file upload */
- size_t bufferlength;
- char *showfilename; /* The filename to show. If not set, the actual
- filename will be used */
char *userp; /* pointer for the read callback */
- struct curl_slist *contentheader;
struct FormInfo *more;
+ struct curl_slist *contentheader;
+ curl_off_t contentslength;
+ size_t namelength;
+ size_t bufferlength;
unsigned char flags;
- BIT(name_alloc);
- BIT(value_alloc);
- BIT(contenttype_alloc);
- BIT(showfilename_alloc);
};
CURLcode Curl_getformdata(CURL *data,