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