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