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