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