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