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