GIT 1.6.0.6
authorJunio C Hamano <gitster@pobox.com>
Sat, 20 Dec 2008 03:27:06 +0000 (19:27 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sat, 20 Dec 2008 03:27:35 +0000 (19:27 -0800)
Signed-off-by: Junio C Hamano <gitster@pobox.com>
1  2 
Documentation/RelNotes-1.6.0.6.txt
RelNotes
gitweb/gitweb.perl
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..64ece1ffd5cb36430da30437a1bd1e167611662c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,33 @@@
++GIT v1.6.0.6 Release Notes
++==========================
++
++Fixes since 1.6.0.5
++-------------------
++
++ * "git fsck" had a deep recursion that wasted stack space.
++
++ * "git fast-export" and "git fast-import" choked on an old style
++   annotated tag that lack the tagger information.
++
++ * "git mergetool -- file" did not correctly skip "--" marker that
++   signals the end of options list.
++
++ * "git show $tag" segfaulted when an annotated $tag pointed at a
++   nonexistent object.
++
++ * "git show 2>error" when the standard output is automatically redirected
++   to the pager redirected the standard error to the pager as well; there
++   was no need to.
++
++ * "git send-email" did not correctly handle list of addresses when
++   they had quoted comma (e.g. "Lastname, Givenname" <mail@addre.ss>).
++
++ * Logic to discover branch ancestry in "git svn" was unreliable when
++   the process to fetch history was interrupted.
++
++ * Removed support for an obsolete gitweb request URI, whose
++   implementation ran "git diff" Porcelain, instead of using plumbing,
++   which would have run an external diff command specified in the
++   repository configuration as the gitweb user.
++
++Also contains numerous documentation typofixes.
diff --combined RelNotes
index ebf508f2d7ccb5b3c32dd298dfbfcd243a006947,6ca1d5b43948525e43c3c354dd424ab054772a95..009d8f0e27fec18b98d11d1fed6dab81cfd1d6f4
+++ b/RelNotes
@@@ -1,1 -1,1 +1,1 @@@
- Documentation/RelNotes-1.6.0.5.txt
 -Documentation/RelNotes-1.5.6.6.txt
++Documentation/RelNotes-1.6.0.6.txt
diff --combined gitweb/gitweb.perl
index ced7bb740f45858671d6b9fdb83fd13f15d18c1d,f88ce35ce8542e271a737335a116684429de2127..804670c2c6288f586c3e1860d2a87995b822b91f
@@@ -27,13 -27,6 +27,13 @@@ our $version = "++GIT_VERSION++"
  our $my_url = $cgi->url();
  our $my_uri = $cgi->url(-absolute => 1);
  
 +# if we're called with PATH_INFO, we have to strip that
 +# from the URL to find our real URL
 +if (my $path_info = $ENV{"PATH_INFO"}) {
 +      $my_url =~ s,\Q$path_info\E$,,;
 +      $my_uri =~ s,\Q$path_info\E$,,;
 +}
 +
  # core git executable to use
  # this can just be "git" if your webserver has a sensible PATH
  our $GIT = "++GIT_BINDIR++/git";
@@@ -232,7 -225,6 +232,7 @@@ our %feature = 
        # $feature{'grep'}{'override'} = 1;
        # and in project config gitweb.grep = 0|1;
        'grep' => {
 +              'sub' => \&feature_grep,
                'override' => 0,
                'default' => [1]},
  
@@@ -394,7 -386,7 +394,7 @@@ $projects_list ||= $projectroot
  our $action = $cgi->param('a');
  if (defined $action) {
        if ($action =~ m/[^0-9a-zA-Z\.\-_]/) {
 -              die_error(undef, "Invalid action parameter");
 +              die_error(400, "Invalid action parameter");
        }
  }
  
@@@ -407,21 -399,21 +407,21 @@@ if (defined $project) 
            ($export_ok && !(-e "$projectroot/$project/$export_ok")) ||
            ($strict_export && !project_in_list($project))) {
                undef $project;
 -              die_error(undef, "No such project");
 +              die_error(404, "No such project");
        }
  }
  
  our $file_name = $cgi->param('f');
  if (defined $file_name) {
        if (!validate_pathname($file_name)) {
 -              die_error(undef, "Invalid file parameter");
 +              die_error(400, "Invalid file parameter");
        }
  }
  
  our $file_parent = $cgi->param('fp');
  if (defined $file_parent) {
        if (!validate_pathname($file_parent)) {
 -              die_error(undef, "Invalid file parent parameter");
 +              die_error(400, "Invalid file parent parameter");
        }
  }
  
  our $hash = $cgi->param('h');
  if (defined $hash) {
        if (!validate_refname($hash)) {
 -              die_error(undef, "Invalid hash parameter");
 +              die_error(400, "Invalid hash parameter");
        }
  }
  
  our $hash_parent = $cgi->param('hp');
  if (defined $hash_parent) {
        if (!validate_refname($hash_parent)) {
 -              die_error(undef, "Invalid hash parent parameter");
 +              die_error(400, "Invalid hash parent parameter");
        }
  }
  
  our $hash_base = $cgi->param('hb');
  if (defined $hash_base) {
        if (!validate_refname($hash_base)) {
 -              die_error(undef, "Invalid hash base parameter");
 +              die_error(400, "Invalid hash base parameter");
        }
  }
  
