File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / src / tool_operate.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (4 years, 10 months ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>