summaryrefslogtreecommitdiffabout
path: root/ui-shared.c
authorLars Hjemli <hjemli@gmail.com>2009-01-11 20:23:04 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2009-01-11 20:23:04 (UTC)
commiteb14609dc46461728a065c0a243b338fc32fd762 (patch) (unidiff)
treef00563342db8859f46ac8141fdaa5d4e17eb940e /ui-shared.c
parent720b6ece90900df9f836a45d8e7f1cd56f62400a (diff)
downloadcgit-eb14609dc46461728a065c0a243b338fc32fd762.zip
cgit-eb14609dc46461728a065c0a243b338fc32fd762.tar.gz
cgit-eb14609dc46461728a065c0a243b338fc32fd762.tar.bz2
Avoid SEGFAULT on invalid requests
When an unknown page is requested, either on the querystring or via PATH_INFO, we end up with a null-referencing cgit_cmd. This null- pointer is then used as argument to the hc() function (which decides what tab to render as 'active'), but this function failed to check if a valid cmd was specified and a SEGFAULT would occur. This patch fixes the issue by introducing a 'fallback-cmd' which specifies what tab to render as 'active' when no valid cmd is requested. While at it, we now also keep track of the active repository even if an invalid cmd was requested since we want to show the error message about the invalid request in the correct context. Noticed-by: Robin Redeker <elmex@ta-sa.org> Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (limited to 'ui-shared.c') (more/less context) (ignore whitespace changes)
-rw-r--r--ui-shared.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/ui-shared.c b/ui-shared.c
index 224e5f3..76cd00d 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -452,263 +452,268 @@ void cgit_print_http_headers(struct cgit_context *ctx)
452 if (ctx->page.filename) 452 if (ctx->page.filename)
453 htmlf("Content-Disposition: inline; filename=\"%s\"\n", 453 htmlf("Content-Disposition: inline; filename=\"%s\"\n",
454 ctx->page.filename); 454 ctx->page.filename);
455 htmlf("Last-Modified: %s\n", http_date(ctx->page.modified)); 455 htmlf("Last-Modified: %s\n", http_date(ctx->page.modified));
456 htmlf("Expires: %s\n", http_date(ctx->page.expires)); 456 htmlf("Expires: %s\n", http_date(ctx->page.expires));
457 html("\n"); 457 html("\n");
458} 458}
459 459
460void cgit_print_docstart(struct cgit_context *ctx) 460void cgit_print_docstart(struct cgit_context *ctx)
461{ 461{
462 char *host = cgit_hosturl(); 462 char *host = cgit_hosturl();
463 html(cgit_doctype); 463 html(cgit_doctype);
464 html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n"); 464 html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n");
465 html("<head>\n"); 465 html("<head>\n");
466 html("<title>"); 466 html("<title>");
467 html_txt(ctx->page.title); 467 html_txt(ctx->page.title);
468 html("</title>\n"); 468 html("</title>\n");
469 htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version); 469 htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version);
470 if (ctx->cfg.robots && *ctx->cfg.robots) 470 if (ctx->cfg.robots && *ctx->cfg.robots)
471 htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots); 471 htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots);
472 html("<link rel='stylesheet' type='text/css' href='"); 472 html("<link rel='stylesheet' type='text/css' href='");
473 html_attr(ctx->cfg.css); 473 html_attr(ctx->cfg.css);
474 html("'/>\n"); 474 html("'/>\n");
475 if (ctx->cfg.favicon) { 475 if (ctx->cfg.favicon) {
476 html("<link rel='shortcut icon' href='"); 476 html("<link rel='shortcut icon' href='");
477 html_attr(ctx->cfg.favicon); 477 html_attr(ctx->cfg.favicon);
478 html("'/>\n"); 478 html("'/>\n");
479 } 479 }
480 if (host && ctx->repo) { 480 if (host && ctx->repo) {
481 html("<link rel='alternate' title='Atom feed' href='http://"); 481 html("<link rel='alternate' title='Atom feed' href='http://");
482 html_attr(cgit_hosturl()); 482 html_attr(cgit_hosturl());
483 html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.path, 483 html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.path,
484 fmt("h=%s", ctx->qry.head))); 484 fmt("h=%s", ctx->qry.head)));
485 html("' type='application/atom+xml'/>"); 485 html("' type='application/atom+xml'/>");
486 } 486 }
487 html("</head>\n"); 487 html("</head>\n");
488 html("<body>\n"); 488 html("<body>\n");
489} 489}
490 490
491void cgit_print_docend() 491void cgit_print_docend()
492{ 492{
493 html("</div>"); 493 html("</div>");
494 if (ctx.cfg.footer) 494 if (ctx.cfg.footer)
495 html_include(ctx.cfg.footer); 495 html_include(ctx.cfg.footer);
496 else { 496 else {
497 htmlf("<div class='footer'>generated by cgit %s at ", 497 htmlf("<div class='footer'>generated by cgit %s at ",
498 cgit_version); 498 cgit_version);
499 cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time); 499 cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time);
500 html("</div>\n"); 500 html("</div>\n");
501 } 501 }
502 html("</body>\n</html>\n"); 502 html("</body>\n</html>\n");
503} 503}
504 504
505int print_branch_option(const char *refname, const unsigned char *sha1, 505int print_branch_option(const char *refname, const unsigned char *sha1,
506 int flags, void *cb_data) 506 int flags, void *cb_data)
507{ 507{
508 char *name = (char *)refname; 508 char *name = (char *)refname;
509 html_option(name, name, ctx.qry.head); 509 html_option(name, name, ctx.qry.head);
510 return 0; 510 return 0;
511} 511}
512 512
513int print_archive_ref(const char *refname, const unsigned char *sha1, 513int print_archive_ref(const char *refname, const unsigned char *sha1,
514 int flags, void *cb_data) 514 int flags, void *cb_data)
515{ 515{
516 struct tag *tag; 516 struct tag *tag;
517 struct taginfo *info; 517 struct taginfo *info;
518 struct object *obj; 518 struct object *obj;
519 char buf[256], *url; 519 char buf[256], *url;
520 unsigned char fileid[20]; 520 unsigned char fileid[20];
521 int *header = (int *)cb_data; 521 int *header = (int *)cb_data;
522 522
523 if (prefixcmp(refname, "refs/archives")) 523 if (prefixcmp(refname, "refs/archives"))
524 return 0; 524 return 0;
525 strncpy(buf, refname+14, sizeof(buf)); 525 strncpy(buf, refname+14, sizeof(buf));
526 obj = parse_object(sha1); 526 obj = parse_object(sha1);
527 if (!obj) 527 if (!obj)
528 return 1; 528 return 1;
529 if (obj->type == OBJ_TAG) { 529 if (obj->type == OBJ_TAG) {
530 tag = lookup_tag(sha1); 530 tag = lookup_tag(sha1);
531 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) 531 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
532 return 0; 532 return 0;
533 hashcpy(fileid, tag->tagged->sha1); 533 hashcpy(fileid, tag->tagged->sha1);
534 } else if (obj->type != OBJ_BLOB) { 534 } else if (obj->type != OBJ_BLOB) {
535 return 0; 535 return 0;
536 } else { 536 } else {
537 hashcpy(fileid, sha1); 537 hashcpy(fileid, sha1);
538 } 538 }
539 if (!*header) { 539 if (!*header) {
540 html("<h1>download</h1>\n"); 540 html("<h1>download</h1>\n");
541 *header = 1; 541 *header = 1;
542 } 542 }
543 url = cgit_pageurl(ctx.qry.repo, "blob", 543 url = cgit_pageurl(ctx.qry.repo, "blob",
544 fmt("id=%s&amp;path=%s", sha1_to_hex(fileid), 544 fmt("id=%s&amp;path=%s", sha1_to_hex(fileid),
545 buf)); 545 buf));
546 html_link_open(url, NULL, "menu"); 546 html_link_open(url, NULL, "menu");
547 html_txt(strlpart(buf, 20)); 547 html_txt(strlpart(buf, 20));
548 html_link_close(); 548 html_link_close();
549 return 0; 549 return 0;
550} 550}
551 551
552void add_hidden_formfields(int incl_head, int incl_search, char *page) 552void add_hidden_formfields(int incl_head, int incl_search, char *page)
553{ 553{
554 char *url; 554 char *url;
555 555
556 if (!ctx.cfg.virtual_root) { 556 if (!ctx.cfg.virtual_root) {
557 url = fmt("%s/%s", ctx.qry.repo, page); 557 url = fmt("%s/%s", ctx.qry.repo, page);
558 if (ctx.qry.path) 558 if (ctx.qry.path)
559 url = fmt("%s/%s", url, ctx.qry.path); 559 url = fmt("%s/%s", url, ctx.qry.path);
560 html_hidden("url", url); 560 html_hidden("url", url);
561 } 561 }
562 562
563 if (incl_head && ctx.qry.head && ctx.repo->defbranch && 563 if (incl_head && ctx.qry.head && ctx.repo->defbranch &&
564 strcmp(ctx.qry.head, ctx.repo->defbranch)) 564 strcmp(ctx.qry.head, ctx.repo->defbranch))
565 html_hidden("h", ctx.qry.head); 565 html_hidden("h", ctx.qry.head);
566 566
567 if (ctx.qry.sha1) 567 if (ctx.qry.sha1)
568 html_hidden("id", ctx.qry.sha1); 568 html_hidden("id", ctx.qry.sha1);
569 if (ctx.qry.sha2) 569 if (ctx.qry.sha2)
570 html_hidden("id2", ctx.qry.sha2); 570 html_hidden("id2", ctx.qry.sha2);
571 571
572 if (incl_search) { 572 if (incl_search) {
573 if (ctx.qry.grep) 573 if (ctx.qry.grep)
574 html_hidden("qt", ctx.qry.grep); 574 html_hidden("qt", ctx.qry.grep);
575 if (ctx.qry.search) 575 if (ctx.qry.search)
576 html_hidden("q", ctx.qry.search); 576 html_hidden("q", ctx.qry.search);
577 } 577 }
578} 578}
579 579
580const char *fallback_cmd = "repolist";
581
580char *hc(struct cgit_cmd *cmd, const char *page) 582char *hc(struct cgit_cmd *cmd, const char *page)
581{ 583{
582 return (strcmp(cmd->name, page) ? NULL : "active"); 584 return (strcmp(cmd ? cmd->name : fallback_cmd, page) ? NULL : "active");
583} 585}
584 586
585void cgit_print_pageheader(struct cgit_context *ctx) 587void cgit_print_pageheader(struct cgit_context *ctx)
586{ 588{
587 struct cgit_cmd *cmd = cgit_get_cmd(ctx); 589 struct cgit_cmd *cmd = cgit_get_cmd(ctx);
588 590
591 if (!cmd && ctx->repo)
592 fallback_cmd = "summary";
593
589 html("<table id='header'>\n"); 594 html("<table id='header'>\n");
590 html("<tr>\n"); 595 html("<tr>\n");
591 html("<td class='logo' rowspan='2'><a href='"); 596 html("<td class='logo' rowspan='2'><a href='");
592 if (ctx->cfg.logo_link) 597 if (ctx->cfg.logo_link)
593 html_attr(ctx->cfg.logo_link); 598 html_attr(ctx->cfg.logo_link);
594 else 599 else
595 html_attr(cgit_rooturl()); 600 html_attr(cgit_rooturl());
596 html("'><img src='"); 601 html("'><img src='");
597 html_attr(ctx->cfg.logo); 602 html_attr(ctx->cfg.logo);
598 html("' alt='cgit logo'/></a></td>\n"); 603 html("' alt='cgit logo'/></a></td>\n");
599 604
600 html("<td class='main'>"); 605 html("<td class='main'>");
601 if (ctx->repo) { 606 if (ctx->repo) {
602 cgit_index_link("index", NULL, NULL, NULL, 0); 607 cgit_index_link("index", NULL, NULL, NULL, 0);
603 html(" : "); 608 html(" : ");
604 cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL); 609 cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL);
605 html("</td><td class='form'>"); 610 html("</td><td class='form'>");
606 html("<form method='get' action=''>\n"); 611 html("<form method='get' action=''>\n");
607 add_hidden_formfields(0, 1, ctx->qry.page); 612 add_hidden_formfields(0, 1, ctx->qry.page);
608 html("<select name='h' onchange='this.form.submit();'>\n"); 613 html("<select name='h' onchange='this.form.submit();'>\n");
609 for_each_branch_ref(print_branch_option, ctx->qry.head); 614 for_each_branch_ref(print_branch_option, ctx->qry.head);
610 html("</select> "); 615 html("</select> ");
611 html("<input type='submit' name='' value='switch'/>"); 616 html("<input type='submit' name='' value='switch'/>");
612 html("</form>"); 617 html("</form>");
613 } else 618 } else
614 html_txt(ctx->cfg.root_title); 619 html_txt(ctx->cfg.root_title);
615 html("</td></tr>\n"); 620 html("</td></tr>\n");
616 621
617 html("<tr><td class='sub'>"); 622 html("<tr><td class='sub'>");
618 if (ctx->repo) { 623 if (ctx->repo) {
619 html_txt(ctx->repo->desc); 624 html_txt(ctx->repo->desc);
620 html("</td><td class='sub right'>"); 625 html("</td><td class='sub right'>");
621 html_txt(ctx->repo->owner); 626 html_txt(ctx->repo->owner);
622 } else { 627 } else {
623 if (ctx->cfg.root_desc) 628 if (ctx->cfg.root_desc)
624 html_txt(ctx->cfg.root_desc); 629 html_txt(ctx->cfg.root_desc);
625 else if (ctx->cfg.index_info) 630 else if (ctx->cfg.index_info)
626 html_include(ctx->cfg.index_info); 631 html_include(ctx->cfg.index_info);
627 } 632 }
628 html("</td></tr></table>\n"); 633 html("</td></tr></table>\n");
629 634
630 html("<table class='tabs'><tr><td>\n"); 635 html("<table class='tabs'><tr><td>\n");
631 if (ctx->repo) { 636 if (ctx->repo) {
632 cgit_summary_link("summary", NULL, hc(cmd, "summary"), 637 cgit_summary_link("summary", NULL, hc(cmd, "summary"),
633 ctx->qry.head); 638 ctx->qry.head);
634 cgit_refs_link("refs", NULL, hc(cmd, "refs"), ctx->qry.head, 639 cgit_refs_link("refs", NULL, hc(cmd, "refs"), ctx->qry.head,
635 ctx->qry.sha1, NULL); 640 ctx->qry.sha1, NULL);
636 cgit_log_link("log", NULL, hc(cmd, "log"), ctx->qry.head, 641 cgit_log_link("log", NULL, hc(cmd, "log"), ctx->qry.head,
637 NULL, NULL, 0, NULL, NULL); 642 NULL, NULL, 0, NULL, NULL);
638 cgit_tree_link("tree", NULL, hc(cmd, "tree"), ctx->qry.head, 643 cgit_tree_link("tree", NULL, hc(cmd, "tree"), ctx->qry.head,
639 ctx->qry.sha1, NULL); 644 ctx->qry.sha1, NULL);
640 cgit_commit_link("commit", NULL, hc(cmd, "commit"), 645 cgit_commit_link("commit", NULL, hc(cmd, "commit"),
641 ctx->qry.head, ctx->qry.sha1); 646 ctx->qry.head, ctx->qry.sha1);
642 cgit_diff_link("diff", NULL, hc(cmd, "diff"), ctx->qry.head, 647 cgit_diff_link("diff", NULL, hc(cmd, "diff"), ctx->qry.head,
643 ctx->qry.sha1, ctx->qry.sha2, NULL); 648 ctx->qry.sha1, ctx->qry.sha2, NULL);
644 if (ctx->repo->readme) 649 if (ctx->repo->readme)
645 reporevlink("about", "about", NULL, 650 reporevlink("about", "about", NULL,
646 hc(cmd, "about"), ctx->qry.head, NULL, 651 hc(cmd, "about"), ctx->qry.head, NULL,
647 NULL); 652 NULL);
648 html("</td><td class='form'>"); 653 html("</td><td class='form'>");
649 html("<form class='right' method='get' action='"); 654 html("<form class='right' method='get' action='");
650 if (ctx->cfg.virtual_root) 655 if (ctx->cfg.virtual_root)
651 html_url_path(cgit_fileurl(ctx->qry.repo, "log", 656 html_url_path(cgit_fileurl(ctx->qry.repo, "log",
652 ctx->qry.path, NULL)); 657 ctx->qry.path, NULL));
653 html("'>\n"); 658 html("'>\n");
654 add_hidden_formfields(1, 0, "log"); 659 add_hidden_formfields(1, 0, "log");
655 html("<select name='qt'>\n"); 660 html("<select name='qt'>\n");
656 html_option("grep", "log msg", ctx->qry.grep); 661 html_option("grep", "log msg", ctx->qry.grep);
657 html_option("author", "author", ctx->qry.grep); 662 html_option("author", "author", ctx->qry.grep);
658 html_option("committer", "committer", ctx->qry.grep); 663 html_option("committer", "committer", ctx->qry.grep);
659 html("</select>\n"); 664 html("</select>\n");
660 html("<input class='txt' type='text' size='10' name='q' value='"); 665 html("<input class='txt' type='text' size='10' name='q' value='");
661 html_attr(ctx->qry.search); 666 html_attr(ctx->qry.search);
662 html("'/>\n"); 667 html("'/>\n");
663 html("<input type='submit' value='search'/>\n"); 668 html("<input type='submit' value='search'/>\n");
664 html("</form>\n"); 669 html("</form>\n");
665 } else { 670 } else {
666 site_link(NULL, "index", NULL, hc(cmd, "repolist"), NULL, 0); 671 site_link(NULL, "index", NULL, hc(cmd, "repolist"), NULL, 0);
667 if (ctx->cfg.root_readme) 672 if (ctx->cfg.root_readme)
668 site_link("about", "about", NULL, hc(cmd, "about"), 673 site_link("about", "about", NULL, hc(cmd, "about"),
669 NULL, 0); 674 NULL, 0);
670 html("</td><td class='form'>"); 675 html("</td><td class='form'>");
671 html("<form method='get' action='"); 676 html("<form method='get' action='");
672 html_attr(cgit_rooturl()); 677 html_attr(cgit_rooturl());
673 html("'>\n"); 678 html("'>\n");
674 html("<input type='text' name='q' size='10' value='"); 679 html("<input type='text' name='q' size='10' value='");
675 html_attr(ctx->qry.search); 680 html_attr(ctx->qry.search);
676 html("'/>\n"); 681 html("'/>\n");
677 html("<input type='submit' value='search'/>\n"); 682 html("<input type='submit' value='search'/>\n");
678 html("</form>"); 683 html("</form>");
679 } 684 }
680 html("</td></tr></table>\n"); 685 html("</td></tr></table>\n");
681 html("<div class='content'>"); 686 html("<div class='content'>");
682} 687}
683 688
684void cgit_print_filemode(unsigned short mode) 689void cgit_print_filemode(unsigned short mode)
685{ 690{
686 if (S_ISDIR(mode)) 691 if (S_ISDIR(mode))
687 html("d"); 692 html("d");
688 else if (S_ISLNK(mode)) 693 else if (S_ISLNK(mode))
689 html("l"); 694 html("l");
690 else if (S_ISGITLINK(mode)) 695 else if (S_ISGITLINK(mode))
691 html("m"); 696 html("m");
692 else 697 else
693 html("-"); 698 html("-");
694 html_fileperm(mode >> 6); 699 html_fileperm(mode >> 6);
695 html_fileperm(mode >> 3); 700 html_fileperm(mode >> 3);
696 html_fileperm(mode); 701 html_fileperm(mode);
697} 702}
698 703
699void cgit_print_snapshot_links(const char *repo, const char *head, 704void cgit_print_snapshot_links(const char *repo, const char *head,
700 const char *hex, int snapshots) 705 const char *hex, int snapshots)
701{ 706{
702 const struct cgit_snapshot_format* f; 707 const struct cgit_snapshot_format* f;
703 char *filename; 708 char *filename;
704 709
705 for (f = cgit_snapshot_formats; f->suffix; f++) { 710 for (f = cgit_snapshot_formats; f->suffix; f++) {
706 if (!(snapshots & f->bit)) 711 if (!(snapshots & f->bit))
707 continue; 712 continue;
708 filename = fmt("%s-%s%s", cgit_repobasename(repo), hex, 713 filename = fmt("%s-%s%s", cgit_repobasename(repo), hex,
709 f->suffix); 714 f->suffix);
710 cgit_snapshot_link(filename, NULL, NULL, (char *)head, 715 cgit_snapshot_link(filename, NULL, NULL, (char *)head,
711 (char *)hex, filename); 716 (char *)hex, filename);
712 html("<br/>"); 717 html("<br/>");
713 } 718 }
714} 719}