Annotation of embedaddon/curl/src/tool_operate.c, revision 1.1.1.1

1.1       misho       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>