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