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


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:16