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