Annotation of embedaddon/curl/lib/formdata.c, revision 1.1

1.1     ! misho       1: /***************************************************************************
        !             2:  *                                  _   _ ____  _
        !             3:  *  Project                     ___| | | |  _ \| |
        !             4:  *                             / __| | | | |_) | |
        !             5:  *                            | (__| |_| |  _ <| |___
        !             6:  *                             \___|\___/|_| \_\_____|
        !             7:  *
        !             8:  * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
        !             9:  *
        !            10:  * This software is licensed as described in the file COPYING, which
        !            11:  * you should have received as part of this distribution. The terms
        !            12:  * are also available at 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: #include "formdata.h"
        !            28: #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)
        !            29: 
        !            30: #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
        !            31: #include <libgen.h>
        !            32: #endif
        !            33: 
        !            34: #include "urldata.h" /* for struct Curl_easy */
        !            35: #include "mime.h"
        !            36: #include "non-ascii.h"
        !            37: #include "vtls/vtls.h"
        !            38: #include "strcase.h"
        !            39: #include "sendf.h"
        !            40: #include "strdup.h"
        !            41: #include "rand.h"
        !            42: #include "warnless.h"
        !            43: /* The last 3 #include files should be in this order */
        !            44: #include "curl_printf.h"
        !            45: #include "curl_memory.h"
        !            46: #include "memdebug.h"
        !            47: 
        !            48: 
        !            49: #define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
        !            50: #define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
        !            51: #define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
        !            52: #define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
        !            53: #define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
        !            54: #define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
        !            55: #define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
        !            56: 
        !            57: /***************************************************************************
        !            58:  *
        !            59:  * AddHttpPost()
        !            60:  *
        !            61:  * Adds a HttpPost structure to the list, if parent_post is given becomes
        !            62:  * a subpost of parent_post instead of a direct list element.
        !            63:  *
        !            64:  * Returns newly allocated HttpPost on success and NULL if malloc failed.
        !            65:  *
        !            66:  ***************************************************************************/
        !            67: static struct curl_httppost *
        !            68: AddHttpPost(char *name, size_t namelength,
        !            69:             char *value, curl_off_t contentslength,
        !            70:             char *buffer, size_t bufferlength,
        !            71:             char *contenttype,
        !            72:             long flags,
        !            73:             struct curl_slist *contentHeader,
        !            74:             char *showfilename, char *userp,
        !            75:             struct curl_httppost *parent_post,
        !            76:             struct curl_httppost **httppost,
        !            77:             struct curl_httppost **last_post)
        !            78: {
        !            79:   struct curl_httppost *post;
        !            80:   post = calloc(1, sizeof(struct curl_httppost));
        !            81:   if(post) {
        !            82:     post->name = name;
        !            83:     post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
        !            84:     post->contents = value;
        !            85:     post->contentlen = contentslength;
        !            86:     post->buffer = buffer;
        !            87:     post->bufferlength = (long)bufferlength;
        !            88:     post->contenttype = contenttype;
        !            89:     post->contentheader = contentHeader;
        !            90:     post->showfilename = showfilename;
        !            91:     post->userp = userp;
        !            92:     post->flags = flags | CURL_HTTPPOST_LARGE;
        !            93:   }
        !            94:   else
        !            95:     return NULL;
        !            96: 
        !            97:   if(parent_post) {
        !            98:     /* now, point our 'more' to the original 'more' */
        !            99:     post->more = parent_post->more;
        !           100: 
        !           101:     /* then move the original 'more' to point to ourselves */
        !           102:     parent_post->more = post;
        !           103:   }
        !           104:   else {
        !           105:     /* make the previous point to this */
        !           106:     if(*last_post)
        !           107:       (*last_post)->next = post;
        !           108:     else
        !           109:       (*httppost) = post;
        !           110: 
        !           111:     (*last_post) = post;
        !           112:   }
        !           113:   return post;
        !           114: }
        !           115: 
        !           116: /***************************************************************************
        !           117:  *
        !           118:  * AddFormInfo()
        !           119:  *
        !           120:  * Adds a FormInfo structure to the list presented by parent_form_info.
        !           121:  *
        !           122:  * Returns newly allocated FormInfo on success and NULL if malloc failed/
        !           123:  * parent_form_info is NULL.
        !           124:  *
        !           125:  ***************************************************************************/
        !           126: static FormInfo * AddFormInfo(char *value,
        !           127:                               char *contenttype,
        !           128:                               FormInfo *parent_form_info)
        !           129: {
        !           130:   FormInfo *form_info;
        !           131:   form_info = calloc(1, sizeof(struct FormInfo));
        !           132:   if(form_info) {
        !           133:     if(value)
        !           134:       form_info->value = value;
        !           135:     if(contenttype)
        !           136:       form_info->contenttype = contenttype;
        !           137:     form_info->flags = HTTPPOST_FILENAME;
        !           138:   }
        !           139:   else
        !           140:     return NULL;
        !           141: 
        !           142:   if(parent_form_info) {
        !           143:     /* now, point our 'more' to the original 'more' */
        !           144:     form_info->more = parent_form_info->more;
        !           145: 
        !           146:     /* then move the original 'more' to point to ourselves */
        !           147:     parent_form_info->more = form_info;
        !           148:   }
        !           149: 
        !           150:   return form_info;
        !           151: }
        !           152: 
        !           153: /***************************************************************************
        !           154:  *
        !           155:  * FormAdd()
        !           156:  *
        !           157:  * Stores a formpost parameter and builds the appropriate linked list.
        !           158:  *
        !           159:  * Has two principal functionalities: using files and byte arrays as
        !           160:  * post parts. Byte arrays are either copied or just the pointer is stored
        !           161:  * (as the user requests) while for files only the filename and not the
        !           162:  * content is stored.
        !           163:  *
        !           164:  * While you may have only one byte array for each name, multiple filenames
        !           165:  * are allowed (and because of this feature CURLFORM_END is needed after
        !           166:  * using CURLFORM_FILE).
        !           167:  *
        !           168:  * Examples:
        !           169:  *
        !           170:  * Simple name/value pair with copied contents:
        !           171:  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
        !           172:  * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
        !           173:  *
        !           174:  * name/value pair where only the content pointer is remembered:
        !           175:  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
        !           176:  * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
        !           177:  * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
        !           178:  *
        !           179:  * storing a filename (CONTENTTYPE is optional!):
        !           180:  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
        !           181:  * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
        !           182:  * CURLFORM_END);
        !           183:  *
        !           184:  * storing multiple filenames:
        !           185:  * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
        !           186:  * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
        !           187:  *
        !           188:  * Returns:
        !           189:  * CURL_FORMADD_OK             on success
        !           190:  * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
        !           191:  * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
        !           192:  * CURL_FORMADD_NULL           if a null pointer was given for a char
        !           193:  * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
        !           194:  * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
        !           195:  * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
        !           196:  * CURL_FORMADD_MEMORY         if a HttpPost struct cannot be allocated
        !           197:  * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
        !           198:  * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
        !           199:  *
        !           200:  ***************************************************************************/
        !           201: 
        !           202: static
        !           203: CURLFORMcode FormAdd(struct curl_httppost **httppost,
        !           204:                      struct curl_httppost **last_post,
        !           205:                      va_list params)
        !           206: {
        !           207:   FormInfo *first_form, *current_form, *form = NULL;
        !           208:   CURLFORMcode return_value = CURL_FORMADD_OK;
        !           209:   const char *prevtype = NULL;
        !           210:   struct curl_httppost *post = NULL;
        !           211:   CURLformoption option;
        !           212:   struct curl_forms *forms = NULL;
        !           213:   char *array_value = NULL; /* value read from an array */
        !           214: 
        !           215:   /* This is a state variable, that if TRUE means that we're parsing an
        !           216:      array that we got passed to us. If FALSE we're parsing the input
        !           217:      va_list arguments. */
        !           218:   bool array_state = FALSE;
        !           219: 
        !           220:   /*
        !           221:    * We need to allocate the first struct to fill in.
        !           222:    */
        !           223:   first_form = calloc(1, sizeof(struct FormInfo));
        !           224:   if(!first_form)
        !           225:     return CURL_FORMADD_MEMORY;
        !           226: 
        !           227:   current_form = first_form;
        !           228: 
        !           229:   /*
        !           230:    * Loop through all the options set. Break if we have an error to report.
        !           231:    */
        !           232:   while(return_value == CURL_FORMADD_OK) {
        !           233: 
        !           234:     /* first see if we have more parts of the array param */
        !           235:     if(array_state && forms) {
        !           236:       /* get the upcoming option from the given array */
        !           237:       option = forms->option;
        !           238:       array_value = (char *)forms->value;
        !           239: 
        !           240:       forms++; /* advance this to next entry */
        !           241:       if(CURLFORM_END == option) {
        !           242:         /* end of array state */
        !           243:         array_state = FALSE;
        !           244:         continue;
        !           245:       }
        !           246:     }
        !           247:     else {
        !           248:       /* This is not array-state, get next option */
        !           249:       option = va_arg(params, CURLformoption);
        !           250:       if(CURLFORM_END == option)
        !           251:         break;
        !           252:     }
        !           253: 
        !           254:     switch(option) {
        !           255:     case CURLFORM_ARRAY:
        !           256:       if(array_state)
        !           257:         /* we don't support an array from within an array */
        !           258:         return_value = CURL_FORMADD_ILLEGAL_ARRAY;
        !           259:       else {
        !           260:         forms = va_arg(params, struct curl_forms *);
        !           261:         if(forms)
        !           262:           array_state = TRUE;
        !           263:         else
        !           264:           return_value = CURL_FORMADD_NULL;
        !           265:       }
        !           266:       break;
        !           267: 
        !           268:       /*
        !           269:        * Set the Name property.
        !           270:        */
        !           271:     case CURLFORM_PTRNAME:
        !           272: #ifdef CURL_DOES_CONVERSIONS
        !           273:       /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
        !           274:        * the data in all cases so that we'll have safe memory for the eventual
        !           275:        * conversion.
        !           276:        */
        !           277: #else
        !           278:       current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
        !           279: #endif
        !           280:       /* FALLTHROUGH */
        !           281:     case CURLFORM_COPYNAME:
        !           282:       if(current_form->name)
        !           283:         return_value = CURL_FORMADD_OPTION_TWICE;
        !           284:       else {
        !           285:         char *name = array_state?
        !           286:           array_value:va_arg(params, char *);
        !           287:         if(name)
        !           288:           current_form->name = name; /* store for the moment */
        !           289:         else
        !           290:           return_value = CURL_FORMADD_NULL;
        !           291:       }
        !           292:       break;
        !           293:     case CURLFORM_NAMELENGTH:
        !           294:       if(current_form->namelength)
        !           295:         return_value = CURL_FORMADD_OPTION_TWICE;
        !           296:       else
        !           297:         current_form->namelength =
        !           298:           array_state?(size_t)array_value:(size_t)va_arg(params, long);
        !           299:       break;
        !           300: 
        !           301:       /*
        !           302:        * Set the contents property.
        !           303:        */
        !           304:     case CURLFORM_PTRCONTENTS:
        !           305:       current_form->flags |= HTTPPOST_PTRCONTENTS;
        !           306:       /* FALLTHROUGH */
        !           307:     case CURLFORM_COPYCONTENTS:
        !           308:       if(current_form->value)
        !           309:         return_value = CURL_FORMADD_OPTION_TWICE;
        !           310:       else {
        !           311:         char *value =
        !           312:           array_state?array_value:va_arg(params, char *);
        !           313:         if(value)
        !           314:           current_form->value = value; /* store for the moment */
        !           315:         else
        !           316:           return_value = CURL_FORMADD_NULL;
        !           317:       }
        !           318:       break;
        !           319:     case CURLFORM_CONTENTSLENGTH:
        !           320:       current_form->contentslength =
        !           321:         array_state?(size_t)array_value:(size_t)va_arg(params, long);
        !           322:       break;
        !           323: 
        !           324:     case CURLFORM_CONTENTLEN:
        !           325:       current_form->flags |= CURL_HTTPPOST_LARGE;
        !           326:       current_form->contentslength =
        !           327:         array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
        !           328:       break;
        !           329: 
        !           330:       /* Get contents from a given file name */
        !           331:     case CURLFORM_FILECONTENT:
        !           332:       if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
        !           333:         return_value = CURL_FORMADD_OPTION_TWICE;
        !           334:       else {
        !           335:         const char *filename = array_state?
        !           336:           array_value:va_arg(params, char *);
        !           337:         if(filename) {
        !           338:           current_form->value = strdup(filename);
        !           339:           if(!current_form->value)
        !           340:             return_value = CURL_FORMADD_MEMORY;
        !           341:           else {
        !           342:             current_form->flags |= HTTPPOST_READFILE;
        !           343:             current_form->value_alloc = TRUE;
        !           344:           }
        !           345:         }
        !           346:         else
        !           347:           return_value = CURL_FORMADD_NULL;
        !           348:       }
        !           349:       break;
        !           350: 
        !           351:       /* We upload a file */
        !           352:     case CURLFORM_FILE:
        !           353:       {
        !           354:         const char *filename = array_state?array_value:
        !           355:           va_arg(params, char *);
        !           356: 
        !           357:         if(current_form->value) {
        !           358:           if(current_form->flags & HTTPPOST_FILENAME) {
        !           359:             if(filename) {
        !           360:               char *fname = strdup(filename);
        !           361:               if(!fname)
        !           362:                 return_value = CURL_FORMADD_MEMORY;
        !           363:               else {
        !           364:                 form = AddFormInfo(fname, NULL, current_form);
        !           365:                 if(!form) {
        !           366:                   free(fname);
        !           367:                   return_value = CURL_FORMADD_MEMORY;
        !           368:                 }
        !           369:                 else {
        !           370:                   form->value_alloc = TRUE;
        !           371:                   current_form = form;
        !           372:                   form = NULL;
        !           373:                 }
        !           374:               }
        !           375:             }
        !           376:             else
        !           377:               return_value = CURL_FORMADD_NULL;
        !           378:           }
        !           379:           else
        !           380:             return_value = CURL_FORMADD_OPTION_TWICE;
        !           381:         }
        !           382:         else {
        !           383:           if(filename) {
        !           384:             current_form->value = strdup(filename);
        !           385:             if(!current_form->value)
        !           386:               return_value = CURL_FORMADD_MEMORY;
        !           387:             else {
        !           388:               current_form->flags |= HTTPPOST_FILENAME;
        !           389:               current_form->value_alloc = TRUE;
        !           390:             }
        !           391:           }
        !           392:           else
        !           393:             return_value = CURL_FORMADD_NULL;
        !           394:         }
        !           395:         break;
        !           396:       }
        !           397: 
        !           398:     case CURLFORM_BUFFERPTR:
        !           399:       current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
        !           400:       if(current_form->buffer)
        !           401:         return_value = CURL_FORMADD_OPTION_TWICE;
        !           402:       else {
        !           403:         char *buffer =
        !           404:           array_state?array_value:va_arg(params, char *);
        !           405:         if(buffer) {
        !           406:           current_form->buffer = buffer; /* store for the moment */
        !           407:           current_form->value = buffer; /* make it non-NULL to be accepted
        !           408:                                            as fine */
        !           409:         }
        !           410:         else
        !           411:           return_value = CURL_FORMADD_NULL;
        !           412:       }
        !           413:       break;
        !           414: 
        !           415:     case CURLFORM_BUFFERLENGTH:
        !           416:       if(current_form->bufferlength)
        !           417:         return_value = CURL_FORMADD_OPTION_TWICE;
        !           418:       else
        !           419:         current_form->bufferlength =
        !           420:           array_state?(size_t)array_value:(size_t)va_arg(params, long);
        !           421:       break;
        !           422: 
        !           423:     case CURLFORM_STREAM:
        !           424:       current_form->flags |= HTTPPOST_CALLBACK;
        !           425:       if(current_form->userp)
        !           426:         return_value = CURL_FORMADD_OPTION_TWICE;
        !           427:       else {
        !           428:         char *userp =
        !           429:           array_state?array_value:va_arg(params, char *);
        !           430:         if(userp) {
        !           431:           current_form->userp = userp;
        !           432:           current_form->value = userp; /* this isn't strictly true but we
        !           433:                                           derive a value from this later on
        !           434:                                           and we need this non-NULL to be
        !           435:                                           accepted as a fine form part */
        !           436:         }
        !           437:         else
        !           438:           return_value = CURL_FORMADD_NULL;
        !           439:       }
        !           440:       break;
        !           441: 
        !           442:     case CURLFORM_CONTENTTYPE:
        !           443:       {
        !           444:         const char *contenttype =
        !           445:           array_state?array_value:va_arg(params, char *);
        !           446:         if(current_form->contenttype) {
        !           447:           if(current_form->flags & HTTPPOST_FILENAME) {
        !           448:             if(contenttype) {
        !           449:               char *type = strdup(contenttype);
        !           450:               if(!type)
        !           451:                 return_value = CURL_FORMADD_MEMORY;
        !           452:               else {
        !           453:                 form = AddFormInfo(NULL, type, current_form);
        !           454:                 if(!form) {
        !           455:                   free(type);
        !           456:                   return_value = CURL_FORMADD_MEMORY;
        !           457:                 }
        !           458:                 else {
        !           459:                   form->contenttype_alloc = TRUE;
        !           460:                   current_form = form;
        !           461:                   form = NULL;
        !           462:                 }
        !           463:               }
        !           464:             }
        !           465:             else
        !           466:               return_value = CURL_FORMADD_NULL;
        !           467:           }
        !           468:           else
        !           469:             return_value = CURL_FORMADD_OPTION_TWICE;
        !           470:         }
        !           471:         else {
        !           472:           if(contenttype) {
        !           473:             current_form->contenttype = strdup(contenttype);
        !           474:             if(!current_form->contenttype)
        !           475:               return_value = CURL_FORMADD_MEMORY;
        !           476:             else
        !           477:               current_form->contenttype_alloc = TRUE;
        !           478:           }
        !           479:           else
        !           480:             return_value = CURL_FORMADD_NULL;
        !           481:         }
        !           482:         break;
        !           483:       }
        !           484:     case CURLFORM_CONTENTHEADER:
        !           485:       {
        !           486:         /* this "cast increases required alignment of target type" but
        !           487:            we consider it OK anyway */
        !           488:         struct curl_slist *list = array_state?
        !           489:           (struct curl_slist *)(void *)array_value:
        !           490:           va_arg(params, struct curl_slist *);
        !           491: 
        !           492:         if(current_form->contentheader)
        !           493:           return_value = CURL_FORMADD_OPTION_TWICE;
        !           494:         else
        !           495:           current_form->contentheader = list;
        !           496: 
        !           497:         break;
        !           498:       }
        !           499:     case CURLFORM_FILENAME:
        !           500:     case CURLFORM_BUFFER:
        !           501:       {
        !           502:         const char *filename = array_state?array_value:
        !           503:           va_arg(params, char *);
        !           504:         if(current_form->showfilename)
        !           505:           return_value = CURL_FORMADD_OPTION_TWICE;
        !           506:         else {
        !           507:           current_form->showfilename = strdup(filename);
        !           508:           if(!current_form->showfilename)
        !           509:             return_value = CURL_FORMADD_MEMORY;
        !           510:           else
        !           511:             current_form->showfilename_alloc = TRUE;
        !           512:         }
        !           513:         break;
        !           514:       }
        !           515:     default:
        !           516:       return_value = CURL_FORMADD_UNKNOWN_OPTION;
        !           517:       break;
        !           518:     }
        !           519:   }
        !           520: 
        !           521:   if(CURL_FORMADD_OK != return_value) {
        !           522:     /* On error, free allocated fields for all nodes of the FormInfo linked
        !           523:        list without deallocating nodes. List nodes are deallocated later on */
        !           524:     FormInfo *ptr;
        !           525:     for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
        !           526:       if(ptr->name_alloc) {
        !           527:         Curl_safefree(ptr->name);
        !           528:         ptr->name_alloc = FALSE;
        !           529:       }
        !           530:       if(ptr->value_alloc) {
        !           531:         Curl_safefree(ptr->value);
        !           532:         ptr->value_alloc = FALSE;
        !           533:       }
        !           534:       if(ptr->contenttype_alloc) {
        !           535:         Curl_safefree(ptr->contenttype);
        !           536:         ptr->contenttype_alloc = FALSE;
        !           537:       }
        !           538:       if(ptr->showfilename_alloc) {
        !           539:         Curl_safefree(ptr->showfilename);
        !           540:         ptr->showfilename_alloc = FALSE;
        !           541:       }
        !           542:     }
        !           543:   }
        !           544: 
        !           545:   if(CURL_FORMADD_OK == return_value) {
        !           546:     /* go through the list, check for completeness and if everything is
        !           547:      * alright add the HttpPost item otherwise set return_value accordingly */
        !           548: 
        !           549:     post = NULL;
        !           550:     for(form = first_form;
        !           551:         form != NULL;
        !           552:         form = form->more) {
        !           553:       if(((!form->name || !form->value) && !post) ||
        !           554:          ( (form->contentslength) &&
        !           555:            (form->flags & HTTPPOST_FILENAME) ) ||
        !           556:          ( (form->flags & HTTPPOST_FILENAME) &&
        !           557:            (form->flags & HTTPPOST_PTRCONTENTS) ) ||
        !           558: 
        !           559:          ( (!form->buffer) &&
        !           560:            (form->flags & HTTPPOST_BUFFER) &&
        !           561:            (form->flags & HTTPPOST_PTRBUFFER) ) ||
        !           562: 
        !           563:          ( (form->flags & HTTPPOST_READFILE) &&
        !           564:            (form->flags & HTTPPOST_PTRCONTENTS) )
        !           565:         ) {
        !           566:         return_value = CURL_FORMADD_INCOMPLETE;
        !           567:         break;
        !           568:       }
        !           569:       if(((form->flags & HTTPPOST_FILENAME) ||
        !           570:           (form->flags & HTTPPOST_BUFFER)) &&
        !           571:          !form->contenttype) {
        !           572:         char *f = (form->flags & HTTPPOST_BUFFER)?
        !           573:           form->showfilename : form->value;
        !           574:         char const *type;
        !           575:         type = Curl_mime_contenttype(f);
        !           576:         if(!type)
        !           577:           type = prevtype;
        !           578:         if(!type)
        !           579:           type = FILE_CONTENTTYPE_DEFAULT;
        !           580: 
        !           581:         /* our contenttype is missing */
        !           582:         form->contenttype = strdup(type);
        !           583:         if(!form->contenttype) {
        !           584:           return_value = CURL_FORMADD_MEMORY;
        !           585:           break;
        !           586:         }
        !           587:         form->contenttype_alloc = TRUE;
        !           588:       }
        !           589:       if(form->name && form->namelength) {
        !           590:         /* Name should not contain nul bytes. */
        !           591:         size_t i;
        !           592:         for(i = 0; i < form->namelength; i++)
        !           593:           if(!form->name[i]) {
        !           594:             return_value = CURL_FORMADD_NULL;
        !           595:             break;
        !           596:           }
        !           597:         if(return_value != CURL_FORMADD_OK)
        !           598:           break;
        !           599:       }
        !           600:       if(!(form->flags & HTTPPOST_PTRNAME) &&
        !           601:          (form == first_form) ) {
        !           602:         /* Note that there's small risk that form->name is NULL here if the
        !           603:            app passed in a bad combo, so we better check for that first. */
        !           604:         if(form->name) {
        !           605:           /* copy name (without strdup; possibly not nul-terminated) */
        !           606:           form->name = Curl_memdup(form->name, form->namelength?
        !           607:                                    form->namelength:
        !           608:                                    strlen(form->name) + 1);
        !           609:         }
        !           610:         if(!form->name) {
        !           611:           return_value = CURL_FORMADD_MEMORY;
        !           612:           break;
        !           613:         }
        !           614:         form->name_alloc = TRUE;
        !           615:       }
        !           616:       if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
        !           617:                           HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
        !           618:                           HTTPPOST_CALLBACK)) && form->value) {
        !           619:         /* copy value (without strdup; possibly contains null characters) */
        !           620:         size_t clen  = (size_t) form->contentslength;
        !           621:         if(!clen)
        !           622:           clen = strlen(form->value) + 1;
        !           623: 
        !           624:         form->value = Curl_memdup(form->value, clen);
        !           625: 
        !           626:         if(!form->value) {
        !           627:           return_value = CURL_FORMADD_MEMORY;
        !           628:           break;
        !           629:         }
        !           630:         form->value_alloc = TRUE;
        !           631:       }
        !           632:       post = AddHttpPost(form->name, form->namelength,
        !           633:                          form->value, form->contentslength,
        !           634:                          form->buffer, form->bufferlength,
        !           635:                          form->contenttype, form->flags,
        !           636:                          form->contentheader, form->showfilename,
        !           637:                          form->userp,
        !           638:                          post, httppost,
        !           639:                          last_post);
        !           640: 
        !           641:       if(!post) {
        !           642:         return_value = CURL_FORMADD_MEMORY;
        !           643:         break;
        !           644:       }
        !           645: 
        !           646:       if(form->contenttype)
        !           647:         prevtype = form->contenttype;
        !           648:     }
        !           649:     if(CURL_FORMADD_OK != return_value) {
        !           650:       /* On error, free allocated fields for nodes of the FormInfo linked
        !           651:          list which are not already owned by the httppost linked list
        !           652:          without deallocating nodes. List nodes are deallocated later on */
        !           653:       FormInfo *ptr;
        !           654:       for(ptr = form; ptr != NULL; ptr = ptr->more) {
        !           655:         if(ptr->name_alloc) {
        !           656:           Curl_safefree(ptr->name);
        !           657:           ptr->name_alloc = FALSE;
        !           658:         }
        !           659:         if(ptr->value_alloc) {
        !           660:           Curl_safefree(ptr->value);
        !           661:           ptr->value_alloc = FALSE;
        !           662:         }
        !           663:         if(ptr->contenttype_alloc) {
        !           664:           Curl_safefree(ptr->contenttype);
        !           665:           ptr->contenttype_alloc = FALSE;
        !           666:         }
        !           667:         if(ptr->showfilename_alloc) {
        !           668:           Curl_safefree(ptr->showfilename);
        !           669:           ptr->showfilename_alloc = FALSE;
        !           670:         }
        !           671:       }
        !           672:     }
        !           673:   }
        !           674: 
        !           675:   /* Always deallocate FormInfo linked list nodes without touching node
        !           676:      fields given that these have either been deallocated or are owned
        !           677:      now by the httppost linked list */
        !           678:   while(first_form) {
        !           679:     FormInfo *ptr = first_form->more;
        !           680:     free(first_form);
        !           681:     first_form = ptr;
        !           682:   }
        !           683: 
        !           684:   return return_value;
        !           685: }
        !           686: 
        !           687: /*
        !           688:  * curl_formadd() is a public API to add a section to the multipart formpost.
        !           689:  *
        !           690:  * @unittest: 1308
        !           691:  */
        !           692: 
        !           693: CURLFORMcode curl_formadd(struct curl_httppost **httppost,
        !           694:                           struct curl_httppost **last_post,
        !           695:                           ...)
        !           696: {
        !           697:   va_list arg;
        !           698:   CURLFORMcode result;
        !           699:   va_start(arg, last_post);
        !           700:   result = FormAdd(httppost, last_post, arg);
        !           701:   va_end(arg);
        !           702:   return result;
        !           703: }
        !           704: 
        !           705: /*
        !           706:  * curl_formget()
        !           707:  * Serialize a curl_httppost struct.
        !           708:  * Returns 0 on success.
        !           709:  *
        !           710:  * @unittest: 1308
        !           711:  */
        !           712: int curl_formget(struct curl_httppost *form, void *arg,
        !           713:                  curl_formget_callback append)
        !           714: {
        !           715:   CURLcode result;
        !           716:   curl_mimepart toppart;
        !           717: 
        !           718:   Curl_mime_initpart(&toppart, NULL); /* default form is empty */
        !           719:   result = Curl_getformdata(NULL, &toppart, form, NULL);
        !           720:   if(!result)
        !           721:     result = Curl_mime_prepare_headers(&toppart, "multipart/form-data",
        !           722:                                        NULL, MIMESTRATEGY_FORM);
        !           723: 
        !           724:   while(!result) {
        !           725:     char buffer[8192];
        !           726:     size_t nread = Curl_mime_read(buffer, 1, sizeof(buffer), &toppart);
        !           727: 
        !           728:     if(!nread)
        !           729:       break;
        !           730: 
        !           731:     if(nread > sizeof(buffer) || append(arg, buffer, nread) != nread) {
        !           732:       result = CURLE_READ_ERROR;
        !           733:       if(nread == CURL_READFUNC_ABORT)
        !           734:         result = CURLE_ABORTED_BY_CALLBACK;
        !           735:     }
        !           736:   }
        !           737: 
        !           738:   Curl_mime_cleanpart(&toppart);
        !           739:   return (int) result;
        !           740: }
        !           741: 
        !           742: /*
        !           743:  * curl_formfree() is an external function to free up a whole form post
        !           744:  * chain
        !           745:  */
        !           746: void curl_formfree(struct curl_httppost *form)
        !           747: {
        !           748:   struct curl_httppost *next;
        !           749: 
        !           750:   if(!form)
        !           751:     /* no form to free, just get out of this */
        !           752:     return;
        !           753: 
        !           754:   do {
        !           755:     next = form->next;  /* the following form line */
        !           756: 
        !           757:     /* recurse to sub-contents */
        !           758:     curl_formfree(form->more);
        !           759: 
        !           760:     if(!(form->flags & HTTPPOST_PTRNAME))
        !           761:       free(form->name); /* free the name */
        !           762:     if(!(form->flags &
        !           763:          (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
        !           764:       )
        !           765:       free(form->contents); /* free the contents */
        !           766:     free(form->contenttype); /* free the content type */
        !           767:     free(form->showfilename); /* free the faked file name */
        !           768:     free(form);       /* free the struct */
        !           769:     form = next;
        !           770:   } while(form); /* continue */
        !           771: }
        !           772: 
        !           773: 
        !           774: /* Set mime part name, taking care of non nul-terminated name string. */
        !           775: static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
        !           776: {
        !           777:   char *zname;
        !           778:   CURLcode res;
        !           779: 
        !           780:   if(!name || !len)
        !           781:     return curl_mime_name(part, name);
        !           782:   zname = malloc(len + 1);
        !           783:   if(!zname)
        !           784:     return CURLE_OUT_OF_MEMORY;
        !           785:   memcpy(zname, name, len);
        !           786:   zname[len] = '\0';
        !           787:   res = curl_mime_name(part, zname);
        !           788:   free(zname);
        !           789:   return res;
        !           790: }
        !           791: 
        !           792: /*
        !           793:  * Curl_getformdata() converts a linked list of "meta data" into a mime
        !           794:  * structure. The input list is in 'post', while the output is stored in
        !           795:  * mime part at '*finalform'.
        !           796:  *
        !           797:  * This function will not do a failf() for the potential memory failures but
        !           798:  * should for all other errors it spots. Just note that this function MAY get
        !           799:  * a NULL pointer in the 'data' argument.
        !           800:  */
        !           801: 
        !           802: CURLcode Curl_getformdata(struct Curl_easy *data,
        !           803:                           curl_mimepart *finalform,
        !           804:                           struct curl_httppost *post,
        !           805:                           curl_read_callback fread_func)
        !           806: {
        !           807:   CURLcode result = CURLE_OK;
        !           808:   curl_mime *form = NULL;
        !           809:   curl_mimepart *part;
        !           810:   struct curl_httppost *file;
        !           811: 
        !           812:   Curl_mime_cleanpart(finalform); /* default form is empty */
        !           813: 
        !           814:   if(!post)
        !           815:     return result; /* no input => no output! */
        !           816: 
        !           817:   form = curl_mime_init(data);
        !           818:   if(!form)
        !           819:     result = CURLE_OUT_OF_MEMORY;
        !           820: 
        !           821:   if(!result)
        !           822:     result = curl_mime_subparts(finalform, form);
        !           823: 
        !           824:   /* Process each top part. */
        !           825:   for(; !result && post; post = post->next) {
        !           826:     /* If we have more than a file here, create a mime subpart and fill it. */
        !           827:     curl_mime *multipart = form;
        !           828:     if(post->more) {
        !           829:       part = curl_mime_addpart(form);
        !           830:       if(!part)
        !           831:         result = CURLE_OUT_OF_MEMORY;
        !           832:       if(!result)
        !           833:         result = setname(part, post->name, post->namelength);
        !           834:       if(!result) {
        !           835:         multipart = curl_mime_init(data);
        !           836:         if(!multipart)
        !           837:           result = CURLE_OUT_OF_MEMORY;
        !           838:       }
        !           839:       if(!result)
        !           840:         result = curl_mime_subparts(part, multipart);
        !           841:     }
        !           842: 
        !           843:     /* Generate all the part contents. */
        !           844:     for(file = post; !result && file; file = file->more) {
        !           845:       /* Create the part. */
        !           846:       part = curl_mime_addpart(multipart);
        !           847:       if(!part)
        !           848:         result = CURLE_OUT_OF_MEMORY;
        !           849: 
        !           850:       /* Set the headers. */
        !           851:       if(!result)
        !           852:         result = curl_mime_headers(part, file->contentheader, 0);
        !           853: 
        !           854:       /* Set the content type. */
        !           855:       if(!result && file->contenttype)
        !           856:         result = curl_mime_type(part, file->contenttype);
        !           857: 
        !           858:       /* Set field name. */
        !           859:       if(!result && !post->more)
        !           860:         result = setname(part, post->name, post->namelength);
        !           861: 
        !           862:       /* Process contents. */
        !           863:       if(!result) {
        !           864:         curl_off_t clen = post->contentslength;
        !           865: 
        !           866:         if(post->flags & CURL_HTTPPOST_LARGE)
        !           867:           clen = post->contentlen;
        !           868:         if(!clen)
        !           869:           clen = -1;
        !           870: 
        !           871:         if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
        !           872:           if(!strcmp(file->contents, "-")) {
        !           873:             /* There are a few cases where the code below won't work; in
        !           874:                particular, freopen(stdin) by the caller is not guaranteed
        !           875:                to result as expected. This feature has been kept for backward
        !           876:                compatibility: use of "-" pseudo file name should be avoided. */
        !           877:             result = curl_mime_data_cb(part, (curl_off_t) -1,
        !           878:                                        (curl_read_callback) fread,
        !           879:                                        CURLX_FUNCTION_CAST(curl_seek_callback,
        !           880:                                                            fseek),
        !           881:                                        NULL, (void *) stdin);
        !           882:           }
        !           883:           else
        !           884:             result = curl_mime_filedata(part, file->contents);
        !           885:           if(!result && (post->flags & HTTPPOST_READFILE))
        !           886:             result = curl_mime_filename(part, NULL);
        !           887:         }
        !           888:         else if(post->flags & HTTPPOST_BUFFER)
        !           889:           result = curl_mime_data(part, post->buffer,
        !           890:                                   post->bufferlength? post->bufferlength: -1);
        !           891:         else if(post->flags & HTTPPOST_CALLBACK)
        !           892:           /* the contents should be read with the callback and the size is set
        !           893:              with the contentslength */
        !           894:           result = curl_mime_data_cb(part, clen,
        !           895:                                      fread_func, NULL, NULL, post->userp);
        !           896:         else {
        !           897:           result = curl_mime_data(part, post->contents, (ssize_t) clen);
        !           898: #ifdef CURL_DOES_CONVERSIONS
        !           899:           /* Convert textual contents now. */
        !           900:           if(!result && data && part->datasize)
        !           901:             result = Curl_convert_to_network(data, part->data, part->datasize);
        !           902: #endif
        !           903:         }
        !           904:       }
        !           905: 
        !           906:       /* Set fake file name. */
        !           907:       if(!result && post->showfilename)
        !           908:         if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
        !           909:                                         HTTPPOST_CALLBACK)))
        !           910:           result = curl_mime_filename(part, post->showfilename);
        !           911:     }
        !           912:   }
        !           913: 
        !           914:   if(result)
        !           915:     Curl_mime_cleanpart(finalform);
        !           916: 
        !           917:   return result;
        !           918: }
        !           919: 
        !           920: #else
        !           921: /* if disabled */
        !           922: CURLFORMcode curl_formadd(struct curl_httppost **httppost,
        !           923:                           struct curl_httppost **last_post,
        !           924:                           ...)
        !           925: {
        !           926:   (void)httppost;
        !           927:   (void)last_post;
        !           928:   return CURL_FORMADD_DISABLED;
        !           929: }
        !           930: 
        !           931: int curl_formget(struct curl_httppost *form, void *arg,
        !           932:                  curl_formget_callback append)
        !           933: {
        !           934:   (void) form;
        !           935:   (void) arg;
        !           936:   (void) append;
        !           937:   return CURL_FORMADD_DISABLED;
        !           938: }
        !           939: 
        !           940: void curl_formfree(struct curl_httppost *form)
        !           941: {
        !           942:   (void)form;
        !           943:   /* does nothing HTTP is disabled */
        !           944: }
        !           945: 
        !           946: #endif  /* if disabled */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>