xref: /third_party/curl/lib/formdata.c (revision 13498266)
1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25#include "curl_setup.h"
26
27#include <curl/curl.h>
28
29#include "formdata.h"
30#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
31
32#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
33#include <libgen.h>
34#endif
35
36#include "urldata.h" /* for struct Curl_easy */
37#include "mime.h"
38#include "vtls/vtls.h"
39#include "strcase.h"
40#include "sendf.h"
41#include "strdup.h"
42#include "rand.h"
43#include "warnless.h"
44/* The last 3 #include files should be in this order */
45#include "curl_printf.h"
46#include "curl_memory.h"
47#include "memdebug.h"
48
49
50#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
51#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
52#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
53#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
54#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
55#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
56#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
57
58/***************************************************************************
59 *
60 * AddHttpPost()
61 *
62 * Adds an HttpPost structure to the list, if parent_post is given becomes
63 * a subpost of parent_post instead of a direct list element.
64 *
65 * Returns newly allocated HttpPost on success and NULL if malloc failed.
66 *
67 ***************************************************************************/
68static struct curl_httppost *
69AddHttpPost(char *name, size_t namelength,
70            char *value, curl_off_t contentslength,
71            char *buffer, size_t bufferlength,
72            char *contenttype,
73            long flags,
74            struct curl_slist *contentHeader,
75            char *showfilename, char *userp,
76            struct curl_httppost *parent_post,
77            struct curl_httppost **httppost,
78            struct curl_httppost **last_post)
79{
80  struct curl_httppost *post;
81  if(!namelength && name)
82    namelength = strlen(name);
83  if((bufferlength > LONG_MAX) || (namelength > LONG_MAX))
84    /* avoid overflow in typecasts below */
85    return NULL;
86  post = calloc(1, sizeof(struct curl_httppost));
87  if(post) {
88    post->name = name;
89    post->namelength = (long)namelength;
90    post->contents = value;
91    post->contentlen = contentslength;
92    post->buffer = buffer;
93    post->bufferlength = (long)bufferlength;
94    post->contenttype = contenttype;
95    post->contentheader = contentHeader;
96    post->showfilename = showfilename;
97    post->userp = userp;
98    post->flags = flags | CURL_HTTPPOST_LARGE;
99  }
100  else
101    return NULL;
102
103  if(parent_post) {
104    /* now, point our 'more' to the original 'more' */
105    post->more = parent_post->more;
106
107    /* then move the original 'more' to point to ourselves */
108    parent_post->more = post;
109  }
110  else {
111    /* make the previous point to this */
112    if(*last_post)
113      (*last_post)->next = post;
114    else
115      (*httppost) = post;
116
117    (*last_post) = post;
118  }
119  return post;
120}
121
122/***************************************************************************
123 *
124 * AddFormInfo()
125 *
126 * Adds a FormInfo structure to the list presented by parent_form_info.
127 *
128 * Returns newly allocated FormInfo on success and NULL if malloc failed/
129 * parent_form_info is NULL.
130 *
131 ***************************************************************************/
132static struct FormInfo *AddFormInfo(char *value,
133                                    char *contenttype,
134                                    struct FormInfo *parent_form_info)
135{
136  struct FormInfo *form_info;
137  form_info = calloc(1, sizeof(struct FormInfo));
138  if(!form_info)
139    return NULL;
140  if(value)
141    form_info->value = value;
142  if(contenttype)
143    form_info->contenttype = contenttype;
144  form_info->flags = HTTPPOST_FILENAME;
145
146  if(parent_form_info) {
147    /* now, point our 'more' to the original 'more' */
148    form_info->more = parent_form_info->more;
149
150    /* then move the original 'more' to point to ourselves */
151    parent_form_info->more = form_info;
152  }
153
154  return form_info;
155}
156
157/***************************************************************************
158 *
159 * FormAdd()
160 *
161 * Stores a formpost parameter and builds the appropriate linked list.
162 *
163 * Has two principal functionalities: using files and byte arrays as
164 * post parts. Byte arrays are either copied or just the pointer is stored
165 * (as the user requests) while for files only the filename and not the
166 * content is stored.
167 *
168 * While you may have only one byte array for each name, multiple filenames
169 * are allowed (and because of this feature CURLFORM_END is needed after
170 * using CURLFORM_FILE).
171 *
172 * Examples:
173 *
174 * Simple name/value pair with copied contents:
175 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
176 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
177 *
178 * name/value pair where only the content pointer is remembered:
179 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
180 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
181 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
182 *
183 * storing a filename (CONTENTTYPE is optional!):
184 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
185 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
186 * CURLFORM_END);
187 *
188 * storing multiple filenames:
189 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
190 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
191 *
192 * Returns:
193 * CURL_FORMADD_OK             on success
194 * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
195 * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
196 * CURL_FORMADD_NULL           if a null pointer was given for a char
197 * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
198 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
199 * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
200 * CURL_FORMADD_MEMORY         if an HttpPost struct cannot be allocated
201 * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
202 * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
203 *
204 ***************************************************************************/
205
206static
207CURLFORMcode FormAdd(struct curl_httppost **httppost,
208                     struct curl_httppost **last_post,
209                     va_list params)
210{
211  struct FormInfo *first_form, *current_form, *form = NULL;
212  CURLFORMcode return_value = CURL_FORMADD_OK;
213  const char *prevtype = NULL;
214  struct curl_httppost *post = NULL;
215  CURLformoption option;
216  struct curl_forms *forms = NULL;
217  char *array_value = NULL; /* value read from an array */
218
219  /* This is a state variable, that if TRUE means that we're parsing an
220     array that we got passed to us. If FALSE we're parsing the input
221     va_list arguments. */
222  bool array_state = FALSE;
223
224  /*
225   * We need to allocate the first struct to fill in.
226   */
227  first_form = calloc(1, sizeof(struct FormInfo));
228  if(!first_form)
229    return CURL_FORMADD_MEMORY;
230
231  current_form = first_form;
232
233  /*
234   * Loop through all the options set. Break if we have an error to report.
235   */
236  while(return_value == CURL_FORMADD_OK) {
237
238    /* first see if we have more parts of the array param */
239    if(array_state && forms) {
240      /* get the upcoming option from the given array */
241      option = forms->option;
242      array_value = (char *)forms->value;
243
244      forms++; /* advance this to next entry */
245      if(CURLFORM_END == option) {
246        /* end of array state */
247        array_state = FALSE;
248        continue;
249      }
250    }
251    else {
252      /* This is not array-state, get next option. This gets an 'int' with
253         va_arg() because CURLformoption might be a smaller type than int and
254         might cause compiler warnings and wrong behavior. */
255      option = (CURLformoption)va_arg(params, int);
256      if(CURLFORM_END == option)
257        break;
258    }
259
260    switch(option) {
261    case CURLFORM_ARRAY:
262      if(array_state)
263        /* we don't support an array from within an array */
264        return_value = CURL_FORMADD_ILLEGAL_ARRAY;
265      else {
266        forms = va_arg(params, struct curl_forms *);
267        if(forms)
268          array_state = TRUE;
269        else
270          return_value = CURL_FORMADD_NULL;
271      }
272      break;
273
274      /*
275       * Set the Name property.
276       */
277    case CURLFORM_PTRNAME:
278      current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
279
280      FALLTHROUGH();
281    case CURLFORM_COPYNAME:
282      if(current_form->name)
283        return_value = CURL_FORMADD_OPTION_TWICE;
284      else {
285        char *name = array_state?
286          array_value:va_arg(params, char *);
287        if(name)
288          current_form->name = name; /* store for the moment */
289        else
290          return_value = CURL_FORMADD_NULL;
291      }
292      break;
293    case CURLFORM_NAMELENGTH:
294      if(current_form->namelength)
295        return_value = CURL_FORMADD_OPTION_TWICE;
296      else
297        current_form->namelength =
298          array_state?(size_t)array_value:(size_t)va_arg(params, long);
299      break;
300
301      /*
302       * Set the contents property.
303       */
304    case CURLFORM_PTRCONTENTS:
305      current_form->flags |= HTTPPOST_PTRCONTENTS;
306      FALLTHROUGH();
307    case CURLFORM_COPYCONTENTS:
308      if(current_form->value)
309        return_value = CURL_FORMADD_OPTION_TWICE;
310      else {
311        char *value =
312          array_state?array_value:va_arg(params, char *);
313        if(value)
314          current_form->value = value; /* store for the moment */
315        else
316          return_value = CURL_FORMADD_NULL;
317      }
318      break;
319    case CURLFORM_CONTENTSLENGTH:
320      current_form->contentslength =
321        array_state?(size_t)array_value:(size_t)va_arg(params, long);
322      break;
323
324    case CURLFORM_CONTENTLEN:
325      current_form->flags |= CURL_HTTPPOST_LARGE;
326      current_form->contentslength =
327        array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
328      break;
329
330      /* Get contents from a given file name */
331    case CURLFORM_FILECONTENT:
332      if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
333        return_value = CURL_FORMADD_OPTION_TWICE;
334      else {
335        const char *filename = array_state?
336          array_value:va_arg(params, char *);
337        if(filename) {
338          current_form->value = strdup(filename);
339          if(!current_form->value)
340            return_value = CURL_FORMADD_MEMORY;
341          else {
342            current_form->flags |= HTTPPOST_READFILE;
343            current_form->value_alloc = TRUE;
344          }
345        }
346        else
347          return_value = CURL_FORMADD_NULL;
348      }
349      break;
350
351      /* We upload a file */
352    case CURLFORM_FILE:
353      {
354        const char *filename = array_state?array_value:
355          va_arg(params, char *);
356
357        if(current_form->value) {
358          if(current_form->flags & HTTPPOST_FILENAME) {
359            if(filename) {
360              char *fname = strdup(filename);
361              if(!fname)
362                return_value = CURL_FORMADD_MEMORY;
363              else {
364                form = AddFormInfo(fname, NULL, current_form);
365                if(!form) {
366                  free(fname);
367                  return_value = CURL_FORMADD_MEMORY;
368                }
369                else {
370                  form->value_alloc = TRUE;
371                  current_form = form;
372                  form = NULL;
373                }
374              }
375            }
376            else
377              return_value = CURL_FORMADD_NULL;
378          }
379          else
380            return_value = CURL_FORMADD_OPTION_TWICE;
381        }
382        else {
383          if(filename) {
384            current_form->value = strdup(filename);
385            if(!current_form->value)
386              return_value = CURL_FORMADD_MEMORY;
387            else {
388              current_form->flags |= HTTPPOST_FILENAME;
389              current_form->value_alloc = TRUE;
390            }
391          }
392          else
393            return_value = CURL_FORMADD_NULL;
394        }
395        break;
396      }
397
398    case CURLFORM_BUFFERPTR:
399      current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
400      if(current_form->buffer)
401        return_value = CURL_FORMADD_OPTION_TWICE;
402      else {
403        char *buffer =
404          array_state?array_value:va_arg(params, char *);
405        if(buffer) {
406          current_form->buffer = buffer; /* store for the moment */
407          current_form->value = buffer; /* make it non-NULL to be accepted
408                                           as fine */
409        }
410        else
411          return_value = CURL_FORMADD_NULL;
412      }
413      break;
414
415    case CURLFORM_BUFFERLENGTH:
416      if(current_form->bufferlength)
417        return_value = CURL_FORMADD_OPTION_TWICE;
418      else
419        current_form->bufferlength =
420          array_state?(size_t)array_value:(size_t)va_arg(params, long);
421      break;
422
423    case CURLFORM_STREAM:
424      current_form->flags |= HTTPPOST_CALLBACK;
425      if(current_form->userp)
426        return_value = CURL_FORMADD_OPTION_TWICE;
427      else {
428        char *userp =
429          array_state?array_value:va_arg(params, char *);
430        if(userp) {
431          current_form->userp = userp;
432          current_form->value = userp; /* this isn't strictly true but we
433                                          derive a value from this later on
434                                          and we need this non-NULL to be
435                                          accepted as a fine form part */
436        }
437        else
438          return_value = CURL_FORMADD_NULL;
439      }
440      break;
441
442    case CURLFORM_CONTENTTYPE:
443      {
444        const char *contenttype =
445          array_state?array_value:va_arg(params, char *);
446        if(current_form->contenttype) {
447          if(current_form->flags & HTTPPOST_FILENAME) {
448            if(contenttype) {
449              char *type = strdup(contenttype);
450              if(!type)
451                return_value = CURL_FORMADD_MEMORY;
452              else {
453                form = AddFormInfo(NULL, type, current_form);
454                if(!form) {
455                  free(type);
456                  return_value = CURL_FORMADD_MEMORY;
457                }
458                else {
459                  form->contenttype_alloc = TRUE;
460                  current_form = form;
461                  form = NULL;
462                }
463              }
464            }
465            else
466              return_value = CURL_FORMADD_NULL;
467          }
468          else
469            return_value = CURL_FORMADD_OPTION_TWICE;
470        }
471        else {
472          if(contenttype) {
473            current_form->contenttype = strdup(contenttype);
474            if(!current_form->contenttype)
475              return_value = CURL_FORMADD_MEMORY;
476            else
477              current_form->contenttype_alloc = TRUE;
478          }
479          else
480            return_value = CURL_FORMADD_NULL;
481        }
482        break;
483      }
484    case CURLFORM_CONTENTHEADER:
485      {
486        /* this "cast increases required alignment of target type" but
487           we consider it OK anyway */
488        struct curl_slist *list = array_state?
489          (struct curl_slist *)(void *)array_value:
490          va_arg(params, struct curl_slist *);
491
492        if(current_form->contentheader)
493          return_value = CURL_FORMADD_OPTION_TWICE;
494        else
495          current_form->contentheader = list;
496
497        break;
498      }
499    case CURLFORM_FILENAME:
500    case CURLFORM_BUFFER:
501      {
502        const char *filename = array_state?array_value:
503          va_arg(params, char *);
504        if(current_form->showfilename)
505          return_value = CURL_FORMADD_OPTION_TWICE;
506        else {
507          current_form->showfilename = strdup(filename);
508          if(!current_form->showfilename)
509            return_value = CURL_FORMADD_MEMORY;
510          else
511            current_form->showfilename_alloc = TRUE;
512        }
513        break;
514      }
515    default:
516      return_value = CURL_FORMADD_UNKNOWN_OPTION;
517      break;
518    }
519  }
520
521  if(CURL_FORMADD_OK != return_value) {
522    /* On error, free allocated fields for all nodes of the FormInfo linked
523       list without deallocating nodes. List nodes are deallocated later on */
524    struct FormInfo *ptr;
525    for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
526      if(ptr->name_alloc) {
527        Curl_safefree(ptr->name);
528        ptr->name_alloc = FALSE;
529      }
530      if(ptr->value_alloc) {
531        Curl_safefree(ptr->value);
532        ptr->value_alloc = FALSE;
533      }
534      if(ptr->contenttype_alloc) {
535        Curl_safefree(ptr->contenttype);
536        ptr->contenttype_alloc = FALSE;
537      }
538      if(ptr->showfilename_alloc) {
539        Curl_safefree(ptr->showfilename);
540        ptr->showfilename_alloc = FALSE;
541      }
542    }
543  }
544
545  if(CURL_FORMADD_OK == return_value) {
546    /* go through the list, check for completeness and if everything is
547     * alright add the HttpPost item otherwise set return_value accordingly */
548
549    post = NULL;
550    for(form = first_form;
551        form != NULL;
552        form = form->more) {
553      if(((!form->name || !form->value) && !post) ||
554         ( (form->contentslength) &&
555           (form->flags & HTTPPOST_FILENAME) ) ||
556         ( (form->flags & HTTPPOST_FILENAME) &&
557           (form->flags & HTTPPOST_PTRCONTENTS) ) ||
558
559         ( (!form->buffer) &&
560           (form->flags & HTTPPOST_BUFFER) &&
561           (form->flags & HTTPPOST_PTRBUFFER) ) ||
562
563         ( (form->flags & HTTPPOST_READFILE) &&
564           (form->flags & HTTPPOST_PTRCONTENTS) )
565        ) {
566        return_value = CURL_FORMADD_INCOMPLETE;
567        break;
568      }
569      if(((form->flags & HTTPPOST_FILENAME) ||
570          (form->flags & HTTPPOST_BUFFER)) &&
571         !form->contenttype) {
572        char *f = (form->flags & HTTPPOST_BUFFER)?
573          form->showfilename : form->value;
574        char const *type;
575        type = Curl_mime_contenttype(f);
576        if(!type)
577          type = prevtype;
578        if(!type)
579          type = FILE_CONTENTTYPE_DEFAULT;
580
581        /* our contenttype is missing */
582        form->contenttype = strdup(type);
583        if(!form->contenttype) {
584          return_value = CURL_FORMADD_MEMORY;
585          break;
586        }
587        form->contenttype_alloc = TRUE;
588      }
589      if(form->name && form->namelength) {
590        /* Name should not contain nul bytes. */
591        size_t i;
592        for(i = 0; i < form->namelength; i++)
593          if(!form->name[i]) {
594            return_value = CURL_FORMADD_NULL;
595            break;
596          }
597        if(return_value != CURL_FORMADD_OK)
598          break;
599      }
600      if(!(form->flags & HTTPPOST_PTRNAME) &&
601         (form == first_form) ) {
602        /* Note that there's small risk that form->name is NULL here if the
603           app passed in a bad combo, so we better check for that first. */
604        if(form->name) {
605          /* copy name (without strdup; possibly not null-terminated) */
606          form->name = Curl_memdup0(form->name, form->namelength?
607                                    form->namelength:
608                                    strlen(form->name));
609        }
610        if(!form->name) {
611          return_value = CURL_FORMADD_MEMORY;
612          break;
613        }
614        form->name_alloc = TRUE;
615      }
616      if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
617                          HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
618                          HTTPPOST_CALLBACK)) && form->value) {
619        /* copy value (without strdup; possibly contains null characters) */
620        size_t clen  = (size_t) form->contentslength;
621        if(!clen)
622          clen = strlen(form->value) + 1;
623
624        form->value = Curl_memdup(form->value, clen);
625
626        if(!form->value) {
627          return_value = CURL_FORMADD_MEMORY;
628          break;
629        }
630        form->value_alloc = TRUE;
631      }
632      post = AddHttpPost(form->name, form->namelength,
633                         form->value, form->contentslength,
634                         form->buffer, form->bufferlength,
635                         form->contenttype, form->flags,
636                         form->contentheader, form->showfilename,
637                         form->userp,
638                         post, httppost,
639                         last_post);
640
641      if(!post) {
642        return_value = CURL_FORMADD_MEMORY;
643        break;
644      }
645
646      if(form->contenttype)
647        prevtype = form->contenttype;
648    }
649    if(CURL_FORMADD_OK != return_value) {
650      /* On error, free allocated fields for nodes of the FormInfo linked
651         list which are not already owned by the httppost linked list
652         without deallocating nodes. List nodes are deallocated later on */
653      struct FormInfo *ptr;
654      for(ptr = form; ptr != NULL; ptr = ptr->more) {
655        if(ptr->name_alloc) {
656          Curl_safefree(ptr->name);
657          ptr->name_alloc = FALSE;
658        }
659        if(ptr->value_alloc) {
660          Curl_safefree(ptr->value);
661          ptr->value_alloc = FALSE;
662        }
663        if(ptr->contenttype_alloc) {
664          Curl_safefree(ptr->contenttype);
665          ptr->contenttype_alloc = FALSE;
666        }
667        if(ptr->showfilename_alloc) {
668          Curl_safefree(ptr->showfilename);
669          ptr->showfilename_alloc = FALSE;
670        }
671      }
672    }
673  }
674
675  /* Always deallocate FormInfo linked list nodes without touching node
676     fields given that these have either been deallocated or are owned
677     now by the httppost linked list */
678  while(first_form) {
679    struct FormInfo *ptr = first_form->more;
680    free(first_form);
681    first_form = ptr;
682  }
683
684  return return_value;
685}
686
687/*
688 * curl_formadd() is a public API to add a section to the multipart formpost.
689 *
690 * @unittest: 1308
691 */
692
693CURLFORMcode curl_formadd(struct curl_httppost **httppost,
694                          struct curl_httppost **last_post,
695                          ...)
696{
697  va_list arg;
698  CURLFORMcode result;
699  va_start(arg, last_post);
700  result = FormAdd(httppost, last_post, arg);
701  va_end(arg);
702  return result;
703}
704
705/*
706 * curl_formget()
707 * Serialize a curl_httppost struct.
708 * Returns 0 on success.
709 *
710 * @unittest: 1308
711 */
712int curl_formget(struct curl_httppost *form, void *arg,
713                 curl_formget_callback append)
714{
715  CURLcode result;
716  curl_mimepart toppart;
717
718  Curl_mime_initpart(&toppart); /* default form is empty */
719  result = Curl_getformdata(NULL, &toppart, form, NULL);
720  if(!result)
721    result = Curl_mime_prepare_headers(NULL, &toppart, "multipart/form-data",
722                                       NULL, MIMESTRATEGY_FORM);
723
724  while(!result) {
725    char buffer[8192];
726    size_t nread = Curl_mime_read(buffer, 1, sizeof(buffer), &toppart);
727
728    if(!nread)
729      break;
730
731    if(nread > sizeof(buffer) || append(arg, buffer, nread) != nread) {
732      result = CURLE_READ_ERROR;
733      if(nread == CURL_READFUNC_ABORT)
734        result = CURLE_ABORTED_BY_CALLBACK;
735    }
736  }
737
738  Curl_mime_cleanpart(&toppart);
739  return (int) result;
740}
741
742/*
743 * curl_formfree() is an external function to free up a whole form post
744 * chain
745 */
746void curl_formfree(struct curl_httppost *form)
747{
748  struct curl_httppost *next;
749
750  if(!form)
751    /* no form to free, just get out of this */
752    return;
753
754  do {
755    next = form->next;  /* the following form line */
756
757    /* recurse to sub-contents */
758    curl_formfree(form->more);
759
760    if(!(form->flags & HTTPPOST_PTRNAME))
761      free(form->name); /* free the name */
762    if(!(form->flags &
763         (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
764      )
765      free(form->contents); /* free the contents */
766    free(form->contenttype); /* free the content type */
767    free(form->showfilename); /* free the faked file name */
768    free(form);       /* free the struct */
769    form = next;
770  } while(form); /* continue */
771}
772
773
774/* Set mime part name, taking care of non null-terminated name string. */
775static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
776{
777  char *zname;
778  CURLcode res;
779
780  if(!name || !len)
781    return curl_mime_name(part, name);
782  zname = Curl_memdup0(name, len);
783  if(!zname)
784    return CURLE_OUT_OF_MEMORY;
785  res = curl_mime_name(part, zname);
786  free(zname);
787  return res;
788}
789
790/* wrap call to fseeko so it matches the calling convention of callback */
791static int fseeko_wrapper(void *stream, curl_off_t offset, int whence)
792{
793#if defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO)
794  return fseeko(stream, (off_t)offset, whence);
795#elif defined(HAVE__FSEEKI64)
796  return _fseeki64(stream, (__int64)offset, whence);
797#else
798  if(offset > LONG_MAX)
799    return -1;
800  return fseek(stream, (long)offset, whence);
801#endif
802}
803
804/*
805 * Curl_getformdata() converts a linked list of "meta data" into a mime
806 * structure. The input list is in 'post', while the output is stored in
807 * mime part at '*finalform'.
808 *
809 * This function will not do a failf() for the potential memory failures but
810 * should for all other errors it spots. Just note that this function MAY get
811 * a NULL pointer in the 'data' argument.
812 */
813
814CURLcode Curl_getformdata(struct Curl_easy *data,
815                          curl_mimepart *finalform,
816                          struct curl_httppost *post,
817                          curl_read_callback fread_func)
818{
819  CURLcode result = CURLE_OK;
820  curl_mime *form = NULL;
821  curl_mimepart *part;
822  struct curl_httppost *file;
823
824  Curl_mime_cleanpart(finalform); /* default form is empty */
825
826  if(!post)
827    return result; /* no input => no output! */
828
829  form = curl_mime_init(data);
830  if(!form)
831    result = CURLE_OUT_OF_MEMORY;
832
833  if(!result)
834    result = curl_mime_subparts(finalform, form);
835
836  /* Process each top part. */
837  for(; !result && post; post = post->next) {
838    /* If we have more than a file here, create a mime subpart and fill it. */
839    curl_mime *multipart = form;
840    if(post->more) {
841      part = curl_mime_addpart(form);
842      if(!part)
843        result = CURLE_OUT_OF_MEMORY;
844      if(!result)
845        result = setname(part, post->name, post->namelength);
846      if(!result) {
847        multipart = curl_mime_init(data);
848        if(!multipart)
849          result = CURLE_OUT_OF_MEMORY;
850      }
851      if(!result)
852        result = curl_mime_subparts(part, multipart);
853    }
854
855    /* Generate all the part contents. */
856    for(file = post; !result && file; file = file->more) {
857      /* Create the part. */
858      part = curl_mime_addpart(multipart);
859      if(!part)
860        result = CURLE_OUT_OF_MEMORY;
861
862      /* Set the headers. */
863      if(!result)
864        result = curl_mime_headers(part, file->contentheader, 0);
865
866      /* Set the content type. */
867      if(!result && file->contenttype)
868        result = curl_mime_type(part, file->contenttype);
869
870      /* Set field name. */
871      if(!result && !post->more)
872        result = setname(part, post->name, post->namelength);
873
874      /* Process contents. */
875      if(!result) {
876        curl_off_t clen = post->contentslength;
877
878        if(post->flags & CURL_HTTPPOST_LARGE)
879          clen = post->contentlen;
880
881        if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
882          if(!strcmp(file->contents, "-")) {
883            /* There are a few cases where the code below won't work; in
884               particular, freopen(stdin) by the caller is not guaranteed
885               to result as expected. This feature has been kept for backward
886               compatibility: use of "-" pseudo file name should be avoided. */
887            result = curl_mime_data_cb(part, (curl_off_t) -1,
888                                       (curl_read_callback) fread,
889                                       fseeko_wrapper,
890                                       NULL, (void *) stdin);
891          }
892          else
893            result = curl_mime_filedata(part, file->contents);
894          if(!result && (post->flags & HTTPPOST_READFILE))
895            result = curl_mime_filename(part, NULL);
896        }
897        else if(post->flags & HTTPPOST_BUFFER)
898          result = curl_mime_data(part, post->buffer,
899                                  post->bufferlength? post->bufferlength: -1);
900        else if(post->flags & HTTPPOST_CALLBACK) {
901          /* the contents should be read with the callback and the size is set
902             with the contentslength */
903          if(!clen)
904            clen = -1;
905          result = curl_mime_data_cb(part, clen,
906                                     fread_func, NULL, NULL, post->userp);
907        }
908        else {
909          size_t uclen;
910          if(!clen)
911            uclen = CURL_ZERO_TERMINATED;
912          else
913            uclen = (size_t)clen;
914          result = curl_mime_data(part, post->contents, uclen);
915        }
916      }
917
918      /* Set fake file name. */
919      if(!result && post->showfilename)
920        if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
921                                        HTTPPOST_CALLBACK)))
922          result = curl_mime_filename(part, post->showfilename);
923    }
924  }
925
926  if(result)
927    Curl_mime_cleanpart(finalform);
928
929  return result;
930}
931
932#else
933/* if disabled */
934CURLFORMcode curl_formadd(struct curl_httppost **httppost,
935                          struct curl_httppost **last_post,
936                          ...)
937{
938  (void)httppost;
939  (void)last_post;
940  return CURL_FORMADD_DISABLED;
941}
942
943int curl_formget(struct curl_httppost *form, void *arg,
944                 curl_formget_callback append)
945{
946  (void) form;
947  (void) arg;
948  (void) append;
949  return CURL_FORMADD_DISABLED;
950}
951
952void curl_formfree(struct curl_httppost *form)
953{
954  (void)form;
955  /* Nothing to do. */
956}
957
958#endif  /* if disabled */
959