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