• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2018, 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 #ifndef CURL_DISABLE_HTTP
28 
29 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
30 #include <libgen.h>
31 #endif
32 
33 #include "urldata.h" /* for struct Curl_easy */
34 #include "formdata.h"
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,FormInfo * parent_form_info)126 static FormInfo * AddFormInfo(char *value,
127                               char *contenttype,
128                               FormInfo *parent_form_info)
129 {
130   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   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     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 nul-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       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     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     switch(nread) {
732     default:
733       if(append(arg, buffer, nread) != nread)
734         result = CURLE_READ_ERROR;
735       break;
736     case CURL_READFUNC_ABORT:
737     case CURL_READFUNC_PAUSE:
738       break;
739     }
740   }
741 
742   Curl_mime_cleanpart(&toppart);
743   return (int) result;
744 }
745 
746 /*
747  * curl_formfree() is an external function to free up a whole form post
748  * chain
749  */
curl_formfree(struct curl_httppost * form)750 void curl_formfree(struct curl_httppost *form)
751 {
752   struct curl_httppost *next;
753 
754   if(!form)
755     /* no form to free, just get out of this */
756     return;
757 
758   do {
759     next = form->next;  /* the following form line */
760 
761     /* recurse to sub-contents */
762     curl_formfree(form->more);
763 
764     if(!(form->flags & HTTPPOST_PTRNAME))
765       free(form->name); /* free the name */
766     if(!(form->flags &
767          (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
768       )
769       free(form->contents); /* free the contents */
770     free(form->contenttype); /* free the content type */
771     free(form->showfilename); /* free the faked file name */
772     free(form);       /* free the struct */
773     form = next;
774   } while(form); /* continue */
775 }
776 
777 
778 /* Set mime part name, taking care of non nul-terminated name string. */
setname(curl_mimepart * part,const char * name,size_t len)779 static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
780 {
781   char *zname;
782   CURLcode res;
783 
784   if(!name || !len)
785     return curl_mime_name(part, name);
786   zname = malloc(len + 1);
787   if(!zname)
788     return CURLE_OUT_OF_MEMORY;
789   memcpy(zname, name, len);
790   zname[len] = '\0';
791   res = curl_mime_name(part, zname);
792   free(zname);
793   return res;
794 }
795 
796 /*
797  * Curl_getformdata() converts a linked list of "meta data" into a mime
798  * structure. The input list is in 'post', while the output is stored in
799  * mime part at '*finalform'.
800  *
801  * This function will not do a failf() for the potential memory failures but
802  * should for all other errors it spots. Just note that this function MAY get
803  * a NULL pointer in the 'data' argument.
804  */
805 
Curl_getformdata(struct Curl_easy * data,curl_mimepart * finalform,struct curl_httppost * post,curl_read_callback fread_func)806 CURLcode Curl_getformdata(struct Curl_easy *data,
807                           curl_mimepart *finalform,
808                           struct curl_httppost *post,
809                           curl_read_callback fread_func)
810 {
811   CURLcode result = CURLE_OK;
812   curl_mime *form = NULL;
813   curl_mimepart *part;
814   struct curl_httppost *file;
815 
816   Curl_mime_cleanpart(finalform); /* default form is empty */
817 
818   if(!post)
819     return result; /* no input => no output! */
820 
821   form = curl_mime_init(data);
822   if(!form)
823     result = CURLE_OUT_OF_MEMORY;
824 
825   if(!result)
826     result = curl_mime_subparts(finalform, form);
827 
828   /* Process each top part. */
829   for(; !result && post; post = post->next) {
830     /* If we have more than a file here, create a mime subpart and fill it. */
831     curl_mime *multipart = form;
832     if(post->more) {
833       part = curl_mime_addpart(form);
834       if(!part)
835         result = CURLE_OUT_OF_MEMORY;
836       if(!result)
837         result = setname(part, post->name, post->namelength);
838       if(!result) {
839         multipart = curl_mime_init(data);
840         if(!multipart)
841           result = CURLE_OUT_OF_MEMORY;
842       }
843       if(!result)
844         result = curl_mime_subparts(part, multipart);
845     }
846 
847     /* Generate all the part contents. */
848     for(file = post; !result && file; file = file->more) {
849       /* Create the part. */
850       part = curl_mime_addpart(multipart);
851       if(!part)
852         result = CURLE_OUT_OF_MEMORY;
853 
854       /* Set the headers. */
855       if(!result)
856         result = curl_mime_headers(part, file->contentheader, 0);
857 
858       /* Set the content type. */
859       if(!result && file->contenttype)
860         result = curl_mime_type(part, file->contenttype);
861 
862       /* Set field name. */
863       if(!result && !post->more)
864         result = setname(part, post->name, post->namelength);
865 
866       /* Process contents. */
867       if(!result) {
868         curl_off_t clen = post->contentslength;
869 
870         if(post->flags & CURL_HTTPPOST_LARGE)
871           clen = post->contentlen;
872         if(!clen)
873           clen = -1;
874 
875         if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
876           if(!strcmp(file->contents, "-")) {
877             /* There are a few cases where the code below won't work; in
878                particular, freopen(stdin) by the caller is not guaranteed
879                to result as expected. This feature has been kept for backward
880                compatibility: use of "-" pseudo file name should be avoided. */
881             result = curl_mime_data_cb(part, (curl_off_t) -1,
882                                        (curl_read_callback) fread,
883                                        CURLX_FUNCTION_CAST(curl_seek_callback,
884                                                            fseek),
885                                        NULL, (void *) stdin);
886           }
887           else
888             result = curl_mime_filedata(part, file->contents);
889           if(!result && (post->flags & HTTPPOST_READFILE))
890             result = curl_mime_filename(part, NULL);
891         }
892         else if(post->flags & HTTPPOST_BUFFER)
893           result = curl_mime_data(part, post->buffer,
894                                   post->bufferlength? post->bufferlength: -1);
895         else if(post->flags & HTTPPOST_CALLBACK)
896           /* the contents should be read with the callback and the size is set
897              with the contentslength */
898           result = curl_mime_data_cb(part, clen,
899                                      fread_func, NULL, NULL, post->userp);
900         else {
901           result = curl_mime_data(part, post->contents, (ssize_t) clen);
902 #ifdef CURL_DOES_CONVERSIONS
903           /* Convert textual contents now. */
904           if(!result && data && part->datasize)
905             result = Curl_convert_to_network(data, part->data, part->datasize);
906 #endif
907         }
908       }
909 
910       /* Set fake file name. */
911       if(!result && post->showfilename)
912         if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
913                                         HTTPPOST_CALLBACK)))
914           result = curl_mime_filename(part, post->showfilename);
915     }
916   }
917 
918   if(result)
919     Curl_mime_cleanpart(finalform);
920 
921   return result;
922 }
923 
924 #else  /* CURL_DISABLE_HTTP */
curl_formadd(struct curl_httppost ** httppost,struct curl_httppost ** last_post,...)925 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
926                           struct curl_httppost **last_post,
927                           ...)
928 {
929   (void)httppost;
930   (void)last_post;
931   return CURL_FORMADD_DISABLED;
932 }
933 
curl_formget(struct curl_httppost * form,void * arg,curl_formget_callback append)934 int curl_formget(struct curl_httppost *form, void *arg,
935                  curl_formget_callback append)
936 {
937   (void) form;
938   (void) arg;
939   (void) append;
940   return CURL_FORMADD_DISABLED;
941 }
942 
curl_formfree(struct curl_httppost * form)943 void curl_formfree(struct curl_httppost *form)
944 {
945   (void)form;
946   /* does nothing HTTP is disabled */
947 }
948 
949 
950 #endif  /* !defined(CURL_DISABLE_HTTP) */
951