113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                                  _   _ ____  _
313498266Sopenharmony_ci *  Project                     ___| | | |  _ \| |
413498266Sopenharmony_ci *                             / __| | | | |_) | |
513498266Sopenharmony_ci *                            | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                             \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
913498266Sopenharmony_ci *
1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1313498266Sopenharmony_ci *
1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1713498266Sopenharmony_ci *
1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1913498266Sopenharmony_ci * KIND, either express or implied.
2013498266Sopenharmony_ci *
2113498266Sopenharmony_ci * SPDX-License-Identifier: curl
2213498266Sopenharmony_ci *
2313498266Sopenharmony_ci ***************************************************************************/
2413498266Sopenharmony_ci#include "tool_setup.h"
2513498266Sopenharmony_ci
2613498266Sopenharmony_ci#ifdef HAVE_FCNTL_H
2713498266Sopenharmony_ci#  include <fcntl.h>
2813498266Sopenharmony_ci#endif
2913498266Sopenharmony_ci
3013498266Sopenharmony_ci#ifdef HAVE_LOCALE_H
3113498266Sopenharmony_ci#  include <locale.h>
3213498266Sopenharmony_ci#endif
3313498266Sopenharmony_ci
3413498266Sopenharmony_ci#ifdef HAVE_SYS_SELECT_H
3513498266Sopenharmony_ci#  include <sys/select.h>
3613498266Sopenharmony_ci#elif defined(HAVE_UNISTD_H)
3713498266Sopenharmony_ci#  include <unistd.h>
3813498266Sopenharmony_ci#endif
3913498266Sopenharmony_ci
4013498266Sopenharmony_ci#ifdef __VMS
4113498266Sopenharmony_ci#  include <fabdef.h>
4213498266Sopenharmony_ci#endif
4313498266Sopenharmony_ci
4413498266Sopenharmony_ci#ifdef __AMIGA__
4513498266Sopenharmony_ci#  include <proto/dos.h>
4613498266Sopenharmony_ci#endif
4713498266Sopenharmony_ci
4813498266Sopenharmony_ci#define ENABLE_CURLX_PRINTF
4913498266Sopenharmony_ci/* use our own printf() functions */
5013498266Sopenharmony_ci#include "curlx.h"
5113498266Sopenharmony_ci
5213498266Sopenharmony_ci#include "tool_binmode.h"
5313498266Sopenharmony_ci#include "tool_cfgable.h"
5413498266Sopenharmony_ci#include "tool_cb_dbg.h"
5513498266Sopenharmony_ci#include "tool_cb_hdr.h"
5613498266Sopenharmony_ci#include "tool_cb_prg.h"
5713498266Sopenharmony_ci#include "tool_cb_rea.h"
5813498266Sopenharmony_ci#include "tool_cb_see.h"
5913498266Sopenharmony_ci#include "tool_cb_wrt.h"
6013498266Sopenharmony_ci#include "tool_dirhie.h"
6113498266Sopenharmony_ci#include "tool_doswin.h"
6213498266Sopenharmony_ci#include "tool_easysrc.h"
6313498266Sopenharmony_ci#include "tool_filetime.h"
6413498266Sopenharmony_ci#include "tool_getparam.h"
6513498266Sopenharmony_ci#include "tool_helpers.h"
6613498266Sopenharmony_ci#include "tool_findfile.h"
6713498266Sopenharmony_ci#include "tool_libinfo.h"
6813498266Sopenharmony_ci#include "tool_main.h"
6913498266Sopenharmony_ci#include "tool_msgs.h"
7013498266Sopenharmony_ci#include "tool_operate.h"
7113498266Sopenharmony_ci#include "tool_operhlp.h"
7213498266Sopenharmony_ci#include "tool_paramhlp.h"
7313498266Sopenharmony_ci#include "tool_parsecfg.h"
7413498266Sopenharmony_ci#include "tool_setopt.h"
7513498266Sopenharmony_ci#include "tool_sleep.h"
7613498266Sopenharmony_ci#include "tool_urlglob.h"
7713498266Sopenharmony_ci#include "tool_util.h"
7813498266Sopenharmony_ci#include "tool_writeout.h"
7913498266Sopenharmony_ci#include "tool_xattr.h"
8013498266Sopenharmony_ci#include "tool_vms.h"
8113498266Sopenharmony_ci#include "tool_help.h"
8213498266Sopenharmony_ci#include "tool_hugehelp.h"
8313498266Sopenharmony_ci#include "tool_progress.h"
8413498266Sopenharmony_ci#include "tool_ipfs.h"
8513498266Sopenharmony_ci#include "dynbuf.h"
8613498266Sopenharmony_ci
8713498266Sopenharmony_ci#include "memdebug.h" /* keep this as LAST include */
8813498266Sopenharmony_ci
8913498266Sopenharmony_ci#ifdef CURLDEBUG
9013498266Sopenharmony_ci/* libcurl's debug builds provide an extra function */
9113498266Sopenharmony_ciCURLcode curl_easy_perform_ev(CURL *easy);
9213498266Sopenharmony_ci#endif
9313498266Sopenharmony_ci
9413498266Sopenharmony_ci#ifndef O_BINARY
9513498266Sopenharmony_ci/* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
9613498266Sopenharmony_ci   source code but yet it doesn't ruin anything */
9713498266Sopenharmony_ci#  define O_BINARY 0
9813498266Sopenharmony_ci#endif
9913498266Sopenharmony_ci
10013498266Sopenharmony_ci#define CURL_CA_CERT_ERRORMSG                                               \
10113498266Sopenharmony_ci  "More details here: https://curl.se/docs/sslcerts.html\n\n"          \
10213498266Sopenharmony_ci  "curl failed to verify the legitimacy of the server and therefore "       \
10313498266Sopenharmony_ci  "could not\nestablish a secure connection to it. To learn more about "    \
10413498266Sopenharmony_ci  "this situation and\nhow to fix it, please visit the web page mentioned " \
10513498266Sopenharmony_ci  "above.\n"
10613498266Sopenharmony_ci
10713498266Sopenharmony_cistatic CURLcode single_transfer(struct GlobalConfig *global,
10813498266Sopenharmony_ci                                struct OperationConfig *config,
10913498266Sopenharmony_ci                                CURLSH *share,
11013498266Sopenharmony_ci                                bool capath_from_env,
11113498266Sopenharmony_ci                                bool *added);
11213498266Sopenharmony_cistatic CURLcode create_transfer(struct GlobalConfig *global,
11313498266Sopenharmony_ci                                CURLSH *share,
11413498266Sopenharmony_ci                                bool *added);
11513498266Sopenharmony_ci
11613498266Sopenharmony_cistatic bool is_fatal_error(CURLcode code)
11713498266Sopenharmony_ci{
11813498266Sopenharmony_ci  switch(code) {
11913498266Sopenharmony_ci  case CURLE_FAILED_INIT:
12013498266Sopenharmony_ci  case CURLE_OUT_OF_MEMORY:
12113498266Sopenharmony_ci  case CURLE_UNKNOWN_OPTION:
12213498266Sopenharmony_ci  case CURLE_FUNCTION_NOT_FOUND:
12313498266Sopenharmony_ci  case CURLE_BAD_FUNCTION_ARGUMENT:
12413498266Sopenharmony_ci    /* critical error */
12513498266Sopenharmony_ci    return TRUE;
12613498266Sopenharmony_ci  default:
12713498266Sopenharmony_ci    break;
12813498266Sopenharmony_ci  }
12913498266Sopenharmony_ci
13013498266Sopenharmony_ci  /* no error or not critical */
13113498266Sopenharmony_ci  return FALSE;
13213498266Sopenharmony_ci}
13313498266Sopenharmony_ci
13413498266Sopenharmony_ci/*
13513498266Sopenharmony_ci * Check if a given string is a PKCS#11 URI
13613498266Sopenharmony_ci */
13713498266Sopenharmony_cistatic bool is_pkcs11_uri(const char *string)
13813498266Sopenharmony_ci{
13913498266Sopenharmony_ci  if(curl_strnequal(string, "pkcs11:", 7)) {
14013498266Sopenharmony_ci    return TRUE;
14113498266Sopenharmony_ci  }
14213498266Sopenharmony_ci  else {
14313498266Sopenharmony_ci    return FALSE;
14413498266Sopenharmony_ci  }
14513498266Sopenharmony_ci}
14613498266Sopenharmony_ci
14713498266Sopenharmony_ci#ifdef __VMS
14813498266Sopenharmony_ci/*
14913498266Sopenharmony_ci * get_vms_file_size does what it takes to get the real size of the file
15013498266Sopenharmony_ci *
15113498266Sopenharmony_ci * For fixed files, find out the size of the EOF block and adjust.
15213498266Sopenharmony_ci *
15313498266Sopenharmony_ci * For all others, have to read the entire file in, discarding the contents.
15413498266Sopenharmony_ci * Most posted text files will be small, and binary files like zlib archives
15513498266Sopenharmony_ci * and CD/DVD images should be either a STREAM_LF format or a fixed format.
15613498266Sopenharmony_ci *
15713498266Sopenharmony_ci */
15813498266Sopenharmony_cistatic curl_off_t vms_realfilesize(const char *name,
15913498266Sopenharmony_ci                                   const struct_stat *stat_buf)
16013498266Sopenharmony_ci{
16113498266Sopenharmony_ci  char buffer[8192];
16213498266Sopenharmony_ci  curl_off_t count;
16313498266Sopenharmony_ci  int ret_stat;
16413498266Sopenharmony_ci  FILE * file;
16513498266Sopenharmony_ci
16613498266Sopenharmony_ci  /* !checksrc! disable FOPENMODE 1 */
16713498266Sopenharmony_ci  file = fopen(name, "r"); /* VMS */
16813498266Sopenharmony_ci  if(!file) {
16913498266Sopenharmony_ci    return 0;
17013498266Sopenharmony_ci  }
17113498266Sopenharmony_ci  count = 0;
17213498266Sopenharmony_ci  ret_stat = 1;
17313498266Sopenharmony_ci  while(ret_stat > 0) {
17413498266Sopenharmony_ci    ret_stat = fread(buffer, 1, sizeof(buffer), file);
17513498266Sopenharmony_ci    if(ret_stat)
17613498266Sopenharmony_ci      count += ret_stat;
17713498266Sopenharmony_ci  }
17813498266Sopenharmony_ci  fclose(file);
17913498266Sopenharmony_ci
18013498266Sopenharmony_ci  return count;
18113498266Sopenharmony_ci}
18213498266Sopenharmony_ci
18313498266Sopenharmony_ci/*
18413498266Sopenharmony_ci *
18513498266Sopenharmony_ci *  VmsSpecialSize checks to see if the stat st_size can be trusted and
18613498266Sopenharmony_ci *  if not to call a routine to get the correct size.
18713498266Sopenharmony_ci *
18813498266Sopenharmony_ci */
18913498266Sopenharmony_cistatic curl_off_t VmsSpecialSize(const char *name,
19013498266Sopenharmony_ci                                 const struct_stat *stat_buf)
19113498266Sopenharmony_ci{
19213498266Sopenharmony_ci  switch(stat_buf->st_fab_rfm) {
19313498266Sopenharmony_ci  case FAB$C_VAR:
19413498266Sopenharmony_ci  case FAB$C_VFC:
19513498266Sopenharmony_ci    return vms_realfilesize(name, stat_buf);
19613498266Sopenharmony_ci    break;
19713498266Sopenharmony_ci  default:
19813498266Sopenharmony_ci    return stat_buf->st_size;
19913498266Sopenharmony_ci  }
20013498266Sopenharmony_ci}
20113498266Sopenharmony_ci#endif /* __VMS */
20213498266Sopenharmony_ci
20313498266Sopenharmony_ci#define BUFFER_SIZE (100*1024)
20413498266Sopenharmony_ci
20513498266Sopenharmony_cistruct per_transfer *transfers; /* first node */
20613498266Sopenharmony_cistatic struct per_transfer *transfersl; /* last node */
20713498266Sopenharmony_cistatic curl_off_t all_pers;
20813498266Sopenharmony_ci
20913498266Sopenharmony_ci/* add_per_transfer creates a new 'per_transfer' node in the linked
21013498266Sopenharmony_ci   list of transfers */
21113498266Sopenharmony_cistatic CURLcode add_per_transfer(struct per_transfer **per)
21213498266Sopenharmony_ci{
21313498266Sopenharmony_ci  struct per_transfer *p;
21413498266Sopenharmony_ci  p = calloc(1, sizeof(struct per_transfer));
21513498266Sopenharmony_ci  if(!p)
21613498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
21713498266Sopenharmony_ci  if(!transfers)
21813498266Sopenharmony_ci    /* first entry */
21913498266Sopenharmony_ci    transfersl = transfers = p;
22013498266Sopenharmony_ci  else {
22113498266Sopenharmony_ci    /* make the last node point to the new node */
22213498266Sopenharmony_ci    transfersl->next = p;
22313498266Sopenharmony_ci    /* make the new node point back to the formerly last node */
22413498266Sopenharmony_ci    p->prev = transfersl;
22513498266Sopenharmony_ci    /* move the last node pointer to the new entry */
22613498266Sopenharmony_ci    transfersl = p;
22713498266Sopenharmony_ci  }
22813498266Sopenharmony_ci  *per = p;
22913498266Sopenharmony_ci  all_xfers++; /* count total number of transfers added */
23013498266Sopenharmony_ci  all_pers++;
23113498266Sopenharmony_ci
23213498266Sopenharmony_ci  return CURLE_OK;
23313498266Sopenharmony_ci}
23413498266Sopenharmony_ci
23513498266Sopenharmony_ci/* Remove the specified transfer from the list (and free it), return the next
23613498266Sopenharmony_ci   in line */
23713498266Sopenharmony_cistatic struct per_transfer *del_per_transfer(struct per_transfer *per)
23813498266Sopenharmony_ci{
23913498266Sopenharmony_ci  struct per_transfer *n;
24013498266Sopenharmony_ci  struct per_transfer *p;
24113498266Sopenharmony_ci  DEBUGASSERT(transfers);
24213498266Sopenharmony_ci  DEBUGASSERT(transfersl);
24313498266Sopenharmony_ci  DEBUGASSERT(per);
24413498266Sopenharmony_ci
24513498266Sopenharmony_ci  n = per->next;
24613498266Sopenharmony_ci  p = per->prev;
24713498266Sopenharmony_ci
24813498266Sopenharmony_ci  if(p)
24913498266Sopenharmony_ci    p->next = n;
25013498266Sopenharmony_ci  else
25113498266Sopenharmony_ci    transfers = n;
25213498266Sopenharmony_ci
25313498266Sopenharmony_ci  if(n)
25413498266Sopenharmony_ci    n->prev = p;
25513498266Sopenharmony_ci  else
25613498266Sopenharmony_ci    transfersl = p;
25713498266Sopenharmony_ci
25813498266Sopenharmony_ci  free(per);
25913498266Sopenharmony_ci  all_pers--;
26013498266Sopenharmony_ci
26113498266Sopenharmony_ci  return n;
26213498266Sopenharmony_ci}
26313498266Sopenharmony_ci
26413498266Sopenharmony_cistatic CURLcode pre_transfer(struct GlobalConfig *global,
26513498266Sopenharmony_ci                             struct per_transfer *per)
26613498266Sopenharmony_ci{
26713498266Sopenharmony_ci  curl_off_t uploadfilesize = -1;
26813498266Sopenharmony_ci  struct_stat fileinfo;
26913498266Sopenharmony_ci  CURLcode result = CURLE_OK;
27013498266Sopenharmony_ci
27113498266Sopenharmony_ci  if(per->uploadfile && !stdin_upload(per->uploadfile)) {
27213498266Sopenharmony_ci    /* VMS Note:
27313498266Sopenharmony_ci     *
27413498266Sopenharmony_ci     * Reading binary from files can be a problem...  Only FIXED, VAR
27513498266Sopenharmony_ci     * etc WITHOUT implied CC will work. Others need a \n appended to
27613498266Sopenharmony_ci     * a line
27713498266Sopenharmony_ci     *
27813498266Sopenharmony_ci     * - Stat gives a size but this is UNRELIABLE in VMS. E.g.
27913498266Sopenharmony_ci     * a fixed file with implied CC needs to have a byte added for every
28013498266Sopenharmony_ci     * record processed, this can be derived from Filesize & recordsize
28113498266Sopenharmony_ci     * for VARiable record files the records need to be counted!  for
28213498266Sopenharmony_ci     * every record add 1 for linefeed and subtract 2 for the record
28313498266Sopenharmony_ci     * header for VARIABLE header files only the bare record data needs
28413498266Sopenharmony_ci     * to be considered with one appended if implied CC
28513498266Sopenharmony_ci     */
28613498266Sopenharmony_ci#ifdef __VMS
28713498266Sopenharmony_ci    /* Calculate the real upload size for VMS */
28813498266Sopenharmony_ci    per->infd = -1;
28913498266Sopenharmony_ci    if(stat(per->uploadfile, &fileinfo) == 0) {
29013498266Sopenharmony_ci      fileinfo.st_size = VmsSpecialSize(uploadfile, &fileinfo);
29113498266Sopenharmony_ci      switch(fileinfo.st_fab_rfm) {
29213498266Sopenharmony_ci      case FAB$C_VAR:
29313498266Sopenharmony_ci      case FAB$C_VFC:
29413498266Sopenharmony_ci      case FAB$C_STMCR:
29513498266Sopenharmony_ci        per->infd = open(per->uploadfile, O_RDONLY | O_BINARY);
29613498266Sopenharmony_ci        break;
29713498266Sopenharmony_ci      default:
29813498266Sopenharmony_ci        per->infd = open(per->uploadfile, O_RDONLY | O_BINARY,
29913498266Sopenharmony_ci                        "rfm=stmlf", "ctx=stm");
30013498266Sopenharmony_ci      }
30113498266Sopenharmony_ci    }
30213498266Sopenharmony_ci    if(per->infd == -1)
30313498266Sopenharmony_ci#else
30413498266Sopenharmony_ci      per->infd = open(per->uploadfile, O_RDONLY | O_BINARY);
30513498266Sopenharmony_ci    if((per->infd == -1) || fstat(per->infd, &fileinfo))
30613498266Sopenharmony_ci#endif
30713498266Sopenharmony_ci    {
30813498266Sopenharmony_ci      helpf(tool_stderr, "Can't open '%s'", per->uploadfile);
30913498266Sopenharmony_ci      if(per->infd != -1) {
31013498266Sopenharmony_ci        close(per->infd);
31113498266Sopenharmony_ci        per->infd = STDIN_FILENO;
31213498266Sopenharmony_ci      }
31313498266Sopenharmony_ci      return CURLE_READ_ERROR;
31413498266Sopenharmony_ci    }
31513498266Sopenharmony_ci    per->infdopen = TRUE;
31613498266Sopenharmony_ci
31713498266Sopenharmony_ci    /* we ignore file size for char/block devices, sockets, etc. */
31813498266Sopenharmony_ci    if(S_ISREG(fileinfo.st_mode))
31913498266Sopenharmony_ci      uploadfilesize = fileinfo.st_size;
32013498266Sopenharmony_ci
32113498266Sopenharmony_ci#ifdef DEBUGBUILD
32213498266Sopenharmony_ci    /* allow dedicated test cases to override */
32313498266Sopenharmony_ci    {
32413498266Sopenharmony_ci      char *ev = getenv("CURL_UPLOAD_SIZE");
32513498266Sopenharmony_ci      if(ev) {
32613498266Sopenharmony_ci        int sz = atoi(ev);
32713498266Sopenharmony_ci        uploadfilesize = (curl_off_t)sz;
32813498266Sopenharmony_ci      }
32913498266Sopenharmony_ci    }
33013498266Sopenharmony_ci#endif
33113498266Sopenharmony_ci
33213498266Sopenharmony_ci    if(uploadfilesize != -1) {
33313498266Sopenharmony_ci      struct OperationConfig *config = per->config; /* for the macro below */
33413498266Sopenharmony_ci#ifdef CURL_DISABLE_LIBCURL_OPTION
33513498266Sopenharmony_ci      (void)config;
33613498266Sopenharmony_ci      (void)global;
33713498266Sopenharmony_ci#endif
33813498266Sopenharmony_ci      my_setopt(per->curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
33913498266Sopenharmony_ci    }
34013498266Sopenharmony_ci  }
34113498266Sopenharmony_ci  per->uploadfilesize = uploadfilesize;
34213498266Sopenharmony_ci  per->start = tvnow();
34313498266Sopenharmony_ci  return result;
34413498266Sopenharmony_ci}
34513498266Sopenharmony_ci
34613498266Sopenharmony_ci/* When doing serial transfers, we use a single fixed error area */
34713498266Sopenharmony_cistatic char global_errorbuffer[CURL_ERROR_SIZE];
34813498266Sopenharmony_ci
34913498266Sopenharmony_civoid single_transfer_cleanup(struct OperationConfig *config)
35013498266Sopenharmony_ci{
35113498266Sopenharmony_ci  if(config) {
35213498266Sopenharmony_ci    struct State *state = &config->state;
35313498266Sopenharmony_ci    if(state->urls) {
35413498266Sopenharmony_ci      /* Free list of remaining URLs */
35513498266Sopenharmony_ci      glob_cleanup(state->urls);
35613498266Sopenharmony_ci      state->urls = NULL;
35713498266Sopenharmony_ci    }
35813498266Sopenharmony_ci    Curl_safefree(state->outfiles);
35913498266Sopenharmony_ci    Curl_safefree(state->uploadfile);
36013498266Sopenharmony_ci    if(state->inglob) {
36113498266Sopenharmony_ci      /* Free list of globbed upload files */
36213498266Sopenharmony_ci      glob_cleanup(state->inglob);
36313498266Sopenharmony_ci      state->inglob = NULL;
36413498266Sopenharmony_ci    }
36513498266Sopenharmony_ci  }
36613498266Sopenharmony_ci}
36713498266Sopenharmony_ci
36813498266Sopenharmony_ci/*
36913498266Sopenharmony_ci * Call this after a transfer has completed.
37013498266Sopenharmony_ci */
37113498266Sopenharmony_cistatic CURLcode post_per_transfer(struct GlobalConfig *global,
37213498266Sopenharmony_ci                                  struct per_transfer *per,
37313498266Sopenharmony_ci                                  CURLcode result,
37413498266Sopenharmony_ci                                  bool *retryp,
37513498266Sopenharmony_ci                                  long *delay) /* milliseconds! */
37613498266Sopenharmony_ci{
37713498266Sopenharmony_ci  struct OutStruct *outs = &per->outs;
37813498266Sopenharmony_ci  CURL *curl = per->curl;
37913498266Sopenharmony_ci  struct OperationConfig *config = per->config;
38013498266Sopenharmony_ci  int rc;
38113498266Sopenharmony_ci
38213498266Sopenharmony_ci  if(!curl || !config)
38313498266Sopenharmony_ci    return result;
38413498266Sopenharmony_ci
38513498266Sopenharmony_ci  *retryp = FALSE;
38613498266Sopenharmony_ci  *delay = 0; /* for no retry, keep it zero */
38713498266Sopenharmony_ci
38813498266Sopenharmony_ci  if(per->infdopen)
38913498266Sopenharmony_ci    close(per->infd);
39013498266Sopenharmony_ci
39113498266Sopenharmony_ci#ifdef __VMS
39213498266Sopenharmony_ci  if(is_vms_shell()) {
39313498266Sopenharmony_ci    /* VMS DCL shell behavior */
39413498266Sopenharmony_ci    if(global->silent && !global->showerror)
39513498266Sopenharmony_ci      vms_show = VMSSTS_HIDE;
39613498266Sopenharmony_ci  }
39713498266Sopenharmony_ci  else
39813498266Sopenharmony_ci#endif
39913498266Sopenharmony_ci    if(!config->synthetic_error && result &&
40013498266Sopenharmony_ci       (!global->silent || global->showerror)) {
40113498266Sopenharmony_ci      const char *msg = per->errorbuffer;
40213498266Sopenharmony_ci      fprintf(tool_stderr, "curl: (%d) %s\n", result,
40313498266Sopenharmony_ci              (msg && msg[0]) ? msg : curl_easy_strerror(result));
40413498266Sopenharmony_ci      if(result == CURLE_PEER_FAILED_VERIFICATION)
40513498266Sopenharmony_ci        fputs(CURL_CA_CERT_ERRORMSG, tool_stderr);
40613498266Sopenharmony_ci    }
40713498266Sopenharmony_ci    else if(config->failwithbody) {
40813498266Sopenharmony_ci      /* if HTTP response >= 400, return error */
40913498266Sopenharmony_ci      long code = 0;
41013498266Sopenharmony_ci      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
41113498266Sopenharmony_ci      if(code >= 400) {
41213498266Sopenharmony_ci        if(!global->silent || global->showerror)
41313498266Sopenharmony_ci          fprintf(tool_stderr,
41413498266Sopenharmony_ci                  "curl: (%d) The requested URL returned error: %ld\n",
41513498266Sopenharmony_ci                  CURLE_HTTP_RETURNED_ERROR, code);
41613498266Sopenharmony_ci        result = CURLE_HTTP_RETURNED_ERROR;
41713498266Sopenharmony_ci      }
41813498266Sopenharmony_ci    }
41913498266Sopenharmony_ci  /* Set file extended attributes */
42013498266Sopenharmony_ci  if(!result && config->xattr && outs->fopened && outs->stream) {
42113498266Sopenharmony_ci    rc = fwrite_xattr(curl, per->this_url, fileno(outs->stream));
42213498266Sopenharmony_ci    if(rc)
42313498266Sopenharmony_ci      warnf(config->global, "Error setting extended attributes on '%s': %s",
42413498266Sopenharmony_ci            outs->filename, strerror(errno));
42513498266Sopenharmony_ci  }
42613498266Sopenharmony_ci
42713498266Sopenharmony_ci  if(!result && !outs->stream && !outs->bytes) {
42813498266Sopenharmony_ci    /* we have received no data despite the transfer was successful
42913498266Sopenharmony_ci       ==> force creation of an empty output file (if an output file
43013498266Sopenharmony_ci       was specified) */
43113498266Sopenharmony_ci    long cond_unmet = 0L;
43213498266Sopenharmony_ci    /* do not create (or even overwrite) the file in case we get no
43313498266Sopenharmony_ci       data because of unmet condition */
43413498266Sopenharmony_ci    curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &cond_unmet);
43513498266Sopenharmony_ci    if(!cond_unmet && !tool_create_output_file(outs, config))
43613498266Sopenharmony_ci      result = CURLE_WRITE_ERROR;
43713498266Sopenharmony_ci  }
43813498266Sopenharmony_ci
43913498266Sopenharmony_ci  if(!outs->s_isreg && outs->stream) {
44013498266Sopenharmony_ci    /* Dump standard stream buffered data */
44113498266Sopenharmony_ci    rc = fflush(outs->stream);
44213498266Sopenharmony_ci    if(!result && rc) {
44313498266Sopenharmony_ci      /* something went wrong in the writing process */
44413498266Sopenharmony_ci      result = CURLE_WRITE_ERROR;
44513498266Sopenharmony_ci      errorf(global, "Failed writing body");
44613498266Sopenharmony_ci    }
44713498266Sopenharmony_ci  }
44813498266Sopenharmony_ci
44913498266Sopenharmony_ci#ifdef _WIN32
45013498266Sopenharmony_ci  /* Discard incomplete UTF-8 sequence buffered from body */
45113498266Sopenharmony_ci  if(outs->utf8seq[0])
45213498266Sopenharmony_ci    memset(outs->utf8seq, 0, sizeof(outs->utf8seq));
45313498266Sopenharmony_ci#endif
45413498266Sopenharmony_ci
45513498266Sopenharmony_ci  /* if retry-max-time is non-zero, make sure we haven't exceeded the
45613498266Sopenharmony_ci     time */
45713498266Sopenharmony_ci  if(per->retry_numretries &&
45813498266Sopenharmony_ci     (!config->retry_maxtime ||
45913498266Sopenharmony_ci      (tvdiff(tvnow(), per->retrystart) <
46013498266Sopenharmony_ci       config->retry_maxtime*1000L)) ) {
46113498266Sopenharmony_ci    enum {
46213498266Sopenharmony_ci      RETRY_NO,
46313498266Sopenharmony_ci      RETRY_ALL_ERRORS,
46413498266Sopenharmony_ci      RETRY_TIMEOUT,
46513498266Sopenharmony_ci      RETRY_CONNREFUSED,
46613498266Sopenharmony_ci      RETRY_HTTP,
46713498266Sopenharmony_ci      RETRY_FTP,
46813498266Sopenharmony_ci      RETRY_LAST /* not used */
46913498266Sopenharmony_ci    } retry = RETRY_NO;
47013498266Sopenharmony_ci    long response = 0;
47113498266Sopenharmony_ci    if((CURLE_OPERATION_TIMEDOUT == result) ||
47213498266Sopenharmony_ci       (CURLE_COULDNT_RESOLVE_HOST == result) ||
47313498266Sopenharmony_ci       (CURLE_COULDNT_RESOLVE_PROXY == result) ||
47413498266Sopenharmony_ci       (CURLE_FTP_ACCEPT_TIMEOUT == result))
47513498266Sopenharmony_ci      /* retry timeout always */
47613498266Sopenharmony_ci      retry = RETRY_TIMEOUT;
47713498266Sopenharmony_ci    else if(config->retry_connrefused &&
47813498266Sopenharmony_ci            (CURLE_COULDNT_CONNECT == result)) {
47913498266Sopenharmony_ci      long oserrno = 0;
48013498266Sopenharmony_ci      curl_easy_getinfo(curl, CURLINFO_OS_ERRNO, &oserrno);
48113498266Sopenharmony_ci      if(ECONNREFUSED == oserrno)
48213498266Sopenharmony_ci        retry = RETRY_CONNREFUSED;
48313498266Sopenharmony_ci    }
48413498266Sopenharmony_ci    else if((CURLE_OK == result) ||
48513498266Sopenharmony_ci            ((config->failonerror || config->failwithbody) &&
48613498266Sopenharmony_ci             (CURLE_HTTP_RETURNED_ERROR == result))) {
48713498266Sopenharmony_ci      /* If it returned OK. _or_ failonerror was enabled and it
48813498266Sopenharmony_ci         returned due to such an error, check for HTTP transient
48913498266Sopenharmony_ci         errors to retry on. */
49013498266Sopenharmony_ci      const char *scheme;
49113498266Sopenharmony_ci      curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme);
49213498266Sopenharmony_ci      scheme = proto_token(scheme);
49313498266Sopenharmony_ci      if(scheme == proto_http || scheme == proto_https) {
49413498266Sopenharmony_ci        /* This was HTTP(S) */
49513498266Sopenharmony_ci        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
49613498266Sopenharmony_ci
49713498266Sopenharmony_ci        switch(response) {
49813498266Sopenharmony_ci        case 408: /* Request Timeout */
49913498266Sopenharmony_ci        case 429: /* Too Many Requests (RFC6585) */
50013498266Sopenharmony_ci        case 500: /* Internal Server Error */
50113498266Sopenharmony_ci        case 502: /* Bad Gateway */
50213498266Sopenharmony_ci        case 503: /* Service Unavailable */
50313498266Sopenharmony_ci        case 504: /* Gateway Timeout */
50413498266Sopenharmony_ci          retry = RETRY_HTTP;
50513498266Sopenharmony_ci          /*
50613498266Sopenharmony_ci           * At this point, we have already written data to the output
50713498266Sopenharmony_ci           * file (or terminal). If we write to a file, we must rewind
50813498266Sopenharmony_ci           * or close/re-open the file so that the next attempt starts
50913498266Sopenharmony_ci           * over from the beginning.
51013498266Sopenharmony_ci           *
51113498266Sopenharmony_ci           * TODO: similar action for the upload case. We might need
51213498266Sopenharmony_ci           * to start over reading from a previous point if we have
51313498266Sopenharmony_ci           * uploaded something when this was returned.
51413498266Sopenharmony_ci           */
51513498266Sopenharmony_ci          break;
51613498266Sopenharmony_ci        }
51713498266Sopenharmony_ci      }
51813498266Sopenharmony_ci    } /* if CURLE_OK */
51913498266Sopenharmony_ci    else if(result) {
52013498266Sopenharmony_ci      const char *scheme;
52113498266Sopenharmony_ci
52213498266Sopenharmony_ci      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
52313498266Sopenharmony_ci      curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme);
52413498266Sopenharmony_ci      scheme = proto_token(scheme);
52513498266Sopenharmony_ci
52613498266Sopenharmony_ci      if((scheme == proto_ftp || scheme == proto_ftps) && response / 100 == 4)
52713498266Sopenharmony_ci        /*
52813498266Sopenharmony_ci         * This is typically when the FTP server only allows a certain
52913498266Sopenharmony_ci         * amount of users and we are not one of them.  All 4xx codes
53013498266Sopenharmony_ci         * are transient.
53113498266Sopenharmony_ci         */
53213498266Sopenharmony_ci        retry = RETRY_FTP;
53313498266Sopenharmony_ci    }
53413498266Sopenharmony_ci
53513498266Sopenharmony_ci    if(result && !retry && config->retry_all_errors)
53613498266Sopenharmony_ci      retry = RETRY_ALL_ERRORS;
53713498266Sopenharmony_ci
53813498266Sopenharmony_ci    if(retry) {
53913498266Sopenharmony_ci      long sleeptime = 0;
54013498266Sopenharmony_ci      curl_off_t retry_after = 0;
54113498266Sopenharmony_ci      static const char * const m[]={
54213498266Sopenharmony_ci        NULL,
54313498266Sopenharmony_ci        "(retrying all errors)",
54413498266Sopenharmony_ci        ": timeout",
54513498266Sopenharmony_ci        ": connection refused",
54613498266Sopenharmony_ci        ": HTTP error",
54713498266Sopenharmony_ci        ": FTP error"
54813498266Sopenharmony_ci      };
54913498266Sopenharmony_ci
55013498266Sopenharmony_ci      sleeptime = per->retry_sleep;
55113498266Sopenharmony_ci      if(RETRY_HTTP == retry) {
55213498266Sopenharmony_ci        curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after);
55313498266Sopenharmony_ci        if(retry_after) {
55413498266Sopenharmony_ci          /* store in a 'long', make sure it doesn't overflow */
55513498266Sopenharmony_ci          if(retry_after > LONG_MAX/1000)
55613498266Sopenharmony_ci            sleeptime = LONG_MAX;
55713498266Sopenharmony_ci          else
55813498266Sopenharmony_ci            sleeptime = (long)retry_after * 1000; /* milliseconds */
55913498266Sopenharmony_ci
56013498266Sopenharmony_ci          /* if adding retry_after seconds to the process would exceed the
56113498266Sopenharmony_ci             maximum time allowed for retrying, then exit the retries right
56213498266Sopenharmony_ci             away */
56313498266Sopenharmony_ci          if(config->retry_maxtime) {
56413498266Sopenharmony_ci            curl_off_t seconds = tvdiff(tvnow(), per->retrystart)/1000;
56513498266Sopenharmony_ci
56613498266Sopenharmony_ci            if((CURL_OFF_T_MAX - retry_after < seconds) ||
56713498266Sopenharmony_ci               (seconds + retry_after > config->retry_maxtime)) {
56813498266Sopenharmony_ci              warnf(config->global, "The Retry-After: time would "
56913498266Sopenharmony_ci                    "make this command line exceed the maximum allowed time "
57013498266Sopenharmony_ci                    "for retries.");
57113498266Sopenharmony_ci              goto noretry;
57213498266Sopenharmony_ci            }
57313498266Sopenharmony_ci          }
57413498266Sopenharmony_ci        }
57513498266Sopenharmony_ci      }
57613498266Sopenharmony_ci      warnf(config->global, "Problem %s. "
57713498266Sopenharmony_ci            "Will retry in %ld seconds. "
57813498266Sopenharmony_ci            "%ld retries left.",
57913498266Sopenharmony_ci            m[retry], sleeptime/1000L, per->retry_numretries);
58013498266Sopenharmony_ci
58113498266Sopenharmony_ci      per->retry_numretries--;
58213498266Sopenharmony_ci      if(!config->retry_delay) {
58313498266Sopenharmony_ci        per->retry_sleep *= 2;
58413498266Sopenharmony_ci        if(per->retry_sleep > RETRY_SLEEP_MAX)
58513498266Sopenharmony_ci          per->retry_sleep = RETRY_SLEEP_MAX;
58613498266Sopenharmony_ci      }
58713498266Sopenharmony_ci      if(outs->bytes && outs->filename && outs->stream) {
58813498266Sopenharmony_ci        /* We have written data to an output file, we truncate file
58913498266Sopenharmony_ci         */
59013498266Sopenharmony_ci        notef(config->global,
59113498266Sopenharmony_ci              "Throwing away %"  CURL_FORMAT_CURL_OFF_T " bytes",
59213498266Sopenharmony_ci              outs->bytes);
59313498266Sopenharmony_ci        fflush(outs->stream);
59413498266Sopenharmony_ci        /* truncate file at the position where we started appending */
59513498266Sopenharmony_ci#ifdef HAVE_FTRUNCATE
59613498266Sopenharmony_ci        if(ftruncate(fileno(outs->stream), outs->init)) {
59713498266Sopenharmony_ci          /* when truncate fails, we can't just append as then we'll
59813498266Sopenharmony_ci             create something strange, bail out */
59913498266Sopenharmony_ci          errorf(config->global, "Failed to truncate file");
60013498266Sopenharmony_ci          return CURLE_WRITE_ERROR;
60113498266Sopenharmony_ci        }
60213498266Sopenharmony_ci        /* now seek to the end of the file, the position where we
60313498266Sopenharmony_ci           just truncated the file in a large file-safe way */
60413498266Sopenharmony_ci        rc = fseek(outs->stream, 0, SEEK_END);
60513498266Sopenharmony_ci#else
60613498266Sopenharmony_ci        /* ftruncate is not available, so just reposition the file
60713498266Sopenharmony_ci           to the location we would have truncated it. This won't
60813498266Sopenharmony_ci           work properly with large files on 32-bit systems, but
60913498266Sopenharmony_ci           most of those will have ftruncate. */
61013498266Sopenharmony_ci        rc = fseek(outs->stream, (long)outs->init, SEEK_SET);
61113498266Sopenharmony_ci#endif
61213498266Sopenharmony_ci        if(rc) {
61313498266Sopenharmony_ci          errorf(config->global, "Failed seeking to end of file");
61413498266Sopenharmony_ci          return CURLE_WRITE_ERROR;
61513498266Sopenharmony_ci        }
61613498266Sopenharmony_ci        outs->bytes = 0; /* clear for next round */
61713498266Sopenharmony_ci      }
61813498266Sopenharmony_ci      *retryp = TRUE;
61913498266Sopenharmony_ci      *delay = sleeptime;
62013498266Sopenharmony_ci      return CURLE_OK;
62113498266Sopenharmony_ci    }
62213498266Sopenharmony_ci  } /* if retry_numretries */
62313498266Sopenharmony_cinoretry:
62413498266Sopenharmony_ci
62513498266Sopenharmony_ci  if((global->progressmode == CURL_PROGRESS_BAR) &&
62613498266Sopenharmony_ci     per->progressbar.calls)
62713498266Sopenharmony_ci    /* if the custom progress bar has been displayed, we output a
62813498266Sopenharmony_ci       newline here */
62913498266Sopenharmony_ci    fputs("\n", per->progressbar.out);
63013498266Sopenharmony_ci
63113498266Sopenharmony_ci  /* Close the outs file */
63213498266Sopenharmony_ci  if(outs->fopened && outs->stream) {
63313498266Sopenharmony_ci    rc = fclose(outs->stream);
63413498266Sopenharmony_ci    if(!result && rc) {
63513498266Sopenharmony_ci      /* something went wrong in the writing process */
63613498266Sopenharmony_ci      result = CURLE_WRITE_ERROR;
63713498266Sopenharmony_ci      errorf(config->global, "curl: (%d) Failed writing body", result);
63813498266Sopenharmony_ci    }
63913498266Sopenharmony_ci    if(result && config->rm_partial) {
64013498266Sopenharmony_ci      struct_stat st;
64113498266Sopenharmony_ci      if(!stat(outs->filename, &st) &&
64213498266Sopenharmony_ci         S_ISREG(st.st_mode)) {
64313498266Sopenharmony_ci        if(!unlink(outs->filename))
64413498266Sopenharmony_ci          notef(global, "Removed output file: %s", outs->filename);
64513498266Sopenharmony_ci        else
64613498266Sopenharmony_ci          warnf(global, "Failed removing: %s", outs->filename);
64713498266Sopenharmony_ci      }
64813498266Sopenharmony_ci      else
64913498266Sopenharmony_ci        warnf(global, "Skipping removal; not a regular file: %s",
65013498266Sopenharmony_ci              outs->filename);
65113498266Sopenharmony_ci    }
65213498266Sopenharmony_ci  }
65313498266Sopenharmony_ci
65413498266Sopenharmony_ci  /* File time can only be set _after_ the file has been closed */
65513498266Sopenharmony_ci  if(!result && config->remote_time && outs->s_isreg && outs->filename) {
65613498266Sopenharmony_ci    /* Ask libcurl if we got a remote file time */
65713498266Sopenharmony_ci    curl_off_t filetime = -1;
65813498266Sopenharmony_ci    curl_easy_getinfo(curl, CURLINFO_FILETIME_T, &filetime);
65913498266Sopenharmony_ci    setfiletime(filetime, outs->filename, global);
66013498266Sopenharmony_ci  }
66113498266Sopenharmony_ci
66213498266Sopenharmony_ci  /* Write the --write-out data before cleanup but after result is final */
66313498266Sopenharmony_ci  if(config->writeout)
66413498266Sopenharmony_ci    ourWriteOut(config, per, result);
66513498266Sopenharmony_ci
66613498266Sopenharmony_ci  /* Close function-local opened file descriptors */
66713498266Sopenharmony_ci  if(per->heads.fopened && per->heads.stream)
66813498266Sopenharmony_ci    fclose(per->heads.stream);
66913498266Sopenharmony_ci
67013498266Sopenharmony_ci  if(per->heads.alloc_filename)
67113498266Sopenharmony_ci    Curl_safefree(per->heads.filename);
67213498266Sopenharmony_ci
67313498266Sopenharmony_ci  if(per->etag_save.fopened && per->etag_save.stream)
67413498266Sopenharmony_ci    fclose(per->etag_save.stream);
67513498266Sopenharmony_ci
67613498266Sopenharmony_ci  if(per->etag_save.alloc_filename)
67713498266Sopenharmony_ci    Curl_safefree(per->etag_save.filename);
67813498266Sopenharmony_ci
67913498266Sopenharmony_ci  curl_easy_cleanup(per->curl);
68013498266Sopenharmony_ci  if(outs->alloc_filename)
68113498266Sopenharmony_ci    free(outs->filename);
68213498266Sopenharmony_ci  free(per->this_url);
68313498266Sopenharmony_ci  free(per->outfile);
68413498266Sopenharmony_ci  free(per->uploadfile);
68513498266Sopenharmony_ci  if(global->parallel)
68613498266Sopenharmony_ci    free(per->errorbuffer);
68713498266Sopenharmony_ci
68813498266Sopenharmony_ci  return result;
68913498266Sopenharmony_ci}
69013498266Sopenharmony_ci
69113498266Sopenharmony_ci/*
69213498266Sopenharmony_ci * Return the protocol token for the scheme used in the given URL
69313498266Sopenharmony_ci */
69413498266Sopenharmony_cistatic CURLcode url_proto(char **url,
69513498266Sopenharmony_ci                          struct OperationConfig *config,
69613498266Sopenharmony_ci                          char **scheme)
69713498266Sopenharmony_ci{
69813498266Sopenharmony_ci  CURLcode result = CURLE_OK;
69913498266Sopenharmony_ci  CURLU *uh = curl_url();
70013498266Sopenharmony_ci  const char *proto = NULL;
70113498266Sopenharmony_ci  *scheme = NULL;
70213498266Sopenharmony_ci
70313498266Sopenharmony_ci  if(uh) {
70413498266Sopenharmony_ci    if(*url) {
70513498266Sopenharmony_ci      char *schemep = NULL;
70613498266Sopenharmony_ci
70713498266Sopenharmony_ci      if(!curl_url_set(uh, CURLUPART_URL, *url,
70813498266Sopenharmony_ci                       CURLU_GUESS_SCHEME | CURLU_NON_SUPPORT_SCHEME) &&
70913498266Sopenharmony_ci         !curl_url_get(uh, CURLUPART_SCHEME, &schemep,
71013498266Sopenharmony_ci                       CURLU_DEFAULT_SCHEME)) {
71113498266Sopenharmony_ci        if(curl_strequal(schemep, proto_ipfs) ||
71213498266Sopenharmony_ci           curl_strequal(schemep, proto_ipns)) {
71313498266Sopenharmony_ci          result = ipfs_url_rewrite(uh, schemep, url, config);
71413498266Sopenharmony_ci          /* short-circuit proto_token, we know it's ipfs or ipns */
71513498266Sopenharmony_ci          if(curl_strequal(schemep, proto_ipfs))
71613498266Sopenharmony_ci            proto = proto_ipfs;
71713498266Sopenharmony_ci          else if(curl_strequal(schemep, proto_ipns))
71813498266Sopenharmony_ci            proto = proto_ipns;
71913498266Sopenharmony_ci          if(result)
72013498266Sopenharmony_ci            config->synthetic_error = TRUE;
72113498266Sopenharmony_ci        }
72213498266Sopenharmony_ci        else
72313498266Sopenharmony_ci          proto = proto_token(schemep);
72413498266Sopenharmony_ci
72513498266Sopenharmony_ci        curl_free(schemep);
72613498266Sopenharmony_ci      }
72713498266Sopenharmony_ci    }
72813498266Sopenharmony_ci    curl_url_cleanup(uh);
72913498266Sopenharmony_ci  }
73013498266Sopenharmony_ci
73113498266Sopenharmony_ci  *scheme = (char *) (proto? proto: "???");   /* Never match if not found. */
73213498266Sopenharmony_ci  return result;
73313498266Sopenharmony_ci}
73413498266Sopenharmony_ci
73513498266Sopenharmony_ci/* create the next (singular) transfer */
73613498266Sopenharmony_cistatic CURLcode single_transfer(struct GlobalConfig *global,
73713498266Sopenharmony_ci                                struct OperationConfig *config,
73813498266Sopenharmony_ci                                CURLSH *share,
73913498266Sopenharmony_ci                                bool capath_from_env,
74013498266Sopenharmony_ci                                bool *added)
74113498266Sopenharmony_ci{
74213498266Sopenharmony_ci  CURLcode result = CURLE_OK;
74313498266Sopenharmony_ci  struct getout *urlnode;
74413498266Sopenharmony_ci  bool orig_noprogress = global->noprogress;
74513498266Sopenharmony_ci  bool orig_isatty = global->isatty;
74613498266Sopenharmony_ci  struct State *state = &config->state;
74713498266Sopenharmony_ci  char *httpgetfields = state->httpgetfields;
74813498266Sopenharmony_ci
74913498266Sopenharmony_ci  *added = FALSE; /* not yet */
75013498266Sopenharmony_ci
75113498266Sopenharmony_ci  if(config->postfields) {
75213498266Sopenharmony_ci    if(config->use_httpget) {
75313498266Sopenharmony_ci      if(!httpgetfields) {
75413498266Sopenharmony_ci        /* Use the postfields data for an HTTP get */
75513498266Sopenharmony_ci        httpgetfields = state->httpgetfields = config->postfields;
75613498266Sopenharmony_ci        config->postfields = NULL;
75713498266Sopenharmony_ci        if(SetHTTPrequest(config,
75813498266Sopenharmony_ci                          (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
75913498266Sopenharmony_ci                          &config->httpreq)) {
76013498266Sopenharmony_ci          result = CURLE_FAILED_INIT;
76113498266Sopenharmony_ci        }
76213498266Sopenharmony_ci      }
76313498266Sopenharmony_ci    }
76413498266Sopenharmony_ci    else {
76513498266Sopenharmony_ci      if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq))
76613498266Sopenharmony_ci        result = CURLE_FAILED_INIT;
76713498266Sopenharmony_ci    }
76813498266Sopenharmony_ci    if(result) {
76913498266Sopenharmony_ci      single_transfer_cleanup(config);
77013498266Sopenharmony_ci      return result;
77113498266Sopenharmony_ci    }
77213498266Sopenharmony_ci  }
77313498266Sopenharmony_ci  if(!state->urlnode) {
77413498266Sopenharmony_ci    /* first time caller, setup things */
77513498266Sopenharmony_ci    state->urlnode = config->url_list;
77613498266Sopenharmony_ci    state->infilenum = 1;
77713498266Sopenharmony_ci  }
77813498266Sopenharmony_ci
77913498266Sopenharmony_ci  while(config->state.urlnode) {
78013498266Sopenharmony_ci    static bool warn_more_options = FALSE;
78113498266Sopenharmony_ci    char *infiles; /* might be a glob pattern */
78213498266Sopenharmony_ci    struct URLGlob *inglob = state->inglob;
78313498266Sopenharmony_ci    urlnode = config->state.urlnode;
78413498266Sopenharmony_ci
78513498266Sopenharmony_ci    /* urlnode->url is the full URL (it might be NULL) */
78613498266Sopenharmony_ci
78713498266Sopenharmony_ci    if(!urlnode->url) {
78813498266Sopenharmony_ci      /* This node has no URL. Free node data without destroying the
78913498266Sopenharmony_ci         node itself nor modifying next pointer and continue to next */
79013498266Sopenharmony_ci      Curl_safefree(urlnode->outfile);
79113498266Sopenharmony_ci      Curl_safefree(urlnode->infile);
79213498266Sopenharmony_ci      urlnode->flags = 0;
79313498266Sopenharmony_ci      config->state.urlnode = urlnode->next;
79413498266Sopenharmony_ci      state->up = 0;
79513498266Sopenharmony_ci      if(!warn_more_options) {
79613498266Sopenharmony_ci        /* only show this once */
79713498266Sopenharmony_ci        warnf(config->global, "Got more output options than URLs");
79813498266Sopenharmony_ci        warn_more_options = TRUE;
79913498266Sopenharmony_ci      }
80013498266Sopenharmony_ci      continue; /* next URL please */
80113498266Sopenharmony_ci    }
80213498266Sopenharmony_ci
80313498266Sopenharmony_ci    /* save outfile pattern before expansion */
80413498266Sopenharmony_ci    if(urlnode->outfile && !state->outfiles) {
80513498266Sopenharmony_ci      state->outfiles = strdup(urlnode->outfile);
80613498266Sopenharmony_ci      if(!state->outfiles) {
80713498266Sopenharmony_ci        errorf(global, "out of memory");
80813498266Sopenharmony_ci        result = CURLE_OUT_OF_MEMORY;
80913498266Sopenharmony_ci        break;
81013498266Sopenharmony_ci      }
81113498266Sopenharmony_ci    }
81213498266Sopenharmony_ci
81313498266Sopenharmony_ci    infiles = urlnode->infile;
81413498266Sopenharmony_ci
81513498266Sopenharmony_ci    if(!config->globoff && infiles && !inglob) {
81613498266Sopenharmony_ci      /* Unless explicitly shut off */
81713498266Sopenharmony_ci      result = glob_url(&inglob, infiles, &state->infilenum,
81813498266Sopenharmony_ci                        (!global->silent || global->showerror)?
81913498266Sopenharmony_ci                        tool_stderr:NULL);
82013498266Sopenharmony_ci      if(result)
82113498266Sopenharmony_ci        break;
82213498266Sopenharmony_ci      config->state.inglob = inglob;
82313498266Sopenharmony_ci    }
82413498266Sopenharmony_ci
82513498266Sopenharmony_ci    {
82613498266Sopenharmony_ci      curl_off_t urlnum;
82713498266Sopenharmony_ci
82813498266Sopenharmony_ci      if(!state->up && !infiles)
82913498266Sopenharmony_ci        Curl_nop_stmt;
83013498266Sopenharmony_ci      else {
83113498266Sopenharmony_ci        if(!state->uploadfile) {
83213498266Sopenharmony_ci          if(inglob) {
83313498266Sopenharmony_ci            result = glob_next_url(&state->uploadfile, inglob);
83413498266Sopenharmony_ci            if(result == CURLE_OUT_OF_MEMORY)
83513498266Sopenharmony_ci              errorf(global, "out of memory");
83613498266Sopenharmony_ci          }
83713498266Sopenharmony_ci          else if(!state->up) {
83813498266Sopenharmony_ci            state->uploadfile = strdup(infiles);
83913498266Sopenharmony_ci            if(!state->uploadfile) {
84013498266Sopenharmony_ci              errorf(global, "out of memory");
84113498266Sopenharmony_ci              result = CURLE_OUT_OF_MEMORY;
84213498266Sopenharmony_ci            }
84313498266Sopenharmony_ci          }
84413498266Sopenharmony_ci        }
84513498266Sopenharmony_ci        if(result)
84613498266Sopenharmony_ci          break;
84713498266Sopenharmony_ci      }
84813498266Sopenharmony_ci
84913498266Sopenharmony_ci      if(!state->urlnum) {
85013498266Sopenharmony_ci        if(!config->globoff) {
85113498266Sopenharmony_ci          /* Unless explicitly shut off, we expand '{...}' and '[...]'
85213498266Sopenharmony_ci             expressions and return total number of URLs in pattern set */
85313498266Sopenharmony_ci          result = glob_url(&state->urls, urlnode->url, &state->urlnum,
85413498266Sopenharmony_ci                            (!global->silent || global->showerror)?
85513498266Sopenharmony_ci                            tool_stderr:NULL);
85613498266Sopenharmony_ci          if(result)
85713498266Sopenharmony_ci            break;
85813498266Sopenharmony_ci          urlnum = state->urlnum;
85913498266Sopenharmony_ci        }
86013498266Sopenharmony_ci        else
86113498266Sopenharmony_ci          urlnum = 1; /* without globbing, this is a single URL */
86213498266Sopenharmony_ci      }
86313498266Sopenharmony_ci      else
86413498266Sopenharmony_ci        urlnum = state->urlnum;
86513498266Sopenharmony_ci
86613498266Sopenharmony_ci      if(state->up < state->infilenum) {
86713498266Sopenharmony_ci        struct per_transfer *per = NULL;
86813498266Sopenharmony_ci        struct OutStruct *outs;
86913498266Sopenharmony_ci        struct OutStruct *heads;
87013498266Sopenharmony_ci        struct OutStruct *etag_save;
87113498266Sopenharmony_ci        struct HdrCbData *hdrcbdata = NULL;
87213498266Sopenharmony_ci        struct OutStruct etag_first;
87313498266Sopenharmony_ci        char *use_proto;
87413498266Sopenharmony_ci        CURL *curl;
87513498266Sopenharmony_ci
87613498266Sopenharmony_ci        /* --etag-save */
87713498266Sopenharmony_ci        memset(&etag_first, 0, sizeof(etag_first));
87813498266Sopenharmony_ci        etag_save = &etag_first;
87913498266Sopenharmony_ci        etag_save->stream = stdout;
88013498266Sopenharmony_ci
88113498266Sopenharmony_ci        /* --etag-compare */
88213498266Sopenharmony_ci        if(config->etag_compare_file) {
88313498266Sopenharmony_ci          char *etag_from_file = NULL;
88413498266Sopenharmony_ci          char *header = NULL;
88513498266Sopenharmony_ci          ParameterError pe;
88613498266Sopenharmony_ci
88713498266Sopenharmony_ci          /* open file for reading: */
88813498266Sopenharmony_ci          FILE *file = fopen(config->etag_compare_file, FOPEN_READTEXT);
88913498266Sopenharmony_ci          if(!file && !config->etag_save_file) {
89013498266Sopenharmony_ci            errorf(global,
89113498266Sopenharmony_ci                   "Failed to open %s", config->etag_compare_file);
89213498266Sopenharmony_ci            result = CURLE_READ_ERROR;
89313498266Sopenharmony_ci            break;
89413498266Sopenharmony_ci          }
89513498266Sopenharmony_ci
89613498266Sopenharmony_ci          if((PARAM_OK == file2string(&etag_from_file, file)) &&
89713498266Sopenharmony_ci             etag_from_file) {
89813498266Sopenharmony_ci            header = aprintf("If-None-Match: %s", etag_from_file);
89913498266Sopenharmony_ci            Curl_safefree(etag_from_file);
90013498266Sopenharmony_ci          }
90113498266Sopenharmony_ci          else
90213498266Sopenharmony_ci            header = aprintf("If-None-Match: \"\"");
90313498266Sopenharmony_ci
90413498266Sopenharmony_ci          if(!header) {
90513498266Sopenharmony_ci            if(file)
90613498266Sopenharmony_ci              fclose(file);
90713498266Sopenharmony_ci            errorf(global,
90813498266Sopenharmony_ci                   "Failed to allocate memory for custom etag header");
90913498266Sopenharmony_ci            result = CURLE_OUT_OF_MEMORY;
91013498266Sopenharmony_ci            break;
91113498266Sopenharmony_ci          }
91213498266Sopenharmony_ci
91313498266Sopenharmony_ci          /* add Etag from file to list of custom headers */
91413498266Sopenharmony_ci          pe = add2list(&config->headers, header);
91513498266Sopenharmony_ci          Curl_safefree(header);
91613498266Sopenharmony_ci
91713498266Sopenharmony_ci          if(file)
91813498266Sopenharmony_ci            fclose(file);
91913498266Sopenharmony_ci          if(pe != PARAM_OK) {
92013498266Sopenharmony_ci            result = CURLE_OUT_OF_MEMORY;
92113498266Sopenharmony_ci            break;
92213498266Sopenharmony_ci          }
92313498266Sopenharmony_ci        }
92413498266Sopenharmony_ci
92513498266Sopenharmony_ci        if(config->etag_save_file) {
92613498266Sopenharmony_ci          /* open file for output: */
92713498266Sopenharmony_ci          if(strcmp(config->etag_save_file, "-")) {
92813498266Sopenharmony_ci            FILE *newfile = fopen(config->etag_save_file, "wb");
92913498266Sopenharmony_ci            if(!newfile) {
93013498266Sopenharmony_ci              warnf(global, "Failed creating file for saving etags: \"%s\". "
93113498266Sopenharmony_ci                    "Skip this transfer", config->etag_save_file);
93213498266Sopenharmony_ci              Curl_safefree(state->outfiles);
93313498266Sopenharmony_ci              glob_cleanup(state->urls);
93413498266Sopenharmony_ci              return CURLE_OK;
93513498266Sopenharmony_ci            }
93613498266Sopenharmony_ci            else {
93713498266Sopenharmony_ci              etag_save->filename = config->etag_save_file;
93813498266Sopenharmony_ci              etag_save->s_isreg = TRUE;
93913498266Sopenharmony_ci              etag_save->fopened = TRUE;
94013498266Sopenharmony_ci              etag_save->stream = newfile;
94113498266Sopenharmony_ci            }
94213498266Sopenharmony_ci          }
94313498266Sopenharmony_ci          else {
94413498266Sopenharmony_ci            /* always use binary mode for protocol header output */
94513498266Sopenharmony_ci            set_binmode(etag_save->stream);
94613498266Sopenharmony_ci          }
94713498266Sopenharmony_ci        }
94813498266Sopenharmony_ci
94913498266Sopenharmony_ci        curl = curl_easy_init();
95013498266Sopenharmony_ci        if(curl)
95113498266Sopenharmony_ci          result = add_per_transfer(&per);
95213498266Sopenharmony_ci        else
95313498266Sopenharmony_ci          result = CURLE_OUT_OF_MEMORY;
95413498266Sopenharmony_ci        if(result) {
95513498266Sopenharmony_ci          curl_easy_cleanup(curl);
95613498266Sopenharmony_ci          if(etag_save->fopened)
95713498266Sopenharmony_ci            fclose(etag_save->stream);
95813498266Sopenharmony_ci          break;
95913498266Sopenharmony_ci        }
96013498266Sopenharmony_ci        per->etag_save = etag_first; /* copy the whole struct */
96113498266Sopenharmony_ci        if(state->uploadfile) {
96213498266Sopenharmony_ci          per->uploadfile = strdup(state->uploadfile);
96313498266Sopenharmony_ci          if(!per->uploadfile) {
96413498266Sopenharmony_ci            curl_easy_cleanup(curl);
96513498266Sopenharmony_ci            result = CURLE_OUT_OF_MEMORY;
96613498266Sopenharmony_ci            break;
96713498266Sopenharmony_ci          }
96813498266Sopenharmony_ci          if(SetHTTPrequest(config, HTTPREQ_PUT, &config->httpreq)) {
96913498266Sopenharmony_ci            Curl_safefree(per->uploadfile);
97013498266Sopenharmony_ci            curl_easy_cleanup(curl);
97113498266Sopenharmony_ci            result = CURLE_FAILED_INIT;
97213498266Sopenharmony_ci            break;
97313498266Sopenharmony_ci          }
97413498266Sopenharmony_ci        }
97513498266Sopenharmony_ci        *added = TRUE;
97613498266Sopenharmony_ci        per->config = config;
97713498266Sopenharmony_ci        per->curl = curl;
97813498266Sopenharmony_ci        per->urlnum = urlnode->num;
97913498266Sopenharmony_ci
98013498266Sopenharmony_ci        /* default headers output stream is stdout */
98113498266Sopenharmony_ci        heads = &per->heads;
98213498266Sopenharmony_ci        heads->stream = stdout;
98313498266Sopenharmony_ci
98413498266Sopenharmony_ci        /* Single header file for all URLs */
98513498266Sopenharmony_ci        if(config->headerfile) {
98613498266Sopenharmony_ci          /* open file for output: */
98713498266Sopenharmony_ci          if(strcmp(config->headerfile, "-")) {
98813498266Sopenharmony_ci            FILE *newfile;
98913498266Sopenharmony_ci
99013498266Sopenharmony_ci            /*
99113498266Sopenharmony_ci             * Since every transfer has its own file handle for dumping
99213498266Sopenharmony_ci             * the headers, we need to open it in append mode, since transfers
99313498266Sopenharmony_ci             * might finish in any order.
99413498266Sopenharmony_ci             * The first transfer just clears the file.
99513498266Sopenharmony_ci             * TODO: Consider placing the file handle inside the
99613498266Sopenharmony_ci             * OperationConfig, so that it does not need to be opened/closed
99713498266Sopenharmony_ci             * for every transfer.
99813498266Sopenharmony_ci             */
99913498266Sopenharmony_ci            if(!per->prev || per->prev->config != config) {
100013498266Sopenharmony_ci              newfile = fopen(config->headerfile, "wb");
100113498266Sopenharmony_ci              if(newfile)
100213498266Sopenharmony_ci                fclose(newfile);
100313498266Sopenharmony_ci            }
100413498266Sopenharmony_ci            newfile = fopen(config->headerfile, "ab");
100513498266Sopenharmony_ci
100613498266Sopenharmony_ci            if(!newfile) {
100713498266Sopenharmony_ci              errorf(global, "Failed to open %s", config->headerfile);
100813498266Sopenharmony_ci              result = CURLE_WRITE_ERROR;
100913498266Sopenharmony_ci              break;
101013498266Sopenharmony_ci            }
101113498266Sopenharmony_ci            else {
101213498266Sopenharmony_ci              heads->filename = config->headerfile;
101313498266Sopenharmony_ci              heads->s_isreg = TRUE;
101413498266Sopenharmony_ci              heads->fopened = TRUE;
101513498266Sopenharmony_ci              heads->stream = newfile;
101613498266Sopenharmony_ci            }
101713498266Sopenharmony_ci          }
101813498266Sopenharmony_ci          else {
101913498266Sopenharmony_ci            /* always use binary mode for protocol header output */
102013498266Sopenharmony_ci            set_binmode(heads->stream);
102113498266Sopenharmony_ci          }
102213498266Sopenharmony_ci        }
102313498266Sopenharmony_ci
102413498266Sopenharmony_ci        hdrcbdata = &per->hdrcbdata;
102513498266Sopenharmony_ci
102613498266Sopenharmony_ci        outs = &per->outs;
102713498266Sopenharmony_ci
102813498266Sopenharmony_ci        per->outfile = NULL;
102913498266Sopenharmony_ci        per->infdopen = FALSE;
103013498266Sopenharmony_ci        per->infd = STDIN_FILENO;
103113498266Sopenharmony_ci
103213498266Sopenharmony_ci        /* default output stream is stdout */
103313498266Sopenharmony_ci        outs->stream = stdout;
103413498266Sopenharmony_ci
103513498266Sopenharmony_ci        if(state->urls) {
103613498266Sopenharmony_ci          result = glob_next_url(&per->this_url, state->urls);
103713498266Sopenharmony_ci          if(result)
103813498266Sopenharmony_ci            break;
103913498266Sopenharmony_ci        }
104013498266Sopenharmony_ci        else if(!state->li) {
104113498266Sopenharmony_ci          per->this_url = strdup(urlnode->url);
104213498266Sopenharmony_ci          if(!per->this_url) {
104313498266Sopenharmony_ci            result = CURLE_OUT_OF_MEMORY;
104413498266Sopenharmony_ci            break;
104513498266Sopenharmony_ci          }
104613498266Sopenharmony_ci        }
104713498266Sopenharmony_ci        else
104813498266Sopenharmony_ci          per->this_url = NULL;
104913498266Sopenharmony_ci        if(!per->this_url)
105013498266Sopenharmony_ci          break;
105113498266Sopenharmony_ci
105213498266Sopenharmony_ci        if(state->outfiles) {
105313498266Sopenharmony_ci          per->outfile = strdup(state->outfiles);
105413498266Sopenharmony_ci          if(!per->outfile) {
105513498266Sopenharmony_ci            result = CURLE_OUT_OF_MEMORY;
105613498266Sopenharmony_ci            break;
105713498266Sopenharmony_ci          }
105813498266Sopenharmony_ci        }
105913498266Sopenharmony_ci
106013498266Sopenharmony_ci        if(((urlnode->flags&GETOUT_USEREMOTE) ||
106113498266Sopenharmony_ci            (per->outfile && strcmp("-", per->outfile)))) {
106213498266Sopenharmony_ci
106313498266Sopenharmony_ci          /*
106413498266Sopenharmony_ci           * We have specified a file name to store the result in, or we have
106513498266Sopenharmony_ci           * decided we want to use the remote file name.
106613498266Sopenharmony_ci           */
106713498266Sopenharmony_ci
106813498266Sopenharmony_ci          if(!per->outfile) {
106913498266Sopenharmony_ci            /* extract the file name from the URL */
107013498266Sopenharmony_ci            result = get_url_file_name(&per->outfile, per->this_url);
107113498266Sopenharmony_ci            if(result) {
107213498266Sopenharmony_ci              errorf(global, "Failed to extract a sensible file name"
107313498266Sopenharmony_ci                     " from the URL to use for storage");
107413498266Sopenharmony_ci              break;
107513498266Sopenharmony_ci            }
107613498266Sopenharmony_ci            if(!*per->outfile && !config->content_disposition) {
107713498266Sopenharmony_ci              errorf(global, "Remote file name has no length");
107813498266Sopenharmony_ci              result = CURLE_WRITE_ERROR;
107913498266Sopenharmony_ci              break;
108013498266Sopenharmony_ci            }
108113498266Sopenharmony_ci          }
108213498266Sopenharmony_ci          else if(state->urls) {
108313498266Sopenharmony_ci            /* fill '#1' ... '#9' terms from URL pattern */
108413498266Sopenharmony_ci            char *storefile = per->outfile;
108513498266Sopenharmony_ci            result = glob_match_url(&per->outfile, storefile, state->urls);
108613498266Sopenharmony_ci            Curl_safefree(storefile);
108713498266Sopenharmony_ci            if(result) {
108813498266Sopenharmony_ci              /* bad globbing */
108913498266Sopenharmony_ci              warnf(global, "bad output glob");
109013498266Sopenharmony_ci              break;
109113498266Sopenharmony_ci            }
109213498266Sopenharmony_ci            if(!*per->outfile) {
109313498266Sopenharmony_ci              warnf(global, "output glob produces empty string");
109413498266Sopenharmony_ci              result = CURLE_WRITE_ERROR;
109513498266Sopenharmony_ci              break;
109613498266Sopenharmony_ci            }
109713498266Sopenharmony_ci          }
109813498266Sopenharmony_ci
109913498266Sopenharmony_ci          if(config->output_dir && *config->output_dir) {
110013498266Sopenharmony_ci            char *d = aprintf("%s/%s", config->output_dir, per->outfile);
110113498266Sopenharmony_ci            if(!d) {
110213498266Sopenharmony_ci              result = CURLE_WRITE_ERROR;
110313498266Sopenharmony_ci              break;
110413498266Sopenharmony_ci            }
110513498266Sopenharmony_ci            free(per->outfile);
110613498266Sopenharmony_ci            per->outfile = d;
110713498266Sopenharmony_ci          }
110813498266Sopenharmony_ci          /* Create the directory hierarchy, if not pre-existent to a multiple
110913498266Sopenharmony_ci             file output call */
111013498266Sopenharmony_ci
111113498266Sopenharmony_ci          if(config->create_dirs) {
111213498266Sopenharmony_ci            result = create_dir_hierarchy(per->outfile, global);
111313498266Sopenharmony_ci            /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */
111413498266Sopenharmony_ci            if(result)
111513498266Sopenharmony_ci              break;
111613498266Sopenharmony_ci          }
111713498266Sopenharmony_ci
111813498266Sopenharmony_ci          if((urlnode->flags & GETOUT_USEREMOTE)
111913498266Sopenharmony_ci             && config->content_disposition) {
112013498266Sopenharmony_ci            /* Our header callback MIGHT set the filename */
112113498266Sopenharmony_ci            DEBUGASSERT(!outs->filename);
112213498266Sopenharmony_ci          }
112313498266Sopenharmony_ci
112413498266Sopenharmony_ci          if(config->resume_from_current) {
112513498266Sopenharmony_ci            /* We're told to continue from where we are now. Get the size
112613498266Sopenharmony_ci               of the file as it is now and open it for append instead */
112713498266Sopenharmony_ci            struct_stat fileinfo;
112813498266Sopenharmony_ci            /* VMS -- Danger, the filesize is only valid for stream files */
112913498266Sopenharmony_ci            if(0 == stat(per->outfile, &fileinfo))
113013498266Sopenharmony_ci              /* set offset to current file size: */
113113498266Sopenharmony_ci              config->resume_from = fileinfo.st_size;
113213498266Sopenharmony_ci            else
113313498266Sopenharmony_ci              /* let offset be 0 */
113413498266Sopenharmony_ci              config->resume_from = 0;
113513498266Sopenharmony_ci          }
113613498266Sopenharmony_ci
113713498266Sopenharmony_ci          if(config->resume_from) {
113813498266Sopenharmony_ci#ifdef __VMS
113913498266Sopenharmony_ci            /* open file for output, forcing VMS output format into stream
114013498266Sopenharmony_ci               mode which is needed for stat() call above to always work. */
114113498266Sopenharmony_ci            FILE *file = fopen(outfile, "ab",
114213498266Sopenharmony_ci                               "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0");
114313498266Sopenharmony_ci#else
114413498266Sopenharmony_ci            /* open file for output: */
114513498266Sopenharmony_ci            FILE *file = fopen(per->outfile, "ab");
114613498266Sopenharmony_ci#endif
114713498266Sopenharmony_ci            if(!file) {
114813498266Sopenharmony_ci              errorf(global, "Can't open '%s'", per->outfile);
114913498266Sopenharmony_ci              result = CURLE_WRITE_ERROR;
115013498266Sopenharmony_ci              break;
115113498266Sopenharmony_ci            }
115213498266Sopenharmony_ci            outs->fopened = TRUE;
115313498266Sopenharmony_ci            outs->stream = file;
115413498266Sopenharmony_ci            outs->init = config->resume_from;
115513498266Sopenharmony_ci          }
115613498266Sopenharmony_ci          else {
115713498266Sopenharmony_ci            outs->stream = NULL; /* open when needed */
115813498266Sopenharmony_ci          }
115913498266Sopenharmony_ci          outs->filename = per->outfile;
116013498266Sopenharmony_ci          outs->s_isreg = TRUE;
116113498266Sopenharmony_ci        }
116213498266Sopenharmony_ci
116313498266Sopenharmony_ci        if(per->uploadfile && !stdin_upload(per->uploadfile)) {
116413498266Sopenharmony_ci          /*
116513498266Sopenharmony_ci           * We have specified a file to upload and it isn't "-".
116613498266Sopenharmony_ci           */
116713498266Sopenharmony_ci          result = add_file_name_to_url(per->curl, &per->this_url,
116813498266Sopenharmony_ci                                        per->uploadfile);
116913498266Sopenharmony_ci          if(result)
117013498266Sopenharmony_ci            break;
117113498266Sopenharmony_ci        }
117213498266Sopenharmony_ci        else if(per->uploadfile && stdin_upload(per->uploadfile)) {
117313498266Sopenharmony_ci          /* count to see if there are more than one auth bit set
117413498266Sopenharmony_ci             in the authtype field */
117513498266Sopenharmony_ci          int authbits = 0;
117613498266Sopenharmony_ci          int bitcheck = 0;
117713498266Sopenharmony_ci          while(bitcheck < 32) {
117813498266Sopenharmony_ci            if(config->authtype & (1UL << bitcheck++)) {
117913498266Sopenharmony_ci              authbits++;
118013498266Sopenharmony_ci              if(authbits > 1) {
118113498266Sopenharmony_ci                /* more than one, we're done! */
118213498266Sopenharmony_ci                break;
118313498266Sopenharmony_ci              }
118413498266Sopenharmony_ci            }
118513498266Sopenharmony_ci          }
118613498266Sopenharmony_ci
118713498266Sopenharmony_ci          /*
118813498266Sopenharmony_ci           * If the user has also selected --anyauth or --proxy-anyauth
118913498266Sopenharmony_ci           * we should warn them.
119013498266Sopenharmony_ci           */
119113498266Sopenharmony_ci          if(config->proxyanyauth || (authbits>1)) {
119213498266Sopenharmony_ci            warnf(global,
119313498266Sopenharmony_ci                  "Using --anyauth or --proxy-anyauth with upload from stdin"
119413498266Sopenharmony_ci                  " involves a big risk of it not working. Use a temporary"
119513498266Sopenharmony_ci                  " file or a fixed auth type instead");
119613498266Sopenharmony_ci          }
119713498266Sopenharmony_ci
119813498266Sopenharmony_ci          DEBUGASSERT(per->infdopen == FALSE);
119913498266Sopenharmony_ci          DEBUGASSERT(per->infd == STDIN_FILENO);
120013498266Sopenharmony_ci
120113498266Sopenharmony_ci          set_binmode(stdin);
120213498266Sopenharmony_ci          if(!strcmp(per->uploadfile, ".")) {
120313498266Sopenharmony_ci            if(curlx_nonblock((curl_socket_t)per->infd, TRUE) < 0)
120413498266Sopenharmony_ci              warnf(global,
120513498266Sopenharmony_ci                    "fcntl failed on fd=%d: %s", per->infd, strerror(errno));
120613498266Sopenharmony_ci          }
120713498266Sopenharmony_ci        }
120813498266Sopenharmony_ci
120913498266Sopenharmony_ci        if(per->uploadfile && config->resume_from_current)
121013498266Sopenharmony_ci          config->resume_from = -1; /* -1 will then force get-it-yourself */
121113498266Sopenharmony_ci
121213498266Sopenharmony_ci        if(output_expected(per->this_url, per->uploadfile) && outs->stream &&
121313498266Sopenharmony_ci           isatty(fileno(outs->stream)))
121413498266Sopenharmony_ci          /* we send the output to a tty, therefore we switch off the progress
121513498266Sopenharmony_ci             meter */
121613498266Sopenharmony_ci          per->noprogress = global->noprogress = global->isatty = TRUE;
121713498266Sopenharmony_ci        else {
121813498266Sopenharmony_ci          /* progress meter is per download, so restore config
121913498266Sopenharmony_ci             values */
122013498266Sopenharmony_ci          per->noprogress = global->noprogress = orig_noprogress;
122113498266Sopenharmony_ci          global->isatty = orig_isatty;
122213498266Sopenharmony_ci        }
122313498266Sopenharmony_ci
122413498266Sopenharmony_ci        if(httpgetfields || config->query) {
122513498266Sopenharmony_ci          char *q = httpgetfields ? httpgetfields : config->query;
122613498266Sopenharmony_ci          CURLU *uh = curl_url();
122713498266Sopenharmony_ci          if(uh) {
122813498266Sopenharmony_ci            CURLUcode uerr;
122913498266Sopenharmony_ci            uerr = curl_url_set(uh, CURLUPART_URL, per->this_url,
123013498266Sopenharmony_ci                            CURLU_GUESS_SCHEME);
123113498266Sopenharmony_ci            if(uerr) {
123213498266Sopenharmony_ci              result = urlerr_cvt(uerr);
123313498266Sopenharmony_ci              errorf(global, "(%d) Could not parse the URL, "
123413498266Sopenharmony_ci                     "failed to set query", result);
123513498266Sopenharmony_ci              config->synthetic_error = TRUE;
123613498266Sopenharmony_ci            }
123713498266Sopenharmony_ci            else {
123813498266Sopenharmony_ci              char *updated = NULL;
123913498266Sopenharmony_ci              uerr = curl_url_set(uh, CURLUPART_QUERY, q, CURLU_APPENDQUERY);
124013498266Sopenharmony_ci              if(!uerr)
124113498266Sopenharmony_ci                uerr = curl_url_get(uh, CURLUPART_URL, &updated,
124213498266Sopenharmony_ci                                   CURLU_GUESS_SCHEME);
124313498266Sopenharmony_ci              if(uerr)
124413498266Sopenharmony_ci                result = urlerr_cvt(uerr);
124513498266Sopenharmony_ci              else {
124613498266Sopenharmony_ci                Curl_safefree(per->this_url); /* free previous URL */
124713498266Sopenharmony_ci                per->this_url = updated; /* use our new URL instead! */
124813498266Sopenharmony_ci              }
124913498266Sopenharmony_ci            }
125013498266Sopenharmony_ci            curl_url_cleanup(uh);
125113498266Sopenharmony_ci            if(result)
125213498266Sopenharmony_ci              break;
125313498266Sopenharmony_ci          }
125413498266Sopenharmony_ci        }
125513498266Sopenharmony_ci
125613498266Sopenharmony_ci        if((!per->outfile || !strcmp(per->outfile, "-")) &&
125713498266Sopenharmony_ci           !config->use_ascii) {
125813498266Sopenharmony_ci          /* We get the output to stdout and we have not got the ASCII/text
125913498266Sopenharmony_ci             flag, then set stdout to be binary */
126013498266Sopenharmony_ci          set_binmode(stdout);
126113498266Sopenharmony_ci        }
126213498266Sopenharmony_ci
126313498266Sopenharmony_ci        /* explicitly passed to stdout means okaying binary gunk */
126413498266Sopenharmony_ci        config->terminal_binary_ok =
126513498266Sopenharmony_ci          (per->outfile && !strcmp(per->outfile, "-"));
126613498266Sopenharmony_ci
126713498266Sopenharmony_ci        /* Avoid having this setopt added to the --libcurl source output. */
126813498266Sopenharmony_ci        result = curl_easy_setopt(curl, CURLOPT_SHARE, share);
126913498266Sopenharmony_ci        if(result)
127013498266Sopenharmony_ci          break;
127113498266Sopenharmony_ci
127213498266Sopenharmony_ci        /* result is only used when for ipfs and ipns, ignored otherwise */
127313498266Sopenharmony_ci        result = url_proto(&per->this_url, config, &use_proto);
127413498266Sopenharmony_ci        if(result && (use_proto == proto_ipfs || use_proto == proto_ipns))
127513498266Sopenharmony_ci          break;
127613498266Sopenharmony_ci
127713498266Sopenharmony_ci        /* On most modern OSes, exiting works thoroughly,
127813498266Sopenharmony_ci           we'll clean everything up via exit(), so don't bother with
127913498266Sopenharmony_ci           slow cleanups. Crappy ones might need to skip this.
128013498266Sopenharmony_ci           Note: avoid having this setopt added to the --libcurl source
128113498266Sopenharmony_ci           output. */
128213498266Sopenharmony_ci        result = curl_easy_setopt(curl, CURLOPT_QUICK_EXIT, 1L);
128313498266Sopenharmony_ci        if(result)
128413498266Sopenharmony_ci          break;
128513498266Sopenharmony_ci
128613498266Sopenharmony_ci        if(!config->tcp_nodelay)
128713498266Sopenharmony_ci          my_setopt(curl, CURLOPT_TCP_NODELAY, 0L);
128813498266Sopenharmony_ci
128913498266Sopenharmony_ci        if(config->tcp_fastopen)
129013498266Sopenharmony_ci          my_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L);
129113498266Sopenharmony_ci
129213498266Sopenharmony_ci        /* where to store */
129313498266Sopenharmony_ci        my_setopt(curl, CURLOPT_WRITEDATA, per);
129413498266Sopenharmony_ci        my_setopt(curl, CURLOPT_INTERLEAVEDATA, per);
129513498266Sopenharmony_ci
129613498266Sopenharmony_ci        /* what call to write */
129713498266Sopenharmony_ci        my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
129813498266Sopenharmony_ci
129913498266Sopenharmony_ci        /* Note that if CURLOPT_READFUNCTION is fread (the default), then
130013498266Sopenharmony_ci         * lib/telnet.c will Curl_poll() on the input file descriptor
130113498266Sopenharmony_ci         * rather than calling the READFUNCTION at regular intervals.
130213498266Sopenharmony_ci         * The circumstances in which it is preferable to enable this
130313498266Sopenharmony_ci         * behavior, by omitting to set the READFUNCTION & READDATA options,
130413498266Sopenharmony_ci         * have not been determined.
130513498266Sopenharmony_ci         */
130613498266Sopenharmony_ci        my_setopt(curl, CURLOPT_READDATA, per);
130713498266Sopenharmony_ci        /* what call to read */
130813498266Sopenharmony_ci        my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb);
130913498266Sopenharmony_ci
131013498266Sopenharmony_ci        /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
131113498266Sopenharmony_ci           CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
131213498266Sopenharmony_ci        my_setopt(curl, CURLOPT_SEEKDATA, per);
131313498266Sopenharmony_ci        my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);
131413498266Sopenharmony_ci
131513498266Sopenharmony_ci        {
131613498266Sopenharmony_ci#ifdef CURLDEBUG
131713498266Sopenharmony_ci          char *env = getenv("CURL_BUFFERSIZE");
131813498266Sopenharmony_ci          if(env) {
131913498266Sopenharmony_ci            long size = strtol(env, NULL, 10);
132013498266Sopenharmony_ci            if(size)
132113498266Sopenharmony_ci              my_setopt(curl, CURLOPT_BUFFERSIZE, size);
132213498266Sopenharmony_ci          }
132313498266Sopenharmony_ci          else
132413498266Sopenharmony_ci#endif
132513498266Sopenharmony_ci          if(config->recvpersecond &&
132613498266Sopenharmony_ci             (config->recvpersecond < BUFFER_SIZE))
132713498266Sopenharmony_ci            /* use a smaller sized buffer for better sleeps */
132813498266Sopenharmony_ci            my_setopt(curl, CURLOPT_BUFFERSIZE, (long)config->recvpersecond);
132913498266Sopenharmony_ci          else
133013498266Sopenharmony_ci            my_setopt(curl, CURLOPT_BUFFERSIZE, (long)BUFFER_SIZE);
133113498266Sopenharmony_ci        }
133213498266Sopenharmony_ci
133313498266Sopenharmony_ci        my_setopt_str(curl, CURLOPT_URL, per->this_url);
133413498266Sopenharmony_ci        my_setopt(curl, CURLOPT_NOPROGRESS,
133513498266Sopenharmony_ci                  global->noprogress || global->silent?1L:0L);
133613498266Sopenharmony_ci        if(config->no_body)
133713498266Sopenharmony_ci          my_setopt(curl, CURLOPT_NOBODY, 1L);
133813498266Sopenharmony_ci
133913498266Sopenharmony_ci        if(config->oauth_bearer)
134013498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_XOAUTH2_BEARER, config->oauth_bearer);
134113498266Sopenharmony_ci
134213498266Sopenharmony_ci        my_setopt_str(curl, CURLOPT_PROXY, config->proxy);
134313498266Sopenharmony_ci
134413498266Sopenharmony_ci        if(config->proxy && result) {
134513498266Sopenharmony_ci          errorf(global, "proxy support is disabled in this libcurl");
134613498266Sopenharmony_ci          config->synthetic_error = TRUE;
134713498266Sopenharmony_ci          result = CURLE_NOT_BUILT_IN;
134813498266Sopenharmony_ci          break;
134913498266Sopenharmony_ci        }
135013498266Sopenharmony_ci
135113498266Sopenharmony_ci        /* new in libcurl 7.5 */
135213498266Sopenharmony_ci        if(config->proxy)
135313498266Sopenharmony_ci          my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->proxyver);
135413498266Sopenharmony_ci
135513498266Sopenharmony_ci        my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
135613498266Sopenharmony_ci
135713498266Sopenharmony_ci        /* new in libcurl 7.3 */
135813498266Sopenharmony_ci        my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel?1L:0L);
135913498266Sopenharmony_ci
136013498266Sopenharmony_ci        /* new in libcurl 7.52.0 */
136113498266Sopenharmony_ci        if(config->preproxy)
136213498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_PRE_PROXY, config->preproxy);
136313498266Sopenharmony_ci
136413498266Sopenharmony_ci        /* new in libcurl 7.10.6 */
136513498266Sopenharmony_ci        if(config->proxyanyauth)
136613498266Sopenharmony_ci          my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
136713498266Sopenharmony_ci                            (long)CURLAUTH_ANY);
136813498266Sopenharmony_ci        else if(config->proxynegotiate)
136913498266Sopenharmony_ci          my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
137013498266Sopenharmony_ci                            (long)CURLAUTH_GSSNEGOTIATE);
137113498266Sopenharmony_ci        else if(config->proxyntlm)
137213498266Sopenharmony_ci          my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
137313498266Sopenharmony_ci                            (long)CURLAUTH_NTLM);
137413498266Sopenharmony_ci        else if(config->proxydigest)
137513498266Sopenharmony_ci          my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
137613498266Sopenharmony_ci                            (long)CURLAUTH_DIGEST);
137713498266Sopenharmony_ci        else if(config->proxybasic)
137813498266Sopenharmony_ci          my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
137913498266Sopenharmony_ci                            (long)CURLAUTH_BASIC);
138013498266Sopenharmony_ci
138113498266Sopenharmony_ci        /* new in libcurl 7.19.4 */
138213498266Sopenharmony_ci        my_setopt_str(curl, CURLOPT_NOPROXY, config->noproxy);
138313498266Sopenharmony_ci
138413498266Sopenharmony_ci        my_setopt(curl, CURLOPT_SUPPRESS_CONNECT_HEADERS,
138513498266Sopenharmony_ci                  config->suppress_connect_headers?1L:0L);
138613498266Sopenharmony_ci
138713498266Sopenharmony_ci        my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror?1L:0L);
138813498266Sopenharmony_ci        my_setopt(curl, CURLOPT_REQUEST_TARGET, config->request_target);
138913498266Sopenharmony_ci        my_setopt(curl, CURLOPT_UPLOAD, per->uploadfile?1L:0L);
139013498266Sopenharmony_ci        my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly?1L:0L);
139113498266Sopenharmony_ci        my_setopt(curl, CURLOPT_APPEND, config->ftp_append?1L:0L);
139213498266Sopenharmony_ci
139313498266Sopenharmony_ci        if(config->netrc_opt)
139413498266Sopenharmony_ci          my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_OPTIONAL);
139513498266Sopenharmony_ci        else if(config->netrc || config->netrc_file)
139613498266Sopenharmony_ci          my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_REQUIRED);
139713498266Sopenharmony_ci        else
139813498266Sopenharmony_ci          my_setopt_enum(curl, CURLOPT_NETRC, (long)CURL_NETRC_IGNORED);
139913498266Sopenharmony_ci
140013498266Sopenharmony_ci        if(config->netrc_file)
140113498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_NETRC_FILE, config->netrc_file);
140213498266Sopenharmony_ci
140313498266Sopenharmony_ci        my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii?1L:0L);
140413498266Sopenharmony_ci        if(config->login_options)
140513498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_LOGIN_OPTIONS, config->login_options);
140613498266Sopenharmony_ci        my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
140713498266Sopenharmony_ci        my_setopt_str(curl, CURLOPT_RANGE, config->range);
140813498266Sopenharmony_ci        if(!global->parallel) {
140913498266Sopenharmony_ci          per->errorbuffer = global_errorbuffer;
141013498266Sopenharmony_ci          my_setopt(curl, CURLOPT_ERRORBUFFER, global_errorbuffer);
141113498266Sopenharmony_ci        }
141213498266Sopenharmony_ci        my_setopt(curl, CURLOPT_TIMEOUT_MS, config->timeout_ms);
141313498266Sopenharmony_ci
141413498266Sopenharmony_ci        switch(config->httpreq) {
141513498266Sopenharmony_ci        case HTTPREQ_SIMPLEPOST:
141613498266Sopenharmony_ci          if(config->resume_from) {
141713498266Sopenharmony_ci            errorf(global, "cannot mix --continue-at with --data");
141813498266Sopenharmony_ci            result = CURLE_FAILED_INIT;
141913498266Sopenharmony_ci          }
142013498266Sopenharmony_ci          else {
142113498266Sopenharmony_ci            my_setopt_str(curl, CURLOPT_POSTFIELDS,
142213498266Sopenharmony_ci                          curlx_dyn_ptr(&config->postdata));
142313498266Sopenharmony_ci            my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE,
142413498266Sopenharmony_ci                      (curl_off_t)curlx_dyn_len(&config->postdata));
142513498266Sopenharmony_ci          }
142613498266Sopenharmony_ci          break;
142713498266Sopenharmony_ci        case HTTPREQ_MIMEPOST:
142813498266Sopenharmony_ci          /* free previous remainders */
142913498266Sopenharmony_ci          curl_mime_free(config->mimepost);
143013498266Sopenharmony_ci          config->mimepost = NULL;
143113498266Sopenharmony_ci          if(config->resume_from) {
143213498266Sopenharmony_ci            errorf(global, "cannot mix --continue-at with --form");
143313498266Sopenharmony_ci            result = CURLE_FAILED_INIT;
143413498266Sopenharmony_ci          }
143513498266Sopenharmony_ci          else {
143613498266Sopenharmony_ci            result = tool2curlmime(curl, config->mimeroot, &config->mimepost);
143713498266Sopenharmony_ci            if(!result)
143813498266Sopenharmony_ci              my_setopt_mimepost(curl, CURLOPT_MIMEPOST, config->mimepost);
143913498266Sopenharmony_ci          }
144013498266Sopenharmony_ci          break;
144113498266Sopenharmony_ci        default:
144213498266Sopenharmony_ci          break;
144313498266Sopenharmony_ci        }
144413498266Sopenharmony_ci        if(result)
144513498266Sopenharmony_ci          break;
144613498266Sopenharmony_ci
144713498266Sopenharmony_ci        /* new in libcurl 7.81.0 */
144813498266Sopenharmony_ci        if(config->mime_options)
144913498266Sopenharmony_ci          my_setopt(curl, CURLOPT_MIME_OPTIONS, config->mime_options);
145013498266Sopenharmony_ci
145113498266Sopenharmony_ci        /* new in libcurl 7.10.6 (default is Basic) */
145213498266Sopenharmony_ci        if(config->authtype)
145313498266Sopenharmony_ci          my_setopt_bitmask(curl, CURLOPT_HTTPAUTH, (long)config->authtype);
145413498266Sopenharmony_ci
145513498266Sopenharmony_ci        my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers);
145613498266Sopenharmony_ci
145713498266Sopenharmony_ci        if(proto_http || proto_rtsp) {
145813498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_REFERER, config->referer);
145913498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
146013498266Sopenharmony_ci        }
146113498266Sopenharmony_ci
146213498266Sopenharmony_ci        if(proto_http) {
146313498266Sopenharmony_ci          long postRedir = 0;
146413498266Sopenharmony_ci
146513498266Sopenharmony_ci          my_setopt(curl, CURLOPT_FOLLOWLOCATION,
146613498266Sopenharmony_ci                    config->followlocation?1L:0L);
146713498266Sopenharmony_ci          my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH,
146813498266Sopenharmony_ci                    config->unrestricted_auth?1L:0L);
146913498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_AWS_SIGV4, config->aws_sigv4);
147013498266Sopenharmony_ci          my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer?1L:0L);
147113498266Sopenharmony_ci
147213498266Sopenharmony_ci          /* new in libcurl 7.36.0 */
147313498266Sopenharmony_ci          if(config->proxyheaders) {
147413498266Sopenharmony_ci            my_setopt_slist(curl, CURLOPT_PROXYHEADER, config->proxyheaders);
147513498266Sopenharmony_ci            my_setopt(curl, CURLOPT_HEADEROPT, (long)CURLHEADER_SEPARATE);
147613498266Sopenharmony_ci          }
147713498266Sopenharmony_ci
147813498266Sopenharmony_ci          /* new in libcurl 7.5 */
147913498266Sopenharmony_ci          my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
148013498266Sopenharmony_ci
148113498266Sopenharmony_ci          if(config->httpversion)
148213498266Sopenharmony_ci            my_setopt_enum(curl, CURLOPT_HTTP_VERSION, config->httpversion);
148313498266Sopenharmony_ci          else if(feature_http2)
148413498266Sopenharmony_ci            my_setopt_enum(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
148513498266Sopenharmony_ci
148613498266Sopenharmony_ci          /* curl 7.19.1 (the 301 version existed in 7.18.2),
148713498266Sopenharmony_ci             303 was added in 7.26.0 */
148813498266Sopenharmony_ci          if(config->post301)
148913498266Sopenharmony_ci            postRedir |= CURL_REDIR_POST_301;
149013498266Sopenharmony_ci          if(config->post302)
149113498266Sopenharmony_ci            postRedir |= CURL_REDIR_POST_302;
149213498266Sopenharmony_ci          if(config->post303)
149313498266Sopenharmony_ci            postRedir |= CURL_REDIR_POST_303;
149413498266Sopenharmony_ci          my_setopt(curl, CURLOPT_POSTREDIR, postRedir);
149513498266Sopenharmony_ci
149613498266Sopenharmony_ci          /* new in libcurl 7.21.6 */
149713498266Sopenharmony_ci          if(config->encoding)
149813498266Sopenharmony_ci            my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, "");
149913498266Sopenharmony_ci
150013498266Sopenharmony_ci          /* new in libcurl 7.21.6 */
150113498266Sopenharmony_ci          if(config->tr_encoding)
150213498266Sopenharmony_ci            my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1L);
150313498266Sopenharmony_ci          /* new in libcurl 7.64.0 */
150413498266Sopenharmony_ci          my_setopt(curl, CURLOPT_HTTP09_ALLOWED,
150513498266Sopenharmony_ci                    config->http09_allowed ? 1L : 0L);
150613498266Sopenharmony_ci          if(result) {
150713498266Sopenharmony_ci            errorf(global, "HTTP/0.9 is not supported in this build");
150813498266Sopenharmony_ci            return result;
150913498266Sopenharmony_ci          }
151013498266Sopenharmony_ci
151113498266Sopenharmony_ci        } /* (proto_http) */
151213498266Sopenharmony_ci
151313498266Sopenharmony_ci        if(proto_ftp)
151413498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
151513498266Sopenharmony_ci        my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
151613498266Sopenharmony_ci                  config->low_speed_limit);
151713498266Sopenharmony_ci        my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
151813498266Sopenharmony_ci        my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE,
151913498266Sopenharmony_ci                  config->sendpersecond);
152013498266Sopenharmony_ci        my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE,
152113498266Sopenharmony_ci                  config->recvpersecond);
152213498266Sopenharmony_ci
152313498266Sopenharmony_ci        if(config->use_resume)
152413498266Sopenharmony_ci          my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, config->resume_from);
152513498266Sopenharmony_ci        else
152613498266Sopenharmony_ci          my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, CURL_OFF_T_C(0));
152713498266Sopenharmony_ci
152813498266Sopenharmony_ci        my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
152913498266Sopenharmony_ci        my_setopt_str(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_key_passwd);
153013498266Sopenharmony_ci
153113498266Sopenharmony_ci        if(use_proto == proto_scp || use_proto == proto_sftp) {
153213498266Sopenharmony_ci          /* SSH and SSL private key uses same command-line option */
153313498266Sopenharmony_ci          /* new in libcurl 7.16.1 */
153413498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
153513498266Sopenharmony_ci          /* new in libcurl 7.16.1 */
153613498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
153713498266Sopenharmony_ci
153813498266Sopenharmony_ci          /* new in libcurl 7.17.1: SSH host key md5 checking allows us
153913498266Sopenharmony_ci             to fail if we are not talking to who we think we should */
154013498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
154113498266Sopenharmony_ci                        config->hostpubmd5);
154213498266Sopenharmony_ci
154313498266Sopenharmony_ci          /* new in libcurl 7.80.0: SSH host key sha256 checking allows us
154413498266Sopenharmony_ci             to fail if we are not talking to who we think we should */
154513498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256,
154613498266Sopenharmony_ci              config->hostpubsha256);
154713498266Sopenharmony_ci
154813498266Sopenharmony_ci          /* new in libcurl 7.56.0 */
154913498266Sopenharmony_ci          if(config->ssh_compression)
155013498266Sopenharmony_ci            my_setopt(curl, CURLOPT_SSH_COMPRESSION, 1L);
155113498266Sopenharmony_ci        }
155213498266Sopenharmony_ci
155313498266Sopenharmony_ci        if(config->cacert)
155413498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
155513498266Sopenharmony_ci        if(config->proxy_cacert)
155613498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_PROXY_CAINFO, config->proxy_cacert);
155713498266Sopenharmony_ci
155813498266Sopenharmony_ci        if(config->capath) {
155913498266Sopenharmony_ci          result = res_setopt_str(curl, CURLOPT_CAPATH, config->capath);
156013498266Sopenharmony_ci          if(result == CURLE_NOT_BUILT_IN) {
156113498266Sopenharmony_ci            warnf(global, "ignoring %s, not supported by libcurl",
156213498266Sopenharmony_ci                  capath_from_env?
156313498266Sopenharmony_ci                  "SSL_CERT_DIR environment variable":"--capath");
156413498266Sopenharmony_ci          }
156513498266Sopenharmony_ci          else if(result)
156613498266Sopenharmony_ci            break;
156713498266Sopenharmony_ci        }
156813498266Sopenharmony_ci        /* For the time being if --proxy-capath is not set then we use the
156913498266Sopenharmony_ci           --capath value for it, if any. See #1257 */
157013498266Sopenharmony_ci        if(config->proxy_capath || config->capath) {
157113498266Sopenharmony_ci          result = res_setopt_str(curl, CURLOPT_PROXY_CAPATH,
157213498266Sopenharmony_ci                                  (config->proxy_capath ?
157313498266Sopenharmony_ci                                   config->proxy_capath :
157413498266Sopenharmony_ci                                   config->capath));
157513498266Sopenharmony_ci          if((result == CURLE_NOT_BUILT_IN) ||
157613498266Sopenharmony_ci             (result == CURLE_UNKNOWN_OPTION)) {
157713498266Sopenharmony_ci            if(config->proxy_capath) {
157813498266Sopenharmony_ci              warnf(global,
157913498266Sopenharmony_ci                    "ignoring --proxy-capath, not supported by libcurl");
158013498266Sopenharmony_ci            }
158113498266Sopenharmony_ci          }
158213498266Sopenharmony_ci          else if(result)
158313498266Sopenharmony_ci            break;
158413498266Sopenharmony_ci        }
158513498266Sopenharmony_ci
158613498266Sopenharmony_ci        if(config->crlfile)
158713498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
158813498266Sopenharmony_ci        if(config->proxy_crlfile)
158913498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->proxy_crlfile);
159013498266Sopenharmony_ci        else if(config->crlfile) /* CURLOPT_PROXY_CRLFILE default is crlfile */
159113498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->crlfile);
159213498266Sopenharmony_ci
159313498266Sopenharmony_ci        if(config->pinnedpubkey)
159413498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY, config->pinnedpubkey);
159513498266Sopenharmony_ci
159613498266Sopenharmony_ci        if(config->ssl_ec_curves)
159713498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_SSL_EC_CURVES, config->ssl_ec_curves);
159813498266Sopenharmony_ci
159913498266Sopenharmony_ci        if(config->writeout)
160013498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_CERTINFO, 1L);
160113498266Sopenharmony_ci
160213498266Sopenharmony_ci        if(feature_ssl) {
160313498266Sopenharmony_ci          /* Check if config->cert is a PKCS#11 URI and set the
160413498266Sopenharmony_ci           * config->cert_type if necessary */
160513498266Sopenharmony_ci          if(config->cert) {
160613498266Sopenharmony_ci            if(!config->cert_type) {
160713498266Sopenharmony_ci              if(is_pkcs11_uri(config->cert)) {
160813498266Sopenharmony_ci                config->cert_type = strdup("ENG");
160913498266Sopenharmony_ci              }
161013498266Sopenharmony_ci            }
161113498266Sopenharmony_ci          }
161213498266Sopenharmony_ci
161313498266Sopenharmony_ci          /* Check if config->key is a PKCS#11 URI and set the
161413498266Sopenharmony_ci           * config->key_type if necessary */
161513498266Sopenharmony_ci          if(config->key) {
161613498266Sopenharmony_ci            if(!config->key_type) {
161713498266Sopenharmony_ci              if(is_pkcs11_uri(config->key)) {
161813498266Sopenharmony_ci                config->key_type = strdup("ENG");
161913498266Sopenharmony_ci              }
162013498266Sopenharmony_ci            }
162113498266Sopenharmony_ci          }
162213498266Sopenharmony_ci
162313498266Sopenharmony_ci          /* Check if config->proxy_cert is a PKCS#11 URI and set the
162413498266Sopenharmony_ci           * config->proxy_type if necessary */
162513498266Sopenharmony_ci          if(config->proxy_cert) {
162613498266Sopenharmony_ci            if(!config->proxy_cert_type) {
162713498266Sopenharmony_ci              if(is_pkcs11_uri(config->proxy_cert)) {
162813498266Sopenharmony_ci                config->proxy_cert_type = strdup("ENG");
162913498266Sopenharmony_ci              }
163013498266Sopenharmony_ci            }
163113498266Sopenharmony_ci          }
163213498266Sopenharmony_ci
163313498266Sopenharmony_ci          /* Check if config->proxy_key is a PKCS#11 URI and set the
163413498266Sopenharmony_ci           * config->proxy_key_type if necessary */
163513498266Sopenharmony_ci          if(config->proxy_key) {
163613498266Sopenharmony_ci            if(!config->proxy_key_type) {
163713498266Sopenharmony_ci              if(is_pkcs11_uri(config->proxy_key)) {
163813498266Sopenharmony_ci                config->proxy_key_type = strdup("ENG");
163913498266Sopenharmony_ci              }
164013498266Sopenharmony_ci            }
164113498266Sopenharmony_ci          }
164213498266Sopenharmony_ci
164313498266Sopenharmony_ci          /* In debug build of curl tool, using
164413498266Sopenharmony_ci           *    --cert loadmem=<filename>:<password> --cert-type p12
164513498266Sopenharmony_ci           *  must do the same thing as classic:
164613498266Sopenharmony_ci           *    --cert <filename>:<password> --cert-type p12
164713498266Sopenharmony_ci           *  but is designed to test blob */
164813498266Sopenharmony_ci#if defined(CURLDEBUG) || defined(DEBUGBUILD)
164913498266Sopenharmony_ci          if(config->cert && (strlen(config->cert) > 8) &&
165013498266Sopenharmony_ci             (memcmp(config->cert, "loadmem=",8) == 0)) {
165113498266Sopenharmony_ci            FILE *fInCert = fopen(config->cert + 8, "rb");
165213498266Sopenharmony_ci            void *certdata = NULL;
165313498266Sopenharmony_ci            long filesize = 0;
165413498266Sopenharmony_ci            bool continue_reading = fInCert != NULL;
165513498266Sopenharmony_ci            if(continue_reading)
165613498266Sopenharmony_ci              continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
165713498266Sopenharmony_ci            if(continue_reading)
165813498266Sopenharmony_ci              filesize = ftell(fInCert);
165913498266Sopenharmony_ci            if(filesize < 0)
166013498266Sopenharmony_ci              continue_reading = FALSE;
166113498266Sopenharmony_ci            if(continue_reading)
166213498266Sopenharmony_ci              continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
166313498266Sopenharmony_ci            if(continue_reading)
166413498266Sopenharmony_ci              certdata = malloc(((size_t)filesize) + 1);
166513498266Sopenharmony_ci            if((!certdata) ||
166613498266Sopenharmony_ci                ((int)fread(certdata, (size_t)filesize, 1, fInCert) != 1))
166713498266Sopenharmony_ci              continue_reading = FALSE;
166813498266Sopenharmony_ci            if(fInCert)
166913498266Sopenharmony_ci              fclose(fInCert);
167013498266Sopenharmony_ci            if((filesize > 0) && continue_reading) {
167113498266Sopenharmony_ci              struct curl_blob structblob;
167213498266Sopenharmony_ci              structblob.data = certdata;
167313498266Sopenharmony_ci              structblob.len = (size_t)filesize;
167413498266Sopenharmony_ci              structblob.flags = CURL_BLOB_COPY;
167513498266Sopenharmony_ci              my_setopt_str(curl, CURLOPT_SSLCERT_BLOB, &structblob);
167613498266Sopenharmony_ci              /* if test run well, we are sure we don't reuse
167713498266Sopenharmony_ci               * original mem pointer */
167813498266Sopenharmony_ci              memset(certdata, 0, (size_t)filesize);
167913498266Sopenharmony_ci            }
168013498266Sopenharmony_ci            free(certdata);
168113498266Sopenharmony_ci          }
168213498266Sopenharmony_ci          else
168313498266Sopenharmony_ci#endif
168413498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_SSLCERT, config->cert);
168513498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert);
168613498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
168713498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE,
168813498266Sopenharmony_ci                        config->proxy_cert_type);
168913498266Sopenharmony_ci
169013498266Sopenharmony_ci
169113498266Sopenharmony_ci#if defined(CURLDEBUG) || defined(DEBUGBUILD)
169213498266Sopenharmony_ci          if(config->key && (strlen(config->key) > 8) &&
169313498266Sopenharmony_ci             (memcmp(config->key, "loadmem=",8) == 0)) {
169413498266Sopenharmony_ci            FILE *fInCert = fopen(config->key + 8, "rb");
169513498266Sopenharmony_ci            void *certdata = NULL;
169613498266Sopenharmony_ci            long filesize = 0;
169713498266Sopenharmony_ci            bool continue_reading = fInCert != NULL;
169813498266Sopenharmony_ci            if(continue_reading)
169913498266Sopenharmony_ci              continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
170013498266Sopenharmony_ci            if(continue_reading)
170113498266Sopenharmony_ci              filesize = ftell(fInCert);
170213498266Sopenharmony_ci            if(filesize < 0)
170313498266Sopenharmony_ci              continue_reading = FALSE;
170413498266Sopenharmony_ci            if(continue_reading)
170513498266Sopenharmony_ci              continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
170613498266Sopenharmony_ci            if(continue_reading)
170713498266Sopenharmony_ci              certdata = malloc(((size_t)filesize) + 1);
170813498266Sopenharmony_ci            if((!certdata) ||
170913498266Sopenharmony_ci                ((int)fread(certdata, (size_t)filesize, 1, fInCert) != 1))
171013498266Sopenharmony_ci              continue_reading = FALSE;
171113498266Sopenharmony_ci            if(fInCert)
171213498266Sopenharmony_ci              fclose(fInCert);
171313498266Sopenharmony_ci            if((filesize > 0) && continue_reading) {
171413498266Sopenharmony_ci              struct curl_blob structblob;
171513498266Sopenharmony_ci              structblob.data = certdata;
171613498266Sopenharmony_ci              structblob.len = (size_t)filesize;
171713498266Sopenharmony_ci              structblob.flags = CURL_BLOB_COPY;
171813498266Sopenharmony_ci              my_setopt_str(curl, CURLOPT_SSLKEY_BLOB, &structblob);
171913498266Sopenharmony_ci              /* if test run well, we are sure we don't reuse
172013498266Sopenharmony_ci               * original mem pointer */
172113498266Sopenharmony_ci              memset(certdata, 0, (size_t)filesize);
172213498266Sopenharmony_ci            }
172313498266Sopenharmony_ci            free(certdata);
172413498266Sopenharmony_ci          }
172513498266Sopenharmony_ci          else
172613498266Sopenharmony_ci#endif
172713498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_SSLKEY, config->key);
172813498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key);
172913498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
173013498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_PROXY_SSLKEYTYPE,
173113498266Sopenharmony_ci                        config->proxy_key_type);
173213498266Sopenharmony_ci          if(config->insecure_ok) {
173313498266Sopenharmony_ci            my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
173413498266Sopenharmony_ci            my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
173513498266Sopenharmony_ci          }
173613498266Sopenharmony_ci          else {
173713498266Sopenharmony_ci            my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
173813498266Sopenharmony_ci            /* libcurl default is strict verifyhost -> 2L   */
173913498266Sopenharmony_ci            /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */
174013498266Sopenharmony_ci          }
174113498266Sopenharmony_ci
174213498266Sopenharmony_ci          if(config->doh_insecure_ok) {
174313498266Sopenharmony_ci            my_setopt(curl, CURLOPT_DOH_SSL_VERIFYPEER, 0L);
174413498266Sopenharmony_ci            my_setopt(curl, CURLOPT_DOH_SSL_VERIFYHOST, 0L);
174513498266Sopenharmony_ci          }
174613498266Sopenharmony_ci
174713498266Sopenharmony_ci          if(config->proxy_insecure_ok) {
174813498266Sopenharmony_ci            my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0L);
174913498266Sopenharmony_ci            my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0L);
175013498266Sopenharmony_ci          }
175113498266Sopenharmony_ci          else {
175213498266Sopenharmony_ci            my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L);
175313498266Sopenharmony_ci          }
175413498266Sopenharmony_ci
175513498266Sopenharmony_ci          if(config->verifystatus)
175613498266Sopenharmony_ci            my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);
175713498266Sopenharmony_ci
175813498266Sopenharmony_ci          if(config->doh_verifystatus)
175913498266Sopenharmony_ci            my_setopt(curl, CURLOPT_DOH_SSL_VERIFYSTATUS, 1L);
176013498266Sopenharmony_ci
176113498266Sopenharmony_ci          if(config->falsestart)
176213498266Sopenharmony_ci            my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L);
176313498266Sopenharmony_ci
176413498266Sopenharmony_ci          my_setopt_enum(curl, CURLOPT_SSLVERSION,
176513498266Sopenharmony_ci                         config->ssl_version | config->ssl_version_max);
176613498266Sopenharmony_ci          if(config->proxy)
176713498266Sopenharmony_ci            my_setopt_enum(curl, CURLOPT_PROXY_SSLVERSION,
176813498266Sopenharmony_ci                           config->proxy_ssl_version);
176913498266Sopenharmony_ci
177013498266Sopenharmony_ci          {
177113498266Sopenharmony_ci            long mask =
177213498266Sopenharmony_ci              (config->ssl_allow_beast ?
177313498266Sopenharmony_ci               CURLSSLOPT_ALLOW_BEAST : 0) |
177413498266Sopenharmony_ci              (config->ssl_no_revoke ?
177513498266Sopenharmony_ci               CURLSSLOPT_NO_REVOKE : 0) |
177613498266Sopenharmony_ci              (config->ssl_revoke_best_effort ?
177713498266Sopenharmony_ci               CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
177813498266Sopenharmony_ci              (config->native_ca_store ?
177913498266Sopenharmony_ci               CURLSSLOPT_NATIVE_CA : 0) |
178013498266Sopenharmony_ci              (config->ssl_auto_client_cert ?
178113498266Sopenharmony_ci               CURLSSLOPT_AUTO_CLIENT_CERT : 0);
178213498266Sopenharmony_ci
178313498266Sopenharmony_ci            if(mask)
178413498266Sopenharmony_ci              my_setopt_bitmask(curl, CURLOPT_SSL_OPTIONS, mask);
178513498266Sopenharmony_ci          }
178613498266Sopenharmony_ci
178713498266Sopenharmony_ci          {
178813498266Sopenharmony_ci            long mask =
178913498266Sopenharmony_ci              (config->proxy_ssl_allow_beast ?
179013498266Sopenharmony_ci               CURLSSLOPT_ALLOW_BEAST : 0) |
179113498266Sopenharmony_ci              (config->proxy_ssl_auto_client_cert ?
179213498266Sopenharmony_ci               CURLSSLOPT_AUTO_CLIENT_CERT : 0) |
179313498266Sopenharmony_ci              (config->proxy_native_ca_store ?
179413498266Sopenharmony_ci               CURLSSLOPT_NATIVE_CA : 0);
179513498266Sopenharmony_ci
179613498266Sopenharmony_ci            if(mask)
179713498266Sopenharmony_ci              my_setopt_bitmask(curl, CURLOPT_PROXY_SSL_OPTIONS, mask);
179813498266Sopenharmony_ci          }
179913498266Sopenharmony_ci        }
180013498266Sopenharmony_ci
180113498266Sopenharmony_ci        if(config->path_as_is)
180213498266Sopenharmony_ci          my_setopt(curl, CURLOPT_PATH_AS_IS, 1L);
180313498266Sopenharmony_ci
180413498266Sopenharmony_ci        if((use_proto == proto_scp || use_proto == proto_sftp) &&
180513498266Sopenharmony_ci           !config->insecure_ok) {
180613498266Sopenharmony_ci          char *known = findfile(".ssh/known_hosts", FALSE);
180713498266Sopenharmony_ci          if(known) {
180813498266Sopenharmony_ci            /* new in curl 7.19.6 */
180913498266Sopenharmony_ci            result = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, known);
181013498266Sopenharmony_ci            curl_free(known);
181113498266Sopenharmony_ci            if(result == CURLE_UNKNOWN_OPTION)
181213498266Sopenharmony_ci              /* libssh2 version older than 1.1.1 */
181313498266Sopenharmony_ci              result = CURLE_OK;
181413498266Sopenharmony_ci            if(result)
181513498266Sopenharmony_ci              break;
181613498266Sopenharmony_ci          }
181713498266Sopenharmony_ci          else
181813498266Sopenharmony_ci            warnf(global, "Couldn't find a known_hosts file");
181913498266Sopenharmony_ci        }
182013498266Sopenharmony_ci
182113498266Sopenharmony_ci        if(config->no_body || config->remote_time) {
182213498266Sopenharmony_ci          /* no body or use remote time */
182313498266Sopenharmony_ci          my_setopt(curl, CURLOPT_FILETIME, 1L);
182413498266Sopenharmony_ci        }
182513498266Sopenharmony_ci
182613498266Sopenharmony_ci        my_setopt(curl, CURLOPT_CRLF, config->crlf?1L:0L);
182713498266Sopenharmony_ci        my_setopt_slist(curl, CURLOPT_QUOTE, config->quote);
182813498266Sopenharmony_ci        my_setopt_slist(curl, CURLOPT_POSTQUOTE, config->postquote);
182913498266Sopenharmony_ci        my_setopt_slist(curl, CURLOPT_PREQUOTE, config->prequote);
183013498266Sopenharmony_ci
183113498266Sopenharmony_ci        if(config->cookies) {
183213498266Sopenharmony_ci          struct curlx_dynbuf cookies;
183313498266Sopenharmony_ci          struct curl_slist *cl;
183413498266Sopenharmony_ci
183513498266Sopenharmony_ci          /* The maximum size needs to match MAX_NAME in cookie.h */
183613498266Sopenharmony_ci#define MAX_COOKIE_LINE 8200
183713498266Sopenharmony_ci          curlx_dyn_init(&cookies, MAX_COOKIE_LINE);
183813498266Sopenharmony_ci          for(cl = config->cookies; cl; cl = cl->next) {
183913498266Sopenharmony_ci            if(cl == config->cookies)
184013498266Sopenharmony_ci              result = curlx_dyn_addf(&cookies, "%s", cl->data);
184113498266Sopenharmony_ci            else
184213498266Sopenharmony_ci              result = curlx_dyn_addf(&cookies, ";%s", cl->data);
184313498266Sopenharmony_ci
184413498266Sopenharmony_ci            if(result) {
184513498266Sopenharmony_ci              warnf(global,
184613498266Sopenharmony_ci                    "skipped provided cookie, the cookie header "
184713498266Sopenharmony_ci                    "would go over %u bytes", MAX_COOKIE_LINE);
184813498266Sopenharmony_ci              break;
184913498266Sopenharmony_ci            }
185013498266Sopenharmony_ci          }
185113498266Sopenharmony_ci
185213498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_COOKIE, curlx_dyn_ptr(&cookies));
185313498266Sopenharmony_ci          curlx_dyn_free(&cookies);
185413498266Sopenharmony_ci        }
185513498266Sopenharmony_ci
185613498266Sopenharmony_ci        if(config->cookiefiles) {
185713498266Sopenharmony_ci          struct curl_slist *cfl;
185813498266Sopenharmony_ci
185913498266Sopenharmony_ci          for(cfl = config->cookiefiles; cfl; cfl = cfl->next)
186013498266Sopenharmony_ci            my_setopt_str(curl, CURLOPT_COOKIEFILE, cfl->data);
186113498266Sopenharmony_ci        }
186213498266Sopenharmony_ci
186313498266Sopenharmony_ci        /* new in libcurl 7.9 */
186413498266Sopenharmony_ci        if(config->cookiejar)
186513498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
186613498266Sopenharmony_ci
186713498266Sopenharmony_ci        /* new in libcurl 7.9.7 */
186813498266Sopenharmony_ci        my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession?1L:0L);
186913498266Sopenharmony_ci
187013498266Sopenharmony_ci        my_setopt_enum(curl, CURLOPT_TIMECONDITION, (long)config->timecond);
187113498266Sopenharmony_ci        my_setopt(curl, CURLOPT_TIMEVALUE_LARGE, config->condtime);
187213498266Sopenharmony_ci        my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
187313498266Sopenharmony_ci        customrequest_helper(config, config->httpreq, config->customrequest);
187413498266Sopenharmony_ci        my_setopt(curl, CURLOPT_STDERR, tool_stderr);
187513498266Sopenharmony_ci
187613498266Sopenharmony_ci        /* three new ones in libcurl 7.3: */
187713498266Sopenharmony_ci        my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
187813498266Sopenharmony_ci        my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
187913498266Sopenharmony_ci        progressbarinit(&per->progressbar, config);
188013498266Sopenharmony_ci
188113498266Sopenharmony_ci        if((global->progressmode == CURL_PROGRESS_BAR) &&
188213498266Sopenharmony_ci           !global->noprogress && !global->silent) {
188313498266Sopenharmony_ci          /* we want the alternative style, then we have to implement it
188413498266Sopenharmony_ci             ourselves! */
188513498266Sopenharmony_ci          my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_progress_cb);
188613498266Sopenharmony_ci          my_setopt(curl, CURLOPT_XFERINFODATA, per);
188713498266Sopenharmony_ci        }
188813498266Sopenharmony_ci        else if(per->uploadfile && !strcmp(per->uploadfile, ".")) {
188913498266Sopenharmony_ci          /* when reading from stdin in non-blocking mode, we use the progress
189013498266Sopenharmony_ci             function to unpause a busy read */
189113498266Sopenharmony_ci          my_setopt(curl, CURLOPT_NOPROGRESS, 0L);
189213498266Sopenharmony_ci          my_setopt(curl, CURLOPT_XFERINFOFUNCTION, tool_readbusy_cb);
189313498266Sopenharmony_ci          my_setopt(curl, CURLOPT_XFERINFODATA, per);
189413498266Sopenharmony_ci        }
189513498266Sopenharmony_ci
189613498266Sopenharmony_ci        /* new in libcurl 7.24.0: */
189713498266Sopenharmony_ci        if(config->dns_servers)
189813498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_DNS_SERVERS, config->dns_servers);
189913498266Sopenharmony_ci
190013498266Sopenharmony_ci        /* new in libcurl 7.33.0: */
190113498266Sopenharmony_ci        if(config->dns_interface)
190213498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_DNS_INTERFACE, config->dns_interface);
190313498266Sopenharmony_ci        if(config->dns_ipv4_addr)
190413498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP4, config->dns_ipv4_addr);
190513498266Sopenharmony_ci        if(config->dns_ipv6_addr)
190613498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_DNS_LOCAL_IP6, config->dns_ipv6_addr);
190713498266Sopenharmony_ci
190813498266Sopenharmony_ci        /* new in libcurl 7.6.2: */
190913498266Sopenharmony_ci        my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
191013498266Sopenharmony_ci
191113498266Sopenharmony_ci        /* new in libcurl 7.7: */
191213498266Sopenharmony_ci        my_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, config->connecttimeout_ms);
191313498266Sopenharmony_ci
191413498266Sopenharmony_ci        if(config->doh_url)
191513498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_DOH_URL, config->doh_url);
191613498266Sopenharmony_ci
191713498266Sopenharmony_ci        if(config->cipher_list)
191813498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
191913498266Sopenharmony_ci
192013498266Sopenharmony_ci        if(config->proxy_cipher_list)
192113498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_PROXY_SSL_CIPHER_LIST,
192213498266Sopenharmony_ci                        config->proxy_cipher_list);
192313498266Sopenharmony_ci
192413498266Sopenharmony_ci        if(config->cipher13_list)
192513498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_TLS13_CIPHERS, config->cipher13_list);
192613498266Sopenharmony_ci
192713498266Sopenharmony_ci        if(config->proxy_cipher13_list)
192813498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_PROXY_TLS13_CIPHERS,
192913498266Sopenharmony_ci                        config->proxy_cipher13_list);
193013498266Sopenharmony_ci
193113498266Sopenharmony_ci        /* new in libcurl 7.9.2: */
193213498266Sopenharmony_ci        if(config->disable_epsv)
193313498266Sopenharmony_ci          /* disable it */
193413498266Sopenharmony_ci          my_setopt(curl, CURLOPT_FTP_USE_EPSV, 0L);
193513498266Sopenharmony_ci
193613498266Sopenharmony_ci        /* new in libcurl 7.10.5 */
193713498266Sopenharmony_ci        if(config->disable_eprt)
193813498266Sopenharmony_ci          /* disable it */
193913498266Sopenharmony_ci          my_setopt(curl, CURLOPT_FTP_USE_EPRT, 0L);
194013498266Sopenharmony_ci
194113498266Sopenharmony_ci        if(global->tracetype != TRACE_NONE) {
194213498266Sopenharmony_ci          my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb);
194313498266Sopenharmony_ci          my_setopt(curl, CURLOPT_DEBUGDATA, config);
194413498266Sopenharmony_ci          my_setopt(curl, CURLOPT_VERBOSE, 1L);
194513498266Sopenharmony_ci        }
194613498266Sopenharmony_ci
194713498266Sopenharmony_ci        /* new in curl 7.9.3 */
194813498266Sopenharmony_ci        if(config->engine) {
194913498266Sopenharmony_ci          result = res_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
195013498266Sopenharmony_ci          if(result)
195113498266Sopenharmony_ci            break;
195213498266Sopenharmony_ci        }
195313498266Sopenharmony_ci
195413498266Sopenharmony_ci        /* new in curl 7.10.7, extended in 7.19.4. Modified to use
195513498266Sopenharmony_ci           CREATE_DIR_RETRY in 7.49.0 */
195613498266Sopenharmony_ci        my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
195713498266Sopenharmony_ci                  (long)(config->ftp_create_dirs?
195813498266Sopenharmony_ci                         CURLFTP_CREATE_DIR_RETRY:
195913498266Sopenharmony_ci                         CURLFTP_CREATE_DIR_NONE));
196013498266Sopenharmony_ci
196113498266Sopenharmony_ci        /* new in curl 7.10.8 */
196213498266Sopenharmony_ci        if(config->max_filesize)
196313498266Sopenharmony_ci          my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
196413498266Sopenharmony_ci                    config->max_filesize);
196513498266Sopenharmony_ci
196613498266Sopenharmony_ci        my_setopt(curl, CURLOPT_IPRESOLVE, config->ip_version);
196713498266Sopenharmony_ci
196813498266Sopenharmony_ci        /* new in curl 7.15.5 */
196913498266Sopenharmony_ci        if(config->ftp_ssl_reqd)
197013498266Sopenharmony_ci          my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
197113498266Sopenharmony_ci
197213498266Sopenharmony_ci        /* new in curl 7.11.0 */
197313498266Sopenharmony_ci        else if(config->ftp_ssl)
197413498266Sopenharmony_ci          my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY);
197513498266Sopenharmony_ci
197613498266Sopenharmony_ci        /* new in curl 7.16.0 */
197713498266Sopenharmony_ci        else if(config->ftp_ssl_control)
197813498266Sopenharmony_ci          my_setopt_enum(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_CONTROL);
197913498266Sopenharmony_ci
198013498266Sopenharmony_ci        /* new in curl 7.16.1 */
198113498266Sopenharmony_ci        if(config->ftp_ssl_ccc)
198213498266Sopenharmony_ci          my_setopt_enum(curl, CURLOPT_FTP_SSL_CCC,
198313498266Sopenharmony_ci                         (long)config->ftp_ssl_ccc_mode);
198413498266Sopenharmony_ci
198513498266Sopenharmony_ci        /* new in curl 7.19.4 */
198613498266Sopenharmony_ci        if(config->socks5_gssapi_nec)
198713498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC, 1L);
198813498266Sopenharmony_ci
198913498266Sopenharmony_ci        /* new in curl 7.55.0 */
199013498266Sopenharmony_ci        if(config->socks5_auth)
199113498266Sopenharmony_ci          my_setopt_bitmask(curl, CURLOPT_SOCKS5_AUTH,
199213498266Sopenharmony_ci                            (long)config->socks5_auth);
199313498266Sopenharmony_ci
199413498266Sopenharmony_ci        /* new in curl 7.43.0 */
199513498266Sopenharmony_ci        if(config->proxy_service_name)
199613498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_PROXY_SERVICE_NAME,
199713498266Sopenharmony_ci                        config->proxy_service_name);
199813498266Sopenharmony_ci
199913498266Sopenharmony_ci        /* new in curl 7.43.0 */
200013498266Sopenharmony_ci        if(config->service_name)
200113498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_SERVICE_NAME,
200213498266Sopenharmony_ci                        config->service_name);
200313498266Sopenharmony_ci
200413498266Sopenharmony_ci        /* curl 7.13.0 */
200513498266Sopenharmony_ci        my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
200613498266Sopenharmony_ci        my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl?1L:0L);
200713498266Sopenharmony_ci
200813498266Sopenharmony_ci        /* curl 7.14.2 */
200913498266Sopenharmony_ci        my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip?1L:0L);
201013498266Sopenharmony_ci
201113498266Sopenharmony_ci        /* curl 7.15.1 */
201213498266Sopenharmony_ci        if(proto_ftp)
201313498266Sopenharmony_ci          my_setopt(curl, CURLOPT_FTP_FILEMETHOD,
201413498266Sopenharmony_ci                    (long)config->ftp_filemethod);
201513498266Sopenharmony_ci
201613498266Sopenharmony_ci        /* curl 7.15.2 */
201713498266Sopenharmony_ci        if(config->localport) {
201813498266Sopenharmony_ci          my_setopt(curl, CURLOPT_LOCALPORT, config->localport);
201913498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_LOCALPORTRANGE, config->localportrange);
202013498266Sopenharmony_ci        }
202113498266Sopenharmony_ci
202213498266Sopenharmony_ci        /* curl 7.15.5 */
202313498266Sopenharmony_ci        my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
202413498266Sopenharmony_ci                      config->ftp_alternative_to_user);
202513498266Sopenharmony_ci
202613498266Sopenharmony_ci        /* curl 7.16.0 */
202713498266Sopenharmony_ci        if(config->disable_sessionid)
202813498266Sopenharmony_ci          /* disable it */
202913498266Sopenharmony_ci          my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L);
203013498266Sopenharmony_ci
203113498266Sopenharmony_ci        /* curl 7.16.2 */
203213498266Sopenharmony_ci        if(config->raw) {
203313498266Sopenharmony_ci          my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, 0L);
203413498266Sopenharmony_ci          my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, 0L);
203513498266Sopenharmony_ci        }
203613498266Sopenharmony_ci
203713498266Sopenharmony_ci        /* curl 7.17.1 */
203813498266Sopenharmony_ci        if(!config->nokeepalive) {
203913498266Sopenharmony_ci          my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
204013498266Sopenharmony_ci          if(config->alivetime) {
204113498266Sopenharmony_ci            my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime);
204213498266Sopenharmony_ci            my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime);
204313498266Sopenharmony_ci          }
204413498266Sopenharmony_ci        }
204513498266Sopenharmony_ci        else
204613498266Sopenharmony_ci          my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
204713498266Sopenharmony_ci
204813498266Sopenharmony_ci        /* curl 7.20.0 */
204913498266Sopenharmony_ci        if(config->tftp_blksize && proto_tftp)
205013498266Sopenharmony_ci          my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
205113498266Sopenharmony_ci
205213498266Sopenharmony_ci        if(config->mail_from)
205313498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
205413498266Sopenharmony_ci
205513498266Sopenharmony_ci        if(config->mail_rcpt)
205613498266Sopenharmony_ci          my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
205713498266Sopenharmony_ci
205813498266Sopenharmony_ci        /* curl 7.69.x */
205913498266Sopenharmony_ci        my_setopt(curl, CURLOPT_MAIL_RCPT_ALLOWFAILS,
206013498266Sopenharmony_ci                  config->mail_rcpt_allowfails ? 1L : 0L);
206113498266Sopenharmony_ci
206213498266Sopenharmony_ci        /* curl 7.20.x */
206313498266Sopenharmony_ci        if(config->ftp_pret)
206413498266Sopenharmony_ci          my_setopt(curl, CURLOPT_FTP_USE_PRET, 1L);
206513498266Sopenharmony_ci
206613498266Sopenharmony_ci        if(config->create_file_mode)
206713498266Sopenharmony_ci          my_setopt(curl, CURLOPT_NEW_FILE_PERMS, config->create_file_mode);
206813498266Sopenharmony_ci
206913498266Sopenharmony_ci        if(config->proto_present)
207013498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_PROTOCOLS_STR, config->proto_str);
207113498266Sopenharmony_ci        if(config->proto_redir_present)
207213498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_REDIR_PROTOCOLS_STR,
207313498266Sopenharmony_ci                        config->proto_redir_str);
207413498266Sopenharmony_ci
207513498266Sopenharmony_ci        if(config->content_disposition
207613498266Sopenharmony_ci           && (urlnode->flags & GETOUT_USEREMOTE))
207713498266Sopenharmony_ci          hdrcbdata->honor_cd_filename = TRUE;
207813498266Sopenharmony_ci        else
207913498266Sopenharmony_ci          hdrcbdata->honor_cd_filename = FALSE;
208013498266Sopenharmony_ci
208113498266Sopenharmony_ci        hdrcbdata->outs = outs;
208213498266Sopenharmony_ci        hdrcbdata->heads = heads;
208313498266Sopenharmony_ci        hdrcbdata->etag_save = etag_save;
208413498266Sopenharmony_ci        hdrcbdata->global = global;
208513498266Sopenharmony_ci        hdrcbdata->config = config;
208613498266Sopenharmony_ci
208713498266Sopenharmony_ci        my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb);
208813498266Sopenharmony_ci        my_setopt(curl, CURLOPT_HEADERDATA, per);
208913498266Sopenharmony_ci
209013498266Sopenharmony_ci        if(config->resolve)
209113498266Sopenharmony_ci          /* new in 7.21.3 */
209213498266Sopenharmony_ci          my_setopt_slist(curl, CURLOPT_RESOLVE, config->resolve);
209313498266Sopenharmony_ci
209413498266Sopenharmony_ci        if(config->connect_to)
209513498266Sopenharmony_ci          /* new in 7.49.0 */
209613498266Sopenharmony_ci          my_setopt_slist(curl, CURLOPT_CONNECT_TO, config->connect_to);
209713498266Sopenharmony_ci
209813498266Sopenharmony_ci        /* new in 7.21.4 */
209913498266Sopenharmony_ci        if(feature_tls_srp) {
210013498266Sopenharmony_ci          if(config->tls_username)
210113498266Sopenharmony_ci            my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME,
210213498266Sopenharmony_ci                          config->tls_username);
210313498266Sopenharmony_ci          if(config->tls_password)
210413498266Sopenharmony_ci            my_setopt_str(curl, CURLOPT_TLSAUTH_PASSWORD,
210513498266Sopenharmony_ci                          config->tls_password);
210613498266Sopenharmony_ci          if(config->tls_authtype)
210713498266Sopenharmony_ci            my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE,
210813498266Sopenharmony_ci                          config->tls_authtype);
210913498266Sopenharmony_ci          if(config->proxy_tls_username)
211013498266Sopenharmony_ci            my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_USERNAME,
211113498266Sopenharmony_ci                          config->proxy_tls_username);
211213498266Sopenharmony_ci          if(config->proxy_tls_password)
211313498266Sopenharmony_ci            my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD,
211413498266Sopenharmony_ci                          config->proxy_tls_password);
211513498266Sopenharmony_ci          if(config->proxy_tls_authtype)
211613498266Sopenharmony_ci            my_setopt_str(curl, CURLOPT_PROXY_TLSAUTH_TYPE,
211713498266Sopenharmony_ci                          config->proxy_tls_authtype);
211813498266Sopenharmony_ci        }
211913498266Sopenharmony_ci
212013498266Sopenharmony_ci        /* new in 7.22.0 */
212113498266Sopenharmony_ci        if(config->gssapi_delegation)
212213498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION,
212313498266Sopenharmony_ci                        config->gssapi_delegation);
212413498266Sopenharmony_ci
212513498266Sopenharmony_ci        if(config->mail_auth)
212613498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth);
212713498266Sopenharmony_ci
212813498266Sopenharmony_ci        /* new in 7.66.0 */
212913498266Sopenharmony_ci        if(config->sasl_authzid)
213013498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_SASL_AUTHZID, config->sasl_authzid);
213113498266Sopenharmony_ci
213213498266Sopenharmony_ci        /* new in 7.31.0 */
213313498266Sopenharmony_ci        if(config->sasl_ir)
213413498266Sopenharmony_ci          my_setopt(curl, CURLOPT_SASL_IR, 1L);
213513498266Sopenharmony_ci
213613498266Sopenharmony_ci        if(config->noalpn) {
213713498266Sopenharmony_ci          my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L);
213813498266Sopenharmony_ci        }
213913498266Sopenharmony_ci
214013498266Sopenharmony_ci        /* new in 7.40.0, abstract support added in 7.53.0 */
214113498266Sopenharmony_ci        if(config->unix_socket_path) {
214213498266Sopenharmony_ci          if(config->abstract_unix_socket) {
214313498266Sopenharmony_ci            my_setopt_str(curl, CURLOPT_ABSTRACT_UNIX_SOCKET,
214413498266Sopenharmony_ci                          config->unix_socket_path);
214513498266Sopenharmony_ci          }
214613498266Sopenharmony_ci          else {
214713498266Sopenharmony_ci            my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH,
214813498266Sopenharmony_ci                          config->unix_socket_path);
214913498266Sopenharmony_ci          }
215013498266Sopenharmony_ci        }
215113498266Sopenharmony_ci
215213498266Sopenharmony_ci        /* new in 7.45.0 */
215313498266Sopenharmony_ci        if(config->proto_default)
215413498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_DEFAULT_PROTOCOL, config->proto_default);
215513498266Sopenharmony_ci
215613498266Sopenharmony_ci        /* new in 7.47.0 */
215713498266Sopenharmony_ci        if(config->expect100timeout_ms > 0)
215813498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_EXPECT_100_TIMEOUT_MS,
215913498266Sopenharmony_ci                        config->expect100timeout_ms);
216013498266Sopenharmony_ci
216113498266Sopenharmony_ci        /* new in 7.48.0 */
216213498266Sopenharmony_ci        if(config->tftp_no_options && proto_tftp)
216313498266Sopenharmony_ci          my_setopt(curl, CURLOPT_TFTP_NO_OPTIONS, 1L);
216413498266Sopenharmony_ci
216513498266Sopenharmony_ci        /* new in 7.59.0 */
216613498266Sopenharmony_ci        if(config->happy_eyeballs_timeout_ms != CURL_HET_DEFAULT)
216713498266Sopenharmony_ci          my_setopt(curl, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS,
216813498266Sopenharmony_ci                    config->happy_eyeballs_timeout_ms);
216913498266Sopenharmony_ci
217013498266Sopenharmony_ci        /* new in 7.60.0 */
217113498266Sopenharmony_ci        if(config->haproxy_protocol)
217213498266Sopenharmony_ci          my_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L);
217313498266Sopenharmony_ci
217413498266Sopenharmony_ci        /* new in 8.2.0 */
217513498266Sopenharmony_ci        if(config->haproxy_clientip)
217613498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_HAPROXY_CLIENT_IP,
217713498266Sopenharmony_ci              config->haproxy_clientip);
217813498266Sopenharmony_ci
217913498266Sopenharmony_ci        if(config->disallow_username_in_url)
218013498266Sopenharmony_ci          my_setopt(curl, CURLOPT_DISALLOW_USERNAME_IN_URL, 1L);
218113498266Sopenharmony_ci
218213498266Sopenharmony_ci        if(config->altsvc)
218313498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_ALTSVC, config->altsvc);
218413498266Sopenharmony_ci
218513498266Sopenharmony_ci        if(config->hsts)
218613498266Sopenharmony_ci          my_setopt_str(curl, CURLOPT_HSTS, config->hsts);
218713498266Sopenharmony_ci
218813498266Sopenharmony_ci        /* initialize retry vars for loop below */
218913498266Sopenharmony_ci        per->retry_sleep_default = (config->retry_delay) ?
219013498266Sopenharmony_ci          config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
219113498266Sopenharmony_ci        per->retry_numretries = config->req_retry;
219213498266Sopenharmony_ci        per->retry_sleep = per->retry_sleep_default; /* ms */
219313498266Sopenharmony_ci        per->retrystart = tvnow();
219413498266Sopenharmony_ci
219513498266Sopenharmony_ci        state->li++;
219613498266Sopenharmony_ci        /* Here's looping around each globbed URL */
219713498266Sopenharmony_ci        if(state->li >= urlnum) {
219813498266Sopenharmony_ci          state->li = 0;
219913498266Sopenharmony_ci          state->urlnum = 0; /* forced reglob of URLs */
220013498266Sopenharmony_ci          glob_cleanup(state->urls);
220113498266Sopenharmony_ci          state->urls = NULL;
220213498266Sopenharmony_ci          state->up++;
220313498266Sopenharmony_ci          Curl_safefree(state->uploadfile); /* clear it to get the next */
220413498266Sopenharmony_ci        }
220513498266Sopenharmony_ci      }
220613498266Sopenharmony_ci      else {
220713498266Sopenharmony_ci        /* Free this URL node data without destroying the
220813498266Sopenharmony_ci           node itself nor modifying next pointer. */
220913498266Sopenharmony_ci        Curl_safefree(urlnode->outfile);
221013498266Sopenharmony_ci        Curl_safefree(urlnode->infile);
221113498266Sopenharmony_ci        urlnode->flags = 0;
221213498266Sopenharmony_ci        glob_cleanup(state->urls);
221313498266Sopenharmony_ci        state->urls = NULL;
221413498266Sopenharmony_ci        state->urlnum = 0;
221513498266Sopenharmony_ci
221613498266Sopenharmony_ci        Curl_safefree(state->outfiles);
221713498266Sopenharmony_ci        Curl_safefree(state->uploadfile);
221813498266Sopenharmony_ci        if(state->inglob) {
221913498266Sopenharmony_ci          /* Free list of globbed upload files */
222013498266Sopenharmony_ci          glob_cleanup(state->inglob);
222113498266Sopenharmony_ci          state->inglob = NULL;
222213498266Sopenharmony_ci        }
222313498266Sopenharmony_ci        config->state.urlnode = urlnode->next;
222413498266Sopenharmony_ci        state->up = 0;
222513498266Sopenharmony_ci        continue;
222613498266Sopenharmony_ci      }
222713498266Sopenharmony_ci    }
222813498266Sopenharmony_ci    break;
222913498266Sopenharmony_ci  }
223013498266Sopenharmony_ci  Curl_safefree(state->outfiles);
223113498266Sopenharmony_ci
223213498266Sopenharmony_ci  if(!*added || result) {
223313498266Sopenharmony_ci    *added = FALSE;
223413498266Sopenharmony_ci    single_transfer_cleanup(config);
223513498266Sopenharmony_ci  }
223613498266Sopenharmony_ci  return result;
223713498266Sopenharmony_ci}
223813498266Sopenharmony_ci
223913498266Sopenharmony_cistatic long all_added; /* number of easy handles currently added */
224013498266Sopenharmony_ci
224113498266Sopenharmony_ci/*
224213498266Sopenharmony_ci * add_parallel_transfers() sets 'morep' to TRUE if there are more transfers
224313498266Sopenharmony_ci * to add even after this call returns. sets 'addedp' to TRUE if one or more
224413498266Sopenharmony_ci * transfers were added.
224513498266Sopenharmony_ci */
224613498266Sopenharmony_cistatic CURLcode add_parallel_transfers(struct GlobalConfig *global,
224713498266Sopenharmony_ci                                       CURLM *multi,
224813498266Sopenharmony_ci                                       CURLSH *share,
224913498266Sopenharmony_ci                                       bool *morep,
225013498266Sopenharmony_ci                                       bool *addedp)
225113498266Sopenharmony_ci{
225213498266Sopenharmony_ci  struct per_transfer *per;
225313498266Sopenharmony_ci  CURLcode result = CURLE_OK;
225413498266Sopenharmony_ci  CURLMcode mcode;
225513498266Sopenharmony_ci  bool sleeping = FALSE;
225613498266Sopenharmony_ci  char *errorbuf;
225713498266Sopenharmony_ci  *addedp = FALSE;
225813498266Sopenharmony_ci  *morep = FALSE;
225913498266Sopenharmony_ci  if(all_pers < (global->parallel_max*2)) {
226013498266Sopenharmony_ci    result = create_transfer(global, share, addedp);
226113498266Sopenharmony_ci    if(result)
226213498266Sopenharmony_ci      return result;
226313498266Sopenharmony_ci  }
226413498266Sopenharmony_ci  for(per = transfers; per && (all_added < global->parallel_max);
226513498266Sopenharmony_ci      per = per->next) {
226613498266Sopenharmony_ci    bool getadded = FALSE;
226713498266Sopenharmony_ci    if(per->added)
226813498266Sopenharmony_ci      /* already added */
226913498266Sopenharmony_ci      continue;
227013498266Sopenharmony_ci    if(per->startat && (time(NULL) < per->startat)) {
227113498266Sopenharmony_ci      /* this is still delaying */
227213498266Sopenharmony_ci      sleeping = TRUE;
227313498266Sopenharmony_ci      continue;
227413498266Sopenharmony_ci    }
227513498266Sopenharmony_ci    per->added = TRUE;
227613498266Sopenharmony_ci
227713498266Sopenharmony_ci    result = pre_transfer(global, per);
227813498266Sopenharmony_ci    if(result)
227913498266Sopenharmony_ci      return result;
228013498266Sopenharmony_ci
228113498266Sopenharmony_ci    errorbuf = malloc(CURL_ERROR_SIZE);
228213498266Sopenharmony_ci    if(!errorbuf)
228313498266Sopenharmony_ci      return CURLE_OUT_OF_MEMORY;
228413498266Sopenharmony_ci
228513498266Sopenharmony_ci    /* parallel connect means that we don't set PIPEWAIT since pipewait
228613498266Sopenharmony_ci       will make libcurl prefer multiplexing */
228713498266Sopenharmony_ci    (void)curl_easy_setopt(per->curl, CURLOPT_PIPEWAIT,
228813498266Sopenharmony_ci                           global->parallel_connect ? 0L : 1L);
228913498266Sopenharmony_ci    (void)curl_easy_setopt(per->curl, CURLOPT_PRIVATE, per);
229013498266Sopenharmony_ci    (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFOFUNCTION, xferinfo_cb);
229113498266Sopenharmony_ci    (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFODATA, per);
229213498266Sopenharmony_ci    (void)curl_easy_setopt(per->curl, CURLOPT_NOPROGRESS, 0L);
229313498266Sopenharmony_ci
229413498266Sopenharmony_ci    mcode = curl_multi_add_handle(multi, per->curl);
229513498266Sopenharmony_ci    if(mcode) {
229613498266Sopenharmony_ci      DEBUGASSERT(mcode == CURLM_OUT_OF_MEMORY);
229713498266Sopenharmony_ci      result = CURLE_OUT_OF_MEMORY;
229813498266Sopenharmony_ci    }
229913498266Sopenharmony_ci
230013498266Sopenharmony_ci    if(!result)
230113498266Sopenharmony_ci      result = create_transfer(global, share, &getadded);
230213498266Sopenharmony_ci    if(result) {
230313498266Sopenharmony_ci      free(errorbuf);
230413498266Sopenharmony_ci      return result;
230513498266Sopenharmony_ci    }
230613498266Sopenharmony_ci    errorbuf[0] = 0;
230713498266Sopenharmony_ci    (void)curl_easy_setopt(per->curl, CURLOPT_ERRORBUFFER, errorbuf);
230813498266Sopenharmony_ci    per->errorbuffer = errorbuf;
230913498266Sopenharmony_ci    per->added = TRUE;
231013498266Sopenharmony_ci    all_added++;
231113498266Sopenharmony_ci    *addedp = TRUE;
231213498266Sopenharmony_ci  }
231313498266Sopenharmony_ci  *morep = (per || sleeping) ? TRUE : FALSE;
231413498266Sopenharmony_ci  return CURLE_OK;
231513498266Sopenharmony_ci}
231613498266Sopenharmony_ci
231713498266Sopenharmony_cistatic CURLcode parallel_transfers(struct GlobalConfig *global,
231813498266Sopenharmony_ci                                   CURLSH *share)
231913498266Sopenharmony_ci{
232013498266Sopenharmony_ci  CURLM *multi;
232113498266Sopenharmony_ci  CURLMcode mcode = CURLM_OK;
232213498266Sopenharmony_ci  CURLcode result = CURLE_OK;
232313498266Sopenharmony_ci  int still_running = 1;
232413498266Sopenharmony_ci  struct timeval start = tvnow();
232513498266Sopenharmony_ci  bool more_transfers;
232613498266Sopenharmony_ci  bool added_transfers;
232713498266Sopenharmony_ci  /* wrapitup is set TRUE after a critical error occurs to end all transfers */
232813498266Sopenharmony_ci  bool wrapitup = FALSE;
232913498266Sopenharmony_ci  /* wrapitup_processed is set TRUE after the per transfer abort flag is set */
233013498266Sopenharmony_ci  bool wrapitup_processed = FALSE;
233113498266Sopenharmony_ci  time_t tick = time(NULL);
233213498266Sopenharmony_ci
233313498266Sopenharmony_ci  multi = curl_multi_init();
233413498266Sopenharmony_ci  if(!multi)
233513498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
233613498266Sopenharmony_ci
233713498266Sopenharmony_ci  result = add_parallel_transfers(global, multi, share,
233813498266Sopenharmony_ci                                  &more_transfers, &added_transfers);
233913498266Sopenharmony_ci  if(result) {
234013498266Sopenharmony_ci    curl_multi_cleanup(multi);
234113498266Sopenharmony_ci    return result;
234213498266Sopenharmony_ci  }
234313498266Sopenharmony_ci
234413498266Sopenharmony_ci  while(!mcode && (still_running || more_transfers)) {
234513498266Sopenharmony_ci    /* If stopping prematurely (eg due to a --fail-early condition) then signal
234613498266Sopenharmony_ci       that any transfers in the multi should abort (via progress callback). */
234713498266Sopenharmony_ci    if(wrapitup) {
234813498266Sopenharmony_ci      if(!still_running)
234913498266Sopenharmony_ci        break;
235013498266Sopenharmony_ci      if(!wrapitup_processed) {
235113498266Sopenharmony_ci        struct per_transfer *per;
235213498266Sopenharmony_ci        for(per = transfers; per; per = per->next) {
235313498266Sopenharmony_ci          if(per->added)
235413498266Sopenharmony_ci            per->abort = TRUE;
235513498266Sopenharmony_ci        }
235613498266Sopenharmony_ci        wrapitup_processed = TRUE;
235713498266Sopenharmony_ci      }
235813498266Sopenharmony_ci    }
235913498266Sopenharmony_ci
236013498266Sopenharmony_ci    mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL);
236113498266Sopenharmony_ci    if(!mcode)
236213498266Sopenharmony_ci      mcode = curl_multi_perform(multi, &still_running);
236313498266Sopenharmony_ci
236413498266Sopenharmony_ci    progress_meter(global, &start, FALSE);
236513498266Sopenharmony_ci
236613498266Sopenharmony_ci    if(!mcode) {
236713498266Sopenharmony_ci      int rc;
236813498266Sopenharmony_ci      CURLMsg *msg;
236913498266Sopenharmony_ci      bool checkmore = FALSE;
237013498266Sopenharmony_ci      do {
237113498266Sopenharmony_ci        msg = curl_multi_info_read(multi, &rc);
237213498266Sopenharmony_ci        if(msg) {
237313498266Sopenharmony_ci          bool retry;
237413498266Sopenharmony_ci          long delay;
237513498266Sopenharmony_ci          struct per_transfer *ended;
237613498266Sopenharmony_ci          CURL *easy = msg->easy_handle;
237713498266Sopenharmony_ci          CURLcode tres = msg->data.result;
237813498266Sopenharmony_ci          curl_easy_getinfo(easy, CURLINFO_PRIVATE, (void *)&ended);
237913498266Sopenharmony_ci          curl_multi_remove_handle(multi, easy);
238013498266Sopenharmony_ci
238113498266Sopenharmony_ci          if(ended->abort && (tres == CURLE_ABORTED_BY_CALLBACK) &&
238213498266Sopenharmony_ci             ended->errorbuffer) {
238313498266Sopenharmony_ci            msnprintf(ended->errorbuffer, CURL_ERROR_SIZE,
238413498266Sopenharmony_ci                      "Transfer aborted due to critical error "
238513498266Sopenharmony_ci                      "in another transfer");
238613498266Sopenharmony_ci          }
238713498266Sopenharmony_ci          tres = post_per_transfer(global, ended, tres, &retry, &delay);
238813498266Sopenharmony_ci          progress_finalize(ended); /* before it goes away */
238913498266Sopenharmony_ci          all_added--; /* one fewer added */
239013498266Sopenharmony_ci          checkmore = TRUE;
239113498266Sopenharmony_ci          if(retry) {
239213498266Sopenharmony_ci            ended->added = FALSE; /* add it again */
239313498266Sopenharmony_ci            /* we delay retries in full integer seconds only */
239413498266Sopenharmony_ci            ended->startat = delay ? time(NULL) + delay/1000 : 0;
239513498266Sopenharmony_ci          }
239613498266Sopenharmony_ci          else {
239713498266Sopenharmony_ci            /* result receives this transfer's error unless the transfer was
239813498266Sopenharmony_ci               marked for abort due to a critical error in another transfer */
239913498266Sopenharmony_ci            if(tres && (!ended->abort || !result))
240013498266Sopenharmony_ci              result = tres;
240113498266Sopenharmony_ci            if(is_fatal_error(result) || (result && global->fail_early))
240213498266Sopenharmony_ci              wrapitup = TRUE;
240313498266Sopenharmony_ci            (void)del_per_transfer(ended);
240413498266Sopenharmony_ci          }
240513498266Sopenharmony_ci        }
240613498266Sopenharmony_ci      } while(msg);
240713498266Sopenharmony_ci      if(wrapitup) {
240813498266Sopenharmony_ci        if(still_running)
240913498266Sopenharmony_ci          continue;
241013498266Sopenharmony_ci        else
241113498266Sopenharmony_ci          break;
241213498266Sopenharmony_ci      }
241313498266Sopenharmony_ci      if(!checkmore) {
241413498266Sopenharmony_ci        time_t tock = time(NULL);
241513498266Sopenharmony_ci        if(tick != tock) {
241613498266Sopenharmony_ci          checkmore = TRUE;
241713498266Sopenharmony_ci          tick = tock;
241813498266Sopenharmony_ci        }
241913498266Sopenharmony_ci      }
242013498266Sopenharmony_ci      if(checkmore) {
242113498266Sopenharmony_ci        /* one or more transfers completed, add more! */
242213498266Sopenharmony_ci        CURLcode tres = add_parallel_transfers(global, multi, share,
242313498266Sopenharmony_ci                                               &more_transfers,
242413498266Sopenharmony_ci                                               &added_transfers);
242513498266Sopenharmony_ci        if(tres)
242613498266Sopenharmony_ci          result = tres;
242713498266Sopenharmony_ci        if(added_transfers)
242813498266Sopenharmony_ci          /* we added new ones, make sure the loop doesn't exit yet */
242913498266Sopenharmony_ci          still_running = 1;
243013498266Sopenharmony_ci      }
243113498266Sopenharmony_ci      if(is_fatal_error(result) || (result && global->fail_early))
243213498266Sopenharmony_ci        wrapitup = TRUE;
243313498266Sopenharmony_ci    }
243413498266Sopenharmony_ci  }
243513498266Sopenharmony_ci
243613498266Sopenharmony_ci  (void)progress_meter(global, &start, TRUE);
243713498266Sopenharmony_ci
243813498266Sopenharmony_ci  /* Make sure to return some kind of error if there was a multi problem */
243913498266Sopenharmony_ci  if(mcode) {
244013498266Sopenharmony_ci    result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
244113498266Sopenharmony_ci      /* The other multi errors should never happen, so return
244213498266Sopenharmony_ci         something suitably generic */
244313498266Sopenharmony_ci      CURLE_BAD_FUNCTION_ARGUMENT;
244413498266Sopenharmony_ci  }
244513498266Sopenharmony_ci
244613498266Sopenharmony_ci  curl_multi_cleanup(multi);
244713498266Sopenharmony_ci
244813498266Sopenharmony_ci  return result;
244913498266Sopenharmony_ci}
245013498266Sopenharmony_ci
245113498266Sopenharmony_cistatic CURLcode serial_transfers(struct GlobalConfig *global,
245213498266Sopenharmony_ci                                 CURLSH *share)
245313498266Sopenharmony_ci{
245413498266Sopenharmony_ci  CURLcode returncode = CURLE_OK;
245513498266Sopenharmony_ci  CURLcode result = CURLE_OK;
245613498266Sopenharmony_ci  struct per_transfer *per;
245713498266Sopenharmony_ci  bool added = FALSE;
245813498266Sopenharmony_ci
245913498266Sopenharmony_ci  result = create_transfer(global, share, &added);
246013498266Sopenharmony_ci  if(result)
246113498266Sopenharmony_ci    return result;
246213498266Sopenharmony_ci  if(!added) {
246313498266Sopenharmony_ci    errorf(global, "no transfer performed");
246413498266Sopenharmony_ci    return CURLE_READ_ERROR;
246513498266Sopenharmony_ci  }
246613498266Sopenharmony_ci  for(per = transfers; per;) {
246713498266Sopenharmony_ci    bool retry;
246813498266Sopenharmony_ci    long delay_ms;
246913498266Sopenharmony_ci    bool bailout = FALSE;
247013498266Sopenharmony_ci    struct timeval start;
247113498266Sopenharmony_ci    result = pre_transfer(global, per);
247213498266Sopenharmony_ci    if(result)
247313498266Sopenharmony_ci      break;
247413498266Sopenharmony_ci
247513498266Sopenharmony_ci    if(global->libcurl) {
247613498266Sopenharmony_ci      result = easysrc_perform();
247713498266Sopenharmony_ci      if(result)
247813498266Sopenharmony_ci        break;
247913498266Sopenharmony_ci    }
248013498266Sopenharmony_ci    start = tvnow();
248113498266Sopenharmony_ci#ifdef CURLDEBUG
248213498266Sopenharmony_ci    if(global->test_event_based)
248313498266Sopenharmony_ci      result = curl_easy_perform_ev(per->curl);
248413498266Sopenharmony_ci    else
248513498266Sopenharmony_ci#endif
248613498266Sopenharmony_ci      result = curl_easy_perform(per->curl);
248713498266Sopenharmony_ci
248813498266Sopenharmony_ci    returncode = post_per_transfer(global, per, result, &retry, &delay_ms);
248913498266Sopenharmony_ci    if(retry) {
249013498266Sopenharmony_ci      tool_go_sleep(delay_ms);
249113498266Sopenharmony_ci      continue;
249213498266Sopenharmony_ci    }
249313498266Sopenharmony_ci
249413498266Sopenharmony_ci    /* Bail out upon critical errors or --fail-early */
249513498266Sopenharmony_ci    if(is_fatal_error(returncode) || (returncode && global->fail_early))
249613498266Sopenharmony_ci      bailout = TRUE;
249713498266Sopenharmony_ci    else {
249813498266Sopenharmony_ci      /* setup the next one just before we delete this */
249913498266Sopenharmony_ci      result = create_transfer(global, share, &added);
250013498266Sopenharmony_ci      if(result) {
250113498266Sopenharmony_ci        returncode = result;
250213498266Sopenharmony_ci        bailout = TRUE;
250313498266Sopenharmony_ci      }
250413498266Sopenharmony_ci    }
250513498266Sopenharmony_ci
250613498266Sopenharmony_ci    per = del_per_transfer(per);
250713498266Sopenharmony_ci
250813498266Sopenharmony_ci    if(bailout)
250913498266Sopenharmony_ci      break;
251013498266Sopenharmony_ci
251113498266Sopenharmony_ci    if(per && global->ms_per_transfer) {
251213498266Sopenharmony_ci      /* how long time did the most recent transfer take in number of
251313498266Sopenharmony_ci         milliseconds */
251413498266Sopenharmony_ci      long milli = tvdiff(tvnow(), start);
251513498266Sopenharmony_ci      if(milli < global->ms_per_transfer) {
251613498266Sopenharmony_ci        notef(global, "Transfer took %ld ms, waits %ldms as set by --rate",
251713498266Sopenharmony_ci              milli, global->ms_per_transfer - milli);
251813498266Sopenharmony_ci        /* The transfer took less time than wanted. Wait a little. */
251913498266Sopenharmony_ci        tool_go_sleep(global->ms_per_transfer - milli);
252013498266Sopenharmony_ci      }
252113498266Sopenharmony_ci    }
252213498266Sopenharmony_ci  }
252313498266Sopenharmony_ci  if(returncode)
252413498266Sopenharmony_ci    /* returncode errors have priority */
252513498266Sopenharmony_ci    result = returncode;
252613498266Sopenharmony_ci
252713498266Sopenharmony_ci  if(result)
252813498266Sopenharmony_ci    single_transfer_cleanup(global->current);
252913498266Sopenharmony_ci
253013498266Sopenharmony_ci  return result;
253113498266Sopenharmony_ci}
253213498266Sopenharmony_ci
253313498266Sopenharmony_ci/* setup a transfer for the given config */
253413498266Sopenharmony_cistatic CURLcode transfer_per_config(struct GlobalConfig *global,
253513498266Sopenharmony_ci                                    struct OperationConfig *config,
253613498266Sopenharmony_ci                                    CURLSH *share,
253713498266Sopenharmony_ci                                    bool *added)
253813498266Sopenharmony_ci{
253913498266Sopenharmony_ci  CURLcode result = CURLE_OK;
254013498266Sopenharmony_ci  bool capath_from_env;
254113498266Sopenharmony_ci  *added = FALSE;
254213498266Sopenharmony_ci
254313498266Sopenharmony_ci  /* Check we have a url */
254413498266Sopenharmony_ci  if(!config->url_list || !config->url_list->url) {
254513498266Sopenharmony_ci    helpf(tool_stderr, "(%d) no URL specified", CURLE_FAILED_INIT);
254613498266Sopenharmony_ci    return CURLE_FAILED_INIT;
254713498266Sopenharmony_ci  }
254813498266Sopenharmony_ci
254913498266Sopenharmony_ci  /* On WIN32 we can't set the path to curl-ca-bundle.crt
255013498266Sopenharmony_ci   * at compile time. So we look here for the file in two ways:
255113498266Sopenharmony_ci   * 1: look at the environment variable CURL_CA_BUNDLE for a path
255213498266Sopenharmony_ci   * 2: if #1 isn't found, use the windows API function SearchPath()
255313498266Sopenharmony_ci   *    to find it along the app's path (includes app's dir and CWD)
255413498266Sopenharmony_ci   *
255513498266Sopenharmony_ci   * We support the environment variable thing for non-Windows platforms
255613498266Sopenharmony_ci   * too. Just for the sake of it.
255713498266Sopenharmony_ci   */
255813498266Sopenharmony_ci  capath_from_env = false;
255913498266Sopenharmony_ci  if(!config->cacert &&
256013498266Sopenharmony_ci     !config->capath &&
256113498266Sopenharmony_ci     (!config->insecure_ok || (config->doh_url && !config->doh_insecure_ok))) {
256213498266Sopenharmony_ci    CURL *curltls = curl_easy_init();
256313498266Sopenharmony_ci    struct curl_tlssessioninfo *tls_backend_info = NULL;
256413498266Sopenharmony_ci
256513498266Sopenharmony_ci    /* With the addition of CAINFO support for Schannel, this search could find
256613498266Sopenharmony_ci     * a certificate bundle that was previously ignored. To maintain backward
256713498266Sopenharmony_ci     * compatibility, only perform this search if not using Schannel.
256813498266Sopenharmony_ci     */
256913498266Sopenharmony_ci    result = curl_easy_getinfo(curltls, CURLINFO_TLS_SSL_PTR,
257013498266Sopenharmony_ci                               &tls_backend_info);
257113498266Sopenharmony_ci    if(result) {
257213498266Sopenharmony_ci      curl_easy_cleanup(curltls);
257313498266Sopenharmony_ci      return result;
257413498266Sopenharmony_ci    }
257513498266Sopenharmony_ci
257613498266Sopenharmony_ci    /* Set the CA cert locations specified in the environment. For Windows if
257713498266Sopenharmony_ci     * no environment-specified filename is found then check for CA bundle
257813498266Sopenharmony_ci     * default filename curl-ca-bundle.crt in the user's PATH.
257913498266Sopenharmony_ci     *
258013498266Sopenharmony_ci     * If Schannel is the selected SSL backend then these locations are
258113498266Sopenharmony_ci     * ignored. We allow setting CA location for schannel only when explicitly
258213498266Sopenharmony_ci     * specified by the user via CURLOPT_CAINFO / --cacert.
258313498266Sopenharmony_ci     */
258413498266Sopenharmony_ci    if(tls_backend_info->backend != CURLSSLBACKEND_SCHANNEL) {
258513498266Sopenharmony_ci      char *env;
258613498266Sopenharmony_ci      env = curlx_getenv("CURL_CA_BUNDLE");
258713498266Sopenharmony_ci      if(env) {
258813498266Sopenharmony_ci        config->cacert = strdup(env);
258913498266Sopenharmony_ci        if(!config->cacert) {
259013498266Sopenharmony_ci          curl_free(env);
259113498266Sopenharmony_ci          curl_easy_cleanup(curltls);
259213498266Sopenharmony_ci          errorf(global, "out of memory");
259313498266Sopenharmony_ci          return CURLE_OUT_OF_MEMORY;
259413498266Sopenharmony_ci        }
259513498266Sopenharmony_ci      }
259613498266Sopenharmony_ci      else {
259713498266Sopenharmony_ci        env = curlx_getenv("SSL_CERT_DIR");
259813498266Sopenharmony_ci        if(env) {
259913498266Sopenharmony_ci          config->capath = strdup(env);
260013498266Sopenharmony_ci          if(!config->capath) {
260113498266Sopenharmony_ci            curl_free(env);
260213498266Sopenharmony_ci            curl_easy_cleanup(curltls);
260313498266Sopenharmony_ci            errorf(global, "out of memory");
260413498266Sopenharmony_ci            return CURLE_OUT_OF_MEMORY;
260513498266Sopenharmony_ci          }
260613498266Sopenharmony_ci          curl_free(env);
260713498266Sopenharmony_ci          capath_from_env = true;
260813498266Sopenharmony_ci        }
260913498266Sopenharmony_ci        env = curlx_getenv("SSL_CERT_FILE");
261013498266Sopenharmony_ci        if(env) {
261113498266Sopenharmony_ci          config->cacert = strdup(env);
261213498266Sopenharmony_ci          if(!config->cacert) {
261313498266Sopenharmony_ci            curl_free(env);
261413498266Sopenharmony_ci            if(capath_from_env)
261513498266Sopenharmony_ci              free(config->capath);
261613498266Sopenharmony_ci            curl_easy_cleanup(curltls);
261713498266Sopenharmony_ci            errorf(global, "out of memory");
261813498266Sopenharmony_ci            return CURLE_OUT_OF_MEMORY;
261913498266Sopenharmony_ci          }
262013498266Sopenharmony_ci        }
262113498266Sopenharmony_ci      }
262213498266Sopenharmony_ci
262313498266Sopenharmony_ci      if(env)
262413498266Sopenharmony_ci        curl_free(env);
262513498266Sopenharmony_ci#ifdef _WIN32
262613498266Sopenharmony_ci      else {
262713498266Sopenharmony_ci        result = FindWin32CACert(config, tls_backend_info->backend,
262813498266Sopenharmony_ci                                 TEXT("curl-ca-bundle.crt"));
262913498266Sopenharmony_ci      }
263013498266Sopenharmony_ci#endif
263113498266Sopenharmony_ci    }
263213498266Sopenharmony_ci    curl_easy_cleanup(curltls);
263313498266Sopenharmony_ci  }
263413498266Sopenharmony_ci
263513498266Sopenharmony_ci  if(!result)
263613498266Sopenharmony_ci    result = single_transfer(global, config, share, capath_from_env, added);
263713498266Sopenharmony_ci
263813498266Sopenharmony_ci  return result;
263913498266Sopenharmony_ci}
264013498266Sopenharmony_ci
264113498266Sopenharmony_ci/*
264213498266Sopenharmony_ci * 'create_transfer' gets the details and sets up a new transfer if 'added'
264313498266Sopenharmony_ci * returns TRUE.
264413498266Sopenharmony_ci */
264513498266Sopenharmony_cistatic CURLcode create_transfer(struct GlobalConfig *global,
264613498266Sopenharmony_ci                                CURLSH *share,
264713498266Sopenharmony_ci                                bool *added)
264813498266Sopenharmony_ci{
264913498266Sopenharmony_ci  CURLcode result = CURLE_OK;
265013498266Sopenharmony_ci  *added = FALSE;
265113498266Sopenharmony_ci  while(global->current) {
265213498266Sopenharmony_ci    result = transfer_per_config(global, global->current, share, added);
265313498266Sopenharmony_ci    if(!result && !*added) {
265413498266Sopenharmony_ci      /* when one set is drained, continue to next */
265513498266Sopenharmony_ci      global->current = global->current->next;
265613498266Sopenharmony_ci      continue;
265713498266Sopenharmony_ci    }
265813498266Sopenharmony_ci    break;
265913498266Sopenharmony_ci  }
266013498266Sopenharmony_ci  return result;
266113498266Sopenharmony_ci}
266213498266Sopenharmony_ci
266313498266Sopenharmony_cistatic CURLcode run_all_transfers(struct GlobalConfig *global,
266413498266Sopenharmony_ci                                  CURLSH *share,
266513498266Sopenharmony_ci                                  CURLcode result)
266613498266Sopenharmony_ci{
266713498266Sopenharmony_ci  /* Save the values of noprogress and isatty to restore them later on */
266813498266Sopenharmony_ci  bool orig_noprogress = global->noprogress;
266913498266Sopenharmony_ci  bool orig_isatty = global->isatty;
267013498266Sopenharmony_ci  struct per_transfer *per;
267113498266Sopenharmony_ci
267213498266Sopenharmony_ci  /* Time to actually do the transfers */
267313498266Sopenharmony_ci  if(!result) {
267413498266Sopenharmony_ci    if(global->parallel)
267513498266Sopenharmony_ci      result = parallel_transfers(global, share);
267613498266Sopenharmony_ci    else
267713498266Sopenharmony_ci      result = serial_transfers(global, share);
267813498266Sopenharmony_ci  }
267913498266Sopenharmony_ci
268013498266Sopenharmony_ci  /* cleanup if there are any left */
268113498266Sopenharmony_ci  for(per = transfers; per;) {
268213498266Sopenharmony_ci    bool retry;
268313498266Sopenharmony_ci    long delay;
268413498266Sopenharmony_ci    CURLcode result2 = post_per_transfer(global, per, result, &retry, &delay);
268513498266Sopenharmony_ci    if(!result)
268613498266Sopenharmony_ci      /* don't overwrite the original error */
268713498266Sopenharmony_ci      result = result2;
268813498266Sopenharmony_ci
268913498266Sopenharmony_ci    /* Free list of given URLs */
269013498266Sopenharmony_ci    clean_getout(per->config);
269113498266Sopenharmony_ci
269213498266Sopenharmony_ci    per = del_per_transfer(per);
269313498266Sopenharmony_ci  }
269413498266Sopenharmony_ci
269513498266Sopenharmony_ci  /* Reset the global config variables */
269613498266Sopenharmony_ci  global->noprogress = orig_noprogress;
269713498266Sopenharmony_ci  global->isatty = orig_isatty;
269813498266Sopenharmony_ci
269913498266Sopenharmony_ci
270013498266Sopenharmony_ci  return result;
270113498266Sopenharmony_ci}
270213498266Sopenharmony_ci
270313498266Sopenharmony_ciCURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[])
270413498266Sopenharmony_ci{
270513498266Sopenharmony_ci  CURLcode result = CURLE_OK;
270613498266Sopenharmony_ci  char *first_arg = argc > 1 ? curlx_convert_tchar_to_UTF8(argv[1]) : NULL;
270713498266Sopenharmony_ci
270813498266Sopenharmony_ci#ifdef HAVE_SETLOCALE
270913498266Sopenharmony_ci  /* Override locale for number parsing (only) */
271013498266Sopenharmony_ci  setlocale(LC_ALL, "");
271113498266Sopenharmony_ci  setlocale(LC_NUMERIC, "C");
271213498266Sopenharmony_ci#endif
271313498266Sopenharmony_ci
271413498266Sopenharmony_ci  /* Parse .curlrc if necessary */
271513498266Sopenharmony_ci  if((argc == 1) ||
271613498266Sopenharmony_ci     (first_arg && strncmp(first_arg, "-q", 2) &&
271713498266Sopenharmony_ci      !curl_strequal(first_arg, "--disable"))) {
271813498266Sopenharmony_ci    parseconfig(NULL, global); /* ignore possible failure */
271913498266Sopenharmony_ci
272013498266Sopenharmony_ci    /* If we had no arguments then make sure a url was specified in .curlrc */
272113498266Sopenharmony_ci    if((argc < 2) && (!global->first->url_list)) {
272213498266Sopenharmony_ci      helpf(tool_stderr, NULL);
272313498266Sopenharmony_ci      result = CURLE_FAILED_INIT;
272413498266Sopenharmony_ci    }
272513498266Sopenharmony_ci  }
272613498266Sopenharmony_ci
272713498266Sopenharmony_ci  curlx_unicodefree(first_arg);
272813498266Sopenharmony_ci
272913498266Sopenharmony_ci  if(!result) {
273013498266Sopenharmony_ci    /* Parse the command line arguments */
273113498266Sopenharmony_ci    ParameterError res = parse_args(global, argc, argv);
273213498266Sopenharmony_ci    if(res) {
273313498266Sopenharmony_ci      result = CURLE_OK;
273413498266Sopenharmony_ci
273513498266Sopenharmony_ci      /* Check if we were asked for the help */
273613498266Sopenharmony_ci      if(res == PARAM_HELP_REQUESTED)
273713498266Sopenharmony_ci        tool_help(global->help_category);
273813498266Sopenharmony_ci      /* Check if we were asked for the manual */
273913498266Sopenharmony_ci      else if(res == PARAM_MANUAL_REQUESTED)
274013498266Sopenharmony_ci        hugehelp();
274113498266Sopenharmony_ci      /* Check if we were asked for the version information */
274213498266Sopenharmony_ci      else if(res == PARAM_VERSION_INFO_REQUESTED)
274313498266Sopenharmony_ci        tool_version_info();
274413498266Sopenharmony_ci      /* Check if we were asked to list the SSL engines */
274513498266Sopenharmony_ci      else if(res == PARAM_ENGINES_REQUESTED)
274613498266Sopenharmony_ci        tool_list_engines();
274713498266Sopenharmony_ci      else if(res == PARAM_LIBCURL_UNSUPPORTED_PROTOCOL)
274813498266Sopenharmony_ci        result = CURLE_UNSUPPORTED_PROTOCOL;
274913498266Sopenharmony_ci      else if(res == PARAM_READ_ERROR)
275013498266Sopenharmony_ci        result = CURLE_READ_ERROR;
275113498266Sopenharmony_ci      else
275213498266Sopenharmony_ci        result = CURLE_FAILED_INIT;
275313498266Sopenharmony_ci    }
275413498266Sopenharmony_ci    else {
275513498266Sopenharmony_ci      if(global->libcurl) {
275613498266Sopenharmony_ci        /* Initialise the libcurl source output */
275713498266Sopenharmony_ci        result = easysrc_init();
275813498266Sopenharmony_ci      }
275913498266Sopenharmony_ci
276013498266Sopenharmony_ci      /* Perform the main operations */
276113498266Sopenharmony_ci      if(!result) {
276213498266Sopenharmony_ci        size_t count = 0;
276313498266Sopenharmony_ci        struct OperationConfig *operation = global->first;
276413498266Sopenharmony_ci        CURLSH *share = curl_share_init();
276513498266Sopenharmony_ci        if(!share) {
276613498266Sopenharmony_ci          if(global->libcurl) {
276713498266Sopenharmony_ci            /* Cleanup the libcurl source output */
276813498266Sopenharmony_ci            easysrc_cleanup();
276913498266Sopenharmony_ci          }
277013498266Sopenharmony_ci          result = CURLE_OUT_OF_MEMORY;
277113498266Sopenharmony_ci        }
277213498266Sopenharmony_ci
277313498266Sopenharmony_ci        if(!result) {
277413498266Sopenharmony_ci          curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
277513498266Sopenharmony_ci          curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
277613498266Sopenharmony_ci          curl_share_setopt(share, CURLSHOPT_SHARE,
277713498266Sopenharmony_ci                            CURL_LOCK_DATA_SSL_SESSION);
277813498266Sopenharmony_ci          curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
277913498266Sopenharmony_ci          curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_PSL);
278013498266Sopenharmony_ci          curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_HSTS);
278113498266Sopenharmony_ci
278213498266Sopenharmony_ci          /* Get the required arguments for each operation */
278313498266Sopenharmony_ci          do {
278413498266Sopenharmony_ci            result = get_args(operation, count++);
278513498266Sopenharmony_ci
278613498266Sopenharmony_ci            operation = operation->next;
278713498266Sopenharmony_ci          } while(!result && operation);
278813498266Sopenharmony_ci
278913498266Sopenharmony_ci          /* Set the current operation pointer */
279013498266Sopenharmony_ci          global->current = global->first;
279113498266Sopenharmony_ci
279213498266Sopenharmony_ci          /* now run! */
279313498266Sopenharmony_ci          result = run_all_transfers(global, share, result);
279413498266Sopenharmony_ci
279513498266Sopenharmony_ci          curl_share_cleanup(share);
279613498266Sopenharmony_ci          if(global->libcurl) {
279713498266Sopenharmony_ci            /* Cleanup the libcurl source output */
279813498266Sopenharmony_ci            easysrc_cleanup();
279913498266Sopenharmony_ci
280013498266Sopenharmony_ci            /* Dump the libcurl code if previously enabled */
280113498266Sopenharmony_ci            dumpeasysrc(global);
280213498266Sopenharmony_ci          }
280313498266Sopenharmony_ci        }
280413498266Sopenharmony_ci      }
280513498266Sopenharmony_ci      else
280613498266Sopenharmony_ci        errorf(global, "out of memory");
280713498266Sopenharmony_ci    }
280813498266Sopenharmony_ci  }
280913498266Sopenharmony_ci
281013498266Sopenharmony_ci  varcleanup(global);
281113498266Sopenharmony_ci
281213498266Sopenharmony_ci  return result;
281313498266Sopenharmony_ci}
2814