@@@ -455,10 -447,10 +455,10 @@@ our @extra_options = $cgi->param('opt')
  if (defined @extra_options) {
        foreach my $opt (@extra_options) {
                if (not exists $allowed_options{$opt}) {
 -                      die_error(undef, "Invalid option parameter");
 +                      die_error(400, "Invalid option parameter");
                }
                if (not grep(/^$action$/, @{$allowed_options{$opt}})) {
 -                      die_error(undef, "Invalid option parameter for this action");
 +                      die_error(400, "Invalid option parameter for this action");
                }
        }
  }
  our $hash_parent_base = $cgi->param('hpb');
  if (defined $hash_parent_base) {
        if (!validate_refname($hash_parent_base)) {
 -              die_error(undef, "Invalid hash parent base parameter");
 +              die_error(400, "Invalid hash parent base parameter");
        }
  }
  
  our $page = $cgi->param('pg');
  if (defined $page) {
        if ($page =~ m/[^0-9]/) {
 -              die_error(undef, "Invalid page parameter");
 +              die_error(400, "Invalid page parameter");
        }
  }
  
  our $searchtype = $cgi->param('st');
  if (defined $searchtype) {
        if ($searchtype =~ m/[^a-z]/) {
 -              die_error(undef, "Invalid searchtype parameter");
 +              die_error(400, "Invalid searchtype parameter");
        }
  }
  
@@@ -491,7 -483,7 +491,7 @@@ our $searchtext = $cgi->param('s')
  our $search_regexp;
  if (defined $searchtext) {
        if (length($searchtext) < 2) {
 -              die_error(undef, "At least two characters are required for search parameter");
 +              die_error(403, "At least two characters are required for search parameter");
        }
        $search_regexp = $search_use_regexp ? $searchtext : quotemeta $searchtext;
  }
@@@ -547,7 -539,7 +547,7 @@@ $git_dir = "$projectroot/$project" if $
  
  # dispatch
  my %actions = (
 -      "blame" => \&git_blame2,
 +      "blame" => \&git_blame,
        "blobdiff" => \&git_blobdiff,
        "blobdiff_plain" => \&git_blobdiff_plain,
        "blob" => \&git_blob,
@@@ -588,11 -580,11 +588,11 @@@ if (!defined $action) 
        }
  }
  if (!defined($actions{$action})) {
 -      die_error(undef, "Unknown action");
 +      die_error(400, "Unknown action");
  }
  if ($action !~ m/^(opml|project_list|project_index)$/ &&
      !$project) {
 -      die_error(undef, "Project needed");
 +      die_error(400, "Project needed");
  }
  $actions{$action}->();
  exit;
@@@ -1673,7 -1665,7 +1673,7 @@@ sub git_get_hash_by_path 
        $path =~ s,/+$,,;
  
        open my $fd, "-|", git_cmd(), "ls-tree", $base, "--", $path
 -              or die_error(undef, "Open git-ls-tree failed");
 +              or die_error(500, "Open git-ls-tree failed");
        my $line = <$fd>;
        close $fd or return undef;
  
