Home | History | Annotate | Download | only in src
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2017, 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 #include "tool_setup.h"
     23 
     24 #ifdef HAVE_FCNTL_H
     25 #  include <fcntl.h>
     26 #endif
     27 
     28 #ifdef HAVE_UTIME_H
     29 #  include <utime.h>
     30 #elif defined(HAVE_SYS_UTIME_H)
     31 #  include <sys/utime.h>
     32 #endif
     33 
     34 #ifdef HAVE_LOCALE_H
     35 #  include <locale.h>
     36 #endif
     37 
     38 #ifdef __VMS
     39 #  include <fabdef.h>
     40 #endif
     41 
     42 #include "strcase.h"
     43 
     44 #define ENABLE_CURLX_PRINTF
     45 /* use our own printf() functions */
     46 #include "curlx.h"
     47 
     48 #include "tool_binmode.h"
     49 #include "tool_cfgable.h"
     50 #include "tool_cb_dbg.h"
     51 #include "tool_cb_hdr.h"
     52 #include "tool_cb_prg.h"
     53 #include "tool_cb_rea.h"
     54 #include "tool_cb_see.h"
     55 #include "tool_cb_wrt.h"
     56 #include "tool_dirhie.h"
     57 #include "tool_doswin.h"
     58 #include "tool_easysrc.h"
     59 #include "tool_getparam.h"
     60 #include "tool_helpers.h"
     61 #include "tool_homedir.h"
     62 #include "tool_libinfo.h"
     63 #include "tool_main.h"
     64 #include "tool_metalink.h"
     65 #include "tool_msgs.h"
     66 #include "tool_operate.h"
     67 #include "tool_operhlp.h"
     68 #include "tool_paramhlp.h"
     69 #include "tool_parsecfg.h"
     70 #include "tool_setopt.h"
     71 #include "tool_sleep.h"
     72 #include "tool_urlglob.h"
     73 #include "tool_util.h"
     74 #include "tool_writeout.h"
     75 #include "tool_xattr.h"
     76 #include "tool_vms.h"
     77 #include "tool_help.h"
     78 #include "tool_hugehelp.h"
     79 
     80 #include "memdebug.h" /* keep this as LAST include */
     81 
     82 #ifdef CURLDEBUG
     83 /* libcurl's debug builds provide an extra function */
     84 CURLcode curl_easy_perform_ev(CURL *easy);
     85 #endif
     86 
     87 #define CURLseparator  "--_curl_--"
     88 
     89 #ifndef O_BINARY
     90 /* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
     91    source code but yet it doesn't ruin anything */
     92 #  define O_BINARY 0
     93 #endif
     94 
     95 #define CURL_CA_CERT_ERRORMSG                                               \
     96   "More details here: https://curl.haxx.se/docs/sslcerts.html\n\n"          \
     97   "curl failed to verify the legitimacy of the server and therefore "       \
     98   "could not\nestablish a secure connection to it. To learn more about "    \
     99   "this situation and\nhow to fix it, please visit the web page mentioned " \
    100   "above.\n"
    101 
    102 static bool is_fatal_error(CURLcode code)
    103 {
    104   switch(code) {
    105   /* TODO: Should CURLE_SSL_CACERT be included as critical error ? */
    106   case CURLE_FAILED_INIT:
    107   case CURLE_OUT_OF_MEMORY:
    108   case CURLE_UNKNOWN_OPTION:
    109   case CURLE_FUNCTION_NOT_FOUND:
    110   case CURLE_BAD_FUNCTION_ARGUMENT:
    111     /* critical error */
    112     return TRUE;
    113   default:
    114     break;
    115   }
    116 
    117   /* no error or not critical */
    118   return FALSE;
    119 }
    120 
    121 #ifdef __VMS
    122 /*
    123  * get_vms_file_size does what it takes to get the real size of the file
    124  *
    125  * For fixed files, find out the size of the EOF block and adjust.
    126  *
    127  * For all others, have to read the entire file in, discarding the contents.
    128  * Most posted text files will be small, and binary files like zlib archives
    129  * and CD/DVD images should be either a STREAM_LF format or a fixed format.
    130  *
    131  */
    132 static curl_off_t vms_realfilesize(const char *name,
    133                                    const struct_stat *stat_buf)
    134 {
    135   char buffer[8192];
    136   curl_off_t count;
    137   int ret_stat;
    138   FILE * file;
    139 
    140   /* !checksrc! disable FOPENMODE 1 */
    141   file = fopen(name, "r"); /* VMS */
    142   if(file == NULL) {
    143     return 0;
    144   }
    145   count = 0;
    146   ret_stat = 1;
    147   while(ret_stat > 0) {
    148     ret_stat = fread(buffer, 1, sizeof(buffer), file);
    149     if(ret_stat != 0)
    150       count += ret_stat;
    151   }
    152   fclose(file);
    153 
    154   return count;
    155 }
    156 
    157 /*
    158  *
    159  *  VmsSpecialSize checks to see if the stat st_size can be trusted and
    160  *  if not to call a routine to get the correct size.
    161  *
    162  */
    163 static curl_off_t VmsSpecialSize(const char *name,
    164                                  const struct_stat *stat_buf)
    165 {
    166   switch(stat_buf->st_fab_rfm) {
    167   case FAB$C_VAR:
    168   case FAB$C_VFC:
    169     return vms_realfilesize(name, stat_buf);
    170     break;
    171   default:
    172     return stat_buf->st_size;
    173   }
    174 }
    175 #endif /* __VMS */
    176 
    177 #if defined(HAVE_UTIME) || \
    178     (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8))
    179 static void setfiletime(long filetime, const char *filename,
    180                         FILE *error_stream)
    181 {
    182   if(filetime >= 0) {
    183 /* Windows utime() may attempt to adjust our unix gmt 'filetime' by a daylight
    184    saving time offset and since it's GMT that is bad behavior. When we have
    185    access to a 64-bit type we can bypass utime and set the times directly. */
    186 #if defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)
    187     HANDLE hfile;
    188 
    189 #if (SIZEOF_LONG >= 8)
    190     /* 910670515199 is the maximum unix filetime that can be used as a
    191        Windows FILETIME without overflow: 30827-12-31T23:59:59. */
    192     if(filetime > CURL_OFF_T_C(910670515199)) {
    193       fprintf(error_stream,
    194               "Failed to set filetime %ld on outfile: overflow\n",
    195               filetime);
    196       return;
    197     }
    198 #endif /* SIZEOF_LONG >= 8 */
    199 
    200     hfile = CreateFileA(filename, FILE_WRITE_ATTRIBUTES,
    201                         (FILE_SHARE_READ | FILE_SHARE_WRITE |
    202                          FILE_SHARE_DELETE),
    203                         NULL, OPEN_EXISTING, 0, NULL);
    204     if(hfile != INVALID_HANDLE_VALUE) {
    205       curl_off_t converted = ((curl_off_t)filetime * 10000000) +
    206                              CURL_OFF_T_C(116444736000000000);
    207       FILETIME ft;
    208       ft.dwLowDateTime = (DWORD)(converted & 0xFFFFFFFF);
    209       ft.dwHighDateTime = (DWORD)(converted >> 32);
    210       if(!SetFileTime(hfile, NULL, &ft, &ft)) {
    211         fprintf(error_stream,
    212                 "Failed to set filetime %ld on outfile: "
    213                 "SetFileTime failed: GetLastError %u\n",
    214                 filetime, GetLastError());
    215       }
    216       CloseHandle(hfile);
    217     }
    218     else {
    219       fprintf(error_stream,
    220               "Failed to set filetime %ld on outfile: "
    221               "CreateFile failed: GetLastError %u\n",
    222               filetime, GetLastError());
    223     }
    224 
    225 #elif defined(HAVE_UTIMES)
    226     struct timeval times[2];
    227     times[0].tv_sec = times[1].tv_sec = filetime;
    228     times[0].tv_usec = times[1].tv_usec = 0;
    229     if(utimes(filename, times)) {
    230       fprintf(error_stream,
    231               "Failed to set filetime %ld on outfile: errno %d\n",
    232               filetime, errno);
    233     }
    234 
    235 #elif defined(HAVE_UTIME)
    236     struct utimbuf times;
    237     times.actime = (time_t)filetime;
    238     times.modtime = (time_t)filetime;
    239     if(utime(filename, &times)) {
    240       fprintf(error_stream,
    241               "Failed to set filetime %ld on outfile: errno %d\n",
    242               filetime, errno);
    243     }
    244 #endif
    245   }
    246 }
    247 #endif /* defined(HAVE_UTIME) || \
    248           (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)) */
    249 
    250 #define BUFFER_SIZE (100*1024)
    251 
    252 static CURLcode operate_do(struct GlobalConfig *global,
    253                            struct OperationConfig *config)
    254 {
    255   char errorbuffer[CURL_ERROR_SIZE];
    256   struct ProgressData progressbar;
    257   struct getout *urlnode;
    258 
    259   struct HdrCbData hdrcbdata;
    260   struct OutStruct heads;
    261 
    262   metalinkfile *mlfile_last = NULL;
    263 
    264   CURL *curl = config->easy;
    265   char *httpgetfields = NULL;
    266 
    267   CURLcode result = CURLE_OK;
    268   unsigned long li;
    269   bool capath_from_env;
    270 
    271   /* Save the values of noprogress and isatty to restore them later on */
    272   bool orig_noprogress = global->noprogress;
    273   bool orig_isatty = global->isatty;
    274 
    275   errorbuffer[0] = '\0';
    276 
    277   /* default headers output stream is stdout */
    278   memset(&hdrcbdata, 0, sizeof(struct HdrCbData));
    279   memset(&heads, 0, sizeof(struct OutStruct));
    280   heads.stream = stdout;
    281   heads.config = config;
    282 
    283   /*
    284   ** Beyond this point no return'ing from this function allowed.
    285   ** Jump to label 'quit_curl' in order to abandon this function
    286   ** from outside of nested loops further down below.
    287   */
    288 
    289   /* Check we have a url */
    290   if(!config->url_list || !config->url_list->url) {
    291     helpf(global->errors, "no URL specified!\n");
    292     result = CURLE_FAILED_INIT;
    293     goto quit_curl;
    294   }
    295 
    296   /* On WIN32 we can't set the path to curl-ca-bundle.crt
    297    * at compile time. So we look here for the file in two ways:
    298    * 1: look at the environment variable CURL_CA_BUNDLE for a path
    299    * 2: if #1 isn't found, use the windows API function SearchPath()
    300    *    to find it along the app's path (includes app's dir and CWD)
    301    *
    302    * We support the environment variable thing for non-Windows platforms
    303    * too. Just for the sake of it.
    304    */
    305   capath_from_env = false;
    306   if(!config->cacert &&
    307      !config->capath &&
    308      !config->insecure_ok) {
    309     char *env;
    310     env = curlx_getenv("CURL_CA_BUNDLE");
    311     if(env) {
    312       config->cacert = strdup(env);
    313       if(!config->cacert) {
    314         curl_free(env);
    315         helpf(global->errors, "out of memory\n");
    316         result = CURLE_OUT_OF_MEMORY;
    317         goto quit_curl;
    318       }
    319     }
    320     else {
    321       env = curlx_getenv("SSL_CERT_DIR");
    322       if(env) {
    323         config->capath = strdup(env);
    324         if(!config->capath) {
    325           curl_free(env);
    326           helpf(global->errors, "out of memory\n");
    327           result = CURLE_OUT_OF_MEMORY;
    328           goto quit_curl;
    329         }
    330         capath_from_env = true;
    331       }
    332       else {
    333         env = curlx_getenv("SSL_CERT_FILE");
    334         if(env) {
    335           config->cacert = strdup(env);
    336           if(!config->cacert) {
    337             curl_free(env);
    338             helpf(global->errors, "out of memory\n");
    339             result = CURLE_OUT_OF_MEMORY;
    340             goto quit_curl;
    341           }
    342         }
    343       }
    344     }
    345 
    346     if(env)
    347       curl_free(env);
    348 #ifdef WIN32
    349     else {
    350       result = FindWin32CACert(config, "curl-ca-bundle.crt");
    351       if(result)
    352         goto quit_curl;
    353     }
    354 #endif
    355   }
    356 
    357   if(config->postfields) {
    358     if(config->use_httpget) {
    359       /* Use the postfields data for a http get */
    360       httpgetfields = strdup(config->postfields);
    361       Curl_safefree(config->postfields);
    362       if(!httpgetfields) {
    363         helpf(global->errors, "out of memory\n");
    364         result = CURLE_OUT_OF_MEMORY;
    365         goto quit_curl;
    366       }
    367       if(SetHTTPrequest(config,
    368                         (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
    369                         &config->httpreq)) {
    370         result = CURLE_FAILED_INIT;
    371         goto quit_curl;
    372       }
    373     }
    374     else {
    375       if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq)) {
    376         result = CURLE_FAILED_INIT;
    377         goto quit_curl;
    378       }
    379     }
    380   }
    381 
    382   /* Single header file for all URLs */
    383   if(config->headerfile) {
    384     /* open file for output: */
    385     if(strcmp(config->headerfile, "-")) {
    386       FILE *newfile = fopen(config->headerfile, "wb");
    387       if(!newfile) {
    388         warnf(config->global, "Failed to open %s\n", config->headerfile);
    389         result = CURLE_WRITE_ERROR;
    390         goto quit_curl;
    391       }
    392       else {
    393         heads.filename = config->headerfile;
    394         heads.s_isreg = TRUE;
    395         heads.fopened = TRUE;
    396         heads.stream = newfile;
    397       }
    398     }
    399     else {
    400       /* always use binary mode for protocol header output */
    401       set_binmode(heads.stream);
    402     }
    403   }
    404 
    405   /*
    406   ** Nested loops start here.
    407   */
    408 
    409   /* loop through the list of given URLs */
    410 
    411   for(urlnode = config->url_list; urlnode; urlnode = urlnode->next) {
    412 
    413     unsigned long up; /* upload file counter within a single upload glob */
    414     char *infiles; /* might be a glob pattern */
    415     char *outfiles;
    416     unsigned long infilenum;
    417     URLGlob *inglob;
    418 
    419     int metalink = 0; /* nonzero for metalink download. */
    420     metalinkfile *mlfile;
    421     metalink_resource *mlres;
    422 
    423     outfiles = NULL;
    424     infilenum = 1;
    425     inglob = NULL;
    426 
    427     if(urlnode->flags & GETOUT_METALINK) {
    428       metalink = 1;
    429       if(mlfile_last == NULL) {
    430         mlfile_last = config->metalinkfile_list;
    431       }
    432       mlfile = mlfile_last;
    433       mlfile_last = mlfile_last->next;
    434       mlres = mlfile->resource;
    435     }
    436     else {
    437       mlfile = NULL;
    438       mlres = NULL;
    439     }
    440 
    441     /* urlnode->url is the full URL (it might be NULL) */
    442 
    443     if(!urlnode->url) {
    444       /* This node has no URL. Free node data without destroying the
    445          node itself nor modifying next pointer and continue to next */
    446       Curl_safefree(urlnode->outfile);
    447       Curl_safefree(urlnode->infile);
    448       urlnode->flags = 0;
    449       continue; /* next URL please */
    450     }
    451 
    452     /* save outfile pattern before expansion */
    453     if(urlnode->outfile) {
    454       outfiles = strdup(urlnode->outfile);
    455       if(!outfiles) {
    456         helpf(global->errors, "out of memory\n");
    457         result = CURLE_OUT_OF_MEMORY;
    458         break;
    459       }
    460     }
    461 
    462     infiles = urlnode->infile;
    463 
    464     if(!config->globoff && infiles) {
    465       /* Unless explicitly shut off */
    466       result = glob_url(&inglob, infiles, &infilenum,
    467                         global->showerror?global->errors:NULL);
    468       if(result) {
    469         Curl_safefree(outfiles);
    470         break;
    471       }
    472     }
    473 
    474     /* Here's the loop for uploading multiple files within the same
    475        single globbed string. If no upload, we enter the loop once anyway. */
    476     for(up = 0 ; up < infilenum; up++) {
    477 
    478       char *uploadfile; /* a single file, never a glob */
    479       int separator;
    480       URLGlob *urls;
    481       unsigned long urlnum;
    482 
    483       uploadfile = NULL;
    484       urls = NULL;
    485       urlnum = 0;
    486 
    487       if(!up && !infiles)
    488         Curl_nop_stmt;
    489       else {
    490         if(inglob) {
    491           result = glob_next_url(&uploadfile, inglob);
    492           if(result == CURLE_OUT_OF_MEMORY)
    493             helpf(global->errors, "out of memory\n");
    494         }
    495         else if(!up) {
    496           uploadfile = strdup(infiles);
    497           if(!uploadfile) {
    498             helpf(global->errors, "out of memory\n");
    499             result = CURLE_OUT_OF_MEMORY;
    500           }
    501         }
    502         else
    503           uploadfile = NULL;
    504         if(!uploadfile)
    505           break;
    506       }
    507 
    508       if(metalink) {
    509         /* For Metalink download, we don't use glob. Instead we use
    510            the number of resources as urlnum. */
    511         urlnum = count_next_metalink_resource(mlfile);
    512       }
    513       else
    514       if(!config->globoff) {
    515         /* Unless explicitly shut off, we expand '{...}' and '[...]'
    516            expressions and return total number of URLs in pattern set */
    517         result = glob_url(&urls, urlnode->url, &urlnum,
    518                           global->showerror?global->errors:NULL);
    519         if(result) {
    520           Curl_safefree(uploadfile);
    521           break;
    522         }
    523       }
    524       else
    525         urlnum = 1; /* without globbing, this is a single URL */
    526 
    527       /* if multiple files extracted to stdout, insert separators! */
    528       separator = ((!outfiles || !strcmp(outfiles, "-")) && urlnum > 1);
    529 
    530       /* Here's looping around each globbed URL */
    531       for(li = 0 ; li < urlnum; li++) {
    532 
    533         int infd;
    534         bool infdopen;
    535         char *outfile;
    536         struct OutStruct outs;
    537         struct InStruct input;
    538         struct timeval retrystart;
    539         curl_off_t uploadfilesize;
    540         long retry_numretries;
    541         long retry_sleep_default;
    542         long retry_sleep;
    543         char *this_url = NULL;
    544         int metalink_next_res = 0;
    545 
    546         outfile = NULL;
    547         infdopen = FALSE;
    548         infd = STDIN_FILENO;
    549         uploadfilesize = -1; /* -1 means unknown */
    550 
    551         /* default output stream is stdout */
    552         memset(&outs, 0, sizeof(struct OutStruct));
    553         outs.stream = stdout;
    554         outs.config = config;
    555 
    556         if(metalink) {
    557           /* For Metalink download, use name in Metalink file as
    558              filename. */
    559           outfile = strdup(mlfile->filename);
    560           if(!outfile) {
    561             result = CURLE_OUT_OF_MEMORY;
    562             goto show_error;
    563           }
    564           this_url = strdup(mlres->url);
    565           if(!this_url) {
    566             result = CURLE_OUT_OF_MEMORY;
    567             goto show_error;
    568           }
    569         }
    570         else {
    571           if(urls) {
    572             result = glob_next_url(&this_url, urls);
    573             if(result)
    574               goto show_error;
    575           }
    576           else if(!li) {
    577             this_url = strdup(urlnode->url);
    578             if(!this_url) {
    579               result = CURLE_OUT_OF_MEMORY;
    580               goto show_error;
    581             }
    582           }
    583           else
    584             this_url = NULL;
    585           if(!this_url)
    586             break;
    587 
    588           if(outfiles) {
    589             outfile = strdup(outfiles);
    590             if(!outfile) {
    591               result = CURLE_OUT_OF_MEMORY;
    592               goto show_error;
    593             }
    594           }
    595         }
    596 
    597         if(((urlnode->flags&GETOUT_USEREMOTE) ||
    598             (outfile && strcmp("-", outfile))) &&
    599            (metalink || !config->use_metalink)) {
    600 
    601           /*
    602            * We have specified a file name to store the result in, or we have
    603            * decided we want to use the remote file name.
    604            */
    605 
    606           if(!outfile) {
    607             /* extract the file name from the URL */
    608             result = get_url_file_name(&outfile, this_url);
    609             if(result)
    610               goto show_error;
    611             if(!*outfile && !config->content_disposition) {
    612               helpf(global->errors, "Remote file name has no length!\n");
    613               result = CURLE_WRITE_ERROR;
    614               goto quit_urls;
    615             }
    616           }
    617           else if(urls) {
    618             /* fill '#1' ... '#9' terms from URL pattern */
    619             char *storefile = outfile;
    620             result = glob_match_url(&outfile, storefile, urls);
    621             Curl_safefree(storefile);
    622             if(result) {
    623               /* bad globbing */
    624               warnf(config->global, "bad output glob!\n");
    625               goto quit_urls;
    626             }
    627           }
    628 
    629           /* Create the directory hierarchy, if not pre-existent to a multiple
    630              file output call */
    631 
    632           if(config->create_dirs || metalink) {
    633             result = create_dir_hierarchy(outfile, global->errors);
    634             /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */
    635             if(result == CURLE_WRITE_ERROR)
    636               goto quit_urls;
    637             if(result) {
    638               goto show_error;
    639             }
    640           }
    641 
    642           if((urlnode->flags & GETOUT_USEREMOTE)
    643              && config->content_disposition) {
    644             /* Our header callback MIGHT set the filename */
    645             DEBUGASSERT(!outs.filename);
    646           }
    647 
    648           if(config->resume_from_current) {
    649             /* We're told to continue from where we are now. Get the size
    650                of the file as it is now and open it for append instead */
    651             struct_stat fileinfo;
    652             /* VMS -- Danger, the filesize is only valid for stream files */
    653             if(0 == stat(outfile, &fileinfo))
    654               /* set offset to current file size: */
    655               config->resume_from = fileinfo.st_size;
    656             else
    657               /* let offset be 0 */
    658               config->resume_from = 0;
    659           }
    660 
    661           if(config->resume_from) {
    662 #ifdef __VMS
    663             /* open file for output, forcing VMS output format into stream
    664                mode which is needed for stat() call above to always work. */
    665             FILE *file = fopen(outfile, config->resume_from?"ab":"wb",
    666                                "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0");
    667 #else
    668             /* open file for output: */
    669             FILE *file = fopen(outfile, config->resume_from?"ab":"wb");
    670 #endif
    671             if(!file) {
    672               helpf(global->errors, "Can't open '%s'!\n", outfile);
    673               result = CURLE_WRITE_ERROR;
    674               goto quit_urls;
    675             }
    676             outs.fopened = TRUE;
    677             outs.stream = file;
    678             outs.init = config->resume_from;
    679           }
    680           else {
    681             outs.stream = NULL; /* open when needed */
    682           }
    683           outs.filename = outfile;
    684           outs.s_isreg = TRUE;
    685         }
    686 
    687         if(uploadfile && !stdin_upload(uploadfile)) {
    688           /*
    689            * We have specified a file to upload and it isn't "-".
    690            */
    691           struct_stat fileinfo;
    692 
    693           this_url = add_file_name_to_url(curl, this_url, uploadfile);
    694           if(!this_url) {
    695             result = CURLE_OUT_OF_MEMORY;
    696             goto show_error;
    697           }
    698           /* VMS Note:
    699            *
    700            * Reading binary from files can be a problem...  Only FIXED, VAR
    701            * etc WITHOUT implied CC will work Others need a \n appended to a
    702            * line
    703            *
    704            * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a
    705            * fixed file with implied CC needs to have a byte added for every
    706            * record processed, this can by derived from Filesize & recordsize
    707            * for VARiable record files the records need to be counted!  for
    708            * every record add 1 for linefeed and subtract 2 for the record
    709            * header for VARIABLE header files only the bare record data needs
    710            * to be considered with one appended if implied CC
    711            */
    712 #ifdef __VMS
    713           /* Calculate the real upload site for VMS */
    714           infd = -1;
    715           if(stat(uploadfile, &fileinfo) == 0) {
    716             fileinfo.st_size = VmsSpecialSize(uploadfile, &fileinfo);
    717             switch(fileinfo.st_fab_rfm) {
    718             case FAB$C_VAR:
    719             case FAB$C_VFC:
    720             case FAB$C_STMCR:
    721               infd = open(uploadfile, O_RDONLY | O_BINARY);
    722               break;
    723             default:
    724               infd = open(uploadfile, O_RDONLY | O_BINARY,
    725                           "rfm=stmlf", "ctx=stm");
    726             }
    727           }
    728           if(infd == -1)
    729 #else
    730           infd = open(uploadfile, O_RDONLY | O_BINARY);
    731           if((infd == -1) || fstat(infd, &fileinfo))
    732 #endif
    733           {
    734             helpf(global->errors, "Can't open '%s'!\n", uploadfile);
    735             if(infd != -1) {
    736               close(infd);
    737               infd = STDIN_FILENO;
    738             }
    739             result = CURLE_READ_ERROR;
    740             goto quit_urls;
    741           }
    742           infdopen = TRUE;
    743 
    744           /* we ignore file size for char/block devices, sockets, etc. */
    745           if(S_ISREG(fileinfo.st_mode))
    746             uploadfilesize = fileinfo.st_size;
    747 
    748         }
    749         else if(uploadfile && stdin_upload(uploadfile)) {
    750           /* count to see if there are more than one auth bit set
    751              in the authtype field */
    752           int authbits = 0;
    753           int bitcheck = 0;
    754           while(bitcheck < 32) {
    755             if(config->authtype & (1UL << bitcheck++)) {
    756               authbits++;
    757               if(authbits > 1) {
    758                 /* more than one, we're done! */
    759                 break;
    760               }
    761             }
    762           }
    763 
    764           /*
    765            * If the user has also selected --anyauth or --proxy-anyauth
    766            * we should warn him/her.
    767            */
    768           if(config->proxyanyauth || (authbits>1)) {
    769             warnf(config->global,
    770                   "Using --anyauth or --proxy-anyauth with upload from stdin"
    771                   " involves a big risk of it not working. Use a temporary"
    772                   " file or a fixed auth type instead!\n");
    773           }
    774 
    775           DEBUGASSERT(infdopen == FALSE);
    776           DEBUGASSERT(infd == STDIN_FILENO);
    777 
    778           set_binmode(stdin);
    779           if(!strcmp(uploadfile, ".")) {
    780             if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
    781               warnf(config->global,
    782                     "fcntl failed on fd=%d: %s\n", infd, strerror(errno));
    783           }
    784         }
    785 
    786         if(uploadfile && config->resume_from_current)
    787           config->resume_from = -1; /* -1 will then force get-it-yourself */
    788 
    789         if(output_expected(this_url, uploadfile) && outs.stream &&
    790            isatty(fileno(outs.stream)))
    791           /* we send the output to a tty, therefore we switch off the progress
    792              meter */
    793           global->noprogress = global->isatty = TRUE;
    794         else {
    795           /* progress meter is per download, so restore config
    796              values */
    797           global->noprogress = orig_noprogress;
    798           global->isatty = orig_isatty;
    799         }
    800 
    801         if(urlnum > 1 && !global->mute) {
    802           fprintf(global->errors, "\n[%lu/%lu]: %s --> %s\n",
    803                   li + 1, urlnum, this_url, outfile ? outfile : "<stdout>");
    804           if(separator)
    805             printf("%s%s\n", CURLseparator, this_url);
    806         }
    807         if(httpgetfields) {
    808           char *urlbuffer;
    809           /* Find out whether the url contains a file name */
    810           const char *pc = strstr(this_url, "://");
    811           char sep = '?';
    812           if(pc)
    813             pc += 3;
    814           else
    815             pc = this_url;
    816 
    817           pc = strrchr(pc, '/'); /* check for a slash */
    818 
    819           if(pc) {
    820             /* there is a slash present in the URL */
    821 
    822             if(strchr(pc, '?'))
    823               /* Ouch, there's already a question mark in the URL string, we
    824                  then append the data with an ampersand separator instead! */
    825               sep = '&';
    826           }
    827           /*
    828            * Then append ? followed by the get fields to the url.
    829            */
    830           if(pc)
    831             urlbuffer = aprintf("%s%c%s", this_url, sep, httpgetfields);
    832           else
    833             /* Append  / before the ? to create a well-formed url
    834                if the url contains a hostname only
    835             */
    836             urlbuffer = aprintf("%s/?%s", this_url, httpgetfields);
    837 
    838           if(!urlbuffer) {
    839             result = CURLE_OUT_OF_MEMORY;
    840             goto show_error;
    841           }
    842 
    843           Curl_safefree(this_url); /* free previous URL */
    844           this_url = urlbuffer; /* use our new URL instead! */
    845         }
    846 
    847         if(!global->errors)
    848           global->errors = stderr;
    849 
    850         if((!outfile || !strcmp(outfile, "-")) && !config->use_ascii) {
    851           /* We get the output to stdout and we have not got the ASCII/text
    852              flag, then set stdout to be binary */
    853           set_binmode(stdout);
    854         }
    855 
    856         /* explicitly passed to stdout means okaying binary gunk */
    857         config->terminal_binary_ok = (outfile && !strcmp(outfile, "-"));
    858 
    859         if(!config->tcp_nodelay)
    860           my_setopt(curl, CURLOPT_TCP_NODELAY, 0L);
    861 
    862         if(config->tcp_fastopen)
    863           my_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L);
    864 
    865         /* where to store */
    866         my_setopt(curl, CURLOPT_WRITEDATA, &outs);
    867         my_setopt(curl, CURLOPT_INTERLEAVEDATA, &outs);
    868         if(metalink || !config->use_metalink)
    869           /* what call to write */
    870           my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
    871 #ifdef USE_METALINK
    872         else
    873           /* Set Metalink specific write callback function to parse
    874              XML data progressively. */
    875           my_setopt(curl, CURLOPT_WRITEFUNCTION, metalink_write_cb);
    876 #endif /* USE_METALINK */
    877 
    878         /* for uploads */
    879         input.fd = infd;
    880         input.config = config;
    881         /* Note that if CURLOPT_READFUNCTION is fread (the default), then
    882          * lib/telnet.c will Curl_poll() on the input file descriptor
    883          * rather then calling the READFUNCTION at regular intervals.
    884          * The circumstances in which it is preferable to enable this
    885          * behaviour, by omitting to set the READFUNCTION & READDATA options,
    886          * have not been determined.
    887          */
    888         my_setopt(curl, CURLOPT_READDATA, &input);
    889         /* what call to read */
    890         my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb);
    891 
    892         /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
    893            CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
    894         my_setopt(curl, CURLOPT_SEEKDATA, &input);
    895         my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);
    896 
    897         if(config->recvpersecond &&
    898            (config->recvpersecond < BUFFER_SIZE))
    899           /* use a smaller sized buffer for better sleeps */
    900           my_setopt(curl, CURLOPT_BUFFERSIZE, (long)config->recvpersecond);
    901         else
    902           my_setopt(curl, CURLOPT_BUFFERSIZE, (long)BUFFER_SIZE);
    903 
    904         /* size of uploaded file: */
    905         if(uploadfilesize != -1)
    906           my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
    907         my_setopt_str(curl, CURLOPT_URL, this_url);     /* what to fetch */
    908         my_setopt(curl, CURLOPT_NOPROGRESS, global->noprogress?1L:0L);
    909         if(config->no_body) {
    910           my_setopt(curl, CURLOPT_NOBODY, 1L);
    911           my_setopt(curl, CURLOPT_HEADER, 1L);
    912         }
    913         /* If --metalink is used, we ignore --include (headers in
    914            output) option because mixing headers to the body will
    915            confuse XML parser and/or hash check will fail. */
    916         else if(!config->use_metalink)
    917           my_setopt(curl, CURLOPT_HEADER, config->include_headers?1L:0L);
    918 
    919         if(config->oauth_bearer)
    920           my_setopt_str(curl, CURLOPT_XOAUTH2_BEARER, config->oauth_bearer);
    921 
    922 #if !defined(CURL_DISABLE_PROXY)
    923         {
    924           /* TODO: Make this a run-time check instead of compile-time one. */
    925 
    926           my_setopt_str(curl, CURLOPT_PROXY, config->proxy);
    927           /* new in libcurl 7.5 */
    928           if(config->proxy)
    929             my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->proxyver);
    930 
    931           my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
    932 
    933           /* new in libcurl 7.3 */
    934           my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel?1L:0L);
    935 
    936           /* new in libcurl 7.52.0 */
    937           if(config->preproxy)
    938             my_setopt_str(curl, CURLOPT_PRE_PROXY, config->preproxy);
    939 
    940           /* new in libcurl 7.10.6 */
    941           if(config->proxyanyauth)
    942             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
    943                               (long)CURLAUTH_ANY);
    944           else if(config->proxynegotiate)
    945             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
    946                               (long)CURLAUTH_GSSNEGOTIATE);
    947           else if(config->proxyntlm)
    948             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
    949                               (long)CURLAUTH_NTLM);
    950           else if(config->proxydigest)
    951             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
    952                               (long)CURLAUTH_DIGEST);
    953           else if(config->proxybasic)
    954             my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
    955                               (long)CURLAUTH_BASIC);
    956 
    957           /* new in libcurl 7.19.4 */
    958           my_setopt_str(curl, CURLOPT_NOPROXY, config->noproxy);
    959 
    960           my_setopt(curl, CURLOPT_SUPPRESS_CONNECT_HEADERS,
    961                     config->suppress_connect_headers?1L:0L);
    962         }
    963 #endif /* !CURL_DISABLE_PROXY */
    964 
    965         my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror?1L:0L);
    966         my_setopt(curl, CURLOPT_REQUEST_TARGET, config->request_target);
    967         my_setopt(curl, CURLOPT_UPLOAD, uploadfile?1L:0L);
    968         my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly?1L:0L);
    969         my_setopt(curl, CURLOPT_APPEND, config->ftp_append?1L:0L);
    970 
    971         if(config->netrc_opt)
    972           my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_OPTIONAL);
    973         else if(config->netrc || config->netrc_file)
    974           my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_REQUIRED);
    975         else
    976           my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_IGNORED);
    977 
    978         if(config->netrc_file)
    979           my_setopt_str(curl, CURLOPT_NETRC_FILE, config->netrc_file);
    980 
    981         my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii?1L:0L);
    982         if(config->login_options)
    983           my_setopt_str(curl, CURLOPT_LOGIN_OPTIONS, config->login_options);
    984         my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
    985         my_setopt_str(curl, CURLOPT_RANGE, config->range);
    986         my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
    987         my_setopt(curl, CURLOPT_TIMEOUT_MS, (long)(config->timeout * 1000));
    988 
    989         switch(config->httpreq) {
    990         case HTTPREQ_SIMPLEPOST:
    991           my_setopt_str(curl, CURLOPT_POSTFIELDS,
    992                         config->postfields);
    993           my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE,
    994                     config->postfieldsize);
    995           break;
    996         case HTTPREQ_MIMEPOST:
    997           my_setopt_mimepost(curl, CURLOPT_MIMEPOST, config->mimepost);
    998           break;
    999         default:
   1000           break;
   1001         }
   1002 
   1003         /* new in libcurl 7.10.6 (default is Basic) */
   1004         if(config->authtype)
   1005           my_setopt_bitmask(curl, CURLOPT_HTTPAUTH, (long)config->authtype);
   1006 
   1007         my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers);
   1008 
   1009         if(built_in_protos & (CURLPROTO_HTTP | CURLPROTO_RTSP)) {
   1010           my_setopt_str(curl, CURLOPT_REFERER, config->referer);
   1011           my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
   1012         }
   1013 
   1014         if(built_in_protos & CURLPROTO_HTTP) {
   1015 
   1016           long postRedir = 0;
   1017 
   1018           my_setopt(curl, CURLOPT_FOLLOWLOCATION,
   1019                     config->followlocation?1L:0L);
   1020           my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH,
   1021                     config->unrestricted_auth?1L:0L);
   1022 
   1023           my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer?1L:0L);
   1024 
   1025           /* new in libcurl 7.36.0 */
   1026           if(config->proxyheaders) {
   1027             my_setopt_slist(curl, CURLOPT_PROXYHEADER, config->proxyheaders);
   1028             my_setopt(curl, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE);
   1029           }
   1030 
   1031           /* new in libcurl 7.5 */
   1032           my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
   1033 
   1034           if(config->httpversion)
   1035             my_setopt_enum(curl, CURLOPT_HTTP_VERSION, config->httpversion);
   1036           else if(curlinfo->features & CURL_VERSION_HTTP2) {
   1037             my_setopt_enum(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
   1038           }
   1039 
   1040           /* curl 7.19.1 (the 301 version existed in 7.18.2),
   1041              303 was added in 7.26.0 */
   1042           if(config->post301)
   1043             postRedir |= CURL_REDIR_POST_301;
   1044           if(config->post302)
   1045             postRedir |= CURL_REDIR_POST_302;
   1046           if(config->post303)
   1047             postRedir |= CURL_REDIR_POST_303;
   1048           my_setopt(curl, CURLOPT_POSTREDIR, postRedir);
   1049 
   1050           /* new in libcurl 7.21.6 */
   1051           if(config->encoding)
   1052             my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, "");
   1053 
   1054           /* new in libcurl 7.21.6 */
   1055           if(config->tr_encoding)
   1056             my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1L);
   1057 
   1058         } /* (built_in_protos & CURLPROTO_HTTP) */
   1059 
   1060         my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
   1061         my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
   1062                   config->low_speed_limit);
   1063         my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
   1064         my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE,
   1065                   config->sendpersecond);
   1066         my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE,
   1067                   config->recvpersecond);
   1068 
   1069         if(config->use_resume)
   1070           my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, config->resume_from);
   1071         else
   1072           my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, CURL_OFF_T_C(0));
   1073 
   1074         my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
   1075         my_setopt_str(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_key_passwd);
   1076 
   1077         if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
   1078 
   1079           /* SSH and SSL private key uses same command-line option */
   1080           /* new in libcurl 7.16.1 */
   1081           my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
   1082           /* new in libcurl 7.16.1 */
   1083           my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
   1084 
   1085           /* new in libcurl 7.17.1: SSH host key md5 checking allows us
   1086              to fail if we are not talking to who we think we should */
   1087           my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
   1088                         config->hostpubmd5);
   1089 
   1090           /* new in libcurl 7.56.0 */
   1091           if(config->ssh_compression)
   1092             my_setopt(curl, CURLOPT_SSH_COMPRESSION, 1L);
   1093         }
   1094 
   1095         if(config->cacert)
   1096           my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
   1097         if(config->proxy_cacert)
   1098           my_setopt_str(curl, CURLOPT_PROXY_CAINFO, config->proxy_cacert);
   1099 
   1100         if(config->capath) {
   1101           result = res_setopt_str(curl, CURLOPT_CAPATH, config->capath);
   1102           if(result == CURLE_NOT_BUILT_IN) {
   1103             warnf(config->global, "ignoring %s, not supported by libcurl\n",
   1104                   capath_from_env?
   1105                   "SSL_CERT_DIR environment variable":"--capath");
   1106           }
   1107           else if(result)
   1108             goto show_error;
   1109         }
   1110         /* For the time being if --proxy-capath is not set then we use the
   1111            --capath value for it, if any. See #1257 */
   1112         if(config->proxy_capath || config->capath) {
   1113           result = res_setopt_str(curl, CURLOPT_PROXY_CAPATH,
   1114                                   (config->proxy_capath ?
   1115                                    config->proxy_capath :
   1116                                    config->capath));
   1117           if(result == CURLE_NOT_BUILT_IN) {
   1118             if(config->proxy_capath) {
   1119               warnf(config->global,
   1120                     "ignoring --proxy-capath, not supported by libcurl\n");
   1121             }
   1122           }
   1123           else if(result)
   1124             goto show_error;
   1125         }
   1126 
   1127         if(config->crlfile)
   1128           my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
   1129         if(config->proxy_crlfile)
   1130           my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->proxy_crlfile);
   1131         else if(config->crlfile) /* CURLOPT_PROXY_CRLFILE default is crlfile */
   1132           my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->crlfile);
   1133 
   1134         if(config->pinnedpubkey)
   1135           my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY, config->pinnedpubkey);
   1136 
   1137         if(curlinfo->features & CURL_VERSION_SSL) {
   1138           my_setopt_str(curl, CURLOPT_SSLCERT, config->cert);
   1139           my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert);
   1140           my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
   1141           my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE,
   1142                         config->proxy_cert_type);
   1143           my_setopt_str(curl, CURLOPT_SSLKEY, config->key);
   1144           my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key);
   1145           my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
   1146           my_setopt_str(curl, CURLOPT_PROXY_SSLKEYTYPE,
   1147                         config->proxy_key_type);
   1148 
   1149           if(config->insecure_ok) {
   1150             my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
   1151             my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
   1152           }
   1153           else {
   1154             my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
   1155             /* libcurl default is strict verifyhost -> 2L   */
   1156             /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */
   1157           }
   1158           if(config->proxy_insecure_ok) {
   1159             my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0L);
   1160             my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0L);
   1161           }
   1162           else {
   1163             my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L);
   1164           }
   1165 
   1166           if(config->verifystatus)
   1167             my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);
   1168 
   1169           if(config->falsestart)
   1170             my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L);
   1171 
   1172           my_setopt_enum(curl, CURLOPT_SSLVERSION,
   1173                          config->ssl_version | config->ssl_version_max);
   1174           my_setopt_enum(curl, CURLOPT_PROXY_SSLVERSION,
   1175                          config->proxy_ssl_version);
   1176         }
   1177         if(config->path_as_is)
   1178           my_setopt(curl, CURLOPT_PATH_AS_IS, 1L);
   1179 
   1180         if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
   1181           if(!config->insecure_ok) {
   1182             char *home;
   1183             char *file;
   1184             result = CURLE_OUT_OF_MEMORY;
   1185             home = homedir();
   1186             if(home) {
   1187               file = aprintf("%s/%sssh/known_hosts", home, DOT_CHAR);
   1188               if(file) {
   1189                 /* new in curl 7.19.6 */
   1190                 result = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file);
   1191                 curl_free(file);
   1192                 if(result == CURLE_UNKNOWN_OPTION)
   1193                   /* libssh2 version older than 1.1.1 */
   1194                   result = CURLE_OK;
   1195               }
   1196               Curl_safefree(home);
   1197             }
   1198             if(result)
   1199               goto show_error;
   1200           }
   1201         }
   1202 
   1203         if(config->no_body || config->remote_time) {
   1204           /* no body or use remote time */
   1205           my_setopt(curl, CURLOPT_FILETIME, 1L);
   1206         }
   1207 
   1208         my_setopt(curl, CURLOPT_CRLF, config->crlf?1L:0L);
   1209         my_setopt_slist(curl, CURLOPT_QUOTE, config->quote);
   1210         my_setopt_slist(curl, CURLOPT_POSTQUOTE, config->postquote);
   1211         my_setopt_slist(curl, CURLOPT_PREQUOTE, config->prequote);
   1212 
   1213 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
   1214         if(config->cookie)
   1215           my_setopt_str(curl, CURLOPT_COOKIE, config->cookie);
   1216 
   1217         if(config->cookiefile)
   1218           my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile);
   1219 
   1220         /* new in libcurl 7.9 */
   1221         if(config->cookiejar)
   1222           my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
   1223 
   1224         /* new in libcurl 7.9.7 */
   1225         my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession?1L:0L);
   1226 #else
   1227         if(config->cookie || config->cookiefile || config->cookiejar) {
   1228           warnf(config->global, "cookie option(s) used even though cookie "
   1229                 "support is disabled!\n");
   1230           return CURLE_NOT_BUILT_IN;
   1231         }
   1232 #endif
   1233 
   1234         my_setopt_enum(curl, CURLOPT_TIMECONDITION, (long)config->timecond);
   1235         my_setopt(curl, CURLOPT_TIMEVALUE, (long)config->condtime);
   1236         my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
   1237         customrequest_helper(config, config->httpreq, config->customrequest);
   1238         my_setopt(curl, CURLOPT_STDERR, global->errors);
   1239 
   1240         /* three new ones in libcurl 7.3: */
   1241         my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
   1242         my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
   1243 
   1244         progressbarinit(&progressbar, config);
   1245         if((global->progressmode == CURL_PROGRESS_BAR) &&
   1246            !global->noprogress && !global->mute) {
   1247           /* we want the alternative style, then we have to implement it
   1248              ourselves! */
   1249           my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_progress_cb);
   1250           my_setopt(curl, CURLOPT_XFERINFODATA, &progressbar);
   1251         }
   1252 
   1253         /* new in libcurl 7.24.0: */
   1254         if(config->dns_servers)
   1255           my_setopt_str(curl, CURLOPT_DNS_SERVERS, config->dns_servers);
   1256 
   1257         /* new in libcurl 7.33.0: */
   1258         if(config->dns_interface)
   1259           my_setopt_str(curl, CURLOPT_DNS_INTERFACE, config->dns_interface);
   1260         if(config->dns_ipv4_addr)
   1261           my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP4, config->dns_ipv4_addr);
   1262         if(config->dns_ipv6_addr)
   1263         my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP6, config->dns_ipv6_addr);
   1264 
   1265         /* new in libcurl 7.6.2: */
   1266         my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
   1267 
   1268         /* new in libcurl 7.7: */
   1269         my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file);
   1270         my_setopt_str(curl, CURLOPT_EGDSOCKET, config->egd_file);
   1271         my_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS,
   1272                   (long)(config->connecttimeout * 1000));
   1273 
   1274         if(config->cipher_list)
   1275           my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
   1276 
   1277         if(config->proxy_cipher_list)
   1278           my_setopt_str(curl, CURLOPT_PROXY_SSL_CIPHER_LIST,
   1279                         config->proxy_cipher_list);
   1280 
   1281         /* new in libcurl 7.9.2: */
   1282         if(config->disable_epsv)
   1283           /* disable it */
   1284           my_setopt(curl, CURLOPT_FTP_USE_EPSV, 0L);
   1285 
   1286         /* new in libcurl 7.10.5 */
   1287         if(config->disable_eprt)
   1288           /* disable it */
   1289           my_setopt(curl, CURLOPT_FTP_USE_EPRT, 0L);
   1290 
   1291         if(global->tracetype != TRACE_NONE) {
   1292           my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb);
   1293           my_setopt(curl, CURLOPT_DEBUGDATA, config);
   1294           my_setopt(curl, CURLOPT_VERBOSE, 1L);
   1295         }
   1296 
   1297         /* new in curl 7.9.3 */
   1298         if(config->engine) {
   1299           result = res_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
   1300           if(result)
   1301             goto show_error;
   1302         }
   1303 
   1304         /* new in curl 7.10.7, extended in 7.19.4. Modified to use
   1305            CREATE_DIR_RETRY in 7.49.0 */
   1306         my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
   1307                   (long)(config->ftp_create_dirs?
   1308                          CURLFTP_CREATE_DIR_RETRY:
   1309                          CURLFTP_CREATE_DIR_NONE));
   1310 
   1311         /* new in curl 7.10.8 */
   1312         if(config->max_filesize)
   1313           my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
   1314                     config->max_filesize);
   1315 
   1316         if(4 == config->ip_version)
   1317           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
   1318         else if(6 == config->ip_version)
   1319           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
   1320         else
   1321           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
   1322 
   1323         /* new in curl 7.15.5 */
   1324         if(config->ftp_ssl_reqd)
   1325           my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
   1326 
   1327         /* new in curl 7.11.0 */
   1328         else if(config->ftp_ssl)
   1329           my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY);
   1330 
   1331         /* new in curl 7.16.0 */
   1332         else if(config->ftp_ssl_control)
   1333           my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_CONTROL);
   1334 
   1335         /* new in curl 7.16.1 */
   1336         if(config->ftp_ssl_ccc)
   1337           my_setopt_enum(curl, CURLOPT_FTP_SSL_CCC,
   1338                          (long)config->ftp_ssl_ccc_mode);
   1339 
   1340         /* new in curl 7.19.4 */
   1341         if(config->socks5_gssapi_nec)
   1342           my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC,
   1343                         config->socks5_gssapi_nec);
   1344 
   1345         /* new in curl 7.55.0 */
   1346         if(config->socks5_auth)
   1347           my_setopt_bitmask(curl, CURLOPT_SOCKS5_AUTH,
   1348                             (long)config->socks5_auth);
   1349 
   1350         /* new in curl 7.43.0 */
   1351         if(config->proxy_service_name)
   1352           my_setopt_str(curl, CURLOPT_PROXY_SERVICE_NAME,
   1353                         config->proxy_service_name);
   1354 
   1355         /* new in curl 7.43.0 */
   1356         if(config->service_name)
   1357           my_setopt_str(curl, CURLOPT_SERVICE_NAME,
   1358                         config->service_name);
   1359 
   1360         /* curl 7.13.0 */
   1361         my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
   1362 
   1363         my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl?1L:0L);
   1364 
   1365         /* curl 7.14.2 */
   1366         my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip?1L:0L);
   1367 
   1368         /* curl 7.15.1 */
   1369         my_setopt(curl, CURLOPT_FTP_FILEMETHOD, (long)config->ftp_filemethod);
   1370 
   1371         /* curl 7.15.2 */
   1372         if(config->localport) {
   1373           my_setopt(curl, CURLOPT_LOCALPORT, (long)config->localport);
   1374           my_setopt_str(curl, CURLOPT_LOCALPORTRANGE,
   1375                         (long)config->localportrange);
   1376         }
   1377 
   1378         /* curl 7.15.5 */
   1379         my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
   1380                       config->ftp_alternative_to_user);
   1381 
   1382         /* curl 7.16.0 */
   1383         if(config->disable_sessionid)
   1384           /* disable it */
   1385           my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L);
   1386 
   1387         /* curl 7.16.2 */
   1388         if(config->raw) {
   1389           my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, 0L);
   1390           my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, 0L);
   1391         }
   1392 
   1393         /* curl 7.17.1 */
   1394         if(!config->nokeepalive) {
   1395           my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
   1396           if(config->alivetime != 0) {
   1397             my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime);
   1398             my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime);
   1399           }
   1400         }
   1401         else
   1402           my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
   1403 
   1404         /* curl 7.20.0 */
   1405         if(config->tftp_blksize)
   1406           my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
   1407 
   1408         if(config->mail_from)
   1409           my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
   1410 
   1411         if(config->mail_rcpt)
   1412           my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
   1413 
   1414         /* curl 7.20.x */
   1415         if(config->ftp_pret)
   1416           my_setopt(curl, CURLOPT_FTP_USE_PRET, 1L);
   1417 
   1418         if(config->proto_present)
   1419           my_setopt_flags(curl, CURLOPT_PROTOCOLS, config->proto);
   1420         if(config->proto_redir_present)
   1421           my_setopt_flags(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir);
   1422 
   1423         if(config->content_disposition
   1424            && (urlnode->flags & GETOUT_USEREMOTE))
   1425           hdrcbdata.honor_cd_filename = TRUE;
   1426         else
   1427           hdrcbdata.honor_cd_filename = FALSE;
   1428 
   1429         hdrcbdata.outs = &outs;
   1430         hdrcbdata.heads = &heads;
   1431 
   1432         my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb);
   1433         my_setopt(curl, CURLOPT_HEADERDATA, &hdrcbdata);
   1434 
   1435         if(config->resolve)
   1436           /* new in 7.21.3 */
   1437           my_setopt_slist(curl, CURLOPT_RESOLVE, config->resolve);
   1438 
   1439         if(config->connect_to)
   1440           /* new in 7.49.0 */
   1441           my_setopt_slist(curl, CURLOPT_CONNECT_TO, config->connect_to);
   1442 
   1443         /* new in 7.21.4 */
   1444         if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
   1445           if(config->tls_username)
   1446             my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME,
   1447                           config->tls_username);
   1448           if(config->tls_password)
   1449             my_setopt_str(curl, CURLOPT_TLSAUTH_PASSWORD,
   1450                           config->tls_password);
   1451           if(config->tls_authtype)
   1452             my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE,
   1453                           config->tls_authtype);
   1454           if(config->proxy_tls_username)
   1455             my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_USERNAME,
   1456                           config->proxy_tls_username);
   1457           if(config->proxy_tls_password)
   1458             my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD,
   1459                           config->proxy_tls_password);
   1460           if(config->proxy_tls_authtype)
   1461             my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_TYPE,
   1462                           config->proxy_tls_authtype);
   1463         }
   1464 
   1465         /* new in 7.22.0 */
   1466         if(config->gssapi_delegation)
   1467           my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION,
   1468                         config->gssapi_delegation);
   1469 
   1470         /* new in 7.25.0 and 7.44.0 */
   1471         {
   1472           long mask = (config->ssl_allow_beast ? CURLSSLOPT_ALLOW_BEAST : 0) |
   1473                       (config->ssl_no_revoke ? CURLSSLOPT_NO_REVOKE : 0);
   1474           if(mask)
   1475             my_setopt_bitmask(curl, CURLOPT_SSL_OPTIONS, mask);
   1476         }
   1477 
   1478         if(config->proxy_ssl_allow_beast)
   1479           my_setopt(curl, CURLOPT_PROXY_SSL_OPTIONS,
   1480                     (long)CURLSSLOPT_ALLOW_BEAST);
   1481 
   1482         if(config->mail_auth)
   1483           my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth);
   1484 
   1485         /* new in 7.31.0 */
   1486         if(config->sasl_ir)
   1487           my_setopt(curl, CURLOPT_SASL_IR, 1L);
   1488 
   1489         if(config->nonpn) {
   1490           my_setopt(curl, CURLOPT_SSL_ENABLE_NPN, 0L);
   1491         }
   1492 
   1493         if(config->noalpn) {
   1494           my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L);
   1495         }
   1496 
   1497         /* new in 7.40.0, abstract support added in 7.53.0 */
   1498         if(config->unix_socket_path) {
   1499           if(config->abstract_unix_socket) {
   1500             my_setopt_str(curl, CURLOPT_ABSTRACT_UNIX_SOCKET,
   1501                           config->unix_socket_path);
   1502           }
   1503           else {
   1504             my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH,
   1505                           config->unix_socket_path);
   1506           }
   1507         }
   1508         /* new in 7.45.0 */
   1509         if(config->proto_default)
   1510           my_setopt_str(curl, CURLOPT_DEFAULT_PROTOCOL, config->proto_default);
   1511 
   1512         /* new in 7.47.0 */
   1513         if(config->expect100timeout > 0)
   1514           my_setopt_str(curl, CURLOPT_EXPECT_100_TIMEOUT_MS,
   1515                         (long)(config->expect100timeout*1000));
   1516 
   1517         /* new in 7.48.0 */
   1518         if(config->tftp_no_options)
   1519           my_setopt(curl, CURLOPT_TFTP_NO_OPTIONS, 1L);
   1520 
   1521         /* initialize retry vars for loop below */
   1522         retry_sleep_default = (config->retry_delay) ?
   1523           config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
   1524 
   1525         retry_numretries = config->req_retry;
   1526         retry_sleep = retry_sleep_default; /* ms */
   1527         retrystart = tvnow();
   1528 
   1529 #ifndef CURL_DISABLE_LIBCURL_OPTION
   1530         if(global->libcurl) {
   1531           result = easysrc_perform();
   1532           if(result)
   1533             goto show_error;
   1534         }
   1535 #endif
   1536 
   1537         for(;;) {
   1538 #ifdef USE_METALINK
   1539           if(!metalink && config->use_metalink) {
   1540             /* If outs.metalink_parser is non-NULL, delete it first. */
   1541             if(outs.metalink_parser)
   1542               metalink_parser_context_delete(outs.metalink_parser);
   1543             outs.metalink_parser = metalink_parser_context_new();
   1544             if(outs.metalink_parser == NULL) {
   1545               result = CURLE_OUT_OF_MEMORY;
   1546               goto show_error;
   1547             }
   1548             fprintf(config->global->errors,
   1549                     "Metalink: parsing (%s) metalink/XML...\n", this_url);
   1550           }
   1551           else if(metalink)
   1552             fprintf(config->global->errors,
   1553                     "Metalink: fetching (%s) from (%s)...\n",
   1554                     mlfile->filename, this_url);
   1555 #endif /* USE_METALINK */
   1556 
   1557 #ifdef CURLDEBUG
   1558           if(config->test_event_based)
   1559             result = curl_easy_perform_ev(curl);
   1560           else
   1561 #endif
   1562           result = curl_easy_perform(curl);
   1563 
   1564           if(!result && !outs.stream && !outs.bytes) {
   1565             /* we have received no data despite the transfer was successful
   1566                ==> force cration of an empty output file (if an output file
   1567                was specified) */
   1568             long cond_unmet = 0L;
   1569             /* do not create (or even overwrite) the file in case we get no
   1570                data because of unmet condition */
   1571             curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &cond_unmet);
   1572             if(!cond_unmet && !tool_create_output_file(&outs))
   1573               result = CURLE_WRITE_ERROR;
   1574           }
   1575 
   1576           if(outs.is_cd_filename && outs.stream && !global->mute &&
   1577              outs.filename)
   1578             printf("curl: Saved to filename '%s'\n", outs.filename);
   1579 
   1580           /* if retry-max-time is non-zero, make sure we haven't exceeded the
   1581              time */
   1582           if(retry_numretries &&
   1583              (!config->retry_maxtime ||
   1584               (tvdiff(tvnow(), retrystart) <
   1585                config->retry_maxtime*1000L)) ) {
   1586             enum {
   1587               RETRY_NO,
   1588               RETRY_TIMEOUT,
   1589               RETRY_CONNREFUSED,
   1590               RETRY_HTTP,
   1591               RETRY_FTP,
   1592               RETRY_LAST /* not used */
   1593             } retry = RETRY_NO;
   1594             long response;
   1595             if((CURLE_OPERATION_TIMEDOUT == result) ||
   1596                (CURLE_COULDNT_RESOLVE_HOST == result) ||
   1597                (CURLE_COULDNT_RESOLVE_PROXY == result) ||
   1598                (CURLE_FTP_ACCEPT_TIMEOUT == result))
   1599               /* retry timeout always */
   1600               retry = RETRY_TIMEOUT;
   1601             else if(config->retry_connrefused &&
   1602                     (CURLE_COULDNT_CONNECT == result)) {
   1603               long oserrno;
   1604               curl_easy_getinfo(curl, CURLINFO_OS_ERRNO, &oserrno);
   1605               if(ECONNREFUSED == oserrno)
   1606                 retry = RETRY_CONNREFUSED;
   1607             }
   1608             else if((CURLE_OK == result) ||
   1609                     (config->failonerror &&
   1610                      (CURLE_HTTP_RETURNED_ERROR == result))) {
   1611               /* If it returned OK. _or_ failonerror was enabled and it
   1612                  returned due to such an error, check for HTTP transient
   1613                  errors to retry on. */
   1614               char *effective_url = NULL;
   1615               curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
   1616               if(effective_url &&
   1617                  checkprefix("http", effective_url)) {
   1618                 /* This was HTTP(S) */
   1619                 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
   1620 
   1621                 switch(response) {
   1622                 case 500: /* Internal Server Error */
   1623                 case 502: /* Bad Gateway */
   1624                 case 503: /* Service Unavailable */
   1625                 case 504: /* Gateway Timeout */
   1626                   retry = RETRY_HTTP;
   1627                   /*
   1628                    * At this point, we have already written data to the output
   1629                    * file (or terminal). If we write to a file, we must rewind
   1630                    * or close/re-open the file so that the next attempt starts
   1631                    * over from the beginning.
   1632                    *
   1633                    * TODO: similar action for the upload case. We might need
   1634                    * to start over reading from a previous point if we have
   1635                    * uploaded something when this was returned.
   1636                    */
   1637                   break;
   1638                 }
   1639               }
   1640             } /* if CURLE_OK */
   1641             else if(result) {
   1642               curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
   1643 
   1644               if(response/100 == 4)
   1645                 /*
   1646                  * This is typically when the FTP server only allows a certain
   1647                  * amount of users and we are not one of them.  All 4xx codes
   1648                  * are transient.
   1649                  */
   1650                 retry = RETRY_FTP;
   1651             }
   1652 
   1653             if(retry) {
   1654               static const char * const m[]={
   1655                 NULL,
   1656                 "timeout",
   1657                 "connection refused",
   1658                 "HTTP error",
   1659                 "FTP error"
   1660               };
   1661 
   1662               warnf(config->global, "Transient problem: %s "
   1663                     "Will retry in %ld seconds. "
   1664                     "%ld retries left.\n",
   1665                     m[retry], retry_sleep/1000L, retry_numretries);
   1666 
   1667               tool_go_sleep(retry_sleep);
   1668               retry_numretries--;
   1669               if(!config->retry_delay) {
   1670                 retry_sleep *= 2;
   1671                 if(retry_sleep > RETRY_SLEEP_MAX)
   1672                   retry_sleep = RETRY_SLEEP_MAX;
   1673               }
   1674               if(outs.bytes && outs.filename && outs.stream) {
   1675                 int rc;
   1676                 /* We have written data to a output file, we truncate file
   1677                  */
   1678                 if(!global->mute)
   1679                   fprintf(global->errors, "Throwing away %"
   1680                           CURL_FORMAT_CURL_OFF_T " bytes\n",
   1681                           outs.bytes);
   1682                 fflush(outs.stream);
   1683                 /* truncate file at the position where we started appending */
   1684 #ifdef HAVE_FTRUNCATE
   1685                 if(ftruncate(fileno(outs.stream), outs.init)) {
   1686                   /* when truncate fails, we can't just append as then we'll
   1687                      create something strange, bail out */
   1688                   if(!global->mute)
   1689                     fprintf(global->errors,
   1690                             "failed to truncate, exiting\n");
   1691                   result = CURLE_WRITE_ERROR;
   1692                   goto quit_urls;
   1693                 }
   1694                 /* now seek to the end of the file, the position where we
   1695                    just truncated the file in a large file-safe way */
   1696                 rc = fseek(outs.stream, 0, SEEK_END);
   1697 #else
   1698                 /* ftruncate is not available, so just reposition the file
   1699                    to the location we would have truncated it. This won't
   1700                    work properly with large files on 32-bit systems, but
   1701                    most of those will have ftruncate. */
   1702                 rc = fseek(outs.stream, (long)outs.init, SEEK_SET);
   1703 #endif
   1704                 if(rc) {
   1705                   if(!global->mute)
   1706                     fprintf(global->errors,
   1707                             "failed seeking to end of file, exiting\n");
   1708                   result = CURLE_WRITE_ERROR;
   1709                   goto quit_urls;
   1710                 }
   1711                 outs.bytes = 0; /* clear for next round */
   1712               }
   1713               continue; /* curl_easy_perform loop */
   1714             }
   1715           } /* if retry_numretries */
   1716           else if(metalink) {
   1717             /* Metalink: Decide to try the next resource or
   1718                not. Basically, we want to try the next resource if
   1719                download was not successful. */
   1720             long response;
   1721             if(CURLE_OK == result) {
   1722               /* TODO We want to try next resource when download was
   1723                  not successful. How to know that? */
   1724               char *effective_url = NULL;
   1725               curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
   1726               if(effective_url &&
   1727                  curl_strnequal(effective_url, "http", 4)) {
   1728                 /* This was HTTP(S) */
   1729                 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
   1730                 if(response != 200 && response != 206) {
   1731                   metalink_next_res = 1;
   1732                   fprintf(global->errors,
   1733                           "Metalink: fetching (%s) from (%s) FAILED "
   1734                           "(HTTP status code %ld)\n",
   1735                           mlfile->filename, this_url, response);
   1736                 }
   1737               }
   1738             }
   1739             else {
   1740               metalink_next_res = 1;
   1741               fprintf(global->errors,
   1742                       "Metalink: fetching (%s) from (%s) FAILED (%s)\n",
   1743                       mlfile->filename, this_url,
   1744                       (errorbuffer[0]) ?
   1745                       errorbuffer : curl_easy_strerror(result));
   1746             }
   1747           }
   1748           if(metalink && !metalink_next_res)
   1749             fprintf(global->errors, "Metalink: fetching (%s) from (%s) OK\n",
   1750                     mlfile->filename, this_url);
   1751 
   1752           /* In all ordinary cases, just break out of loop here */
   1753           break; /* curl_easy_perform loop */
   1754 
   1755         }
   1756 
   1757         if((global->progressmode == CURL_PROGRESS_BAR) &&
   1758            progressbar.calls)
   1759           /* if the custom progress bar has been displayed, we output a
   1760              newline here */
   1761           fputs("\n", progressbar.out);
   1762 
   1763         if(config->writeout)
   1764           ourWriteOut(curl, &outs, config->writeout);
   1765 
   1766         /*
   1767         ** Code within this loop may jump directly here to label 'show_error'
   1768         ** in order to display an error message for CURLcode stored in 'res'
   1769         ** variable and exit loop once that necessary writing and cleanup
   1770         ** in label 'quit_urls' has been done.
   1771         */
   1772 
   1773         show_error:
   1774 
   1775 #ifdef __VMS
   1776         if(is_vms_shell()) {
   1777           /* VMS DCL shell behavior */
   1778           if(!global->showerror)
   1779             vms_show = VMSSTS_HIDE;
   1780         }
   1781         else
   1782 #endif
   1783         if(config->synthetic_error) {
   1784           ;
   1785         }
   1786         else if(result && global->showerror) {
   1787           fprintf(global->errors, "curl: (%d) %s\n", result, (errorbuffer[0]) ?
   1788                   errorbuffer : curl_easy_strerror(result));
   1789           if(result == CURLE_SSL_CACERT)
   1790             fputs(CURL_CA_CERT_ERRORMSG, global->errors);
   1791         }
   1792 
   1793         /* Fall through comment to 'quit_urls' label */
   1794 
   1795         /*
   1796         ** Upon error condition and always that a message has already been
   1797         ** displayed, code within this loop may jump directly here to label
   1798         ** 'quit_urls' otherwise it should jump to 'show_error' label above.
   1799         **
   1800         ** When 'res' variable is _not_ CURLE_OK loop will exit once that
   1801         ** all code following 'quit_urls' has been executed. Otherwise it
   1802         ** will loop to the beginning from where it may exit if there are
   1803         ** no more urls left.
   1804         */
   1805 
   1806         quit_urls:
   1807 
   1808         /* Set file extended attributes */
   1809         if(!result && config->xattr && outs.fopened && outs.stream) {
   1810           int rc = fwrite_xattr(curl, fileno(outs.stream));
   1811           if(rc)
   1812             warnf(config->global, "Error setting extended attributes: %s\n",
   1813                   strerror(errno));
   1814         }
   1815 
   1816         /* Close the file */
   1817         if(outs.fopened && outs.stream) {
   1818           int rc = fclose(outs.stream);
   1819           if(!result && rc) {
   1820             /* something went wrong in the writing process */
   1821             result = CURLE_WRITE_ERROR;
   1822             fprintf(global->errors, "(%d) Failed writing body\n", result);
   1823           }
   1824         }
   1825         else if(!outs.s_isreg && outs.stream) {
   1826           /* Dump standard stream buffered data */
   1827           int rc = fflush(outs.stream);
   1828           if(!result && rc) {
   1829             /* something went wrong in the writing process */
   1830             result = CURLE_WRITE_ERROR;
   1831             fprintf(global->errors, "(%d) Failed writing body\n", result);
   1832           }
   1833         }
   1834 
   1835 #ifdef __AMIGA__
   1836         if(!result && outs.s_isreg && outs.filename) {
   1837           /* Set the url (up to 80 chars) as comment for the file */
   1838           if(strlen(url) > 78)
   1839             url[79] = '\0';
   1840           SetComment(outs.filename, url);
   1841         }
   1842 #endif
   1843 
   1844 #if defined(HAVE_UTIME) || \
   1845     (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8))
   1846         /* File time can only be set _after_ the file has been closed */
   1847         if(!result && config->remote_time && outs.s_isreg && outs.filename) {
   1848           /* Ask libcurl if we got a remote file time */
   1849           long filetime = -1;
   1850           curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
   1851           if(filetime >= 0)
   1852             setfiletime(filetime, outs.filename, config->global->errors);
   1853         }
   1854 #endif /* defined(HAVE_UTIME) || \
   1855           (defined(WIN32) && (SIZEOF_CURL_OFF_T >= 8)) */
   1856 
   1857 #ifdef USE_METALINK
   1858         if(!metalink && config->use_metalink && result == CURLE_OK) {
   1859           int rv = parse_metalink(config, &outs, this_url);
   1860           if(rv == 0)
   1861             fprintf(config->global->errors, "Metalink: parsing (%s) OK\n",
   1862                     this_url);
   1863           else if(rv == -1)
   1864             fprintf(config->global->errors, "Metalink: parsing (%s) FAILED\n",
   1865                     this_url);
   1866         }
   1867         else if(metalink && result == CURLE_OK && !metalink_next_res) {
   1868           int rv = metalink_check_hash(global, mlfile, outs.filename);
   1869           if(rv == 0) {
   1870             metalink_next_res = 1;
   1871           }
   1872         }
   1873 #endif /* USE_METALINK */
   1874 
   1875         /* No more business with this output struct */
   1876         if(outs.alloc_filename)
   1877           Curl_safefree(outs.filename);
   1878 #ifdef USE_METALINK
   1879         if(outs.metalink_parser)
   1880           metalink_parser_context_delete(outs.metalink_parser);
   1881 #endif /* USE_METALINK */
   1882         memset(&outs, 0, sizeof(struct OutStruct));
   1883         hdrcbdata.outs = NULL;
   1884 
   1885         /* Free loop-local allocated memory and close loop-local opened fd */
   1886 
   1887         Curl_safefree(outfile);
   1888         Curl_safefree(this_url);
   1889 
   1890         if(infdopen)
   1891           close(infd);
   1892 
   1893         if(metalink) {
   1894           /* Should exit if error is fatal. */
   1895           if(is_fatal_error(result)) {
   1896             break;
   1897           }
   1898           if(!metalink_next_res)
   1899             break;
   1900           mlres = mlres->next;
   1901           if(mlres == NULL)
   1902             /* TODO If metalink_next_res is 1 and mlres is NULL,
   1903              * set res to error code
   1904              */
   1905             break;
   1906         }
   1907         else
   1908         if(urlnum > 1) {
   1909           /* when url globbing, exit loop upon critical error */
   1910           if(is_fatal_error(result))
   1911             break;
   1912         }
   1913         else if(result)
   1914           /* when not url globbing, exit loop upon any error */
   1915           break;
   1916 
   1917       } /* loop to the next URL */
   1918 
   1919       /* Free loop-local allocated memory */
   1920 
   1921       Curl_safefree(uploadfile);
   1922 
   1923       if(urls) {
   1924         /* Free list of remaining URLs */
   1925         glob_cleanup(urls);
   1926         urls = NULL;
   1927       }
   1928 
   1929       if(infilenum > 1) {
   1930         /* when file globbing, exit loop upon critical error */
   1931         if(is_fatal_error(result))
   1932           break;
   1933       }
   1934       else if(result)
   1935         /* when not file globbing, exit loop upon any error */
   1936         break;
   1937 
   1938     } /* loop to the next globbed upload file */
   1939 
   1940     /* Free loop-local allocated memory */
   1941 
   1942     Curl_safefree(outfiles);
   1943 
   1944     if(inglob) {
   1945       /* Free list of globbed upload files */
   1946       glob_cleanup(inglob);
   1947       inglob = NULL;
   1948     }
   1949 
   1950     /* Free this URL node data without destroying the
   1951        the node itself nor modifying next pointer. */
   1952     Curl_safefree(urlnode->url);
   1953     Curl_safefree(urlnode->outfile);
   1954     Curl_safefree(urlnode->infile);
   1955     urlnode->flags = 0;
   1956 
   1957     /*
   1958     ** Bail out upon critical errors or --fail-early
   1959     */
   1960     if(is_fatal_error(result) || (result && global->fail_early))
   1961       goto quit_curl;
   1962 
   1963   } /* for-loop through all URLs */
   1964 
   1965   /*
   1966   ** Nested loops end here.
   1967   */
   1968 
   1969   quit_curl:
   1970 
   1971   /* Reset the global config variables */
   1972   global->noprogress = orig_noprogress;
   1973   global->isatty = orig_isatty;
   1974 
   1975   /* Free function-local referenced allocated memory */
   1976   Curl_safefree(httpgetfields);
   1977 
   1978   /* Free list of given URLs */
   1979   clean_getout(config);
   1980 
   1981   hdrcbdata.heads = NULL;
   1982 
   1983   /* Close function-local opened file descriptors */
   1984   if(heads.fopened && heads.stream)
   1985     fclose(heads.stream);
   1986 
   1987   if(heads.alloc_filename)
   1988     Curl_safefree(heads.filename);
   1989 
   1990   /* Release metalink related resources here */
   1991   clean_metalink(config);
   1992 
   1993   return result;
   1994 }
   1995 
   1996 CURLcode operate(struct GlobalConfig *config, int argc, argv_item_t argv[])
   1997 {
   1998   CURLcode result = CURLE_OK;
   1999 
   2000   /* Setup proper locale from environment */
   2001 #ifdef HAVE_SETLOCALE
   2002   setlocale(LC_ALL, "");
   2003 #endif
   2004 
   2005   /* Parse .curlrc if necessary */
   2006   if((argc == 1) ||
   2007      (!curl_strequal(argv[1], "-q") &&
   2008       !curl_strequal(argv[1], "--disable"))) {
   2009     parseconfig(NULL, config); /* ignore possible failure */
   2010 
   2011     /* If we had no arguments then make sure a url was specified in .curlrc */
   2012     if((argc < 2) && (!config->first->url_list)) {
   2013       helpf(config->errors, NULL);
   2014       result = CURLE_FAILED_INIT;
   2015     }
   2016   }
   2017 
   2018   if(!result) {
   2019     /* Parse the command line arguments */
   2020     ParameterError res = parse_args(config, argc, argv);
   2021     if(res) {
   2022       result = CURLE_OK;
   2023 
   2024       /* Check if we were asked for the help */
   2025       if(res == PARAM_HELP_REQUESTED)
   2026         tool_help();
   2027       /* Check if we were asked for the manual */
   2028       else if(res == PARAM_MANUAL_REQUESTED)
   2029         hugehelp();
   2030       /* Check if we were asked for the version information */
   2031       else if(res == PARAM_VERSION_INFO_REQUESTED)
   2032         tool_version_info();
   2033       /* Check if we were asked to list the SSL engines */
   2034       else if(res == PARAM_ENGINES_REQUESTED)
   2035         tool_list_engines(config->easy);
   2036       else if(res == PARAM_LIBCURL_UNSUPPORTED_PROTOCOL)
   2037         result = CURLE_UNSUPPORTED_PROTOCOL;
   2038       else
   2039         result = CURLE_FAILED_INIT;
   2040     }
   2041     else {
   2042 #ifndef CURL_DISABLE_LIBCURL_OPTION
   2043       if(config->libcurl) {
   2044         /* Initialise the libcurl source output */
   2045         result = easysrc_init();
   2046       }
   2047 #endif
   2048 
   2049       /* Perform the main operations */
   2050       if(!result) {
   2051         size_t count = 0;
   2052         struct OperationConfig *operation = config->first;
   2053 
   2054         /* Get the required aguments for each operation */
   2055         while(!result && operation) {
   2056           result = get_args(operation, count++);
   2057 
   2058           operation = operation->next;
   2059         }
   2060 
   2061         /* Set the current operation pointer */
   2062         config->current = config->first;
   2063 
   2064         /* Perform each operation */
   2065         while(!result && config->current) {
   2066           result = operate_do(config, config->current);
   2067 
   2068           config->current = config->current->next;
   2069 
   2070           if(config->current && config->current->easy)
   2071             curl_easy_reset(config->current->easy);
   2072         }
   2073 
   2074 #ifndef CURL_DISABLE_LIBCURL_OPTION
   2075         if(config->libcurl) {
   2076           /* Cleanup the libcurl source output */
   2077           easysrc_cleanup();
   2078 
   2079           /* Dump the libcurl code if previously enabled */
   2080           dumpeasysrc(config);
   2081         }
   2082 #endif
   2083       }
   2084       else
   2085         helpf(config->errors, "out of memory\n");
   2086     }
   2087   }
   2088 
   2089   return result;
   2090 }
   2091