Annotation of embedaddon/curl/lib/formdata.c, revision 1.1.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>