Home | History | Annotate | Download | only in src
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.haxx.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  ***************************************************************************/
     22 #include "tool_setup.h"
     23 
     24 #include "mime.h"
     25 #include "strcase.h"
     26 
     27 #define ENABLE_CURLX_PRINTF
     28 /* use our own printf() functions */
     29 #include "curlx.h"
     30 
     31 #include "tool_cfgable.h"
     32 #include "tool_convert.h"
     33 #include "tool_msgs.h"
     34 #include "tool_binmode.h"
     35 #include "tool_getparam.h"
     36 #include "tool_paramhlp.h"
     37 #include "tool_formparse.h"
     38 
     39 #include "memdebug.h" /* keep this as LAST include */
     40 
     41 /* Stdin parameters. */
     42 typedef struct {
     43   char *data;  /* Memory data. */
     44   curl_off_t origin;  /* File read origin offset. */
     45   curl_off_t size; /* Data size. */
     46   curl_off_t curpos; /* Current read position. */
     47 }  standard_input;
     48 
     49 
     50 /*
     51  * helper function to get a word from form param
     52  * after call get_parm_word, str either point to string end
     53  * or point to any of end chars.
     54  */
     55 static char *get_param_word(char **str, char **end_pos, char endchar)
     56 {
     57   char *ptr = *str;
     58   char *word_begin = NULL;
     59   char *ptr2;
     60   char *escape = NULL;
     61 
     62   /* the first non-space char is here */
     63   word_begin = ptr;
     64   if(*ptr == '"') {
     65     ++ptr;
     66     while(*ptr) {
     67       if(*ptr == '\\') {
     68         if(ptr[1] == '\\' || ptr[1] == '"') {
     69           /* remember the first escape position */
     70           if(!escape)
     71             escape = ptr;
     72           /* skip escape of back-slash or double-quote */
     73           ptr += 2;
     74           continue;
     75         }
     76       }
     77       if(*ptr == '"') {
     78         *end_pos = ptr;
     79         if(escape) {
     80           /* has escape, we restore the unescaped string here */
     81           ptr = ptr2 = escape;
     82           do {
     83             if(*ptr == '\\' && (ptr[1] == '\\' || ptr[1] == '"'))
     84               ++ptr;
     85             *ptr2++ = *ptr++;
     86           }
     87           while(ptr < *end_pos);
     88           *end_pos = ptr2;
     89         }
     90         while(*ptr && *ptr != ';' && *ptr != endchar)
     91           ++ptr;
     92         *str = ptr;
     93         return word_begin + 1;
     94       }
     95       ++ptr;
     96     }
     97     /* end quote is missing, treat it as non-quoted. */
     98     ptr = word_begin;
     99   }
    100 
    101   while(*ptr && *ptr != ';' && *ptr != endchar)
    102     ++ptr;
    103   *str = *end_pos = ptr;
    104   return word_begin;
    105 }
    106 
    107 /* Append slist item and return -1 if failed. */
    108 static int slist_append(struct curl_slist **plist, const char *data)
    109 {
    110   struct curl_slist *s = curl_slist_append(*plist, data);
    111 
    112   if(!s)
    113     return -1;
    114 
    115   *plist = s;
    116   return 0;
    117 }
    118 
    119 /* Read headers from a file and append to list. */
    120 static int read_field_headers(struct OperationConfig *config,
    121                               const char *filename, FILE *fp,
    122                               struct curl_slist **pheaders)
    123 {
    124   size_t hdrlen = 0;
    125   size_t pos = 0;
    126   int c;
    127   bool incomment = FALSE;
    128   int lineno = 1;
    129   char hdrbuf[999]; /* Max. header length + 1. */
    130 
    131   for(;;) {
    132     c = getc(fp);
    133     if(c == EOF || (!pos && !ISSPACE(c))) {
    134       /* Strip and flush the current header. */
    135       while(hdrlen && ISSPACE(hdrbuf[hdrlen - 1]))
    136         hdrlen--;
    137       if(hdrlen) {
    138         hdrbuf[hdrlen] = '\0';
    139         if(slist_append(pheaders, hdrbuf)) {
    140           fprintf(config->global->errors,
    141                   "Out of memory for field headers!\n");
    142           return -1;
    143         }
    144         hdrlen = 0;
    145       }
    146     }
    147 
    148     switch(c) {
    149     case EOF:
    150       if(ferror(fp)) {
    151         fprintf(config->global->errors,
    152                 "Header file %s read error: %s\n", filename, strerror(errno));
    153         return -1;
    154       }
    155       return 0;    /* Done. */
    156     case '\r':
    157       continue;    /* Ignore. */
    158     case '\n':
    159       pos = 0;
    160       incomment = FALSE;
    161       lineno++;
    162       continue;
    163     case '#':
    164       if(!pos)
    165         incomment = TRUE;
    166       break;
    167     }
    168 
    169     pos++;
    170     if(!incomment) {
    171       if(hdrlen == sizeof hdrbuf - 1) {
    172         warnf(config->global, "File %s line %d: header too long (truncated)\n",
    173               filename, lineno);
    174         c = ' ';
    175       }
    176       if(hdrlen <= sizeof hdrbuf - 1)
    177         hdrbuf[hdrlen++] = (char) c;
    178     }
    179   }
    180   /* NOTREACHED */
    181 }
    182 
    183 static int get_param_part(struct OperationConfig *config, char endchar,
    184                           char **str, char **pdata, char **ptype,
    185                           char **pfilename, char **pencoder,
    186                           struct curl_slist **pheaders)
    187 {
    188   char *p = *str;
    189   char *type = NULL;
    190   char *filename = NULL;
    191   char *encoder = NULL;
    192   char *endpos;
    193   char *tp;
    194   char sep;
    195   char type_major[128] = "";
    196   char type_minor[128] = "";
    197   char *endct = NULL;
    198   struct curl_slist *headers = NULL;
    199 
    200   if(ptype)
    201     *ptype = NULL;
    202   if(pfilename)
    203     *pfilename = NULL;
    204   if(pheaders)
    205     *pheaders = NULL;
    206   if(pencoder)
    207     *pencoder = NULL;
    208   while(ISSPACE(*p))
    209     p++;
    210   tp = p;
    211   *pdata = get_param_word(&p, &endpos, endchar);
    212   /* If not quoted, strip trailing spaces. */
    213   if(*pdata == tp)
    214     while(endpos > *pdata && ISSPACE(endpos[-1]))
    215       endpos--;
    216   sep = *p;
    217   *endpos = '\0';
    218   while(sep == ';') {
    219     while(ISSPACE(*++p))
    220       ;
    221 
    222     if(!endct && checkprefix("type=", p)) {
    223       for(p += 5; ISSPACE(*p); p++)
    224         ;
    225       /* set type pointer */
    226       type = p;
    227 
    228       /* verify that this is a fine type specifier */
    229       if(2 != sscanf(type, "%127[^/ ]/%127[^;, \n]", type_major, type_minor)) {
    230         warnf(config->global, "Illegally formatted content-type field!\n");
    231         curl_slist_free_all(headers);
    232         return -1; /* illegal content-type syntax! */
    233       }
    234 
    235       /* now point beyond the content-type specifier */
    236       p = type + strlen(type_major) + strlen(type_minor) + 1;
    237       for(endct = p; *p && *p != ';' && *p != endchar; p++)
    238         if(!ISSPACE(*p))
    239           endct = p + 1;
    240       sep = *p;
    241     }
    242     else if(checkprefix("filename=", p)) {
    243       if(endct) {
    244         *endct = '\0';
    245         endct = NULL;
    246       }
    247       for(p += 9; ISSPACE(*p); p++)
    248         ;
    249       tp = p;
    250       filename = get_param_word(&p, &endpos, endchar);
    251       /* If not quoted, strip trailing spaces. */
    252       if(filename == tp)
    253         while(endpos > filename && ISSPACE(endpos[-1]))
    254           endpos--;
    255       sep = *p;
    256       *endpos = '\0';
    257     }
    258     else if(checkprefix("headers=", p)) {
    259       if(endct) {
    260         *endct = '\0';
    261         endct = NULL;
    262       }
    263       p += 8;
    264       if(*p == '@' || *p == '<') {
    265         char *hdrfile;
    266         FILE *fp;
    267         /* Read headers from a file. */
    268 
    269         do {
    270           p++;
    271         } while(ISSPACE(*p));
    272         tp = p;
    273         hdrfile = get_param_word(&p, &endpos, endchar);
    274         /* If not quoted, strip trailing spaces. */
    275         if(hdrfile == tp)
    276           while(endpos > hdrfile && ISSPACE(endpos[-1]))
    277             endpos--;
    278         sep = *p;
    279         *endpos = '\0';
    280         /* TODO: maybe special fopen for VMS? */
    281         fp = fopen(hdrfile, FOPEN_READTEXT);
    282         if(!fp)
    283           warnf(config->global, "Cannot read from %s: %s\n", hdrfile,
    284                 strerror(errno));
    285         else {
    286           int i = read_field_headers(config, hdrfile, fp, &headers);
    287 
    288           fclose(fp);
    289           if(i) {
    290             curl_slist_free_all(headers);
    291             return -1;
    292           }
    293         }
    294       }
    295       else {
    296         char *hdr;
    297 
    298         while(ISSPACE(*p))
    299           p++;
    300         tp = p;
    301         hdr = get_param_word(&p, &endpos, endchar);
    302         /* If not quoted, strip trailing spaces. */
    303         if(hdr == tp)
    304           while(endpos > hdr && ISSPACE(endpos[-1]))
    305             endpos--;
    306         sep = *p;
    307         *endpos = '\0';
    308         if(slist_append(&headers, hdr)) {
    309           fprintf(config->global->errors, "Out of memory for field header!\n");
    310           curl_slist_free_all(headers);
    311           return -1;
    312         }
    313       }
    314     }
    315     else if(checkprefix("encoder=", p)) {
    316       if(endct) {
    317         *endct = '\0';
    318         endct = NULL;
    319       }
    320       for(p += 8; ISSPACE(*p); p++)
    321         ;
    322       tp = p;
    323       encoder = get_param_word(&p, &endpos, endchar);
    324       /* If not quoted, strip trailing spaces. */
    325       if(encoder == tp)
    326         while(endpos > encoder && ISSPACE(endpos[-1]))
    327           endpos--;
    328       sep = *p;
    329       *endpos = '\0';
    330     }
    331     else if(endct) {
    332       /* This is part of content type. */
    333       for(endct = p; *p && *p != ';' && *p != endchar; p++)
    334         if(!ISSPACE(*p))
    335           endct = p + 1;
    336       sep = *p;
    337     }
    338     else {
    339       /* unknown prefix, skip to next block */
    340       char *unknown = get_param_word(&p, &endpos, endchar);
    341 
    342       sep = *p;
    343       *endpos = '\0';
    344       if(*unknown)
    345         warnf(config->global, "skip unknown form field: %s\n", unknown);
    346     }
    347   }
    348 
    349   /* Terminate content type. */
    350   if(endct)
    351     *endct = '\0';
    352 
    353   if(ptype)
    354     *ptype = type;
    355   else if(type)
    356     warnf(config->global, "Field content type not allowed here: %s\n", type);
    357 
    358   if(pfilename)
    359     *pfilename = filename;
    360   else if(filename)
    361     warnf(config->global,
    362           "Field file name not allowed here: %s\n", filename);
    363 
    364   if(pencoder)
    365     *pencoder = encoder;
    366   else if(encoder)
    367     warnf(config->global,
    368           "Field encoder not allowed here: %s\n", encoder);
    369 
    370   if(pheaders)
    371     *pheaders = headers;
    372   else if(headers) {
    373     warnf(config->global,
    374           "Field headers not allowed here: %s\n", headers->data);
    375     curl_slist_free_all(headers);
    376   }
    377 
    378   *str = p;
    379   return sep & 0xFF;
    380 }
    381 
    382 
    383 /* Mime part callbacks for stdin. */
    384 static size_t stdin_read(char *buffer, size_t size, size_t nitems, void *arg)
    385 {
    386   standard_input *sip = (standard_input *) arg;
    387   curl_off_t bytesleft;
    388   (void) size;  /* Always 1: ignored. */
    389 
    390   if(sip->curpos >= sip->size)
    391     return 0;  /* At eof. */
    392   bytesleft = sip->size - sip->curpos;
    393   if((curl_off_t) nitems > bytesleft)
    394     nitems = (size_t) bytesleft;
    395   if(sip->data) {
    396     /* Return data from memory. */
    397     memcpy(buffer, sip->data + (size_t) sip->curpos, nitems);
    398   }
    399   else {
    400     /* Read from stdin. */
    401     nitems = fread(buffer, 1, nitems, stdin);
    402   }
    403   sip->curpos += nitems;
    404   return nitems;
    405 }
    406 
    407 static int stdin_seek(void *instream, curl_off_t offset, int whence)
    408 {
    409   standard_input *sip = (standard_input *) instream;
    410 
    411   switch(whence) {
    412   case SEEK_CUR:
    413     offset += sip->curpos;
    414     break;
    415   case SEEK_END:
    416     offset += sip->size;
    417     break;
    418   }
    419   if(offset < 0)
    420     return CURL_SEEKFUNC_CANTSEEK;
    421   if(!sip->data) {
    422     if(fseek(stdin, (long) (offset + sip->origin), SEEK_SET))
    423       return CURL_SEEKFUNC_CANTSEEK;
    424   }
    425   sip->curpos = offset;
    426   return CURL_SEEKFUNC_OK;
    427 }
    428 
    429 static void stdin_free(void *ptr)
    430 {
    431   standard_input *sip = (standard_input *) ptr;
    432 
    433   Curl_safefree(sip->data);
    434   free(sip);
    435 }
    436 
    437 /* Set a part's data from a file, taking care about the pseudo filename "-" as
    438  * a shortcut to read stdin: if so, use a callback to read OUR stdin (to
    439  * workaround Windows DLL file handle caveat).
    440  * If stdin is a regular file opened in binary mode, save current offset as
    441  * origin for rewind and do not buffer data. Else read to EOF and keep in
    442  * memory. In all cases, compute the stdin data size.
    443  */
    444 static CURLcode file_or_stdin(curl_mimepart *part, const char *file)
    445 {
    446   standard_input *sip = NULL;
    447   int fd = -1;
    448   CURLcode result = CURLE_OK;
    449   struct_stat sbuf;
    450 
    451   if(strcmp(file, "-"))
    452     return curl_mime_filedata(part, file);
    453 
    454   sip = (standard_input *) malloc(sizeof *sip);
    455   if(!sip)
    456     return CURLE_OUT_OF_MEMORY;
    457 
    458   memset((char *) sip, 0, sizeof *sip);
    459   set_binmode(stdin);
    460 
    461   /* If stdin is a regular file, do not buffer data but read it when needed. */
    462   fd = fileno(stdin);
    463   sip->origin = ftell(stdin);
    464   if(fd >= 0 && sip->origin >= 0 && !fstat(fd, &sbuf) &&
    465 #ifdef __VMS
    466      sbuf.st_fab_rfm != FAB$C_VAR && sbuf.st_fab_rfm != FAB$C_VFC &&
    467 #endif
    468      S_ISREG(sbuf.st_mode)) {
    469     sip->size = sbuf.st_size - sip->origin;
    470     if(sip->size < 0)
    471       sip->size = 0;
    472   }
    473   else {  /* Not suitable for direct use, buffer stdin data. */
    474     size_t stdinsize = 0;
    475 
    476     sip->origin = 0;
    477     if(file2memory(&sip->data, &stdinsize, stdin) != PARAM_OK)
    478       result = CURLE_OUT_OF_MEMORY;
    479     else {
    480       if(!stdinsize)
    481         sip->data = NULL;  /* Has been freed if no data. */
    482       sip->size = stdinsize;
    483       if(ferror(stdin))
    484         result = CURLE_READ_ERROR;
    485     }
    486   }
    487 
    488   /* Set remote file name. */
    489   if(!result)
    490     result = curl_mime_filename(part, file);
    491 
    492   /* Set part's data from callback. */
    493   if(!result)
    494     result = curl_mime_data_cb(part, sip->size,
    495                                stdin_read, stdin_seek, stdin_free, sip);
    496   if(result)
    497     stdin_free(sip);
    498   return result;
    499 }
    500 
    501 
    502 /***************************************************************************
    503  *
    504  * formparse()
    505  *
    506  * Reads a 'name=value' parameter and builds the appropriate linked list.
    507  *
    508  * Specify files to upload with 'name=@filename', or 'name=@"filename"'
    509  * in case the filename contain ',' or ';'. Supports specified
    510  * given Content-Type of the files. Such as ';type=<content-type>'.
    511  *
    512  * If literal_value is set, any initial '@' or '<' in the value string
    513  * loses its special meaning, as does any embedded ';type='.
    514  *
    515  * You may specify more than one file for a single name (field). Specify
    516  * multiple files by writing it like:
    517  *
    518  * 'name=@filename,filename2,filename3'
    519  *
    520  * or use double-quotes quote the filename:
    521  *
    522  * 'name=@"filename","filename2","filename3"'
    523  *
    524  * If you want content-types specified for each too, write them like:
    525  *
    526  * 'name=@filename;type=image/gif,filename2,filename3'
    527  *
    528  * If you want custom headers added for a single part, write them in a separate
    529  * file and do like this:
    530  *
    531  * 'name=foo;headers=@headerfile' or why not
    532  * 'name=@filemame;headers=@headerfile'
    533  *
    534  * To upload a file, but to fake the file name that will be included in the
    535  * formpost, do like this:
    536  *
    537  * 'name=@filename;filename=/dev/null' or quote the faked filename like:
    538  * 'name=@filename;filename="play, play, and play.txt"'
    539  *
    540  * If filename/path contains ',' or ';', it must be quoted by double-quotes,
    541  * else curl will fail to figure out the correct filename. if the filename
    542  * tobe quoted contains '"' or '\', '"' and '\' must be escaped by backslash.
    543  *
    544  * This function uses curl_formadd to fulfill it's job. Is heavily based on
    545  * the old curl_formparse code.
    546  *
    547  ***************************************************************************/
    548 
    549 int formparse(struct OperationConfig *config,
    550               const char *input,
    551               curl_mime **mimepost,
    552               curl_mime **mimecurrent,
    553               bool literal_value)
    554 {
    555   /* input MUST be a string in the format 'name=contents' and we'll
    556      build a linked list with the info */
    557   char *name = NULL;
    558   char *contents = NULL;
    559   char *contp;
    560   char *data;
    561   char *type = NULL;
    562   char *filename = NULL;
    563   char *encoder = NULL;
    564   struct curl_slist *headers = NULL;
    565   curl_mimepart *part = NULL;
    566   CURLcode res;
    567   int sep = '\0';
    568 
    569   /* Allocate the main mime structure if needed. */
    570   if(!*mimepost) {
    571     *mimepost = curl_mime_init(config->easy);
    572     if(!*mimepost) {
    573       warnf(config->global, "curl_mime_init failed!\n");
    574       return 1;
    575     }
    576     *mimecurrent = *mimepost;
    577   }
    578 
    579   /* Make a copy we can overwrite. */
    580   contents = strdup(input);
    581   if(!contents) {
    582     fprintf(config->global->errors, "out of memory\n");
    583     return 2;
    584   }
    585 
    586   /* Scan for the end of the name. */
    587   contp = strchr(contents, '=');
    588   if(contp) {
    589     if(contp > contents)
    590       name = contents;
    591     *contp++ = '\0';
    592 
    593     if(*contp == '(' && !literal_value) {
    594       curl_mime *subparts;
    595 
    596       /* Starting a multipart. */
    597       sep = get_param_part(config, '\0',
    598                            &contp, &data, &type, NULL, NULL, &headers);
    599       if(sep < 0) {
    600         Curl_safefree(contents);
    601         return 3;
    602       }
    603       subparts = curl_mime_init(config->easy);
    604       if(!subparts) {
    605         warnf(config->global, "curl_mime_init failed!\n");
    606         curl_slist_free_all(headers);
    607         Curl_safefree(contents);
    608         return 4;
    609       }
    610       part = curl_mime_addpart(*mimecurrent);
    611       if(!part) {
    612         warnf(config->global, "curl_mime_addpart failed!\n");
    613         curl_mime_free(subparts);
    614         curl_slist_free_all(headers);
    615         Curl_safefree(contents);
    616         return 5;
    617       }
    618       if(curl_mime_subparts(part, subparts)) {
    619         warnf(config->global, "curl_mime_subparts failed!\n");
    620         curl_mime_free(subparts);
    621         curl_slist_free_all(headers);
    622         Curl_safefree(contents);
    623         return 6;
    624       }
    625       *mimecurrent = subparts;
    626       if(curl_mime_headers(part, headers, 1)) {
    627         warnf(config->global, "curl_mime_headers failed!\n");
    628         curl_slist_free_all(headers);
    629         Curl_safefree(contents);
    630         return 7;
    631       }
    632       if(curl_mime_type(part, type)) {
    633         warnf(config->global, "curl_mime_type failed!\n");
    634         Curl_safefree(contents);
    635         return 8;
    636       }
    637     }
    638     else if(!name && !strcmp(contp, ")") && !literal_value) {
    639       /* Ending a mutipart. */
    640       if(*mimecurrent == *mimepost) {
    641         warnf(config->global, "no multipart to terminate!\n");
    642         Curl_safefree(contents);
    643         return 9;
    644         }
    645       *mimecurrent = (*mimecurrent)->parent->parent;
    646     }
    647     else if('@' == contp[0] && !literal_value) {
    648 
    649       /* we use the @-letter to indicate file name(s) */
    650 
    651       curl_mime *subparts = NULL;
    652 
    653       do {
    654         /* since this was a file, it may have a content-type specifier
    655            at the end too, or a filename. Or both. */
    656         ++contp;
    657         sep = get_param_part(config, ',', &contp,
    658                              &data, &type, &filename, &encoder, &headers);
    659         if(sep < 0) {
    660           if(subparts != *mimecurrent)
    661             curl_mime_free(subparts);
    662           Curl_safefree(contents);
    663           return 10;
    664         }
    665 
    666         /* now contp point to comma or string end.
    667            If more files to come, make sure we have multiparts. */
    668         if(!subparts) {
    669           if(sep != ',')    /* If there is a single file. */
    670             subparts = *mimecurrent;
    671           else {
    672             subparts = curl_mime_init(config->easy);
    673             if(!subparts) {
    674               warnf(config->global, "curl_mime_init failed!\n");
    675               curl_slist_free_all(headers);
    676               Curl_safefree(contents);
    677               return 11;
    678             }
    679           }
    680         }
    681 
    682         /* Allocate a part for that file. */
    683         part = curl_mime_addpart(subparts);
    684         if(!part) {
    685           warnf(config->global, "curl_mime_addpart failed!\n");
    686           if(subparts != *mimecurrent)
    687             curl_mime_free(subparts);
    688           curl_slist_free_all(headers);
    689           Curl_safefree(contents);
    690           return 12;
    691         }
    692 
    693         /* Set part headers. */
    694         if(curl_mime_headers(part, headers, 1)) {
    695           warnf(config->global, "curl_mime_headers failed!\n");
    696           if(subparts != *mimecurrent)
    697             curl_mime_free(subparts);
    698           curl_slist_free_all(headers);
    699           Curl_safefree(contents);
    700           return 13;
    701         }
    702 
    703         /* Setup file in part. */
    704         res = file_or_stdin(part, data);
    705         if(res) {
    706           warnf(config->global, "setting file %s  failed!\n", data);
    707           if(res != CURLE_READ_ERROR) {
    708             if(subparts != *mimecurrent)
    709               curl_mime_free(subparts);
    710             Curl_safefree(contents);
    711             return 14;
    712           }
    713         }
    714         if(filename && curl_mime_filename(part, filename)) {
    715           warnf(config->global, "curl_mime_filename failed!\n");
    716           if(subparts != *mimecurrent)
    717             curl_mime_free(subparts);
    718           Curl_safefree(contents);
    719           return 15;
    720         }
    721         if(curl_mime_type(part, type)) {
    722           warnf(config->global, "curl_mime_type failed!\n");
    723           if(subparts != *mimecurrent)
    724             curl_mime_free(subparts);
    725           Curl_safefree(contents);
    726           return 16;
    727         }
    728         if(curl_mime_encoder(part, encoder)) {
    729           warnf(config->global, "curl_mime_encoder failed!\n");
    730           if(subparts != *mimecurrent)
    731             curl_mime_free(subparts);
    732           Curl_safefree(contents);
    733           return 17;
    734         }
    735 
    736         /* *contp could be '\0', so we just check with the delimiter */
    737       } while(sep); /* loop if there's another file name */
    738 
    739       /* now we add the multiple files section */
    740       if(subparts != *mimecurrent) {
    741         part = curl_mime_addpart(*mimecurrent);
    742         if(!part) {
    743           warnf(config->global, "curl_mime_addpart failed!\n");
    744           curl_mime_free(subparts);
    745           Curl_safefree(contents);
    746           return 18;
    747         }
    748         if(curl_mime_subparts(part, subparts)) {
    749           warnf(config->global, "curl_mime_subparts failed!\n");
    750           curl_mime_free(subparts);
    751           Curl_safefree(contents);
    752           return 19;
    753         }
    754       }
    755     }
    756     else {
    757         /* Allocate a mime part. */
    758         part = curl_mime_addpart(*mimecurrent);
    759         if(!part) {
    760           warnf(config->global, "curl_mime_addpart failed!\n");
    761           Curl_safefree(contents);
    762           return 20;
    763         }
    764 
    765       if(*contp == '<' && !literal_value) {
    766         ++contp;
    767         sep = get_param_part(config, '\0', &contp,
    768                              &data, &type, NULL, &encoder, &headers);
    769         if(sep < 0) {
    770           Curl_safefree(contents);
    771           return 21;
    772         }
    773 
    774         /* Set part headers. */
    775         if(curl_mime_headers(part, headers, 1)) {
    776           warnf(config->global, "curl_mime_headers failed!\n");
    777           curl_slist_free_all(headers);
    778           Curl_safefree(contents);
    779           return 22;
    780         }
    781 
    782         /* Setup file in part. */
    783         res = file_or_stdin(part, data);
    784         if(res) {
    785           warnf(config->global, "setting file %s failed!\n", data);
    786           if(res != CURLE_READ_ERROR) {
    787             Curl_safefree(contents);
    788             return 23;
    789           }
    790         }
    791       }
    792       else {
    793         if(literal_value)
    794           data = contp;
    795         else {
    796           sep = get_param_part(config, '\0', &contp,
    797                                &data, &type, &filename, &encoder, &headers);
    798           if(sep < 0) {
    799             Curl_safefree(contents);
    800             return 24;
    801           }
    802         }
    803 
    804         /* Set part headers. */
    805         if(curl_mime_headers(part, headers, 1)) {
    806           warnf(config->global, "curl_mime_headers failed!\n");
    807           curl_slist_free_all(headers);
    808           Curl_safefree(contents);
    809           return 25;
    810         }
    811 
    812 #ifdef CURL_DOES_CONVERSIONS
    813         if(convert_to_network(data, strlen(data))) {
    814           warnf(config->global, "curl_formadd failed!\n");
    815           Curl_safefree(contents);
    816           return 26;
    817         }
    818 #endif
    819 
    820         if(curl_mime_data(part, data, CURL_ZERO_TERMINATED)) {
    821           warnf(config->global, "curl_mime_data failed!\n");
    822           Curl_safefree(contents);
    823           return 27;
    824         }
    825       }
    826 
    827       if(curl_mime_filename(part, filename)) {
    828         warnf(config->global, "curl_mime_filename failed!\n");
    829         Curl_safefree(contents);
    830         return 28;
    831       }
    832       if(curl_mime_type(part, type)) {
    833         warnf(config->global, "curl_mime_type failed!\n");
    834         Curl_safefree(contents);
    835         return 29;
    836       }
    837       if(curl_mime_encoder(part, encoder)) {
    838         warnf(config->global, "curl_mime_encoder failed!\n");
    839         Curl_safefree(contents);
    840         return 30;
    841       }
    842 
    843       if(sep) {
    844         *contp = (char) sep;
    845         warnf(config->global,
    846               "garbage at end of field specification: %s\n", contp);
    847       }
    848     }
    849 
    850     /* Set part name. */
    851     if(name && curl_mime_name(part, name)) {
    852       warnf(config->global, "curl_mime_name failed!\n");
    853       Curl_safefree(contents);
    854       return 31;
    855     }
    856   }
    857   else {
    858     warnf(config->global, "Illegally formatted input field!\n");
    859     Curl_safefree(contents);
    860     return 32;
    861   }
    862   Curl_safefree(contents);
    863   return 0;
    864 }
    865