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