author | Mark Lodato <lodatom@gmail.com> | 2011-05-13 23:59:07 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2011-05-23 21:20:59 (UTC) |
commit | ec79265f2053e6dc20e0ec486719f5954d2be83d (patch) (unidiff) | |
tree | bae66fbd919c03d0204554cc0c109c7eba0e3b97 /cgit.c | |
parent | c8ea73caabcb16ffb74baa70d35650027ed772c4 (diff) | |
download | cgit-ec79265f2053e6dc20e0ec486719f5954d2be83d.zip cgit-ec79265f2053e6dc20e0ec486719f5954d2be83d.tar.gz cgit-ec79265f2053e6dc20e0ec486719f5954d2be83d.tar.bz2 |
fix virtual-root if script-name is ""
In d0cb841 (Avoid trailing slash in virtual-root), virtual-root was set
from script-name using trim_end(). However, if script-name was the
empty string (""), which happens when cgit is used to serve the root
path on a domain (/), trim_end() returns NULL and cgit acts like
virtual-root is not available. Now, set virtual-root to "" in this
case, which fixes this bug.
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | cgit.c | 5 |
1 files changed, 4 insertions, 1 deletions
@@ -568,227 +568,230 @@ void print_repo(FILE *f, struct cgit_repo *repo) | |||
568 | if (repo->snapshots != ctx.cfg.snapshots) { | 568 | if (repo->snapshots != ctx.cfg.snapshots) { |
569 | char *tmp = build_snapshot_setting(repo->snapshots); | 569 | char *tmp = build_snapshot_setting(repo->snapshots); |
570 | fprintf(f, "repo.snapshots=%s\n", tmp); | 570 | fprintf(f, "repo.snapshots=%s\n", tmp); |
571 | free(tmp); | 571 | free(tmp); |
572 | } | 572 | } |
573 | if (repo->max_stats != ctx.cfg.max_stats) | 573 | if (repo->max_stats != ctx.cfg.max_stats) |
574 | fprintf(f, "repo.max-stats=%s\n", | 574 | fprintf(f, "repo.max-stats=%s\n", |
575 | cgit_find_stats_periodname(repo->max_stats)); | 575 | cgit_find_stats_periodname(repo->max_stats)); |
576 | fprintf(f, "\n"); | 576 | fprintf(f, "\n"); |
577 | } | 577 | } |
578 | 578 | ||
579 | void print_repolist(FILE *f, struct cgit_repolist *list, int start) | 579 | void print_repolist(FILE *f, struct cgit_repolist *list, int start) |
580 | { | 580 | { |
581 | int i; | 581 | int i; |
582 | 582 | ||
583 | for(i = start; i < list->count; i++) | 583 | for(i = start; i < list->count; i++) |
584 | print_repo(f, &list->repos[i]); | 584 | print_repo(f, &list->repos[i]); |
585 | } | 585 | } |
586 | 586 | ||
587 | /* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' | 587 | /* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' |
588 | * and return 0 on success. | 588 | * and return 0 on success. |
589 | */ | 589 | */ |
590 | static int generate_cached_repolist(const char *path, const char *cached_rc) | 590 | static int generate_cached_repolist(const char *path, const char *cached_rc) |
591 | { | 591 | { |
592 | char *locked_rc; | 592 | char *locked_rc; |
593 | int idx; | 593 | int idx; |
594 | FILE *f; | 594 | FILE *f; |
595 | 595 | ||
596 | locked_rc = xstrdup(fmt("%s.lock", cached_rc)); | 596 | locked_rc = xstrdup(fmt("%s.lock", cached_rc)); |
597 | f = fopen(locked_rc, "wx"); | 597 | f = fopen(locked_rc, "wx"); |
598 | if (!f) { | 598 | if (!f) { |
599 | /* Inform about the error unless the lockfile already existed, | 599 | /* Inform about the error unless the lockfile already existed, |
600 | * since that only means we've got concurrent requests. | 600 | * since that only means we've got concurrent requests. |
601 | */ | 601 | */ |
602 | if (errno != EEXIST) | 602 | if (errno != EEXIST) |
603 | fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", | 603 | fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", |
604 | locked_rc, strerror(errno), errno); | 604 | locked_rc, strerror(errno), errno); |
605 | return errno; | 605 | return errno; |
606 | } | 606 | } |
607 | idx = cgit_repolist.count; | 607 | idx = cgit_repolist.count; |
608 | if (ctx.cfg.project_list) | 608 | if (ctx.cfg.project_list) |
609 | scan_projects(path, ctx.cfg.project_list, repo_config); | 609 | scan_projects(path, ctx.cfg.project_list, repo_config); |
610 | else | 610 | else |
611 | scan_tree(path, repo_config); | 611 | scan_tree(path, repo_config); |
612 | print_repolist(f, &cgit_repolist, idx); | 612 | print_repolist(f, &cgit_repolist, idx); |
613 | if (rename(locked_rc, cached_rc)) | 613 | if (rename(locked_rc, cached_rc)) |
614 | fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", | 614 | fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", |
615 | locked_rc, cached_rc, strerror(errno), errno); | 615 | locked_rc, cached_rc, strerror(errno), errno); |
616 | fclose(f); | 616 | fclose(f); |
617 | return 0; | 617 | return 0; |
618 | } | 618 | } |
619 | 619 | ||
620 | static void process_cached_repolist(const char *path) | 620 | static void process_cached_repolist(const char *path) |
621 | { | 621 | { |
622 | struct stat st; | 622 | struct stat st; |
623 | char *cached_rc; | 623 | char *cached_rc; |
624 | time_t age; | 624 | time_t age; |
625 | unsigned long hash; | 625 | unsigned long hash; |
626 | 626 | ||
627 | hash = hash_str(path); | 627 | hash = hash_str(path); |
628 | if (ctx.cfg.project_list) | 628 | if (ctx.cfg.project_list) |
629 | hash += hash_str(ctx.cfg.project_list); | 629 | hash += hash_str(ctx.cfg.project_list); |
630 | cached_rc = xstrdup(fmt("%s/rc-%8lx", ctx.cfg.cache_root, hash)); | 630 | cached_rc = xstrdup(fmt("%s/rc-%8lx", ctx.cfg.cache_root, hash)); |
631 | 631 | ||
632 | if (stat(cached_rc, &st)) { | 632 | if (stat(cached_rc, &st)) { |
633 | /* Nothing is cached, we need to scan without forking. And | 633 | /* Nothing is cached, we need to scan without forking. And |
634 | * if we fail to generate a cached repolist, we need to | 634 | * if we fail to generate a cached repolist, we need to |
635 | * invoke scan_tree manually. | 635 | * invoke scan_tree manually. |
636 | */ | 636 | */ |
637 | if (generate_cached_repolist(path, cached_rc)) { | 637 | if (generate_cached_repolist(path, cached_rc)) { |
638 | if (ctx.cfg.project_list) | 638 | if (ctx.cfg.project_list) |
639 | scan_projects(path, ctx.cfg.project_list, | 639 | scan_projects(path, ctx.cfg.project_list, |
640 | repo_config); | 640 | repo_config); |
641 | else | 641 | else |
642 | scan_tree(path, repo_config); | 642 | scan_tree(path, repo_config); |
643 | } | 643 | } |
644 | return; | 644 | return; |
645 | } | 645 | } |
646 | 646 | ||
647 | parse_configfile(cached_rc, config_cb); | 647 | parse_configfile(cached_rc, config_cb); |
648 | 648 | ||
649 | /* If the cached configfile hasn't expired, lets exit now */ | 649 | /* If the cached configfile hasn't expired, lets exit now */ |
650 | age = time(NULL) - st.st_mtime; | 650 | age = time(NULL) - st.st_mtime; |
651 | if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) | 651 | if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) |
652 | return; | 652 | return; |
653 | 653 | ||
654 | /* The cached repolist has been parsed, but it was old. So lets | 654 | /* The cached repolist has been parsed, but it was old. So lets |
655 | * rescan the specified path and generate a new cached repolist | 655 | * rescan the specified path and generate a new cached repolist |
656 | * in a child-process to avoid latency for the current request. | 656 | * in a child-process to avoid latency for the current request. |
657 | */ | 657 | */ |
658 | if (fork()) | 658 | if (fork()) |
659 | return; | 659 | return; |
660 | 660 | ||
661 | exit(generate_cached_repolist(path, cached_rc)); | 661 | exit(generate_cached_repolist(path, cached_rc)); |
662 | } | 662 | } |
663 | 663 | ||
664 | static void cgit_parse_args(int argc, const char **argv) | 664 | static void cgit_parse_args(int argc, const char **argv) |
665 | { | 665 | { |
666 | int i; | 666 | int i; |
667 | int scan = 0; | 667 | int scan = 0; |
668 | 668 | ||
669 | for (i = 1; i < argc; i++) { | 669 | for (i = 1; i < argc; i++) { |
670 | if (!strncmp(argv[i], "--cache=", 8)) { | 670 | if (!strncmp(argv[i], "--cache=", 8)) { |
671 | ctx.cfg.cache_root = xstrdup(argv[i]+8); | 671 | ctx.cfg.cache_root = xstrdup(argv[i]+8); |
672 | } | 672 | } |
673 | if (!strcmp(argv[i], "--nocache")) { | 673 | if (!strcmp(argv[i], "--nocache")) { |
674 | ctx.cfg.nocache = 1; | 674 | ctx.cfg.nocache = 1; |
675 | } | 675 | } |
676 | if (!strcmp(argv[i], "--nohttp")) { | 676 | if (!strcmp(argv[i], "--nohttp")) { |
677 | ctx.env.no_http = "1"; | 677 | ctx.env.no_http = "1"; |
678 | } | 678 | } |
679 | if (!strncmp(argv[i], "--query=", 8)) { | 679 | if (!strncmp(argv[i], "--query=", 8)) { |
680 | ctx.qry.raw = xstrdup(argv[i]+8); | 680 | ctx.qry.raw = xstrdup(argv[i]+8); |
681 | } | 681 | } |
682 | if (!strncmp(argv[i], "--repo=", 7)) { | 682 | if (!strncmp(argv[i], "--repo=", 7)) { |
683 | ctx.qry.repo = xstrdup(argv[i]+7); | 683 | ctx.qry.repo = xstrdup(argv[i]+7); |
684 | } | 684 | } |
685 | if (!strncmp(argv[i], "--page=", 7)) { | 685 | if (!strncmp(argv[i], "--page=", 7)) { |
686 | ctx.qry.page = xstrdup(argv[i]+7); | 686 | ctx.qry.page = xstrdup(argv[i]+7); |
687 | } | 687 | } |
688 | if (!strncmp(argv[i], "--head=", 7)) { | 688 | if (!strncmp(argv[i], "--head=", 7)) { |
689 | ctx.qry.head = xstrdup(argv[i]+7); | 689 | ctx.qry.head = xstrdup(argv[i]+7); |
690 | ctx.qry.has_symref = 1; | 690 | ctx.qry.has_symref = 1; |
691 | } | 691 | } |
692 | if (!strncmp(argv[i], "--sha1=", 7)) { | 692 | if (!strncmp(argv[i], "--sha1=", 7)) { |
693 | ctx.qry.sha1 = xstrdup(argv[i]+7); | 693 | ctx.qry.sha1 = xstrdup(argv[i]+7); |
694 | ctx.qry.has_sha1 = 1; | 694 | ctx.qry.has_sha1 = 1; |
695 | } | 695 | } |
696 | if (!strncmp(argv[i], "--ofs=", 6)) { | 696 | if (!strncmp(argv[i], "--ofs=", 6)) { |
697 | ctx.qry.ofs = atoi(argv[i]+6); | 697 | ctx.qry.ofs = atoi(argv[i]+6); |
698 | } | 698 | } |
699 | if (!strncmp(argv[i], "--scan-tree=", 12) || | 699 | if (!strncmp(argv[i], "--scan-tree=", 12) || |
700 | !strncmp(argv[i], "--scan-path=", 12)) { | 700 | !strncmp(argv[i], "--scan-path=", 12)) { |
701 | /* HACK: the global snapshot bitmask defines the | 701 | /* HACK: the global snapshot bitmask defines the |
702 | * set of allowed snapshot formats, but the config | 702 | * set of allowed snapshot formats, but the config |
703 | * file hasn't been parsed yet so the mask is | 703 | * file hasn't been parsed yet so the mask is |
704 | * currently 0. By setting all bits high before | 704 | * currently 0. By setting all bits high before |
705 | * scanning we make sure that any in-repo cgitrc | 705 | * scanning we make sure that any in-repo cgitrc |
706 | * snapshot setting is respected by scan_tree(). | 706 | * snapshot setting is respected by scan_tree(). |
707 | * BTW: we assume that there'll never be more than | 707 | * BTW: we assume that there'll never be more than |
708 | * 255 different snapshot formats supported by cgit... | 708 | * 255 different snapshot formats supported by cgit... |
709 | */ | 709 | */ |
710 | ctx.cfg.snapshots = 0xFF; | 710 | ctx.cfg.snapshots = 0xFF; |
711 | scan++; | 711 | scan++; |
712 | scan_tree(argv[i] + 12, repo_config); | 712 | scan_tree(argv[i] + 12, repo_config); |
713 | } | 713 | } |
714 | } | 714 | } |
715 | if (scan) { | 715 | if (scan) { |
716 | qsort(cgit_repolist.repos, cgit_repolist.count, | 716 | qsort(cgit_repolist.repos, cgit_repolist.count, |
717 | sizeof(struct cgit_repo), cmp_repos); | 717 | sizeof(struct cgit_repo), cmp_repos); |
718 | print_repolist(stdout, &cgit_repolist, 0); | 718 | print_repolist(stdout, &cgit_repolist, 0); |
719 | exit(0); | 719 | exit(0); |
720 | } | 720 | } |
721 | } | 721 | } |
722 | 722 | ||
723 | static int calc_ttl() | 723 | static int calc_ttl() |
724 | { | 724 | { |
725 | if (!ctx.repo) | 725 | if (!ctx.repo) |
726 | return ctx.cfg.cache_root_ttl; | 726 | return ctx.cfg.cache_root_ttl; |
727 | 727 | ||
728 | if (!ctx.qry.page) | 728 | if (!ctx.qry.page) |
729 | return ctx.cfg.cache_repo_ttl; | 729 | return ctx.cfg.cache_repo_ttl; |
730 | 730 | ||
731 | if (ctx.qry.has_symref) | 731 | if (ctx.qry.has_symref) |
732 | return ctx.cfg.cache_dynamic_ttl; | 732 | return ctx.cfg.cache_dynamic_ttl; |
733 | 733 | ||
734 | if (ctx.qry.has_sha1) | 734 | if (ctx.qry.has_sha1) |
735 | return ctx.cfg.cache_static_ttl; | 735 | return ctx.cfg.cache_static_ttl; |
736 | 736 | ||
737 | return ctx.cfg.cache_repo_ttl; | 737 | return ctx.cfg.cache_repo_ttl; |
738 | } | 738 | } |
739 | 739 | ||
740 | int main(int argc, const char **argv) | 740 | int main(int argc, const char **argv) |
741 | { | 741 | { |
742 | const char *path; | 742 | const char *path; |
743 | char *qry; | 743 | char *qry; |
744 | int err, ttl; | 744 | int err, ttl; |
745 | 745 | ||
746 | prepare_context(&ctx); | 746 | prepare_context(&ctx); |
747 | cgit_repolist.length = 0; | 747 | cgit_repolist.length = 0; |
748 | cgit_repolist.count = 0; | 748 | cgit_repolist.count = 0; |
749 | cgit_repolist.repos = NULL; | 749 | cgit_repolist.repos = NULL; |
750 | 750 | ||
751 | cgit_parse_args(argc, argv); | 751 | cgit_parse_args(argc, argv); |
752 | parse_configfile(expand_macros(ctx.env.cgit_config), config_cb); | 752 | parse_configfile(expand_macros(ctx.env.cgit_config), config_cb); |
753 | ctx.repo = NULL; | 753 | ctx.repo = NULL; |
754 | http_parse_querystring(ctx.qry.raw, querystring_cb); | 754 | http_parse_querystring(ctx.qry.raw, querystring_cb); |
755 | 755 | ||
756 | /* If virtual-root isn't specified in cgitrc, lets pretend | 756 | /* If virtual-root isn't specified in cgitrc, lets pretend |
757 | * that virtual-root equals SCRIPT_NAME, minus any possibly | 757 | * that virtual-root equals SCRIPT_NAME, minus any possibly |
758 | * trailing slashes. | 758 | * trailing slashes. |
759 | */ | 759 | */ |
760 | if (!ctx.cfg.virtual_root) | 760 | if (!ctx.cfg.virtual_root && ctx.cfg.script_name) { |
761 | ctx.cfg.virtual_root = trim_end(ctx.cfg.script_name, '/'); | 761 | ctx.cfg.virtual_root = trim_end(ctx.cfg.script_name, '/'); |
762 | if (!ctx.cfg.virtual_root) | ||
763 | ctx.cfg.virtual_root = ""; | ||
764 | } | ||
762 | 765 | ||
763 | /* If no url parameter is specified on the querystring, lets | 766 | /* If no url parameter is specified on the querystring, lets |
764 | * use PATH_INFO as url. This allows cgit to work with virtual | 767 | * use PATH_INFO as url. This allows cgit to work with virtual |
765 | * urls without the need for rewriterules in the webserver (as | 768 | * urls without the need for rewriterules in the webserver (as |
766 | * long as PATH_INFO is included in the cache lookup key). | 769 | * long as PATH_INFO is included in the cache lookup key). |
767 | */ | 770 | */ |
768 | path = ctx.env.path_info; | 771 | path = ctx.env.path_info; |
769 | if (!ctx.qry.url && path) { | 772 | if (!ctx.qry.url && path) { |
770 | if (path[0] == '/') | 773 | if (path[0] == '/') |
771 | path++; | 774 | path++; |
772 | ctx.qry.url = xstrdup(path); | 775 | ctx.qry.url = xstrdup(path); |
773 | if (ctx.qry.raw) { | 776 | if (ctx.qry.raw) { |
774 | qry = ctx.qry.raw; | 777 | qry = ctx.qry.raw; |
775 | ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry)); | 778 | ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry)); |
776 | free(qry); | 779 | free(qry); |
777 | } else | 780 | } else |
778 | ctx.qry.raw = xstrdup(ctx.qry.url); | 781 | ctx.qry.raw = xstrdup(ctx.qry.url); |
779 | cgit_parse_url(ctx.qry.url); | 782 | cgit_parse_url(ctx.qry.url); |
780 | } | 783 | } |
781 | 784 | ||
782 | ttl = calc_ttl(); | 785 | ttl = calc_ttl(); |
783 | ctx.page.expires += ttl*60; | 786 | ctx.page.expires += ttl*60; |
784 | if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD")) | 787 | if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD")) |
785 | ctx.cfg.nocache = 1; | 788 | ctx.cfg.nocache = 1; |
786 | if (ctx.cfg.nocache) | 789 | if (ctx.cfg.nocache) |
787 | ctx.cfg.cache_size = 0; | 790 | ctx.cfg.cache_size = 0; |
788 | err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, | 791 | err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, |
789 | ctx.qry.raw, ttl, process_request, &ctx); | 792 | ctx.qry.raw, ttl, process_request, &ctx); |
790 | if (err) | 793 | if (err) |
791 | cgit_print_error(fmt("Error processing page: %s (%d)", | 794 | cgit_print_error(fmt("Error processing page: %s (%d)", |
792 | strerror(err), err)); | 795 | strerror(err), err)); |
793 | return err; | 796 | return err; |
794 | } | 797 | } |