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