• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2020, 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.haxx.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  ***************************************************************************/
22 
23 #include "curl_setup.h"
24 
25 #include <curl/curl.h>
26 
27 #include "formdata.h"
28 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)
29 
30 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
31 #include <libgen.h>
32 #endif
33 
34 #include "urldata.h" /* for struct Curl_easy */
35 #include "mime.h"
36 #include "non-ascii.h"
37 #include "vtls/vtls.h"
38 #include "strcase.h"
39 #include "sendf.h"
40 #include "strdup.h"
41 #include "rand.h"
42 #include "warnless.h"
43 /* The last 3 #include files should be in this order */
44 #include "curl_printf.h"
45 #include "curl_memory.h"
46 #include "memdebug.h"
47 
48 
49 #define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
50 #define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
51 #define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
52 #define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
53 #define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
54 #define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
55 #define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
56 
57 /***************************************************************************
58  *
59  * AddHttpPost()
60  *
61  * Adds a HttpPost structure to the list, if parent_post is given becomes
62  * a subpost of parent_post instead of a direct list element.
63  *
64  * Returns newly allocated HttpPost on success and NULL if malloc failed.
65  *
66  ***************************************************************************/
67 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)68 AddHttpPost(char *name, size_t namelength,
69             char *value, curl_off_t contentslength,
70             char *buffer, size_t bufferlength,
71             char *contenttype,
72             long flags,
73             struct curl_slist *contentHeader,
74             char *showfilename, char *userp,
75             struct curl_httppost *parent_post,
76             struct curl_httppost **httppost,
77             struct curl_httppost **last_post)
78 {
79   struct curl_httppost *post;
80   post = calloc(1, sizeof(struct curl_httppost));
81   if(post) {
82     post->name = name;
83     post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
84     post->contents = value;
85     post->contentlen = contentslength;
86     post->buffer = buffer;
87     post->bufferlength = (long)bufferlength;
88     post->contenttype = contenttype;
89     post->contentheader = contentHeader;
90     post->showfilename = showfilename;
91     post->userp = userp;
92     post->flags = flags | CURL_HTTPPOST_LARGE;
93   }
94   else
95     return NULL;
96 
97   if(parent_post) {
98     /* now, point our 'more' to the original 'more' */
99     post->more = parent_post->more;
100 
101     /* then move the original 'more' to point to ourselves */
102     parent_post->more = post;
103   }
104   else {
105     /* make the previous point to this */
106     if(*last_post)
107       (*last_post)->next = post;
108     else
109       (*httppost) = post;
110 
111     (*last_post) = post;
112   }
113   return post;
114 }
115 
116 /***************************************************************************
117  *
118  * AddFormInfo()
119  *
120  * Adds a FormInfo structure to the list presented by parent_form_info.
121  *
122  * Returns newly allocated FormInfo on success and NULL if malloc failed/
123  * parent_form_info is NULL.
124  *
125  ***************************************************************************/
AddFormInfo(char * value,char * contenttype,struct FormInfo * parent_form_info)126 static struct FormInfo *AddFormInfo(char *value,
127                                     char *contenttype,
128                                     struct FormInfo *parent_form_info)
129 {
130   struct FormInfo *form_info;
131   form_info = calloc(1, sizeof(struct FormInfo));
132   if(form_info) {
133     if(value)
134       form_info->value = value;
135     if(contenttype)
136       form_info->contenttype = contenttype;
137     form_info->flags = HTTPPOST_FILENAME;
138   }
139   else
140     return NULL;
141 
142   if(parent_form_info) {
143     /* now, point our 'more' to the original 'more' */
144     form_info->more = parent_form_info->more;
145 
146     /* then move the original 'more' to point to ourselves */
147     parent_form_info->more = form_info;
148   }
149 
150   return form_info;
151 }
152 
153 /***************************************************************************
154  *
155  * FormAdd()
156  *
157  * Stores a formpost parameter and builds the appropriate linked list.
158  *
159  * Has two principal functionalities: using files and byte arrays as
160  * post parts. Byte arrays are either copied or just the pointer is stored
161  * (as the user requests) while for files only the filename and not the
162  * content is stored.
163  *
164  * While you may have only one byte array for each name, multiple filenames
165  * are allowed (and because of this feature CURLFORM_END is needed after
166  * using CURLFORM_FILE).
167  *
168  * Examples:
169  *
170  * Simple name/value pair with copied contents:
171  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
172  * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
173  *
174  * name/value pair where only the content pointer is remembered:
175  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
176  * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
177  * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
178  *
179  * storing a filename (CONTENTTYPE is optional!):
180  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
181  * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
182  * CURLFORM_END);
183  *
184  * storing multiple filenames:
185  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
186  * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
187  *
188  * Returns:
189  * CURL_FORMADD_OK             on success
190  * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
191  * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
192  * CURL_FORMADD_NULL           if a null pointer was given for a char
193  * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
194  * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
195  * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
196  * CURL_FORMADD_MEMORY         if a HttpPost struct cannot be allocated
197  * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
198  * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
199  *
200  ***************************************************************************/
201 
202 static
FormAdd(struct curl_httppost ** httppost,struct curl_httppost ** last_post,va_list params)203 CURLFORMcode FormAdd(struct curl_httppost **httppost,
204                      struct curl_httppost **last_post,
205                      va_list params)
206 {
207   struct FormInfo *first_form, *current_form, *form = NULL;
208   CURLFORMcode return_value = CURL_FORMADD_OK;
209   const char *prevtype = NULL;
210   struct curl_httppost *post = NULL;
211   CURLformoption option;
212   struct curl_forms *forms = NULL;
213   char *array_value = NULL; /* value read from an array */
214 
215   /* This is a state variable, that if TRUE means that we're parsing an
216      array that we got passed to us. If FALSE we're parsing the input
217      va_list arguments. */
218   bool array_state = FALSE;
219 
220   /*
221    * We need to allocate the first struct to fill in.
222    */
223   first_form = calloc(1, sizeof(struct FormInfo));
224   if(!first_form)
225     return CURL_FORMADD_MEMORY;
226 
227   current_form = first_form;
228 
229   /*
230    * Loop through all the options set. Break if we have an error to report.
231    */
232   while(return_value == CURL_FORMADD_OK) {
233 
234     /* first see if we have more parts of the array param */
235     if(array_state && forms) {
236       /* get the upcoming option from the given array */
237       option = forms->option;
238       array_value = (char *)forms->value;
239 
240       forms++; /* advance this to next entry */
241       if(CURLFORM_END == option) {
242         /* end of array state */
243         array_state = FALSE;
244         continue;
245       }
246     }
247     else {
248       /* This is not array-state, get next option */
249       option = va_arg(params, CURLformoption);
250       if(CURLFORM_END == option)
251         break;
252     }
253 
254     switch(option) {
255     case CURLFORM_ARRAY:
256       if(array_state)
257         /* we don't support an array from within an array */
258         return_value = CURL_FORMADD_ILLEGAL_ARRAY;
259       else {
260         forms = va_arg(params, struct curl_forms *);
261         if(forms)
262           array_state = TRUE;
263         else
264           return_value = CURL_FORMADD_NULL;
265       }
266       break;
267 
268       /*
269        * Set the Name property.
270        */
271     case CURLFORM_PTRNAME:
272 #ifdef CURL_DOES_CONVERSIONS
273       /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
274        * the data in all cases so that we'll have safe memory for the eventual
275        * conversion.
276        */
277 #else
278       current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
279 #endif
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_memdup(form->name, form->namelength?
607                                    form->namelength:
608                                    strlen(form->name) + 1);
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, NULL); /* default form is empty */
719   result = Curl_getformdata(NULL, &toppart, form, NULL);
720   if(!result)
721     result = Curl_mime_prepare_headers(&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 = malloc(len + 1);
783   if(!zname)
784     return CURLE_OUT_OF_MEMORY;
785   memcpy(zname, name, len);
786   zname[len] = '\0';
787   res = curl_mime_name(part, zname);
788   free(zname);
789   return res;
790 }
791 
792 /*
793  * Curl_getformdata() converts a linked list of "meta data" into a mime
794  * structure. The input list is in 'post', while the output is stored in
795  * mime part at '*finalform'.
796  *
797  * This function will not do a failf() for the potential memory failures but
798  * should for all other errors it spots. Just note that this function MAY get
799  * a NULL pointer in the 'data' argument.
800  */
801 
Curl_getformdata(struct Curl_easy * data,curl_mimepart * finalform,struct curl_httppost * post,curl_read_callback fread_func)802 CURLcode Curl_getformdata(struct Curl_easy *data,
803                           curl_mimepart *finalform,
804                           struct curl_httppost *post,
805                           curl_read_callback fread_func)
806 {
807   CURLcode result = CURLE_OK;
808   curl_mime *form = NULL;
809   curl_mimepart *part;
810   struct curl_httppost *file;
811 
812   Curl_mime_cleanpart(finalform); /* default form is empty */
813 
814   if(!post)
815     return result; /* no input => no output! */
816 
817   form = curl_mime_init(data);
818   if(!form)
819     result = CURLE_OUT_OF_MEMORY;
820 
821   if(!result)
822     result = curl_mime_subparts(finalform, form);
823 
824   /* Process each top part. */
825   for(; !result && post; post = post->next) {
826     /* If we have more than a file here, create a mime subpart and fill it. */
827     curl_mime *multipart = form;
828     if(post->more) {
829       part = curl_mime_addpart(form);
830       if(!part)
831         result = CURLE_OUT_OF_MEMORY;
832       if(!result)
833         result = setname(part, post->name, post->namelength);
834       if(!result) {
835         multipart = curl_mime_init(data);
836         if(!multipart)
837           result = CURLE_OUT_OF_MEMORY;
838       }
839       if(!result)
840         result = curl_mime_subparts(part, multipart);
841     }
842 
843     /* Generate all the part contents. */
844     for(file = post; !result && file; file = file->more) {
845       /* Create the part. */
846       part = curl_mime_addpart(multipart);
847       if(!part)
848         result = CURLE_OUT_OF_MEMORY;
849 
850       /* Set the headers. */
851       if(!result)
852         result = curl_mime_headers(part, file->contentheader, 0);
853 
854       /* Set the content type. */
855       if(!result && file->contenttype)
856         result = curl_mime_type(part, file->contenttype);
857 
858       /* Set field name. */
859       if(!result && !post->more)
860         result = setname(part, post->name, post->namelength);
861 
862       /* Process contents. */
863       if(!result) {
864         curl_off_t clen = post->contentslength;
865 
866         if(post->flags & CURL_HTTPPOST_LARGE)
867           clen = post->contentlen;
868         if(!clen)
869           clen = -1;
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           result = curl_mime_data_cb(part, clen,
895                                      fread_func, NULL, NULL, post->userp);
896         else {
897           result = curl_mime_data(part, post->contents, (ssize_t) clen);
898 #ifdef CURL_DOES_CONVERSIONS
899           /* Convert textual contents now. */
900           if(!result && data && part->datasize)
901             result = Curl_convert_to_network(data, part->data, part->datasize);
902 #endif
903         }
904       }
905 
906       /* Set fake file name. */
907       if(!result && post->showfilename)
908         if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
909                                         HTTPPOST_CALLBACK)))
910           result = curl_mime_filename(part, post->showfilename);
911     }
912   }
913 
914   if(result)
915     Curl_mime_cleanpart(finalform);
916 
917   return result;
918 }
919 
920 #else
921 /* if disabled */
curl_formadd(struct curl_httppost ** httppost,struct curl_httppost ** last_post,...)922 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
923                           struct curl_httppost **last_post,
924                           ...)
925 {
926   (void)httppost;
927   (void)last_post;
928   return CURL_FORMADD_DISABLED;
929 }
930 
curl_formget(struct curl_httppost * form,void * arg,curl_formget_callback append)931 int curl_formget(struct curl_httppost *form, void *arg,
932                  curl_formget_callback append)
933 {
934   (void) form;
935   (void) arg;
936   (void) append;
937   return CURL_FORMADD_DISABLED;
938 }
939 
curl_formfree(struct curl_httppost * form)940 void curl_formfree(struct curl_httppost *form)
941 {
942   (void)form;
943   /* does nothing HTTP is disabled */
944 }
945 
946 #endif  /* if disabled */
947