xref: /curl/lib/formdata.c (revision 3829759b)
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'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 
curl_formadd(struct curl_httppost ** httppost,struct curl_httppost ** last_post,...)693 CURLFORMcode 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  */
curl_formget(struct curl_httppost * form,void * arg,curl_formget_callback append)712 int 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  */
curl_formfree(struct curl_httppost * form)746 void 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. */
setname(curl_mimepart * part,const char * name,size_t len)775 static 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 */
fseeko_wrapper(void * stream,curl_off_t offset,int whence)791 static 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 
Curl_getformdata(struct Curl_easy * data,curl_mimepart * finalform,struct curl_httppost * post,curl_read_callback fread_func)814 CURLcode 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 */
curl_formadd(struct curl_httppost ** httppost,struct curl_httppost ** last_post,...)934 CURLFORMcode 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 
curl_formget(struct curl_httppost * form,void * arg,curl_formget_callback append)943 int 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 
curl_formfree(struct curl_httppost * form)952 void curl_formfree(struct curl_httppost *form)
953 {
954   (void)form;
955   /* Nothing to do. */
956 }
957 
958 #endif  /* if disabled */
959