Revert "Imported Upstream version 7.53.1"
[platform/upstream/curl.git] / lib / formdata.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2016, 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 "vtls/vtls.h"
36 #include "strequal.h"
37 #include "sendf.h"
38 #include "strdup.h"
39 /* The last 3 #include files should be in this order */
40 #include "curl_printf.h"
41 #include "curl_memory.h"
42 #include "memdebug.h"
43
44 #ifndef HAVE_BASENAME
45 static char *Curl_basename(char *path);
46 #define basename(x)  Curl_basename((x))
47 #endif
48
49 static size_t readfromfile(struct Form *form, char *buffer, size_t size);
50 static char *formboundary(struct Curl_easy *data);
51
52 /* What kind of Content-Type to use on un-specified files with unrecognized
53    extensions. */
54 #define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
55
56 #define FORM_FILE_SEPARATOR ','
57 #define FORM_TYPE_SEPARATOR ';'
58
59 #define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
60 #define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
61 #define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
62 #define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
63 #define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
64 #define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
65 #define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
66
67 /***************************************************************************
68  *
69  * AddHttpPost()
70  *
71  * Adds a HttpPost structure to the list, if parent_post is given becomes
72  * a subpost of parent_post instead of a direct list element.
73  *
74  * Returns newly allocated HttpPost on success and NULL if malloc failed.
75  *
76  ***************************************************************************/
77 static struct curl_httppost *
78 AddHttpPost(char *name, size_t namelength,
79             char *value, curl_off_t contentslength,
80             char *buffer, size_t bufferlength,
81             char *contenttype,
82             long flags,
83             struct curl_slist* contentHeader,
84             char *showfilename, char *userp,
85             struct curl_httppost *parent_post,
86             struct curl_httppost **httppost,
87             struct curl_httppost **last_post)
88 {
89   struct curl_httppost *post;
90   post = calloc(1, sizeof(struct curl_httppost));
91   if(post) {
92     post->name = name;
93     post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
94     post->contents = value;
95     post->contentlen = contentslength;
96     post->buffer = buffer;
97     post->bufferlength = (long)bufferlength;
98     post->contenttype = contenttype;
99     post->contentheader = contentHeader;
100     post->showfilename = showfilename;
101     post->userp = userp,
102     post->flags = flags | CURL_HTTPPOST_LARGE;
103   }
104   else
105     return NULL;
106
107   if(parent_post) {
108     /* now, point our 'more' to the original 'more' */
109     post->more = parent_post->more;
110
111     /* then move the original 'more' to point to ourselves */
112     parent_post->more = post;
113   }
114   else {
115     /* make the previous point to this */
116     if(*last_post)
117       (*last_post)->next = post;
118     else
119       (*httppost) = post;
120
121     (*last_post) = post;
122   }
123   return post;
124 }
125
126 /***************************************************************************
127  *
128  * AddFormInfo()
129  *
130  * Adds a FormInfo structure to the list presented by parent_form_info.
131  *
132  * Returns newly allocated FormInfo on success and NULL if malloc failed/
133  * parent_form_info is NULL.
134  *
135  ***************************************************************************/
136 static FormInfo * AddFormInfo(char *value,
137                               char *contenttype,
138                               FormInfo *parent_form_info)
139 {
140   FormInfo *form_info;
141   form_info = calloc(1, sizeof(struct FormInfo));
142   if(form_info) {
143     if(value)
144       form_info->value = value;
145     if(contenttype)
146       form_info->contenttype = contenttype;
147     form_info->flags = HTTPPOST_FILENAME;
148   }
149   else
150     return NULL;
151
152   if(parent_form_info) {
153     /* now, point our 'more' to the original 'more' */
154     form_info->more = parent_form_info->more;
155
156     /* then move the original 'more' to point to ourselves */
157     parent_form_info->more = form_info;
158   }
159
160   return form_info;
161 }
162
163 /***************************************************************************
164  *
165  * ContentTypeForFilename()
166  *
167  * Provides content type for filename if one of the known types (else
168  * (either the prevtype or the default is returned).
169  *
170  * Returns some valid contenttype for filename.
171  *
172  ***************************************************************************/
173 static const char *ContentTypeForFilename(const char *filename,
174                                           const char *prevtype)
175 {
176   const char *contenttype = NULL;
177   unsigned int i;
178   /*
179    * No type was specified, we scan through a few well-known
180    * extensions and pick the first we match!
181    */
182   struct ContentType {
183     const char *extension;
184     const char *type;
185   };
186   static const struct ContentType ctts[]={
187     {".gif",  "image/gif"},
188     {".jpg",  "image/jpeg"},
189     {".jpeg", "image/jpeg"},
190     {".txt",  "text/plain"},
191     {".html", "text/html"},
192     {".xml", "application/xml"}
193   };
194
195   if(prevtype)
196     /* default to the previously set/used! */
197     contenttype = prevtype;
198   else
199     contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
200
201   if(filename) { /* in case a NULL was passed in */
202     for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
203       if(strlen(filename) >= strlen(ctts[i].extension)) {
204         if(strequal(filename +
205                     strlen(filename) - strlen(ctts[i].extension),
206                     ctts[i].extension)) {
207           contenttype = ctts[i].type;
208           break;
209         }
210       }
211     }
212   }
213   /* we have a contenttype by now */
214   return contenttype;
215 }
216
217 /***************************************************************************
218  *
219  * FormAdd()
220  *
221  * Stores a formpost parameter and builds the appropriate linked list.
222  *
223  * Has two principal functionalities: using files and byte arrays as
224  * post parts. Byte arrays are either copied or just the pointer is stored
225  * (as the user requests) while for files only the filename and not the
226  * content is stored.
227  *
228  * While you may have only one byte array for each name, multiple filenames
229  * are allowed (and because of this feature CURLFORM_END is needed after
230  * using CURLFORM_FILE).
231  *
232  * Examples:
233  *
234  * Simple name/value pair with copied contents:
235  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
236  * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
237  *
238  * name/value pair where only the content pointer is remembered:
239  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
240  * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
241  * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
242  *
243  * storing a filename (CONTENTTYPE is optional!):
244  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
245  * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
246  * CURLFORM_END);
247  *
248  * storing multiple filenames:
249  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
250  * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
251  *
252  * Returns:
253  * CURL_FORMADD_OK             on success
254  * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
255  * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
256  * CURL_FORMADD_NULL           if a null pointer was given for a char
257  * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
258  * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
259  * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
260  * CURL_FORMADD_MEMORY         if a HttpPost struct cannot be allocated
261  * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
262  * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
263  *
264  ***************************************************************************/
265
266 static
267 CURLFORMcode FormAdd(struct curl_httppost **httppost,
268                      struct curl_httppost **last_post,
269                      va_list params)
270 {
271   FormInfo *first_form, *current_form, *form = NULL;
272   CURLFORMcode return_value = CURL_FORMADD_OK;
273   const char *prevtype = NULL;
274   struct curl_httppost *post = NULL;
275   CURLformoption option;
276   struct curl_forms *forms = NULL;
277   char *array_value=NULL; /* value read from an array */
278
279   /* This is a state variable, that if TRUE means that we're parsing an
280      array that we got passed to us. If FALSE we're parsing the input
281      va_list arguments. */
282   bool array_state = FALSE;
283
284   /*
285    * We need to allocate the first struct to fill in.
286    */
287   first_form = calloc(1, sizeof(struct FormInfo));
288   if(!first_form)
289     return CURL_FORMADD_MEMORY;
290
291   current_form = first_form;
292
293   /*
294    * Loop through all the options set. Break if we have an error to report.
295    */
296   while(return_value == CURL_FORMADD_OK) {
297
298     /* first see if we have more parts of the array param */
299     if(array_state && forms) {
300       /* get the upcoming option from the given array */
301       option = forms->option;
302       array_value = (char *)forms->value;
303
304       forms++; /* advance this to next entry */
305       if(CURLFORM_END == option) {
306         /* end of array state */
307         array_state = FALSE;
308         continue;
309       }
310     }
311     else {
312       /* This is not array-state, get next option */
313       option = va_arg(params, CURLformoption);
314       if(CURLFORM_END == option)
315         break;
316     }
317
318     switch (option) {
319     case CURLFORM_ARRAY:
320       if(array_state)
321         /* we don't support an array from within an array */
322         return_value = CURL_FORMADD_ILLEGAL_ARRAY;
323       else {
324         forms = va_arg(params, struct curl_forms *);
325         if(forms)
326           array_state = TRUE;
327         else
328           return_value = CURL_FORMADD_NULL;
329       }
330       break;
331
332       /*
333        * Set the Name property.
334        */
335     case CURLFORM_PTRNAME:
336 #ifdef CURL_DOES_CONVERSIONS
337       /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
338        * the data in all cases so that we'll have safe memory for the eventual
339        * conversion.
340        */
341 #else
342       current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
343 #endif
344     case CURLFORM_COPYNAME:
345       if(current_form->name)
346         return_value = CURL_FORMADD_OPTION_TWICE;
347       else {
348         char *name = array_state?
349           array_value:va_arg(params, char *);
350         if(name)
351           current_form->name = name; /* store for the moment */
352         else
353           return_value = CURL_FORMADD_NULL;
354       }
355       break;
356     case CURLFORM_NAMELENGTH:
357       if(current_form->namelength)
358         return_value = CURL_FORMADD_OPTION_TWICE;
359       else
360         current_form->namelength =
361           array_state?(size_t)array_value:(size_t)va_arg(params, long);
362       break;
363
364       /*
365        * Set the contents property.
366        */
367     case CURLFORM_PTRCONTENTS:
368       current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
369     case CURLFORM_COPYCONTENTS:
370       if(current_form->value)
371         return_value = CURL_FORMADD_OPTION_TWICE;
372       else {
373         char *value =
374           array_state?array_value:va_arg(params, char *);
375         if(value)
376           current_form->value = value; /* store for the moment */
377         else
378           return_value = CURL_FORMADD_NULL;
379       }
380       break;
381     case CURLFORM_CONTENTSLENGTH:
382       current_form->contentslength =
383         array_state?(size_t)array_value:(size_t)va_arg(params, long);
384       break;
385
386     case CURLFORM_CONTENTLEN:
387       current_form->flags |= CURL_HTTPPOST_LARGE;
388       current_form->contentslength =
389         array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
390       break;
391
392       /* Get contents from a given file name */
393     case CURLFORM_FILECONTENT:
394       if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
395         return_value = CURL_FORMADD_OPTION_TWICE;
396       else {
397         const char *filename = array_state?
398           array_value:va_arg(params, char *);
399         if(filename) {
400           current_form->value = strdup(filename);
401           if(!current_form->value)
402             return_value = CURL_FORMADD_MEMORY;
403           else {
404             current_form->flags |= HTTPPOST_READFILE;
405             current_form->value_alloc = TRUE;
406           }
407         }
408         else
409           return_value = CURL_FORMADD_NULL;
410       }
411       break;
412
413       /* We upload a file */
414     case CURLFORM_FILE:
415       {
416         const char *filename = array_state?array_value:
417           va_arg(params, char *);
418
419         if(current_form->value) {
420           if(current_form->flags & HTTPPOST_FILENAME) {
421             if(filename) {
422               char *fname = strdup(filename);
423               if(!fname)
424                 return_value = CURL_FORMADD_MEMORY;
425               else {
426                 form = AddFormInfo(fname, NULL, current_form);
427                 if(!form) {
428                   free(fname);
429                   return_value = CURL_FORMADD_MEMORY;
430                 }
431                 else {
432                   form->value_alloc = TRUE;
433                   current_form = form;
434                   form = NULL;
435                 }
436               }
437             }
438             else
439               return_value = CURL_FORMADD_NULL;
440           }
441           else
442             return_value = CURL_FORMADD_OPTION_TWICE;
443         }
444         else {
445           if(filename) {
446             current_form->value = strdup(filename);
447             if(!current_form->value)
448               return_value = CURL_FORMADD_MEMORY;
449             else {
450               current_form->flags |= HTTPPOST_FILENAME;
451               current_form->value_alloc = TRUE;
452             }
453           }
454           else
455             return_value = CURL_FORMADD_NULL;
456         }
457         break;
458       }
459
460     case CURLFORM_BUFFERPTR:
461       current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
462       if(current_form->buffer)
463         return_value = CURL_FORMADD_OPTION_TWICE;
464       else {
465         char *buffer =
466           array_state?array_value:va_arg(params, char *);
467         if(buffer) {
468           current_form->buffer = buffer; /* store for the moment */
469           current_form->value = buffer; /* make it non-NULL to be accepted
470                                            as fine */
471         }
472         else
473           return_value = CURL_FORMADD_NULL;
474       }
475       break;
476
477     case CURLFORM_BUFFERLENGTH:
478       if(current_form->bufferlength)
479         return_value = CURL_FORMADD_OPTION_TWICE;
480       else
481         current_form->bufferlength =
482           array_state?(size_t)array_value:(size_t)va_arg(params, long);
483       break;
484
485     case CURLFORM_STREAM:
486       current_form->flags |= HTTPPOST_CALLBACK;
487       if(current_form->userp)
488         return_value = CURL_FORMADD_OPTION_TWICE;
489       else {
490         char *userp =
491           array_state?array_value:va_arg(params, char *);
492         if(userp) {
493           current_form->userp = userp;
494           current_form->value = userp; /* this isn't strictly true but we
495                                           derive a value from this later on
496                                           and we need this non-NULL to be
497                                           accepted as a fine form part */
498         }
499         else
500           return_value = CURL_FORMADD_NULL;
501       }
502       break;
503
504     case CURLFORM_CONTENTTYPE:
505       {
506         const char *contenttype =
507           array_state?array_value:va_arg(params, char *);
508         if(current_form->contenttype) {
509           if(current_form->flags & HTTPPOST_FILENAME) {
510             if(contenttype) {
511               char *type = strdup(contenttype);
512               if(!type)
513                 return_value = CURL_FORMADD_MEMORY;
514               else {
515                 form = AddFormInfo(NULL, type, current_form);
516                 if(!form) {
517                   free(type);
518                   return_value = CURL_FORMADD_MEMORY;
519                 }
520                 else {
521                   form->contenttype_alloc = TRUE;
522                   current_form = form;
523                   form = NULL;
524                 }
525               }
526             }
527             else
528               return_value = CURL_FORMADD_NULL;
529           }
530           else
531             return_value = CURL_FORMADD_OPTION_TWICE;
532         }
533         else {
534           if(contenttype) {
535             current_form->contenttype = strdup(contenttype);
536             if(!current_form->contenttype)
537               return_value = CURL_FORMADD_MEMORY;
538             else
539               current_form->contenttype_alloc = TRUE;
540           }
541           else
542             return_value = CURL_FORMADD_NULL;
543         }
544         break;
545       }
546     case CURLFORM_CONTENTHEADER:
547       {
548         /* this "cast increases required alignment of target type" but
549            we consider it OK anyway */
550         struct curl_slist* list = array_state?
551           (struct curl_slist*)(void*)array_value:
552           va_arg(params, struct curl_slist*);
553
554         if(current_form->contentheader)
555           return_value = CURL_FORMADD_OPTION_TWICE;
556         else
557           current_form->contentheader = list;
558
559         break;
560       }
561     case CURLFORM_FILENAME:
562     case CURLFORM_BUFFER:
563       {
564         const char *filename = array_state?array_value:
565           va_arg(params, char *);
566         if(current_form->showfilename)
567           return_value = CURL_FORMADD_OPTION_TWICE;
568         else {
569           current_form->showfilename = strdup(filename);
570           if(!current_form->showfilename)
571             return_value = CURL_FORMADD_MEMORY;
572           else
573             current_form->showfilename_alloc = TRUE;
574         }
575         break;
576       }
577     default:
578       return_value = CURL_FORMADD_UNKNOWN_OPTION;
579       break;
580     }
581   }
582
583   if(CURL_FORMADD_OK != return_value) {
584     /* On error, free allocated fields for all nodes of the FormInfo linked
585        list without deallocating nodes. List nodes are deallocated later on */
586     FormInfo *ptr;
587     for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
588       if(ptr->name_alloc) {
589         Curl_safefree(ptr->name);
590         ptr->name_alloc = FALSE;
591       }
592       if(ptr->value_alloc) {
593         Curl_safefree(ptr->value);
594         ptr->value_alloc = FALSE;
595       }
596       if(ptr->contenttype_alloc) {
597         Curl_safefree(ptr->contenttype);
598         ptr->contenttype_alloc = FALSE;
599       }
600       if(ptr->showfilename_alloc) {
601         Curl_safefree(ptr->showfilename);
602         ptr->showfilename_alloc = FALSE;
603       }
604     }
605   }
606
607   if(CURL_FORMADD_OK == return_value) {
608     /* go through the list, check for completeness and if everything is
609      * alright add the HttpPost item otherwise set return_value accordingly */
610
611     post = NULL;
612     for(form = first_form;
613         form != NULL;
614         form = form->more) {
615       if(((!form->name || !form->value) && !post) ||
616          ( (form->contentslength) &&
617            (form->flags & HTTPPOST_FILENAME) ) ||
618          ( (form->flags & HTTPPOST_FILENAME) &&
619            (form->flags & HTTPPOST_PTRCONTENTS) ) ||
620
621          ( (!form->buffer) &&
622            (form->flags & HTTPPOST_BUFFER) &&
623            (form->flags & HTTPPOST_PTRBUFFER) ) ||
624
625          ( (form->flags & HTTPPOST_READFILE) &&
626            (form->flags & HTTPPOST_PTRCONTENTS) )
627         ) {
628         return_value = CURL_FORMADD_INCOMPLETE;
629         break;
630       }
631       else {
632         if(((form->flags & HTTPPOST_FILENAME) ||
633             (form->flags & HTTPPOST_BUFFER)) &&
634            !form->contenttype) {
635           char *f = form->flags & HTTPPOST_BUFFER?
636             form->showfilename : form->value;
637
638           /* our contenttype is missing */
639           form->contenttype = strdup(ContentTypeForFilename(f, prevtype));
640           if(!form->contenttype) {
641             return_value = CURL_FORMADD_MEMORY;
642             break;
643           }
644           form->contenttype_alloc = TRUE;
645         }
646         if(!(form->flags & HTTPPOST_PTRNAME) &&
647            (form == first_form) ) {
648           /* Note that there's small risk that form->name is NULL here if the
649              app passed in a bad combo, so we better check for that first. */
650           if(form->name) {
651             /* copy name (without strdup; possibly contains null characters) */
652             form->name = Curl_memdup(form->name, form->namelength?
653                                      form->namelength:
654                                      strlen(form->name)+1);
655           }
656           if(!form->name) {
657             return_value = CURL_FORMADD_MEMORY;
658             break;
659           }
660           form->name_alloc = TRUE;
661         }
662         if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
663                             HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
664                             HTTPPOST_CALLBACK)) && form->value) {
665           /* copy value (without strdup; possibly contains null characters) */
666           size_t clen  = (size_t) form->contentslength;
667           if(!clen)
668             clen = strlen(form->value)+1;
669
670           form->value = Curl_memdup(form->value, clen);
671
672           if(!form->value) {
673             return_value = CURL_FORMADD_MEMORY;
674             break;
675           }
676           form->value_alloc = TRUE;
677         }
678         post = AddHttpPost(form->name, form->namelength,
679                            form->value, form->contentslength,
680                            form->buffer, form->bufferlength,
681                            form->contenttype, form->flags,
682                            form->contentheader, form->showfilename,
683                            form->userp,
684                            post, httppost,
685                            last_post);
686
687         if(!post) {
688           return_value = CURL_FORMADD_MEMORY;
689           break;
690         }
691
692         if(form->contenttype)
693           prevtype = form->contenttype;
694       }
695     }
696     if(CURL_FORMADD_OK != return_value) {
697       /* On error, free allocated fields for nodes of the FormInfo linked
698          list which are not already owned by the httppost linked list
699          without deallocating nodes. List nodes are deallocated later on */
700       FormInfo *ptr;
701       for(ptr = form; ptr != NULL; ptr = ptr->more) {
702         if(ptr->name_alloc) {
703           Curl_safefree(ptr->name);
704           ptr->name_alloc = FALSE;
705         }
706         if(ptr->value_alloc) {
707           Curl_safefree(ptr->value);
708           ptr->value_alloc = FALSE;
709         }
710         if(ptr->contenttype_alloc) {
711           Curl_safefree(ptr->contenttype);
712           ptr->contenttype_alloc = FALSE;
713         }
714         if(ptr->showfilename_alloc) {
715           Curl_safefree(ptr->showfilename);
716           ptr->showfilename_alloc = FALSE;
717         }
718       }
719     }
720   }
721
722   /* Always deallocate FormInfo linked list nodes without touching node
723      fields given that these have either been deallocated or are owned
724      now by the httppost linked list */
725   while(first_form) {
726     FormInfo *ptr = first_form->more;
727     free(first_form);
728     first_form = ptr;
729   }
730
731   return return_value;
732 }
733
734 /*
735  * curl_formadd() is a public API to add a section to the multipart formpost.
736  *
737  * @unittest: 1308
738  */
739
740 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
741                           struct curl_httppost **last_post,
742                           ...)
743 {
744   va_list arg;
745   CURLFORMcode result;
746   va_start(arg, last_post);
747   result = FormAdd(httppost, last_post, arg);
748   va_end(arg);
749   return result;
750 }
751
752 #ifdef __VMS
753 #include <fabdef.h>
754 /*
755  * get_vms_file_size does what it takes to get the real size of the file
756  *
757  * For fixed files, find out the size of the EOF block and adjust.
758  *
759  * For all others, have to read the entire file in, discarding the contents.
760  * Most posted text files will be small, and binary files like zlib archives
761  * and CD/DVD images should be either a STREAM_LF format or a fixed format.
762  *
763  */
764 curl_off_t VmsRealFileSize(const char * name,
765                            const struct_stat * stat_buf)
766 {
767   char buffer[8192];
768   curl_off_t count;
769   int ret_stat;
770   FILE * file;
771
772   file = fopen(name, FOPEN_READTEXT); /* VMS */
773   if(file == NULL)
774     return 0;
775
776   count = 0;
777   ret_stat = 1;
778   while(ret_stat > 0) {
779     ret_stat = fread(buffer, 1, sizeof(buffer), file);
780     if(ret_stat != 0)
781       count += ret_stat;
782   }
783   fclose(file);
784
785   return count;
786 }
787
788 /*
789  *
790  *  VmsSpecialSize checks to see if the stat st_size can be trusted and
791  *  if not to call a routine to get the correct size.
792  *
793  */
794 static curl_off_t VmsSpecialSize(const char * name,
795                                  const struct_stat * stat_buf)
796 {
797   switch(stat_buf->st_fab_rfm) {
798   case FAB$C_VAR:
799   case FAB$C_VFC:
800     return VmsRealFileSize(name, stat_buf);
801     break;
802   default:
803     return stat_buf->st_size;
804   }
805 }
806
807 #endif
808
809 #ifndef __VMS
810 #define filesize(name, stat_data) (stat_data.st_size)
811 #else
812     /* Getting the expected file size needs help on VMS */
813 #define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
814 #endif
815
816 /*
817  * AddFormData() adds a chunk of data to the FormData linked list.
818  *
819  * size is incremented by the chunk length, unless it is NULL
820  */
821 static CURLcode AddFormData(struct FormData **formp,
822                             enum formtype type,
823                             const void *line,
824                             curl_off_t length,
825                             curl_off_t *size)
826 {
827   struct FormData *newform;
828   char *alloc2 = NULL;
829   CURLcode result = CURLE_OK;
830   if(length < 0 || (size && *size < 0))
831     return CURLE_BAD_FUNCTION_ARGUMENT;
832
833   newform = malloc(sizeof(struct FormData));
834   if(!newform)
835     return CURLE_OUT_OF_MEMORY;
836   newform->next = NULL;
837
838   if(type <= FORM_CONTENT) {
839     /* we make it easier for plain strings: */
840     if(!length)
841       length = strlen((char *)line);
842 #if (SIZEOF_SIZE_T < CURL_SIZEOF_CURL_OFF_T)
843     else if(length >= (curl_off_t)(size_t)-1) {
844       result = CURLE_BAD_FUNCTION_ARGUMENT;
845       goto error;
846     }
847 #endif
848
849     newform->line = malloc((size_t)length+1);
850     if(!newform->line) {
851       result = CURLE_OUT_OF_MEMORY;
852       goto error;
853     }
854     alloc2 = newform->line;
855     memcpy(newform->line, line, (size_t)length);
856     newform->length = (size_t)length;
857     newform->line[(size_t)length]=0; /* zero terminate for easier debugging */
858   }
859   else
860     /* For callbacks and files we don't have any actual data so we just keep a
861        pointer to whatever this points to */
862     newform->line = (char *)line;
863
864   newform->type = type;
865
866   if(*formp) {
867     (*formp)->next = newform;
868     *formp = newform;
869   }
870   else
871     *formp = newform;
872
873   if(size) {
874     if(type != FORM_FILE)
875       /* for static content as well as callback data we add the size given
876          as input argument */
877       *size += length;
878     else {
879       /* Since this is a file to be uploaded here, add the size of the actual
880          file */
881       if(!strequal("-", newform->line)) {
882         struct_stat file;
883         if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode))
884           *size += filesize(newform->line, file);
885         else {
886           result = CURLE_BAD_FUNCTION_ARGUMENT;
887           goto error;
888         }
889       }
890     }
891   }
892   return CURLE_OK;
893   error:
894   if(newform)
895     free(newform);
896   if(alloc2)
897     free(alloc2);
898   return result;
899 }
900
901 /*
902  * AddFormDataf() adds printf()-style formatted data to the formdata chain.
903  */
904
905 static CURLcode AddFormDataf(struct FormData **formp,
906                              curl_off_t *size,
907                              const char *fmt, ...)
908 {
909   char s[4096];
910   va_list ap;
911   va_start(ap, fmt);
912   vsnprintf(s, sizeof(s), fmt, ap);
913   va_end(ap);
914
915   return AddFormData(formp, FORM_DATA, s, 0, size);
916 }
917
918 /*
919  * Curl_formclean() is used from http.c, this cleans a built FormData linked
920  * list
921  */
922 void Curl_formclean(struct FormData **form_ptr)
923 {
924   struct FormData *next, *form;
925
926   form = *form_ptr;
927   if(!form)
928     return;
929
930   do {
931     next=form->next;  /* the following form line */
932     if(form->type <= FORM_CONTENT)
933       free(form->line); /* free the line */
934     free(form);       /* free the struct */
935
936   } while((form = next) != NULL); /* continue */
937
938   *form_ptr = NULL;
939 }
940
941 /*
942  * curl_formget()
943  * Serialize a curl_httppost struct.
944  * Returns 0 on success.
945  *
946  * @unittest: 1308
947  */
948 int curl_formget(struct curl_httppost *form, void *arg,
949                  curl_formget_callback append)
950 {
951   CURLcode result;
952   curl_off_t size;
953   struct FormData *data, *ptr;
954
955   result = Curl_getformdata(NULL, &data, form, NULL, &size);
956   if(result)
957     return (int)result;
958
959   for(ptr = data; ptr; ptr = ptr->next) {
960     if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) {
961       char buffer[8192];
962       size_t nread;
963       struct Form temp;
964
965       Curl_FormInit(&temp, ptr);
966
967       do {
968         nread = readfromfile(&temp, buffer, sizeof(buffer));
969         if((nread == (size_t) -1) ||
970            (nread > sizeof(buffer)) ||
971            (nread != append(arg, buffer, nread))) {
972           if(temp.fp)
973             fclose(temp.fp);
974           Curl_formclean(&data);
975           return -1;
976         }
977       } while(nread);
978     }
979     else {
980       if(ptr->length != append(arg, ptr->line, ptr->length)) {
981         Curl_formclean(&data);
982         return -1;
983       }
984     }
985   }
986   Curl_formclean(&data);
987   return 0;
988 }
989
990 /*
991  * curl_formfree() is an external function to free up a whole form post
992  * chain
993  */
994 void curl_formfree(struct curl_httppost *form)
995 {
996   struct curl_httppost *next;
997
998   if(!form)
999     /* no form to free, just get out of this */
1000     return;
1001
1002   do {
1003     next=form->next;  /* the following form line */
1004
1005     /* recurse to sub-contents */
1006     curl_formfree(form->more);
1007
1008     if(!(form->flags & HTTPPOST_PTRNAME))
1009       free(form->name); /* free the name */
1010     if(!(form->flags &
1011          (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
1012       )
1013       free(form->contents); /* free the contents */
1014     free(form->contenttype); /* free the content type */
1015     free(form->showfilename); /* free the faked file name */
1016     free(form);       /* free the struct */
1017
1018   } while((form = next) != NULL); /* continue */
1019 }
1020
1021 #ifndef HAVE_BASENAME
1022 /*
1023   (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
1024   Edition)
1025
1026   The basename() function shall take the pathname pointed to by path and
1027   return a pointer to the final component of the pathname, deleting any
1028   trailing '/' characters.
1029
1030   If the string pointed to by path consists entirely of the '/' character,
1031   basename() shall return a pointer to the string "/". If the string pointed
1032   to by path is exactly "//", it is implementation-defined whether '/' or "//"
1033   is returned.
1034
1035   If path is a null pointer or points to an empty string, basename() shall
1036   return a pointer to the string ".".
1037
1038   The basename() function may modify the string pointed to by path, and may
1039   return a pointer to static storage that may then be overwritten by a
1040   subsequent call to basename().
1041
1042   The basename() function need not be reentrant. A function that is not
1043   required to be reentrant is not required to be thread-safe.
1044
1045 */
1046 static char *Curl_basename(char *path)
1047 {
1048   /* Ignore all the details above for now and make a quick and simple
1049      implementaion here */
1050   char *s1;
1051   char *s2;
1052
1053   s1=strrchr(path, '/');
1054   s2=strrchr(path, '\\');
1055
1056   if(s1 && s2) {
1057     path = (s1 > s2? s1 : s2)+1;
1058   }
1059   else if(s1)
1060     path = s1 + 1;
1061   else if(s2)
1062     path = s2 + 1;
1063
1064   return path;
1065 }
1066 #endif
1067
1068 static char *strippath(const char *fullfile)
1069 {
1070   char *filename;
1071   char *base;
1072   filename = strdup(fullfile); /* duplicate since basename() may ruin the
1073                                   buffer it works on */
1074   if(!filename)
1075     return NULL;
1076   base = strdup(basename(filename));
1077
1078   free(filename); /* free temporary buffer */
1079
1080   return base; /* returns an allocated string or NULL ! */
1081 }
1082
1083 static CURLcode formdata_add_filename(const struct curl_httppost *file,
1084                                       struct FormData **form,
1085                                       curl_off_t *size)
1086 {
1087   CURLcode result = CURLE_OK;
1088   char *filename = file->showfilename;
1089   char *filebasename = NULL;
1090   char *filename_escaped = NULL;
1091
1092   if(!filename) {
1093     filebasename = strippath(file->contents);
1094     if(!filebasename)
1095       return CURLE_OUT_OF_MEMORY;
1096     filename = filebasename;
1097   }
1098
1099   if(strchr(filename, '\\') || strchr(filename, '"')) {
1100     char *p0, *p1;
1101
1102     /* filename need be escaped */
1103     filename_escaped = malloc(strlen(filename)*2+1);
1104     if(!filename_escaped) {
1105       free(filebasename);
1106       return CURLE_OUT_OF_MEMORY;
1107     }
1108     p0 = filename_escaped;
1109     p1 = filename;
1110     while(*p1) {
1111       if(*p1 == '\\' || *p1 == '"')
1112         *p0++ = '\\';
1113       *p0++ = *p1++;
1114     }
1115     *p0 = '\0';
1116     filename = filename_escaped;
1117   }
1118   result = AddFormDataf(form, size,
1119                         "; filename=\"%s\"",
1120                         filename);
1121   free(filename_escaped);
1122   free(filebasename);
1123   return result;
1124 }
1125
1126 /*
1127  * Curl_getformdata() converts a linked list of "meta data" into a complete
1128  * (possibly huge) multipart formdata. The input list is in 'post', while the
1129  * output resulting linked lists gets stored in '*finalform'. *sizep will get
1130  * the total size of the whole POST.
1131  * A multipart/form_data content-type is built, unless a custom content-type
1132  * is passed in 'custom_content_type'.
1133  *
1134  * This function will not do a failf() for the potential memory failures but
1135  * should for all other errors it spots. Just note that this function MAY get
1136  * a NULL pointer in the 'data' argument.
1137  */
1138
1139 CURLcode Curl_getformdata(struct Curl_easy *data,
1140                           struct FormData **finalform,
1141                           struct curl_httppost *post,
1142                           const char *custom_content_type,
1143                           curl_off_t *sizep)
1144 {
1145   struct FormData *form = NULL;
1146   struct FormData *firstform;
1147   struct curl_httppost *file;
1148   CURLcode result = CURLE_OK;
1149
1150   curl_off_t size = 0; /* support potentially ENORMOUS formposts */
1151   char *boundary;
1152   char *fileboundary = NULL;
1153   struct curl_slist* curList;
1154
1155   *finalform = NULL; /* default form is empty */
1156
1157   if(!post)
1158     return result; /* no input => no output! */
1159
1160   boundary = formboundary(data);
1161   if(!boundary)
1162     return CURLE_OUT_OF_MEMORY;
1163
1164   /* Make the first line of the output */
1165   result = AddFormDataf(&form, NULL,
1166                         "%s; boundary=%s\r\n",
1167                         custom_content_type?custom_content_type:
1168                         "Content-Type: multipart/form-data",
1169                         boundary);
1170
1171   if(result) {
1172     free(boundary);
1173     return result;
1174   }
1175   /* we DO NOT include that line in the total size of the POST, since it'll be
1176      part of the header! */
1177
1178   firstform = form;
1179
1180   do {
1181
1182     if(size) {
1183       result = AddFormDataf(&form, &size, "\r\n");
1184       if(result)
1185         break;
1186     }
1187
1188     /* boundary */
1189     result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
1190     if(result)
1191       break;
1192
1193     /* Maybe later this should be disabled when a custom_content_type is
1194        passed, since Content-Disposition is not meaningful for all multipart
1195        types.
1196     */
1197     result = AddFormDataf(&form, &size,
1198                           "Content-Disposition: form-data; name=\"");
1199     if(result)
1200       break;
1201
1202     result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
1203                          &size);
1204     if(result)
1205       break;
1206
1207     result = AddFormDataf(&form, &size, "\"");
1208     if(result)
1209       break;
1210
1211     if(post->more) {
1212       /* If used, this is a link to more file names, we must then do
1213          the magic to include several files with the same field name */
1214
1215       free(fileboundary);
1216       fileboundary = formboundary(data);
1217       if(!fileboundary) {
1218         result = CURLE_OUT_OF_MEMORY;
1219         break;
1220       }
1221
1222       result = AddFormDataf(&form, &size,
1223                             "\r\nContent-Type: multipart/mixed;"
1224                             " boundary=%s\r\n",
1225                             fileboundary);
1226       if(result)
1227         break;
1228     }
1229
1230     file = post;
1231
1232     do {
1233
1234       /* If 'showfilename' is set, that is a faked name passed on to us
1235          to use to in the formpost. If that is not set, the actually used
1236          local file name should be added. */
1237
1238       if(post->more) {
1239         /* if multiple-file */
1240         result = AddFormDataf(&form, &size,
1241                               "\r\n--%s\r\nContent-Disposition: "
1242                               "attachment",
1243                               fileboundary);
1244         if(result)
1245           break;
1246         result = formdata_add_filename(file, &form, &size);
1247         if(result)
1248           break;
1249       }
1250       else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
1251                              HTTPPOST_CALLBACK)) {
1252         /* it should be noted that for the HTTPPOST_FILENAME and
1253            HTTPPOST_CALLBACK cases the ->showfilename struct member is always
1254            assigned at this point */
1255         if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) {
1256           result = formdata_add_filename(post, &form, &size);
1257         }
1258
1259         if(result)
1260           break;
1261       }
1262
1263       if(file->contenttype) {
1264         /* we have a specified type */
1265         result = AddFormDataf(&form, &size,
1266                               "\r\nContent-Type: %s",
1267                               file->contenttype);
1268         if(result)
1269           break;
1270       }
1271
1272       curList = file->contentheader;
1273       while(curList) {
1274         /* Process the additional headers specified for this form */
1275         result = AddFormDataf(&form, &size, "\r\n%s", curList->data);
1276         if(result)
1277           break;
1278         curList = curList->next;
1279       }
1280       if(result)
1281         break;
1282
1283       result = AddFormDataf(&form, &size, "\r\n\r\n");
1284       if(result)
1285         break;
1286
1287       if((post->flags & HTTPPOST_FILENAME) ||
1288          (post->flags & HTTPPOST_READFILE)) {
1289         /* we should include the contents from the specified file */
1290         FILE *fileread;
1291
1292         fileread = strequal("-", file->contents)?
1293           stdin:fopen(file->contents, "rb"); /* binary read for win32  */
1294
1295         /*
1296          * VMS: This only allows for stream files on VMS.  Stream files are
1297          * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
1298          * every record needs to have a \n appended & 1 added to SIZE
1299          */
1300
1301         if(fileread) {
1302           if(fileread != stdin) {
1303             /* close the file */
1304             fclose(fileread);
1305             /* add the file name only - for later reading from this */
1306             result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
1307           }
1308           else {
1309             /* When uploading from stdin, we can't know the size of the file,
1310              * thus must read the full file as before. We *could* use chunked
1311              * transfer-encoding, but that only works for HTTP 1.1 and we
1312              * can't be sure we work with such a server.
1313              */
1314             size_t nread;
1315             char buffer[512];
1316             while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
1317               result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
1318               if(result)
1319                 break;
1320             }
1321           }
1322         }
1323         else {
1324           if(data)
1325             failf(data, "couldn't open file \"%s\"", file->contents);
1326           *finalform = NULL;
1327           result = CURLE_READ_ERROR;
1328         }
1329       }
1330       else if(post->flags & HTTPPOST_BUFFER)
1331         /* include contents of buffer */
1332         result = AddFormData(&form, FORM_CONTENT, post->buffer,
1333                              post->bufferlength, &size);
1334       else if(post->flags & HTTPPOST_CALLBACK)
1335         /* the contents should be read with the callback and the size is set
1336            with the contentslength */
1337         result = AddFormData(&form, FORM_CALLBACK, post->userp,
1338                              post->flags&CURL_HTTPPOST_LARGE?
1339                              post->contentlen:post->contentslength, &size);
1340       else
1341         /* include the contents we got */
1342         result = AddFormData(&form, FORM_CONTENT, post->contents,
1343                              post->flags&CURL_HTTPPOST_LARGE?
1344                              post->contentlen:post->contentslength, &size);
1345       file = file->more;
1346     } while(file && !result); /* for each specified file for this field */
1347
1348     if(result)
1349       break;
1350
1351     if(post->more) {
1352       /* this was a multiple-file inclusion, make a termination file
1353          boundary: */
1354       result = AddFormDataf(&form, &size,
1355                            "\r\n--%s--",
1356                            fileboundary);
1357       if(result)
1358         break;
1359     }
1360
1361   } while((post = post->next) != NULL); /* for each field */
1362
1363   /* end-boundary for everything */
1364   if(!result)
1365     result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary);
1366
1367   if(result) {
1368     Curl_formclean(&firstform);
1369     free(fileboundary);
1370     free(boundary);
1371     return result;
1372   }
1373
1374   *sizep = size;
1375
1376   free(fileboundary);
1377   free(boundary);
1378
1379   *finalform = firstform;
1380
1381   return result;
1382 }
1383
1384 /*
1385  * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
1386  * and resets the 'sent' counter.
1387  */
1388 int Curl_FormInit(struct Form *form, struct FormData *formdata)
1389 {
1390   if(!formdata)
1391     return 1; /* error */
1392
1393   form->data = formdata;
1394   form->sent = 0;
1395   form->fp = NULL;
1396   form->fread_func = ZERO_NULL;
1397
1398   return 0;
1399 }
1400
1401 #ifndef __VMS
1402 # define fopen_read fopen
1403 #else
1404   /*
1405    * vmsfopenread
1406    *
1407    * For upload to work as expected on VMS, different optional
1408    * parameters must be added to the fopen command based on
1409    * record format of the file.
1410    *
1411    */
1412 # define fopen_read vmsfopenread
1413 static FILE * vmsfopenread(const char *file, const char *mode) {
1414   struct_stat statbuf;
1415   int result;
1416
1417   result = stat(file, &statbuf);
1418
1419   switch (statbuf.st_fab_rfm) {
1420   case FAB$C_VAR:
1421   case FAB$C_VFC:
1422   case FAB$C_STMCR:
1423     return fopen(file, FOPEN_READTEXT); /* VMS */
1424     break;
1425   default:
1426     return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
1427   }
1428 }
1429 #endif
1430
1431 /*
1432  * readfromfile()
1433  *
1434  * The read callback that this function may use can return a value larger than
1435  * 'size' (which then this function returns) that indicates a problem and it
1436  * must be properly dealt with
1437  */
1438 static size_t readfromfile(struct Form *form, char *buffer,
1439                            size_t size)
1440 {
1441   size_t nread;
1442   bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE;
1443
1444   if(callback) {
1445     if(form->fread_func == ZERO_NULL)
1446       return 0;
1447     else
1448       nread = form->fread_func(buffer, 1, size, form->data->line);
1449   }
1450   else {
1451     if(!form->fp) {
1452       /* this file hasn't yet been opened */
1453       form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
1454       if(!form->fp)
1455         return (size_t)-1; /* failure */
1456     }
1457     nread = fread(buffer, 1, size, form->fp);
1458   }
1459   if(!nread) {
1460     /* this is the last chunk from the file, move on */
1461     if(form->fp) {
1462       fclose(form->fp);
1463       form->fp = NULL;
1464     }
1465     form->data = form->data->next;
1466   }
1467
1468   return nread;
1469 }
1470
1471 /*
1472  * Curl_FormReader() is the fread() emulation function that will be used to
1473  * deliver the formdata to the transfer loop and then sent away to the peer.
1474  */
1475 size_t Curl_FormReader(char *buffer,
1476                        size_t size,
1477                        size_t nitems,
1478                        FILE *mydata)
1479 {
1480   struct Form *form;
1481   size_t wantedsize;
1482   size_t gotsize = 0;
1483
1484   form=(struct Form *)mydata;
1485
1486   wantedsize = size * nitems;
1487
1488   if(!form->data)
1489     return 0; /* nothing, error, empty */
1490
1491   if((form->data->type == FORM_FILE) ||
1492      (form->data->type == FORM_CALLBACK)) {
1493     gotsize = readfromfile(form, buffer, wantedsize);
1494
1495     if(gotsize)
1496       /* If positive or -1, return. If zero, continue! */
1497       return gotsize;
1498   }
1499   do {
1500
1501     if((form->data->length - form->sent) > wantedsize - gotsize) {
1502
1503       memcpy(buffer + gotsize, form->data->line + form->sent,
1504              wantedsize - gotsize);
1505
1506       form->sent += wantedsize-gotsize;
1507
1508       return wantedsize;
1509     }
1510
1511     memcpy(buffer+gotsize,
1512            form->data->line + form->sent,
1513            (form->data->length - form->sent) );
1514     gotsize += form->data->length - form->sent;
1515
1516     form->sent = 0;
1517
1518     form->data = form->data->next; /* advance */
1519
1520   } while(form->data && (form->data->type < FORM_CALLBACK));
1521   /* If we got an empty line and we have more data, we proceed to the next
1522      line immediately to avoid returning zero before we've reached the end. */
1523
1524   return gotsize;
1525 }
1526
1527 /*
1528  * Curl_formpostheader() returns the first line of the formpost, the
1529  * request-header part (which is not part of the request-body like the rest of
1530  * the post).
1531  */
1532 char *Curl_formpostheader(void *formp, size_t *len)
1533 {
1534   char *header;
1535   struct Form *form=(struct Form *)formp;
1536
1537   if(!form->data)
1538     return 0; /* nothing, ERROR! */
1539
1540   header = form->data->line;
1541   *len = form->data->length;
1542
1543   form->data = form->data->next; /* advance */
1544
1545   return header;
1546 }
1547
1548 /*
1549  * formboundary() creates a suitable boundary string and returns an allocated
1550  * one.
1551  */
1552 static char *formboundary(struct Curl_easy *data)
1553 {
1554   /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
1555      combinations */
1556   return aprintf("------------------------%08x%08x",
1557                  Curl_rand(data), Curl_rand(data));
1558 }
1559
1560 #else  /* CURL_DISABLE_HTTP */
1561 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
1562                           struct curl_httppost **last_post,
1563                           ...)
1564 {
1565   (void)httppost;
1566   (void)last_post;
1567   return CURL_FORMADD_DISABLED;
1568 }
1569
1570 int curl_formget(struct curl_httppost *form, void *arg,
1571                  curl_formget_callback append)
1572 {
1573   (void) form;
1574   (void) arg;
1575   (void) append;
1576   return CURL_FORMADD_DISABLED;
1577 }
1578
1579 void curl_formfree(struct curl_httppost *form)
1580 {
1581   (void)form;
1582   /* does nothing HTTP is disabled */
1583 }
1584
1585
1586 #endif  /* !defined(CURL_DISABLE_HTTP) */