f718a3e4e9c070cd1b337203ed086c9a38998de0
[platform/upstream/curl.git] / lib / formdata.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2013, 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 "sslgen.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       return CURLE_OUT_OF_MEMORY;
1115     p0 = filename_escaped;
1116     p1 = filename;
1117     while(*p1) {
1118       if(*p1 == '\\' || *p1 == '"')
1119         *p0++ = '\\';
1120       *p0++ = *p1++;
1121     }
1122     *p0 = '\0';
1123     filename = filename_escaped;
1124   }
1125   result = AddFormDataf(form, size,
1126                         "; filename=\"%s\"",
1127                         filename);
1128   Curl_safefree(filename_escaped);
1129   Curl_safefree(filebasename);
1130   return result;
1131 }
1132
1133 /*
1134  * Curl_getformdata() converts a linked list of "meta data" into a complete
1135  * (possibly huge) multipart formdata. The input list is in 'post', while the
1136  * output resulting linked lists gets stored in '*finalform'. *sizep will get
1137  * the total size of the whole POST.
1138  * A multipart/form_data content-type is built, unless a custom content-type
1139  * is passed in 'custom_content_type'.
1140  *
1141  * This function will not do a failf() for the potential memory failures but
1142  * should for all other errors it spots. Just note that this function MAY get
1143  * a NULL pointer in the 'data' argument.
1144  */
1145
1146 CURLcode Curl_getformdata(struct SessionHandle *data,
1147                           struct FormData **finalform,
1148                           struct curl_httppost *post,
1149                           const char *custom_content_type,
1150                           curl_off_t *sizep)
1151 {
1152   struct FormData *form = NULL;
1153   struct FormData *firstform;
1154   struct curl_httppost *file;
1155   CURLcode result = CURLE_OK;
1156
1157   curl_off_t size = 0; /* support potentially ENORMOUS formposts */
1158   char *boundary;
1159   char *fileboundary = NULL;
1160   struct curl_slist* curList;
1161
1162   *finalform = NULL; /* default form is empty */
1163
1164   if(!post)
1165     return result; /* no input => no output! */
1166
1167   boundary = formboundary(data);
1168   if(!boundary)
1169     return CURLE_OUT_OF_MEMORY;
1170
1171   /* Make the first line of the output */
1172   result = AddFormDataf(&form, NULL,
1173                         "%s; boundary=%s\r\n",
1174                         custom_content_type?custom_content_type:
1175                         "Content-Type: multipart/form-data",
1176                         boundary);
1177
1178   if(result) {
1179     Curl_safefree(boundary);
1180     return result;
1181   }
1182   /* we DO NOT include that line in the total size of the POST, since it'll be
1183      part of the header! */
1184
1185   firstform = form;
1186
1187   do {
1188
1189     if(size) {
1190       result = AddFormDataf(&form, &size, "\r\n");
1191       if(result)
1192         break;
1193     }
1194
1195     /* boundary */
1196     result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
1197     if(result)
1198       break;
1199
1200     /* Maybe later this should be disabled when a custom_content_type is
1201        passed, since Content-Disposition is not meaningful for all multipart
1202        types.
1203     */
1204     result = AddFormDataf(&form, &size,
1205                           "Content-Disposition: form-data; name=\"");
1206     if(result)
1207       break;
1208
1209     result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
1210                          &size);
1211     if(result)
1212       break;
1213
1214     result = AddFormDataf(&form, &size, "\"");
1215     if(result)
1216       break;
1217
1218     if(post->more) {
1219       /* If used, this is a link to more file names, we must then do
1220          the magic to include several files with the same field name */
1221
1222       Curl_safefree(fileboundary);
1223       fileboundary = formboundary(data);
1224       if(!fileboundary) {
1225         result = CURLE_OUT_OF_MEMORY;
1226         break;
1227       }
1228
1229       result = AddFormDataf(&form, &size,
1230                             "\r\nContent-Type: multipart/mixed,"
1231                             " boundary=%s\r\n",
1232                             fileboundary);
1233       if(result)
1234         break;
1235     }
1236
1237     file = post;
1238
1239     do {
1240
1241       /* If 'showfilename' is set, that is a faked name passed on to us
1242          to use to in the formpost. If that is not set, the actually used
1243          local file name should be added. */
1244
1245       if(post->more) {
1246         /* if multiple-file */
1247         result = AddFormDataf(&form, &size,
1248                               "\r\n--%s\r\nContent-Disposition: "
1249                               "attachment",
1250                               fileboundary);
1251         if(result)
1252           break;
1253         result = formdata_add_filename(file, &form, &size);
1254         if(result)
1255           break;
1256       }
1257       else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
1258                              HTTPPOST_CALLBACK)) {
1259         /* it should be noted that for the HTTPPOST_FILENAME and
1260            HTTPPOST_CALLBACK cases the ->showfilename struct member is always
1261            assigned at this point */
1262         if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) {
1263           result = formdata_add_filename(post, &form, &size);
1264         }
1265
1266         if(result)
1267           break;
1268       }
1269
1270       if(file->contenttype) {
1271         /* we have a specified type */
1272         result = AddFormDataf(&form, &size,
1273                               "\r\nContent-Type: %s",
1274                               file->contenttype);
1275         if(result)
1276           break;
1277       }
1278
1279       curList = file->contentheader;
1280       while(curList) {
1281         /* Process the additional headers specified for this form */
1282         result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
1283         if(result)
1284           break;
1285         curList = curList->next;
1286       }
1287       if(result)
1288         break;
1289
1290       result = AddFormDataf(&form, &size, "\r\n\r\n");
1291       if(result)
1292         break;
1293
1294       if((post->flags & HTTPPOST_FILENAME) ||
1295          (post->flags & HTTPPOST_READFILE)) {
1296         /* we should include the contents from the specified file */
1297         FILE *fileread;
1298
1299         fileread = strequal("-", file->contents)?
1300           stdin:fopen(file->contents, "rb"); /* binary read for win32  */
1301
1302         /*
1303          * VMS: This only allows for stream files on VMS.  Stream files are
1304          * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
1305          * every record needs to have a \n appended & 1 added to SIZE
1306          */
1307
1308         if(fileread) {
1309           if(fileread != stdin) {
1310             /* close the file */
1311             fclose(fileread);
1312             /* add the file name only - for later reading from this */
1313             result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
1314           }
1315           else {
1316             /* When uploading from stdin, we can't know the size of the file,
1317              * thus must read the full file as before. We *could* use chunked
1318              * transfer-encoding, but that only works for HTTP 1.1 and we
1319              * can't be sure we work with such a server.
1320              */
1321             size_t nread;
1322             char buffer[512];
1323             while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
1324               result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
1325               if(result)
1326                 break;
1327             }
1328           }
1329         }
1330         else {
1331           if(data)
1332             failf(data, "couldn't open file \"%s\"", file->contents);
1333           *finalform = NULL;
1334           result = CURLE_READ_ERROR;
1335         }
1336       }
1337       else if(post->flags & HTTPPOST_BUFFER)
1338         /* include contents of buffer */
1339         result = AddFormData(&form, FORM_CONTENT, post->buffer,
1340                              post->bufferlength, &size);
1341       else if(post->flags & HTTPPOST_CALLBACK)
1342         /* the contents should be read with the callback and the size
1343            is set with the contentslength */
1344         result = AddFormData(&form, FORM_CALLBACK, post->userp,
1345                              post->contentslength, &size);
1346       else
1347         /* include the contents we got */
1348         result = AddFormData(&form, FORM_CONTENT, post->contents,
1349                              post->contentslength, &size);
1350
1351       file = file->more;
1352     } while(file && !result); /* for each specified file for this field */
1353
1354     if(result)
1355       break;
1356
1357     if(post->more) {
1358       /* this was a multiple-file inclusion, make a termination file
1359          boundary: */
1360       result = AddFormDataf(&form, &size,
1361                            "\r\n--%s--",
1362                            fileboundary);
1363       if(result)
1364         break;
1365     }
1366
1367   } while((post = post->next) != NULL); /* for each field */
1368
1369   /* end-boundary for everything */
1370   if(CURLE_OK == result)
1371     result = AddFormDataf(&form, &size,
1372                           "\r\n--%s--\r\n",
1373                           boundary);
1374
1375   if(result) {
1376     Curl_formclean(&firstform);
1377     Curl_safefree(fileboundary);
1378     Curl_safefree(boundary);
1379     return result;
1380   }
1381
1382   *sizep = size;
1383
1384   Curl_safefree(fileboundary);
1385   Curl_safefree(boundary);
1386
1387   *finalform = firstform;
1388
1389   return result;
1390 }
1391
1392 /*
1393  * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
1394  * and resets the 'sent' counter.
1395  */
1396 int Curl_FormInit(struct Form *form, struct FormData *formdata )
1397 {
1398   if(!formdata)
1399     return 1; /* error */
1400
1401   form->data = formdata;
1402   form->sent = 0;
1403   form->fp = NULL;
1404   form->fread_func = ZERO_NULL;
1405
1406   return 0;
1407 }
1408
1409 #ifndef __VMS
1410 # define fopen_read fopen
1411 #else
1412   /*
1413    * vmsfopenread
1414    *
1415    * For upload to work as expected on VMS, different optional
1416    * parameters must be added to the fopen command based on
1417    * record format of the file.
1418    *
1419    */
1420 # define fopen_read vmsfopenread
1421 static FILE * vmsfopenread(const char *file, const char *mode) {
1422   struct_stat statbuf;
1423   int result;
1424
1425   result = stat(file, &statbuf);
1426
1427   switch (statbuf.st_fab_rfm) {
1428   case FAB$C_VAR:
1429   case FAB$C_VFC:
1430   case FAB$C_STMCR:
1431     return fopen(file, "r");
1432     break;
1433   default:
1434     return fopen(file, "r", "rfm=stmlf", "ctx=stm");
1435   }
1436 }
1437 #endif
1438
1439 /*
1440  * readfromfile()
1441  *
1442  * The read callback that this function may use can return a value larger than
1443  * 'size' (which then this function returns) that indicates a problem and it
1444  * must be properly dealt with
1445  */
1446 static size_t readfromfile(struct Form *form, char *buffer,
1447                            size_t size)
1448 {
1449   size_t nread;
1450   bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE;
1451
1452   if(callback) {
1453     if(form->fread_func == ZERO_NULL)
1454       return 0;
1455     else
1456       nread = form->fread_func(buffer, 1, size, form->data->line);
1457   }
1458   else {
1459     if(!form->fp) {
1460       /* this file hasn't yet been opened */
1461       form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
1462       if(!form->fp)
1463         return (size_t)-1; /* failure */
1464     }
1465     nread = fread(buffer, 1, size, form->fp);
1466   }
1467   if(!nread) {
1468     /* this is the last chunk from the file, move on */
1469     if(form->fp) {
1470       fclose(form->fp);
1471       form->fp = NULL;
1472     }
1473     form->data = form->data->next;
1474   }
1475
1476   return nread;
1477 }
1478
1479 /*
1480  * Curl_FormReader() is the fread() emulation function that will be used to
1481  * deliver the formdata to the transfer loop and then sent away to the peer.
1482  */
1483 size_t Curl_FormReader(char *buffer,
1484                        size_t size,
1485                        size_t nitems,
1486                        FILE *mydata)
1487 {
1488   struct Form *form;
1489   size_t wantedsize;
1490   size_t gotsize = 0;
1491
1492   form=(struct Form *)mydata;
1493
1494   wantedsize = size * nitems;
1495
1496   if(!form->data)
1497     return 0; /* nothing, error, empty */
1498
1499   if((form->data->type == FORM_FILE) ||
1500      (form->data->type == FORM_CALLBACK)) {
1501     gotsize = readfromfile(form, buffer, wantedsize);
1502
1503     if(gotsize)
1504       /* If positive or -1, return. If zero, continue! */
1505       return gotsize;
1506   }
1507   do {
1508
1509     if((form->data->length - form->sent ) > wantedsize - gotsize) {
1510
1511       memcpy(buffer + gotsize , form->data->line + form->sent,
1512              wantedsize - gotsize);
1513
1514       form->sent += wantedsize-gotsize;
1515
1516       return wantedsize;
1517     }
1518
1519     memcpy(buffer+gotsize,
1520            form->data->line + form->sent,
1521            (form->data->length - form->sent) );
1522     gotsize += form->data->length - form->sent;
1523
1524     form->sent = 0;
1525
1526     form->data = form->data->next; /* advance */
1527
1528   } while(form->data && (form->data->type < FORM_CALLBACK));
1529   /* If we got an empty line and we have more data, we proceed to the next
1530      line immediately to avoid returning zero before we've reached the end. */
1531
1532   return gotsize;
1533 }
1534
1535 /*
1536  * Curl_formpostheader() returns the first line of the formpost, the
1537  * request-header part (which is not part of the request-body like the rest of
1538  * the post).
1539  */
1540 char *Curl_formpostheader(void *formp, size_t *len)
1541 {
1542   char *header;
1543   struct Form *form=(struct Form *)formp;
1544
1545   if(!form->data)
1546     return 0; /* nothing, ERROR! */
1547
1548   header = form->data->line;
1549   *len = form->data->length;
1550
1551   form->data = form->data->next; /* advance */
1552
1553   return header;
1554 }
1555
1556 /*
1557  * formboundary() creates a suitable boundary string and returns an allocated
1558  * one.
1559  */
1560 static char *formboundary(struct SessionHandle *data)
1561 {
1562   /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
1563      combinations */
1564   return aprintf("------------------------%08x%08x",
1565                  Curl_rand(data), Curl_rand(data));
1566 }
1567
1568 #else  /* CURL_DISABLE_HTTP */
1569 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
1570                           struct curl_httppost **last_post,
1571                           ...)
1572 {
1573   (void)httppost;
1574   (void)last_post;
1575   return CURL_FORMADD_DISABLED;
1576 }
1577
1578 int curl_formget(struct curl_httppost *form, void *arg,
1579                  curl_formget_callback append)
1580 {
1581   (void) form;
1582   (void) arg;
1583   (void) append;
1584   return CURL_FORMADD_DISABLED;
1585 }
1586
1587 void curl_formfree(struct curl_httppost *form)
1588 {
1589   (void)form;
1590   /* does nothing HTTP is disabled */
1591 }
1592
1593
1594 #endif  /* !defined(CURL_DISABLE_HTTP) */