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