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