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