Imported Upstream version 7.59.0
[platform/upstream/curl.git] / src / tool_formparse.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2017, 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 #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 }