PageRenderTime 52ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/curl-7.28.0/src/tool_operate.c

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