formdata.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 #include "curl_setup.h"
00024 
00025 #include <curl/curl.h>
00026 
00027 #ifndef CURL_DISABLE_HTTP
00028 
00029 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
00030 #include <libgen.h>
00031 #endif
00032 
00033 #include "urldata.h" /* for struct Curl_easy */
00034 #include "formdata.h"
00035 #include "vtls/vtls.h"
00036 #include "strcase.h"
00037 #include "sendf.h"
00038 #include "strdup.h"
00039 #include "rand.h"
00040 /* The last 3 #include files should be in this order */
00041 #include "curl_printf.h"
00042 #include "curl_memory.h"
00043 #include "memdebug.h"
00044 
00045 #ifndef HAVE_BASENAME
00046 static char *Curl_basename(char *path);
00047 #define basename(x)  Curl_basename((x))
00048 #endif
00049 
00050 static size_t readfromfile(struct Form *form, char *buffer, size_t size);
00051 static char *formboundary(struct Curl_easy *data);
00052 
00053 /* What kind of Content-Type to use on un-specified files with unrecognized
00054    extensions. */
00055 #define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
00056 
00057 #define FORM_FILE_SEPARATOR ','
00058 #define FORM_TYPE_SEPARATOR ';'
00059 
00060 #define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
00061 #define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
00062 #define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
00063 #define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
00064 #define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
00065 #define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
00066 #define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
00067 
00068 /***************************************************************************
00069  *
00070  * AddHttpPost()
00071  *
00072  * Adds a HttpPost structure to the list, if parent_post is given becomes
00073  * a subpost of parent_post instead of a direct list element.
00074  *
00075  * Returns newly allocated HttpPost on success and NULL if malloc failed.
00076  *
00077  ***************************************************************************/
00078 static struct curl_httppost *
00079 AddHttpPost(char *name, size_t namelength,
00080             char *value, curl_off_t contentslength,
00081             char *buffer, size_t bufferlength,
00082             char *contenttype,
00083             long flags,
00084             struct curl_slist *contentHeader,
00085             char *showfilename, char *userp,
00086             struct curl_httppost *parent_post,
00087             struct curl_httppost **httppost,
00088             struct curl_httppost **last_post)
00089 {
00090   struct curl_httppost *post;
00091   post = calloc(1, sizeof(struct curl_httppost));
00092   if(post) {
00093     post->name = name;
00094     post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
00095     post->contents = value;
00096     post->contentlen = contentslength;
00097     post->buffer = buffer;
00098     post->bufferlength = (long)bufferlength;
00099     post->contenttype = contenttype;
00100     post->contentheader = contentHeader;
00101     post->showfilename = showfilename;
00102     post->userp = userp,
00103     post->flags = flags | CURL_HTTPPOST_LARGE;
00104   }
00105   else
00106     return NULL;
00107 
00108   if(parent_post) {
00109     /* now, point our 'more' to the original 'more' */
00110     post->more = parent_post->more;
00111 
00112     /* then move the original 'more' to point to ourselves */
00113     parent_post->more = post;
00114   }
00115   else {
00116     /* make the previous point to this */
00117     if(*last_post)
00118       (*last_post)->next = post;
00119     else
00120       (*httppost) = post;
00121 
00122     (*last_post) = post;
00123   }
00124   return post;
00125 }
00126 
00127 /***************************************************************************
00128  *
00129  * AddFormInfo()
00130  *
00131  * Adds a FormInfo structure to the list presented by parent_form_info.
00132  *
00133  * Returns newly allocated FormInfo on success and NULL if malloc failed/
00134  * parent_form_info is NULL.
00135  *
00136  ***************************************************************************/
00137 static FormInfo * AddFormInfo(char *value,
00138                               char *contenttype,
00139                               FormInfo *parent_form_info)
00140 {
00141   FormInfo *form_info;
00142   form_info = calloc(1, sizeof(struct FormInfo));
00143   if(form_info) {
00144     if(value)
00145       form_info->value = value;
00146     if(contenttype)
00147       form_info->contenttype = contenttype;
00148     form_info->flags = HTTPPOST_FILENAME;
00149   }
00150   else
00151     return NULL;
00152 
00153   if(parent_form_info) {
00154     /* now, point our 'more' to the original 'more' */
00155     form_info->more = parent_form_info->more;
00156 
00157     /* then move the original 'more' to point to ourselves */
00158     parent_form_info->more = form_info;
00159   }
00160 
00161   return form_info;
00162 }
00163 
00164 /***************************************************************************
00165  *
00166  * ContentTypeForFilename()
00167  *
00168  * Provides content type for filename if one of the known types (else
00169  * (either the prevtype or the default is returned).
00170  *
00171  * Returns some valid contenttype for filename.
00172  *
00173  ***************************************************************************/
00174 static const char *ContentTypeForFilename(const char *filename,
00175                                           const char *prevtype)
00176 {
00177   const char *contenttype = NULL;
00178   unsigned int i;
00179   /*
00180    * No type was specified, we scan through a few well-known
00181    * extensions and pick the first we match!
00182    */
00183   struct ContentType {
00184     const char *extension;
00185     const char *type;
00186   };
00187   static const struct ContentType ctts[]={
00188     {".gif",  "image/gif"},
00189     {".jpg",  "image/jpeg"},
00190     {".jpeg", "image/jpeg"},
00191     {".txt",  "text/plain"},
00192     {".html", "text/html"},
00193     {".xml", "application/xml"}
00194   };
00195 
00196   if(prevtype)
00197     /* default to the previously set/used! */
00198     contenttype = prevtype;
00199   else
00200     contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
00201 
00202   if(filename) { /* in case a NULL was passed in */
00203     for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
00204       if(strlen(filename) >= strlen(ctts[i].extension)) {
00205         if(strcasecompare(filename +
00206                           strlen(filename) - strlen(ctts[i].extension),
00207                           ctts[i].extension)) {
00208           contenttype = ctts[i].type;
00209           break;
00210         }
00211       }
00212     }
00213   }
00214   /* we have a contenttype by now */
00215   return contenttype;
00216 }
00217 
00218 /***************************************************************************
00219  *
00220  * FormAdd()
00221  *
00222  * Stores a formpost parameter and builds the appropriate linked list.
00223  *
00224  * Has two principal functionalities: using files and byte arrays as
00225  * post parts. Byte arrays are either copied or just the pointer is stored
00226  * (as the user requests) while for files only the filename and not the
00227  * content is stored.
00228  *
00229  * While you may have only one byte array for each name, multiple filenames
00230  * are allowed (and because of this feature CURLFORM_END is needed after
00231  * using CURLFORM_FILE).
00232  *
00233  * Examples:
00234  *
00235  * Simple name/value pair with copied contents:
00236  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
00237  * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
00238  *
00239  * name/value pair where only the content pointer is remembered:
00240  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
00241  * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
00242  * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
00243  *
00244  * storing a filename (CONTENTTYPE is optional!):
00245  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
00246  * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
00247  * CURLFORM_END);
00248  *
00249  * storing multiple filenames:
00250  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
00251  * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
00252  *
00253  * Returns:
00254  * CURL_FORMADD_OK             on success
00255  * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
00256  * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
00257  * CURL_FORMADD_NULL           if a null pointer was given for a char
00258  * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
00259  * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
00260  * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
00261  * CURL_FORMADD_MEMORY         if a HttpPost struct cannot be allocated
00262  * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
00263  * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
00264  *
00265  ***************************************************************************/
00266 
00267 static
00268 CURLFORMcode FormAdd(struct curl_httppost **httppost,
00269                      struct curl_httppost **last_post,
00270                      va_list params)
00271 {
00272   FormInfo *first_form, *current_form, *form = NULL;
00273   CURLFORMcode return_value = CURL_FORMADD_OK;
00274   const char *prevtype = NULL;
00275   struct curl_httppost *post = NULL;
00276   CURLformoption option;
00277   struct curl_forms *forms = NULL;
00278   char *array_value=NULL; /* value read from an array */
00279 
00280   /* This is a state variable, that if TRUE means that we're parsing an
00281      array that we got passed to us. If FALSE we're parsing the input
00282      va_list arguments. */
00283   bool array_state = FALSE;
00284 
00285   /*
00286    * We need to allocate the first struct to fill in.
00287    */
00288   first_form = calloc(1, sizeof(struct FormInfo));
00289   if(!first_form)
00290     return CURL_FORMADD_MEMORY;
00291 
00292   current_form = first_form;
00293 
00294   /*
00295    * Loop through all the options set. Break if we have an error to report.
00296    */
00297   while(return_value == CURL_FORMADD_OK) {
00298 
00299     /* first see if we have more parts of the array param */
00300     if(array_state && forms) {
00301       /* get the upcoming option from the given array */
00302       option = forms->option;
00303       array_value = (char *)forms->value;
00304 
00305       forms++; /* advance this to next entry */
00306       if(CURLFORM_END == option) {
00307         /* end of array state */
00308         array_state = FALSE;
00309         continue;
00310       }
00311     }
00312     else {
00313       /* This is not array-state, get next option */
00314       option = va_arg(params, CURLformoption);
00315       if(CURLFORM_END == option)
00316         break;
00317     }
00318 
00319     switch(option) {
00320     case CURLFORM_ARRAY:
00321       if(array_state)
00322         /* we don't support an array from within an array */
00323         return_value = CURL_FORMADD_ILLEGAL_ARRAY;
00324       else {
00325         forms = va_arg(params, struct curl_forms *);
00326         if(forms)
00327           array_state = TRUE;
00328         else
00329           return_value = CURL_FORMADD_NULL;
00330       }
00331       break;
00332 
00333       /*
00334        * Set the Name property.
00335        */
00336     case CURLFORM_PTRNAME:
00337 #ifdef CURL_DOES_CONVERSIONS
00338       /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
00339        * the data in all cases so that we'll have safe memory for the eventual
00340        * conversion.
00341        */
00342 #else
00343       current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
00344 #endif
00345     case CURLFORM_COPYNAME:
00346       if(current_form->name)
00347         return_value = CURL_FORMADD_OPTION_TWICE;
00348       else {
00349         char *name = array_state?
00350           array_value:va_arg(params, char *);
00351         if(name)
00352           current_form->name = name; /* store for the moment */
00353         else
00354           return_value = CURL_FORMADD_NULL;
00355       }
00356       break;
00357     case CURLFORM_NAMELENGTH:
00358       if(current_form->namelength)
00359         return_value = CURL_FORMADD_OPTION_TWICE;
00360       else
00361         current_form->namelength =
00362           array_state?(size_t)array_value:(size_t)va_arg(params, long);
00363       break;
00364 
00365       /*
00366        * Set the contents property.
00367        */
00368     case CURLFORM_PTRCONTENTS:
00369       current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
00370     case CURLFORM_COPYCONTENTS:
00371       if(current_form->value)
00372         return_value = CURL_FORMADD_OPTION_TWICE;
00373       else {
00374         char *value =
00375           array_state?array_value:va_arg(params, char *);
00376         if(value)
00377           current_form->value = value; /* store for the moment */
00378         else
00379           return_value = CURL_FORMADD_NULL;
00380       }
00381       break;
00382     case CURLFORM_CONTENTSLENGTH:
00383       current_form->contentslength =
00384         array_state?(size_t)array_value:(size_t)va_arg(params, long);
00385       break;
00386 
00387     case CURLFORM_CONTENTLEN:
00388       current_form->flags |= CURL_HTTPPOST_LARGE;
00389       current_form->contentslength =
00390         array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
00391       break;
00392 
00393       /* Get contents from a given file name */
00394     case CURLFORM_FILECONTENT:
00395       if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
00396         return_value = CURL_FORMADD_OPTION_TWICE;
00397       else {
00398         const char *filename = array_state?
00399           array_value:va_arg(params, char *);
00400         if(filename) {
00401           current_form->value = strdup(filename);
00402           if(!current_form->value)
00403             return_value = CURL_FORMADD_MEMORY;
00404           else {
00405             current_form->flags |= HTTPPOST_READFILE;
00406             current_form->value_alloc = TRUE;
00407           }
00408         }
00409         else
00410           return_value = CURL_FORMADD_NULL;
00411       }
00412       break;
00413 
00414       /* We upload a file */
00415     case CURLFORM_FILE:
00416       {
00417         const char *filename = array_state?array_value:
00418           va_arg(params, char *);
00419 
00420         if(current_form->value) {
00421           if(current_form->flags & HTTPPOST_FILENAME) {
00422             if(filename) {
00423               char *fname = strdup(filename);
00424               if(!fname)
00425                 return_value = CURL_FORMADD_MEMORY;
00426               else {
00427                 form = AddFormInfo(fname, NULL, current_form);
00428                 if(!form) {
00429                   free(fname);
00430                   return_value = CURL_FORMADD_MEMORY;
00431                 }
00432                 else {
00433                   form->value_alloc = TRUE;
00434                   current_form = form;
00435                   form = NULL;
00436                 }
00437               }
00438             }
00439             else
00440               return_value = CURL_FORMADD_NULL;
00441           }
00442           else
00443             return_value = CURL_FORMADD_OPTION_TWICE;
00444         }
00445         else {
00446           if(filename) {
00447             current_form->value = strdup(filename);
00448             if(!current_form->value)
00449               return_value = CURL_FORMADD_MEMORY;
00450             else {
00451               current_form->flags |= HTTPPOST_FILENAME;
00452               current_form->value_alloc = TRUE;
00453             }
00454           }
00455           else
00456             return_value = CURL_FORMADD_NULL;
00457         }
00458         break;
00459       }
00460 
00461     case CURLFORM_BUFFERPTR:
00462       current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
00463       if(current_form->buffer)
00464         return_value = CURL_FORMADD_OPTION_TWICE;
00465       else {
00466         char *buffer =
00467           array_state?array_value:va_arg(params, char *);
00468         if(buffer) {
00469           current_form->buffer = buffer; /* store for the moment */
00470           current_form->value = buffer; /* make it non-NULL to be accepted
00471                                            as fine */
00472         }
00473         else
00474           return_value = CURL_FORMADD_NULL;
00475       }
00476       break;
00477 
00478     case CURLFORM_BUFFERLENGTH:
00479       if(current_form->bufferlength)
00480         return_value = CURL_FORMADD_OPTION_TWICE;
00481       else
00482         current_form->bufferlength =
00483           array_state?(size_t)array_value:(size_t)va_arg(params, long);
00484       break;
00485 
00486     case CURLFORM_STREAM:
00487       current_form->flags |= HTTPPOST_CALLBACK;
00488       if(current_form->userp)
00489         return_value = CURL_FORMADD_OPTION_TWICE;
00490       else {
00491         char *userp =
00492           array_state?array_value:va_arg(params, char *);
00493         if(userp) {
00494           current_form->userp = userp;
00495           current_form->value = userp; /* this isn't strictly true but we
00496                                           derive a value from this later on
00497                                           and we need this non-NULL to be
00498                                           accepted as a fine form part */
00499         }
00500         else
00501           return_value = CURL_FORMADD_NULL;
00502       }
00503       break;
00504 
00505     case CURLFORM_CONTENTTYPE:
00506       {
00507         const char *contenttype =
00508           array_state?array_value:va_arg(params, char *);
00509         if(current_form->contenttype) {
00510           if(current_form->flags & HTTPPOST_FILENAME) {
00511             if(contenttype) {
00512               char *type = strdup(contenttype);
00513               if(!type)
00514                 return_value = CURL_FORMADD_MEMORY;
00515               else {
00516                 form = AddFormInfo(NULL, type, current_form);
00517                 if(!form) {
00518                   free(type);
00519                   return_value = CURL_FORMADD_MEMORY;
00520                 }
00521                 else {
00522                   form->contenttype_alloc = TRUE;
00523                   current_form = form;
00524                   form = NULL;
00525                 }
00526               }
00527             }
00528             else
00529               return_value = CURL_FORMADD_NULL;
00530           }
00531           else
00532             return_value = CURL_FORMADD_OPTION_TWICE;
00533         }
00534         else {
00535           if(contenttype) {
00536             current_form->contenttype = strdup(contenttype);
00537             if(!current_form->contenttype)
00538               return_value = CURL_FORMADD_MEMORY;
00539             else
00540               current_form->contenttype_alloc = TRUE;
00541           }
00542           else
00543             return_value = CURL_FORMADD_NULL;
00544         }
00545         break;
00546       }
00547     case CURLFORM_CONTENTHEADER:
00548       {
00549         /* this "cast increases required alignment of target type" but
00550            we consider it OK anyway */
00551         struct curl_slist *list = array_state?
00552           (struct curl_slist *)(void *)array_value:
00553           va_arg(params, struct curl_slist *);
00554 
00555         if(current_form->contentheader)
00556           return_value = CURL_FORMADD_OPTION_TWICE;
00557         else
00558           current_form->contentheader = list;
00559 
00560         break;
00561       }
00562     case CURLFORM_FILENAME:
00563     case CURLFORM_BUFFER:
00564       {
00565         const char *filename = array_state?array_value:
00566           va_arg(params, char *);
00567         if(current_form->showfilename)
00568           return_value = CURL_FORMADD_OPTION_TWICE;
00569         else {
00570           current_form->showfilename = strdup(filename);
00571           if(!current_form->showfilename)
00572             return_value = CURL_FORMADD_MEMORY;
00573           else
00574             current_form->showfilename_alloc = TRUE;
00575         }
00576         break;
00577       }
00578     default:
00579       return_value = CURL_FORMADD_UNKNOWN_OPTION;
00580       break;
00581     }
00582   }
00583 
00584   if(CURL_FORMADD_OK != return_value) {
00585     /* On error, free allocated fields for all nodes of the FormInfo linked
00586        list without deallocating nodes. List nodes are deallocated later on */
00587     FormInfo *ptr;
00588     for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
00589       if(ptr->name_alloc) {
00590         Curl_safefree(ptr->name);
00591         ptr->name_alloc = FALSE;
00592       }
00593       if(ptr->value_alloc) {
00594         Curl_safefree(ptr->value);
00595         ptr->value_alloc = FALSE;
00596       }
00597       if(ptr->contenttype_alloc) {
00598         Curl_safefree(ptr->contenttype);
00599         ptr->contenttype_alloc = FALSE;
00600       }
00601       if(ptr->showfilename_alloc) {
00602         Curl_safefree(ptr->showfilename);
00603         ptr->showfilename_alloc = FALSE;
00604       }
00605     }
00606   }
00607 
00608   if(CURL_FORMADD_OK == return_value) {
00609     /* go through the list, check for completeness and if everything is
00610      * alright add the HttpPost item otherwise set return_value accordingly */
00611 
00612     post = NULL;
00613     for(form = first_form;
00614         form != NULL;
00615         form = form->more) {
00616       if(((!form->name || !form->value) && !post) ||
00617          ( (form->contentslength) &&
00618            (form->flags & HTTPPOST_FILENAME) ) ||
00619          ( (form->flags & HTTPPOST_FILENAME) &&
00620            (form->flags & HTTPPOST_PTRCONTENTS) ) ||
00621 
00622          ( (!form->buffer) &&
00623            (form->flags & HTTPPOST_BUFFER) &&
00624            (form->flags & HTTPPOST_PTRBUFFER) ) ||
00625 
00626          ( (form->flags & HTTPPOST_READFILE) &&
00627            (form->flags & HTTPPOST_PTRCONTENTS) )
00628         ) {
00629         return_value = CURL_FORMADD_INCOMPLETE;
00630         break;
00631       }
00632       else {
00633         if(((form->flags & HTTPPOST_FILENAME) ||
00634             (form->flags & HTTPPOST_BUFFER)) &&
00635            !form->contenttype) {
00636           char *f = form->flags & HTTPPOST_BUFFER?
00637             form->showfilename : form->value;
00638 
00639           /* our contenttype is missing */
00640           form->contenttype = strdup(ContentTypeForFilename(f, prevtype));
00641           if(!form->contenttype) {
00642             return_value = CURL_FORMADD_MEMORY;
00643             break;
00644           }
00645           form->contenttype_alloc = TRUE;
00646         }
00647         if(!(form->flags & HTTPPOST_PTRNAME) &&
00648            (form == first_form) ) {
00649           /* Note that there's small risk that form->name is NULL here if the
00650              app passed in a bad combo, so we better check for that first. */
00651           if(form->name) {
00652             /* copy name (without strdup; possibly contains null characters) */
00653             form->name = Curl_memdup(form->name, form->namelength?
00654                                      form->namelength:
00655                                      strlen(form->name)+1);
00656           }
00657           if(!form->name) {
00658             return_value = CURL_FORMADD_MEMORY;
00659             break;
00660           }
00661           form->name_alloc = TRUE;
00662         }
00663         if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
00664                             HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
00665                             HTTPPOST_CALLBACK)) && form->value) {
00666           /* copy value (without strdup; possibly contains null characters) */
00667           size_t clen  = (size_t) form->contentslength;
00668           if(!clen)
00669             clen = strlen(form->value)+1;
00670 
00671           form->value = Curl_memdup(form->value, clen);
00672 
00673           if(!form->value) {
00674             return_value = CURL_FORMADD_MEMORY;
00675             break;
00676           }
00677           form->value_alloc = TRUE;
00678         }
00679         post = AddHttpPost(form->name, form->namelength,
00680                            form->value, form->contentslength,
00681                            form->buffer, form->bufferlength,
00682                            form->contenttype, form->flags,
00683                            form->contentheader, form->showfilename,
00684                            form->userp,
00685                            post, httppost,
00686                            last_post);
00687 
00688         if(!post) {
00689           return_value = CURL_FORMADD_MEMORY;
00690           break;
00691         }
00692 
00693         if(form->contenttype)
00694           prevtype = form->contenttype;
00695       }
00696     }
00697     if(CURL_FORMADD_OK != return_value) {
00698       /* On error, free allocated fields for nodes of the FormInfo linked
00699          list which are not already owned by the httppost linked list
00700          without deallocating nodes. List nodes are deallocated later on */
00701       FormInfo *ptr;
00702       for(ptr = form; ptr != NULL; ptr = ptr->more) {
00703         if(ptr->name_alloc) {
00704           Curl_safefree(ptr->name);
00705           ptr->name_alloc = FALSE;
00706         }
00707         if(ptr->value_alloc) {
00708           Curl_safefree(ptr->value);
00709           ptr->value_alloc = FALSE;
00710         }
00711         if(ptr->contenttype_alloc) {
00712           Curl_safefree(ptr->contenttype);
00713           ptr->contenttype_alloc = FALSE;
00714         }
00715         if(ptr->showfilename_alloc) {
00716           Curl_safefree(ptr->showfilename);
00717           ptr->showfilename_alloc = FALSE;
00718         }
00719       }
00720     }
00721   }
00722 
00723   /* Always deallocate FormInfo linked list nodes without touching node
00724      fields given that these have either been deallocated or are owned
00725      now by the httppost linked list */
00726   while(first_form) {
00727     FormInfo *ptr = first_form->more;
00728     free(first_form);
00729     first_form = ptr;
00730   }
00731 
00732   return return_value;
00733 }
00734 
00735 /*
00736  * curl_formadd() is a public API to add a section to the multipart formpost.
00737  *
00738  * @unittest: 1308
00739  */
00740 
00741 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
00742                           struct curl_httppost **last_post,
00743                           ...)
00744 {
00745   va_list arg;
00746   CURLFORMcode result;
00747   va_start(arg, last_post);
00748   result = FormAdd(httppost, last_post, arg);
00749   va_end(arg);
00750   return result;
00751 }
00752 
00753 #ifdef __VMS
00754 #include <fabdef.h>
00755 /*
00756  * get_vms_file_size does what it takes to get the real size of the file
00757  *
00758  * For fixed files, find out the size of the EOF block and adjust.
00759  *
00760  * For all others, have to read the entire file in, discarding the contents.
00761  * Most posted text files will be small, and binary files like zlib archives
00762  * and CD/DVD images should be either a STREAM_LF format or a fixed format.
00763  *
00764  */
00765 curl_off_t VmsRealFileSize(const char *name,
00766                            const struct_stat *stat_buf)
00767 {
00768   char buffer[8192];
00769   curl_off_t count;
00770   int ret_stat;
00771   FILE * file;
00772 
00773   file = fopen(name, FOPEN_READTEXT); /* VMS */
00774   if(file == NULL)
00775     return 0;
00776 
00777   count = 0;
00778   ret_stat = 1;
00779   while(ret_stat > 0) {
00780     ret_stat = fread(buffer, 1, sizeof(buffer), file);
00781     if(ret_stat != 0)
00782       count += ret_stat;
00783   }
00784   fclose(file);
00785 
00786   return count;
00787 }
00788 
00789 /*
00790  *
00791  *  VmsSpecialSize checks to see if the stat st_size can be trusted and
00792  *  if not to call a routine to get the correct size.
00793  *
00794  */
00795 static curl_off_t VmsSpecialSize(const char *name,
00796                                  const struct_stat *stat_buf)
00797 {
00798   switch(stat_buf->st_fab_rfm) {
00799   case FAB$C_VAR:
00800   case FAB$C_VFC:
00801     return VmsRealFileSize(name, stat_buf);
00802     break;
00803   default:
00804     return stat_buf->st_size;
00805   }
00806 }
00807 
00808 #endif
00809 
00810 #ifndef __VMS
00811 #define filesize(name, stat_data) (stat_data.st_size)
00812 #else
00813     /* Getting the expected file size needs help on VMS */
00814 #define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
00815 #endif
00816 
00817 /*
00818  * AddFormData() adds a chunk of data to the FormData linked list.
00819  *
00820  * size is incremented by the chunk length, unless it is NULL
00821  */
00822 static CURLcode AddFormData(struct FormData **formp,
00823                             enum formtype type,
00824                             const void *line,
00825                             curl_off_t length,
00826                             curl_off_t *size)
00827 {
00828   struct FormData *newform;
00829   char *alloc2 = NULL;
00830   CURLcode result = CURLE_OK;
00831   if(length < 0 || (size && *size < 0))
00832     return CURLE_BAD_FUNCTION_ARGUMENT;
00833 
00834   newform = malloc(sizeof(struct FormData));
00835   if(!newform)
00836     return CURLE_OUT_OF_MEMORY;
00837   newform->next = NULL;
00838 
00839   if(type <= FORM_CONTENT) {
00840     /* we make it easier for plain strings: */
00841     if(!length)
00842       length = strlen((char *)line);
00843 #if (SIZEOF_SIZE_T < CURL_SIZEOF_CURL_OFF_T)
00844     else if(length >= (curl_off_t)(size_t)-1) {
00845       result = CURLE_BAD_FUNCTION_ARGUMENT;
00846       goto error;
00847     }
00848 #endif
00849     if(type != FORM_DATAMEM) {
00850       newform->line = malloc((size_t)length+1);
00851       if(!newform->line) {
00852         result = CURLE_OUT_OF_MEMORY;
00853         goto error;
00854       }
00855       alloc2 = newform->line;
00856       memcpy(newform->line, line, (size_t)length);
00857 
00858       /* zero terminate for easier debugging */
00859       newform->line[(size_t)length]=0;
00860     }
00861     else {
00862       newform->line = (char *)line;
00863       type = FORM_DATA; /* in all other aspects this is just FORM_DATA */
00864     }
00865     newform->length = (size_t)length;
00866   }
00867   else
00868     /* For callbacks and files we don't have any actual data so we just keep a
00869        pointer to whatever this points to */
00870     newform->line = (char *)line;
00871 
00872   newform->type = type;
00873 
00874   if(size) {
00875     if(type != FORM_FILE)
00876       /* for static content as well as callback data we add the size given
00877          as input argument */
00878       *size += length;
00879     else {
00880       /* Since this is a file to be uploaded here, add the size of the actual
00881          file */
00882       if(strcmp("-", newform->line)) {
00883         struct_stat file;
00884         if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode))
00885           *size += filesize(newform->line, file);
00886         else {
00887           result = CURLE_BAD_FUNCTION_ARGUMENT;
00888           goto error;
00889         }
00890       }
00891     }
00892   }
00893 
00894   if(*formp) {
00895     (*formp)->next = newform;
00896     *formp = newform;
00897   }
00898   else
00899     *formp = newform;
00900 
00901   return CURLE_OK;
00902   error:
00903   if(newform)
00904     free(newform);
00905   if(alloc2)
00906     free(alloc2);
00907   return result;
00908 }
00909 
00910 /*
00911  * AddFormDataf() adds printf()-style formatted data to the formdata chain.
00912  */
00913 
00914 static CURLcode AddFormDataf(struct FormData **formp,
00915                              curl_off_t *size,
00916                              const char *fmt, ...)
00917 {
00918   char *s;
00919   CURLcode result;
00920   va_list ap;
00921   va_start(ap, fmt);
00922   s = curl_mvaprintf(fmt, ap);
00923   va_end(ap);
00924 
00925   if(!s)
00926     return CURLE_OUT_OF_MEMORY;
00927 
00928   result = AddFormData(formp, FORM_DATAMEM, s, 0, size);
00929   if(result)
00930     free(s);
00931 
00932   return result;
00933 }
00934 
00935 /*
00936  * Curl_formclean() is used from http.c, this cleans a built FormData linked
00937  * list
00938  */
00939 void Curl_formclean(struct FormData **form_ptr)
00940 {
00941   struct FormData *next, *form;
00942 
00943   form = *form_ptr;
00944   if(!form)
00945     return;
00946 
00947   do {
00948     next=form->next;  /* the following form line */
00949     if(form->type <= FORM_CONTENT)
00950       free(form->line); /* free the line */
00951     free(form);       /* free the struct */
00952     form = next;
00953   } while(form); /* continue */
00954 
00955   *form_ptr = NULL;
00956 }
00957 
00958 /*
00959  * curl_formget()
00960  * Serialize a curl_httppost struct.
00961  * Returns 0 on success.
00962  *
00963  * @unittest: 1308
00964  */
00965 int curl_formget(struct curl_httppost *form, void *arg,
00966                  curl_formget_callback append)
00967 {
00968   CURLcode result;
00969   curl_off_t size;
00970   struct FormData *data, *ptr;
00971 
00972   result = Curl_getformdata(NULL, &data, form, NULL, &size);
00973   if(result)
00974     return (int)result;
00975 
00976   for(ptr = data; ptr; ptr = ptr->next) {
00977     if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) {
00978       char buffer[8192];
00979       size_t nread;
00980       struct Form temp;
00981 
00982       Curl_FormInit(&temp, ptr);
00983 
00984       do {
00985         nread = readfromfile(&temp, buffer, sizeof(buffer));
00986         if((nread == (size_t) -1) ||
00987            (nread > sizeof(buffer)) ||
00988            (nread != append(arg, buffer, nread))) {
00989           if(temp.fp)
00990             fclose(temp.fp);
00991           Curl_formclean(&data);
00992           return -1;
00993         }
00994       } while(nread);
00995     }
00996     else {
00997       if(ptr->length != append(arg, ptr->line, ptr->length)) {
00998         Curl_formclean(&data);
00999         return -1;
01000       }
01001     }
01002   }
01003   Curl_formclean(&data);
01004   return 0;
01005 }
01006 
01007 /*
01008  * curl_formfree() is an external function to free up a whole form post
01009  * chain
01010  */
01011 void curl_formfree(struct curl_httppost *form)
01012 {
01013   struct curl_httppost *next;
01014 
01015   if(!form)
01016     /* no form to free, just get out of this */
01017     return;
01018 
01019   do {
01020     next=form->next;  /* the following form line */
01021 
01022     /* recurse to sub-contents */
01023     curl_formfree(form->more);
01024 
01025     if(!(form->flags & HTTPPOST_PTRNAME))
01026       free(form->name); /* free the name */
01027     if(!(form->flags &
01028          (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
01029       )
01030       free(form->contents); /* free the contents */
01031     free(form->contenttype); /* free the content type */
01032     free(form->showfilename); /* free the faked file name */
01033     free(form);       /* free the struct */
01034     form = next;
01035   } while(form); /* continue */
01036 }
01037 
01038 #ifndef HAVE_BASENAME
01039 /*
01040   (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
01041   Edition)
01042 
01043   The basename() function shall take the pathname pointed to by path and
01044   return a pointer to the final component of the pathname, deleting any
01045   trailing '/' characters.
01046 
01047   If the string pointed to by path consists entirely of the '/' character,
01048   basename() shall return a pointer to the string "/". If the string pointed
01049   to by path is exactly "//", it is implementation-defined whether '/' or "//"
01050   is returned.
01051 
01052   If path is a null pointer or points to an empty string, basename() shall
01053   return a pointer to the string ".".
01054 
01055   The basename() function may modify the string pointed to by path, and may
01056   return a pointer to static storage that may then be overwritten by a
01057   subsequent call to basename().
01058 
01059   The basename() function need not be reentrant. A function that is not
01060   required to be reentrant is not required to be thread-safe.
01061 
01062 */
01063 static char *Curl_basename(char *path)
01064 {
01065   /* Ignore all the details above for now and make a quick and simple
01066      implementaion here */
01067   char *s1;
01068   char *s2;
01069 
01070   s1=strrchr(path, '/');
01071   s2=strrchr(path, '\\');
01072 
01073   if(s1 && s2) {
01074     path = (s1 > s2? s1 : s2)+1;
01075   }
01076   else if(s1)
01077     path = s1 + 1;
01078   else if(s2)
01079     path = s2 + 1;
01080 
01081   return path;
01082 }
01083 #endif
01084 
01085 static char *strippath(const char *fullfile)
01086 {
01087   char *filename;
01088   char *base;
01089   filename = strdup(fullfile); /* duplicate since basename() may ruin the
01090                                   buffer it works on */
01091   if(!filename)
01092     return NULL;
01093   base = strdup(basename(filename));
01094 
01095   free(filename); /* free temporary buffer */
01096 
01097   return base; /* returns an allocated string or NULL ! */
01098 }
01099 
01100 static CURLcode formdata_add_filename(const struct curl_httppost *file,
01101                                       struct FormData **form,
01102                                       curl_off_t *size)
01103 {
01104   CURLcode result = CURLE_OK;
01105   char *filename = file->showfilename;
01106   char *filebasename = NULL;
01107   char *filename_escaped = NULL;
01108 
01109   if(!filename) {
01110     filebasename = strippath(file->contents);
01111     if(!filebasename)
01112       return CURLE_OUT_OF_MEMORY;
01113     filename = filebasename;
01114   }
01115 
01116   if(strchr(filename, '\\') || strchr(filename, '"')) {
01117     char *p0, *p1;
01118 
01119     /* filename need be escaped */
01120     filename_escaped = malloc(strlen(filename)*2+1);
01121     if(!filename_escaped) {
01122       free(filebasename);
01123       return CURLE_OUT_OF_MEMORY;
01124     }
01125     p0 = filename_escaped;
01126     p1 = filename;
01127     while(*p1) {
01128       if(*p1 == '\\' || *p1 == '"')
01129         *p0++ = '\\';
01130       *p0++ = *p1++;
01131     }
01132     *p0 = '\0';
01133     filename = filename_escaped;
01134   }
01135   result = AddFormDataf(form, size,
01136                         "; filename=\"%s\"",
01137                         filename);
01138   free(filename_escaped);
01139   free(filebasename);
01140   return result;
01141 }
01142 
01143 /*
01144  * Curl_getformdata() converts a linked list of "meta data" into a complete
01145  * (possibly huge) multipart formdata. The input list is in 'post', while the
01146  * output resulting linked lists gets stored in '*finalform'. *sizep will get
01147  * the total size of the whole POST.
01148  * A multipart/form_data content-type is built, unless a custom content-type
01149  * is passed in 'custom_content_type'.
01150  *
01151  * This function will not do a failf() for the potential memory failures but
01152  * should for all other errors it spots. Just note that this function MAY get
01153  * a NULL pointer in the 'data' argument.
01154  */
01155 
01156 CURLcode Curl_getformdata(struct Curl_easy *data,
01157                           struct FormData **finalform,
01158                           struct curl_httppost *post,
01159                           const char *custom_content_type,
01160                           curl_off_t *sizep)
01161 {
01162   struct FormData *form = NULL;
01163   struct FormData *firstform;
01164   struct curl_httppost *file;
01165   CURLcode result = CURLE_OK;
01166 
01167   curl_off_t size = 0; /* support potentially ENORMOUS formposts */
01168   char *boundary;
01169   char *fileboundary = NULL;
01170   struct curl_slist *curList;
01171 
01172   *finalform = NULL; /* default form is empty */
01173 
01174   if(!post)
01175     return result; /* no input => no output! */
01176 
01177   boundary = formboundary(data);
01178   if(!boundary)
01179     return CURLE_OUT_OF_MEMORY;
01180 
01181   /* Make the first line of the output */
01182   result = AddFormDataf(&form, NULL,
01183                         "%s; boundary=%s\r\n",
01184                         custom_content_type?custom_content_type:
01185                         "Content-Type: multipart/form-data",
01186                         boundary);
01187 
01188   if(result) {
01189     free(boundary);
01190     return result;
01191   }
01192   /* we DO NOT include that line in the total size of the POST, since it'll be
01193      part of the header! */
01194 
01195   firstform = form;
01196 
01197   do {
01198 
01199     if(size) {
01200       result = AddFormDataf(&form, &size, "\r\n");
01201       if(result)
01202         break;
01203     }
01204 
01205     /* boundary */
01206     result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
01207     if(result)
01208       break;
01209 
01210     /* Maybe later this should be disabled when a custom_content_type is
01211        passed, since Content-Disposition is not meaningful for all multipart
01212        types.
01213     */
01214     result = AddFormDataf(&form, &size,
01215                           "Content-Disposition: form-data; name=\"");
01216     if(result)
01217       break;
01218 
01219     result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
01220                          &size);
01221     if(result)
01222       break;
01223 
01224     result = AddFormDataf(&form, &size, "\"");
01225     if(result)
01226       break;
01227 
01228     if(post->more) {
01229       /* If used, this is a link to more file names, we must then do
01230          the magic to include several files with the same field name */
01231 
01232       free(fileboundary);
01233       fileboundary = formboundary(data);
01234       if(!fileboundary) {
01235         result = CURLE_OUT_OF_MEMORY;
01236         break;
01237       }
01238 
01239       result = AddFormDataf(&form, &size,
01240                             "\r\nContent-Type: multipart/mixed;"
01241                             " boundary=%s\r\n",
01242                             fileboundary);
01243       if(result)
01244         break;
01245     }
01246 
01247     file = post;
01248 
01249     do {
01250 
01251       /* If 'showfilename' is set, that is a faked name passed on to us
01252          to use to in the formpost. If that is not set, the actually used
01253          local file name should be added. */
01254 
01255       if(post->more) {
01256         /* if multiple-file */
01257         result = AddFormDataf(&form, &size,
01258                               "\r\n--%s\r\nContent-Disposition: "
01259                               "attachment",
01260                               fileboundary);
01261         if(result)
01262           break;
01263         result = formdata_add_filename(file, &form, &size);
01264         if(result)
01265           break;
01266       }
01267       else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
01268                              HTTPPOST_CALLBACK)) {
01269         /* it should be noted that for the HTTPPOST_FILENAME and
01270            HTTPPOST_CALLBACK cases the ->showfilename struct member is always
01271            assigned at this point */
01272         if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) {
01273           result = formdata_add_filename(post, &form, &size);
01274         }
01275 
01276         if(result)
01277           break;
01278       }
01279 
01280       if(file->contenttype) {
01281         /* we have a specified type */
01282         result = AddFormDataf(&form, &size,
01283                               "\r\nContent-Type: %s",
01284                               file->contenttype);
01285         if(result)
01286           break;
01287       }
01288 
01289       curList = file->contentheader;
01290       while(curList) {
01291         /* Process the additional headers specified for this form */
01292         result = AddFormDataf(&form, &size, "\r\n%s", curList->data);
01293         if(result)
01294           break;
01295         curList = curList->next;
01296       }
01297       if(result)
01298         break;
01299 
01300       result = AddFormDataf(&form, &size, "\r\n\r\n");
01301       if(result)
01302         break;
01303 
01304       if((post->flags & HTTPPOST_FILENAME) ||
01305          (post->flags & HTTPPOST_READFILE)) {
01306         /* we should include the contents from the specified file */
01307         FILE *fileread;
01308 
01309         fileread = !strcmp("-", file->contents)?
01310           stdin:fopen(file->contents, "rb"); /* binary read for win32  */
01311 
01312         /*
01313          * VMS: This only allows for stream files on VMS.  Stream files are
01314          * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
01315          * every record needs to have a \n appended & 1 added to SIZE
01316          */
01317 
01318         if(fileread) {
01319           if(fileread != stdin) {
01320             /* close the file */
01321             fclose(fileread);
01322             /* add the file name only - for later reading from this */
01323             result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
01324           }
01325           else {
01326             /* When uploading from stdin, we can't know the size of the file,
01327              * thus must read the full file as before. We *could* use chunked
01328              * transfer-encoding, but that only works for HTTP 1.1 and we
01329              * can't be sure we work with such a server.
01330              */
01331             size_t nread;
01332             char buffer[512];
01333             while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
01334               result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
01335               if(result)
01336                 break;
01337             }
01338           }
01339         }
01340         else {
01341           if(data)
01342             failf(data, "couldn't open file \"%s\"", file->contents);
01343           *finalform = NULL;
01344           result = CURLE_READ_ERROR;
01345         }
01346       }
01347       else if(post->flags & HTTPPOST_BUFFER)
01348         /* include contents of buffer */
01349         result = AddFormData(&form, FORM_CONTENT, post->buffer,
01350                              post->bufferlength, &size);
01351       else if(post->flags & HTTPPOST_CALLBACK)
01352         /* the contents should be read with the callback and the size is set
01353            with the contentslength */
01354         result = AddFormData(&form, FORM_CALLBACK, post->userp,
01355                              post->flags&CURL_HTTPPOST_LARGE?
01356                              post->contentlen:post->contentslength, &size);
01357       else
01358         /* include the contents we got */
01359         result = AddFormData(&form, FORM_CONTENT, post->contents,
01360                              post->flags&CURL_HTTPPOST_LARGE?
01361                              post->contentlen:post->contentslength, &size);
01362       file = file->more;
01363     } while(file && !result); /* for each specified file for this field */
01364 
01365     if(result)
01366       break;
01367 
01368     if(post->more) {
01369       /* this was a multiple-file inclusion, make a termination file
01370          boundary: */
01371       result = AddFormDataf(&form, &size,
01372                            "\r\n--%s--",
01373                            fileboundary);
01374       if(result)
01375         break;
01376     }
01377     post = post->next;
01378   } while(post); /* for each field */
01379 
01380   /* end-boundary for everything */
01381   if(!result)
01382     result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary);
01383 
01384   if(result) {
01385     Curl_formclean(&firstform);
01386     free(fileboundary);
01387     free(boundary);
01388     return result;
01389   }
01390 
01391   *sizep = size;
01392 
01393   free(fileboundary);
01394   free(boundary);
01395 
01396   *finalform = firstform;
01397 
01398   return result;
01399 }
01400 
01401 /*
01402  * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
01403  * and resets the 'sent' counter.
01404  */
01405 int Curl_FormInit(struct Form *form, struct FormData *formdata)
01406 {
01407   if(!formdata)
01408     return 1; /* error */
01409 
01410   form->data = formdata;
01411   form->sent = 0;
01412   form->fp = NULL;
01413   form->fread_func = ZERO_NULL;
01414 
01415   return 0;
01416 }
01417 
01418 #ifndef __VMS
01419 # define fopen_read fopen
01420 #else
01421   /*
01422    * vmsfopenread
01423    *
01424    * For upload to work as expected on VMS, different optional
01425    * parameters must be added to the fopen command based on
01426    * record format of the file.
01427    *
01428    */
01429 # define fopen_read vmsfopenread
01430 static FILE * vmsfopenread(const char *file, const char *mode)
01431 {
01432   struct_stat statbuf;
01433   int result;
01434 
01435   result = stat(file, &statbuf);
01436 
01437   switch(statbuf.st_fab_rfm) {
01438   case FAB$C_VAR:
01439   case FAB$C_VFC:
01440   case FAB$C_STMCR:
01441     return fopen(file, FOPEN_READTEXT); /* VMS */
01442     break;
01443   default:
01444     return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
01445   }
01446 }
01447 #endif
01448 
01449 /*
01450  * readfromfile()
01451  *
01452  * The read callback that this function may use can return a value larger than
01453  * 'size' (which then this function returns) that indicates a problem and it
01454  * must be properly dealt with
01455  */
01456 static size_t readfromfile(struct Form *form, char *buffer,
01457                            size_t size)
01458 {
01459   size_t nread;
01460   bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE;
01461 
01462   if(callback) {
01463     if(form->fread_func == ZERO_NULL)
01464       return 0;
01465     else
01466       nread = form->fread_func(buffer, 1, size, form->data->line);
01467   }
01468   else {
01469     if(!form->fp) {
01470       /* this file hasn't yet been opened */
01471       form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
01472       if(!form->fp)
01473         return (size_t)-1; /* failure */
01474     }
01475     nread = fread(buffer, 1, size, form->fp);
01476   }
01477   if(!nread) {
01478     /* this is the last chunk from the file, move on */
01479     if(form->fp) {
01480       fclose(form->fp);
01481       form->fp = NULL;
01482     }
01483     form->data = form->data->next;
01484   }
01485 
01486   return nread;
01487 }
01488 
01489 /*
01490  * Curl_FormReader() is the fread() emulation function that will be used to
01491  * deliver the formdata to the transfer loop and then sent away to the peer.
01492  */
01493 size_t Curl_FormReader(char *buffer,
01494                        size_t size,
01495                        size_t nitems,
01496                        FILE *mydata)
01497 {
01498   struct Form *form;
01499   size_t wantedsize;
01500   size_t gotsize = 0;
01501 
01502   form=(struct Form *)mydata;
01503 
01504   wantedsize = size * nitems;
01505 
01506   if(!form->data)
01507     return 0; /* nothing, error, empty */
01508 
01509   if((form->data->type == FORM_FILE) ||
01510      (form->data->type == FORM_CALLBACK)) {
01511     gotsize = readfromfile(form, buffer, wantedsize);
01512 
01513     if(gotsize)
01514       /* If positive or -1, return. If zero, continue! */
01515       return gotsize;
01516   }
01517   do {
01518 
01519     if((form->data->length - form->sent) > wantedsize - gotsize) {
01520 
01521       memcpy(buffer + gotsize, form->data->line + form->sent,
01522              wantedsize - gotsize);
01523 
01524       form->sent += wantedsize-gotsize;
01525 
01526       return wantedsize;
01527     }
01528 
01529     memcpy(buffer+gotsize,
01530            form->data->line + form->sent,
01531            (form->data->length - form->sent) );
01532     gotsize += form->data->length - form->sent;
01533 
01534     form->sent = 0;
01535 
01536     form->data = form->data->next; /* advance */
01537 
01538   } while(form->data && (form->data->type < FORM_CALLBACK));
01539   /* If we got an empty line and we have more data, we proceed to the next
01540      line immediately to avoid returning zero before we've reached the end. */
01541 
01542   return gotsize;
01543 }
01544 
01545 /*
01546  * Curl_formpostheader() returns the first line of the formpost, the
01547  * request-header part (which is not part of the request-body like the rest of
01548  * the post).
01549  */
01550 char *Curl_formpostheader(void *formp, size_t *len)
01551 {
01552   char *header;
01553   struct Form *form=(struct Form *)formp;
01554 
01555   if(!form->data)
01556     return 0; /* nothing, ERROR! */
01557 
01558   header = form->data->line;
01559   *len = form->data->length;
01560 
01561   form->data = form->data->next; /* advance */
01562 
01563   return header;
01564 }
01565 
01566 /*
01567  * formboundary() creates a suitable boundary string and returns an allocated
01568  * one.
01569  */
01570 static char *formboundary(struct Curl_easy *data)
01571 {
01572   /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
01573      combinations */
01574   unsigned int rnd[2];
01575   CURLcode result = Curl_rand(data, &rnd[0], 2);
01576   if(result)
01577     return NULL;
01578 
01579   return aprintf("------------------------%08x%08x", rnd[0], rnd[1]);
01580 }
01581 
01582 #else  /* CURL_DISABLE_HTTP */
01583 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
01584                           struct curl_httppost **last_post,
01585                           ...)
01586 {
01587   (void)httppost;
01588   (void)last_post;
01589   return CURL_FORMADD_DISABLED;
01590 }
01591 
01592 int curl_formget(struct curl_httppost *form, void *arg,
01593                  curl_formget_callback append)
01594 {
01595   (void) form;
01596   (void) arg;
01597   (void) append;
01598   return CURL_FORMADD_DISABLED;
01599 }
01600 
01601 void curl_formfree(struct curl_httppost *form)
01602 {
01603   (void)form;
01604   /* does nothing HTTP is disabled */
01605 }
01606 
01607 
01608 #endif  /* !defined(CURL_DISABLE_HTTP) */


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:02