xref: /curl/lib/formdata.c (revision fbf5d507)
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  ***************************************************************************/
68 static struct curl_httppost *
AddHttpPost(char * name,size_t namelength,char * value,curl_off_t contentslength,char * buffer,size_t bufferlength,char * contenttype,long flags,struct curl_slist * contentHeader,char * showfilename,char * userp,struct curl_httppost * parent_post,struct curl_httppost ** httppost,struct curl_httppost ** last_post)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  ***************************************************************************/
AddFormInfo(char * value,char * contenttype,struct FormInfo * parent_form_info)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     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 
206 static
FormAdd(struct curl_httppost ** httppost,struct curl_httppost ** last_post,va_list params)207 CURLFORMcode 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 are parsing an
220      array that we got passed to us. If FALSE we are 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 do not 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 :
328         va_arg(params, curl_off_t);
329       break;
330 
331       /* Get contents from a given filename */
332     case CURLFORM_FILECONTENT:
333       if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
334         return_value = CURL_FORMADD_OPTION_TWICE;
335       else {
336         const char *filename = array_state ?
337           array_value : va_arg(params, char *);
338         if(filename) {
339           current_form->value = strdup(filename);
340           if(!current_form->value)
341             return_value = CURL_FORMADD_MEMORY;
342           else {
343             current_form->flags |= HTTPPOST_READFILE;
344             current_form->value_alloc = TRUE;
345           }
346         }
347         else
348           return_value = CURL_FORMADD_NULL;
349       }
350       break;
351 
352       /* We upload a file */
353     case CURLFORM_FILE:
354       {
355         const char *filename = array_state ? array_value :
356           va_arg(params, char *);
357 
358         if(current_form->value) {
359           if(current_form->flags & HTTPPOST_FILENAME) {
360             if(filename) {
361               char *fname = strdup(filename);
362               if(!fname)
363                 return_value = CURL_FORMADD_MEMORY;
364               else {
365                 form = AddFormInfo(fname, NULL, current_form);
366                 if(!form) {
367                   free(fname);
368                   return_value = CURL_FORMADD_MEMORY;
369                 }
370                 else {
371                   form->value_alloc = TRUE;
372                   current_form = form;
373                   form = NULL;
374                 }
375               }
376             }
377             else
378               return_value = CURL_FORMADD_NULL;
379           }
380           else
381             return_value = CURL_FORMADD_OPTION_TWICE;
382         }
383         else {
384           if(filename) {
385             current_form->value = strdup(filename);
386             if(!current_form->value)
387               return_value = CURL_FORMADD_MEMORY;
388             else {
389               current_form->flags |= HTTPPOST_FILENAME;
390               current_form->value_alloc = TRUE;
391             }
392           }
393           else
394             return_value = CURL_FORMADD_NULL;
395         }
396         break;
397       }
398 
399     case CURLFORM_BUFFERPTR:
400       current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
401       if(current_form->buffer)
402         return_value = CURL_FORMADD_OPTION_TWICE;
403       else {
404         char *buffer =
405           array_state ? array_value : va_arg(params, char *);
406         if(buffer) {
407           current_form->buffer = buffer; /* store for the moment */
408           current_form->value = buffer; /* make it non-NULL to be accepted
409                                            as fine */
410         }
411         else
412           return_value = CURL_FORMADD_NULL;
413       }
414       break;
415 
416     case CURLFORM_BUFFERLENGTH:
417       if(current_form->bufferlength)
418         return_value = CURL_FORMADD_OPTION_TWICE;
419       else
420         current_form->bufferlength =
421           array_state ? (size_t)array_value : (size_t)va_arg(params, long);
422       break;
423 
424     case CURLFORM_STREAM:
425       current_form->flags |= HTTPPOST_CALLBACK;
426       if(current_form->userp)
427         return_value = CURL_FORMADD_OPTION_TWICE;
428       else {
429         char *userp =
430           array_state ? array_value : va_arg(params, char *);
431         if(userp) {
432           current_form->userp = userp;
433           current_form->value = userp; /* this is not strictly true but we
434                                           derive a value from this later on
435                                           and we need this non-NULL to be
436                                           accepted as a fine form part */
437         }
438         else
439           return_value = CURL_FORMADD_NULL;
440       }
441       break;
442 
443     case CURLFORM_CONTENTTYPE:
444       {
445         const char *contenttype =
446           array_state ? array_value : va_arg(params, char *);
447         if(current_form->contenttype) {
448           if(current_form->flags & HTTPPOST_FILENAME) {
449             if(contenttype) {
450               char *type = strdup(contenttype);
451               if(!type)
452                 return_value = CURL_FORMADD_MEMORY;
453               else {
454                 form = AddFormInfo(NULL, type, current_form);
455                 if(!form) {
456                   free(type);
457                   return_value = CURL_FORMADD_MEMORY;
458                 }
459                 else {
460                   form->contenttype_alloc = TRUE;
461                   current_form = form;
462                   form = NULL;
463                 }
464               }
465             }
466             else
467               return_value = CURL_FORMADD_NULL;
468           }
469           else
470             return_value = CURL_FORMADD_OPTION_TWICE;
471         }
472         else {
473           if(contenttype) {
474             current_form->contenttype = strdup(contenttype);
475             if(!current_form->contenttype)
476               return_value = CURL_FORMADD_MEMORY;
477             else
478               current_form->contenttype_alloc = TRUE;
479           }
480           else
481             return_value = CURL_FORMADD_NULL;
482         }
483         break;
484       }
485     case CURLFORM_CONTENTHEADER:
486       {
487         /* this "cast increases required alignment of target type" but
488            we consider it OK anyway */
489         struct curl_slist *list = array_state ?
490           (struct curl_slist *)(void *)array_value :
491           va_arg(params, struct curl_slist *);
492 
493         if(current_form->contentheader)
494           return_value = CURL_FORMADD_OPTION_TWICE;
495         else
496           current_form->contentheader = list;
497 
498         break;
499       }
500     case CURLFORM_FILENAME:
501     case CURLFORM_BUFFER:
502       {
503         const char *filename = array_state ? array_value :
504           va_arg(params, char *);
505         if(current_form->showfilename)
506           return_value = CURL_FORMADD_OPTION_TWICE;
507         else {
508           current_form->showfilename = strdup(filename);
509           if(!current_form->showfilename)
510             return_value = CURL_FORMADD_MEMORY;
511           else
512             current_form->showfilename_alloc = TRUE;
513         }
514         break;
515       }
516     default:
517       return_value = CURL_FORMADD_UNKNOWN_OPTION;
518       break;
519     }
520   }
521 
522   if(CURL_FORMADD_OK != return_value) {
523     /* On error, free allocated fields for all nodes of the FormInfo linked
524        list without deallocating nodes. List nodes are deallocated later on */
525     struct FormInfo *ptr;
526     for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
527       if(ptr->name_alloc) {
528         Curl_safefree(ptr->name);
529         ptr->name_alloc = FALSE;
530       }
531       if(ptr->value_alloc) {
532         Curl_safefree(ptr->value);
533         ptr->value_alloc = FALSE;
534       }
535       if(ptr->contenttype_alloc) {
536         Curl_safefree(ptr->contenttype);
537         ptr->contenttype_alloc = FALSE;
538       }
539       if(ptr->showfilename_alloc) {
540         Curl_safefree(ptr->showfilename);
541         ptr->showfilename_alloc = FALSE;
542       }
543     }
544   }
545 
546   if(CURL_FORMADD_OK == return_value) {
547     /* go through the list, check for completeness and if everything is
548      * alright add the HttpPost item otherwise set return_value accordingly */
549 
550     post = NULL;
551     for(form = first_form;
552         form != NULL;
553         form = form->more) {
554       if(((!form->name || !form->value) && !post) ||
555          ( (form->contentslength) &&
556            (form->flags & HTTPPOST_FILENAME) ) ||
557          ( (form->flags & HTTPPOST_FILENAME) &&
558            (form->flags & HTTPPOST_PTRCONTENTS) ) ||
559 
560          ( (!form->buffer) &&
561            (form->flags & HTTPPOST_BUFFER) &&
562            (form->flags & HTTPPOST_PTRBUFFER) ) ||
563 
564          ( (form->flags & HTTPPOST_READFILE) &&
565            (form->flags & HTTPPOST_PTRCONTENTS) )
566         ) {
567         return_value = CURL_FORMADD_INCOMPLETE;
568         break;
569       }
570       if(((form->flags & HTTPPOST_FILENAME) ||
571           (form->flags & HTTPPOST_BUFFER)) &&
572          !form->contenttype) {
573         char *f = (form->flags & HTTPPOST_BUFFER) ?
574           form->showfilename : form->value;
575         char const *type;
576         type = Curl_mime_contenttype(f);
577         if(!type)
578           type = prevtype;
579         if(!type)
580           type = FILE_CONTENTTYPE_DEFAULT;
581 
582         /* our contenttype is missing */
583         form->contenttype = strdup(type);
584         if(!form->contenttype) {
585           return_value = CURL_FORMADD_MEMORY;
586           break;
587         }
588         form->contenttype_alloc = TRUE;
589       }
590       if(form->name && form->namelength) {
591         /* Name should not contain nul bytes. */
592         size_t i;
593         for(i = 0; i < form->namelength; i++)
594           if(!form->name[i]) {
595             return_value = CURL_FORMADD_NULL;
596             break;
597           }
598         if(return_value != CURL_FORMADD_OK)
599           break;
600       }
601       if(!(form->flags & HTTPPOST_PTRNAME) &&
602          (form == first_form) ) {
603         /* Note that there is small risk that form->name is NULL here if the
604            app passed in a bad combo, so we better check for that first. */
605         if(form->name) {
606           /* copy name (without strdup; possibly not null-terminated) */
607           form->name = Curl_memdup0(form->name, form->namelength ?
608                                     form->namelength :
609                                     strlen(form->name));
610         }
611         if(!form->name) {
612           return_value = CURL_FORMADD_MEMORY;
613           break;
614         }
615         form->name_alloc = TRUE;
616       }
617       if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
618                           HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
619                           HTTPPOST_CALLBACK)) && form->value) {
620         /* copy value (without strdup; possibly contains null characters) */
621         size_t clen  = (size_t) form->contentslength;
622         if(!clen)
623           clen = strlen(form->value) + 1;
624 
625         form->value = Curl_memdup(form->value, clen);
626 
627         if(!form->value) {
628           return_value = CURL_FORMADD_MEMORY;
629           break;
630         }
631         form->value_alloc = TRUE;
632       }
633       post = AddHttpPost(form->name, form->namelength,
634                          form->value, form->contentslength,
635                          form->buffer, form->bufferlength,
636                          form->contenttype, form->flags,
637                          form->contentheader, form->showfilename,
638                          form->userp,
639                          post, httppost,
640                          last_post);
641 
642       if(!post) {
643         return_value = CURL_FORMADD_MEMORY;
644         break;
645       }
646 
647       if(form->contenttype)
648         prevtype = form->contenttype;
649     }
650     if(CURL_FORMADD_OK != return_value) {
651       /* On error, free allocated fields for nodes of the FormInfo linked
652          list which are not already owned by the httppost linked list
653          without deallocating nodes. List nodes are deallocated later on */
654       struct FormInfo *ptr;
655       for(ptr = form; ptr != NULL; ptr = ptr->more) {
656         if(ptr->name_alloc) {
657           Curl_safefree(ptr->name);
658           ptr->name_alloc = FALSE;
659         }
660         if(ptr->value_alloc) {
661           Curl_safefree(ptr->value);
662           ptr->value_alloc = FALSE;
663         }
664         if(ptr->contenttype_alloc) {
665           Curl_safefree(ptr->contenttype);
666           ptr->contenttype_alloc = FALSE;
667         }
668         if(ptr->showfilename_alloc) {
669           Curl_safefree(ptr->showfilename);
670           ptr->showfilename_alloc = FALSE;
671         }
672       }
673     }
674   }
675 
676   /* Always deallocate FormInfo linked list nodes without touching node
677      fields given that these have either been deallocated or are owned
678      now by the httppost linked list */
679   while(first_form) {
680     struct FormInfo *ptr = first_form->more;
681     free(first_form);
682     first_form = ptr;
683   }
684 
685   return return_value;
686 }
687 
688 /*
689  * curl_formadd() is a public API to add a section to the multipart formpost.
690  *
691  * @unittest: 1308
692  */
693 
curl_formadd(struct curl_httppost ** httppost,struct curl_httppost ** last_post,...)694 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
695                           struct curl_httppost **last_post,
696                           ...)
697 {
698   va_list arg;
699   CURLFORMcode result;
700   va_start(arg, last_post);
701   result = FormAdd(httppost, last_post, arg);
702   va_end(arg);
703   return result;
704 }
705 
706 /*
707  * curl_formget()
708  * Serialize a curl_httppost struct.
709  * Returns 0 on success.
710  *
711  * @unittest: 1308
712  */
curl_formget(struct curl_httppost * form,void * arg,curl_formget_callback append)713 int curl_formget(struct curl_httppost *form, void *arg,
714                  curl_formget_callback append)
715 {
716   CURLcode result;
717   curl_mimepart toppart;
718 
719   Curl_mime_initpart(&toppart); /* default form is empty */
720   result = Curl_getformdata(NULL, &toppart, form, NULL);
721   if(!result)
722     result = Curl_mime_prepare_headers(NULL, &toppart, "multipart/form-data",
723                                        NULL, MIMESTRATEGY_FORM);
724 
725   while(!result) {
726     char buffer[8192];
727     size_t nread = Curl_mime_read(buffer, 1, sizeof(buffer), &toppart);
728 
729     if(!nread)
730       break;
731 
732     if(nread > sizeof(buffer) || append(arg, buffer, nread) != nread) {
733       result = CURLE_READ_ERROR;
734       if(nread == CURL_READFUNC_ABORT)
735         result = CURLE_ABORTED_BY_CALLBACK;
736     }
737   }
738 
739   Curl_mime_cleanpart(&toppart);
740   return (int) result;
741 }
742 
743 /*
744  * curl_formfree() is an external function to free up a whole form post
745  * chain
746  */
curl_formfree(struct curl_httppost * form)747 void curl_formfree(struct curl_httppost *form)
748 {
749   struct curl_httppost *next;
750 
751   if(!form)
752     /* no form to free, just get out of this */
753     return;
754 
755   do {
756     next = form->next;  /* the following form line */
757 
758     /* recurse to sub-contents */
759     curl_formfree(form->more);
760 
761     if(!(form->flags & HTTPPOST_PTRNAME))
762       free(form->name); /* free the name */
763     if(!(form->flags &
764          (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
765       )
766       free(form->contents); /* free the contents */
767     free(form->contenttype); /* free the content type */
768     free(form->showfilename); /* free the faked filename */
769     free(form);       /* free the struct */
770     form = next;
771   } while(form); /* continue */
772 }
773 
774 
775 /* Set mime part name, taking care of non null-terminated name string. */
setname(curl_mimepart * part,const char * name,size_t len)776 static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
777 {
778   char *zname;
779   CURLcode res;
780 
781   if(!name || !len)
782     return curl_mime_name(part, name);
783   zname = Curl_memdup0(name, len);
784   if(!zname)
785     return CURLE_OUT_OF_MEMORY;
786   res = curl_mime_name(part, zname);
787   free(zname);
788   return res;
789 }
790 
791 /* wrap call to fseeko so it matches the calling convention of callback */
fseeko_wrapper(void * stream,curl_off_t offset,int whence)792 static int fseeko_wrapper(void *stream, curl_off_t offset, int whence)
793 {
794 #if defined(HAVE__FSEEKI64)
795   return _fseeki64(stream, (__int64)offset, whence);
796 #elif defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO)
797   return fseeko(stream, (off_t)offset, whence);
798 #else
799   if(offset > LONG_MAX)
800     return -1;
801   return fseek(stream, (long)offset, whence);
802 #endif
803 }
804 
805 /*
806  * Curl_getformdata() converts a linked list of "meta data" into a mime
807  * structure. The input list is in 'post', while the output is stored in
808  * mime part at '*finalform'.
809  *
810  * This function will not do a failf() for the potential memory failures but
811  * should for all other errors it spots. Just note that this function MAY get
812  * a NULL pointer in the 'data' argument.
813  */
814 
Curl_getformdata(struct Curl_easy * data,curl_mimepart * finalform,struct curl_httppost * post,curl_read_callback fread_func)815 CURLcode Curl_getformdata(struct Curl_easy *data,
816                           curl_mimepart *finalform,
817                           struct curl_httppost *post,
818                           curl_read_callback fread_func)
819 {
820   CURLcode result = CURLE_OK;
821   curl_mime *form = NULL;
822   curl_mimepart *part;
823   struct curl_httppost *file;
824 
825   Curl_mime_cleanpart(finalform); /* default form is empty */
826 
827   if(!post)
828     return result; /* no input => no output! */
829 
830   form = curl_mime_init(data);
831   if(!form)
832     result = CURLE_OUT_OF_MEMORY;
833 
834   if(!result)
835     result = curl_mime_subparts(finalform, form);
836 
837   /* Process each top part. */
838   for(; !result && post; post = post->next) {
839     /* If we have more than a file here, create a mime subpart and fill it. */
840     curl_mime *multipart = form;
841     if(post->more) {
842       part = curl_mime_addpart(form);
843       if(!part)
844         result = CURLE_OUT_OF_MEMORY;
845       if(!result)
846         result = setname(part, post->name, post->namelength);
847       if(!result) {
848         multipart = curl_mime_init(data);
849         if(!multipart)
850           result = CURLE_OUT_OF_MEMORY;
851       }
852       if(!result)
853         result = curl_mime_subparts(part, multipart);
854     }
855 
856     /* Generate all the part contents. */
857     for(file = post; !result && file; file = file->more) {
858       /* Create the part. */
859       part = curl_mime_addpart(multipart);
860       if(!part)
861         result = CURLE_OUT_OF_MEMORY;
862 
863       /* Set the headers. */
864       if(!result)
865         result = curl_mime_headers(part, file->contentheader, 0);
866 
867       /* Set the content type. */
868       if(!result && file->contenttype)
869         result = curl_mime_type(part, file->contenttype);
870 
871       /* Set field name. */
872       if(!result && !post->more)
873         result = setname(part, post->name, post->namelength);
874 
875       /* Process contents. */
876       if(!result) {
877         curl_off_t clen = post->contentslength;
878 
879         if(post->flags & CURL_HTTPPOST_LARGE)
880           clen = post->contentlen;
881 
882         if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
883           if(!strcmp(file->contents, "-")) {
884             /* There are a few cases where the code below will not work; in
885                particular, freopen(stdin) by the caller is not guaranteed
886                to result as expected. This feature has been kept for backward
887                compatibility: use of "-" pseudo filename should be avoided. */
888             result = curl_mime_data_cb(part, (curl_off_t) -1,
889                                        (curl_read_callback) fread,
890                                        fseeko_wrapper,
891                                        NULL, (void *) stdin);
892           }
893           else
894             result = curl_mime_filedata(part, file->contents);
895           if(!result && (post->flags & HTTPPOST_READFILE))
896             result = curl_mime_filename(part, NULL);
897         }
898         else if(post->flags & HTTPPOST_BUFFER)
899           result = curl_mime_data(part, post->buffer,
900                                   post->bufferlength ?
901                                   post->bufferlength : -1);
902         else if(post->flags & HTTPPOST_CALLBACK) {
903           /* the contents should be read with the callback and the size is set
904              with the contentslength */
905           if(!clen)
906             clen = -1;
907           result = curl_mime_data_cb(part, clen,
908                                      fread_func, NULL, NULL, post->userp);
909         }
910         else {
911           size_t uclen;
912           if(!clen)
913             uclen = CURL_ZERO_TERMINATED;
914           else
915             uclen = (size_t)clen;
916           result = curl_mime_data(part, post->contents, uclen);
917         }
918       }
919 
920       /* Set fake filename. */
921       if(!result && post->showfilename)
922         if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
923                                         HTTPPOST_CALLBACK)))
924           result = curl_mime_filename(part, post->showfilename);
925     }
926   }
927 
928   if(result)
929     Curl_mime_cleanpart(finalform);
930 
931   return result;
932 }
933 
934 #else
935 /* if disabled */
curl_formadd(struct curl_httppost ** httppost,struct curl_httppost ** last_post,...)936 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
937                           struct curl_httppost **last_post,
938                           ...)
939 {
940   (void)httppost;
941   (void)last_post;
942   return CURL_FORMADD_DISABLED;
943 }
944 
curl_formget(struct curl_httppost * form,void * arg,curl_formget_callback append)945 int curl_formget(struct curl_httppost *form, void *arg,
946                  curl_formget_callback append)
947 {
948   (void) form;
949   (void) arg;
950   (void) append;
951   return CURL_FORMADD_DISABLED;
952 }
953 
curl_formfree(struct curl_httppost * form)954 void curl_formfree(struct curl_httppost *form)
955 {
956   (void)form;
957   /* Nothing to do. */
958 }
959 
960 #endif  /* if disabled */
961