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