1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 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 *mime_data) 65{ 66 char *mime_data_copy; 67 struct tool_mime *m = NULL; 68 69 mime_data_copy = strdup(mime_data); 70 if(mime_data_copy) { 71 m = tool_mime_new(parent, TOOLMIME_DATA); 72 if(!m) 73 free(mime_data_copy); 74 else 75 m->data = mime_data_copy; 76 } 77 return m; 78} 79 80static struct tool_mime *tool_mime_new_filedata(struct tool_mime *parent, 81 const char *filename, 82 bool isremotefile, 83 CURLcode *errcode) 84{ 85 CURLcode result = CURLE_OK; 86 struct tool_mime *m = NULL; 87 88 *errcode = CURLE_OUT_OF_MEMORY; 89 if(strcmp(filename, "-")) { 90 /* This is a normal file. */ 91 char *filedup = strdup(filename); 92 if(filedup) { 93 m = tool_mime_new(parent, TOOLMIME_FILE); 94 if(!m) 95 free(filedup); 96 else { 97 m->data = filedup; 98 if(!isremotefile) 99 m->kind = TOOLMIME_FILEDATA; 100 *errcode = CURLE_OK; 101 } 102 } 103 } 104 else { /* Standard input. */ 105 int fd = fileno(stdin); 106 char *data = NULL; 107 curl_off_t size; 108 curl_off_t origin; 109 struct_stat sbuf; 110 111 set_binmode(stdin); 112 origin = ftell(stdin); 113 /* If stdin is a regular file, do not buffer data but read it 114 when needed. */ 115 if(fd >= 0 && origin >= 0 && !fstat(fd, &sbuf) && 116#ifdef __VMS 117 sbuf.st_fab_rfm != FAB$C_VAR && sbuf.st_fab_rfm != FAB$C_VFC && 118#endif 119 S_ISREG(sbuf.st_mode)) { 120 size = sbuf.st_size - origin; 121 if(size < 0) 122 size = 0; 123 } 124 else { /* Not suitable for direct use, buffer stdin data. */ 125 size_t stdinsize = 0; 126 127 switch(file2memory(&data, &stdinsize, stdin)) { 128 case PARAM_NO_MEM: 129 return m; 130 case PARAM_READ_ERROR: 131 result = CURLE_READ_ERROR; 132 break; 133 default: 134 if(!stdinsize) { 135 /* Zero-length data has been freed. Re-create it. */ 136 data = strdup(""); 137 if(!data) 138 return m; 139 } 140 break; 141 } 142 size = curlx_uztoso(stdinsize); 143 origin = 0; 144 } 145 m = tool_mime_new(parent, TOOLMIME_STDIN); 146 if(!m) 147 Curl_safefree(data); 148 else { 149 m->data = data; 150 m->origin = origin; 151 m->size = size; 152 m->curpos = 0; 153 if(!isremotefile) 154 m->kind = TOOLMIME_STDINDATA; 155 *errcode = result; 156 } 157 } 158 return m; 159} 160 161void tool_mime_free(struct tool_mime *mime) 162{ 163 if(mime) { 164 if(mime->subparts) 165 tool_mime_free(mime->subparts); 166 if(mime->prev) 167 tool_mime_free(mime->prev); 168 Curl_safefree(mime->name); 169 Curl_safefree(mime->filename); 170 Curl_safefree(mime->type); 171 Curl_safefree(mime->encoder); 172 Curl_safefree(mime->data); 173 curl_slist_free_all(mime->headers); 174 free(mime); 175 } 176} 177 178 179/* Mime part callbacks for stdin. */ 180size_t tool_mime_stdin_read(char *buffer, 181 size_t size, size_t nitems, void *arg) 182{ 183 struct tool_mime *sip = (struct tool_mime *) arg; 184 curl_off_t bytesleft; 185 (void) size; /* Always 1: ignored. */ 186 187 if(sip->size >= 0) { 188 if(sip->curpos >= sip->size) 189 return 0; /* At eof. */ 190 bytesleft = sip->size - sip->curpos; 191 if(curlx_uztoso(nitems) > bytesleft) 192 nitems = curlx_sotouz(bytesleft); 193 } 194 if(nitems) { 195 if(sip->data) { 196 /* Return data from memory. */ 197 memcpy(buffer, sip->data + curlx_sotouz(sip->curpos), nitems); 198 } 199 else { 200 /* Read from stdin. */ 201 nitems = fread(buffer, 1, nitems, stdin); 202 if(ferror(stdin)) { 203 /* Show error only once. */ 204 if(sip->config) { 205 warnf(sip->config, "stdin: %s", strerror(errno)); 206 sip->config = NULL; 207 } 208 return CURL_READFUNC_ABORT; 209 } 210 } 211 sip->curpos += curlx_uztoso(nitems); 212 } 213 return nitems; 214} 215 216int tool_mime_stdin_seek(void *instream, curl_off_t offset, int whence) 217{ 218 struct tool_mime *sip = (struct tool_mime *) instream; 219 220 switch(whence) { 221 case SEEK_CUR: 222 offset += sip->curpos; 223 break; 224 case SEEK_END: 225 offset += sip->size; 226 break; 227 } 228 if(offset < 0) 229 return CURL_SEEKFUNC_CANTSEEK; 230 if(!sip->data) { 231 if(fseek(stdin, (long) (offset + sip->origin), SEEK_SET)) 232 return CURL_SEEKFUNC_CANTSEEK; 233 } 234 sip->curpos = offset; 235 return CURL_SEEKFUNC_OK; 236} 237 238/* Translate an internal mime tree into a libcurl mime tree. */ 239 240static CURLcode tool2curlparts(CURL *curl, struct tool_mime *m, 241 curl_mime *mime) 242{ 243 CURLcode ret = CURLE_OK; 244 curl_mimepart *part = NULL; 245 curl_mime *submime = NULL; 246 const char *filename = NULL; 247 248 if(m) { 249 ret = tool2curlparts(curl, m->prev, mime); 250 if(!ret) { 251 part = curl_mime_addpart(mime); 252 if(!part) 253 ret = CURLE_OUT_OF_MEMORY; 254 } 255 if(!ret) { 256 filename = m->filename; 257 switch(m->kind) { 258 case TOOLMIME_PARTS: 259 ret = tool2curlmime(curl, m, &submime); 260 if(!ret) { 261 ret = curl_mime_subparts(part, submime); 262 if(ret) 263 curl_mime_free(submime); 264 } 265 break; 266 267 case TOOLMIME_DATA: 268 ret = curl_mime_data(part, m->data, CURL_ZERO_TERMINATED); 269 break; 270 271 case TOOLMIME_FILE: 272 case TOOLMIME_FILEDATA: 273 ret = curl_mime_filedata(part, m->data); 274 if(!ret && m->kind == TOOLMIME_FILEDATA && !filename) 275 ret = curl_mime_filename(part, NULL); 276 break; 277 278 case TOOLMIME_STDIN: 279 if(!filename) 280 filename = "-"; 281 FALLTHROUGH(); 282 case TOOLMIME_STDINDATA: 283 ret = curl_mime_data_cb(part, m->size, 284 (curl_read_callback) tool_mime_stdin_read, 285 (curl_seek_callback) tool_mime_stdin_seek, 286 NULL, m); 287 break; 288 289 default: 290 /* Other cases not possible in this context. */ 291 break; 292 } 293 } 294 if(!ret && filename) 295 ret = curl_mime_filename(part, filename); 296 if(!ret) 297 ret = curl_mime_type(part, m->type); 298 if(!ret) 299 ret = curl_mime_headers(part, m->headers, 0); 300 if(!ret) 301 ret = curl_mime_encoder(part, m->encoder); 302 if(!ret) 303 ret = curl_mime_name(part, m->name); 304 } 305 return ret; 306} 307 308CURLcode tool2curlmime(CURL *curl, struct tool_mime *m, curl_mime **mime) 309{ 310 CURLcode ret = CURLE_OK; 311 312 *mime = curl_mime_init(curl); 313 if(!*mime) 314 ret = CURLE_OUT_OF_MEMORY; 315 else 316 ret = tool2curlparts(curl, m->subparts, *mime); 317 if(ret) { 318 curl_mime_free(*mime); 319 *mime = NULL; 320 } 321 return ret; 322} 323 324/* 325 * helper function to get a word from form param 326 * after call get_parm_word, str either point to string end 327 * or point to any of end chars. 328 */ 329static char *get_param_word(struct OperationConfig *config, char **str, 330 char **end_pos, char endchar) 331{ 332 char *ptr = *str; 333 /* the first non-space char is here */ 334 char *word_begin = ptr; 335 char *ptr2; 336 char *escape = NULL; 337 338 if(*ptr == '"') { 339 ++ptr; 340 while(*ptr) { 341 if(*ptr == '\\') { 342 if(ptr[1] == '\\' || ptr[1] == '"') { 343 /* remember the first escape position */ 344 if(!escape) 345 escape = ptr; 346 /* skip escape of back-slash or double-quote */ 347 ptr += 2; 348 continue; 349 } 350 } 351 if(*ptr == '"') { 352 bool trailing_data = FALSE; 353 *end_pos = ptr; 354 if(escape) { 355 /* has escape, we restore the unescaped string here */ 356 ptr = ptr2 = escape; 357 do { 358 if(*ptr == '\\' && (ptr[1] == '\\' || ptr[1] == '"')) 359 ++ptr; 360 *ptr2++ = *ptr++; 361 } 362 while(ptr < *end_pos); 363 *end_pos = ptr2; 364 } 365 ++ptr; 366 while(*ptr && *ptr != ';' && *ptr != endchar) { 367 if(!ISSPACE(*ptr)) 368 trailing_data = TRUE; 369 ++ptr; 370 } 371 if(trailing_data) 372 warnf(config->global, "Trailing data after quoted form parameter"); 373 *str = ptr; 374 return word_begin + 1; 375 } 376 ++ptr; 377 } 378 /* end quote is missing, treat it as non-quoted. */ 379 ptr = word_begin; 380 } 381 382 while(*ptr && *ptr != ';' && *ptr != endchar) 383 ++ptr; 384 *str = *end_pos = ptr; 385 return word_begin; 386} 387 388/* Append slist item and return -1 if failed. */ 389static int slist_append(struct curl_slist **plist, const char *data) 390{ 391 struct curl_slist *s = curl_slist_append(*plist, data); 392 393 if(!s) 394 return -1; 395 396 *plist = s; 397 return 0; 398} 399 400/* Read headers from a file and append to list. */ 401static int read_field_headers(struct OperationConfig *config, 402 const char *filename, FILE *fp, 403 struct curl_slist **pheaders) 404{ 405 size_t hdrlen = 0; 406 size_t pos = 0; 407 bool incomment = FALSE; 408 int lineno = 1; 409 char hdrbuf[999] = ""; /* Max. header length + 1. */ 410 411 for(;;) { 412 int c = getc(fp); 413 if(c == EOF || (!pos && !ISSPACE(c))) { 414 /* Strip and flush the current header. */ 415 while(hdrlen && ISSPACE(hdrbuf[hdrlen - 1])) 416 hdrlen--; 417 if(hdrlen) { 418 hdrbuf[hdrlen] = '\0'; 419 if(slist_append(pheaders, hdrbuf)) { 420 errorf(config->global, "Out of memory for field headers"); 421 return -1; 422 } 423 hdrlen = 0; 424 } 425 } 426 427 switch(c) { 428 case EOF: 429 if(ferror(fp)) { 430 errorf(config->global, "Header file %s read error: %s", filename, 431 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)", 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"); 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", 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 errorf(config->global, "Out of memory for field header"); 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", 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", type); 635 636 if(pfilename) 637 *pfilename = filename; 638 else if(filename) 639 warnf(config->global, 640 "Field file name not allowed here: %s", filename); 641 642 if(pencoder) 643 *pencoder = encoder; 644 else if(encoder) 645 warnf(config->global, 646 "Field encoder not allowed here: %s", encoder); 647 648 if(pheaders) 649 *pheaders = headers; 650 else if(headers) { 651 warnf(config->global, 652 "Field headers not allowed here: %s", 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"); 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"); 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"); 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", 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"); 900 goto fail; 901 } 902 err = 0; 903fail: 904 Curl_safefree(contents); 905 curl_slist_free_all(headers); 906 return err; 907} 908