1 /* 2 * uclient - ustream based protocol client library 3 * 4 * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #define _GNU_SOURCE 20 #include <sys/stat.h> 21 #include <sys/socket.h> 22 #include <unistd.h> 23 #include <stdio.h> 24 #include <ctype.h> 25 #include <getopt.h> 26 #include <fcntl.h> 27 #include <glob.h> 28 #include <stdint.h> 29 #include <inttypes.h> 30 #include <signal.h> 31 32 #include <libubox/blobmsg.h> 33 #include <libubox/list.h> 34 35 #include "progress.h" 36 #include "uclient.h" 37 #include "uclient-utils.h" 38 39 #ifndef strdupa 40 #define strdupa(x) strcpy(alloca(strlen(x)+1),x) 41 #endif 42 43 struct header { 44 struct list_head list; 45 char *name; 46 char *value; 47 }; 48 49 static const char *user_agent = "uclient-fetch"; 50 static const char *method = NULL; 51 static const char *post_data; 52 static const char *post_file; 53 static char opt_post = 0; /* 1 when --post-data/file is used, 2 when --body-data/file is used */ 54 static struct ustream_ssl_ctx *ssl_ctx; 55 static const struct ustream_ssl_ops *ssl_ops; 56 static int quiet = false; 57 static bool verify = true; 58 static bool proxy = true; 59 static bool default_certs = false; 60 static bool no_output; 61 static const char *opt_output_file; 62 static int output_fd = -1; 63 static int error_ret; 64 static off_t out_offset; 65 static off_t out_bytes; 66 static off_t out_len; 67 static char *auth_str; 68 static char **urls; 69 static int n_urls; 70 static int timeout; 71 static bool resume, cur_resume; 72 static LIST_HEAD(headers); 73 74 static struct progress pmt; 75 static struct uloop_timeout pmt_timer; 76 77 static int init_request(struct uclient *cl); 78 static void request_done(struct uclient *cl); 79 80 static void pmt_update(struct uloop_timeout *t) 81 { 82 progress_update(&pmt, out_offset, out_bytes, out_len); 83 uloop_timeout_set(t, 1000); 84 } 85 86 static const char * 87 get_proxy_url(char *url) 88 { 89 char prefix[16]; 90 char *sep; 91 92 if (!proxy) 93 return NULL; 94 95 sep = strchr(url, ':'); 96 if (!sep) 97 return NULL; 98 99 if (sep - url > 5) 100 return NULL; 101 102 memcpy(prefix, url, sep - url); 103 strcpy(prefix + (sep - url), "_proxy"); 104 return getenv(prefix); 105 } 106 107 static int open_output_file(const char *path, uint64_t resume_offset) 108 { 109 const char *output_file = opt_output_file; 110 char *filename = NULL; 111 int flags; 112 int ret; 113 114 if (cur_resume) 115 flags = O_RDWR; 116 else 117 flags = O_WRONLY | O_TRUNC; 118 119 if (!cur_resume && !output_file) 120 flags |= O_EXCL; 121 122 flags |= O_CREAT; 123 124 if (output_file) { 125 if (!strcmp(output_file, "-")) { 126 if (!quiet) 127 fprintf(stderr, "Writing to stdout\n"); 128 129 ret = STDOUT_FILENO; 130 goto done; 131 } 132 } else { 133 filename = uclient_get_url_filename(path, "index.html"); 134 if (!filename) { 135 ret = -ENOMEM; 136 goto out; 137 } 138 139 output_file = filename; 140 } 141 142 if (!quiet) 143 fprintf(stderr, "Writing to '%s'\n", output_file); 144 ret = open(output_file, flags, 0644); 145 if (ret < 0) 146 goto free; 147 148 if (resume_offset && 149 lseek(ret, resume_offset, SEEK_SET) < 0) { 150 if (!quiet) 151 fprintf(stderr, "Failed to seek %"PRIu64" bytes in output file\n", resume_offset); 152 close(ret); 153 ret = -1; 154 goto free; 155 } 156 157 out_offset = resume_offset; 158 out_bytes += resume_offset; 159 done: 160 if (!quiet) { 161 progress_init(&pmt, output_file); 162 pmt_timer.cb = pmt_update; 163 pmt_timer.cb(&pmt_timer); 164 } 165 166 free: 167 free(filename); 168 out: 169 return ret; 170 } 171 172 static void header_done_cb(struct uclient *cl) 173 { 174 enum { 175 H_RANGE, 176 H_LEN, 177 __H_MAX 178 }; 179 static const struct blobmsg_policy policy[__H_MAX] = { 180 [H_RANGE] = { .name = "content-range", .type = BLOBMSG_TYPE_STRING }, 181 [H_LEN] = { .name = "content-length", .type = BLOBMSG_TYPE_STRING }, 182 }; 183 struct blob_attr *tb[__H_MAX]; 184 uint64_t resume_offset = 0, resume_end, resume_size; 185 static int retries; 186 187 if (retries < 10) { 188 int ret = uclient_http_redirect(cl); 189 if (ret < 0) { 190 if (!quiet) 191 fprintf(stderr, "Failed to redirect to %s on %s\n", cl->url->location, cl->url->host); 192 error_ret = 8; 193 request_done(cl); 194 return; 195 } 196 if (ret > 0) { 197 if (!quiet) 198 fprintf(stderr, "Redirected to %s on %s\n", cl->url->location, cl->url->host); 199 200 retries++; 201 return; 202 } 203 } 204 205 if (cl->status_code == 204 && cur_resume) { 206 /* Resume attempt failed, try normal download */ 207 cur_resume = false; 208 init_request(cl); 209 return; 210 } 211 212 blobmsg_parse(policy, __H_MAX, tb, blob_data(cl->meta), blob_len(cl->meta)); 213 214 switch (cl->status_code) { 215 case 416: 216 if (!quiet) 217 fprintf(stderr, "File download already fully retrieved; nothing to do.\n"); 218 request_done(cl); 219 break; 220 case 206: 221 if (!cur_resume) { 222 if (!quiet) 223 fprintf(stderr, "Error: Partial content received, full content requested\n"); 224 error_ret = 8; 225 request_done(cl); 226 break; 227 } 228 229 if (!tb[H_RANGE]) { 230 if (!quiet) 231 fprintf(stderr, "Content-Range header is missing\n"); 232 error_ret = 8; 233 break; 234 } 235 236 if (sscanf(blobmsg_get_string(tb[H_RANGE]), 237 "bytes %"PRIu64"-%"PRIu64"/%"PRIu64, 238 &resume_offset, &resume_end, &resume_size) != 3) { 239 if (!quiet) 240 fprintf(stderr, "Content-Range header is invalid\n"); 241 error_ret = 8; 242 break; 243 } 244 /* fall through */ 245 case 204: 246 case 200: 247 if (no_output) 248 break; 249 250 if (tb[H_LEN]) 251 out_len = strtoul(blobmsg_get_string(tb[H_LEN]), NULL, 10); 252 253 output_fd = open_output_file(cl->url->location, resume_offset); 254 if (output_fd < 0) { 255 if (!quiet) 256 perror("Cannot open output file"); 257 error_ret = 3; 258 request_done(cl); 259 } 260 break; 261 262 default: 263 if (!quiet) 264 fprintf(stderr, "HTTP error %d\n", cl->status_code); 265 request_done(cl); 266 error_ret = 8; 267 break; 268 } 269 } 270 271 static void read_data_cb(struct uclient *cl) 272 { 273 char buf[256]; 274 ssize_t n; 275 int len; 276 277 if (!no_output && output_fd < 0) 278 return; 279 280 while (1) { 281 len = uclient_read(cl, buf, sizeof(buf)); 282 if (len <= 0) 283 return; 284 285 out_bytes += len; 286 if (!no_output) { 287 n = write(output_fd, buf, len); 288 if (n < 0) 289 return; 290 } 291 } 292 } 293 294 static void msg_connecting(struct uclient *cl) 295 { 296 char addr[INET6_ADDRSTRLEN]; 297 int port; 298 299 if (quiet) 300 return; 301 302 uclient_get_addr(addr, &port, &cl->remote_addr); 303 fprintf(stderr, "Connecting to %s:%d\n", addr, port); 304 } 305 306 static void check_resume_offset(struct uclient *cl) 307 { 308 char range_str[64]; 309 struct stat st; 310 char *file; 311 int ret; 312 313 file = uclient_get_url_filename(cl->url->location, "index.html"); 314 if (!file) 315 return; 316 317 ret = stat(file, &st); 318 free(file); 319 if (ret) 320 return; 321 322 if (!st.st_size) 323 return; 324 325 snprintf(range_str, sizeof(range_str), "bytes=%"PRIu64"-", (uint64_t) st.st_size); 326 uclient_http_set_header(cl, "Range", range_str); 327 } 328 329 static int init_request(struct uclient *cl) 330 { 331 struct header *h; 332 char *content_type = "application/x-www-form-urlencoded"; 333 int rc; 334 335 out_offset = 0; 336 out_bytes = 0; 337 out_len = 0; 338 uclient_http_set_ssl_ctx(cl, ssl_ops, ssl_ctx, verify); 339 340 if (timeout) 341 cl->timeout_msecs = timeout * 1000; 342 343 rc = uclient_connect(cl); 344 if (rc) 345 return rc; 346 347 msg_connecting(cl); 348 349 rc = uclient_http_set_request_type(cl, method); 350 if (rc) 351 return rc; 352 353 uclient_http_reset_headers(cl); 354 355 list_for_each_entry(h, &headers, list) { 356 if (!strcasecmp(h->name, "Content-Type")) { 357 if (!opt_post) 358 return -EINVAL; 359 360 content_type = h->value; 361 } else if (!strcasecmp(h->name, "User-Agent")) { 362 user_agent = h->value; 363 } else { 364 uclient_http_set_header(cl, h->name, h->value); 365 } 366 } 367 368 uclient_http_set_header(cl, "User-Agent", user_agent); 369 370 if (cur_resume) 371 check_resume_offset(cl); 372 373 if (opt_post) { 374 uclient_http_set_header(cl, "Content-Type", content_type); 375 } 376 if (post_data) { 377 uclient_write(cl, post_data, strlen(post_data)); 378 } 379 else if(post_file) 380 { 381 FILE *input_file; 382 383 input_file = fopen(post_file, "r"); 384 if (!input_file) 385 return errno; 386 387 char tbuf[1024]; 388 size_t rlen = 0; 389 do 390 { 391 rlen = fread(tbuf, 1, sizeof(tbuf), input_file); 392 uclient_write(cl, tbuf, rlen); 393 } 394 while(rlen); 395 396 fclose(input_file); 397 } 398 399 rc = uclient_request(cl); 400 if (rc) 401 return rc; 402 403 return 0; 404 } 405 406 static void request_done(struct uclient *cl) 407 { 408 const char *proxy_url; 409 410 if (n_urls) { 411 proxy_url = get_proxy_url(*urls); 412 if (proxy_url) { 413 uclient_set_url(cl, proxy_url, NULL); 414 uclient_set_proxy_url(cl, *urls, auth_str); 415 } else { 416 uclient_set_url(cl, *urls, auth_str); 417 } 418 n_urls--; 419 cur_resume = resume; 420 error_ret = init_request(cl); 421 if (error_ret == 0) 422 return; 423 } 424 425 if (output_fd >= 0 && !opt_output_file) { 426 close(output_fd); 427 output_fd = -1; 428 } 429 uclient_disconnect(cl); 430 uloop_end(); 431 } 432 433 434 static void eof_cb(struct uclient *cl) 435 { 436 if (!quiet) { 437 pmt_update(&pmt_timer); 438 uloop_timeout_cancel(&pmt_timer); 439 fprintf(stderr, "\n"); 440 } 441 442 if (!cl->data_eof) { 443 if (!quiet) 444 fprintf(stderr, "Connection reset prematurely\n"); 445 error_ret = 4; 446 } else if (!quiet) { 447 fprintf(stderr, "Download completed (%"PRIu64" bytes)\n", (uint64_t) out_bytes); 448 } 449 request_done(cl); 450 } 451 452 static void 453 handle_uclient_log_msg(struct uclient *cl, enum uclient_log_type type, const char *msg) 454 { 455 static const char * const type_str_list[] = { 456 [UCLIENT_LOG_SSL_ERROR] = "SSL error", 457 [UCLIENT_LOG_SSL_VERIFY_ERROR] = "SSL verify error", 458 }; 459 const char *type_str = NULL; 460 461 if (type < ARRAY_SIZE(type_str_list)) 462 type_str = type_str_list[type]; 463 if (!type_str) 464 type_str = "Unknown"; 465 466 fprintf(stderr, "%s: %s\n", type_str, msg); 467 } 468 469 static void handle_uclient_error(struct uclient *cl, int code) 470 { 471 const char *type = "Unknown error"; 472 bool ignore = false; 473 474 switch(code) { 475 case UCLIENT_ERROR_CONNECT: 476 type = "Connection failed"; 477 error_ret = 4; 478 break; 479 case UCLIENT_ERROR_TIMEDOUT: 480 type = "Connection timed out"; 481 error_ret = 4; 482 break; 483 case UCLIENT_ERROR_SSL_INVALID_CERT: 484 type = "Invalid SSL certificate"; 485 ignore = !verify; 486 error_ret = 5; 487 break; 488 case UCLIENT_ERROR_SSL_CN_MISMATCH: 489 type = "Server hostname does not match SSL certificate"; 490 ignore = !verify; 491 error_ret = 5; 492 break; 493 default: 494 error_ret = 1; 495 break; 496 } 497 498 if (!quiet) 499 fprintf(stderr, "Connection error: %s%s\n", type, ignore ? " (ignored)" : ""); 500 501 if (ignore) 502 error_ret = 0; 503 else 504 request_done(cl); 505 } 506 507 static const struct uclient_cb cb = { 508 .header_done = header_done_cb, 509 .data_read = read_data_cb, 510 .data_eof = eof_cb, 511 .error = handle_uclient_error, 512 .log_msg = handle_uclient_log_msg, 513 }; 514 515 static void usage(const char *progname) 516 { 517 fprintf(stderr, 518 "Usage: %s [options] <URL>\n" 519 "Options:\n" 520 " -4 Use IPv4 only\n" 521 " -6 Use IPv6 only\n" 522 " -O <file> Redirect output to file (use \"-\" for stdout)\n" 523 " -P <dir> Set directory for output files\n" 524 " --quiet | -q Turn off status messages\n" 525 " --continue | -c Continue a partially-downloaded file\n" 526 " --header='Header: value' Add HTTP header. Multiple allowed\n" 527 " --user=<user> HTTP authentication username\n" 528 " --password=<password> HTTP authentication password\n" 529 " --user-agent | -U <str> Set HTTP user agent\n" 530 " --post-data=STRING use the POST method; send STRING as the data\n" 531 " --post-file=FILE use the POST method; send FILE as the data\n" 532 " --method=METHOD use the HTTP method e.g. PUT\n" 533 " --body-data=STRING with --method send the STRING in body\n" 534 " --body-file=FILE with --method send the FILE content in body\n" 535 " --spider | -s Spider mode - only check file existence\n" 536 " --timeout=N | -T N Set connect/request timeout to N seconds\n" 537 " --proxy=on | -Y on Enable interpretation of proxy env vars (default)\n" 538 " --proxy=off | -Y off |\n" 539 " --no-proxy Disable interpretation of proxy env vars\n" 540 "\n" 541 "HTTPS options:\n" 542 " --ca-certificate=<cert> Load CA certificates from file <cert>\n" 543 " --no-check-certificate don't validate the server's certificate\n" 544 " --ciphers=<cipherlist> Set the cipher list string\n" 545 "\n", progname); 546 error_ret = 1; 547 } 548 549 static void init_ca_cert(void) 550 { 551 glob_t gl; 552 unsigned int i; 553 554 glob("/etc/ssl/certs/*.crt", 0, NULL, &gl); 555 for (i = 0; i < gl.gl_pathc; i++) 556 ssl_ops->context_add_ca_crt_file(ssl_ctx, gl.gl_pathv[i]); 557 globfree(&gl); 558 } 559 560 static void no_ssl(const char *progname) 561 { 562 fprintf(stderr, 563 "%s: SSL support not available, please install one of the " 564 "libustream-.*[ssl|tls] packages as well as the ca-bundle and " 565 "ca-certificates packages.\n", 566 progname); 567 error_ret = 1; 568 } 569 570 static void debug_cb(void *priv, int level, const char *msg) 571 { 572 fprintf(stderr, "%s\n", msg); 573 } 574 575 static bool is_valid_header(char *str) 576 { 577 char *tmp = str; 578 579 /* First character must be a letter */ 580 if (!isalpha(*tmp)) 581 return false; 582 583 /* Subsequent characters must be letters, numbers or dashes */ 584 while (*(++tmp) != '\0') { 585 if (!isalnum(*tmp) && *tmp != '-') 586 return false; 587 } 588 589 return true; 590 }; 591 592 enum { 593 L_NO_CHECK_CERTIFICATE, 594 L_CA_CERTIFICATE, 595 L_CIPHERS, 596 L_USER, 597 L_PASSWORD, 598 L_USER_AGENT, 599 L_POST_DATA, 600 L_POST_FILE, 601 L_METHOD, 602 L_BODY_DATA, 603 L_BODY_FILE, 604 L_SPIDER, 605 L_TIMEOUT, 606 L_CONTINUE, 607 L_PROXY, 608 L_NO_PROXY, 609 L_QUIET, 610 L_VERBOSE, 611 L_HEADER, 612 }; 613 614 static const struct option longopts[] = { 615 [L_NO_CHECK_CERTIFICATE] = { "no-check-certificate", no_argument, NULL, 0 }, 616 [L_CA_CERTIFICATE] = { "ca-certificate", required_argument, NULL, 0 }, 617 [L_CIPHERS] = { "ciphers", required_argument, NULL, 0 }, 618 [L_USER] = { "user", required_argument, NULL, 0 }, 619 [L_PASSWORD] = { "password", required_argument, NULL, 0 }, 620 [L_USER_AGENT] = { "user-agent", required_argument, NULL, 0 }, 621 [L_POST_DATA] = { "post-data", required_argument, NULL, 0 }, 622 [L_POST_FILE] = { "post-file", required_argument, NULL, 0 }, 623 [L_METHOD] = { "method", required_argument, NULL, 0 }, 624 [L_BODY_DATA] = { "body-data", required_argument, NULL, 0 }, 625 [L_BODY_FILE] = { "body-file", required_argument, NULL, 0 }, 626 [L_SPIDER] = { "spider", no_argument, NULL, 0 }, 627 [L_TIMEOUT] = { "timeout", required_argument, NULL, 0 }, 628 [L_CONTINUE] = { "continue", no_argument, NULL, 0 }, 629 [L_PROXY] = { "proxy", required_argument, NULL, 0 }, 630 [L_NO_PROXY] = { "no-proxy", no_argument, NULL, 0 }, 631 [L_QUIET] = { "quiet", no_argument, NULL, 0 }, 632 [L_VERBOSE] = { "verbose", no_argument, NULL, 0 }, 633 [L_HEADER] = { "header", required_argument, NULL, 0 }, 634 {} 635 }; 636 637 638 639 int main(int argc, char **argv) 640 { 641 const char *progname = argv[0]; 642 const char *proxy_url; 643 char *username = NULL; 644 char *password = NULL; 645 struct uclient *cl = NULL; 646 int longopt_idx = 0; 647 bool has_cert = false; 648 struct header *h, *th; 649 char *tmp; 650 int i, ch; 651 int rc; 652 int af = -1; 653 int debug_level = 0; 654 655 signal(SIGPIPE, SIG_IGN); 656 ssl_ctx = uclient_new_ssl_context(&ssl_ops); 657 658 while ((ch = getopt_long(argc, argv, "46cO:P:qsT:U:vY:", longopts, &longopt_idx)) != -1) { 659 switch(ch) { 660 case 0: 661 switch (longopt_idx) { 662 case L_NO_CHECK_CERTIFICATE: 663 verify = false; 664 if (ssl_ctx) 665 ssl_ops->context_set_require_validation(ssl_ctx, verify); 666 break; 667 case L_CA_CERTIFICATE: 668 has_cert = true; 669 if (ssl_ctx) 670 ssl_ops->context_add_ca_crt_file(ssl_ctx, optarg); 671 break; 672 case L_CIPHERS: 673 if (ssl_ctx) { 674 if (ssl_ops->context_set_ciphers(ssl_ctx, optarg)) { 675 if (!quiet) 676 fprintf(stderr, "No recognized ciphers in cipher list\n"); 677 exit(1); 678 } 679 } 680 break; 681 case L_USER: 682 if (!strlen(optarg)) 683 break; 684 username = strdupa(optarg); 685 memset(optarg, '*', strlen(optarg)); 686 break; 687 case L_PASSWORD: 688 if (!strlen(optarg)) 689 break; 690 password = strdupa(optarg); 691 memset(optarg, '*', strlen(optarg)); 692 break; 693 case L_USER_AGENT: 694 user_agent = optarg; 695 break; 696 case L_POST_DATA: 697 if (opt_post) { 698 usage(progname); 699 goto out; 700 } 701 opt_post = 1; 702 post_data = optarg; 703 break; 704 case L_POST_FILE: 705 if (opt_post) { 706 usage(progname); 707 goto out; 708 } 709 opt_post = 1; 710 post_file = optarg; 711 break; 712 case L_METHOD: 713 method = optarg; 714 break; 715 case L_BODY_DATA: 716 if (opt_post) { 717 usage(progname); 718 goto out; 719 } 720 opt_post = 2; 721 post_data = optarg; 722 break; 723 case L_BODY_FILE: 724 if (opt_post) { 725 usage(progname); 726 goto out; 727 } 728 opt_post = 2; 729 post_file = optarg; 730 break; 731 case L_SPIDER: 732 no_output = true; 733 break; 734 case L_TIMEOUT: 735 timeout = atoi(optarg); 736 break; 737 case L_CONTINUE: 738 resume = true; 739 break; 740 case L_PROXY: 741 if (strcmp(optarg, "on") != 0) 742 proxy = false; 743 break; 744 case L_NO_PROXY: 745 proxy = false; 746 break; 747 case L_QUIET: 748 quiet = true; 749 break; 750 case L_VERBOSE: 751 debug_level++; 752 break; 753 case L_HEADER: 754 tmp = strchr(optarg, ':'); 755 if (!tmp) { 756 usage(progname); 757 goto out; 758 } 759 *(tmp++) = '\0'; 760 while (isspace(*tmp)) 761 ++tmp; 762 763 if (*tmp == '\0' || !is_valid_header(optarg) || strchr(tmp, '\n')) { 764 usage(progname); 765 goto out; 766 } 767 h = malloc(sizeof(*h)); 768 if (!h) { 769 perror("Set HTTP header"); 770 error_ret = 1; 771 goto out; 772 } 773 h->name = optarg; 774 h->value = tmp; 775 list_add_tail(&h->list, &headers); 776 break; 777 default: 778 usage(progname); 779 goto out; 780 } 781 break; 782 case '4': 783 af = AF_INET; 784 break; 785 case '6': 786 af = AF_INET6; 787 break; 788 case 'c': 789 resume = true; 790 break; 791 case 'U': 792 user_agent = optarg; 793 break; 794 case 'O': 795 opt_output_file = optarg; 796 break; 797 case 'P': 798 if (chdir(optarg)) { 799 if (!quiet) 800 perror("Change output directory"); 801 error_ret = 1; 802 goto out; 803 } 804 break; 805 case 'q': 806 quiet = true; 807 break; 808 case 's': 809 no_output = true; 810 break; 811 case 'T': 812 timeout = atoi(optarg); 813 break; 814 case 'v': 815 debug_level++; 816 break; 817 case 'Y': 818 if (strcmp(optarg, "on") != 0) 819 proxy = false; 820 break; 821 default: 822 usage(progname); 823 goto out; 824 } 825 } 826 827 if (method) { 828 if (opt_post == 1 || no_output) { 829 /* --post-data/file or --spider can't be used with --method */ 830 usage(progname); 831 goto out; 832 } 833 } else { 834 if (opt_post == 1) { 835 method = "POST"; 836 } else if (opt_post == 2) { 837 /* --body-data/file specified but no --method */ 838 usage(progname); 839 goto out; 840 } else if (no_output) { 841 /* Note: GNU wget --spider sends a HEAD and if it failed repeats with a GET */ 842 method = "HEAD"; 843 } else { 844 method = "GET"; 845 } 846 } 847 848 argv += optind; 849 argc -= optind; 850 851 if (debug_level) 852 ssl_ops->context_set_debug(ssl_ctx, debug_level, debug_cb, NULL); 853 854 if (verify && !has_cert) 855 default_certs = true; 856 857 if (argc < 1) { 858 usage(progname); 859 goto out; 860 } 861 862 if (!ssl_ctx) { 863 for (i = 0; i < argc; i++) { 864 if (!strncmp(argv[i], "https", 5)) { 865 no_ssl(progname); 866 goto out; 867 } 868 } 869 } 870 871 urls = argv + 1; 872 n_urls = argc - 1; 873 874 uloop_init(); 875 876 if (username) { 877 if (password) { 878 rc = asprintf(&auth_str, "%s:%s", username, password); 879 if (rc < 0) { 880 error_ret = 1; 881 goto out; 882 } 883 } else 884 auth_str = username; 885 } 886 887 if (!quiet) 888 fprintf(stderr, "Downloading '%s'\n", argv[0]); 889 890 proxy_url = get_proxy_url(argv[0]); 891 if (proxy_url) { 892 cl = uclient_new(proxy_url, auth_str, &cb); 893 if (cl) 894 uclient_set_proxy_url(cl, argv[0], NULL); 895 } else { 896 cl = uclient_new(argv[0], auth_str, &cb); 897 } 898 if (!cl) { 899 fprintf(stderr, "Failed to allocate uclient context\n"); 900 error_ret = 1; 901 goto out; 902 } 903 if (af >= 0) 904 uclient_http_set_address_family(cl, af); 905 906 if (ssl_ctx && default_certs) 907 init_ca_cert(); 908 909 cur_resume = resume; 910 rc = init_request(cl); 911 if (!rc) { 912 /* no error received, we can enter main loop */ 913 uloop_run(); 914 } else { 915 fprintf(stderr, "Failed to send request: %s\n", strerror(rc)); 916 error_ret = 4; 917 goto out; 918 } 919 920 uloop_done(); 921 922 out: 923 if (cl) 924 uclient_free(cl); 925 926 if (output_fd >= 0 && output_fd != STDOUT_FILENO) 927 close(output_fd); 928 929 if (ssl_ctx) 930 ssl_ops->context_free(ssl_ctx); 931 932 list_for_each_entry_safe(h, th, &headers, list) { 933 list_del(&h->list); 934 free(h); 935 } 936 937 return error_ret; 938 } 939
This page was automatically generated by LXR 0.3.1. • OpenWrt