@@@ -2100,7 -2092,7 +2100,7 @@@ sub parse_commit_text 
                        last;
                }
        }
 -      if ($co{'title'} eq "") {
 +      if (! defined $co{'title'} || $co{'title'} eq "") {
                $co{'title'} = $co{'title_short'} = '(no commit message)';
        }
        # remove added spaces
@@@ -2135,7 -2127,7 +2135,7 @@@ sub parse_commit 
                "--max-count=1",
                $commit_id,
                "--",
 -              or die_error(undef, "Open git-rev-list failed");
 +              or die_error(500, "Open git-rev-list failed");
        %co = parse_commit_text(<$fd>, 1);
        close $fd;
  
@@@ -2160,7 -2152,7 +2160,7 @@@ sub parse_commits 
                $commit_id,
                "--",
                ($filename ? ($filename) : ())
 -              or die_error(undef, "Open git-rev-list failed");
 +              or die_error(500, "Open git-rev-list failed");
        while (my $line = <$fd>) {
                my %co = parse_commit_text($line);
                push @cos, \%co;
@@@ -2680,26 -2672,11 +2680,26 @@@ sub git_footer_html 
              "</html>";
  }
  
 +# die_error(<http_status_code>, <error_message>)
 +# Example: die_error(404, 'Hash not found')
 +# By convention, use the following status codes (as defined in RFC 2616):
 +# 400: Invalid or missing CGI parameters, or
 +#      requested object exists but has wrong type.
 +# 403: Requested feature (like "pickaxe" or "snapshot") not enabled on
 +#      this server or project.
 +# 404: Requested object/revision/project doesn't exist.
 +# 500: The server isn't configured properly, or
 +#      an internal error occurred (e.g. failed assertions caused by bugs), or
 +#      an unknown error occurred (e.g. the git binary died unexpectedly).
  sub die_error {
 -      my $status = shift || "403 Forbidden";
 -      my $error = shift || "Malformed query, file missing or permission denied";
 -
 -      git_header_html($status);
 +      my $status = shift || 500;
 +      my $error = shift || "Internal server error";
 +
 +      my %http_responses = (400 => '400 Bad Request',
 +                            403 => '403 Forbidden',
 +                            404 => '404 Not Found',
 +                            500 => '500 Internal Server Error');
 +      git_header_html($http_responses{$status});
        print <<EOF;
  <div class="page_body">
  <br /><br />
@@@ -3543,24 -3520,21 +3543,24 @@@ sub git_patchset_body 
  
  # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  
 -sub git_project_list_body {
 -      my ($projlist, $order, $from, $to, $extra, $no_header) = @_;
 -
 -      my ($check_forks) = gitweb_check_feature('forks');
 -
 +# fills project list info (age, description, owner, forks) for each
 +# project in the list, removing invalid projects from returned list
 +# NOTE: modifies $projlist, but does not remove entries from it
 +sub fill_project_list_info {
 +      my ($projlist, $check_forks) = @_;
        my @projects;
 +
 + PROJECT:
        foreach my $pr (@$projlist) {
 -              my (@aa) = git_get_last_activity($pr->{'path'});
 -              unless (@aa) {
 -                      next;
 +              my (@activity) = git_get_last_activity($pr->{'path'});
 +              unless (@activity) {
 +                      next PROJECT;
                }
 -              ($pr->{'age'}, $pr->{'age_string'}) = @aa;
 +              ($pr->{'age'}, $pr->{'age_string'}) = @activity;
                if (!defined $pr->{'descr'}) {
                        my $descr = git_get_project_description($pr->{'path'}) || "";
 -                      $pr->{'descr_long'} = to_utf8($descr);
 +                      $descr = to_utf8($descr);
 +                      $pr->{'descr_long'} = $descr;
                        $pr->{'descr'} = chop_str($descr, $projects_list_description_width, 5);
                }
                if (!defined $pr->{'owner'}) {
                            ($pname !~ /\/$/) &&
                            (-d "$projectroot/$pname")) {
                                $pr->{'forks'} = "-d $projectroot/$pname";
 -                      }
 -                      else {
 +                      }       else {
                                $pr->{'forks'} = 0;
                        }
                }
                push @projects, $pr;
        }
  
 +      return @projects;
 +}
 +
 +# print 'sort by' <th> element, either sorting by $key if $name eq $order
 +# (changing $list), or generating 'sort by $name' replay link otherwise
 +sub print_sort_th {
 +      my ($str_sort, $name, $order, $key, $header, $list) = @_;
 +      $key    ||= $name;
 +      $header ||= ucfirst($name);
 +
 +      if ($order eq $name) {
 +              if ($str_sort) {
 +                      @$list = sort {$a->{$key} cmp $b->{$key}} @$list;
 +              } else {
 +                      @$list = sort {$a->{$key} <=> $b->{$key}} @$list;
 +              }
 +              print "<th>$header</th>\n";
 +      } else {
 +              print "<th>" .
 +                    $cgi->a({-href => href(-replay=>1, order=>$name),
 +                             -class => "header"}, $header) .
 +                    "</th>\n";
 +      }
 +}
 +
 +sub print_sort_th_str {
 +      print_sort_th(1, @_);
 +}
 +
 +sub print_sort_th_num {
 +      print_sort_th(0, @_);
 +}
 +
 +sub git_project_list_body {
 +      my ($projlist, $order, $from, $to, $extra, $no_header) = @_;
 +
 +      my ($check_forks) = gitweb_check_feature('forks');
 +      my @projects = fill_project_list_info($projlist, $check_forks);
 +
        $order ||= $default_projects_order;
        $from = 0 unless defined $from;
        $to = $#projects if (!defined $to || $#projects < $to);
                if ($check_forks) {
                        print "<th></th>\n";
                }
 -              if ($order eq "project") {
 -                      @projects = sort {$a->{'path'} cmp $b->{'path'}} @projects;
 -                      print "<th>Project</th>\n";
 -              } else {
 -                      print "<th>" .
 -                            $cgi->a({-href => href(project=>undef, order=>'project'),
 -                                     -class => "header"}, "Project") .
 -                            "</th>\n";
 -              }
 -              if ($order eq "descr") {
 -                      @projects = sort {$a->{'descr'} cmp $b->{'descr'}} @projects;
 -                      print "<th>Description</th>\n";
 -              } else {
 -                      print "<th>" .
 -                            $cgi->a({-href => href(project=>undef, order=>'descr'),
 -                                     -class => "header"}, "Description") .
 -                            "</th>\n";
 -              }
 -              if ($order eq "owner") {
 -                      @projects = sort {$a->{'owner'} cmp $b->{'owner'}} @projects;
 -                      print "<th>Owner</th>\n";
 -              } else {
 -                      print "<th>" .
 -                            $cgi->a({-href => href(project=>undef, order=>'owner'),
 -                                     -class => "header"}, "Owner") .
 -                            "</th>\n";
 -              }
 -              if ($order eq "age") {
 -                      @projects = sort {$a->{'age'} <=> $b->{'age'}} @projects;
 -                      print "<th>Last Change</th>\n";
 -              } else {
 -                      print "<th>" .
 -                            $cgi->a({-href => href(project=>undef, order=>'age'),
 -                                     -class => "header"}, "Last Change") .
 -                            "</th>\n";
 -              }
 -              print "<th></th>\n" .
 +              print_sort_th_str('project', $order, 'path',
 +                                'Project', \@projects);
 +              print_sort_th_str('descr', $order, 'descr_long',
 +                                'Description', \@projects);
 +              print_sort_th_str('owner', $order, 'owner',
 +                                'Owner', \@projects);
 +              print_sort_th_num('age', $order, 'age',
 +                                'Last Change', \@projects);
 +              print "<th></th>\n" . # for links
                      "</tr>\n";
        }
        my $alternate = 1;
@@@ -3960,12 -3924,12 +3960,12 @@@ sub git_search_grep_body 
  sub git_project_list {
        my $order = $cgi->param('o');
        if (defined $order && $order !~ m/none|project|descr|owner|age/) {
 -              die_error(undef, "Unknown order parameter");
 +              die_error(400, "Unknown order parameter");
        }
  
        my @list = git_get_projects_list();
        if (!@list) {
 -              die_error(undef, "No projects found");
 +              die_error(404, "No projects found");
        }
  
        git_header_html();
  sub git_forks {
        my $order = $cgi->param('o');
        if (defined $order && $order !~ m/none|project|descr|owner|age/) {
 -              die_error(undef, "Unknown order parameter");
 +              die_error(400, "Unknown order parameter");
        }
  
        my @list = git_get_projects_list($project);
        if (!@list) {
 -              die_error(undef, "No forks found");
 +              die_error(404, "No forks found");
        }
  
        git_header_html();
@@@ -4117,7 -4081,7 +4117,7 @@@ sub git_tag 
        my %tag = parse_tag($hash);
  
        if (! %tag) {
 -              die_error(undef, "Unknown tag object");
 +              die_error(404, "Unknown tag object");
        }
  
        git_print_header_div('commit', esc_html($tag{'name'}), $hash);
        git_footer_html();
  }
  
 -sub git_blame2 {
 +sub git_blame {
        my $fd;
        my $ftype;
  
 -      my ($have_blame) = gitweb_check_feature('blame');
 -      if (!$have_blame) {
 -              die_error('403 Permission denied', "Permission denied");
 -      }
 -      die_error('404 Not Found', "File name not defined") if (!$file_name);
 +      gitweb_check_feature('blame')
 +          or die_error(403, "Blame view not allowed");
 +
 +      die_error(400, "No file name given") unless $file_name;
        $hash_base ||= git_get_head_hash($project);
 -      die_error(undef, "Couldn't find base commit") unless ($hash_base);
 +      die_error(404, "Couldn't find base commit") unless ($hash_base);
        my %co = parse_commit($hash_base)
 -              or die_error(undef, "Reading commit failed");
 +              or die_error(404, "Commit not found");
        if (!defined $hash) {
                $hash = git_get_hash_by_path($hash_base, $file_name, "blob")
 -                      or die_error(undef, "Error looking up file");
 +                      or die_error(404, "Error looking up file");
        }
        $ftype = git_get_type($hash);
        if ($ftype !~ "blob") {
 -              die_error('400 Bad Request', "Object is not a blob");
 +              die_error(400, "Object is not a blob");
        }
        open ($fd, "-|", git_cmd(), "blame", '-p', '--',
              $file_name, $hash_base)
 -              or die_error(undef, "Open git-blame failed");
 +              or die_error(500, "Open git-blame failed");
        git_header_html();
        my $formats_nav =
                $cgi->a({-href => href(action=>"blob", -replay=>1)},
@@@ -4233,7 -4198,7 +4233,7 @@@ HTM
                        print "</td>\n";
                }
                open (my $dd, "-|", git_cmd(), "rev-parse", "$full_rev^")
 -                      or die_error(undef, "Open git-rev-parse failed");
 +                      or die_error(500, "Open git-rev-parse failed");
                my $parent_commit = <$dd>;
                close $dd;
                chomp($parent_commit);
        git_footer_html();
  }
  
 -sub git_blame {
 -      my $fd;
 -
 -      my ($have_blame) = gitweb_check_feature('blame');
 -      if (!$have_blame) {
 -              die_error('403 Permission denied', "Permission denied");
 -      }
 -      die_error('404 Not Found', "File name not defined") if (!$file_name);
 -      $hash_base ||= git_get_head_hash($project);
 -      die_error(undef, "Couldn't find base commit") unless ($hash_base);
 -      my %co = parse_commit($hash_base)
 -              or die_error(undef, "Reading commit failed");
 -      if (!defined $hash) {
 -              $hash = git_get_hash_by_path($hash_base, $file_name, "blob")
 -                      or die_error(undef, "Error lookup file");
 -      }
 -      open ($fd, "-|", git_cmd(), "annotate", '-l', '-t', '-r', $file_name, $hash_base)
 -              or die_error(undef, "Open git-annotate failed");
 -      git_header_html();
 -      my $formats_nav =
 -              $cgi->a({-href => href(action=>"blob", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)},
 -                      "blob") .
 -              " | " .
 -              $cgi->a({-href => href(action=>"history", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)},
 -                      "history") .
 -              " | " .
 -              $cgi->a({-href => href(action=>"blame", file_name=>$file_name)},
 -                      "HEAD");
 -      git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);
 -      git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
 -      git_print_page_path($file_name, 'blob', $hash_base);
 -      print "<div class=\"page_body\">\n";
 -      print <<HTML;
 -<table class="blame">
 -  <tr>
 -    <th>Commit</th>
 -    <th>Age</th>
 -    <th>Author</th>
 -    <th>Line</th>
 -    <th>Data</th>
 -  </tr>
 -HTML
 -      my @line_class = (qw(light dark));
 -      my $line_class_len = scalar (@line_class);
 -      my $line_class_num = $#line_class;
 -      while (my $line = <$fd>) {
 -              my $long_rev;
 -              my $short_rev;
 -              my $author;
 -              my $time;
 -              my $lineno;
 -              my $data;
 -              my $age;
 -              my $age_str;
 -              my $age_class;
 -
 -              chomp $line;
 -              $line_class_num = ($line_class_num + 1) % $line_class_len;
 -
 -              if ($line =~ m/^([0-9a-fA-F]{40})\t\(\s*([^\t]+)\t(\d+) [+-]\d\d\d\d\t(\d+)\)(.*)$/) {
 -                      $long_rev = $1;
 -                      $author   = $2;
 -                      $time     = $3;
 -                      $lineno   = $4;
 -                      $data     = $5;
 -              } else {
 -                      print qq(  <tr><td colspan="5" class="error">Unable to parse: $line</td></tr>\n);
 -                      next;
 -              }
 -              $short_rev  = substr ($long_rev, 0, 8);
 -              $age        = time () - $time;
 -              $age_str    = age_string ($age);
 -              $age_str    =~ s/ /&nbsp;/g;
 -              $age_class  = age_class($age);
 -              $author     = esc_html ($author);
 -              $author     =~ s/ /&nbsp;/g;
 -
 -              $data = untabify($data);
 -              $data = esc_html ($data);
 -
 -              print <<HTML;
 -  <tr class="$line_class[$line_class_num]">
 -    <td class="sha1"><a href="${\href (action=>"commit", hash=>$long_rev)}" class="text">$short_rev..</a></td>
 -    <td class="$age_class">$age_str</td>
 -    <td>$author</td>
 -    <td class="linenr"><a id="$lineno" href="#$lineno" class="linenr">$lineno</a></td>
 -    <td class="pre">$data</td>
 -  </tr>
 -HTML
 -      } # while (my $line = <$fd>)
 -      print "</table>\n\n";
 -      close $fd
 -              or print "Reading blob failed.\n";
 -      print "</div>";
 -      git_footer_html();
 -}
 -
  sub git_tags {
        my $head = git_get_head_hash($project);
        git_header_html();
@@@ -4290,9 -4352,9 +4290,9 @@@ sub git_blob_plain 
                if (defined $file_name) {
                        my $base = $hash_base || git_get_head_hash($project);
                        $hash = git_get_hash_by_path($base, $file_name, "blob")
 -                              or die_error(undef, "Error lookup file");
 +                              or die_error(404, "Cannot find file");
                } else {
 -                      die_error(undef, "No file name defined");
 +                      die_error(400, "No file name defined");
                }
        } elsif ($hash =~ m/^[0-9a-fA-F]{40}$/) {
                # blobs defined by non-textual hash id's can be cached
        }
  
        open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
 -              or die_error(undef, "Open git-cat-file blob '$hash' failed");
 +              or die_error(500, "Open git-cat-file blob '$hash' failed");
  
        # content-type (can include charset)
        $type = blob_contenttype($fd, $file_name, $type);
@@@ -4332,9 -4394,9 +4332,9 @@@ sub git_blob 
                if (defined $file_name) {
                        my $base = $hash_base || git_get_head_hash($project);
                        $hash = git_get_hash_by_path($base, $file_name, "blob")
 -                              or die_error(undef, "Error lookup file");
 +                              or die_error(404, "Cannot find file");
                } else {
 -                      die_error(undef, "No file name defined");
 +                      die_error(400, "No file name defined");
                }
        } elsif ($hash =~ m/^[0-9a-fA-F]{40}$/) {
                # blobs defined by non-textual hash id's can be cached
  
        my ($have_blame) = gitweb_check_feature('blame');
        open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
 -              or die_error(undef, "Couldn't cat $file_name, $hash");
 +              or die_error(500, "Couldn't cat $file_name, $hash");
        my $mimetype = blob_mimetype($fd, $file_name);
        if ($mimetype !~ m!^(?:text/|image/(?:gif|png|jpeg)$)! && -B $fd) {
                close $fd;
@@@ -4422,12 -4484,11 +4422,12 @@@ sub git_tree 
                        $hash = $hash_base;
                }
        }
 +      die_error(404, "No such tree") unless defined($hash);
        $/ = "\0";
        open my $fd, "-|", git_cmd(), "ls-tree", '-z', $hash
 -              or die_error(undef, "Open git-ls-tree failed");
 +              or die_error(500, "Open git-ls-tree failed");
        my @entries = map { chomp; $_ } <$fd>;
 -      close $fd or die_error(undef, "Reading tree failed");
 +      close $fd or die_error(404, "Reading tree failed");
        $/ = "\n";
  
        my $refs = git_get_references();
                if ($basedir ne '' && substr($basedir, -1) ne '/') {
                        $basedir .= '/';
                }
 +              git_print_page_path($file_name, 'tree', $hash_base);
        }
 -      git_print_page_path($file_name, 'tree', $hash_base);
        print "<div class=\"page_body\">\n";
        print "<table class=\"tree\">\n";
        my $alternate = 1;
@@@ -4517,16 -4578,16 +4517,16 @@@ sub git_snapshot 
  
        my $format = $cgi->param('sf');
        if (!@supported_fmts) {
 -              die_error('403 Permission denied', "Permission denied");
 +              die_error(403, "Snapshots not allowed");
        }
        # default to first supported snapshot format
        $format ||= $supported_fmts[0];
        if ($format !~ m/^[a-z0-9]+$/) {
 -              die_error(undef, "Invalid snapshot format parameter");
 +              die_error(400, "Invalid snapshot format parameter");
        } elsif (!exists($known_snapshot_formats{$format})) {
 -              die_error(undef, "Unknown snapshot format");
 +              die_error(400, "Unknown snapshot format");
        } elsif (!grep($_ eq $format, @supported_fmts)) {
 -              die_error(undef, "Unsupported snapshot format");
 +              die_error(403, "Unsupported snapshot format");
        }
  
        if (!defined $hash) {
                -status => '200 OK');
  
        open my $fd, "-|", $cmd
 -              or die_error(undef, "Execute git-archive failed");
 +              or die_error(500, "Execute git-archive failed");
        binmode STDOUT, ':raw';
        print <$fd>;
        binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
@@@ -4622,8 -4683,10 +4622,8 @@@ sub git_log 
  
  sub git_commit {
        $hash ||= $hash_base || "HEAD";
 -      my %co = parse_commit($hash);
 -      if (!%co) {
 -              die_error(undef, "Unknown commit object");
 -      }
 +      my %co = parse_commit($hash)
 +          or die_error(404, "Unknown commit object");
        my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'});
        my %cd = parse_date($co{'committer_epoch'}, $co{'committer_tz'});
  
                @diff_opts,
                (@$parents <= 1 ? $parent : '-c'),
                $hash, "--"
 -              or die_error(undef, "Open git-diff-tree failed");
 +              or die_error(500, "Open git-diff-tree failed");
        @difftree = map { chomp; $_ } <$fd>;
 -      close $fd or die_error(undef, "Reading git-diff-tree failed");
 +      close $fd or die_error(404, "Reading git-diff-tree failed");
  
        # non-textual hash id's can be cached
        my $expires;
@@@ -4758,33 -4821,33 +4758,33 @@@ sub git_object 
  
                open my $fd, "-|", quote_command(
                        git_cmd(), 'cat-file', '-t', $object_id) . ' 2> /dev/null'
 -                      or die_error('404 Not Found', "Object does not exist");
 +                      or die_error(404, "Object does not exist");
                $type = <$fd>;
                chomp $type;
                close $fd
 -                      or die_error('404 Not Found', "Object does not exist");
 +                      or die_error(404, "Object does not exist");
  
        # - hash_base and file_name
        } elsif ($hash_base && defined $file_name) {
                $file_name =~ s,/+$,,;
  
                system(git_cmd(), "cat-file", '-e', $hash_base) == 0
 -                      or die_error('404 Not Found', "Base object does not exist");
 +                      or die_error(404, "Base object does not exist");
  
                # here errors should not hapen
                open my $fd, "-|", git_cmd(), "ls-tree", $hash_base, "--", $file_name
 -                      or die_error(undef, "Open git-ls-tree failed");
 +                      or die_error(500, "Open git-ls-tree failed");
                my $line = <$fd>;
                close $fd;
  
                #'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa  panic.c'
                unless ($line && $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t/) {
 -                      die_error('404 Not Found', "File or directory for given base does not exist");
 +                      die_error(404, "File or directory for given base does not exist");
                }
                $type = $2;
                $hash = $3;
        } else {
 -              die_error('404 Not Found', "Not enough information to find object");
 +              die_error(400, "Not enough information to find object");
        }
  
        print $cgi->redirect(-uri => href(action=>$type, -full=>1,
@@@ -4809,12 -4872,12 +4809,12 @@@ sub git_blobdiff 
                        open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
                                $hash_parent_base, $hash_base,
                                "--", (defined $file_parent ? $file_parent : ()), $file_name
 -                              or die_error(undef, "Open git-diff-tree failed");
 +                              or die_error(500, "Open git-diff-tree failed");
                        @difftree = map { chomp; $_ } <$fd>;
                        close $fd
 -                              or die_error(undef, "Reading git-diff-tree failed");
 +                              or die_error(404, "Reading git-diff-tree failed");
                        @difftree
 -                              or die_error('404 Not Found', "Blob diff not found");
 +                              or die_error(404, "Blob diff not found");
  
                } elsif (defined $hash &&
                         $hash =~ /[0-9a-fA-F]{40}/) {
                        # read filtered raw output
                        open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
                                $hash_parent_base, $hash_base, "--"
 -                              or die_error(undef, "Open git-diff-tree failed");
 +                              or die_error(500, "Open git-diff-tree failed");
                        @difftree =
                                # ':100644 100644 03b21826... 3b93d5e7... M     ls-files.c'
                                # $hash == to_id
                                grep { /^:[0-7]{6} [0-7]{6} [0-9a-fA-F]{40} $hash/ }
                                map { chomp; $_ } <$fd>;
                        close $fd
 -                              or die_error(undef, "Reading git-diff-tree failed");
 +                              or die_error(404, "Reading git-diff-tree failed");
                        @difftree
 -                              or die_error('404 Not Found', "Blob diff not found");
 +                              or die_error(404, "Blob diff not found");
  
                } else {
 -                      die_error('404 Not Found', "Missing one of the blob diff parameters");
 +                      die_error(400, "Missing one of the blob diff parameters");
                }
  
                if (@difftree > 1) {
 -                      die_error('404 Not Found', "Ambiguous blob diff specification");
 +                      die_error(400, "Ambiguous blob diff specification");
                }
  
                %diffinfo = parse_difftree_raw_line($difftree[0]);
                        '-p', ($format eq 'html' ? "--full-index" : ()),
                        $hash_parent_base, $hash_base,
                        "--", (defined $file_parent ? $file_parent : ()), $file_name
 -                      or die_error(undef, "Open git-diff-tree failed");
 +                      or die_error(500, "Open git-diff-tree failed");
        }
  
-       # old/legacy style URI
-       if (!%diffinfo && # if new style URI failed
-           defined $hash && defined $hash_parent) {
-               # fake git-diff-tree raw output
-               $diffinfo{'from_mode'} = $diffinfo{'to_mode'} = "blob";
-               $diffinfo{'from_id'} = $hash_parent;
-               $diffinfo{'to_id'}   = $hash;
-               if (defined $file_name) {
-                       if (defined $file_parent) {
-                               $diffinfo{'status'} = '2';
-                               $diffinfo{'from_file'} = $file_parent;
-                               $diffinfo{'to_file'}   = $file_name;
-                       } else { # assume not renamed
-                               $diffinfo{'status'} = '1';
-                               $diffinfo{'from_file'} = $file_name;
-                               $diffinfo{'to_file'}   = $file_name;
-                       }
-               } else { # no filename given
-                       $diffinfo{'status'} = '2';
-                       $diffinfo{'from_file'} = $hash_parent;
-                       $diffinfo{'to_file'}   = $hash;
-               }
-               # non-textual hash id's can be cached
-               if ($hash =~ m/^[0-9a-fA-F]{40}$/ &&
-                   $hash_parent =~ m/^[0-9a-fA-F]{40}$/) {
-                       $expires = '+1d';
-               }
-               # open patch output
-               open $fd, "-|", git_cmd(), "diff", @diff_opts,
-                       '-p', ($format eq 'html' ? "--full-index" : ()),
-                       $hash_parent, $hash, "--"
-                       or die_error(500, "Open git-diff failed");
-       } else  {
-               die_error(400, "Missing one of the blob diff parameters")
-                       unless %diffinfo;
+       # old/legacy style URI -- not generated anymore since 1.4.3.
+       if (!%diffinfo) {
+               die_error('404 Not Found', "Missing one of the blob diff parameters")
        }
  
        # header
                print "X-Git-Url: " . $cgi->self_url() . "\n\n";
  
        } else {
 -              die_error(undef, "Unknown blobdiff format");
 +              die_error(400, "Unknown blobdiff format");
        }
  
        # patch
@@@ -4966,8 -4995,10 +4932,8 @@@ sub git_blobdiff_plain 
  sub git_commitdiff {
        my $format = shift || 'html';
        $hash ||= $hash_base || "HEAD";
 -      my %co = parse_commit($hash);
 -      if (!%co) {
 -              die_error(undef, "Unknown commit object");
 -      }
 +      my %co = parse_commit($hash)
 +          or die_error(404, "Unknown commit object");
  
        # choose format for commitdiff for merge
        if (! defined $hash_parent && @{$co{'parents'}} > 1) {
                open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
                        "--no-commit-id", "--patch-with-raw", "--full-index",
                        $hash_parent_param, $hash, "--"
 -                      or die_error(undef, "Open git-diff-tree failed");
 +                      or die_error(500, "Open git-diff-tree failed");
  
                while (my $line = <$fd>) {
                        chomp $line;
        } elsif ($format eq 'plain') {
                open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
                        '-p', $hash_parent_param, $hash, "--"
 -                      or die_error(undef, "Open git-diff-tree failed");
 +                      or die_error(500, "Open git-diff-tree failed");
  
        } else {
 -              die_error(undef, "Unknown commitdiff format");
 +              die_error(400, "Unknown commitdiff format");
        }
  
        # non-textual hash id's can be cached
@@@ -5147,15 -5178,19 +5113,15 @@@ sub git_history 
                $page = 0;
        }
        my $ftype;
 -      my %co = parse_commit($hash_base);
 -      if (!%co) {
 -              die_error(undef, "Unknown commit object");
 -      }
 +      my %co = parse_commit($hash_base)
 +          or die_error(404, "Unknown commit object");
  
        my $refs = git_get_references();
        my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
  
        my @commitlist = parse_commits($hash_base, 101, (100 * $page),
 -                                     $file_name, "--full-history");
 -      if (!@commitlist) {
 -              die_error('404 Not Found', "No such file or directory on given branch");
 -      }
 +                                     $file_name, "--full-history")
 +          or die_error(404, "No such file or directory on given branch");
  
        if (!defined $hash && defined $file_name) {
                # some commits could have deleted file in question,
                $ftype = git_get_type($hash);
        }
        if (!defined $ftype) {
 -              die_error(undef, "Unknown type of object");
 +              die_error(500, "Unknown type of object");
        }
  
        my $paging_nav = '';
  }
  
  sub git_search {
 -      my ($have_search) = gitweb_check_feature('search');
 -      if (!$have_search) {
 -              die_error('403 Permission denied', "Permission denied");
 -      }
 +      gitweb_check_feature('search') or die_error(403, "Search is disabled");
        if (!defined $searchtext) {
 -              die_error(undef, "Text field empty");
 +              die_error(400, "Text field is empty");
        }
        if (!defined $hash) {
                $hash = git_get_head_hash($project);
        }
        my %co = parse_commit($hash);
        if (!%co) {
 -              die_error(undef, "Unknown commit object");
 +              die_error(404, "Unknown commit object");
        }
        if (!defined $page) {
                $page = 0;
        if ($searchtype eq 'pickaxe') {
                # pickaxe may take all resources of your box and run for several minutes
                # with every query - so decide by yourself how public you make this feature
 -              my ($have_pickaxe) = gitweb_check_feature('pickaxe');
 -              if (!$have_pickaxe) {
 -                      die_error('403 Permission denied', "Permission denied");
 -              }
 +              gitweb_check_feature('pickaxe')
 +                  or die_error(403, "Pickaxe is disabled");
        }
        if ($searchtype eq 'grep') {
 -              my ($have_grep) = gitweb_check_feature('grep');
 -              if (!$have_grep) {
 -                      die_error('403 Permission denied', "Permission denied");
 -              }
 +              gitweb_check_feature('grep')
 +                  or die_error(403, "Grep is disabled");
        }
  
        git_header_html();
@@@ -5505,7 -5547,7 +5471,7 @@@ sub git_feed 
        # Atom: http://www.atomenabled.org/developers/syndication/
        # RSS:  http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
        if ($format ne 'rss' && $format ne 'atom') {
 -              die_error(undef, "Unknown web feed format");
 +              die_error(400, "Unknown web feed format");
        }
  
        # log/feed of current (HEAD) branch, log of given branch, history of file/directory