bf00a40ac5f72fb24e32c247c8a5d4fd0191b111
[platform/upstream/curl.git] / lib / formdata.c
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$
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="inet_ntoa_r.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="inet_ntoa_r.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="inet_ntoa_r.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="inet_ntoa_r.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="inet_ntoa_r.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="inet_ntoa_r.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 *
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 = (struct curl_httppost *)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  ***************************************************************************/
220 static FormInfo * AddFormInfo(char *value,
221                               char *contenttype,
222                               FormInfo *parent_form_info)
223 {
224   FormInfo *form_info;
225   form_info = (FormInfo *)malloc(sizeof(FormInfo));
226   if(form_info) {
227     memset(form_info, 0, sizeof(FormInfo));
228     if(value)
229       form_info->value = value;
230     if(contenttype)
231       form_info->contenttype = contenttype;
232     form_info->flags = HTTPPOST_FILENAME;
233   }
234   else
235     return NULL;
236
237   if(parent_form_info) {
238     /* now, point our 'more' to the original 'more' */
239     form_info->more = parent_form_info->more;
240
241     /* then move the original 'more' to point to ourselves */
242     parent_form_info->more = form_info;
243   }
244   else
245     return NULL;
246
247   return form_info;
248 }
249
250 /***************************************************************************
251  *
252  * ContentTypeForFilename()
253  *
254  * Provides content type for filename if one of the known types (else
255  * (either the prevtype or the default is returned).
256  *
257  * Returns some valid contenttype for filename.
258  *
259  ***************************************************************************/
260 static const char * ContentTypeForFilename (const char *filename,
261                                             const char *prevtype)
262 {
263   const char *contenttype = NULL;
264   unsigned int i;
265   /*
266    * No type was specified, we scan through a few well-known
267    * extensions and pick the first we match!
268    */
269   struct ContentType {
270     const char *extension;
271     const char *type;
272   };
273   static const struct ContentType ctts[]={
274     {".gif",  "image/gif"},
275     {".jpg",  "image/jpeg"},
276     {".jpeg", "image/jpeg"},
277     {".txt",  "text/plain"},
278     {".html", "text/html"}
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  ***************************************************************************/
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((char *)"");
329
330   buffer = (char*)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
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 = (FormInfo *)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           /* copy name (without strdup; possibly contains null characters) */
747           form->name = memdup(form->name, form->namelength);
748           if(!form->name) {
749             return_value = CURL_FORMADD_MEMORY;
750             break;
751           }
752           form->name_alloc = TRUE;
753         }
754         if( !(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
755                              HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
756                              HTTPPOST_CALLBACK)) ) {
757           /* copy value (without strdup; possibly contains null characters) */
758           form->value = memdup(form->value, form->contentslength);
759           if(!form->value) {
760             return_value = CURL_FORMADD_MEMORY;
761             break;
762           }
763           form->value_alloc = TRUE;
764         }
765         post = AddHttpPost(form->name, form->namelength,
766                            form->value, form->contentslength,
767                            form->buffer, form->bufferlength,
768                            form->contenttype, form->flags,
769                            form->contentheader, form->showfilename,
770                            form->userp,
771                            post, httppost,
772                            last_post);
773
774         if(!post) {
775           return_value = CURL_FORMADD_MEMORY;
776           break;
777         }
778
779         if(form->contenttype)
780           prevtype = form->contenttype;
781       }
782     }
783   }
784
785   if(return_value) {
786     /* we return on error, free possibly allocated fields */
787     if(!form)
788       form = current_form;
789     if(form) {
790       if(form->name_alloc)
791         free(form->name);
792       if(form->value_alloc)
793         free(form->value);
794       if(form->contenttype_alloc)
795         free(form->contenttype);
796       if(form->showfilename_alloc)
797         free(form->showfilename);
798     }
799   }
800
801   /* always delete the allocated memory before returning */
802   form = first_form;
803   while(form != NULL) {
804     FormInfo *delete_form;
805
806     delete_form = form;
807     form = form->more;
808     free (delete_form);
809   }
810
811   return return_value;
812 }
813
814 /*
815  * curl_formadd() is a public API to add a section to the multipart formpost.
816  */
817
818 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
819                           struct curl_httppost **last_post,
820                           ...)
821 {
822   va_list arg;
823   CURLFORMcode result;
824   va_start(arg, last_post);
825   result = FormAdd(httppost, last_post, arg);
826   va_end(arg);
827   return result;
828 }
829
830 /*
831  * AddFormData() adds a chunk of data to the FormData linked list.
832  *
833  * size is incremented by the chunk length, unless it is NULL
834  */
835 static CURLcode AddFormData(struct FormData **formp,
836                             enum formtype type,
837                             const void *line,
838                             size_t length,
839                             curl_off_t *size)
840 {
841   struct FormData *newform = (struct FormData *)
842     malloc(sizeof(struct FormData));
843   if(!newform)
844     return CURLE_OUT_OF_MEMORY;
845   newform->next = NULL;
846
847   if(type <= FORM_CONTENT) {
848     /* we make it easier for plain strings: */
849     if(!length)
850       length = strlen((char *)line);
851
852     newform->line = (char *)malloc(length+1);
853     if(!newform->line) {
854       free(newform);
855       return CURLE_OUT_OF_MEMORY;
856     }
857     memcpy(newform->line, line, length);
858     newform->length = length;
859     newform->line[length]=0; /* zero terminate for easier debugging */
860   }
861   else
862     /* For callbacks and files we don't have any actual data so we just keep a
863        pointer to whatever this points to */
864     newform->line = (char *)line;
865
866   newform->type = type;
867
868   if(*formp) {
869     (*formp)->next = newform;
870     *formp = newform;
871   }
872   else
873     *formp = newform;
874
875   if(size) {
876     if(type != FORM_FILE)
877       /* for static content as well as callback data we add the size given
878          as input argument */
879       *size += length;
880     else {
881       /* Since this is a file to be uploaded here, add the size of the actual
882          file */
883       if(!strequal("-", newform->line)) {
884         struct_stat file;
885         if(!stat(newform->line, &file)) {
886           *size += file.st_size;
887         }
888       }
889     }
890   }
891   return CURLE_OK;
892 }
893
894 /*
895  * AddFormDataf() adds printf()-style formatted data to the formdata chain.
896  */
897
898 static CURLcode AddFormDataf(struct FormData **formp,
899                              curl_off_t *size,
900                              const char *fmt, ...)
901 {
902   char s[4096];
903   va_list ap;
904   va_start(ap, fmt);
905   vsnprintf(s, sizeof(s), fmt, ap);
906   va_end(ap);
907
908   return AddFormData(formp, FORM_DATA, s, 0, size);
909 }
910
911 /*
912  * Curl_formclean() is used from http.c, this cleans a built FormData linked
913  * list
914  */
915 void Curl_formclean(struct FormData **form_ptr)
916 {
917   struct FormData *next, *form;
918
919   form = *form_ptr;
920   if(!form)
921     return;
922
923   do {
924     next=form->next;  /* the following form line */
925     if(form->type <= FORM_CONTENT)
926       free(form->line); /* free the line */
927     free(form);       /* free the struct */
928
929   } while((form = next) != NULL); /* continue */
930
931   *form_ptr = NULL;
932 }
933
934 #ifdef CURL_DOES_CONVERSIONS
935 /*
936  * Curl_formcovert() is used from http.c, this converts any
937    form items that need to be sent in the network encoding.
938    Returns CURLE_OK on success.
939  */
940 CURLcode Curl_formconvert(struct SessionHandle *data, struct FormData *form)
941 {
942   struct FormData *next;
943   CURLcode rc;
944
945   if(!form)
946     return CURLE_OK;
947
948   if(!data)
949     return CURLE_BAD_FUNCTION_ARGUMENT;
950
951   do {
952     next=form->next;  /* the following form line */
953     if(form->type == FORM_DATA) {
954       rc = Curl_convert_to_network(data, form->line, form->length);
955       /* Curl_convert_to_network calls failf if unsuccessful */
956       if(rc != CURLE_OK)
957         return rc;
958     }
959   } while((form = next) != NULL); /* continue */
960   return CURLE_OK;
961 }
962 #endif /* CURL_DOES_CONVERSIONS */
963
964 /*
965  * curl_formget()
966  * Serialize a curl_httppost struct.
967  * Returns 0 on success.
968  */
969 int curl_formget(struct curl_httppost *form, void *arg,
970                  curl_formget_callback append)
971 {
972   CURLcode rc;
973   curl_off_t size;
974   struct FormData *data, *ptr;
975
976   rc = Curl_getFormData(&data, form, NULL, &size);
977   if(rc != CURLE_OK)
978     return (int)rc;
979
980   for (ptr = data; ptr; ptr = ptr->next) {
981     if(ptr->type == FORM_FILE) {
982       char buffer[8192];
983       size_t nread;
984       struct Form temp;
985
986       Curl_FormInit(&temp, ptr);
987
988       do {
989         nread = readfromfile(&temp, buffer, sizeof(buffer));
990         if((nread == (size_t) -1) || (nread != append(arg, buffer, nread))) {
991           if(temp.fp) {
992             fclose(temp.fp);
993           }
994           Curl_formclean(&data);
995           return -1;
996         }
997       } while(nread == sizeof(buffer));
998     } else {
999       if(ptr->length != append(arg, ptr->line, ptr->length)) {
1000         Curl_formclean(&data);
1001         return -1;
1002       }
1003     }
1004   }
1005   Curl_formclean(&data);
1006   return 0;
1007 }
1008
1009 /*
1010  * curl_formfree() is an external function to free up a whole form post
1011  * chain
1012  */
1013 void curl_formfree(struct curl_httppost *form)
1014 {
1015   struct curl_httppost *next;
1016
1017   if(!form)
1018     /* no form to free, just get out of this */
1019     return;
1020
1021   do {
1022     next=form->next;  /* the following form line */
1023
1024     /* recurse to sub-contents */
1025     if(form->more)
1026       curl_formfree(form->more);
1027
1028     if( !(form->flags & HTTPPOST_PTRNAME) && form->name)
1029       free(form->name); /* free the name */
1030     if( !(form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_CALLBACK)) &&
1031         form->contents)
1032       free(form->contents); /* free the contents */
1033     if(form->contenttype)
1034       free(form->contenttype); /* free the content type */
1035     if(form->showfilename)
1036       free(form->showfilename); /* free the faked file name */
1037     free(form);       /* free the struct */
1038
1039   } while((form = next) != NULL); /* continue */
1040 }
1041
1042 #ifndef HAVE_BASENAME
1043 /*
1044   (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
1045   Edition)
1046
1047   The basename() function shall take the pathname pointed to by path and
1048   return a pointer to the final component of the pathname, deleting any
1049   trailing '/' characters.
1050
1051   If the string pointed to by path consists entirely of the '/' character,
1052   basename() shall return a pointer to the string "/". If the string pointed
1053   to by path is exactly "//", it is implementation-defined whether '/' or "//"
1054   is returned.
1055
1056   If path is a null pointer or points to an empty string, basename() shall
1057   return a pointer to the string ".".
1058
1059   The basename() function may modify the string pointed to by path, and may
1060   return a pointer to static storage that may then be overwritten by a
1061   subsequent call to basename().
1062
1063   The basename() function need not be reentrant. A function that is not
1064   required to be reentrant is not required to be thread-safe.
1065
1066 */
1067 static char *basename(char *path)
1068 {
1069   /* Ignore all the details above for now and make a quick and simple
1070      implementaion here */
1071   char *s1;
1072   char *s2;
1073
1074   s1=strrchr(path, '/');
1075   s2=strrchr(path, '\\');
1076
1077   if(s1 && s2) {
1078     path = (s1 > s2? s1 : s2)+1;
1079   }
1080   else if(s1)
1081     path = s1 + 1;
1082   else if(s2)
1083     path = s2 + 1;
1084
1085   return path;
1086 }
1087 #endif
1088
1089 static char *strippath(const char *fullfile)
1090 {
1091   char *filename;
1092   char *base;
1093   filename = strdup(fullfile); /* duplicate since basename() may ruin the
1094                                   buffer it works on */
1095   if(!filename)
1096     return NULL;
1097   base = strdup(basename(filename));
1098
1099   free(filename); /* free temporary buffer */
1100
1101   return base; /* returns an allocated string! */
1102 }
1103
1104 /*
1105  * Curl_getFormData() converts a linked list of "meta data" into a complete
1106  * (possibly huge) multipart formdata. The input list is in 'post', while the
1107  * output resulting linked lists gets stored in '*finalform'. *sizep will get
1108  * the total size of the whole POST.
1109  * A multipart/form_data content-type is built, unless a custom content-type
1110  * is passed in 'custom_content_type'.
1111  */
1112
1113 CURLcode Curl_getFormData(struct FormData **finalform,
1114                           struct curl_httppost *post,
1115                           const char *custom_content_type,
1116                           curl_off_t *sizep)
1117 {
1118   struct FormData *form = NULL;
1119   struct FormData *firstform;
1120   struct curl_httppost *file;
1121   CURLcode result = CURLE_OK;
1122
1123   curl_off_t size=0; /* support potentially ENORMOUS formposts */
1124   char *boundary;
1125   char *fileboundary=NULL;
1126   struct curl_slist* curList;
1127
1128   *finalform=NULL; /* default form is empty */
1129
1130   if(!post)
1131     return result; /* no input => no output! */
1132
1133   boundary = Curl_FormBoundary();
1134   if(!boundary)
1135     return CURLE_OUT_OF_MEMORY;
1136
1137   /* Make the first line of the output */
1138   result = AddFormDataf(&form, NULL,
1139                         "%s; boundary=%s\r\n",
1140                         custom_content_type?custom_content_type:
1141                         "Content-Type: multipart/form-data",
1142                         boundary);
1143
1144   if(result) {
1145     free(boundary);
1146     return result;
1147   }
1148   /* we DO NOT include that line in the total size of the POST, since it'll be
1149      part of the header! */
1150
1151   firstform = form;
1152
1153   do {
1154
1155     if(size) {
1156       result = AddFormDataf(&form, &size, "\r\n");
1157       if(result)
1158         break;
1159     }
1160
1161     /* boundary */
1162     result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
1163     if(result)
1164       break;
1165
1166     /* Maybe later this should be disabled when a custom_content_type is
1167        passed, since Content-Disposition is not meaningful for all multipart
1168        types.
1169     */
1170     result = AddFormDataf(&form, &size,
1171                           "Content-Disposition: form-data; name=\"");
1172     if(result)
1173       break;
1174
1175     result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
1176                          &size);
1177     if(result)
1178       break;
1179
1180     result = AddFormDataf(&form, &size, "\"");
1181     if(result)
1182       break;
1183
1184     if(post->more) {
1185       /* If used, this is a link to more file names, we must then do
1186          the magic to include several files with the same field name */
1187
1188       fileboundary = Curl_FormBoundary();
1189
1190       result = AddFormDataf(&form, &size,
1191                             "\r\nContent-Type: multipart/mixed,"
1192                             " boundary=%s\r\n",
1193                             fileboundary);
1194       if(result)
1195         break;
1196     }
1197
1198     file = post;
1199
1200     do {
1201
1202       /* If 'showfilename' is set, that is a faked name passed on to us
1203          to use to in the formpost. If that is not set, the actually used
1204          local file name should be added. */
1205
1206       if(post->more) {
1207         /* if multiple-file */
1208         char *filebasename=
1209           (!file->showfilename)?strippath(file->contents):NULL;
1210
1211         result = AddFormDataf(&form, &size,
1212                               "\r\n--%s\r\nContent-Disposition: "
1213                               "attachment; filename=\"%s\"",
1214                               fileboundary,
1215                               (file->showfilename?file->showfilename:
1216                                filebasename));
1217         if(filebasename)
1218           free(filebasename);
1219         if(result)
1220           break;
1221       }
1222       else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
1223                              HTTPPOST_CALLBACK)) {
1224         /* it should be noted that for the HTTPPOST_FILENAME and
1225            HTTPPOST_CALLBACK cases the ->showfilename struct member is always
1226            assigned at this point */
1227         char *filebasename=
1228           (!post->showfilename)?strippath(post->contents):NULL;
1229
1230         result = AddFormDataf(&form, &size,
1231                               "; filename=\"%s\"",
1232                               (post->showfilename?post->showfilename:
1233                                filebasename));
1234         if(filebasename)
1235           free(filebasename);
1236
1237         if(result)
1238           break;
1239       }
1240
1241       if(file->contenttype) {
1242         /* we have a specified type */
1243         result = AddFormDataf(&form, &size,
1244                               "\r\nContent-Type: %s",
1245                               file->contenttype);
1246         if(result)
1247           break;
1248       }
1249
1250       curList = file->contentheader;
1251       while( curList ) {
1252         /* Process the additional headers specified for this form */
1253         result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
1254         if(result)
1255           break;
1256         curList = curList->next;
1257       }
1258       if(result) {
1259         Curl_formclean(&firstform);
1260         free(boundary);
1261         return result;
1262       }
1263
1264 #if 0
1265       /* The header Content-Transfer-Encoding: seems to confuse some receivers
1266        * (like the built-in PHP engine). While I can't see any reason why it
1267        * should, I can just as well skip this to the benefit of the users who
1268        * are using such confused receivers.
1269        */
1270
1271       if(file->contenttype &&
1272          !checkprefix("text/", file->contenttype)) {
1273         /* this is not a text content, mention our binary encoding */
1274         result = AddFormDataf(&form, &size,
1275                               "\r\nContent-Transfer-Encoding: binary");
1276         if(result)
1277           break;
1278       }
1279 #endif
1280
1281       result = AddFormDataf(&form, &size, "\r\n\r\n");
1282       if(result)
1283         break;
1284
1285       if((post->flags & HTTPPOST_FILENAME) ||
1286          (post->flags & HTTPPOST_READFILE)) {
1287         /* we should include the contents from the specified file */
1288         FILE *fileread;
1289
1290         fileread = strequal("-", file->contents)?
1291           stdin:fopen(file->contents, "rb"); /* binary read for win32  */
1292
1293         /*
1294          * VMS: This only allows for stream files on VMS.  Stream files are
1295          * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
1296          * every record needs to have a \n appended & 1 added to SIZE
1297          */
1298
1299         if(fileread) {
1300           if(fileread != stdin) {
1301             /* close the file again */
1302             fclose(fileread);
1303             /* add the file name only - for later reading from this */
1304             result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
1305           }
1306           else {
1307             /* When uploading from stdin, we can't know the size of the file,
1308              * thus must read the full file as before. We *could* use chunked
1309              * transfer-encoding, but that only works for HTTP 1.1 and we
1310              * can't be sure we work with such a server.
1311              */
1312             size_t nread;
1313             char buffer[512];
1314             while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
1315               result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
1316               if(result)
1317                 break;
1318             }
1319           }
1320
1321           if(result) {
1322             Curl_formclean(&firstform);
1323             free(boundary);
1324             return result;
1325           }
1326
1327         }
1328         else {
1329 #ifdef _FORM_DEBUG
1330           fprintf(stderr,
1331                   "\n==> Curl_getFormData couldn't open/read \"%s\"\n",
1332                   file->contents);
1333 #endif
1334           Curl_formclean(&firstform);
1335           free(boundary);
1336           *finalform = NULL;
1337           return CURLE_READ_ERROR;
1338         }
1339
1340       }
1341       else if(post->flags & HTTPPOST_BUFFER) {
1342         /* include contents of buffer */
1343         result = AddFormData(&form, FORM_CONTENT, post->buffer,
1344                              post->bufferlength, &size);
1345           if(result)
1346             break;
1347       }
1348       else if(post->flags & HTTPPOST_CALLBACK) {
1349         /* the contents should be read with the callback and the size
1350            is set with the contentslength */
1351         result = AddFormData(&form, FORM_CALLBACK, post->userp,
1352                              post->contentslength, &size);
1353         if(result)
1354           break;
1355       }
1356       else {
1357         /* include the contents we got */
1358         result = AddFormData(&form, FORM_CONTENT, post->contents,
1359                              post->contentslength, &size);
1360         if(result)
1361           break;
1362       }
1363     } while((file = file->more) != NULL); /* for each specified file for this field */
1364     if(result) {
1365       Curl_formclean(&firstform);
1366       free(boundary);
1367       return result;
1368     }
1369
1370     if(post->more) {
1371       /* this was a multiple-file inclusion, make a termination file
1372          boundary: */
1373       result = AddFormDataf(&form, &size,
1374                            "\r\n--%s--",
1375                            fileboundary);
1376       free(fileboundary);
1377       if(result)
1378         break;
1379     }
1380
1381   } while((post = post->next) != NULL); /* for each field */
1382   if(result) {
1383     Curl_formclean(&firstform);
1384     free(boundary);
1385     return result;
1386   }
1387
1388   /* end-boundary for everything */
1389   result = AddFormDataf(&form, &size,
1390                        "\r\n--%s--\r\n",
1391                        boundary);
1392   if(result) {
1393     Curl_formclean(&firstform);
1394     free(boundary);
1395     return result;
1396   }
1397
1398   *sizep = size;
1399
1400   free(boundary);
1401
1402   *finalform=firstform;
1403
1404   return result;
1405 }
1406
1407 /*
1408  * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
1409  * and resets the 'sent' counter.
1410  */
1411 int Curl_FormInit(struct Form *form, struct FormData *formdata )
1412 {
1413   if(!formdata)
1414     return 1; /* error */
1415
1416   form->data = formdata;
1417   form->sent = 0;
1418   form->fp = NULL;
1419
1420   return 0;
1421 }
1422
1423 static size_t readfromfile(struct Form *form, char *buffer,
1424                            size_t size)
1425 {
1426   size_t nread;
1427   bool callback = (bool)(form->data->type == FORM_CALLBACK);
1428
1429   if(callback)
1430     nread = form->fread_func(buffer, 1, size, form->data->line);
1431   else {
1432     if(!form->fp) {
1433       /* this file hasn't yet been opened */
1434       form->fp = fopen(form->data->line, "rb"); /* b is for binary */
1435       if(!form->fp)
1436         return (size_t)-1; /* failure */
1437     }
1438     nread = fread(buffer, 1, size, form->fp);
1439   }
1440   if(!nread || nread > size) {
1441     /* this is the last chunk from the file, move on */
1442     if(!callback) {
1443       fclose(form->fp);
1444       form->fp = NULL;
1445     }
1446     form->data = form->data->next;
1447   }
1448
1449   return nread;
1450 }
1451
1452 /*
1453  * Curl_FormReader() is the fread() emulation function that will be used to
1454  * deliver the formdata to the transfer loop and then sent away to the peer.
1455  */
1456 size_t Curl_FormReader(char *buffer,
1457                        size_t size,
1458                        size_t nitems,
1459                        FILE *mydata)
1460 {
1461   struct Form *form;
1462   size_t wantedsize;
1463   size_t gotsize = 0;
1464
1465   form=(struct Form *)mydata;
1466
1467   wantedsize = size * nitems;
1468
1469   if(!form->data)
1470     return 0; /* nothing, error, empty */
1471
1472   if((form->data->type == FORM_FILE) ||
1473      (form->data->type == FORM_CALLBACK)) {
1474     gotsize = readfromfile(form, buffer, wantedsize);
1475
1476     if(gotsize)
1477       /* If positive or -1, return. If zero, continue! */
1478       return gotsize;
1479   }
1480   do {
1481
1482     if( (form->data->length - form->sent ) > wantedsize - gotsize) {
1483
1484       memcpy(buffer + gotsize , form->data->line + form->sent,
1485              wantedsize - gotsize);
1486
1487       form->sent += wantedsize-gotsize;
1488
1489       return wantedsize;
1490     }
1491
1492     memcpy(buffer+gotsize,
1493            form->data->line + form->sent,
1494            (form->data->length - form->sent) );
1495     gotsize += form->data->length - form->sent;
1496
1497     form->sent = 0;
1498
1499     form->data = form->data->next; /* advance */
1500
1501   } while(form->data && (form->data->type < FORM_CALLBACK));
1502   /* If we got an empty line and we have more data, we proceed to the next
1503      line immediately to avoid returning zero before we've reached the end. */
1504
1505   return gotsize;
1506 }
1507
1508 /*
1509  * Curl_formpostheader() returns the first line of the formpost, the
1510  * request-header part (which is not part of the request-body like the rest of
1511  * the post).
1512  */
1513 char *Curl_formpostheader(void *formp, size_t *len)
1514 {
1515   char *header;
1516   struct Form *form=(struct Form *)formp;
1517
1518   if(!form->data)
1519     return 0; /* nothing, ERROR! */
1520
1521   header = form->data->line;
1522   *len = form->data->length;
1523
1524   form->data = form->data->next; /* advance */
1525
1526   return header;
1527 }
1528
1529
1530 #ifdef _FORM_DEBUG
1531 int FormAddTest(const char * errormsg,
1532                  struct curl_httppost **httppost,
1533                  struct curl_httppost **last_post,
1534                  ...)
1535 {
1536   int result;
1537   va_list arg;
1538   va_start(arg, last_post);
1539   if((result = FormAdd(httppost, last_post, arg)))
1540     fprintf (stderr, "ERROR doing FormAdd ret: %d action: %s\n", result,
1541              errormsg);
1542   va_end(arg);
1543   return result;
1544 }
1545
1546
1547 int main(int argc, argv_item_t argv[])
1548 {
1549   char name1[] = "simple_COPYCONTENTS";
1550   char name2[] = "COPYCONTENTS_+_CONTENTTYPE";
1551   char name3[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH";
1552   char name4[] = "simple_PTRCONTENTS";
1553   char name5[] = "PTRCONTENTS_+_CONTENTSLENGTH";
1554   char name6[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE";
1555   char name7[] = "FILE1_+_CONTENTTYPE";
1556   char name8[] = "FILE1_+_FILE2";
1557   char name9[] = "FILE1_+_FILE2_+_FILE3";
1558   char name10[] = "ARRAY: FILE1_+_FILE2_+_FILE3";
1559   char name11[] = "FILECONTENT";
1560   char value1[] = "value for simple COPYCONTENTS";
1561   char value2[] = "value for COPYCONTENTS + CONTENTTYPE";
1562   char value3[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH";
1563   char value4[] = "value for simple PTRCONTENTS";
1564   char value5[] = "value for PTRCONTENTS + CONTENTSLENGTH";
1565   char value6[] = "value for PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE";
1566   char value7[] = "inet_ntoa_r.h";
1567   char value8[] = "Makefile.b32";
1568   char type2[] = "image/gif";
1569   char type6[] = "text/plain";
1570   char type7[] = "text/html";
1571   int name3length = strlen(name3);
1572   int value3length = strlen(value3);
1573   int value5length = strlen(value5);
1574   int value6length = strlen(value6);
1575   int errors = 0;
1576   CURLcode rc;
1577   curl_off_t size;
1578   size_t nread;
1579   char buffer[4096];
1580   struct curl_httppost *httppost=NULL;
1581   struct curl_httppost *last_post=NULL;
1582   struct curl_forms forms[4];
1583
1584   struct FormData *form;
1585   struct Form formread;
1586
1587   (void) argc;
1588   (void) argv;
1589
1590   if(FormAddTest("simple COPYCONTENTS test", &httppost, &last_post,
1591                   CURLFORM_COPYNAME, name1, CURLFORM_COPYCONTENTS, value1,
1592                   CURLFORM_END))
1593     ++errors;
1594   if(FormAddTest("COPYCONTENTS  + CONTENTTYPE test", &httppost, &last_post,
1595                   CURLFORM_COPYNAME, name2, CURLFORM_COPYCONTENTS, value2,
1596                   CURLFORM_CONTENTTYPE, type2, CURLFORM_END))
1597     ++errors;
1598   /* make null character at start to check that contentslength works
1599      correctly */
1600   name3[1] = '\0';
1601   value3[1] = '\0';
1602   if(FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test",
1603                   &httppost, &last_post,
1604                   CURLFORM_PTRNAME, name3, CURLFORM_COPYCONTENTS, value3,
1605                   CURLFORM_CONTENTSLENGTH, value3length,
1606                   CURLFORM_NAMELENGTH, name3length, CURLFORM_END))
1607     ++errors;
1608   if(FormAddTest("simple PTRCONTENTS test", &httppost, &last_post,
1609                   CURLFORM_COPYNAME, name4, CURLFORM_PTRCONTENTS, value4,
1610                   CURLFORM_END))
1611     ++errors;
1612   /* make null character at start to check that contentslength works
1613      correctly */
1614   value5[1] = '\0';
1615   if(FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost, &last_post,
1616                   CURLFORM_COPYNAME, name5, CURLFORM_PTRCONTENTS, value5,
1617                   CURLFORM_CONTENTSLENGTH, value5length, CURLFORM_END))
1618     ++errors;
1619   /* make null character at start to check that contentslength works
1620      correctly */
1621   value6[1] = '\0';
1622   if(FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test",
1623                   &httppost, &last_post,
1624                   CURLFORM_COPYNAME, name6, CURLFORM_PTRCONTENTS, value6,
1625                   CURLFORM_CONTENTSLENGTH, value6length,
1626                   CURLFORM_CONTENTTYPE, type6, CURLFORM_END))
1627     ++errors;
1628   if(FormAddTest("FILE + CONTENTTYPE test", &httppost, &last_post,
1629                   CURLFORM_COPYNAME, name7, CURLFORM_FILE, value7,
1630                   CURLFORM_CONTENTTYPE, type7, CURLFORM_END))
1631     ++errors;
1632   if(FormAddTest("FILE1 + FILE2 test", &httppost, &last_post,
1633                   CURLFORM_COPYNAME, name8, CURLFORM_FILE, value7,
1634                   CURLFORM_FILE, value8, CURLFORM_END))
1635     ++errors;
1636   if(FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost, &last_post,
1637                   CURLFORM_COPYNAME, name9, CURLFORM_FILE, value7,
1638                   CURLFORM_FILE, value8, CURLFORM_FILE, value7, CURLFORM_END))
1639     ++errors;
1640   forms[0].option = CURLFORM_FILE;
1641   forms[0].value  = value7;
1642   forms[1].option = CURLFORM_FILE;
1643   forms[1].value  = value8;
1644   forms[2].option = CURLFORM_FILE;
1645   forms[2].value  = value7;
1646   forms[3].option  = CURLFORM_END;
1647   if(FormAddTest("FILE1 + FILE2 + FILE3 ARRAY test", &httppost, &last_post,
1648                   CURLFORM_COPYNAME, name10, CURLFORM_ARRAY, forms,
1649                   CURLFORM_END))
1650     ++errors;
1651   if(FormAddTest("FILECONTENT test", &httppost, &last_post,
1652                   CURLFORM_COPYNAME, name11, CURLFORM_FILECONTENT, value7,
1653                   CURLFORM_END))
1654     ++errors;
1655
1656   rc = Curl_getFormData(&form, httppost, NULL, &size);
1657   if(rc != CURLE_OK) {
1658     if(rc != CURLE_READ_ERROR) {
1659       const char *errortext = curl_easy_strerror(rc);
1660       fprintf(stdout, "\n==> Curl_getFormData error: %s\n", errortext);
1661     }
1662     return 0;
1663   }
1664
1665   Curl_FormInit(&formread, form);
1666
1667   do {
1668     nread = Curl_FormReader(buffer, 1, sizeof(buffer),
1669                             (FILE *)&formread);
1670
1671     if(nread < 1)
1672       break;
1673     fwrite(buffer, nread, 1, stdout);
1674   } while(1);
1675
1676   fprintf(stdout, "size: ");
1677   fprintf(stdout, CURL_FORMAT_OFF_T, size);
1678   fprintf(stdout, "\n");
1679   if(errors)
1680     fprintf(stdout, "\n==> %d Test(s) failed!\n", errors);
1681   else
1682     fprintf(stdout, "\nAll Tests seem to have worked (please check output)\n");
1683
1684   return 0;
1685 }
1686
1687 #endif  /* _FORM_DEBUG */
1688
1689 #else  /* CURL_DISABLE_HTTP */
1690 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
1691                           struct curl_httppost **last_post,
1692                           ...)
1693 {
1694   (void)httppost;
1695   (void)last_post;
1696   return CURL_FORMADD_DISABLED;
1697 }
1698
1699 int curl_formget(struct curl_httppost *form, void *arg,
1700                  curl_formget_callback append)
1701 {
1702   (void) form;
1703   (void) arg;
1704   (void) append;
1705   return CURL_FORMADD_DISABLED;
1706 }
1707
1708 void curl_formfree(struct curl_httppost *form)
1709 {
1710   (void)form;
1711   /* does nothing HTTP is disabled */
1712 }
1713
1714 #endif  /* CURL_DISABLE_HTTP */
1715
1716 #if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
1717
1718 /*
1719  * Curl_FormBoundary() creates a suitable boundary string and returns an
1720  * allocated one. This is also used by SSL-code so it must be present even
1721  * if HTTP is disabled!
1722  */
1723 char *Curl_FormBoundary(void)
1724 {
1725   char *retstring;
1726   static int randomizer;   /* this is just so that two boundaries within
1727                               the same form won't be identical */
1728   size_t i;
1729
1730   static const char table16[]="abcdef0123456789";
1731
1732   retstring = (char *)malloc(BOUNDARY_LENGTH+1);
1733
1734   if(!retstring)
1735     return NULL; /* failed */
1736
1737   srand((unsigned int)time(NULL)+randomizer++); /* seed */
1738
1739   strcpy(retstring, "----------------------------");
1740
1741   for(i=strlen(retstring); i<BOUNDARY_LENGTH; i++)
1742     retstring[i] = table16[rand()%16];
1743
1744   /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
1745      combinations */
1746   retstring[BOUNDARY_LENGTH]=0; /* zero terminate */
1747
1748   return retstring;
1749 }
1750
1751 #endif  /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */