xref: /third_party/curl/lib/formdata.c (revision 13498266)
113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci ***************************************************************************/
2413498266Sopenharmony_ci
2513498266Sopenharmony_ci#include "curl_setup.h"
2613498266Sopenharmony_ci
2713498266Sopenharmony_ci#include <curl/curl.h>
2813498266Sopenharmony_ci
2913498266Sopenharmony_ci#include "formdata.h"
3013498266Sopenharmony_ci#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
3113498266Sopenharmony_ci
3213498266Sopenharmony_ci#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
3313498266Sopenharmony_ci#include <libgen.h>
3413498266Sopenharmony_ci#endif
3513498266Sopenharmony_ci
3613498266Sopenharmony_ci#include "urldata.h" /* for struct Curl_easy */
3713498266Sopenharmony_ci#include "mime.h"
3813498266Sopenharmony_ci#include "vtls/vtls.h"
3913498266Sopenharmony_ci#include "strcase.h"
4013498266Sopenharmony_ci#include "sendf.h"
4113498266Sopenharmony_ci#include "strdup.h"
4213498266Sopenharmony_ci#include "rand.h"
4313498266Sopenharmony_ci#include "warnless.h"
4413498266Sopenharmony_ci/* The last 3 #include files should be in this order */
4513498266Sopenharmony_ci#include "curl_printf.h"
4613498266Sopenharmony_ci#include "curl_memory.h"
4713498266Sopenharmony_ci#include "memdebug.h"
4813498266Sopenharmony_ci
4913498266Sopenharmony_ci
5013498266Sopenharmony_ci#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
5113498266Sopenharmony_ci#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
5213498266Sopenharmony_ci#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
5313498266Sopenharmony_ci#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
5413498266Sopenharmony_ci#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
5513498266Sopenharmony_ci#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
5613498266Sopenharmony_ci#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
5713498266Sopenharmony_ci
5813498266Sopenharmony_ci/***************************************************************************
5913498266Sopenharmony_ci *
6013498266Sopenharmony_ci * AddHttpPost()
6113498266Sopenharmony_ci *
6213498266Sopenharmony_ci * Adds an HttpPost structure to the list, if parent_post is given becomes
6313498266Sopenharmony_ci * a subpost of parent_post instead of a direct list element.
6413498266Sopenharmony_ci *
6513498266Sopenharmony_ci * Returns newly allocated HttpPost on success and NULL if malloc failed.
6613498266Sopenharmony_ci *
6713498266Sopenharmony_ci ***************************************************************************/
6813498266Sopenharmony_cistatic struct curl_httppost *
6913498266Sopenharmony_ciAddHttpPost(char *name, size_t namelength,
7013498266Sopenharmony_ci            char *value, curl_off_t contentslength,
7113498266Sopenharmony_ci            char *buffer, size_t bufferlength,
7213498266Sopenharmony_ci            char *contenttype,
7313498266Sopenharmony_ci            long flags,
7413498266Sopenharmony_ci            struct curl_slist *contentHeader,
7513498266Sopenharmony_ci            char *showfilename, char *userp,
7613498266Sopenharmony_ci            struct curl_httppost *parent_post,
7713498266Sopenharmony_ci            struct curl_httppost **httppost,
7813498266Sopenharmony_ci            struct curl_httppost **last_post)
7913498266Sopenharmony_ci{
8013498266Sopenharmony_ci  struct curl_httppost *post;
8113498266Sopenharmony_ci  if(!namelength && name)
8213498266Sopenharmony_ci    namelength = strlen(name);
8313498266Sopenharmony_ci  if((bufferlength > LONG_MAX) || (namelength > LONG_MAX))
8413498266Sopenharmony_ci    /* avoid overflow in typecasts below */
8513498266Sopenharmony_ci    return NULL;
8613498266Sopenharmony_ci  post = calloc(1, sizeof(struct curl_httppost));
8713498266Sopenharmony_ci  if(post) {
8813498266Sopenharmony_ci    post->name = name;
8913498266Sopenharmony_ci    post->namelength = (long)namelength;
9013498266Sopenharmony_ci    post->contents = value;
9113498266Sopenharmony_ci    post->contentlen = contentslength;
9213498266Sopenharmony_ci    post->buffer = buffer;
9313498266Sopenharmony_ci    post->bufferlength = (long)bufferlength;
9413498266Sopenharmony_ci    post->contenttype = contenttype;
9513498266Sopenharmony_ci    post->contentheader = contentHeader;
9613498266Sopenharmony_ci    post->showfilename = showfilename;
9713498266Sopenharmony_ci    post->userp = userp;
9813498266Sopenharmony_ci    post->flags = flags | CURL_HTTPPOST_LARGE;
9913498266Sopenharmony_ci  }
10013498266Sopenharmony_ci  else
10113498266Sopenharmony_ci    return NULL;
10213498266Sopenharmony_ci
10313498266Sopenharmony_ci  if(parent_post) {
10413498266Sopenharmony_ci    /* now, point our 'more' to the original 'more' */
10513498266Sopenharmony_ci    post->more = parent_post->more;
10613498266Sopenharmony_ci
10713498266Sopenharmony_ci    /* then move the original 'more' to point to ourselves */
10813498266Sopenharmony_ci    parent_post->more = post;
10913498266Sopenharmony_ci  }
11013498266Sopenharmony_ci  else {
11113498266Sopenharmony_ci    /* make the previous point to this */
11213498266Sopenharmony_ci    if(*last_post)
11313498266Sopenharmony_ci      (*last_post)->next = post;
11413498266Sopenharmony_ci    else
11513498266Sopenharmony_ci      (*httppost) = post;
11613498266Sopenharmony_ci
11713498266Sopenharmony_ci    (*last_post) = post;
11813498266Sopenharmony_ci  }
11913498266Sopenharmony_ci  return post;
12013498266Sopenharmony_ci}
12113498266Sopenharmony_ci
12213498266Sopenharmony_ci/***************************************************************************
12313498266Sopenharmony_ci *
12413498266Sopenharmony_ci * AddFormInfo()
12513498266Sopenharmony_ci *
12613498266Sopenharmony_ci * Adds a FormInfo structure to the list presented by parent_form_info.
12713498266Sopenharmony_ci *
12813498266Sopenharmony_ci * Returns newly allocated FormInfo on success and NULL if malloc failed/
12913498266Sopenharmony_ci * parent_form_info is NULL.
13013498266Sopenharmony_ci *
13113498266Sopenharmony_ci ***************************************************************************/
13213498266Sopenharmony_cistatic struct FormInfo *AddFormInfo(char *value,
13313498266Sopenharmony_ci                                    char *contenttype,
13413498266Sopenharmony_ci                                    struct FormInfo *parent_form_info)
13513498266Sopenharmony_ci{
13613498266Sopenharmony_ci  struct FormInfo *form_info;
13713498266Sopenharmony_ci  form_info = calloc(1, sizeof(struct FormInfo));
13813498266Sopenharmony_ci  if(!form_info)
13913498266Sopenharmony_ci    return NULL;
14013498266Sopenharmony_ci  if(value)
14113498266Sopenharmony_ci    form_info->value = value;
14213498266Sopenharmony_ci  if(contenttype)
14313498266Sopenharmony_ci    form_info->contenttype = contenttype;
14413498266Sopenharmony_ci  form_info->flags = HTTPPOST_FILENAME;
14513498266Sopenharmony_ci
14613498266Sopenharmony_ci  if(parent_form_info) {
14713498266Sopenharmony_ci    /* now, point our 'more' to the original 'more' */
14813498266Sopenharmony_ci    form_info->more = parent_form_info->more;
14913498266Sopenharmony_ci
15013498266Sopenharmony_ci    /* then move the original 'more' to point to ourselves */
15113498266Sopenharmony_ci    parent_form_info->more = form_info;
15213498266Sopenharmony_ci  }
15313498266Sopenharmony_ci
15413498266Sopenharmony_ci  return form_info;
15513498266Sopenharmony_ci}
15613498266Sopenharmony_ci
15713498266Sopenharmony_ci/***************************************************************************
15813498266Sopenharmony_ci *
15913498266Sopenharmony_ci * FormAdd()
16013498266Sopenharmony_ci *
16113498266Sopenharmony_ci * Stores a formpost parameter and builds the appropriate linked list.
16213498266Sopenharmony_ci *
16313498266Sopenharmony_ci * Has two principal functionalities: using files and byte arrays as
16413498266Sopenharmony_ci * post parts. Byte arrays are either copied or just the pointer is stored
16513498266Sopenharmony_ci * (as the user requests) while for files only the filename and not the
16613498266Sopenharmony_ci * content is stored.
16713498266Sopenharmony_ci *
16813498266Sopenharmony_ci * While you may have only one byte array for each name, multiple filenames
16913498266Sopenharmony_ci * are allowed (and because of this feature CURLFORM_END is needed after
17013498266Sopenharmony_ci * using CURLFORM_FILE).
17113498266Sopenharmony_ci *
17213498266Sopenharmony_ci * Examples:
17313498266Sopenharmony_ci *
17413498266Sopenharmony_ci * Simple name/value pair with copied contents:
17513498266Sopenharmony_ci * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
17613498266Sopenharmony_ci * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
17713498266Sopenharmony_ci *
17813498266Sopenharmony_ci * name/value pair where only the content pointer is remembered:
17913498266Sopenharmony_ci * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
18013498266Sopenharmony_ci * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
18113498266Sopenharmony_ci * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
18213498266Sopenharmony_ci *
18313498266Sopenharmony_ci * storing a filename (CONTENTTYPE is optional!):
18413498266Sopenharmony_ci * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
18513498266Sopenharmony_ci * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
18613498266Sopenharmony_ci * CURLFORM_END);
18713498266Sopenharmony_ci *
18813498266Sopenharmony_ci * storing multiple filenames:
18913498266Sopenharmony_ci * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
19013498266Sopenharmony_ci * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
19113498266Sopenharmony_ci *
19213498266Sopenharmony_ci * Returns:
19313498266Sopenharmony_ci * CURL_FORMADD_OK             on success
19413498266Sopenharmony_ci * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
19513498266Sopenharmony_ci * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
19613498266Sopenharmony_ci * CURL_FORMADD_NULL           if a null pointer was given for a char
19713498266Sopenharmony_ci * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
19813498266Sopenharmony_ci * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
19913498266Sopenharmony_ci * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
20013498266Sopenharmony_ci * CURL_FORMADD_MEMORY         if an HttpPost struct cannot be allocated
20113498266Sopenharmony_ci * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
20213498266Sopenharmony_ci * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
20313498266Sopenharmony_ci *
20413498266Sopenharmony_ci ***************************************************************************/
20513498266Sopenharmony_ci
20613498266Sopenharmony_cistatic
20713498266Sopenharmony_ciCURLFORMcode FormAdd(struct curl_httppost **httppost,
20813498266Sopenharmony_ci                     struct curl_httppost **last_post,
20913498266Sopenharmony_ci                     va_list params)
21013498266Sopenharmony_ci{
21113498266Sopenharmony_ci  struct FormInfo *first_form, *current_form, *form = NULL;
21213498266Sopenharmony_ci  CURLFORMcode return_value = CURL_FORMADD_OK;
21313498266Sopenharmony_ci  const char *prevtype = NULL;
21413498266Sopenharmony_ci  struct curl_httppost *post = NULL;
21513498266Sopenharmony_ci  CURLformoption option;
21613498266Sopenharmony_ci  struct curl_forms *forms = NULL;
21713498266Sopenharmony_ci  char *array_value = NULL; /* value read from an array */
21813498266Sopenharmony_ci
21913498266Sopenharmony_ci  /* This is a state variable, that if TRUE means that we're parsing an
22013498266Sopenharmony_ci     array that we got passed to us. If FALSE we're parsing the input
22113498266Sopenharmony_ci     va_list arguments. */
22213498266Sopenharmony_ci  bool array_state = FALSE;
22313498266Sopenharmony_ci
22413498266Sopenharmony_ci  /*
22513498266Sopenharmony_ci   * We need to allocate the first struct to fill in.
22613498266Sopenharmony_ci   */
22713498266Sopenharmony_ci  first_form = calloc(1, sizeof(struct FormInfo));
22813498266Sopenharmony_ci  if(!first_form)
22913498266Sopenharmony_ci    return CURL_FORMADD_MEMORY;
23013498266Sopenharmony_ci
23113498266Sopenharmony_ci  current_form = first_form;
23213498266Sopenharmony_ci
23313498266Sopenharmony_ci  /*
23413498266Sopenharmony_ci   * Loop through all the options set. Break if we have an error to report.
23513498266Sopenharmony_ci   */
23613498266Sopenharmony_ci  while(return_value == CURL_FORMADD_OK) {
23713498266Sopenharmony_ci
23813498266Sopenharmony_ci    /* first see if we have more parts of the array param */
23913498266Sopenharmony_ci    if(array_state && forms) {
24013498266Sopenharmony_ci      /* get the upcoming option from the given array */
24113498266Sopenharmony_ci      option = forms->option;
24213498266Sopenharmony_ci      array_value = (char *)forms->value;
24313498266Sopenharmony_ci
24413498266Sopenharmony_ci      forms++; /* advance this to next entry */
24513498266Sopenharmony_ci      if(CURLFORM_END == option) {
24613498266Sopenharmony_ci        /* end of array state */
24713498266Sopenharmony_ci        array_state = FALSE;
24813498266Sopenharmony_ci        continue;
24913498266Sopenharmony_ci      }
25013498266Sopenharmony_ci    }
25113498266Sopenharmony_ci    else {
25213498266Sopenharmony_ci      /* This is not array-state, get next option. This gets an 'int' with
25313498266Sopenharmony_ci         va_arg() because CURLformoption might be a smaller type than int and
25413498266Sopenharmony_ci         might cause compiler warnings and wrong behavior. */
25513498266Sopenharmony_ci      option = (CURLformoption)va_arg(params, int);
25613498266Sopenharmony_ci      if(CURLFORM_END == option)
25713498266Sopenharmony_ci        break;
25813498266Sopenharmony_ci    }
25913498266Sopenharmony_ci
26013498266Sopenharmony_ci    switch(option) {
26113498266Sopenharmony_ci    case CURLFORM_ARRAY:
26213498266Sopenharmony_ci      if(array_state)
26313498266Sopenharmony_ci        /* we don't support an array from within an array */
26413498266Sopenharmony_ci        return_value = CURL_FORMADD_ILLEGAL_ARRAY;
26513498266Sopenharmony_ci      else {
26613498266Sopenharmony_ci        forms = va_arg(params, struct curl_forms *);
26713498266Sopenharmony_ci        if(forms)
26813498266Sopenharmony_ci          array_state = TRUE;
26913498266Sopenharmony_ci        else
27013498266Sopenharmony_ci          return_value = CURL_FORMADD_NULL;
27113498266Sopenharmony_ci      }
27213498266Sopenharmony_ci      break;
27313498266Sopenharmony_ci
27413498266Sopenharmony_ci      /*
27513498266Sopenharmony_ci       * Set the Name property.
27613498266Sopenharmony_ci       */
27713498266Sopenharmony_ci    case CURLFORM_PTRNAME:
27813498266Sopenharmony_ci      current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
27913498266Sopenharmony_ci
28013498266Sopenharmony_ci      FALLTHROUGH();
28113498266Sopenharmony_ci    case CURLFORM_COPYNAME:
28213498266Sopenharmony_ci      if(current_form->name)
28313498266Sopenharmony_ci        return_value = CURL_FORMADD_OPTION_TWICE;
28413498266Sopenharmony_ci      else {
28513498266Sopenharmony_ci        char *name = array_state?
28613498266Sopenharmony_ci          array_value:va_arg(params, char *);
28713498266Sopenharmony_ci        if(name)
28813498266Sopenharmony_ci          current_form->name = name; /* store for the moment */
28913498266Sopenharmony_ci        else
29013498266Sopenharmony_ci          return_value = CURL_FORMADD_NULL;
29113498266Sopenharmony_ci      }
29213498266Sopenharmony_ci      break;
29313498266Sopenharmony_ci    case CURLFORM_NAMELENGTH:
29413498266Sopenharmony_ci      if(current_form->namelength)
29513498266Sopenharmony_ci        return_value = CURL_FORMADD_OPTION_TWICE;
29613498266Sopenharmony_ci      else
29713498266Sopenharmony_ci        current_form->namelength =
29813498266Sopenharmony_ci          array_state?(size_t)array_value:(size_t)va_arg(params, long);
29913498266Sopenharmony_ci      break;
30013498266Sopenharmony_ci
30113498266Sopenharmony_ci      /*
30213498266Sopenharmony_ci       * Set the contents property.
30313498266Sopenharmony_ci       */
30413498266Sopenharmony_ci    case CURLFORM_PTRCONTENTS:
30513498266Sopenharmony_ci      current_form->flags |= HTTPPOST_PTRCONTENTS;
30613498266Sopenharmony_ci      FALLTHROUGH();
30713498266Sopenharmony_ci    case CURLFORM_COPYCONTENTS:
30813498266Sopenharmony_ci      if(current_form->value)
30913498266Sopenharmony_ci        return_value = CURL_FORMADD_OPTION_TWICE;
31013498266Sopenharmony_ci      else {
31113498266Sopenharmony_ci        char *value =
31213498266Sopenharmony_ci          array_state?array_value:va_arg(params, char *);
31313498266Sopenharmony_ci        if(value)
31413498266Sopenharmony_ci          current_form->value = value; /* store for the moment */
31513498266Sopenharmony_ci        else
31613498266Sopenharmony_ci          return_value = CURL_FORMADD_NULL;
31713498266Sopenharmony_ci      }
31813498266Sopenharmony_ci      break;
31913498266Sopenharmony_ci    case CURLFORM_CONTENTSLENGTH:
32013498266Sopenharmony_ci      current_form->contentslength =
32113498266Sopenharmony_ci        array_state?(size_t)array_value:(size_t)va_arg(params, long);
32213498266Sopenharmony_ci      break;
32313498266Sopenharmony_ci
32413498266Sopenharmony_ci    case CURLFORM_CONTENTLEN:
32513498266Sopenharmony_ci      current_form->flags |= CURL_HTTPPOST_LARGE;
32613498266Sopenharmony_ci      current_form->contentslength =
32713498266Sopenharmony_ci        array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
32813498266Sopenharmony_ci      break;
32913498266Sopenharmony_ci
33013498266Sopenharmony_ci      /* Get contents from a given file name */
33113498266Sopenharmony_ci    case CURLFORM_FILECONTENT:
33213498266Sopenharmony_ci      if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
33313498266Sopenharmony_ci        return_value = CURL_FORMADD_OPTION_TWICE;
33413498266Sopenharmony_ci      else {
33513498266Sopenharmony_ci        const char *filename = array_state?
33613498266Sopenharmony_ci          array_value:va_arg(params, char *);
33713498266Sopenharmony_ci        if(filename) {
33813498266Sopenharmony_ci          current_form->value = strdup(filename);
33913498266Sopenharmony_ci          if(!current_form->value)
34013498266Sopenharmony_ci            return_value = CURL_FORMADD_MEMORY;
34113498266Sopenharmony_ci          else {
34213498266Sopenharmony_ci            current_form->flags |= HTTPPOST_READFILE;
34313498266Sopenharmony_ci            current_form->value_alloc = TRUE;
34413498266Sopenharmony_ci          }
34513498266Sopenharmony_ci        }
34613498266Sopenharmony_ci        else
34713498266Sopenharmony_ci          return_value = CURL_FORMADD_NULL;
34813498266Sopenharmony_ci      }
34913498266Sopenharmony_ci      break;
35013498266Sopenharmony_ci
35113498266Sopenharmony_ci      /* We upload a file */
35213498266Sopenharmony_ci    case CURLFORM_FILE:
35313498266Sopenharmony_ci      {
35413498266Sopenharmony_ci        const char *filename = array_state?array_value:
35513498266Sopenharmony_ci          va_arg(params, char *);
35613498266Sopenharmony_ci
35713498266Sopenharmony_ci        if(current_form->value) {
35813498266Sopenharmony_ci          if(current_form->flags & HTTPPOST_FILENAME) {
35913498266Sopenharmony_ci            if(filename) {
36013498266Sopenharmony_ci              char *fname = strdup(filename);
36113498266Sopenharmony_ci              if(!fname)
36213498266Sopenharmony_ci                return_value = CURL_FORMADD_MEMORY;
36313498266Sopenharmony_ci              else {
36413498266Sopenharmony_ci                form = AddFormInfo(fname, NULL, current_form);
36513498266Sopenharmony_ci                if(!form) {
36613498266Sopenharmony_ci                  free(fname);
36713498266Sopenharmony_ci                  return_value = CURL_FORMADD_MEMORY;
36813498266Sopenharmony_ci                }
36913498266Sopenharmony_ci                else {
37013498266Sopenharmony_ci                  form->value_alloc = TRUE;
37113498266Sopenharmony_ci                  current_form = form;
37213498266Sopenharmony_ci                  form = NULL;
37313498266Sopenharmony_ci                }
37413498266Sopenharmony_ci              }
37513498266Sopenharmony_ci            }
37613498266Sopenharmony_ci            else
37713498266Sopenharmony_ci              return_value = CURL_FORMADD_NULL;
37813498266Sopenharmony_ci          }
37913498266Sopenharmony_ci          else
38013498266Sopenharmony_ci            return_value = CURL_FORMADD_OPTION_TWICE;
38113498266Sopenharmony_ci        }
38213498266Sopenharmony_ci        else {
38313498266Sopenharmony_ci          if(filename) {
38413498266Sopenharmony_ci            current_form->value = strdup(filename);
38513498266Sopenharmony_ci            if(!current_form->value)
38613498266Sopenharmony_ci              return_value = CURL_FORMADD_MEMORY;
38713498266Sopenharmony_ci            else {
38813498266Sopenharmony_ci              current_form->flags |= HTTPPOST_FILENAME;
38913498266Sopenharmony_ci              current_form->value_alloc = TRUE;
39013498266Sopenharmony_ci            }
39113498266Sopenharmony_ci          }
39213498266Sopenharmony_ci          else
39313498266Sopenharmony_ci            return_value = CURL_FORMADD_NULL;
39413498266Sopenharmony_ci        }
39513498266Sopenharmony_ci        break;
39613498266Sopenharmony_ci      }
39713498266Sopenharmony_ci
39813498266Sopenharmony_ci    case CURLFORM_BUFFERPTR:
39913498266Sopenharmony_ci      current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
40013498266Sopenharmony_ci      if(current_form->buffer)
40113498266Sopenharmony_ci        return_value = CURL_FORMADD_OPTION_TWICE;
40213498266Sopenharmony_ci      else {
40313498266Sopenharmony_ci        char *buffer =
40413498266Sopenharmony_ci          array_state?array_value:va_arg(params, char *);
40513498266Sopenharmony_ci        if(buffer) {
40613498266Sopenharmony_ci          current_form->buffer = buffer; /* store for the moment */
40713498266Sopenharmony_ci          current_form->value = buffer; /* make it non-NULL to be accepted
40813498266Sopenharmony_ci                                           as fine */
40913498266Sopenharmony_ci        }
41013498266Sopenharmony_ci        else
41113498266Sopenharmony_ci          return_value = CURL_FORMADD_NULL;
41213498266Sopenharmony_ci      }
41313498266Sopenharmony_ci      break;
41413498266Sopenharmony_ci
41513498266Sopenharmony_ci    case CURLFORM_BUFFERLENGTH:
41613498266Sopenharmony_ci      if(current_form->bufferlength)
41713498266Sopenharmony_ci        return_value = CURL_FORMADD_OPTION_TWICE;
41813498266Sopenharmony_ci      else
41913498266Sopenharmony_ci        current_form->bufferlength =
42013498266Sopenharmony_ci          array_state?(size_t)array_value:(size_t)va_arg(params, long);
42113498266Sopenharmony_ci      break;
42213498266Sopenharmony_ci
42313498266Sopenharmony_ci    case CURLFORM_STREAM:
42413498266Sopenharmony_ci      current_form->flags |= HTTPPOST_CALLBACK;
42513498266Sopenharmony_ci      if(current_form->userp)
42613498266Sopenharmony_ci        return_value = CURL_FORMADD_OPTION_TWICE;
42713498266Sopenharmony_ci      else {
42813498266Sopenharmony_ci        char *userp =
42913498266Sopenharmony_ci          array_state?array_value:va_arg(params, char *);
43013498266Sopenharmony_ci        if(userp) {
43113498266Sopenharmony_ci          current_form->userp = userp;
43213498266Sopenharmony_ci          current_form->value = userp; /* this isn't strictly true but we
43313498266Sopenharmony_ci                                          derive a value from this later on
43413498266Sopenharmony_ci                                          and we need this non-NULL to be
43513498266Sopenharmony_ci                                          accepted as a fine form part */
43613498266Sopenharmony_ci        }
43713498266Sopenharmony_ci        else
43813498266Sopenharmony_ci          return_value = CURL_FORMADD_NULL;
43913498266Sopenharmony_ci      }
44013498266Sopenharmony_ci      break;
44113498266Sopenharmony_ci
44213498266Sopenharmony_ci    case CURLFORM_CONTENTTYPE:
44313498266Sopenharmony_ci      {
44413498266Sopenharmony_ci        const char *contenttype =
44513498266Sopenharmony_ci          array_state?array_value:va_arg(params, char *);
44613498266Sopenharmony_ci        if(current_form->contenttype) {
44713498266Sopenharmony_ci          if(current_form->flags & HTTPPOST_FILENAME) {
44813498266Sopenharmony_ci            if(contenttype) {
44913498266Sopenharmony_ci              char *type = strdup(contenttype);
45013498266Sopenharmony_ci              if(!type)
45113498266Sopenharmony_ci                return_value = CURL_FORMADD_MEMORY;
45213498266Sopenharmony_ci              else {
45313498266Sopenharmony_ci                form = AddFormInfo(NULL, type, current_form);
45413498266Sopenharmony_ci                if(!form) {
45513498266Sopenharmony_ci                  free(type);
45613498266Sopenharmony_ci                  return_value = CURL_FORMADD_MEMORY;
45713498266Sopenharmony_ci                }
45813498266Sopenharmony_ci                else {
45913498266Sopenharmony_ci                  form->contenttype_alloc = TRUE;
46013498266Sopenharmony_ci                  current_form = form;
46113498266Sopenharmony_ci                  form = NULL;
46213498266Sopenharmony_ci                }
46313498266Sopenharmony_ci              }
46413498266Sopenharmony_ci            }
46513498266Sopenharmony_ci            else
46613498266Sopenharmony_ci              return_value = CURL_FORMADD_NULL;
46713498266Sopenharmony_ci          }
46813498266Sopenharmony_ci          else
46913498266Sopenharmony_ci            return_value = CURL_FORMADD_OPTION_TWICE;
47013498266Sopenharmony_ci        }
47113498266Sopenharmony_ci        else {
47213498266Sopenharmony_ci          if(contenttype) {
47313498266Sopenharmony_ci            current_form->contenttype = strdup(contenttype);
47413498266Sopenharmony_ci            if(!current_form->contenttype)
47513498266Sopenharmony_ci              return_value = CURL_FORMADD_MEMORY;
47613498266Sopenharmony_ci            else
47713498266Sopenharmony_ci              current_form->contenttype_alloc = TRUE;
47813498266Sopenharmony_ci          }
47913498266Sopenharmony_ci          else
48013498266Sopenharmony_ci            return_value = CURL_FORMADD_NULL;
48113498266Sopenharmony_ci        }
48213498266Sopenharmony_ci        break;
48313498266Sopenharmony_ci      }
48413498266Sopenharmony_ci    case CURLFORM_CONTENTHEADER:
48513498266Sopenharmony_ci      {
48613498266Sopenharmony_ci        /* this "cast increases required alignment of target type" but
48713498266Sopenharmony_ci           we consider it OK anyway */
48813498266Sopenharmony_ci        struct curl_slist *list = array_state?
48913498266Sopenharmony_ci          (struct curl_slist *)(void *)array_value:
49013498266Sopenharmony_ci          va_arg(params, struct curl_slist *);
49113498266Sopenharmony_ci
49213498266Sopenharmony_ci        if(current_form->contentheader)
49313498266Sopenharmony_ci          return_value = CURL_FORMADD_OPTION_TWICE;
49413498266Sopenharmony_ci        else
49513498266Sopenharmony_ci          current_form->contentheader = list;
49613498266Sopenharmony_ci
49713498266Sopenharmony_ci        break;
49813498266Sopenharmony_ci      }
49913498266Sopenharmony_ci    case CURLFORM_FILENAME:
50013498266Sopenharmony_ci    case CURLFORM_BUFFER:
50113498266Sopenharmony_ci      {
50213498266Sopenharmony_ci        const char *filename = array_state?array_value:
50313498266Sopenharmony_ci          va_arg(params, char *);
50413498266Sopenharmony_ci        if(current_form->showfilename)
50513498266Sopenharmony_ci          return_value = CURL_FORMADD_OPTION_TWICE;
50613498266Sopenharmony_ci        else {
50713498266Sopenharmony_ci          current_form->showfilename = strdup(filename);
50813498266Sopenharmony_ci          if(!current_form->showfilename)
50913498266Sopenharmony_ci            return_value = CURL_FORMADD_MEMORY;
51013498266Sopenharmony_ci          else
51113498266Sopenharmony_ci            current_form->showfilename_alloc = TRUE;
51213498266Sopenharmony_ci        }
51313498266Sopenharmony_ci        break;
51413498266Sopenharmony_ci      }
51513498266Sopenharmony_ci    default:
51613498266Sopenharmony_ci      return_value = CURL_FORMADD_UNKNOWN_OPTION;
51713498266Sopenharmony_ci      break;
51813498266Sopenharmony_ci    }
51913498266Sopenharmony_ci  }
52013498266Sopenharmony_ci
52113498266Sopenharmony_ci  if(CURL_FORMADD_OK != return_value) {
52213498266Sopenharmony_ci    /* On error, free allocated fields for all nodes of the FormInfo linked
52313498266Sopenharmony_ci       list without deallocating nodes. List nodes are deallocated later on */
52413498266Sopenharmony_ci    struct FormInfo *ptr;
52513498266Sopenharmony_ci    for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
52613498266Sopenharmony_ci      if(ptr->name_alloc) {
52713498266Sopenharmony_ci        Curl_safefree(ptr->name);
52813498266Sopenharmony_ci        ptr->name_alloc = FALSE;
52913498266Sopenharmony_ci      }
53013498266Sopenharmony_ci      if(ptr->value_alloc) {
53113498266Sopenharmony_ci        Curl_safefree(ptr->value);
53213498266Sopenharmony_ci        ptr->value_alloc = FALSE;
53313498266Sopenharmony_ci      }
53413498266Sopenharmony_ci      if(ptr->contenttype_alloc) {
53513498266Sopenharmony_ci        Curl_safefree(ptr->contenttype);
53613498266Sopenharmony_ci        ptr->contenttype_alloc = FALSE;
53713498266Sopenharmony_ci      }
53813498266Sopenharmony_ci      if(ptr->showfilename_alloc) {
53913498266Sopenharmony_ci        Curl_safefree(ptr->showfilename);
54013498266Sopenharmony_ci        ptr->showfilename_alloc = FALSE;
54113498266Sopenharmony_ci      }
54213498266Sopenharmony_ci    }
54313498266Sopenharmony_ci  }
54413498266Sopenharmony_ci
54513498266Sopenharmony_ci  if(CURL_FORMADD_OK == return_value) {
54613498266Sopenharmony_ci    /* go through the list, check for completeness and if everything is
54713498266Sopenharmony_ci     * alright add the HttpPost item otherwise set return_value accordingly */
54813498266Sopenharmony_ci
54913498266Sopenharmony_ci    post = NULL;
55013498266Sopenharmony_ci    for(form = first_form;
55113498266Sopenharmony_ci        form != NULL;
55213498266Sopenharmony_ci        form = form->more) {
55313498266Sopenharmony_ci      if(((!form->name || !form->value) && !post) ||
55413498266Sopenharmony_ci         ( (form->contentslength) &&
55513498266Sopenharmony_ci           (form->flags & HTTPPOST_FILENAME) ) ||
55613498266Sopenharmony_ci         ( (form->flags & HTTPPOST_FILENAME) &&
55713498266Sopenharmony_ci           (form->flags & HTTPPOST_PTRCONTENTS) ) ||
55813498266Sopenharmony_ci
55913498266Sopenharmony_ci         ( (!form->buffer) &&
56013498266Sopenharmony_ci           (form->flags & HTTPPOST_BUFFER) &&
56113498266Sopenharmony_ci           (form->flags & HTTPPOST_PTRBUFFER) ) ||
56213498266Sopenharmony_ci
56313498266Sopenharmony_ci         ( (form->flags & HTTPPOST_READFILE) &&
56413498266Sopenharmony_ci           (form->flags & HTTPPOST_PTRCONTENTS) )
56513498266Sopenharmony_ci        ) {
56613498266Sopenharmony_ci        return_value = CURL_FORMADD_INCOMPLETE;
56713498266Sopenharmony_ci        break;
56813498266Sopenharmony_ci      }
56913498266Sopenharmony_ci      if(((form->flags & HTTPPOST_FILENAME) ||
57013498266Sopenharmony_ci          (form->flags & HTTPPOST_BUFFER)) &&
57113498266Sopenharmony_ci         !form->contenttype) {
57213498266Sopenharmony_ci        char *f = (form->flags & HTTPPOST_BUFFER)?
57313498266Sopenharmony_ci          form->showfilename : form->value;
57413498266Sopenharmony_ci        char const *type;
57513498266Sopenharmony_ci        type = Curl_mime_contenttype(f);
57613498266Sopenharmony_ci        if(!type)
57713498266Sopenharmony_ci          type = prevtype;
57813498266Sopenharmony_ci        if(!type)
57913498266Sopenharmony_ci          type = FILE_CONTENTTYPE_DEFAULT;
58013498266Sopenharmony_ci
58113498266Sopenharmony_ci        /* our contenttype is missing */
58213498266Sopenharmony_ci        form->contenttype = strdup(type);
58313498266Sopenharmony_ci        if(!form->contenttype) {
58413498266Sopenharmony_ci          return_value = CURL_FORMADD_MEMORY;
58513498266Sopenharmony_ci          break;
58613498266Sopenharmony_ci        }
58713498266Sopenharmony_ci        form->contenttype_alloc = TRUE;
58813498266Sopenharmony_ci      }
58913498266Sopenharmony_ci      if(form->name && form->namelength) {
59013498266Sopenharmony_ci        /* Name should not contain nul bytes. */
59113498266Sopenharmony_ci        size_t i;
59213498266Sopenharmony_ci        for(i = 0; i < form->namelength; i++)
59313498266Sopenharmony_ci          if(!form->name[i]) {
59413498266Sopenharmony_ci            return_value = CURL_FORMADD_NULL;
59513498266Sopenharmony_ci            break;
59613498266Sopenharmony_ci          }
59713498266Sopenharmony_ci        if(return_value != CURL_FORMADD_OK)
59813498266Sopenharmony_ci          break;
59913498266Sopenharmony_ci      }
60013498266Sopenharmony_ci      if(!(form->flags & HTTPPOST_PTRNAME) &&
60113498266Sopenharmony_ci         (form == first_form) ) {
60213498266Sopenharmony_ci        /* Note that there's small risk that form->name is NULL here if the
60313498266Sopenharmony_ci           app passed in a bad combo, so we better check for that first. */
60413498266Sopenharmony_ci        if(form->name) {
60513498266Sopenharmony_ci          /* copy name (without strdup; possibly not null-terminated) */
60613498266Sopenharmony_ci          form->name = Curl_memdup0(form->name, form->namelength?
60713498266Sopenharmony_ci                                    form->namelength:
60813498266Sopenharmony_ci                                    strlen(form->name));
60913498266Sopenharmony_ci        }
61013498266Sopenharmony_ci        if(!form->name) {
61113498266Sopenharmony_ci          return_value = CURL_FORMADD_MEMORY;
61213498266Sopenharmony_ci          break;
61313498266Sopenharmony_ci        }
61413498266Sopenharmony_ci        form->name_alloc = TRUE;
61513498266Sopenharmony_ci      }
61613498266Sopenharmony_ci      if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
61713498266Sopenharmony_ci                          HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
61813498266Sopenharmony_ci                          HTTPPOST_CALLBACK)) && form->value) {
61913498266Sopenharmony_ci        /* copy value (without strdup; possibly contains null characters) */
62013498266Sopenharmony_ci        size_t clen  = (size_t) form->contentslength;
62113498266Sopenharmony_ci        if(!clen)
62213498266Sopenharmony_ci          clen = strlen(form->value) + 1;
62313498266Sopenharmony_ci
62413498266Sopenharmony_ci        form->value = Curl_memdup(form->value, clen);
62513498266Sopenharmony_ci
62613498266Sopenharmony_ci        if(!form->value) {
62713498266Sopenharmony_ci          return_value = CURL_FORMADD_MEMORY;
62813498266Sopenharmony_ci          break;
62913498266Sopenharmony_ci        }
63013498266Sopenharmony_ci        form->value_alloc = TRUE;
63113498266Sopenharmony_ci      }
63213498266Sopenharmony_ci      post = AddHttpPost(form->name, form->namelength,
63313498266Sopenharmony_ci                         form->value, form->contentslength,
63413498266Sopenharmony_ci                         form->buffer, form->bufferlength,
63513498266Sopenharmony_ci                         form->contenttype, form->flags,
63613498266Sopenharmony_ci                         form->contentheader, form->showfilename,
63713498266Sopenharmony_ci                         form->userp,
63813498266Sopenharmony_ci                         post, httppost,
63913498266Sopenharmony_ci                         last_post);
64013498266Sopenharmony_ci
64113498266Sopenharmony_ci      if(!post) {
64213498266Sopenharmony_ci        return_value = CURL_FORMADD_MEMORY;
64313498266Sopenharmony_ci        break;
64413498266Sopenharmony_ci      }
64513498266Sopenharmony_ci
64613498266Sopenharmony_ci      if(form->contenttype)
64713498266Sopenharmony_ci        prevtype = form->contenttype;
64813498266Sopenharmony_ci    }
64913498266Sopenharmony_ci    if(CURL_FORMADD_OK != return_value) {
65013498266Sopenharmony_ci      /* On error, free allocated fields for nodes of the FormInfo linked
65113498266Sopenharmony_ci         list which are not already owned by the httppost linked list
65213498266Sopenharmony_ci         without deallocating nodes. List nodes are deallocated later on */
65313498266Sopenharmony_ci      struct FormInfo *ptr;
65413498266Sopenharmony_ci      for(ptr = form; ptr != NULL; ptr = ptr->more) {
65513498266Sopenharmony_ci        if(ptr->name_alloc) {
65613498266Sopenharmony_ci          Curl_safefree(ptr->name);
65713498266Sopenharmony_ci          ptr->name_alloc = FALSE;
65813498266Sopenharmony_ci        }
65913498266Sopenharmony_ci        if(ptr->value_alloc) {
66013498266Sopenharmony_ci          Curl_safefree(ptr->value);
66113498266Sopenharmony_ci          ptr->value_alloc = FALSE;
66213498266Sopenharmony_ci        }
66313498266Sopenharmony_ci        if(ptr->contenttype_alloc) {
66413498266Sopenharmony_ci          Curl_safefree(ptr->contenttype);
66513498266Sopenharmony_ci          ptr->contenttype_alloc = FALSE;
66613498266Sopenharmony_ci        }
66713498266Sopenharmony_ci        if(ptr->showfilename_alloc) {
66813498266Sopenharmony_ci          Curl_safefree(ptr->showfilename);
66913498266Sopenharmony_ci          ptr->showfilename_alloc = FALSE;
67013498266Sopenharmony_ci        }
67113498266Sopenharmony_ci      }
67213498266Sopenharmony_ci    }
67313498266Sopenharmony_ci  }
67413498266Sopenharmony_ci
67513498266Sopenharmony_ci  /* Always deallocate FormInfo linked list nodes without touching node
67613498266Sopenharmony_ci     fields given that these have either been deallocated or are owned
67713498266Sopenharmony_ci     now by the httppost linked list */
67813498266Sopenharmony_ci  while(first_form) {
67913498266Sopenharmony_ci    struct FormInfo *ptr = first_form->more;
68013498266Sopenharmony_ci    free(first_form);
68113498266Sopenharmony_ci    first_form = ptr;
68213498266Sopenharmony_ci  }
68313498266Sopenharmony_ci
68413498266Sopenharmony_ci  return return_value;
68513498266Sopenharmony_ci}
68613498266Sopenharmony_ci
68713498266Sopenharmony_ci/*
68813498266Sopenharmony_ci * curl_formadd() is a public API to add a section to the multipart formpost.
68913498266Sopenharmony_ci *
69013498266Sopenharmony_ci * @unittest: 1308
69113498266Sopenharmony_ci */
69213498266Sopenharmony_ci
69313498266Sopenharmony_ciCURLFORMcode curl_formadd(struct curl_httppost **httppost,
69413498266Sopenharmony_ci                          struct curl_httppost **last_post,
69513498266Sopenharmony_ci                          ...)
69613498266Sopenharmony_ci{
69713498266Sopenharmony_ci  va_list arg;
69813498266Sopenharmony_ci  CURLFORMcode result;
69913498266Sopenharmony_ci  va_start(arg, last_post);
70013498266Sopenharmony_ci  result = FormAdd(httppost, last_post, arg);
70113498266Sopenharmony_ci  va_end(arg);
70213498266Sopenharmony_ci  return result;
70313498266Sopenharmony_ci}
70413498266Sopenharmony_ci
70513498266Sopenharmony_ci/*
70613498266Sopenharmony_ci * curl_formget()
70713498266Sopenharmony_ci * Serialize a curl_httppost struct.
70813498266Sopenharmony_ci * Returns 0 on success.
70913498266Sopenharmony_ci *
71013498266Sopenharmony_ci * @unittest: 1308
71113498266Sopenharmony_ci */
71213498266Sopenharmony_ciint curl_formget(struct curl_httppost *form, void *arg,
71313498266Sopenharmony_ci                 curl_formget_callback append)
71413498266Sopenharmony_ci{
71513498266Sopenharmony_ci  CURLcode result;
71613498266Sopenharmony_ci  curl_mimepart toppart;
71713498266Sopenharmony_ci
71813498266Sopenharmony_ci  Curl_mime_initpart(&toppart); /* default form is empty */
71913498266Sopenharmony_ci  result = Curl_getformdata(NULL, &toppart, form, NULL);
72013498266Sopenharmony_ci  if(!result)
72113498266Sopenharmony_ci    result = Curl_mime_prepare_headers(NULL, &toppart, "multipart/form-data",
72213498266Sopenharmony_ci                                       NULL, MIMESTRATEGY_FORM);
72313498266Sopenharmony_ci
72413498266Sopenharmony_ci  while(!result) {
72513498266Sopenharmony_ci    char buffer[8192];
72613498266Sopenharmony_ci    size_t nread = Curl_mime_read(buffer, 1, sizeof(buffer), &toppart);
72713498266Sopenharmony_ci
72813498266Sopenharmony_ci    if(!nread)
72913498266Sopenharmony_ci      break;
73013498266Sopenharmony_ci
73113498266Sopenharmony_ci    if(nread > sizeof(buffer) || append(arg, buffer, nread) != nread) {
73213498266Sopenharmony_ci      result = CURLE_READ_ERROR;
73313498266Sopenharmony_ci      if(nread == CURL_READFUNC_ABORT)
73413498266Sopenharmony_ci        result = CURLE_ABORTED_BY_CALLBACK;
73513498266Sopenharmony_ci    }
73613498266Sopenharmony_ci  }
73713498266Sopenharmony_ci
73813498266Sopenharmony_ci  Curl_mime_cleanpart(&toppart);
73913498266Sopenharmony_ci  return (int) result;
74013498266Sopenharmony_ci}
74113498266Sopenharmony_ci
74213498266Sopenharmony_ci/*
74313498266Sopenharmony_ci * curl_formfree() is an external function to free up a whole form post
74413498266Sopenharmony_ci * chain
74513498266Sopenharmony_ci */
74613498266Sopenharmony_civoid curl_formfree(struct curl_httppost *form)
74713498266Sopenharmony_ci{
74813498266Sopenharmony_ci  struct curl_httppost *next;
74913498266Sopenharmony_ci
75013498266Sopenharmony_ci  if(!form)
75113498266Sopenharmony_ci    /* no form to free, just get out of this */
75213498266Sopenharmony_ci    return;
75313498266Sopenharmony_ci
75413498266Sopenharmony_ci  do {
75513498266Sopenharmony_ci    next = form->next;  /* the following form line */
75613498266Sopenharmony_ci
75713498266Sopenharmony_ci    /* recurse to sub-contents */
75813498266Sopenharmony_ci    curl_formfree(form->more);
75913498266Sopenharmony_ci
76013498266Sopenharmony_ci    if(!(form->flags & HTTPPOST_PTRNAME))
76113498266Sopenharmony_ci      free(form->name); /* free the name */
76213498266Sopenharmony_ci    if(!(form->flags &
76313498266Sopenharmony_ci         (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
76413498266Sopenharmony_ci      )
76513498266Sopenharmony_ci      free(form->contents); /* free the contents */
76613498266Sopenharmony_ci    free(form->contenttype); /* free the content type */
76713498266Sopenharmony_ci    free(form->showfilename); /* free the faked file name */
76813498266Sopenharmony_ci    free(form);       /* free the struct */
76913498266Sopenharmony_ci    form = next;
77013498266Sopenharmony_ci  } while(form); /* continue */
77113498266Sopenharmony_ci}
77213498266Sopenharmony_ci
77313498266Sopenharmony_ci
77413498266Sopenharmony_ci/* Set mime part name, taking care of non null-terminated name string. */
77513498266Sopenharmony_cistatic CURLcode setname(curl_mimepart *part, const char *name, size_t len)
77613498266Sopenharmony_ci{
77713498266Sopenharmony_ci  char *zname;
77813498266Sopenharmony_ci  CURLcode res;
77913498266Sopenharmony_ci
78013498266Sopenharmony_ci  if(!name || !len)
78113498266Sopenharmony_ci    return curl_mime_name(part, name);
78213498266Sopenharmony_ci  zname = Curl_memdup0(name, len);
78313498266Sopenharmony_ci  if(!zname)
78413498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
78513498266Sopenharmony_ci  res = curl_mime_name(part, zname);
78613498266Sopenharmony_ci  free(zname);
78713498266Sopenharmony_ci  return res;
78813498266Sopenharmony_ci}
78913498266Sopenharmony_ci
79013498266Sopenharmony_ci/* wrap call to fseeko so it matches the calling convention of callback */
79113498266Sopenharmony_cistatic int fseeko_wrapper(void *stream, curl_off_t offset, int whence)
79213498266Sopenharmony_ci{
79313498266Sopenharmony_ci#if defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO)
79413498266Sopenharmony_ci  return fseeko(stream, (off_t)offset, whence);
79513498266Sopenharmony_ci#elif defined(HAVE__FSEEKI64)
79613498266Sopenharmony_ci  return _fseeki64(stream, (__int64)offset, whence);
79713498266Sopenharmony_ci#else
79813498266Sopenharmony_ci  if(offset > LONG_MAX)
79913498266Sopenharmony_ci    return -1;
80013498266Sopenharmony_ci  return fseek(stream, (long)offset, whence);
80113498266Sopenharmony_ci#endif
80213498266Sopenharmony_ci}
80313498266Sopenharmony_ci
80413498266Sopenharmony_ci/*
80513498266Sopenharmony_ci * Curl_getformdata() converts a linked list of "meta data" into a mime
80613498266Sopenharmony_ci * structure. The input list is in 'post', while the output is stored in
80713498266Sopenharmony_ci * mime part at '*finalform'.
80813498266Sopenharmony_ci *
80913498266Sopenharmony_ci * This function will not do a failf() for the potential memory failures but
81013498266Sopenharmony_ci * should for all other errors it spots. Just note that this function MAY get
81113498266Sopenharmony_ci * a NULL pointer in the 'data' argument.
81213498266Sopenharmony_ci */
81313498266Sopenharmony_ci
81413498266Sopenharmony_ciCURLcode Curl_getformdata(struct Curl_easy *data,
81513498266Sopenharmony_ci                          curl_mimepart *finalform,
81613498266Sopenharmony_ci                          struct curl_httppost *post,
81713498266Sopenharmony_ci                          curl_read_callback fread_func)
81813498266Sopenharmony_ci{
81913498266Sopenharmony_ci  CURLcode result = CURLE_OK;
82013498266Sopenharmony_ci  curl_mime *form = NULL;
82113498266Sopenharmony_ci  curl_mimepart *part;
82213498266Sopenharmony_ci  struct curl_httppost *file;
82313498266Sopenharmony_ci
82413498266Sopenharmony_ci  Curl_mime_cleanpart(finalform); /* default form is empty */
82513498266Sopenharmony_ci
82613498266Sopenharmony_ci  if(!post)
82713498266Sopenharmony_ci    return result; /* no input => no output! */
82813498266Sopenharmony_ci
82913498266Sopenharmony_ci  form = curl_mime_init(data);
83013498266Sopenharmony_ci  if(!form)
83113498266Sopenharmony_ci    result = CURLE_OUT_OF_MEMORY;
83213498266Sopenharmony_ci
83313498266Sopenharmony_ci  if(!result)
83413498266Sopenharmony_ci    result = curl_mime_subparts(finalform, form);
83513498266Sopenharmony_ci
83613498266Sopenharmony_ci  /* Process each top part. */
83713498266Sopenharmony_ci  for(; !result && post; post = post->next) {
83813498266Sopenharmony_ci    /* If we have more than a file here, create a mime subpart and fill it. */
83913498266Sopenharmony_ci    curl_mime *multipart = form;
84013498266Sopenharmony_ci    if(post->more) {
84113498266Sopenharmony_ci      part = curl_mime_addpart(form);
84213498266Sopenharmony_ci      if(!part)
84313498266Sopenharmony_ci        result = CURLE_OUT_OF_MEMORY;
84413498266Sopenharmony_ci      if(!result)
84513498266Sopenharmony_ci        result = setname(part, post->name, post->namelength);
84613498266Sopenharmony_ci      if(!result) {
84713498266Sopenharmony_ci        multipart = curl_mime_init(data);
84813498266Sopenharmony_ci        if(!multipart)
84913498266Sopenharmony_ci          result = CURLE_OUT_OF_MEMORY;
85013498266Sopenharmony_ci      }
85113498266Sopenharmony_ci      if(!result)
85213498266Sopenharmony_ci        result = curl_mime_subparts(part, multipart);
85313498266Sopenharmony_ci    }
85413498266Sopenharmony_ci
85513498266Sopenharmony_ci    /* Generate all the part contents. */
85613498266Sopenharmony_ci    for(file = post; !result && file; file = file->more) {
85713498266Sopenharmony_ci      /* Create the part. */
85813498266Sopenharmony_ci      part = curl_mime_addpart(multipart);
85913498266Sopenharmony_ci      if(!part)
86013498266Sopenharmony_ci        result = CURLE_OUT_OF_MEMORY;
86113498266Sopenharmony_ci
86213498266Sopenharmony_ci      /* Set the headers. */
86313498266Sopenharmony_ci      if(!result)
86413498266Sopenharmony_ci        result = curl_mime_headers(part, file->contentheader, 0);
86513498266Sopenharmony_ci
86613498266Sopenharmony_ci      /* Set the content type. */
86713498266Sopenharmony_ci      if(!result && file->contenttype)
86813498266Sopenharmony_ci        result = curl_mime_type(part, file->contenttype);
86913498266Sopenharmony_ci
87013498266Sopenharmony_ci      /* Set field name. */
87113498266Sopenharmony_ci      if(!result && !post->more)
87213498266Sopenharmony_ci        result = setname(part, post->name, post->namelength);
87313498266Sopenharmony_ci
87413498266Sopenharmony_ci      /* Process contents. */
87513498266Sopenharmony_ci      if(!result) {
87613498266Sopenharmony_ci        curl_off_t clen = post->contentslength;
87713498266Sopenharmony_ci
87813498266Sopenharmony_ci        if(post->flags & CURL_HTTPPOST_LARGE)
87913498266Sopenharmony_ci          clen = post->contentlen;
88013498266Sopenharmony_ci
88113498266Sopenharmony_ci        if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
88213498266Sopenharmony_ci          if(!strcmp(file->contents, "-")) {
88313498266Sopenharmony_ci            /* There are a few cases where the code below won't work; in
88413498266Sopenharmony_ci               particular, freopen(stdin) by the caller is not guaranteed
88513498266Sopenharmony_ci               to result as expected. This feature has been kept for backward
88613498266Sopenharmony_ci               compatibility: use of "-" pseudo file name should be avoided. */
88713498266Sopenharmony_ci            result = curl_mime_data_cb(part, (curl_off_t) -1,
88813498266Sopenharmony_ci                                       (curl_read_callback) fread,
88913498266Sopenharmony_ci                                       fseeko_wrapper,
89013498266Sopenharmony_ci                                       NULL, (void *) stdin);
89113498266Sopenharmony_ci          }
89213498266Sopenharmony_ci          else
89313498266Sopenharmony_ci            result = curl_mime_filedata(part, file->contents);
89413498266Sopenharmony_ci          if(!result && (post->flags & HTTPPOST_READFILE))
89513498266Sopenharmony_ci            result = curl_mime_filename(part, NULL);
89613498266Sopenharmony_ci        }
89713498266Sopenharmony_ci        else if(post->flags & HTTPPOST_BUFFER)
89813498266Sopenharmony_ci          result = curl_mime_data(part, post->buffer,
89913498266Sopenharmony_ci                                  post->bufferlength? post->bufferlength: -1);
90013498266Sopenharmony_ci        else if(post->flags & HTTPPOST_CALLBACK) {
90113498266Sopenharmony_ci          /* the contents should be read with the callback and the size is set
90213498266Sopenharmony_ci             with the contentslength */
90313498266Sopenharmony_ci          if(!clen)
90413498266Sopenharmony_ci            clen = -1;
90513498266Sopenharmony_ci          result = curl_mime_data_cb(part, clen,
90613498266Sopenharmony_ci                                     fread_func, NULL, NULL, post->userp);
90713498266Sopenharmony_ci        }
90813498266Sopenharmony_ci        else {
90913498266Sopenharmony_ci          size_t uclen;
91013498266Sopenharmony_ci          if(!clen)
91113498266Sopenharmony_ci            uclen = CURL_ZERO_TERMINATED;
91213498266Sopenharmony_ci          else
91313498266Sopenharmony_ci            uclen = (size_t)clen;
91413498266Sopenharmony_ci          result = curl_mime_data(part, post->contents, uclen);
91513498266Sopenharmony_ci        }
91613498266Sopenharmony_ci      }
91713498266Sopenharmony_ci
91813498266Sopenharmony_ci      /* Set fake file name. */
91913498266Sopenharmony_ci      if(!result && post->showfilename)
92013498266Sopenharmony_ci        if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
92113498266Sopenharmony_ci                                        HTTPPOST_CALLBACK)))
92213498266Sopenharmony_ci          result = curl_mime_filename(part, post->showfilename);
92313498266Sopenharmony_ci    }
92413498266Sopenharmony_ci  }
92513498266Sopenharmony_ci
92613498266Sopenharmony_ci  if(result)
92713498266Sopenharmony_ci    Curl_mime_cleanpart(finalform);
92813498266Sopenharmony_ci
92913498266Sopenharmony_ci  return result;
93013498266Sopenharmony_ci}
93113498266Sopenharmony_ci
93213498266Sopenharmony_ci#else
93313498266Sopenharmony_ci/* if disabled */
93413498266Sopenharmony_ciCURLFORMcode curl_formadd(struct curl_httppost **httppost,
93513498266Sopenharmony_ci                          struct curl_httppost **last_post,
93613498266Sopenharmony_ci                          ...)
93713498266Sopenharmony_ci{
93813498266Sopenharmony_ci  (void)httppost;
93913498266Sopenharmony_ci  (void)last_post;
94013498266Sopenharmony_ci  return CURL_FORMADD_DISABLED;
94113498266Sopenharmony_ci}
94213498266Sopenharmony_ci
94313498266Sopenharmony_ciint curl_formget(struct curl_httppost *form, void *arg,
94413498266Sopenharmony_ci                 curl_formget_callback append)
94513498266Sopenharmony_ci{
94613498266Sopenharmony_ci  (void) form;
94713498266Sopenharmony_ci  (void) arg;
94813498266Sopenharmony_ci  (void) append;
94913498266Sopenharmony_ci  return CURL_FORMADD_DISABLED;
95013498266Sopenharmony_ci}
95113498266Sopenharmony_ci
95213498266Sopenharmony_civoid curl_formfree(struct curl_httppost *form)
95313498266Sopenharmony_ci{
95413498266Sopenharmony_ci  (void)form;
95513498266Sopenharmony_ci  /* Nothing to do. */
95613498266Sopenharmony_ci}
95713498266Sopenharmony_ci
95813498266Sopenharmony_ci#endif  /* if disabled */
959