Generate lists and use symbols in --libcurl code output.
[platform/upstream/curl.git] / src / tool_operate.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2012, 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 http://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 "setup.h"
23
24 #include <curl/curl.h>
25
26 #ifdef HAVE_UNISTD_H
27 #  include <unistd.h>
28 #endif
29
30 #ifdef HAVE_FCNTL_H
31 #  include <fcntl.h>
32 #endif
33
34 #ifdef HAVE_UTIME_H
35 #  include <utime.h>
36 #elif defined(HAVE_SYS_UTIME_H)
37 #  include <sys/utime.h>
38 #endif
39
40 #ifdef HAVE_LOCALE_H
41 #  include <locale.h>
42 #endif
43
44 #ifdef HAVE_NETINET_TCP_H
45 #  include <netinet/tcp.h>
46 #endif
47
48 #include "rawstr.h"
49
50 #define ENABLE_CURLX_PRINTF
51 /* use our own printf() functions */
52 #include "curlx.h"
53
54 #include "tool_binmode.h"
55 #include "tool_cfgable.h"
56 #include "tool_cb_dbg.h"
57 #include "tool_cb_hdr.h"
58 #include "tool_cb_prg.h"
59 #include "tool_cb_rea.h"
60 #include "tool_cb_see.h"
61 #include "tool_cb_wrt.h"
62 #include "tool_dirhie.h"
63 #include "tool_doswin.h"
64 #include "tool_easysrc.h"
65 #include "tool_getparam.h"
66 #include "tool_helpers.h"
67 #include "tool_homedir.h"
68 #include "tool_libinfo.h"
69 #include "tool_main.h"
70 #include "tool_msgs.h"
71 #include "tool_operate.h"
72 #include "tool_operhlp.h"
73 #include "tool_parsecfg.h"
74 #include "tool_setopt.h"
75 #include "tool_sleep.h"
76 #include "tool_urlglob.h"
77 #include "tool_util.h"
78 #include "tool_writeenv.h"
79 #include "tool_writeout.h"
80 #include "tool_xattr.h"
81
82 #include "memdebug.h" /* keep this as LAST include */
83
84 #define CURLseparator  "--_curl_--"
85
86 #ifndef O_BINARY
87 /* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
88    source code but yet it doesn't ruin anything */
89 #  define O_BINARY 0
90 #endif
91
92 #define CURL_CA_CERT_ERRORMSG1                                              \
93   "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n"           \
94   "curl performs SSL certificate verification by default, "                 \
95   "using a \"bundle\"\n"                                                    \
96   " of Certificate Authority (CA) public keys (CA certs). If the default\n" \
97   " bundle file isn't adequate, you can specify an alternate file\n"        \
98   " using the --cacert option.\n"
99
100 #define CURL_CA_CERT_ERRORMSG2                                              \
101   "If this HTTPS server uses a certificate signed by a CA represented in\n" \
102   " the bundle, the certificate verification probably failed due to a\n"    \
103   " problem with the certificate (it might be expired, or the name might\n" \
104   " not match the domain name in the URL).\n"                               \
105   "If you'd like to turn off curl's verification of the certificate, use\n" \
106   " the -k (or --insecure) option.\n"
107
108 static int is_fatal_error(int code)
109 {
110   switch(code) {
111   /* TODO: Should CURLE_SSL_CACERT be included as critical error ? */
112   case CURLE_FAILED_INIT:
113   case CURLE_OUT_OF_MEMORY:
114   case CURLE_UNKNOWN_OPTION:
115   case CURLE_FUNCTION_NOT_FOUND:
116   case CURLE_BAD_FUNCTION_ARGUMENT:
117     /* critical error */
118     return 1;
119   default:
120     break;
121   }
122   /* no error or not critical */
123   return 0;
124 }
125
126 int operate(struct Configurable *config, int argc, argv_item_t argv[])
127 {
128   char errorbuffer[CURL_ERROR_SIZE];
129   struct ProgressData progressbar;
130   struct getout *urlnode;
131
132   struct OutStruct heads;
133
134   CURL *curl = NULL;
135   char *httpgetfields = NULL;
136
137   bool stillflags;
138   int res = 0;
139   int i;
140
141   errorbuffer[0] = '\0';
142   /* default headers output stream is stdout */
143   memset(&heads, 0, sizeof(struct OutStruct));
144   heads.stream = stdout;
145   heads.config = config;
146
147   memory_tracking_init();
148
149   /*
150   ** Initialize curl library - do not call any libcurl functions before
151   ** this point. Note that the memory_tracking_init() magic above is an
152   ** exception, but then that's not part of the official public API.
153   */
154   if(main_init() != CURLE_OK) {
155     helpf(config->errors, "error initializing curl library\n");
156     return CURLE_FAILED_INIT;
157   }
158
159   /* Get libcurl info right away */
160   if(get_libcurl_info() != CURLE_OK) {
161     helpf(config->errors, "error retrieving curl library information\n");
162     main_free();
163     return CURLE_FAILED_INIT;
164   }
165
166   /* Get a curl handle to use for all forthcoming curl transfers */
167   curl = curl_easy_init();
168   if(!curl) {
169     helpf(config->errors, "error initializing curl easy handle\n");
170     main_free();
171     return CURLE_FAILED_INIT;
172   }
173   config->easy = curl;
174
175   /*
176   ** Beyond this point no return'ing from this function allowed.
177   ** Jump to label 'quit_curl' in order to abandon this function
178   ** from outside of nested loops further down below.
179   */
180
181   /* setup proper locale from environment */
182 #ifdef HAVE_SETLOCALE
183   setlocale(LC_ALL, "");
184 #endif
185
186   /* inits */
187   config->postfieldsize = -1;
188   config->showerror = -1; /* will show errors */
189   config->use_httpget = FALSE;
190   config->create_dirs = FALSE;
191   config->maxredirs = DEFAULT_MAXREDIRS;
192   config->proto = CURLPROTO_ALL; /* FIXME: better to read from library */
193   config->proto_present = FALSE;
194   config->proto_redir =
195     CURLPROTO_ALL & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */
196   config->proto_redir_present = FALSE;
197
198   if((argc > 1) &&
199      (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
200      strchr(argv[1], 'q')) {
201     /*
202      * The first flag, that is not a verbose name, but a shortname
203      * and it includes the 'q' flag!
204      */
205     ;
206   }
207   else {
208     parseconfig(NULL, config); /* ignore possible failure */
209   }
210
211   if((argc < 2)  && !config->url_list) {
212     helpf(config->errors, NULL);
213     res = CURLE_FAILED_INIT;
214     goto quit_curl;
215   }
216
217   /* Parse options */
218   for(i = 1, stillflags = TRUE; i < argc; i++) {
219     if(stillflags &&
220        ('-' == argv[i][0])) {
221       char *nextarg;
222       bool passarg;
223       char *origopt = argv[i];
224
225       char *flag = argv[i];
226
227       if(curlx_strequal("--", argv[i]))
228         /* this indicates the end of the flags and thus enables the
229            following (URL) argument to start with -. */
230         stillflags = FALSE;
231       else {
232         nextarg = (i < (argc-1)) ? argv[i+1] : NULL;
233
234         res = getparameter(flag, nextarg, &passarg, config);
235         if(res) {
236           int retval = CURLE_OK;
237           if(res != PARAM_HELP_REQUESTED) {
238             const char *reason = param2text(res);
239             helpf(config->errors, "option %s: %s\n", origopt, reason);
240             retval = CURLE_FAILED_INIT;
241           }
242           res = retval;
243           goto quit_curl;
244         }
245
246         if(passarg) /* we're supposed to skip this */
247           i++;
248       }
249     }
250     else {
251       bool used;
252       /* just add the URL please */
253       res = getparameter((char *)"--url", argv[i], &used, config);
254       if(res)
255         goto quit_curl;
256     }
257   }
258
259   if((!config->url_list || !config->url_list->url) && !config->list_engines) {
260     helpf(config->errors, "no URL specified!\n");
261     res = CURLE_FAILED_INIT;
262     goto quit_curl;
263   }
264
265   if(!config->useragent)
266     config->useragent = my_useragent();
267   if(!config->useragent) {
268     helpf(config->errors, "out of memory\n");
269     res = CURLE_OUT_OF_MEMORY;
270     goto quit_curl;
271   }
272
273   /* On WIN32 we can't set the path to curl-ca-bundle.crt
274    * at compile time. So we look here for the file in two ways:
275    * 1: look at the environment variable CURL_CA_BUNDLE for a path
276    * 2: if #1 isn't found, use the windows API function SearchPath()
277    *    to find it along the app's path (includes app's dir and CWD)
278    *
279    * We support the environment variable thing for non-Windows platforms
280    * too. Just for the sake of it.
281    */
282   if(!config->cacert &&
283      !config->capath &&
284      !config->insecure_ok) {
285     char *env;
286     env = curlx_getenv("CURL_CA_BUNDLE");
287     if(env) {
288       config->cacert = strdup(env);
289       if(!config->cacert) {
290         curl_free(env);
291         helpf(config->errors, "out of memory\n");
292         res = CURLE_OUT_OF_MEMORY;
293         goto quit_curl;
294       }
295     }
296     else {
297       env = curlx_getenv("SSL_CERT_DIR");
298       if(env) {
299         config->capath = strdup(env);
300         if(!config->capath) {
301           curl_free(env);
302           helpf(config->errors, "out of memory\n");
303           res = CURLE_OUT_OF_MEMORY;
304           goto quit_curl;
305         }
306       }
307       else {
308         env = curlx_getenv("SSL_CERT_FILE");
309         if(env) {
310           config->cacert = strdup(env);
311           if(!config->cacert) {
312             curl_free(env);
313             helpf(config->errors, "out of memory\n");
314             res = CURLE_OUT_OF_MEMORY;
315             goto quit_curl;
316           }
317         }
318       }
319     }
320
321     if(env)
322       curl_free(env);
323 #ifdef WIN32
324     else {
325       res = FindWin32CACert(config, "curl-ca-bundle.crt");
326       if(res)
327         goto quit_curl;
328     }
329 #endif
330   }
331
332   if(config->postfields) {
333     if(config->use_httpget) {
334       /* Use the postfields data for a http get */
335       httpgetfields = strdup(config->postfields);
336       Curl_safefree(config->postfields);
337       if(!httpgetfields) {
338         helpf(config->errors, "out of memory\n");
339         res = CURLE_OUT_OF_MEMORY;
340         goto quit_curl;
341       }
342       if(SetHTTPrequest(config,
343                         (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
344                         &config->httpreq)) {
345         res = PARAM_BAD_USE;
346         goto quit_curl;
347       }
348     }
349     else {
350       if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq)) {
351         res = PARAM_BAD_USE;
352         goto quit_curl;
353       }
354     }
355   }
356
357 #ifndef CURL_DISABLE_LIBCURL_OPTION
358   res = easysrc_init();
359   if(res) {
360     helpf(config->errors, "out of memory\n");
361     goto quit_curl;
362   }
363 #endif
364
365   if(config->list_engines) {
366     struct curl_slist *engines = NULL;
367     curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines);
368     list_engines(engines);
369     curl_slist_free_all(engines);
370     res = CURLE_OK;
371     goto quit_curl;
372   }
373
374   /* Single header file for all URLs */
375   if(config->headerfile) {
376     /* open file for output: */
377     if(!curlx_strequal(config->headerfile, "-")) {
378       FILE *newfile = fopen(config->headerfile, "wb");
379       if(!newfile) {
380         warnf(config, "Failed to open %s\n", config->headerfile);
381         res = CURLE_WRITE_ERROR;
382         goto quit_curl;
383       }
384       else {
385         heads.filename = config->headerfile;
386         heads.s_isreg = TRUE;
387         heads.fopened = TRUE;
388         heads.stream = newfile;
389       }
390     }
391   }
392
393   /*
394   ** Nested loops start here.
395   */
396
397   /* loop through the list of given URLs */
398
399   for(urlnode = config->url_list; urlnode; urlnode = urlnode->next) {
400
401     int up; /* upload file counter within a single upload glob */
402     char *infiles; /* might be a glob pattern */
403     char *outfiles;
404     int infilenum;
405     URLGlob *inglob;
406
407     outfiles = NULL;
408     infilenum = 1;
409     inglob = NULL;
410
411     /* urlnode->url is the full URL (it might be NULL) */
412
413     if(!urlnode->url) {
414       /* This node has no URL. Free node data without destroying the
415          node itself nor modifying next pointer and continue to next */
416       Curl_safefree(urlnode->outfile);
417       Curl_safefree(urlnode->infile);
418       urlnode->flags = 0;
419       continue; /* next URL please */
420     }
421
422     /* save outfile pattern before expansion */
423     if(urlnode->outfile) {
424       outfiles = strdup(urlnode->outfile);
425       if(!outfiles) {
426         helpf(config->errors, "out of memory\n");
427         res = CURLE_OUT_OF_MEMORY;
428         break;
429       }
430     }
431
432     infiles = urlnode->infile;
433
434     if(!config->globoff && infiles) {
435       /* Unless explicitly shut off */
436       res = glob_url(&inglob, infiles, &infilenum,
437                      config->showerror?config->errors:NULL);
438       if(res) {
439         Curl_safefree(outfiles);
440         break;
441       }
442     }
443
444     /* Here's the loop for uploading multiple files within the same
445        single globbed string. If no upload, we enter the loop once anyway. */
446     for(up = 0 ; up < infilenum; up++) {
447
448       char *uploadfile; /* a single file, never a glob */
449       int separator;
450       URLGlob *urls;
451       int urlnum;
452
453       uploadfile = NULL;
454       separator = 0;
455       urls = NULL;
456       urlnum = 0;
457
458       if(!up && !infiles)
459         Curl_nop_stmt;
460       else {
461         if(inglob) {
462           res = glob_next_url(&uploadfile, inglob);
463           if(res == CURLE_OUT_OF_MEMORY)
464             helpf(config->errors, "out of memory\n");
465         }
466         else if(!up) {
467           uploadfile = strdup(infiles);
468           if(!uploadfile) {
469             helpf(config->errors, "out of memory\n");
470             res = CURLE_OUT_OF_MEMORY;
471           }
472         }
473         else
474           uploadfile = NULL;
475         if(!uploadfile)
476           break;
477       }
478
479       if(!config->globoff) {
480         /* Unless explicitly shut off, we expand '{...}' and '[...]'
481            expressions and return total number of URLs in pattern set */
482         res = glob_url(&urls, urlnode->url, &urlnum,
483                        config->showerror?config->errors:NULL);
484         if(res) {
485           Curl_safefree(uploadfile);
486           break;
487         }
488       }
489       else
490         urlnum = 1; /* without globbing, this is a single URL */
491
492       /* if multiple files extracted to stdout, insert separators! */
493       separator= ((!outfiles || curlx_strequal(outfiles, "-")) && urlnum > 1);
494
495       /* Here's looping around each globbed URL */
496       for(i = 0 ; i < urlnum; i++) {
497
498         int infd;
499         bool infdopen;
500         char *outfile;
501         struct OutStruct outs;
502         struct InStruct input;
503         struct timeval retrystart;
504         curl_off_t uploadfilesize;
505         long retry_numretries;
506         long retry_sleep_default;
507         long retry_sleep;
508         char *this_url;
509
510         outfile = NULL;
511         infdopen = FALSE;
512         infd = STDIN_FILENO;
513         uploadfilesize = -1; /* -1 means unknown */
514
515         /* default output stream is stdout */
516         memset(&outs, 0, sizeof(struct OutStruct));
517         outs.stream = stdout;
518         outs.config = config;
519
520         if(urls) {
521           res = glob_next_url(&this_url, urls);
522           if(res)
523             goto show_error;
524         }
525         else if(!i) {
526           this_url = strdup(urlnode->url);
527           if(!this_url) {
528             res = CURLE_OUT_OF_MEMORY;
529             goto show_error;
530           }
531         }
532         else
533           this_url = NULL;
534         if(!this_url)
535           break;
536
537         if(outfiles) {
538           outfile = strdup(outfiles);
539           if(!outfile) {
540             res = CURLE_OUT_OF_MEMORY;
541             goto show_error;
542           }
543         }
544
545         if((urlnode->flags&GETOUT_USEREMOTE) ||
546            (outfile && !curlx_strequal("-", outfile)) ) {
547
548           /*
549            * We have specified a file name to store the result in, or we have
550            * decided we want to use the remote file name.
551            */
552
553           if(!outfile) {
554             /* extract the file name from the URL */
555             res = get_url_file_name(&outfile, this_url);
556             if(res)
557               goto show_error;
558             if((!outfile || !*outfile) && !config->content_disposition) {
559               helpf(config->errors, "Remote file name has no length!\n");
560               res = CURLE_WRITE_ERROR;
561               goto quit_urls;
562             }
563 #if defined(MSDOS) || defined(WIN32)
564             /* For DOS and WIN32, we do some major replacing of
565                bad characters in the file name before using it */
566             outfile = sanitize_dos_name(outfile);
567             if(!outfile) {
568               res = CURLE_OUT_OF_MEMORY;
569               goto show_error;
570             }
571 #endif /* MSDOS || WIN32 */
572           }
573           else if(urls) {
574             /* fill '#1' ... '#9' terms from URL pattern */
575             char *storefile = outfile;
576             res = glob_match_url(&outfile, storefile, urls);
577             Curl_safefree(storefile);
578             if(res) {
579               /* bad globbing */
580               warnf(config, "bad output glob!\n");
581               goto quit_urls;
582             }
583           }
584
585           /* Create the directory hierarchy, if not pre-existent to a multiple
586              file output call */
587
588           if(config->create_dirs) {
589             res = create_dir_hierarchy(outfile, config->errors);
590             /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */
591             if(res == CURLE_WRITE_ERROR)
592               goto quit_urls;
593             if(res) {
594               goto show_error;
595             }
596           }
597
598           if((urlnode->flags & GETOUT_USEREMOTE)
599              && config->content_disposition) {
600             /* Our header callback MIGHT set the filename */
601             DEBUGASSERT(!outs.filename);
602           }
603
604           if(config->resume_from_current) {
605             /* We're told to continue from where we are now. Get the size
606                of the file as it is now and open it for append instead */
607             struct_stat fileinfo;
608             /* VMS -- Danger, the filesize is only valid for stream files */
609             if(0 == stat(outfile, &fileinfo))
610               /* set offset to current file size: */
611               config->resume_from = fileinfo.st_size;
612             else
613               /* let offset be 0 */
614               config->resume_from = 0;
615           }
616
617           if(config->resume_from) {
618             /* open file for output: */
619             FILE *file = fopen(outfile, config->resume_from?"ab":"wb");
620             if(!file) {
621               helpf(config->errors, "Can't open '%s'!\n", outfile);
622               res = CURLE_WRITE_ERROR;
623               goto quit_urls;
624             }
625             outs.fopened = TRUE;
626             outs.stream = file;
627             outs.init = config->resume_from;
628           }
629           else {
630             outs.stream = NULL; /* open when needed */
631           }
632           outs.filename = outfile;
633           outs.s_isreg = TRUE;
634         }
635
636         if(uploadfile && !stdin_upload(uploadfile)) {
637           /*
638            * We have specified a file to upload and it isn't "-".
639            */
640           struct_stat fileinfo;
641
642           this_url = add_file_name_to_url(curl, this_url, uploadfile);
643           if(!this_url) {
644             res = CURLE_OUT_OF_MEMORY;
645             goto show_error;
646           }
647           /* VMS Note:
648            *
649            * Reading binary from files can be a problem...  Only FIXED, VAR
650            * etc WITHOUT implied CC will work Others need a \n appended to a
651            * line
652            *
653            * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a
654            * fixed file with implied CC needs to have a byte added for every
655            * record processed, this can by derived from Filesize & recordsize
656            * for VARiable record files the records need to be counted!  for
657            * every record add 1 for linefeed and subtract 2 for the record
658            * header for VARIABLE header files only the bare record data needs
659            * to be considered with one appended if implied CC
660            */
661
662           infd = open(uploadfile, O_RDONLY | O_BINARY);
663           if((infd == -1) || fstat(infd, &fileinfo)) {
664             helpf(config->errors, "Can't open '%s'!\n", uploadfile);
665             if(infd != -1) {
666               close(infd);
667               infd = STDIN_FILENO;
668             }
669             res = CURLE_READ_ERROR;
670             goto quit_urls;
671           }
672           infdopen = TRUE;
673
674           /* we ignore file size for char/block devices, sockets, etc. */
675           if(S_ISREG(fileinfo.st_mode))
676             uploadfilesize = fileinfo.st_size;
677
678         }
679         else if(uploadfile && stdin_upload(uploadfile)) {
680           /* count to see if there are more than one auth bit set
681              in the authtype field */
682           int authbits = 0;
683           int bitcheck = 0;
684           while(bitcheck < 32) {
685             if(config->authtype & (1 << bitcheck++)) {
686               authbits++;
687               if(authbits > 1) {
688                 /* more than one, we're done! */
689                 break;
690               }
691             }
692           }
693
694           /*
695            * If the user has also selected --anyauth or --proxy-anyauth
696            * we should warn him/her.
697            */
698           if(config->proxyanyauth || (authbits>1)) {
699             warnf(config,
700                   "Using --anyauth or --proxy-anyauth with upload from stdin"
701                   " involves a big risk of it not working. Use a temporary"
702                   " file or a fixed auth type instead!\n");
703           }
704
705           DEBUGASSERT(infdopen == FALSE);
706           DEBUGASSERT(infd == STDIN_FILENO);
707
708           set_binmode(stdin);
709           if(curlx_strequal(uploadfile, ".")) {
710             if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
711               warnf(config,
712                     "fcntl failed on fd=%d: %s\n", infd, strerror(errno));
713           }
714         }
715
716         if(uploadfile && config->resume_from_current)
717           config->resume_from = -1; /* -1 will then force get-it-yourself */
718
719         if(output_expected(this_url, uploadfile)
720            && outs.stream && isatty(fileno(outs.stream)))
721           /* we send the output to a tty, therefore we switch off the progress
722              meter */
723           config->noprogress = config->isatty = TRUE;
724
725         if(urlnum > 1 && !(config->mute)) {
726           fprintf(config->errors, "\n[%d/%d]: %s --> %s\n",
727                   i+1, urlnum, this_url, outfile ? outfile : "<stdout>");
728           if(separator)
729             printf("%s%s\n", CURLseparator, this_url);
730         }
731         if(httpgetfields) {
732           char *urlbuffer;
733           /* Find out whether the url contains a file name */
734           const char *pc = strstr(this_url, "://");
735           char sep = '?';
736           if(pc)
737             pc += 3;
738           else
739             pc = this_url;
740
741           pc = strrchr(pc, '/'); /* check for a slash */
742
743           if(pc) {
744             /* there is a slash present in the URL */
745
746             if(strchr(pc, '?'))
747               /* Ouch, there's already a question mark in the URL string, we
748                  then append the data with an ampersand separator instead! */
749               sep='&';
750           }
751           /*
752            * Then append ? followed by the get fields to the url.
753            */
754           urlbuffer = malloc(strlen(this_url) + strlen(httpgetfields) + 3);
755           if(!urlbuffer) {
756             res = CURLE_OUT_OF_MEMORY;
757             goto show_error;
758           }
759           if(pc)
760             sprintf(urlbuffer, "%s%c%s", this_url, sep, httpgetfields);
761           else
762             /* Append  / before the ? to create a well-formed url
763                if the url contains a hostname only
764             */
765             sprintf(urlbuffer, "%s/?%s", this_url, httpgetfields);
766
767           Curl_safefree(this_url); /* free previous URL */
768           this_url = urlbuffer; /* use our new URL instead! */
769         }
770
771         if(!config->errors)
772           config->errors = stderr;
773
774         if((!outfile || !strcmp(outfile, "-")) && !config->use_ascii) {
775           /* We get the output to stdout and we have not got the ASCII/text
776              flag, then set stdout to be binary */
777           set_binmode(stdout);
778         }
779
780         if(config->tcp_nodelay)
781           my_setopt(curl, CURLOPT_TCP_NODELAY, 1);
782
783         /* where to store */
784         my_setopt(curl, CURLOPT_WRITEDATA, &outs);
785         /* what call to write */
786         my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
787
788         /* for uploads */
789         input.fd = infd;
790         input.config = config;
791         /* Note that if CURLOPT_READFUNCTION is fread (the default), then
792          * lib/telnet.c will Curl_poll() on the input file descriptor
793          * rather then calling the READFUNCTION at regular intervals.
794          * The circumstances in which it is preferable to enable this
795          * behaviour, by omitting to set the READFUNCTION & READDATA options,
796          * have not been determined.
797          */
798         my_setopt(curl, CURLOPT_READDATA, &input);
799         /* what call to read */
800         my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb);
801
802         /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
803            CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
804         my_setopt(curl, CURLOPT_SEEKDATA, &input);
805         my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);
806
807         if(config->recvpersecond)
808           /* tell libcurl to use a smaller sized buffer as it allows us to
809              make better sleeps! 7.9.9 stuff! */
810           my_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond);
811
812         /* size of uploaded file: */
813         if(uploadfilesize != -1)
814           my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
815         my_setopt_str(curl, CURLOPT_URL, this_url);     /* what to fetch */
816         my_setopt(curl, CURLOPT_NOPROGRESS, config->noprogress);
817         if(config->no_body) {
818           my_setopt(curl, CURLOPT_NOBODY, 1);
819           my_setopt(curl, CURLOPT_HEADER, 1);
820         }
821         else
822           my_setopt(curl, CURLOPT_HEADER, config->include_headers);
823
824 #if !defined(CURL_DISABLE_PROXY)
825         {
826           /* TODO: Make this a run-time check instead of compile-time one. */
827
828           my_setopt_str(curl, CURLOPT_PROXY, config->proxy);
829           my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
830
831           /* new in libcurl 7.3 */
832           my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel);
833
834           /* new in libcurl 7.5 */
835           if(config->proxy)
836             my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->proxyver);
837
838           /* new in libcurl 7.10 */
839           if(config->socksproxy) {
840             my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy);
841             my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->socksver);
842           }
843
844           /* new in libcurl 7.10.6 */
845           if(config->proxyanyauth)
846             my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
847           else if(config->proxynegotiate)
848             my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE);
849           else if(config->proxyntlm)
850             my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
851           else if(config->proxydigest)
852             my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
853           else if(config->proxybasic)
854             my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
855
856           /* new in libcurl 7.19.4 */
857           my_setopt(curl, CURLOPT_NOPROXY, config->noproxy);
858         }
859 #endif
860
861         my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror);
862         my_setopt(curl, CURLOPT_UPLOAD, uploadfile?TRUE:FALSE);
863         my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly);
864         my_setopt(curl, CURLOPT_APPEND, config->ftp_append);
865
866         if(config->netrc_opt)
867           my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
868         else if(config->netrc || config->netrc_file)
869           my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
870         else
871           my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
872
873         if(config->netrc_file)
874           my_setopt(curl, CURLOPT_NETRC_FILE, config->netrc_file);
875
876         my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii);
877         my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
878         my_setopt_str(curl, CURLOPT_RANGE, config->range);
879         my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
880         my_setopt(curl, CURLOPT_TIMEOUT, config->timeout);
881
882         if(built_in_protos & CURLPROTO_HTTP) {
883
884           my_setopt(curl, CURLOPT_FOLLOWLOCATION,
885                     config->followlocation);
886           my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH,
887                     config->unrestricted_auth);
888
889           switch(config->httpreq) {
890           case HTTPREQ_SIMPLEPOST:
891             my_setopt_str(curl, CURLOPT_POSTFIELDS,
892                           config->postfields);
893             my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE,
894                       config->postfieldsize);
895             break;
896           case HTTPREQ_POST:
897             my_setopt_httppost(curl, CURLOPT_HTTPPOST, config->httppost);
898             break;
899           default:
900             break;
901           }
902
903           my_setopt_str(curl, CURLOPT_REFERER, config->referer);
904           my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer);
905           my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
906           my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers);
907
908           /* new in libcurl 7.5 */
909           my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
910
911           /* new in libcurl 7.9.1 */
912           if(config->httpversion)
913             my_setopt_enum(curl, CURLOPT_HTTP_VERSION, config->httpversion);
914
915           /* new in libcurl 7.10.6 (default is Basic) */
916           if(config->authtype)
917             my_setopt_flags(curl, CURLOPT_HTTPAUTH, config->authtype);
918
919           /* curl 7.19.1 (the 301 version existed in 7.18.2) */
920           my_setopt(curl, CURLOPT_POSTREDIR, config->post301 |
921                     (config->post302 ? CURL_REDIR_POST_302 : FALSE));
922
923           /* new in libcurl 7.21.6 */
924           if(config->encoding)
925             my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, "");
926
927           /* new in libcurl 7.21.6 */
928           if(config->tr_encoding)
929             my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1);
930
931         } /* (built_in_protos & CURLPROTO_HTTP) */
932
933         my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
934         my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
935                   config->low_speed_limit);
936         my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
937         my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE,
938                   config->sendpersecond);
939         my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE,
940                   config->recvpersecond);
941         my_setopt(curl, CURLOPT_RESUME_FROM_LARGE,
942                   config->use_resume?config->resume_from:0);
943
944         my_setopt(curl, CURLOPT_SSLCERT, config->cert);
945         my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
946         my_setopt(curl, CURLOPT_SSLKEY, config->key);
947         my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
948         my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
949
950         if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
951
952           /* SSH and SSL private key uses same command-line option */
953           /* new in libcurl 7.16.1 */
954           my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
955           /* new in libcurl 7.16.1 */
956           my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
957
958           /* new in libcurl 7.17.1: SSH host key md5 checking allows us
959              to fail if we are not talking to who we think we should */
960           my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
961                         config->hostpubmd5);
962         }
963
964         if(config->cacert)
965           my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
966         if(config->capath)
967           my_setopt_str(curl, CURLOPT_CAPATH, config->capath);
968         if(config->crlfile)
969           my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
970
971         if(curlinfo->features & CURL_VERSION_SSL) {
972           if(config->insecure_ok) {
973             my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
974             my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L);
975           }
976           else {
977             my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
978             /* libcurl default is strict verifyhost -> 2L   */
979             /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */
980           }
981         }
982
983         if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
984           if(!config->insecure_ok) {
985             char *home;
986             char *file;
987             res = CURLE_OUT_OF_MEMORY;
988             home = homedir();
989             if(home) {
990               file = aprintf("%s/%sssh/known_hosts", home, DOT_CHAR);
991               if(file) {
992                 /* new in curl 7.19.6 */
993                 res = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file);
994                 curl_free(file);
995                 if(res == CURLE_UNKNOWN_OPTION)
996                   /* libssh2 version older than 1.1.1 */
997                   res = CURLE_OK;
998               }
999               Curl_safefree(home);
1000             }
1001             if(res)
1002               goto show_error;
1003           }
1004         }
1005
1006         if(config->no_body || config->remote_time) {
1007           /* no body or use remote time */
1008           my_setopt(curl, CURLOPT_FILETIME, TRUE);
1009         }
1010
1011         my_setopt(curl, CURLOPT_CRLF, config->crlf);
1012         my_setopt_slist(curl, CURLOPT_QUOTE, config->quote);
1013         my_setopt_slist(curl, CURLOPT_POSTQUOTE, config->postquote);
1014         my_setopt_slist(curl, CURLOPT_PREQUOTE, config->prequote);
1015
1016 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
1017         {
1018           /* TODO: Make this a run-time check instead of compile-time one. */
1019
1020           if(config->cookie)
1021             my_setopt_str(curl, CURLOPT_COOKIE, config->cookie);
1022
1023           if(config->cookiefile)
1024             my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile);
1025
1026           /* new in libcurl 7.9 */
1027           if(config->cookiejar)
1028             my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
1029
1030           /* new in libcurl 7.9.7 */
1031           my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession);
1032         }
1033 #endif
1034
1035         my_setopt_enum(curl, CURLOPT_SSLVERSION, config->ssl_version);
1036         my_setopt_enum(curl, CURLOPT_TIMECONDITION, config->timecond);
1037         my_setopt(curl, CURLOPT_TIMEVALUE, config->condtime);
1038         my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
1039         my_setopt(curl, CURLOPT_STDERR, config->errors);
1040
1041         /* three new ones in libcurl 7.3: */
1042         my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
1043         my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
1044
1045         progressbarinit(&progressbar, config);
1046         if((config->progressmode == CURL_PROGRESS_BAR) &&
1047            !config->noprogress && !config->mute) {
1048           /* we want the alternative style, then we have to implement it
1049              ourselves! */
1050           my_setopt(curl, CURLOPT_PROGRESSFUNCTION, tool_progress_cb);
1051           my_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar);
1052         }
1053
1054         /* new in libcurl 7.6.2: */
1055         my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
1056
1057         /* new in libcurl 7.7: */
1058         my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file);
1059         my_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file);
1060         my_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout);
1061
1062         if(config->cipher_list)
1063           my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
1064
1065         /* new in libcurl 7.9.2: */
1066         if(config->disable_epsv)
1067           /* disable it */
1068           my_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE);
1069
1070         /* new in libcurl 7.10.5 */
1071         if(config->disable_eprt)
1072           /* disable it */
1073           my_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE);
1074
1075         if(config->tracetype != TRACE_NONE) {
1076           my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb);
1077           my_setopt(curl, CURLOPT_DEBUGDATA, config);
1078           my_setopt(curl, CURLOPT_VERBOSE, TRUE);
1079         }
1080
1081         /* new in curl 7.9.3 */
1082         if(config->engine) {
1083           res = res_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
1084           if(res)
1085             goto show_error;
1086           my_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
1087         }
1088
1089         /* new in curl 7.10.7, extended in 7.19.4 but this only sets 0 or 1 */
1090         my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
1091                   config->ftp_create_dirs);
1092
1093         /* new in curl 7.10.8 */
1094         if(config->max_filesize)
1095           my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
1096                     config->max_filesize);
1097
1098         if(4 == config->ip_version)
1099           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1100         else if(6 == config->ip_version)
1101           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
1102         else
1103           my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
1104
1105         /* new in curl 7.15.5 */
1106         if(config->ftp_ssl_reqd)
1107           my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
1108
1109         /* new in curl 7.11.0 */
1110         else if(config->ftp_ssl)
1111           my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
1112
1113         /* new in curl 7.16.0 */
1114         else if(config->ftp_ssl_control)
1115           my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL);
1116
1117         /* new in curl 7.16.1 */
1118         if(config->ftp_ssl_ccc)
1119           my_setopt_enum(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode);
1120
1121 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
1122         {
1123           /* TODO: Make this a run-time check instead of compile-time one. */
1124
1125           /* new in curl 7.19.4 */
1126           if(config->socks5_gssapi_service)
1127             my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE,
1128                           config->socks5_gssapi_service);
1129
1130           /* new in curl 7.19.4 */
1131           if(config->socks5_gssapi_nec)
1132             my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC,
1133                           config->socks5_gssapi_nec);
1134         }
1135 #endif
1136         /* curl 7.13.0 */
1137         my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
1138
1139         my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl);
1140
1141         /* curl 7.14.2 */
1142         my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip);
1143
1144         /* curl 7.15.1 */
1145         my_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod);
1146
1147         /* curl 7.15.2 */
1148         if(config->localport) {
1149           my_setopt(curl, CURLOPT_LOCALPORT, config->localport);
1150           my_setopt_str(curl, CURLOPT_LOCALPORTRANGE,
1151                         config->localportrange);
1152         }
1153
1154         /* curl 7.15.5 */
1155         my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
1156                       config->ftp_alternative_to_user);
1157
1158         /* curl 7.16.0 */
1159         if(config->disable_sessionid)
1160           my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE,
1161                     !config->disable_sessionid);
1162
1163         /* curl 7.16.2 */
1164         if(config->raw) {
1165           my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, FALSE);
1166           my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, FALSE);
1167         }
1168
1169         /* curl 7.17.1 */
1170         if(!config->nokeepalive) {
1171           my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
1172           if(config->alivetime != 0) {
1173 #if !defined(TCP_KEEPIDLE) || !defined(TCP_KEEPINTVL)
1174             warnf(config, "Keep-alive functionality somewhat crippled due to "
1175                 "missing support in your operating system!\n");
1176 #endif
1177             my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime);
1178             my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime);
1179           }
1180         }
1181         else
1182           my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
1183
1184         /* curl 7.20.0 */
1185         if(config->tftp_blksize)
1186           my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
1187
1188         if(config->mail_from)
1189           my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
1190
1191         if(config->mail_rcpt)
1192           my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
1193
1194         /* curl 7.20.x */
1195         if(config->ftp_pret)
1196           my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE);
1197
1198         if(config->proto_present)
1199           my_setopt_flags(curl, CURLOPT_PROTOCOLS, config->proto);
1200         if(config->proto_redir_present)
1201           my_setopt_flags(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir);
1202
1203         if((urlnode->flags & GETOUT_USEREMOTE)
1204            && config->content_disposition) {
1205           my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb);
1206           my_setopt(curl, CURLOPT_HEADERDATA, &outs);
1207         }
1208         else {
1209           /* if HEADERFUNCTION was set to something in the previous loop, it
1210              is important that we set it (back) to NULL now */
1211           my_setopt(curl, CURLOPT_HEADERFUNCTION, NULL);
1212           my_setopt(curl, CURLOPT_HEADERDATA, config->headerfile?&heads:NULL);
1213         }
1214
1215         if(config->resolve)
1216           /* new in 7.21.3 */
1217           my_setopt_slist(curl, CURLOPT_RESOLVE, config->resolve);
1218
1219         /* new in 7.21.4 */
1220         if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
1221           if(config->tls_username)
1222             my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME,
1223                           config->tls_username);
1224           if(config->tls_password)
1225             my_setopt_str(curl, CURLOPT_TLSAUTH_PASSWORD,
1226                           config->tls_password);
1227           if(config->tls_authtype)
1228             my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE,
1229                           config->tls_authtype);
1230         }
1231
1232         /* new in 7.22.0 */
1233         if(config->gssapi_delegation)
1234           my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION,
1235                         config->gssapi_delegation);
1236
1237         /* new in 7.25.0 */
1238         if(config->ssl_allow_beast)
1239           my_setopt(curl, CURLOPT_SSL_OPTIONS, (long)CURLSSLOPT_ALLOW_BEAST);
1240
1241         if(config->mail_auth)
1242           my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth);
1243
1244         /* initialize retry vars for loop below */
1245         retry_sleep_default = (config->retry_delay) ?
1246           config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
1247
1248         retry_numretries = config->req_retry;
1249         retry_sleep = retry_sleep_default; /* ms */
1250         retrystart = tvnow();
1251
1252 #ifndef CURL_DISABLE_LIBCURL_OPTION
1253         res = easysrc_perform();
1254         if(res) {
1255           goto show_error;
1256         }
1257 #endif
1258
1259         for(;;) {
1260           res = curl_easy_perform(curl);
1261
1262           if(config->content_disposition && outs.stream && !config->mute &&
1263              outs.filename)
1264             printf("curl: Saved to filename '%s'\n", outs.filename);
1265
1266           /* if retry-max-time is non-zero, make sure we haven't exceeded the
1267              time */
1268           if(retry_numretries &&
1269              (!config->retry_maxtime ||
1270               (tvdiff(tvnow(), retrystart) <
1271                config->retry_maxtime*1000L)) ) {
1272             enum {
1273               RETRY_NO,
1274               RETRY_TIMEOUT,
1275               RETRY_HTTP,
1276               RETRY_FTP,
1277               RETRY_LAST /* not used */
1278             } retry = RETRY_NO;
1279             long response;
1280             if((CURLE_OPERATION_TIMEDOUT == res) ||
1281                (CURLE_COULDNT_RESOLVE_HOST == res) ||
1282                (CURLE_COULDNT_RESOLVE_PROXY == res) ||
1283                (CURLE_FTP_ACCEPT_TIMEOUT == res))
1284               /* retry timeout always */
1285               retry = RETRY_TIMEOUT;
1286             else if((CURLE_OK == res) ||
1287                     (config->failonerror &&
1288                      (CURLE_HTTP_RETURNED_ERROR == res))) {
1289               /* If it returned OK. _or_ failonerror was enabled and it
1290                  returned due to such an error, check for HTTP transient
1291                  errors to retry on. */
1292               char *effective_url = NULL;
1293               curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
1294               if(effective_url &&
1295                  checkprefix("http", effective_url)) {
1296                 /* This was HTTP(S) */
1297                 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
1298
1299                 switch(response) {
1300                 case 500: /* Internal Server Error */
1301                 case 502: /* Bad Gateway */
1302                 case 503: /* Service Unavailable */
1303                 case 504: /* Gateway Timeout */
1304                   retry = RETRY_HTTP;
1305                   /*
1306                    * At this point, we have already written data to the output
1307                    * file (or terminal). If we write to a file, we must rewind
1308                    * or close/re-open the file so that the next attempt starts
1309                    * over from the beginning.
1310                    *
1311                    * TODO: similar action for the upload case. We might need
1312                    * to start over reading from a previous point if we have
1313                    * uploaded something when this was returned.
1314                    */
1315                   break;
1316                 }
1317               }
1318             } /* if CURLE_OK */
1319             else if(res) {
1320               curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
1321
1322               if(response/100 == 4)
1323                 /*
1324                  * This is typically when the FTP server only allows a certain
1325                  * amount of users and we are not one of them.  All 4xx codes
1326                  * are transient.
1327                  */
1328                 retry = RETRY_FTP;
1329             }
1330
1331             if(retry) {
1332               static const char * const m[]={
1333                 NULL, "timeout", "HTTP error", "FTP error"
1334               };
1335               warnf(config, "Transient problem: %s "
1336                     "Will retry in %ld seconds. "
1337                     "%ld retries left.\n",
1338                     m[retry], retry_sleep/1000L, retry_numretries);
1339
1340               tool_go_sleep(retry_sleep);
1341               retry_numretries--;
1342               if(!config->retry_delay) {
1343                 retry_sleep *= 2;
1344                 if(retry_sleep > RETRY_SLEEP_MAX)
1345                   retry_sleep = RETRY_SLEEP_MAX;
1346               }
1347               if(outs.bytes && outs.filename) {
1348                 /* We have written data to a output file, we truncate file
1349                  */
1350                 if(!config->mute)
1351                   fprintf(config->errors, "Throwing away %"
1352                           CURL_FORMAT_CURL_OFF_T " bytes\n",
1353                           outs.bytes);
1354                 fflush(outs.stream);
1355                 /* truncate file at the position where we started appending */
1356 #ifdef HAVE_FTRUNCATE
1357                 if(ftruncate( fileno(outs.stream), outs.init)) {
1358                   /* when truncate fails, we can't just append as then we'll
1359                      create something strange, bail out */
1360                   if(!config->mute)
1361                     fprintf(config->errors,
1362                             "failed to truncate, exiting\n");
1363                   res = CURLE_WRITE_ERROR;
1364                   goto quit_urls;
1365                 }
1366                 /* now seek to the end of the file, the position where we
1367                    just truncated the file in a large file-safe way */
1368                 fseek(outs.stream, 0, SEEK_END);
1369 #else
1370                 /* ftruncate is not available, so just reposition the file
1371                    to the location we would have truncated it. This won't
1372                    work properly with large files on 32-bit systems, but
1373                    most of those will have ftruncate. */
1374                 fseek(outs.stream, (long)outs.init, SEEK_SET);
1375 #endif
1376                 outs.bytes = 0; /* clear for next round */
1377               }
1378               continue; /* curl_easy_perform loop */
1379             }
1380           } /* if retry_numretries */
1381
1382           /* In all ordinary cases, just break out of loop here */
1383           break; /* curl_easy_perform loop */
1384
1385         }
1386
1387         if((config->progressmode == CURL_PROGRESS_BAR) &&
1388            progressbar.calls)
1389           /* if the custom progress bar has been displayed, we output a
1390              newline here */
1391           fputs("\n", progressbar.out);
1392
1393         if(config->writeout)
1394           ourWriteOut(curl, config->writeout);
1395
1396         if(config->writeenv)
1397           ourWriteEnv(curl);
1398
1399         /*
1400         ** Code within this loop may jump directly here to label 'show_error'
1401         ** in order to display an error message for CURLcode stored in 'res'
1402         ** variable and exit loop once that necessary writing and cleanup
1403         ** in label 'quit_urls' has been done.
1404         */
1405
1406         show_error:
1407
1408 #ifdef __VMS
1409         if(is_vms_shell()) {
1410           /* VMS DCL shell behavior */
1411           if(!config->showerror)
1412             vms_show = VMSSTS_HIDE;
1413         }
1414         else
1415 #endif
1416         if(res && config->showerror) {
1417           fprintf(config->errors, "curl: (%d) %s\n", res, (errorbuffer[0]) ?
1418                   errorbuffer : curl_easy_strerror((CURLcode)res));
1419           if(res == CURLE_SSL_CACERT)
1420             fprintf(config->errors, "%s%s",
1421                     CURL_CA_CERT_ERRORMSG1, CURL_CA_CERT_ERRORMSG2);
1422         }
1423
1424         /* Fall through comment to 'quit_urls' label */
1425
1426         /*
1427         ** Upon error condition and always that a message has already been
1428         ** displayed, code within this loop may jump directly here to label
1429         ** 'quit_urls' otherwise it should jump to 'show_error' label above.
1430         **
1431         ** When 'res' variable is _not_ CURLE_OK loop will exit once that
1432         ** all code following 'quit_urls' has been executed. Otherwise it
1433         ** will loop to the beginning from where it may exit if there are
1434         ** no more urls left.
1435         */
1436
1437         quit_urls:
1438
1439         /* Set file extended attributes */
1440         if(!res && config->xattr && outs.fopened && outs.stream) {
1441           int rc = fwrite_xattr(curl, fileno(outs.stream));
1442           if(rc)
1443             warnf(config, "Error setting extended attributes: %s\n",
1444                   strerror(errno));
1445         }
1446
1447         /* Close the file */
1448         if(outs.fopened && outs.stream) {
1449           int rc = fclose(outs.stream);
1450           if(!res && rc) {
1451             /* something went wrong in the writing process */
1452             res = CURLE_WRITE_ERROR;
1453             fprintf(config->errors, "(%d) Failed writing body\n", res);
1454           }
1455         }
1456         else if(!outs.s_isreg && outs.stream) {
1457           /* Dump standard stream buffered data */
1458           int rc = fflush(outs.stream);
1459           if(!res && rc) {
1460             /* something went wrong in the writing process */
1461             res = CURLE_WRITE_ERROR;
1462             fprintf(config->errors, "(%d) Failed writing body\n", res);
1463           }
1464         }
1465
1466 #ifdef __AMIGA__
1467         if(!res && outs.s_isreg && outs.filename) {
1468           /* Set the url (up to 80 chars) as comment for the file */
1469           if(strlen(url) > 78)
1470             url[79] = '\0';
1471           SetComment(outs.filename, url);
1472         }
1473 #endif
1474
1475 #ifdef HAVE_UTIME
1476         /* File time can only be set _after_ the file has been closed */
1477         if(!res && config->remote_time && outs.s_isreg && outs.filename) {
1478           /* Ask libcurl if we got a remote file time */
1479           long filetime = -1;
1480           curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
1481           if(filetime >= 0) {
1482             struct utimbuf times;
1483             times.actime = (time_t)filetime;
1484             times.modtime = (time_t)filetime;
1485             utime(outs.filename, &times); /* set the time we got */
1486           }
1487         }
1488 #endif
1489         /* No more business with this output struct */
1490         if(outs.alloc_filename)
1491           Curl_safefree(outs.filename);
1492         memset(&outs, 0, sizeof(struct OutStruct));
1493
1494         /* Free loop-local allocated memory and close loop-local opened fd */
1495
1496         Curl_safefree(outfile);
1497         Curl_safefree(this_url);
1498
1499         if(infdopen) {
1500           close(infd);
1501           infdopen = FALSE;
1502           infd = STDIN_FILENO;
1503         }
1504
1505         if(urlnum > 1) {
1506           /* when url globbing, exit loop upon critical error */
1507           if(is_fatal_error(res))
1508             break;
1509         }
1510         else if(res)
1511           /* when not url globbing, exit loop upon any error */
1512           break;
1513
1514       } /* loop to the next URL */
1515
1516       /* Free loop-local allocated memory */
1517
1518       Curl_safefree(uploadfile);
1519
1520       if(urls) {
1521         /* Free list of remaining URLs */
1522         glob_cleanup(urls);
1523         urls = NULL;
1524       }
1525
1526       if(infilenum > 1) {
1527         /* when file globbing, exit loop upon critical error */
1528         if(is_fatal_error(res))
1529           break;
1530       }
1531       else if(res)
1532         /* when not file globbing, exit loop upon any error */
1533         break;
1534
1535     } /* loop to the next globbed upload file */
1536
1537     /* Free loop-local allocated memory */
1538
1539     Curl_safefree(outfiles);
1540
1541     if(inglob) {
1542       /* Free list of globbed upload files */
1543       glob_cleanup(inglob);
1544       inglob = NULL;
1545     }
1546
1547     /* Free this URL node data without destroying the
1548        the node itself nor modifying next pointer. */
1549     Curl_safefree(urlnode->url);
1550     Curl_safefree(urlnode->outfile);
1551     Curl_safefree(urlnode->infile);
1552     urlnode->flags = 0;
1553
1554     /*
1555     ** Bail out upon critical errors
1556     */
1557     if(is_fatal_error(res))
1558       goto quit_curl;
1559
1560   } /* for-loop through all URLs */
1561
1562   /*
1563   ** Nested loops end here.
1564   */
1565
1566   quit_curl:
1567
1568   /* Free function-local referenced allocated memory */
1569   Curl_safefree(httpgetfields);
1570
1571   /* Free list of given URLs */
1572   clean_getout(config);
1573
1574   /* Cleanup the curl handle now that our
1575      progressbar struct is still in scope */
1576   if(curl) {
1577     curl_easy_cleanup(curl);
1578     config->easy = curl = NULL;
1579   }
1580 #ifndef CURL_DISABLE_LIBCURL_OPTION
1581   easysrc_cleanup();
1582 #endif
1583
1584   /* Close function-local opened file descriptors */
1585
1586   if(heads.fopened && heads.stream)
1587     fclose(heads.stream);
1588   if(heads.alloc_filename)
1589     Curl_safefree(heads.filename);
1590
1591   if(config->trace_fopened && config->trace_stream)
1592     fclose(config->trace_stream);
1593
1594 #ifndef CURL_DISABLE_LIBCURL_OPTION
1595   /* Dump the libcurl code if previously enabled.
1596      NOTE: that this function relies on config->errors amongst other things
1597      so not everything can be closed and cleaned before this is called */
1598   dumpeasysrc(config);
1599 #endif
1600
1601   if(config->errors_fopened && config->errors)
1602     fclose(config->errors);
1603
1604   main_free(); /* cleanup */
1605
1606   return res;
1607 }
1608