1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2011, 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#include "setup.h" 23 24#include <curl/curl.h> 25 26#ifdef HAVE_UNISTD_H 27# include <unistd.h> 28#endif 29 30#ifdef HAVE_FCNTL_H 31# include <fcntl.h> 32#endif 33 34#ifdef HAVE_UTIME_H 35# include <utime.h> 36#elif defined(HAVE_SYS_UTIME_H) 37# include <sys/utime.h> 38#endif 39 40#ifdef HAVE_LOCALE_H 41# include <locale.h> 42#endif 43 44#include "rawstr.h" 45 46#define ENABLE_CURLX_PRINTF 47/* use our own printf() functions */ 48#include "curlx.h" 49 50#include "tool_binmode.h" 51#include "tool_cfgable.h" 52#include "tool_cb_dbg.h" 53#include "tool_cb_hdr.h" 54#include "tool_cb_prg.h" 55#include "tool_cb_rea.h" 56#include "tool_cb_see.h" 57#include "tool_cb_skt.h" 58#include "tool_cb_wrt.h" 59#include "tool_dirhie.h" 60#include "tool_doswin.h" 61#include "tool_easysrc.h" 62#include "tool_getparam.h" 63#include "tool_helpers.h" 64#include "tool_homedir.h" 65#include "tool_libinfo.h" 66#include "tool_main.h" 67#include "tool_msgs.h" 68#include "tool_operate.h" 69#include "tool_operhlp.h" 70#include "tool_parsecfg.h" 71#include "tool_setopt.h" 72#include "tool_sleep.h" 73#include "tool_urlglob.h" 74#include "tool_util.h" 75#include "tool_writeenv.h" 76#include "tool_writeout.h" 77#include "tool_xattr.h" 78 79#include "memdebug.h" /* keep this as LAST include */ 80 81#define CURLseparator "--_curl_--" 82 83#ifndef O_BINARY 84/* since O_BINARY as used in bitmasks, setting it to zero makes it usable in 85 source code but yet it doesn't ruin anything */ 86# define O_BINARY 0 87#endif 88 89#define CURL_CA_CERT_ERRORMSG1 \ 90 "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n" \ 91 "curl performs SSL certificate verification by default, " \ 92 "using a \"bundle\"\n" \ 93 " of Certificate Authority (CA) public keys (CA certs). If the default\n" \ 94 " bundle file isn't adequate, you can specify an alternate file\n" \ 95 " using the --cacert option.\n" 96 97#define CURL_CA_CERT_ERRORMSG2 \ 98 "If this HTTPS server uses a certificate signed by a CA represented in\n" \ 99 " the bundle, the certificate verification probably failed due to a\n" \ 100 " problem with the certificate (it might be expired, or the name might\n" \ 101 " not match the domain name in the URL).\n" \ 102 "If you'd like to turn off curl's verification of the certificate, use\n" \ 103 " the -k (or --insecure) option.\n" 104 105int operate(struct Configurable *config, int argc, argv_item_t argv[]) 106{ 107 char errorbuffer[CURL_ERROR_SIZE]; 108 struct ProgressData progressbar; 109 struct getout *urlnode; 110 111 struct OutStruct heads; 112 113 CURL *curl = NULL; 114 char *httpgetfields = NULL; 115 116 bool stillflags; 117 int res = 0; 118 int i; 119 120 errorbuffer[0] = '\0'; 121 /* default headers output stream is stdout */ 122 memset(&heads, 0, sizeof(struct OutStruct)); 123 heads.stream = stdout; 124 heads.config = config; 125 126 memory_tracking_init(); 127 128 /* 129 ** Initialize curl library - do not call any libcurl functions before 130 ** this point. Note that the memory_tracking_init() magic above is an 131 ** exception, but then that's not part of the official public API. 132 */ 133 if(main_init() != CURLE_OK) { 134 helpf(config->errors, "error initializing curl library\n"); 135 return CURLE_FAILED_INIT; 136 } 137 138 /* Get libcurl info right away */ 139 if(get_libcurl_info() != CURLE_OK) { 140 helpf(config->errors, "error retrieving curl library information\n"); 141 main_free(); 142 return CURLE_FAILED_INIT; 143 } 144 145 /* Get a curl handle to use for all forthcoming curl transfers */ 146 curl = curl_easy_init(); 147 if(!curl) { 148 helpf(config->errors, "error initializing curl easy handle\n"); 149 main_free(); 150 return CURLE_FAILED_INIT; 151 } 152 config->easy = curl; 153 154 /* 155 ** Beyond this point no return'ing from this function allowed. 156 ** Jump to label 'quit_curl' in order to abandon this function 157 ** from outside of nested loops further down below. 158 */ 159 160 /* setup proper locale from environment */ 161#ifdef HAVE_SETLOCALE 162 setlocale(LC_ALL, ""); 163#endif 164 165 /* inits */ 166 config->postfieldsize = -1; 167 config->showerror = -1; /* will show errors */ 168 config->use_httpget = FALSE; 169 config->create_dirs = FALSE; 170 config->maxredirs = DEFAULT_MAXREDIRS; 171 config->proto = CURLPROTO_ALL; /* FIXME: better to read from library */ 172 config->proto_present = FALSE; 173 config->proto_redir = 174 CURLPROTO_ALL & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */ 175 config->proto_redir_present = FALSE; 176 177 if((argc > 1) && 178 (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) && 179 strchr(argv[1], 'q')) { 180 /* 181 * The first flag, that is not a verbose name, but a shortname 182 * and it includes the 'q' flag! 183 */ 184 ; 185 } 186 else { 187 parseconfig(NULL, config); /* ignore possible failure */ 188 } 189 190 if((argc < 2) && !config->url_list) { 191 helpf(config->errors, NULL); 192 res = CURLE_FAILED_INIT; 193 goto quit_curl; 194 } 195 196 /* Parse options */ 197 for(i = 1, stillflags = TRUE; i < argc; i++) { 198 if(stillflags && 199 ('-' == argv[i][0])) { 200 char *nextarg; 201 bool passarg; 202 char *origopt = argv[i]; 203 204 char *flag = argv[i]; 205 206 if(curlx_strequal("--", argv[i])) 207 /* this indicates the end of the flags and thus enables the 208 following (URL) argument to start with -. */ 209 stillflags = FALSE; 210 else { 211 nextarg = (i < (argc-1)) ? argv[i+1] : NULL; 212 213 res = getparameter(flag, nextarg, &passarg, config); 214 if(res) { 215 int retval = CURLE_OK; 216 if(res != PARAM_HELP_REQUESTED) { 217 const char *reason = param2text(res); 218 helpf(config->errors, "option %s: %s\n", origopt, reason); 219 retval = CURLE_FAILED_INIT; 220 } 221 res = retval; 222 goto quit_curl; 223 } 224 225 if(passarg) /* we're supposed to skip this */ 226 i++; 227 } 228 } 229 else { 230 bool used; 231 /* just add the URL please */ 232 res = getparameter((char *)"--url", argv[i], &used, config); 233 if(res) 234 goto quit_curl; 235 } 236 } 237 238 if((!config->url_list || !config->url_list->url) && !config->list_engines) { 239 helpf(config->errors, "no URL specified!\n"); 240 res = CURLE_FAILED_INIT; 241 goto quit_curl; 242 } 243 244 if(!config->useragent) 245 config->useragent = my_useragent(); 246 if(!config->useragent) { 247 helpf(config->errors, "out of memory\n"); 248 res = CURLE_OUT_OF_MEMORY; 249 goto quit_curl; 250 } 251 252 /* On WIN32 we can't set the path to curl-ca-bundle.crt 253 * at compile time. So we look here for the file in two ways: 254 * 1: look at the environment variable CURL_CA_BUNDLE for a path 255 * 2: if #1 isn't found, use the windows API function SearchPath() 256 * to find it along the app's path (includes app's dir and CWD) 257 * 258 * We support the environment variable thing for non-Windows platforms 259 * too. Just for the sake of it. 260 */ 261 if(!config->cacert && 262 !config->capath && 263 !config->insecure_ok) { 264 char *env; 265 env = curlx_getenv("CURL_CA_BUNDLE"); 266 if(env) { 267 config->cacert = strdup(env); 268 if(!config->cacert) { 269 curl_free(env); 270 helpf(config->errors, "out of memory\n"); 271 res = CURLE_OUT_OF_MEMORY; 272 goto quit_curl; 273 } 274 } 275 else { 276 env = curlx_getenv("SSL_CERT_DIR"); 277 if(env) { 278 config->capath = strdup(env); 279 if(!config->capath) { 280 curl_free(env); 281 helpf(config->errors, "out of memory\n"); 282 res = CURLE_OUT_OF_MEMORY; 283 goto quit_curl; 284 } 285 } 286 else { 287 env = curlx_getenv("SSL_CERT_FILE"); 288 if(env) { 289 config->cacert = strdup(env); 290 if(!config->cacert) { 291 curl_free(env); 292 helpf(config->errors, "out of memory\n"); 293 res = CURLE_OUT_OF_MEMORY; 294 goto quit_curl; 295 } 296 } 297 } 298 } 299 300 if(env) 301 curl_free(env); 302#ifdef WIN32 303 else { 304 res = FindWin32CACert(config, "curl-ca-bundle.crt"); 305 if(res) 306 goto quit_curl; 307 } 308#endif 309 } 310 311 if(config->postfields) { 312 if(config->use_httpget) { 313 /* Use the postfields data for a http get */ 314 httpgetfields = strdup(config->postfields); 315 Curl_safefree(config->postfields); 316 if(!httpgetfields) { 317 helpf(config->errors, "out of memory\n"); 318 res = CURLE_OUT_OF_MEMORY; 319 goto quit_curl; 320 } 321 if(SetHTTPrequest(config, 322 (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET), 323 &config->httpreq)) { 324 res = PARAM_BAD_USE; 325 goto quit_curl; 326 } 327 } 328 else { 329 if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq)) { 330 res = PARAM_BAD_USE; 331 goto quit_curl; 332 } 333 } 334 } 335 336 /* This is the first entry added to easysrc and it initializes the slist */ 337 easysrc = curl_slist_append(easysrc, "CURL *hnd = curl_easy_init();"); 338 if(!easysrc) { 339 helpf(config->errors, "out of memory\n"); 340 res = CURLE_OUT_OF_MEMORY; 341 goto quit_curl; 342 } 343 344 if(config->list_engines) { 345 struct curl_slist *engines = NULL; 346 curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines); 347 list_engines(engines); 348 curl_slist_free_all(engines); 349 res = CURLE_OK; 350 goto quit_curl; 351 } 352 353 /* Single header file for all URLs */ 354 if(config->headerfile) { 355 /* open file for output: */ 356 if(!curlx_strequal(config->headerfile, "-")) { 357 FILE *newfile = fopen(config->headerfile, "wb"); 358 if(!newfile) { 359 warnf(config, "Failed to open %s\n", config->headerfile); 360 res = CURLE_WRITE_ERROR; 361 goto quit_curl; 362 } 363 else { 364 heads.filename = config->headerfile; 365 heads.s_isreg = TRUE; 366 heads.fopened = TRUE; 367 heads.stream = newfile; 368 } 369 } 370 } 371 372 /* 373 ** Nested loops start here. 374 */ 375 376 /* loop through the list of given URLs */ 377 378 for(urlnode = config->url_list; urlnode; urlnode = urlnode->next) { 379 380 int up; /* upload file counter within a single upload glob */ 381 char *infiles; /* might be a glob pattern */ 382 char *outfiles; 383 int infilenum; 384 URLGlob *inglob; 385 386 outfiles = NULL; 387 infilenum = 0; 388 inglob = NULL; 389 390 /* urlnode->url is the full URL (it might be NULL) */ 391 392 if(!urlnode->url) { 393 /* This node has no URL. Free node data without destroying the 394 node itself nor modifying next pointer and continue to next */ 395 Curl_safefree(urlnode->outfile); 396 Curl_safefree(urlnode->infile); 397 urlnode->flags = 0; 398 continue; /* next URL please */ 399 } 400 401 /* save outfile pattern before expansion */ 402 if(urlnode->outfile) { 403 outfiles = strdup(urlnode->outfile); 404 if(!outfiles) { 405 helpf(config->errors, "out of memory\n"); 406 res = CURLE_OUT_OF_MEMORY; 407 break; 408 } 409 } 410 411 infiles = urlnode->infile; 412 413 if(!config->globoff && infiles) { 414 /* Unless explicitly shut off */ 415 res = glob_url(&inglob, infiles, &infilenum, 416 config->showerror?config->errors:NULL); 417 if(res) { 418 Curl_safefree(outfiles); 419 break; 420 } 421 } 422 423 /* Here's the loop for uploading multiple files within the same 424 single globbed string. If no upload, we enter the loop once anyway. */ 425 for(up = 0 ;; up++) { 426 427 char *uploadfile; /* a single file, never a glob */ 428 int separator; 429 URLGlob *urls; 430 int urlnum; 431 432 uploadfile = NULL; 433 separator = 0; 434 urls = NULL; 435 urlnum = 0; 436 437 if(!up && !infiles) 438 Curl_nop_stmt; 439 else { 440 if(inglob) { 441 res = glob_next_url(&uploadfile, inglob); 442 if(res == CURLE_OUT_OF_MEMORY) 443 helpf(config->errors, "out of memory\n"); 444 } 445 else if(!up) { 446 uploadfile = strdup(infiles); 447 if(!uploadfile) { 448 helpf(config->errors, "out of memory\n"); 449 res = CURLE_OUT_OF_MEMORY; 450 } 451 } 452 else 453 uploadfile = NULL; 454 if(!uploadfile) 455 break; 456 } 457 458 if(!config->globoff) { 459 /* Unless explicitly shut off, we expand '{...}' and '[...]' 460 expressions and return total number of URLs in pattern set */ 461 res = glob_url(&urls, urlnode->url, &urlnum, 462 config->showerror?config->errors:NULL); 463 if(res) { 464 Curl_safefree(uploadfile); 465 break; 466 } 467 } 468 else 469 urlnum = 1; /* without globbing, this is a single URL */ 470 471 /* if multiple files extracted to stdout, insert separators! */ 472 separator= ((!outfiles || curlx_strequal(outfiles, "-")) && urlnum > 1); 473 474 /* Here's looping around each globbed URL */ 475 for(i = 0 ;; i++) { 476 477 int infd; 478 bool infdopen; 479 char *outfile; 480 struct OutStruct outs; 481 struct InStruct input; 482 struct timeval retrystart; 483 curl_off_t uploadfilesize; 484 long retry_numretries; 485 long retry_sleep_default; 486 long retry_sleep; 487 char *this_url; 488 489 outfile = NULL; 490 infdopen = FALSE; 491 infd = STDIN_FILENO; 492 uploadfilesize = -1; /* -1 means unknown */ 493 494 /* default output stream is stdout */ 495 memset(&outs, 0, sizeof(struct OutStruct)); 496 outs.stream = stdout; 497 outs.config = config; 498 499 if(urls) { 500 res = glob_next_url(&this_url, urls); 501 if(res) 502 goto show_error; 503 } 504 else if(!i) { 505 this_url = strdup(urlnode->url); 506 if(!this_url) { 507 res = CURLE_OUT_OF_MEMORY; 508 goto show_error; 509 } 510 } 511 else 512 this_url = NULL; 513 if(!this_url) 514 break; 515 516 if(outfiles) { 517 outfile = strdup(outfiles); 518 if(!outfile) { 519 res = CURLE_OUT_OF_MEMORY; 520 goto show_error; 521 } 522 } 523 524 if((urlnode->flags&GETOUT_USEREMOTE) || 525 (outfile && !curlx_strequal("-", outfile)) ) { 526 527 /* 528 * We have specified a file name to store the result in, or we have 529 * decided we want to use the remote file name. 530 */ 531 532 if(!outfile) { 533 /* extract the file name from the URL */ 534 res = get_url_file_name(&outfile, this_url); 535 if(res) 536 goto show_error; 537 if((!outfile || !*outfile) && !config->content_disposition) { 538 helpf(config->errors, "Remote file name has no length!\n"); 539 res = CURLE_WRITE_ERROR; 540 goto quit_urls; 541 } 542#if defined(MSDOS) || defined(WIN32) 543 /* For DOS and WIN32, we do some major replacing of 544 bad characters in the file name before using it */ 545 outfile = sanitize_dos_name(outfile); 546 if(!outfile) { 547 res = CURLE_OUT_OF_MEMORY; 548 goto show_error; 549 } 550#endif /* MSDOS || WIN32 */ 551 } 552 else if(urls) { 553 /* fill '#1' ... '#9' terms from URL pattern */ 554 char *storefile = outfile; 555 res = glob_match_url(&outfile, storefile, urls); 556 Curl_safefree(storefile); 557 if(res) { 558 /* bad globbing */ 559 warnf(config, "bad output glob!\n"); 560 goto quit_urls; 561 } 562 } 563 564 /* Create the directory hierarchy, if not pre-existent to a multiple 565 file output call */ 566 567 if(config->create_dirs) { 568 res = create_dir_hierarchy(outfile, config->errors); 569 /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */ 570 if(res == CURLE_WRITE_ERROR) 571 goto quit_urls; 572 if(res) { 573 goto show_error; 574 } 575 } 576 577 if((urlnode->flags & GETOUT_USEREMOTE) 578 && config->content_disposition) { 579 /* Our header callback sets the filename */ 580 DEBUGASSERT(!outs.filename); 581 } 582 else { 583 if(config->resume_from_current) { 584 /* We're told to continue from where we are now. Get the size 585 of the file as it is now and open it for append instead */ 586 struct_stat fileinfo; 587 /* VMS -- Danger, the filesize is only valid for stream files */ 588 if(0 == stat(outfile, &fileinfo)) 589 /* set offset to current file size: */ 590 config->resume_from = fileinfo.st_size; 591 else 592 /* let offset be 0 */ 593 config->resume_from = 0; 594 } 595 596 if(config->resume_from) { 597 /* open file for output: */ 598 FILE *file = fopen(outfile, config->resume_from?"ab":"wb"); 599 if(!file) { 600 helpf(config->errors, "Can't open '%s'!\n", outfile); 601 res = CURLE_WRITE_ERROR; 602 goto quit_urls; 603 } 604 outs.fopened = TRUE; 605 outs.stream = file; 606 outs.init = config->resume_from; 607 } 608 else { 609 outs.stream = NULL; /* open when needed */ 610 } 611 outs.filename = outfile; 612 outs.s_isreg = TRUE; 613 } 614 } 615 616 if(uploadfile && !stdin_upload(uploadfile)) { 617 /* 618 * We have specified a file to upload and it isn't "-". 619 */ 620 struct_stat fileinfo; 621 622 this_url = add_file_name_to_url(curl, this_url, uploadfile); 623 if(!this_url) { 624 res = CURLE_OUT_OF_MEMORY; 625 goto show_error; 626 } 627 /* VMS Note: 628 * 629 * Reading binary from files can be a problem... Only FIXED, VAR 630 * etc WITHOUT implied CC will work Others need a \n appended to a 631 * line 632 * 633 * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a 634 * fixed file with implied CC needs to have a byte added for every 635 * record processed, this can by derived from Filesize & recordsize 636 * for VARiable record files the records need to be counted! for 637 * every record add 1 for linefeed and subtract 2 for the record 638 * header for VARIABLE header files only the bare record data needs 639 * to be considered with one appended if implied CC 640 */ 641 642 infd = open(uploadfile, O_RDONLY | O_BINARY); 643 if((infd == -1) || fstat(infd, &fileinfo)) { 644 helpf(config->errors, "Can't open '%s'!\n", uploadfile); 645 if(infd != -1) { 646 close(infd); 647 infd = STDIN_FILENO; 648 } 649 res = CURLE_READ_ERROR; 650 goto quit_urls; 651 } 652 infdopen = TRUE; 653 654 /* we ignore file size for char/block devices, sockets, etc. */ 655 if(S_ISREG(fileinfo.st_mode)) 656 uploadfilesize = fileinfo.st_size; 657 658 } 659 else if(uploadfile && stdin_upload(uploadfile)) { 660 /* count to see if there are more than one auth bit set 661 in the authtype field */ 662 int authbits = 0; 663 int bitcheck = 0; 664 while(bitcheck < 32) { 665 if(config->authtype & (1 << bitcheck++)) { 666 authbits++; 667 if(authbits > 1) { 668 /* more than one, we're done! */ 669 break; 670 } 671 } 672 } 673 674 /* 675 * If the user has also selected --anyauth or --proxy-anyauth 676 * we should warn him/her. 677 */ 678 if(config->proxyanyauth || (authbits>1)) { 679 warnf(config, 680 "Using --anyauth or --proxy-anyauth with upload from stdin" 681 " involves a big risk of it not working. Use a temporary" 682 " file or a fixed auth type instead!\n"); 683 } 684 685 DEBUGASSERT(infdopen == FALSE); 686 DEBUGASSERT(infd == STDIN_FILENO); 687 688 set_binmode(stdin); 689 if(curlx_strequal(uploadfile, ".")) { 690 if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0) 691 warnf(config, 692 "fcntl failed on fd=%d: %s\n", infd, strerror(errno)); 693 } 694 } 695 696 if(uploadfile && config->resume_from_current) 697 config->resume_from = -1; /* -1 will then force get-it-yourself */ 698 699 if(output_expected(this_url, uploadfile) 700 && outs.stream && isatty(fileno(outs.stream))) 701 /* we send the output to a tty, therefore we switch off the progress 702 meter */ 703 config->noprogress = config->isatty = TRUE; 704 705 if(urlnum > 1 && !(config->mute)) { 706 fprintf(config->errors, "\n[%d/%d]: %s --> %s\n", 707 i+1, urlnum, this_url, outfile ? outfile : "<stdout>"); 708 if(separator) 709 printf("%s%s\n", CURLseparator, this_url); 710 } 711 if(httpgetfields) { 712 char *urlbuffer; 713 /* Find out whether the url contains a file name */ 714 const char *pc = strstr(this_url, "://"); 715 char sep = '?'; 716 if(pc) 717 pc += 3; 718 else 719 pc = this_url; 720 721 pc = strrchr(pc, '/'); /* check for a slash */ 722 723 if(pc) { 724 /* there is a slash present in the URL */ 725 726 if(strchr(pc, '?')) 727 /* Ouch, there's already a question mark in the URL string, we 728 then append the data with an ampersand separator instead! */ 729 sep='&'; 730 } 731 /* 732 * Then append ? followed by the get fields to the url. 733 */ 734 urlbuffer = malloc(strlen(this_url) + strlen(httpgetfields) + 3); 735 if(!urlbuffer) { 736 res = CURLE_OUT_OF_MEMORY; 737 goto show_error; 738 } 739 if(pc) 740 sprintf(urlbuffer, "%s%c%s", this_url, sep, httpgetfields); 741 else 742 /* Append / before the ? to create a well-formed url 743 if the url contains a hostname only 744 */ 745 sprintf(urlbuffer, "%s/?%s", this_url, httpgetfields); 746 747 Curl_safefree(this_url); /* free previous URL */ 748 this_url = urlbuffer; /* use our new URL instead! */ 749 } 750 751 if(!config->errors) 752 config->errors = stderr; 753 754 if((!outfile || !strcmp(outfile, "-")) && !config->use_ascii) { 755 /* We get the output to stdout and we have not got the ASCII/text 756 flag, then set stdout to be binary */ 757 set_binmode(stdout); 758 } 759 760 if(config->tcp_nodelay) 761 my_setopt(curl, CURLOPT_TCP_NODELAY, 1); 762 763 /* where to store */ 764 my_setopt(curl, CURLOPT_WRITEDATA, &outs); 765 /* what call to write */ 766 my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb); 767 768 /* for uploads */ 769 input.fd = infd; 770 input.config = config; 771 my_setopt(curl, CURLOPT_READDATA, &input); 772 /* what call to read */ 773 if((outfile && !curlx_strequal("-", outfile)) || 774 !checkprefix("telnet:", this_url)) 775 my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb); 776 777 /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what 778 CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */ 779 my_setopt(curl, CURLOPT_SEEKDATA, &input); 780 my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb); 781 782 if(config->recvpersecond) 783 /* tell libcurl to use a smaller sized buffer as it allows us to 784 make better sleeps! 7.9.9 stuff! */ 785 my_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond); 786 787 /* size of uploaded file: */ 788 if(uploadfilesize != -1) 789 my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize); 790 my_setopt_str(curl, CURLOPT_URL, this_url); /* what to fetch */ 791 my_setopt(curl, CURLOPT_NOPROGRESS, config->noprogress); 792 if(config->no_body) { 793 my_setopt(curl, CURLOPT_NOBODY, 1); 794 my_setopt(curl, CURLOPT_HEADER, 1); 795 } 796 else 797 my_setopt(curl, CURLOPT_HEADER, config->include_headers); 798 799#if !defined(CURL_DISABLE_PROXY) 800 { 801 /* TODO: Make this a run-time check instead of compile-time one. */ 802 803 my_setopt_str(curl, CURLOPT_PROXY, config->proxy); 804 my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd); 805 806 /* new in libcurl 7.3 */ 807 my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel); 808 809 /* new in libcurl 7.5 */ 810 if(config->proxy) 811 my_setopt(curl, CURLOPT_PROXYTYPE, config->proxyver); 812 813 /* new in libcurl 7.10 */ 814 if(config->socksproxy) { 815 my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy); 816 my_setopt(curl, CURLOPT_PROXYTYPE, config->socksver); 817 } 818 819 /* new in libcurl 7.10.6 */ 820 if(config->proxyanyauth) 821 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY); 822 else if(config->proxynegotiate) 823 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE); 824 else if(config->proxyntlm) 825 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM); 826 else if(config->proxydigest) 827 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST); 828 else if(config->proxybasic) 829 my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC); 830 831 /* new in libcurl 7.19.4 */ 832 my_setopt(curl, CURLOPT_NOPROXY, config->noproxy); 833 } 834#endif 835 836 my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror); 837 my_setopt(curl, CURLOPT_UPLOAD, uploadfile?TRUE:FALSE); 838 my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly); 839 my_setopt(curl, CURLOPT_APPEND, config->ftp_append); 840 841 if(config->netrc_opt) 842 my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); 843 else if(config->netrc || config->netrc_file) 844 my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED); 845 else 846 my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED); 847 848 if(config->netrc_file) 849 my_setopt(curl, CURLOPT_NETRC_FILE, config->netrc_file); 850 851 my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii); 852 my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd); 853 my_setopt_str(curl, CURLOPT_RANGE, config->range); 854 my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer); 855 my_setopt(curl, CURLOPT_TIMEOUT, config->timeout); 856 857 if(built_in_protos & CURLPROTO_HTTP) { 858 859 my_setopt(curl, CURLOPT_FOLLOWLOCATION, 860 config->followlocation); 861 my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, 862 config->unrestricted_auth); 863 864 switch(config->httpreq) { 865 case HTTPREQ_SIMPLEPOST: 866 my_setopt_str(curl, CURLOPT_POSTFIELDS, 867 config->postfields); 868 my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, 869 config->postfieldsize); 870 break; 871 case HTTPREQ_POST: 872 my_setopt(curl, CURLOPT_HTTPPOST, config->httppost); 873 break; 874 default: 875 break; 876 } 877 878 my_setopt_str(curl, CURLOPT_REFERER, config->referer); 879 my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer); 880 my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent); 881 my_setopt(curl, CURLOPT_HTTPHEADER, config->headers); 882 883 /* new in libcurl 7.5 */ 884 my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs); 885 886 /* new in libcurl 7.9.1 */ 887 if(config->httpversion) 888 my_setopt(curl, CURLOPT_HTTP_VERSION, config->httpversion); 889 890 /* new in libcurl 7.10.6 (default is Basic) */ 891 if(config->authtype) 892 my_setopt(curl, CURLOPT_HTTPAUTH, config->authtype); 893 894 /* curl 7.19.1 (the 301 version existed in 7.18.2) */ 895 my_setopt(curl, CURLOPT_POSTREDIR, config->post301 | 896 (config->post302 ? CURL_REDIR_POST_302 : FALSE)); 897 898 /* new in libcurl 7.21.6 */ 899 if(config->encoding) 900 my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, ""); 901 902 /* new in libcurl 7.21.6 */ 903 if(config->tr_encoding) 904 my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1); 905 906 } /* (built_in_protos & CURLPROTO_HTTP) */ 907 908 my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport); 909 my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 910 config->low_speed_limit); 911 my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time); 912 my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, 913 config->sendpersecond); 914 my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, 915 config->recvpersecond); 916 my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, 917 config->use_resume?config->resume_from:0); 918 919 my_setopt(curl, CURLOPT_SSLCERT, config->cert); 920 my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type); 921 my_setopt(curl, CURLOPT_SSLKEY, config->key); 922 my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type); 923 my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd); 924 925 if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) { 926 927 /* SSH and SSL private key uses same command-line option */ 928 /* new in libcurl 7.16.1 */ 929 my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key); 930 /* new in libcurl 7.16.1 */ 931 my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey); 932 933 /* new in libcurl 7.17.1: SSH host key md5 checking allows us 934 to fail if we are not talking to who we think we should */ 935 my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, 936 config->hostpubmd5); 937 } 938 939 if(config->cacert) 940 my_setopt_str(curl, CURLOPT_CAINFO, config->cacert); 941 if(config->capath) 942 my_setopt_str(curl, CURLOPT_CAPATH, config->capath); 943 if(config->crlfile) 944 my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile); 945 946 if(curlinfo->features & CURL_VERSION_SSL) { 947 if(config->insecure_ok) { 948 my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 949 my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L); 950 } 951 else { 952 my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); 953 /* libcurl default is strict verifyhost -> 2L */ 954 /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */ 955 } 956 } 957 958 if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) { 959 if(!config->insecure_ok) { 960 char *home; 961 char *file; 962 res = CURLE_OUT_OF_MEMORY; 963 home = homedir(); 964 if(home) { 965 file = aprintf("%s/%sssh/known_hosts", home, DOT_CHAR); 966 if(file) { 967 /* new in curl 7.19.6 */ 968 res = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file); 969 curl_free(file); 970 if(res == CURLE_UNKNOWN_OPTION) 971 /* libssh2 version older than 1.1.1 */ 972 res = CURLE_OK; 973 } 974 Curl_safefree(home); 975 } 976 if(res) 977 goto show_error; 978 } 979 } 980 981 if(config->no_body || config->remote_time) { 982 /* no body or use remote time */ 983 my_setopt(curl, CURLOPT_FILETIME, TRUE); 984 } 985 986 my_setopt(curl, CURLOPT_CRLF, config->crlf); 987 my_setopt(curl, CURLOPT_QUOTE, config->quote); 988 my_setopt(curl, CURLOPT_POSTQUOTE, config->postquote); 989 my_setopt(curl, CURLOPT_PREQUOTE, config->prequote); 990 991#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) 992 { 993 /* TODO: Make this a run-time check instead of compile-time one. */ 994 995 if(config->cookie) 996 my_setopt_str(curl, CURLOPT_COOKIE, config->cookie); 997 998 if(config->cookiefile) 999 my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile); 1000 1001 /* new in libcurl 7.9 */ 1002 if(config->cookiejar) 1003 my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar); 1004 1005 /* new in libcurl 7.9.7 */ 1006 my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession); 1007 } 1008#endif 1009 1010 my_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version); 1011 my_setopt(curl, CURLOPT_TIMECONDITION, config->timecond); 1012 my_setopt(curl, CURLOPT_TIMEVALUE, config->condtime); 1013 my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest); 1014 my_setopt(curl, CURLOPT_STDERR, config->errors); 1015 1016 /* three new ones in libcurl 7.3: */ 1017 my_setopt_str(curl, CURLOPT_INTERFACE, config->iface); 1018 my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel); 1019 1020 progressbarinit(&progressbar, config); 1021 if((config->progressmode == CURL_PROGRESS_BAR) && 1022 !config->noprogress && !config->mute) { 1023 /* we want the alternative style, then we have to implement it 1024 ourselves! */ 1025 my_setopt(curl, CURLOPT_PROGRESSFUNCTION, tool_progress_cb); 1026 my_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar); 1027 } 1028 1029 /* new in libcurl 7.6.2: */ 1030 my_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options); 1031 1032 /* new in libcurl 7.7: */ 1033 my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file); 1034 my_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file); 1035 my_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout); 1036 1037 if(config->cipher_list) 1038 my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list); 1039 1040 /* new in libcurl 7.9.2: */ 1041 if(config->disable_epsv) 1042 /* disable it */ 1043 my_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE); 1044 1045 /* new in libcurl 7.10.5 */ 1046 if(config->disable_eprt) 1047 /* disable it */ 1048 my_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE); 1049 1050 if(config->tracetype != TRACE_NONE) { 1051 my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb); 1052 my_setopt(curl, CURLOPT_DEBUGDATA, config); 1053 my_setopt(curl, CURLOPT_VERBOSE, TRUE); 1054 } 1055 1056 /* new in curl 7.9.3 */ 1057 if(config->engine) { 1058 res = res_setopt_str(curl, CURLOPT_SSLENGINE, config->engine); 1059 if(res) 1060 goto show_error; 1061 my_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1); 1062 } 1063 1064 /* new in curl 7.10.7, extended in 7.19.4 but this only sets 0 or 1 */ 1065 my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, 1066 config->ftp_create_dirs); 1067 1068 /* new in curl 7.10.8 */ 1069 if(config->max_filesize) 1070 my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE, 1071 config->max_filesize); 1072 1073 if(4 == config->ip_version) 1074 my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); 1075 else if(6 == config->ip_version) 1076 my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); 1077 else 1078 my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER); 1079 1080 /* new in curl 7.15.5 */ 1081 if(config->ftp_ssl_reqd) 1082 my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); 1083 1084 /* new in curl 7.11.0 */ 1085 else if(config->ftp_ssl) 1086 my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY); 1087 1088 /* new in curl 7.16.0 */ 1089 else if(config->ftp_ssl_control) 1090 my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL); 1091 1092 /* new in curl 7.16.1 */ 1093 if(config->ftp_ssl_ccc) 1094 my_setopt(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode); 1095 1096#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) 1097 { 1098 /* TODO: Make this a run-time check instead of compile-time one. */ 1099 1100 /* new in curl 7.19.4 */ 1101 if(config->socks5_gssapi_service) 1102 my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE, 1103 config->socks5_gssapi_service); 1104 1105 /* new in curl 7.19.4 */ 1106 if(config->socks5_gssapi_nec) 1107 my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC, 1108 config->socks5_gssapi_nec); 1109 } 1110#endif 1111 /* curl 7.13.0 */ 1112 my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account); 1113 1114 my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl); 1115 1116 /* curl 7.14.2 */ 1117 my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip); 1118 1119 /* curl 7.15.1 */ 1120 my_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod); 1121 1122 /* curl 7.15.2 */ 1123 if(config->localport) { 1124 my_setopt(curl, CURLOPT_LOCALPORT, config->localport); 1125 my_setopt_str(curl, CURLOPT_LOCALPORTRANGE, 1126 config->localportrange); 1127 } 1128 1129 /* curl 7.15.5 */ 1130 my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER, 1131 config->ftp_alternative_to_user); 1132 1133 /* curl 7.16.0 */ 1134 if(config->disable_sessionid) 1135 my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 1136 !config->disable_sessionid); 1137 1138 /* curl 7.16.2 */ 1139 if(config->raw) { 1140 my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, FALSE); 1141 my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, FALSE); 1142 } 1143 1144 /* curl 7.17.1 */ 1145 if(!config->nokeepalive) { 1146 my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, tool_sockopt_cb); 1147 my_setopt(curl, CURLOPT_SOCKOPTDATA, config); 1148 } 1149 1150 /* curl 7.20.0 */ 1151 if(config->tftp_blksize) 1152 my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize); 1153 1154 if(config->mail_from) 1155 my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from); 1156 1157 if(config->mail_rcpt) 1158 my_setopt(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt); 1159 1160 /* curl 7.20.x */ 1161 if(config->ftp_pret) 1162 my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE); 1163 1164 if(config->proto_present) 1165 my_setopt(curl, CURLOPT_PROTOCOLS, config->proto); 1166 if(config->proto_redir_present) 1167 my_setopt(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir); 1168 1169 if((urlnode->flags & GETOUT_USEREMOTE) 1170 && config->content_disposition) { 1171 my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb); 1172 my_setopt(curl, CURLOPT_HEADERDATA, &outs); 1173 } 1174 else { 1175 /* if HEADERFUNCTION was set to something in the previous loop, it 1176 is important that we set it (back) to NULL now */ 1177 my_setopt(curl, CURLOPT_HEADERFUNCTION, NULL); 1178 my_setopt(curl, CURLOPT_HEADERDATA, config->headerfile?&heads:NULL); 1179 } 1180 1181 if(config->resolve) 1182 /* new in 7.21.3 */ 1183 my_setopt(curl, CURLOPT_RESOLVE, config->resolve); 1184 1185 /* new in 7.21.4 */ 1186 if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { 1187 if(config->tls_username) 1188 my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME, 1189 config->tls_username); 1190 if(config->tls_password) 1191 my_setopt_str(curl, CURLOPT_TLSAUTH_PASSWORD, 1192 config->tls_password); 1193 if(config->tls_authtype) 1194 my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE, 1195 config->tls_authtype); 1196 } 1197 1198 /* new in 7.22.0 */ 1199 if(config->gssapi_delegation) 1200 my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION, 1201 config->gssapi_delegation); 1202 1203 /* initialize retry vars for loop below */ 1204 retry_sleep_default = (config->retry_delay) ? 1205 config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */ 1206 1207 retry_numretries = config->req_retry; 1208 retry_sleep = retry_sleep_default; /* ms */ 1209 retrystart = tvnow(); 1210 1211 if(!curl_slist_append(easysrc, "ret = curl_easy_perform(hnd);")) { 1212 res = CURLE_OUT_OF_MEMORY; 1213 goto show_error; 1214 } 1215 1216 for(;;) { 1217 res = curl_easy_perform(curl); 1218 1219 if(config->content_disposition && outs.stream && !config->mute && 1220 outs.filename) 1221 printf("curl: Saved to filename '%s'\n", outs.filename); 1222 1223 /* if retry-max-time is non-zero, make sure we haven't exceeded the 1224 time */ 1225 if(retry_numretries && 1226 (!config->retry_maxtime || 1227 (tvdiff(tvnow(), retrystart) < 1228 config->retry_maxtime*1000L)) ) { 1229 enum { 1230 RETRY_NO, 1231 RETRY_TIMEOUT, 1232 RETRY_HTTP, 1233 RETRY_FTP, 1234 RETRY_LAST /* not used */ 1235 } retry = RETRY_NO; 1236 long response; 1237 if(CURLE_OPERATION_TIMEDOUT == res) 1238 /* retry timeout always */ 1239 retry = RETRY_TIMEOUT; 1240 else if((CURLE_OK == res) || 1241 (config->failonerror && 1242 (CURLE_HTTP_RETURNED_ERROR == res))) { 1243 /* If it returned OK. _or_ failonerror was enabled and it 1244 returned due to such an error, check for HTTP transient 1245 errors to retry on. */ 1246 char *effective_url = NULL; 1247 curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url); 1248 if(effective_url && 1249 checkprefix("http", effective_url)) { 1250 /* This was HTTP(S) */ 1251 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); 1252 1253 switch(response) { 1254 case 500: /* Internal Server Error */ 1255 case 502: /* Bad Gateway */ 1256 case 503: /* Service Unavailable */ 1257 case 504: /* Gateway Timeout */ 1258 retry = RETRY_HTTP; 1259 /* 1260 * At this point, we have already written data to the output 1261 * file (or terminal). If we write to a file, we must rewind 1262 * or close/re-open the file so that the next attempt starts 1263 * over from the beginning. 1264 * 1265 * TODO: similar action for the upload case. We might need 1266 * to start over reading from a previous point if we have 1267 * uploaded something when this was returned. 1268 */ 1269 break; 1270 } 1271 } 1272 } /* if CURLE_OK */ 1273 else if(res) { 1274 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); 1275 1276 if(response/100 == 4) 1277 /* 1278 * This is typically when the FTP server only allows a certain 1279 * amount of users and we are not one of them. All 4xx codes 1280 * are transient. 1281 */ 1282 retry = RETRY_FTP; 1283 } 1284 1285 if(retry) { 1286 static const char * const m[]={ 1287 NULL, "timeout", "HTTP error", "FTP error" 1288 }; 1289 warnf(config, "Transient problem: %s " 1290 "Will retry in %ld seconds. " 1291 "%ld retries left.\n", 1292 m[retry], retry_sleep/1000L, retry_numretries); 1293 1294 tool_go_sleep(retry_sleep); 1295 retry_numretries--; 1296 if(!config->retry_delay) { 1297 retry_sleep *= 2; 1298 if(retry_sleep > RETRY_SLEEP_MAX) 1299 retry_sleep = RETRY_SLEEP_MAX; 1300 } 1301 if(outs.bytes && outs.filename) { 1302 /* We have written data to a output file, we truncate file 1303 */ 1304 if(!config->mute) 1305 fprintf(config->errors, "Throwing away %" 1306 CURL_FORMAT_CURL_OFF_T " bytes\n", 1307 outs.bytes); 1308 fflush(outs.stream); 1309 /* truncate file at the position where we started appending */ 1310#ifdef HAVE_FTRUNCATE 1311 if(ftruncate( fileno(outs.stream), outs.init)) { 1312 /* when truncate fails, we can't just append as then we'll 1313 create something strange, bail out */ 1314 if(!config->mute) 1315 fprintf(config->errors, 1316 "failed to truncate, exiting\n"); 1317 res = CURLE_WRITE_ERROR; 1318 goto quit_urls; 1319 } 1320 /* now seek to the end of the file, the position where we 1321 just truncated the file in a large file-safe way */ 1322 fseek(outs.stream, 0, SEEK_END); 1323#else 1324 /* ftruncate is not available, so just reposition the file 1325 to the location we would have truncated it. This won't 1326 work properly with large files on 32-bit systems, but 1327 most of those will have ftruncate. */ 1328 fseek(outs.stream, (long)outs.init, SEEK_SET); 1329#endif 1330 outs.bytes = 0; /* clear for next round */ 1331 } 1332 continue; /* curl_easy_perform loop */ 1333 } 1334 } /* if retry_numretries */ 1335 1336 /* In all ordinary cases, just break out of loop here */ 1337 break; /* curl_easy_perform loop */ 1338 1339 } 1340 1341 if((config->progressmode == CURL_PROGRESS_BAR) && 1342 progressbar.calls) 1343 /* if the custom progress bar has been displayed, we output a 1344 newline here */ 1345 fputs("\n", progressbar.out); 1346 1347 if(config->writeout) 1348 ourWriteOut(curl, config->writeout); 1349 1350 if(config->writeenv) 1351 ourWriteEnv(curl); 1352 1353 /* 1354 ** Code within this loop may jump directly here to label 'show_error' 1355 ** in order to display an error message for CURLcode stored in 'res' 1356 ** variable and exit loop once that necessary writing and cleanup 1357 ** in label 'quit_urls' has been done. 1358 */ 1359 1360 show_error: 1361 1362#ifdef __VMS 1363 if(is_vms_shell()) { 1364 /* VMS DCL shell behavior */ 1365 if(!config->showerror) 1366 vms_show = VMSSTS_HIDE; 1367 } 1368 else 1369#endif 1370 if(res && config->showerror) { 1371 fprintf(config->errors, "curl: (%d) %s\n", res, (errorbuffer[0]) ? 1372 errorbuffer : curl_easy_strerror((CURLcode)res)); 1373 if(res == CURLE_SSL_CACERT) 1374 fprintf(config->errors, "%s%s", 1375 CURL_CA_CERT_ERRORMSG1, CURL_CA_CERT_ERRORMSG2); 1376 } 1377 1378 /* Fall through comment to 'quit_urls' label */ 1379 1380 /* 1381 ** Upon error condition and always that a message has already been 1382 ** displayed, code within this loop may jump directly here to label 1383 ** 'quit_urls' otherwise it should jump to 'show_error' label above. 1384 ** 1385 ** When 'res' variable is _not_ CURLE_OK loop will exit once that 1386 ** all code following 'quit_urls' has been executed. Otherwise it 1387 ** will loop to the beginning from where it may exit if there are 1388 ** no more urls left. 1389 */ 1390 1391 quit_urls: 1392 1393 /* Set file extended attributes */ 1394 if(!res && config->xattr && outs.fopened && outs.stream) { 1395 int rc = fwrite_xattr(curl, fileno(outs.stream)); 1396 if(rc) 1397 warnf(config, "Error setting extended attributes: %s\n", 1398 strerror(errno)); 1399 } 1400 1401 /* Close the file */ 1402 if(outs.fopened && outs.stream) { 1403 int rc = fclose(outs.stream); 1404 if(!res && rc) { 1405 /* something went wrong in the writing process */ 1406 res = CURLE_WRITE_ERROR; 1407 fprintf(config->errors, "(%d) Failed writing body\n", res); 1408 } 1409 } 1410 else if(!outs.s_isreg && outs.stream) { 1411 /* Dump standard stream buffered data */ 1412 int rc = fflush(outs.stream); 1413 if(!res && rc) { 1414 /* something went wrong in the writing process */ 1415 res = CURLE_WRITE_ERROR; 1416 fprintf(config->errors, "(%d) Failed writing body\n", res); 1417 } 1418 } 1419 1420#ifdef __AMIGA__ 1421 if(!res && outs.s_isreg && outs.filename) { 1422 /* Set the url (up to 80 chars) as comment for the file */ 1423 if(strlen(url) > 78) 1424 url[79] = '\0'; 1425 SetComment(outs.filename, url); 1426 } 1427#endif 1428 1429#ifdef HAVE_UTIME 1430 /* File time can only be set _after_ the file has been closed */ 1431 if(!res && config->remote_time && outs.s_isreg && outs.filename) { 1432 /* Ask libcurl if we got a remote file time */ 1433 long filetime = -1; 1434 curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime); 1435 if(filetime >= 0) { 1436 struct utimbuf times; 1437 times.actime = (time_t)filetime; 1438 times.modtime = (time_t)filetime; 1439 utime(outs.filename, ×); /* set the time we got */ 1440 } 1441 } 1442#endif 1443 /* No more business with this output struct */ 1444 if(outs.alloc_filename) 1445 Curl_safefree(outs.filename); 1446 memset(&outs, 0, sizeof(struct OutStruct)); 1447 1448 /* Free loop-local allocated memory and close loop-local opened fd */ 1449 1450 Curl_safefree(outfile); 1451 Curl_safefree(this_url); 1452 1453 if(infdopen) { 1454 close(infd); 1455 infdopen = FALSE; 1456 infd = STDIN_FILENO; 1457 } 1458 1459 /* upon error exit loop */ 1460 if(res) 1461 break; 1462 1463 } /* loop to the next URL */ 1464 1465 /* Free loop-local allocated memory */ 1466 1467 Curl_safefree(uploadfile); 1468 1469 if(urls) { 1470 /* Free list of remaining URLs */ 1471 glob_cleanup(urls); 1472 urls = NULL; 1473 } 1474 1475 /* upon error exit loop */ 1476 if(res) 1477 break; 1478 1479 } /* loop to the next globbed upload file */ 1480 1481 /* Free loop-local allocated memory */ 1482 1483 Curl_safefree(outfiles); 1484 1485 if(inglob) { 1486 /* Free list of globbed upload files */ 1487 glob_cleanup(inglob); 1488 inglob = NULL; 1489 } 1490 1491 /* Free this URL node data without destroying the 1492 the node itself nor modifying next pointer. */ 1493 Curl_safefree(urlnode->url); 1494 Curl_safefree(urlnode->outfile); 1495 Curl_safefree(urlnode->infile); 1496 urlnode->flags = 0; 1497 1498 /* TODO: Should CURLE_SSL_CACERT be included as critical error ? */ 1499 1500 /* 1501 ** Bail out upon critical errors 1502 */ 1503 switch(res) { 1504 case CURLE_FAILED_INIT: 1505 case CURLE_OUT_OF_MEMORY: 1506 case CURLE_FUNCTION_NOT_FOUND: 1507 case CURLE_BAD_FUNCTION_ARGUMENT: 1508 goto quit_curl; 1509 default: 1510 /* Merrily loop to next URL */ 1511 break; 1512 } 1513 1514 } /* for-loop through all URLs */ 1515 1516 /* 1517 ** Nested loops end here. 1518 */ 1519 1520 quit_curl: 1521 1522 /* Free function-local referenced allocated memory */ 1523 Curl_safefree(httpgetfields); 1524 1525 /* Free list of given URLs */ 1526 clean_getout(config); 1527 1528 /* Cleanup the curl handle now that our 1529 progressbar struct is still in scope */ 1530 if(curl) { 1531 curl_easy_cleanup(curl); 1532 config->easy = curl = NULL; 1533 } 1534 if(easysrc) 1535 curl_slist_append(easysrc, "curl_easy_cleanup(hnd);"); 1536 1537 /* Close function-local opened file descriptors */ 1538 1539 if(heads.fopened && heads.stream) 1540 fclose(heads.stream); 1541 if(heads.alloc_filename) 1542 Curl_safefree(heads.filename); 1543 1544 if(config->trace_fopened && config->trace_stream) 1545 fclose(config->trace_stream); 1546 1547 /* Dump the libcurl code if previously enabled. 1548 NOTE: that this function relies on config->errors amongst other things 1549 so not everything can be closed and cleaned before this is called */ 1550 dumpeasysrc(config); 1551 1552 if(config->errors_fopened && config->errors) 1553 fclose(config->errors); 1554 1555 main_free(); /* cleanup */ 1556 1557 return res; 1558} 1559 1560