1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel (at) 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 23 #include "curl_setup.h" 24 25 #include <curl/curl.h> 26 27 #ifndef CURL_DISABLE_HTTP 28 29 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) 30 #include <libgen.h> 31 #endif 32 33 #include "urldata.h" /* for struct Curl_easy */ 34 #include "formdata.h" 35 #include "vtls/vtls.h" 36 #include "strcase.h" 37 #include "sendf.h" 38 #include "strdup.h" 39 #include "rand.h" 40 /* The last 3 #include files should be in this order */ 41 #include "curl_printf.h" 42 #include "curl_memory.h" 43 #include "memdebug.h" 44 45 #ifndef HAVE_BASENAME 46 static char *Curl_basename(char *path); 47 #define basename(x) Curl_basename((x)) 48 #endif 49 50 static size_t readfromfile(struct Form *form, char *buffer, size_t size); 51 static char *formboundary(struct Curl_easy *data); 52 53 /* What kind of Content-Type to use on un-specified files with unrecognized 54 extensions. */ 55 #define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream" 56 57 #define FORM_FILE_SEPARATOR ',' 58 #define FORM_TYPE_SEPARATOR ';' 59 60 #define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME 61 #define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME 62 #define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS 63 #define HTTPPOST_READFILE CURL_HTTPPOST_READFILE 64 #define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER 65 #define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK 66 #define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER 67 68 /*************************************************************************** 69 * 70 * AddHttpPost() 71 * 72 * Adds a HttpPost structure to the list, if parent_post is given becomes 73 * a subpost of parent_post instead of a direct list element. 74 * 75 * Returns newly allocated HttpPost on success and NULL if malloc failed. 76 * 77 ***************************************************************************/ 78 static struct curl_httppost * 79 AddHttpPost(char *name, size_t namelength, 80 char *value, curl_off_t contentslength, 81 char *buffer, size_t bufferlength, 82 char *contenttype, 83 long flags, 84 struct curl_slist *contentHeader, 85 char *showfilename, char *userp, 86 struct curl_httppost *parent_post, 87 struct curl_httppost **httppost, 88 struct curl_httppost **last_post) 89 { 90 struct curl_httppost *post; 91 post = calloc(1, sizeof(struct curl_httppost)); 92 if(post) { 93 post->name = name; 94 post->namelength = (long)(name?(namelength?namelength:strlen(name)):0); 95 post->contents = value; 96 post->contentlen = contentslength; 97 post->buffer = buffer; 98 post->bufferlength = (long)bufferlength; 99 post->contenttype = contenttype; 100 post->contentheader = contentHeader; 101 post->showfilename = showfilename; 102 post->userp = userp, 103 post->flags = flags | CURL_HTTPPOST_LARGE; 104 } 105 else 106 return NULL; 107 108 if(parent_post) { 109 /* now, point our 'more' to the original 'more' */ 110 post->more = parent_post->more; 111 112 /* then move the original 'more' to point to ourselves */ 113 parent_post->more = post; 114 } 115 else { 116 /* make the previous point to this */ 117 if(*last_post) 118 (*last_post)->next = post; 119 else 120 (*httppost) = post; 121 122 (*last_post) = post; 123 } 124 return post; 125 } 126 127 /*************************************************************************** 128 * 129 * AddFormInfo() 130 * 131 * Adds a FormInfo structure to the list presented by parent_form_info. 132 * 133 * Returns newly allocated FormInfo on success and NULL if malloc failed/ 134 * parent_form_info is NULL. 135 * 136 ***************************************************************************/ 137 static FormInfo * AddFormInfo(char *value, 138 char *contenttype, 139 FormInfo *parent_form_info) 140 { 141 FormInfo *form_info; 142 form_info = calloc(1, sizeof(struct FormInfo)); 143 if(form_info) { 144 if(value) 145 form_info->value = value; 146 if(contenttype) 147 form_info->contenttype = contenttype; 148 form_info->flags = HTTPPOST_FILENAME; 149 } 150 else 151 return NULL; 152 153 if(parent_form_info) { 154 /* now, point our 'more' to the original 'more' */ 155 form_info->more = parent_form_info->more; 156 157 /* then move the original 'more' to point to ourselves */ 158 parent_form_info->more = form_info; 159 } 160 161 return form_info; 162 } 163 164 /*************************************************************************** 165 * 166 * ContentTypeForFilename() 167 * 168 * Provides content type for filename if one of the known types (else 169 * (either the prevtype or the default is returned). 170 * 171 * Returns some valid contenttype for filename. 172 * 173 ***************************************************************************/ 174 static const char *ContentTypeForFilename(const char *filename, 175 const char *prevtype) 176 { 177 const char *contenttype = NULL; 178 unsigned int i; 179 /* 180 * No type was specified, we scan through a few well-known 181 * extensions and pick the first we match! 182 */ 183 struct ContentType { 184 const char *extension; 185 const char *type; 186 }; 187 static const struct ContentType ctts[]={ 188 {".gif", "image/gif"}, 189 {".jpg", "image/jpeg"}, 190 {".jpeg", "image/jpeg"}, 191 {".txt", "text/plain"}, 192 {".html", "text/html"}, 193 {".xml", "application/xml"} 194 }; 195 196 if(prevtype) 197 /* default to the previously set/used! */ 198 contenttype = prevtype; 199 else 200 contenttype = HTTPPOST_CONTENTTYPE_DEFAULT; 201 202 if(filename) { /* in case a NULL was passed in */ 203 for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) { 204 if(strlen(filename) >= strlen(ctts[i].extension)) { 205 if(strcasecompare(filename + 206 strlen(filename) - strlen(ctts[i].extension), 207 ctts[i].extension)) { 208 contenttype = ctts[i].type; 209 break; 210 } 211 } 212 } 213 } 214 /* we have a contenttype by now */ 215 return contenttype; 216 } 217 218 /*************************************************************************** 219 * 220 * FormAdd() 221 * 222 * Stores a formpost parameter and builds the appropriate linked list. 223 * 224 * Has two principal functionalities: using files and byte arrays as 225 * post parts. Byte arrays are either copied or just the pointer is stored 226 * (as the user requests) while for files only the filename and not the 227 * content is stored. 228 * 229 * While you may have only one byte array for each name, multiple filenames 230 * are allowed (and because of this feature CURLFORM_END is needed after 231 * using CURLFORM_FILE). 232 * 233 * Examples: 234 * 235 * Simple name/value pair with copied contents: 236 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", 237 * CURLFORM_COPYCONTENTS, "value", CURLFORM_END); 238 * 239 * name/value pair where only the content pointer is remembered: 240 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", 241 * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END); 242 * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used) 243 * 244 * storing a filename (CONTENTTYPE is optional!): 245 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", 246 * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text", 247 * CURLFORM_END); 248 * 249 * storing multiple filenames: 250 * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", 251 * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END); 252 * 253 * Returns: 254 * CURL_FORMADD_OK on success 255 * CURL_FORMADD_MEMORY if the FormInfo allocation fails 256 * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form 257 * CURL_FORMADD_NULL if a null pointer was given for a char 258 * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed 259 * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used 260 * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) 261 * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated 262 * CURL_FORMADD_MEMORY if some allocation for string copying failed. 263 * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array 264 * 265 ***************************************************************************/ 266 267 static 268 CURLFORMcode FormAdd(struct curl_httppost **httppost, 269 struct curl_httppost **last_post, 270 va_list params) 271 { 272 FormInfo *first_form, *current_form, *form = NULL; 273 CURLFORMcode return_value = CURL_FORMADD_OK; 274 const char *prevtype = NULL; 275 struct curl_httppost *post = NULL; 276 CURLformoption option; 277 struct curl_forms *forms = NULL; 278 char *array_value=NULL; /* value read from an array */ 279 280 /* This is a state variable, that if TRUE means that we're parsing an 281 array that we got passed to us. If FALSE we're parsing the input 282 va_list arguments. */ 283 bool array_state = FALSE; 284 285 /* 286 * We need to allocate the first struct to fill in. 287 */ 288 first_form = calloc(1, sizeof(struct FormInfo)); 289 if(!first_form) 290 return CURL_FORMADD_MEMORY; 291 292 current_form = first_form; 293 294 /* 295 * Loop through all the options set. Break if we have an error to report. 296 */ 297 while(return_value == CURL_FORMADD_OK) { 298 299 /* first see if we have more parts of the array param */ 300 if(array_state && forms) { 301 /* get the upcoming option from the given array */ 302 option = forms->option; 303 array_value = (char *)forms->value; 304 305 forms++; /* advance this to next entry */ 306 if(CURLFORM_END == option) { 307 /* end of array state */ 308 array_state = FALSE; 309 continue; 310 } 311 } 312 else { 313 /* This is not array-state, get next option */ 314 option = va_arg(params, CURLformoption); 315 if(CURLFORM_END == option) 316 break; 317 } 318 319 switch (option) { 320 case CURLFORM_ARRAY: 321 if(array_state) 322 /* we don't support an array from within an array */ 323 return_value = CURL_FORMADD_ILLEGAL_ARRAY; 324 else { 325 forms = va_arg(params, struct curl_forms *); 326 if(forms) 327 array_state = TRUE; 328 else 329 return_value = CURL_FORMADD_NULL; 330 } 331 break; 332 333 /* 334 * Set the Name property. 335 */ 336 case CURLFORM_PTRNAME: 337 #ifdef CURL_DOES_CONVERSIONS 338 /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy 339 * the data in all cases so that we'll have safe memory for the eventual 340 * conversion. 341 */ 342 #else 343 current_form->flags |= HTTPPOST_PTRNAME; /* fall through */ 344 #endif 345 case CURLFORM_COPYNAME: 346 if(current_form->name) 347 return_value = CURL_FORMADD_OPTION_TWICE; 348 else { 349 char *name = array_state? 350 array_value:va_arg(params, char *); 351 if(name) 352 current_form->name = name; /* store for the moment */ 353 else 354 return_value = CURL_FORMADD_NULL; 355 } 356 break; 357 case CURLFORM_NAMELENGTH: 358 if(current_form->namelength) 359 return_value = CURL_FORMADD_OPTION_TWICE; 360 else 361 current_form->namelength = 362 array_state?(size_t)array_value:(size_t)va_arg(params, long); 363 break; 364 365 /* 366 * Set the contents property. 367 */ 368 case CURLFORM_PTRCONTENTS: 369 current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */ 370 case CURLFORM_COPYCONTENTS: 371 if(current_form->value) 372 return_value = CURL_FORMADD_OPTION_TWICE; 373 else { 374 char *value = 375 array_state?array_value:va_arg(params, char *); 376 if(value) 377 current_form->value = value; /* store for the moment */ 378 else 379 return_value = CURL_FORMADD_NULL; 380 } 381 break; 382 case CURLFORM_CONTENTSLENGTH: 383 current_form->contentslength = 384 array_state?(size_t)array_value:(size_t)va_arg(params, long); 385 break; 386 387 case CURLFORM_CONTENTLEN: 388 current_form->flags |= CURL_HTTPPOST_LARGE; 389 current_form->contentslength = 390 array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t); 391 break; 392 393 /* Get contents from a given file name */ 394 case CURLFORM_FILECONTENT: 395 if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE)) 396 return_value = CURL_FORMADD_OPTION_TWICE; 397 else { 398 const char *filename = array_state? 399 array_value:va_arg(params, char *); 400 if(filename) { 401 current_form->value = strdup(filename); 402 if(!current_form->value) 403 return_value = CURL_FORMADD_MEMORY; 404 else { 405 current_form->flags |= HTTPPOST_READFILE; 406 current_form->value_alloc = TRUE; 407 } 408 } 409 else 410 return_value = CURL_FORMADD_NULL; 411 } 412 break; 413 414 /* We upload a file */ 415 case CURLFORM_FILE: 416 { 417 const char *filename = array_state?array_value: 418 va_arg(params, char *); 419 420 if(current_form->value) { 421 if(current_form->flags & HTTPPOST_FILENAME) { 422 if(filename) { 423 char *fname = strdup(filename); 424 if(!fname) 425 return_value = CURL_FORMADD_MEMORY; 426 else { 427 form = AddFormInfo(fname, NULL, current_form); 428 if(!form) { 429 free(fname); 430 return_value = CURL_FORMADD_MEMORY; 431 } 432 else { 433 form->value_alloc = TRUE; 434 current_form = form; 435 form = NULL; 436 } 437 } 438 } 439 else 440 return_value = CURL_FORMADD_NULL; 441 } 442 else 443 return_value = CURL_FORMADD_OPTION_TWICE; 444 } 445 else { 446 if(filename) { 447 current_form->value = strdup(filename); 448 if(!current_form->value) 449 return_value = CURL_FORMADD_MEMORY; 450 else { 451 current_form->flags |= HTTPPOST_FILENAME; 452 current_form->value_alloc = TRUE; 453 } 454 } 455 else 456 return_value = CURL_FORMADD_NULL; 457 } 458 break; 459 } 460 461 case CURLFORM_BUFFERPTR: 462 current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER; 463 if(current_form->buffer) 464 return_value = CURL_FORMADD_OPTION_TWICE; 465 else { 466 char *buffer = 467 array_state?array_value:va_arg(params, char *); 468 if(buffer) { 469 current_form->buffer = buffer; /* store for the moment */ 470 current_form->value = buffer; /* make it non-NULL to be accepted 471 as fine */ 472 } 473 else 474 return_value = CURL_FORMADD_NULL; 475 } 476 break; 477 478 case CURLFORM_BUFFERLENGTH: 479 if(current_form->bufferlength) 480 return_value = CURL_FORMADD_OPTION_TWICE; 481 else 482 current_form->bufferlength = 483 array_state?(size_t)array_value:(size_t)va_arg(params, long); 484 break; 485 486 case CURLFORM_STREAM: 487 current_form->flags |= HTTPPOST_CALLBACK; 488 if(current_form->userp) 489 return_value = CURL_FORMADD_OPTION_TWICE; 490 else { 491 char *userp = 492 array_state?array_value:va_arg(params, char *); 493 if(userp) { 494 current_form->userp = userp; 495 current_form->value = userp; /* this isn't strictly true but we 496 derive a value from this later on 497 and we need this non-NULL to be 498 accepted as a fine form part */ 499 } 500 else 501 return_value = CURL_FORMADD_NULL; 502 } 503 break; 504 505 case CURLFORM_CONTENTTYPE: 506 { 507 const char *contenttype = 508 array_state?array_value:va_arg(params, char *); 509 if(current_form->contenttype) { 510 if(current_form->flags & HTTPPOST_FILENAME) { 511 if(contenttype) { 512 char *type = strdup(contenttype); 513 if(!type) 514 return_value = CURL_FORMADD_MEMORY; 515 else { 516 form = AddFormInfo(NULL, type, current_form); 517 if(!form) { 518 free(type); 519 return_value = CURL_FORMADD_MEMORY; 520 } 521 else { 522 form->contenttype_alloc = TRUE; 523 current_form = form; 524 form = NULL; 525 } 526 } 527 } 528 else 529 return_value = CURL_FORMADD_NULL; 530 } 531 else 532 return_value = CURL_FORMADD_OPTION_TWICE; 533 } 534 else { 535 if(contenttype) { 536 current_form->contenttype = strdup(contenttype); 537 if(!current_form->contenttype) 538 return_value = CURL_FORMADD_MEMORY; 539 else 540 current_form->contenttype_alloc = TRUE; 541 } 542 else 543 return_value = CURL_FORMADD_NULL; 544 } 545 break; 546 } 547 case CURLFORM_CONTENTHEADER: 548 { 549 /* this "cast increases required alignment of target type" but 550 we consider it OK anyway */ 551 struct curl_slist *list = array_state? 552 (struct curl_slist *)(void *)array_value: 553 va_arg(params, struct curl_slist *); 554 555 if(current_form->contentheader) 556 return_value = CURL_FORMADD_OPTION_TWICE; 557 else 558 current_form->contentheader = list; 559 560 break; 561 } 562 case CURLFORM_FILENAME: 563 case CURLFORM_BUFFER: 564 { 565 const char *filename = array_state?array_value: 566 va_arg(params, char *); 567 if(current_form->showfilename) 568 return_value = CURL_FORMADD_OPTION_TWICE; 569 else { 570 current_form->showfilename = strdup(filename); 571 if(!current_form->showfilename) 572 return_value = CURL_FORMADD_MEMORY; 573 else 574 current_form->showfilename_alloc = TRUE; 575 } 576 break; 577 } 578 default: 579 return_value = CURL_FORMADD_UNKNOWN_OPTION; 580 break; 581 } 582 } 583 584 if(CURL_FORMADD_OK != return_value) { 585 /* On error, free allocated fields for all nodes of the FormInfo linked 586 list without deallocating nodes. List nodes are deallocated later on */ 587 FormInfo *ptr; 588 for(ptr = first_form; ptr != NULL; ptr = ptr->more) { 589 if(ptr->name_alloc) { 590 Curl_safefree(ptr->name); 591 ptr->name_alloc = FALSE; 592 } 593 if(ptr->value_alloc) { 594 Curl_safefree(ptr->value); 595 ptr->value_alloc = FALSE; 596 } 597 if(ptr->contenttype_alloc) { 598 Curl_safefree(ptr->contenttype); 599 ptr->contenttype_alloc = FALSE; 600 } 601 if(ptr->showfilename_alloc) { 602 Curl_safefree(ptr->showfilename); 603 ptr->showfilename_alloc = FALSE; 604 } 605 } 606 } 607 608 if(CURL_FORMADD_OK == return_value) { 609 /* go through the list, check for completeness and if everything is 610 * alright add the HttpPost item otherwise set return_value accordingly */ 611 612 post = NULL; 613 for(form = first_form; 614 form != NULL; 615 form = form->more) { 616 if(((!form->name || !form->value) && !post) || 617 ( (form->contentslength) && 618 (form->flags & HTTPPOST_FILENAME) ) || 619 ( (form->flags & HTTPPOST_FILENAME) && 620 (form->flags & HTTPPOST_PTRCONTENTS) ) || 621 622 ( (!form->buffer) && 623 (form->flags & HTTPPOST_BUFFER) && 624 (form->flags & HTTPPOST_PTRBUFFER) ) || 625 626 ( (form->flags & HTTPPOST_READFILE) && 627 (form->flags & HTTPPOST_PTRCONTENTS) ) 628 ) { 629 return_value = CURL_FORMADD_INCOMPLETE; 630 break; 631 } 632 else { 633 if(((form->flags & HTTPPOST_FILENAME) || 634 (form->flags & HTTPPOST_BUFFER)) && 635 !form->contenttype) { 636 char *f = form->flags & HTTPPOST_BUFFER? 637 form->showfilename : form->value; 638 639 /* our contenttype is missing */ 640 form->contenttype = strdup(ContentTypeForFilename(f, prevtype)); 641 if(!form->contenttype) { 642 return_value = CURL_FORMADD_MEMORY; 643 break; 644 } 645 form->contenttype_alloc = TRUE; 646 } 647 if(!(form->flags & HTTPPOST_PTRNAME) && 648 (form == first_form) ) { 649 /* Note that there's small risk that form->name is NULL here if the 650 app passed in a bad combo, so we better check for that first. */ 651 if(form->name) { 652 /* copy name (without strdup; possibly contains null characters) */ 653 form->name = Curl_memdup(form->name, form->namelength? 654 form->namelength: 655 strlen(form->name)+1); 656 } 657 if(!form->name) { 658 return_value = CURL_FORMADD_MEMORY; 659 break; 660 } 661 form->name_alloc = TRUE; 662 } 663 if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE | 664 HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER | 665 HTTPPOST_CALLBACK)) && form->value) { 666 /* copy value (without strdup; possibly contains null characters) */ 667 size_t clen = (size_t) form->contentslength; 668 if(!clen) 669 clen = strlen(form->value)+1; 670 671 form->value = Curl_memdup(form->value, clen); 672 673 if(!form->value) { 674 return_value = CURL_FORMADD_MEMORY; 675 break; 676 } 677 form->value_alloc = TRUE; 678 } 679 post = AddHttpPost(form->name, form->namelength, 680 form->value, form->contentslength, 681 form->buffer, form->bufferlength, 682 form->contenttype, form->flags, 683 form->contentheader, form->showfilename, 684 form->userp, 685 post, httppost, 686 last_post); 687 688 if(!post) { 689 return_value = CURL_FORMADD_MEMORY; 690 break; 691 } 692 693 if(form->contenttype) 694 prevtype = form->contenttype; 695 } 696 } 697 if(CURL_FORMADD_OK != return_value) { 698 /* On error, free allocated fields for nodes of the FormInfo linked 699 list which are not already owned by the httppost linked list 700 without deallocating nodes. List nodes are deallocated later on */ 701 FormInfo *ptr; 702 for(ptr = form; ptr != NULL; ptr = ptr->more) { 703 if(ptr->name_alloc) { 704 Curl_safefree(ptr->name); 705 ptr->name_alloc = FALSE; 706 } 707 if(ptr->value_alloc) { 708 Curl_safefree(ptr->value); 709 ptr->value_alloc = FALSE; 710 } 711 if(ptr->contenttype_alloc) { 712 Curl_safefree(ptr->contenttype); 713 ptr->contenttype_alloc = FALSE; 714 } 715 if(ptr->showfilename_alloc) { 716 Curl_safefree(ptr->showfilename); 717 ptr->showfilename_alloc = FALSE; 718 } 719 } 720 } 721 } 722 723 /* Always deallocate FormInfo linked list nodes without touching node 724 fields given that these have either been deallocated or are owned 725 now by the httppost linked list */ 726 while(first_form) { 727 FormInfo *ptr = first_form->more; 728 free(first_form); 729 first_form = ptr; 730 } 731 732 return return_value; 733 } 734 735 /* 736 * curl_formadd() is a public API to add a section to the multipart formpost. 737 * 738 * @unittest: 1308 739 */ 740 741 CURLFORMcode curl_formadd(struct curl_httppost **httppost, 742 struct curl_httppost **last_post, 743 ...) 744 { 745 va_list arg; 746 CURLFORMcode result; 747 va_start(arg, last_post); 748 result = FormAdd(httppost, last_post, arg); 749 va_end(arg); 750 return result; 751 } 752 753 #ifdef __VMS 754 #include <fabdef.h> 755 /* 756 * get_vms_file_size does what it takes to get the real size of the file 757 * 758 * For fixed files, find out the size of the EOF block and adjust. 759 * 760 * For all others, have to read the entire file in, discarding the contents. 761 * Most posted text files will be small, and binary files like zlib archives 762 * and CD/DVD images should be either a STREAM_LF format or a fixed format. 763 * 764 */ 765 curl_off_t VmsRealFileSize(const char *name, 766 const struct_stat *stat_buf) 767 { 768 char buffer[8192]; 769 curl_off_t count; 770 int ret_stat; 771 FILE * file; 772 773 file = fopen(name, FOPEN_READTEXT); /* VMS */ 774 if(file == NULL) 775 return 0; 776 777 count = 0; 778 ret_stat = 1; 779 while(ret_stat > 0) { 780 ret_stat = fread(buffer, 1, sizeof(buffer), file); 781 if(ret_stat != 0) 782 count += ret_stat; 783 } 784 fclose(file); 785 786 return count; 787 } 788 789 /* 790 * 791 * VmsSpecialSize checks to see if the stat st_size can be trusted and 792 * if not to call a routine to get the correct size. 793 * 794 */ 795 static curl_off_t VmsSpecialSize(const char *name, 796 const struct_stat *stat_buf) 797 { 798 switch(stat_buf->st_fab_rfm) { 799 case FAB$C_VAR: 800 case FAB$C_VFC: 801 return VmsRealFileSize(name, stat_buf); 802 break; 803 default: 804 return stat_buf->st_size; 805 } 806 } 807 808 #endif 809 810 #ifndef __VMS 811 #define filesize(name, stat_data) (stat_data.st_size) 812 #else 813 /* Getting the expected file size needs help on VMS */ 814 #define filesize(name, stat_data) VmsSpecialSize(name, &stat_data) 815 #endif 816 817 /* 818 * AddFormData() adds a chunk of data to the FormData linked list. 819 * 820 * size is incremented by the chunk length, unless it is NULL 821 */ 822 static CURLcode AddFormData(struct FormData **formp, 823 enum formtype type, 824 const void *line, 825 curl_off_t length, 826 curl_off_t *size) 827 { 828 struct FormData *newform; 829 char *alloc2 = NULL; 830 CURLcode result = CURLE_OK; 831 if(length < 0 || (size && *size < 0)) 832 return CURLE_BAD_FUNCTION_ARGUMENT; 833 834 newform = malloc(sizeof(struct FormData)); 835 if(!newform) 836 return CURLE_OUT_OF_MEMORY; 837 newform->next = NULL; 838 839 if(type <= FORM_CONTENT) { 840 /* we make it easier for plain strings: */ 841 if(!length) 842 length = strlen((char *)line); 843 #if (SIZEOF_SIZE_T < CURL_SIZEOF_CURL_OFF_T) 844 else if(length >= (curl_off_t)(size_t)-1) { 845 result = CURLE_BAD_FUNCTION_ARGUMENT; 846 goto error; 847 } 848 #endif 849 if(type != FORM_DATAMEM) { 850 newform->line = malloc((size_t)length+1); 851 if(!newform->line) { 852 result = CURLE_OUT_OF_MEMORY; 853 goto error; 854 } 855 alloc2 = newform->line; 856 memcpy(newform->line, line, (size_t)length); 857 858 /* zero terminate for easier debugging */ 859 newform->line[(size_t)length]=0; 860 } 861 else { 862 newform->line = (char *)line; 863 type = FORM_DATA; /* in all other aspects this is just FORM_DATA */ 864 } 865 newform->length = (size_t)length; 866 } 867 else 868 /* For callbacks and files we don't have any actual data so we just keep a 869 pointer to whatever this points to */ 870 newform->line = (char *)line; 871 872 newform->type = type; 873 874 if(size) { 875 if(type != FORM_FILE) 876 /* for static content as well as callback data we add the size given 877 as input argument */ 878 *size += length; 879 else { 880 /* Since this is a file to be uploaded here, add the size of the actual 881 file */ 882 if(strcmp("-", newform->line)) { 883 struct_stat file; 884 if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode)) 885 *size += filesize(newform->line, file); 886 else { 887 result = CURLE_BAD_FUNCTION_ARGUMENT; 888 goto error; 889 } 890 } 891 } 892 } 893 894 if(*formp) { 895 (*formp)->next = newform; 896 *formp = newform; 897 } 898 else 899 *formp = newform; 900 901 return CURLE_OK; 902 error: 903 if(newform) 904 free(newform); 905 if(alloc2) 906 free(alloc2); 907 return result; 908 } 909 910 /* 911 * AddFormDataf() adds printf()-style formatted data to the formdata chain. 912 */ 913 914 static CURLcode AddFormDataf(struct FormData **formp, 915 curl_off_t *size, 916 const char *fmt, ...) 917 { 918 char *s; 919 CURLcode result; 920 va_list ap; 921 va_start(ap, fmt); 922 s = curl_mvaprintf(fmt, ap); 923 va_end(ap); 924 925 if(!s) 926 return CURLE_OUT_OF_MEMORY; 927 928 result = AddFormData(formp, FORM_DATAMEM, s, 0, size); 929 if(result) 930 free(s); 931 932 return result; 933 } 934 935 /* 936 * Curl_formclean() is used from http.c, this cleans a built FormData linked 937 * list 938 */ 939 void Curl_formclean(struct FormData **form_ptr) 940 { 941 struct FormData *next, *form; 942 943 form = *form_ptr; 944 if(!form) 945 return; 946 947 do { 948 next=form->next; /* the following form line */ 949 if(form->type <= FORM_CONTENT) 950 free(form->line); /* free the line */ 951 free(form); /* free the struct */ 952 953 } while((form = next) != NULL); /* continue */ 954 955 *form_ptr = NULL; 956 } 957 958 /* 959 * curl_formget() 960 * Serialize a curl_httppost struct. 961 * Returns 0 on success. 962 * 963 * @unittest: 1308 964 */ 965 int curl_formget(struct curl_httppost *form, void *arg, 966 curl_formget_callback append) 967 { 968 CURLcode result; 969 curl_off_t size; 970 struct FormData *data, *ptr; 971 972 result = Curl_getformdata(NULL, &data, form, NULL, &size); 973 if(result) 974 return (int)result; 975 976 for(ptr = data; ptr; ptr = ptr->next) { 977 if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) { 978 char buffer[8192]; 979 size_t nread; 980 struct Form temp; 981 982 Curl_FormInit(&temp, ptr); 983 984 do { 985 nread = readfromfile(&temp, buffer, sizeof(buffer)); 986 if((nread == (size_t) -1) || 987 (nread > sizeof(buffer)) || 988 (nread != append(arg, buffer, nread))) { 989 if(temp.fp) 990 fclose(temp.fp); 991 Curl_formclean(&data); 992 return -1; 993 } 994 } while(nread); 995 } 996 else { 997 if(ptr->length != append(arg, ptr->line, ptr->length)) { 998 Curl_formclean(&data); 999 return -1; 1000 } 1001 } 1002 } 1003 Curl_formclean(&data); 1004 return 0; 1005 } 1006 1007 /* 1008 * curl_formfree() is an external function to free up a whole form post 1009 * chain 1010 */ 1011 void curl_formfree(struct curl_httppost *form) 1012 { 1013 struct curl_httppost *next; 1014 1015 if(!form) 1016 /* no form to free, just get out of this */ 1017 return; 1018 1019 do { 1020 next=form->next; /* the following form line */ 1021 1022 /* recurse to sub-contents */ 1023 curl_formfree(form->more); 1024 1025 if(!(form->flags & HTTPPOST_PTRNAME)) 1026 free(form->name); /* free the name */ 1027 if(!(form->flags & 1028 (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK)) 1029 ) 1030 free(form->contents); /* free the contents */ 1031 free(form->contenttype); /* free the content type */ 1032 free(form->showfilename); /* free the faked file name */ 1033 free(form); /* free the struct */ 1034 1035 } while((form = next) != NULL); /* continue */ 1036 } 1037 1038 #ifndef HAVE_BASENAME 1039 /* 1040 (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004 1041 Edition) 1042 1043 The basename() function shall take the pathname pointed to by path and 1044 return a pointer to the final component of the pathname, deleting any 1045 trailing '/' characters. 1046 1047 If the string pointed to by path consists entirely of the '/' character, 1048 basename() shall return a pointer to the string "/". If the string pointed 1049 to by path is exactly "//", it is implementation-defined whether '/' or "//" 1050 is returned. 1051 1052 If path is a null pointer or points to an empty string, basename() shall 1053 return a pointer to the string ".". 1054 1055 The basename() function may modify the string pointed to by path, and may 1056 return a pointer to static storage that may then be overwritten by a 1057 subsequent call to basename(). 1058 1059 The basename() function need not be reentrant. A function that is not 1060 required to be reentrant is not required to be thread-safe. 1061 1062 */ 1063 static char *Curl_basename(char *path) 1064 { 1065 /* Ignore all the details above for now and make a quick and simple 1066 implementaion here */ 1067 char *s1; 1068 char *s2; 1069 1070 s1=strrchr(path, '/'); 1071 s2=strrchr(path, '\\'); 1072 1073 if(s1 && s2) { 1074 path = (s1 > s2? s1 : s2)+1; 1075 } 1076 else if(s1) 1077 path = s1 + 1; 1078 else if(s2) 1079 path = s2 + 1; 1080 1081 return path; 1082 } 1083 #endif 1084 1085 static char *strippath(const char *fullfile) 1086 { 1087 char *filename; 1088 char *base; 1089 filename = strdup(fullfile); /* duplicate since basename() may ruin the 1090 buffer it works on */ 1091 if(!filename) 1092 return NULL; 1093 base = strdup(basename(filename)); 1094 1095 free(filename); /* free temporary buffer */ 1096 1097 return base; /* returns an allocated string or NULL ! */ 1098 } 1099 1100 static CURLcode formdata_add_filename(const struct curl_httppost *file, 1101 struct FormData **form, 1102 curl_off_t *size) 1103 { 1104 CURLcode result = CURLE_OK; 1105 char *filename = file->showfilename; 1106 char *filebasename = NULL; 1107 char *filename_escaped = NULL; 1108 1109 if(!filename) { 1110 filebasename = strippath(file->contents); 1111 if(!filebasename) 1112 return CURLE_OUT_OF_MEMORY; 1113 filename = filebasename; 1114 } 1115 1116 if(strchr(filename, '\\') || strchr(filename, '"')) { 1117 char *p0, *p1; 1118 1119 /* filename need be escaped */ 1120 filename_escaped = malloc(strlen(filename)*2+1); 1121 if(!filename_escaped) { 1122 free(filebasename); 1123 return CURLE_OUT_OF_MEMORY; 1124 } 1125 p0 = filename_escaped; 1126 p1 = filename; 1127 while(*p1) { 1128 if(*p1 == '\\' || *p1 == '"') 1129 *p0++ = '\\'; 1130 *p0++ = *p1++; 1131 } 1132 *p0 = '\0'; 1133 filename = filename_escaped; 1134 } 1135 result = AddFormDataf(form, size, 1136 "; filename=\"%s\"", 1137 filename); 1138 free(filename_escaped); 1139 free(filebasename); 1140 return result; 1141 } 1142 1143 /* 1144 * Curl_getformdata() converts a linked list of "meta data" into a complete 1145 * (possibly huge) multipart formdata. The input list is in 'post', while the 1146 * output resulting linked lists gets stored in '*finalform'. *sizep will get 1147 * the total size of the whole POST. 1148 * A multipart/form_data content-type is built, unless a custom content-type 1149 * is passed in 'custom_content_type'. 1150 * 1151 * This function will not do a failf() for the potential memory failures but 1152 * should for all other errors it spots. Just note that this function MAY get 1153 * a NULL pointer in the 'data' argument. 1154 */ 1155 1156 CURLcode Curl_getformdata(struct Curl_easy *data, 1157 struct FormData **finalform, 1158 struct curl_httppost *post, 1159 const char *custom_content_type, 1160 curl_off_t *sizep) 1161 { 1162 struct FormData *form = NULL; 1163 struct FormData *firstform; 1164 struct curl_httppost *file; 1165 CURLcode result = CURLE_OK; 1166 1167 curl_off_t size = 0; /* support potentially ENORMOUS formposts */ 1168 char *boundary; 1169 char *fileboundary = NULL; 1170 struct curl_slist *curList; 1171 1172 *finalform = NULL; /* default form is empty */ 1173 1174 if(!post) 1175 return result; /* no input => no output! */ 1176 1177 boundary = formboundary(data); 1178 if(!boundary) 1179 return CURLE_OUT_OF_MEMORY; 1180 1181 /* Make the first line of the output */ 1182 result = AddFormDataf(&form, NULL, 1183 "%s; boundary=%s\r\n", 1184 custom_content_type?custom_content_type: 1185 "Content-Type: multipart/form-data", 1186 boundary); 1187 1188 if(result) { 1189 free(boundary); 1190 return result; 1191 } 1192 /* we DO NOT include that line in the total size of the POST, since it'll be 1193 part of the header! */ 1194 1195 firstform = form; 1196 1197 do { 1198 1199 if(size) { 1200 result = AddFormDataf(&form, &size, "\r\n"); 1201 if(result) 1202 break; 1203 } 1204 1205 /* boundary */ 1206 result = AddFormDataf(&form, &size, "--%s\r\n", boundary); 1207 if(result) 1208 break; 1209 1210 /* Maybe later this should be disabled when a custom_content_type is 1211 passed, since Content-Disposition is not meaningful for all multipart 1212 types. 1213 */ 1214 result = AddFormDataf(&form, &size, 1215 "Content-Disposition: form-data; name=\""); 1216 if(result) 1217 break; 1218 1219 result = AddFormData(&form, FORM_DATA, post->name, post->namelength, 1220 &size); 1221 if(result) 1222 break; 1223 1224 result = AddFormDataf(&form, &size, "\""); 1225 if(result) 1226 break; 1227 1228 if(post->more) { 1229 /* If used, this is a link to more file names, we must then do 1230 the magic to include several files with the same field name */ 1231 1232 free(fileboundary); 1233 fileboundary = formboundary(data); 1234 if(!fileboundary) { 1235 result = CURLE_OUT_OF_MEMORY; 1236 break; 1237 } 1238 1239 result = AddFormDataf(&form, &size, 1240 "\r\nContent-Type: multipart/mixed;" 1241 " boundary=%s\r\n", 1242 fileboundary); 1243 if(result) 1244 break; 1245 } 1246 1247 file = post; 1248 1249 do { 1250 1251 /* If 'showfilename' is set, that is a faked name passed on to us 1252 to use to in the formpost. If that is not set, the actually used 1253 local file name should be added. */ 1254 1255 if(post->more) { 1256 /* if multiple-file */ 1257 result = AddFormDataf(&form, &size, 1258 "\r\n--%s\r\nContent-Disposition: " 1259 "attachment", 1260 fileboundary); 1261 if(result) 1262 break; 1263 result = formdata_add_filename(file, &form, &size); 1264 if(result) 1265 break; 1266 } 1267 else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER| 1268 HTTPPOST_CALLBACK)) { 1269 /* it should be noted that for the HTTPPOST_FILENAME and 1270 HTTPPOST_CALLBACK cases the ->showfilename struct member is always 1271 assigned at this point */ 1272 if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) { 1273 result = formdata_add_filename(post, &form, &size); 1274 } 1275 1276 if(result) 1277 break; 1278 } 1279 1280 if(file->contenttype) { 1281 /* we have a specified type */ 1282 result = AddFormDataf(&form, &size, 1283 "\r\nContent-Type: %s", 1284 file->contenttype); 1285 if(result) 1286 break; 1287 } 1288 1289 curList = file->contentheader; 1290 while(curList) { 1291 /* Process the additional headers specified for this form */ 1292 result = AddFormDataf(&form, &size, "\r\n%s", curList->data); 1293 if(result) 1294 break; 1295 curList = curList->next; 1296 } 1297 if(result) 1298 break; 1299 1300 result = AddFormDataf(&form, &size, "\r\n\r\n"); 1301 if(result) 1302 break; 1303 1304 if((post->flags & HTTPPOST_FILENAME) || 1305 (post->flags & HTTPPOST_READFILE)) { 1306 /* we should include the contents from the specified file */ 1307 FILE *fileread; 1308 1309 fileread = !strcmp("-", file->contents)? 1310 stdin:fopen(file->contents, "rb"); /* binary read for win32 */ 1311 1312 /* 1313 * VMS: This only allows for stream files on VMS. Stream files are 1314 * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC, 1315 * every record needs to have a \n appended & 1 added to SIZE 1316 */ 1317 1318 if(fileread) { 1319 if(fileread != stdin) { 1320 /* close the file */ 1321 fclose(fileread); 1322 /* add the file name only - for later reading from this */ 1323 result = AddFormData(&form, FORM_FILE, file->contents, 0, &size); 1324 } 1325 else { 1326 /* When uploading from stdin, we can't know the size of the file, 1327 * thus must read the full file as before. We *could* use chunked 1328 * transfer-encoding, but that only works for HTTP 1.1 and we 1329 * can't be sure we work with such a server. 1330 */ 1331 size_t nread; 1332 char buffer[512]; 1333 while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) { 1334 result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size); 1335 if(result) 1336 break; 1337 } 1338 } 1339 } 1340 else { 1341 if(data) 1342 failf(data, "couldn't open file \"%s\"", file->contents); 1343 *finalform = NULL; 1344 result = CURLE_READ_ERROR; 1345 } 1346 } 1347 else if(post->flags & HTTPPOST_BUFFER) 1348 /* include contents of buffer */ 1349 result = AddFormData(&form, FORM_CONTENT, post->buffer, 1350 post->bufferlength, &size); 1351 else if(post->flags & HTTPPOST_CALLBACK) 1352 /* the contents should be read with the callback and the size is set 1353 with the contentslength */ 1354 result = AddFormData(&form, FORM_CALLBACK, post->userp, 1355 post->flags&CURL_HTTPPOST_LARGE? 1356 post->contentlen:post->contentslength, &size); 1357 else 1358 /* include the contents we got */ 1359 result = AddFormData(&form, FORM_CONTENT, post->contents, 1360 post->flags&CURL_HTTPPOST_LARGE? 1361 post->contentlen:post->contentslength, &size); 1362 file = file->more; 1363 } while(file && !result); /* for each specified file for this field */ 1364 1365 if(result) 1366 break; 1367 1368 if(post->more) { 1369 /* this was a multiple-file inclusion, make a termination file 1370 boundary: */ 1371 result = AddFormDataf(&form, &size, 1372 "\r\n--%s--", 1373 fileboundary); 1374 if(result) 1375 break; 1376 } 1377 1378 } while((post = post->next) != NULL); /* for each field */ 1379 1380 /* end-boundary for everything */ 1381 if(!result) 1382 result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary); 1383 1384 if(result) { 1385 Curl_formclean(&firstform); 1386 free(fileboundary); 1387 free(boundary); 1388 return result; 1389 } 1390 1391 *sizep = size; 1392 1393 free(fileboundary); 1394 free(boundary); 1395 1396 *finalform = firstform; 1397 1398 return result; 1399 } 1400 1401 /* 1402 * Curl_FormInit() inits the struct 'form' points to with the 'formdata' 1403 * and resets the 'sent' counter. 1404 */ 1405 int Curl_FormInit(struct Form *form, struct FormData *formdata) 1406 { 1407 if(!formdata) 1408 return 1; /* error */ 1409 1410 form->data = formdata; 1411 form->sent = 0; 1412 form->fp = NULL; 1413 form->fread_func = ZERO_NULL; 1414 1415 return 0; 1416 } 1417 1418 #ifndef __VMS 1419 # define fopen_read fopen 1420 #else 1421 /* 1422 * vmsfopenread 1423 * 1424 * For upload to work as expected on VMS, different optional 1425 * parameters must be added to the fopen command based on 1426 * record format of the file. 1427 * 1428 */ 1429 # define fopen_read vmsfopenread 1430 static FILE * vmsfopenread(const char *file, const char *mode) 1431 { 1432 struct_stat statbuf; 1433 int result; 1434 1435 result = stat(file, &statbuf); 1436 1437 switch (statbuf.st_fab_rfm) { 1438 case FAB$C_VAR: 1439 case FAB$C_VFC: 1440 case FAB$C_STMCR: 1441 return fopen(file, FOPEN_READTEXT); /* VMS */ 1442 break; 1443 default: 1444 return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm"); 1445 } 1446 } 1447 #endif 1448 1449 /* 1450 * readfromfile() 1451 * 1452 * The read callback that this function may use can return a value larger than 1453 * 'size' (which then this function returns) that indicates a problem and it 1454 * must be properly dealt with 1455 */ 1456 static size_t readfromfile(struct Form *form, char *buffer, 1457 size_t size) 1458 { 1459 size_t nread; 1460 bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE; 1461 1462 if(callback) { 1463 if(form->fread_func == ZERO_NULL) 1464 return 0; 1465 else 1466 nread = form->fread_func(buffer, 1, size, form->data->line); 1467 } 1468 else { 1469 if(!form->fp) { 1470 /* this file hasn't yet been opened */ 1471 form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */ 1472 if(!form->fp) 1473 return (size_t)-1; /* failure */ 1474 } 1475 nread = fread(buffer, 1, size, form->fp); 1476 } 1477 if(!nread) { 1478 /* this is the last chunk from the file, move on */ 1479 if(form->fp) { 1480 fclose(form->fp); 1481 form->fp = NULL; 1482 } 1483 form->data = form->data->next; 1484 } 1485 1486 return nread; 1487 } 1488 1489 /* 1490 * Curl_FormReader() is the fread() emulation function that will be used to 1491 * deliver the formdata to the transfer loop and then sent away to the peer. 1492 */ 1493 size_t Curl_FormReader(char *buffer, 1494 size_t size, 1495 size_t nitems, 1496 FILE *mydata) 1497 { 1498 struct Form *form; 1499 size_t wantedsize; 1500 size_t gotsize = 0; 1501 1502 form=(struct Form *)mydata; 1503 1504 wantedsize = size * nitems; 1505 1506 if(!form->data) 1507 return 0; /* nothing, error, empty */ 1508 1509 if((form->data->type == FORM_FILE) || 1510 (form->data->type == FORM_CALLBACK)) { 1511 gotsize = readfromfile(form, buffer, wantedsize); 1512 1513 if(gotsize) 1514 /* If positive or -1, return. If zero, continue! */ 1515 return gotsize; 1516 } 1517 do { 1518 1519 if((form->data->length - form->sent) > wantedsize - gotsize) { 1520 1521 memcpy(buffer + gotsize, form->data->line + form->sent, 1522 wantedsize - gotsize); 1523 1524 form->sent += wantedsize-gotsize; 1525 1526 return wantedsize; 1527 } 1528 1529 memcpy(buffer+gotsize, 1530 form->data->line + form->sent, 1531 (form->data->length - form->sent) ); 1532 gotsize += form->data->length - form->sent; 1533 1534 form->sent = 0; 1535 1536 form->data = form->data->next; /* advance */ 1537 1538 } while(form->data && (form->data->type < FORM_CALLBACK)); 1539 /* If we got an empty line and we have more data, we proceed to the next 1540 line immediately to avoid returning zero before we've reached the end. */ 1541 1542 return gotsize; 1543 } 1544 1545 /* 1546 * Curl_formpostheader() returns the first line of the formpost, the 1547 * request-header part (which is not part of the request-body like the rest of 1548 * the post). 1549 */ 1550 char *Curl_formpostheader(void *formp, size_t *len) 1551 { 1552 char *header; 1553 struct Form *form=(struct Form *)formp; 1554 1555 if(!form->data) 1556 return 0; /* nothing, ERROR! */ 1557 1558 header = form->data->line; 1559 *len = form->data->length; 1560 1561 form->data = form->data->next; /* advance */ 1562 1563 return header; 1564 } 1565 1566 /* 1567 * formboundary() creates a suitable boundary string and returns an allocated 1568 * one. 1569 */ 1570 static char *formboundary(struct Curl_easy *data) 1571 { 1572 /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615) 1573 combinations */ 1574 unsigned int rnd[2]; 1575 CURLcode result = Curl_rand(data, &rnd[0], 2); 1576 if(result) 1577 return NULL; 1578 1579 return aprintf("------------------------%08x%08x", rnd[0], rnd[1]); 1580 } 1581 1582 #else /* CURL_DISABLE_HTTP */ 1583 CURLFORMcode curl_formadd(struct curl_httppost **httppost, 1584 struct curl_httppost **last_post, 1585 ...) 1586 { 1587 (void)httppost; 1588 (void)last_post; 1589 return CURL_FORMADD_DISABLED; 1590 } 1591 1592 int curl_formget(struct curl_httppost *form, void *arg, 1593 curl_formget_callback append) 1594 { 1595 (void) form; 1596 (void) arg; 1597 (void) append; 1598 return CURL_FORMADD_DISABLED; 1599 } 1600 1601 void curl_formfree(struct curl_httppost *form) 1602 { 1603 (void)form; 1604 /* does nothing HTTP is disabled */ 1605 } 1606 1607 1608 #endif /* !defined(CURL_DISABLE_HTTP) */ 1609