X-Git-Url: https://git.ladys.computer/Gitweb/blobdiff_plain/a8363e741f482dca53bb58c878bc879d6dc41b81bc7e6a9115c0ee4a8d1b25f3..ba0da63ca128eb53c7c9f1265177c56eb23db890becadc99180263ce56d95a0b:/gitweb.perl diff --git a/gitweb.perl b/gitweb.perl index 8c30632..a4f13bb 100755 --- a/gitweb.perl +++ b/gitweb.perl @@ -212,19 +212,9 @@ if (defined $project) { } } +# We have to handle those containing any characters: our $file_name = $cgi->param('f'); -if (defined $file_name) { - if (!validate_input($file_name)) { - die_error(undef, "Invalid file parameter"); - } -} - our $file_parent = $cgi->param('fp'); -if (defined $file_parent) { - if (!validate_input($file_parent)) { - die_error(undef, "Invalid file parent parameter"); - } -} our $hash = $cgi->param('h'); if (defined $hash) { @@ -305,7 +295,7 @@ sub evaluate_path_info { $action ||= "blob_plain"; } $hash_base ||= validate_input($refname); - $file_name ||= validate_input($pathname); + $file_name ||= $pathname; } elsif (defined $refname) { # we got "project.git/branch" $action ||= "shortlog"; @@ -416,7 +406,7 @@ sub validate_input { # correct, but quoted slashes look too horrible in bookmarks sub esc_param { my $str = shift; - $str =~ s/([^A-Za-z0-9\-_.~();\/;?:@&=])/sprintf("%%%02X", ord($1))/eg; + $str =~ s/([^A-Za-z0-9\-_.~()\/:@])/sprintf("%%%02X", ord($1))/eg; $str =~ s/\+/%2B/g; $str =~ s/ /\+/g; return $str; @@ -627,7 +617,7 @@ sub format_subject_html { if (length($short) < length($long)) { return $cgi->a({-href => $href, -class => "list subject", - -title => $long}, + -title => decode("utf8", $long, Encode::FB_DEFAULT)}, esc_html($short) . $extra); } else { return $cgi->a({-href => $href, -class => "list subject"}, @@ -752,7 +742,7 @@ sub git_get_project_description { sub git_get_project_url_list { my $path = shift; - open my $fd, "$projectroot/$path/cloneurl" or return undef; + open my $fd, "$projectroot/$path/cloneurl" or return; my @git_project_url_list = map { chomp; $_ } <$fd>; close $fd; @@ -1282,7 +1272,7 @@ sub git_header_html { if (defined $action) { $title .= "/$action"; if (defined $file_name) { - $title .= " - $file_name"; + $title .= " - " . esc_html($file_name); if ($action eq "tree" && $file_name !~ m|/$|) { $title .= "/"; } @@ -1520,14 +1510,14 @@ sub git_print_page_path { print "
"; print $cgi->a({-href => href(action=>"tree", hash_base=>$hb), - -title => '/'}, '/'); - print " "; + -title => 'tree root'}, "[$project]"); + print " / "; foreach my $dir (@dirname) { $fullname .= ($fullname ? '/' : '') . $dir; print $cgi->a({-href => href(action=>"tree", file_name=>$fullname, hash_base=>$hb), - -title => $fullname}, esc_html($dir . '/')); - print " "; + -title => $fullname}, esc_html($dir)); + print " / "; } if (defined $type && $type eq 'blob') { print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name, @@ -1536,7 +1526,7 @@ sub git_print_page_path { } elsif (defined $type && $type eq 'tree') { print $cgi->a({-href => href(action=>"tree", file_name=>$file_name, hash_base=>$hb), - -title => $name}, esc_html($basename . '/')); + -title => $name}, esc_html($basename)); } else { print esc_html($basename); } @@ -1610,48 +1600,45 @@ sub git_print_tree_entry { my %base_key = (); $base_key{hash_base} = $hash_base if defined $hash_base; + # The format of a table row is: mode list link. Where mode is + # the mode of the entry, list is the name of the entry, an href, + # and link is the action links of the entry. + print "" . mode_str($t->{'mode'}) . "\n"; if ($t->{'type'} eq "blob") { print "" . - $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'}, - file_name=>"$basedir$t->{'name'}", %base_key), - -class => "list"}, esc_html($t->{'name'})) . - "\n" . - "" . - $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'}, - file_name=>"$basedir$t->{'name'}", %base_key)}, - "blob"); + $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'}, + file_name=>"$basedir$t->{'name'}", %base_key), + -class => "list"}, esc_html($t->{'name'})) . "\n"; + print ""; if ($have_blame) { - print " | " . - $cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'}, - file_name=>"$basedir$t->{'name'}", %base_key)}, - "blame"); + print $cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'}, + file_name=>"$basedir$t->{'name'}", %base_key)}, + "blame"); } if (defined $hash_base) { - print " | " . - $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, + if ($have_blame) { + print " | "; + } + print $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}")}, "history"); } print " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}")}, - "raw") . - "\n"; + "raw"); + print "\n"; } elsif ($t->{'type'} eq "tree") { - print "" . - $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'}, + print ""; + print $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}", %base_key)}, - esc_html($t->{'name'})) . - "\n" . - "" . - $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'}, - file_name=>"$basedir$t->{'name'}", %base_key)}, - "tree"); + esc_html($t->{'name'})); + print "\n"; + print ""; if (defined $hash_base) { - print " | " . - $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, + print $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, file_name=>"$basedir$t->{'name'}")}, "history"); } @@ -1975,9 +1962,6 @@ sub git_shortlog_body { # uses global variable $project my ($revlist, $from, $to, $refs, $extra) = @_; - my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); - my $have_snapshot = (defined $ctype && defined $suffix); - $from = 0 unless defined $from; $to = $#{$revlist} if (!defined $to || $#{$revlist} < $to); @@ -2003,10 +1987,8 @@ sub git_shortlog_body { print "\n" . "" . $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " . - $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff"); - if ($have_snapshot) { - print " | " . $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot"); - } + $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " . + $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree"); print "\n" . "\n"; } @@ -2168,7 +2150,8 @@ sub git_heads_body { "\n" . "" . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") . " | " . - $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log") . + $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log") . " | " . + $cgi->a({-href => href(action=>"tree", hash=>$tag{'name'}, hash_base=>$tag{'name'})}, "tree") . "\n" . ""; } @@ -2282,7 +2265,8 @@ sub git_project_list { "" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary")}, "summary") . " | " . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"shortlog")}, "shortlog") . " | " . - $cgi->a({-href => href(project=>$pr->{'path'}, action=>"log")}, "log") . + $cgi->a({-href => href(project=>$pr->{'path'}, action=>"log")}, "log") . " | " . + $cgi->a({-href => href(project=>$pr->{'path'}, action=>"tree")}, "tree") . "\n" . "\n"; } @@ -2433,15 +2417,18 @@ sub git_blame2 { if ($ftype !~ "blob") { die_error("400 Bad Request", "Object is not a blob"); } - open ($fd, "-|", git_cmd(), "blame", '-l', $file_name, $hash_base) + open ($fd, "-|", git_cmd(), "blame", '-l', '--', $file_name, $hash_base) or die_error(undef, "Open git-blame 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"); + "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, $ftype, $hash_base); @@ -2506,8 +2493,11 @@ sub git_blame { $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"); + "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); @@ -2681,16 +2671,20 @@ sub git_blob { " | "; } $formats_nav .= + $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, + hash=>$hash, file_name=>$file_name)}, + "history") . + " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$hash, file_name=>$file_name)}, - "plain") . + "raw") . " | " . $cgi->a({-href => href(action=>"blob", hash_base=>"HEAD", file_name=>$file_name)}, - "head"); + "HEAD"); } else { $formats_nav .= - $cgi->a({-href => href(action=>"blob_plain", hash=>$hash)}, "plain"); + $cgi->a({-href => href(action=>"blob_plain", hash=>$hash)}, "raw"); } git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); @@ -2716,6 +2710,9 @@ sub git_blob { } sub git_tree { + my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); + my $have_snapshot = (defined $ctype && defined $suffix); + if (!defined $hash) { $hash = git_get_head_hash($project); if (defined $file_name) { @@ -2739,7 +2736,23 @@ sub git_tree { my $base = ""; my ($have_blame) = gitweb_check_feature('blame'); if (defined $hash_base && (my %co = parse_commit($hash_base))) { - git_print_page_nav('tree','', $hash_base); + my @views_nav = (); + if (defined $file_name) { + push @views_nav, + $cgi->a({-href => href(action=>"history", hash_base=>$hash_base, + hash=>$hash, file_name=>$file_name)}, + "history"), + $cgi->a({-href => href(action=>"tree", + hash_base=>"HEAD", file_name=>$file_name)}, + "HEAD"), + } + if ($have_snapshot) { + # FIXME: Should be available when we have no hash base as well. + push @views_nav, + $cgi->a({-href => href(action=>"snapshot", hash=>$hash)}, + "snapshot"); + } + git_print_page_nav('tree','', $hash_base, undef, undef, join(' | ', @views_nav)); git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base); } else { undef $hash_base; @@ -2844,6 +2857,8 @@ sub git_log { $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " . $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . + " | " . + $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree") . "
\n" . "
\n" . "" . esc_html($co{'author_name'}) . " [$ad{'rfc2822'}]
\n" . @@ -2884,17 +2899,22 @@ sub git_commit { my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot'); my $have_snapshot = (defined $ctype && defined $suffix); - my $formats_nav = ''; + my @views_nav = (); if (defined $file_name && defined $co{'parent'}) { my $parent = $co{'parent'}; - $formats_nav .= + push @views_nav, $cgi->a({-href => href(action=>"blame", hash_parent=>$parent, file_name=>$file_name)}, "blame"); } + if (defined $co{'parent'}) { + push @views_nav, + $cgi->a({-href => href(action=>"shortlog", hash=>$hash)}, "shortlog"), + $cgi->a({-href => href(action=>"log", hash=>$hash)}, "log"); + } git_header_html(undef, $expires); git_print_page_nav('commit', defined $co{'parent'} ? '' : 'commitdiff', $hash, $co{'tree'}, $hash, - $formats_nav); + join (' | ', @views_nav)); if (defined $co{'parent'}) { git_print_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash); @@ -3073,7 +3093,7 @@ sub git_blobdiff { hash=>$hash, hash_parent=>$hash_parent, hash_base=>$hash_base, hash_parent_base=>$hash_parent_base, file_name=>$file_name, file_parent=>$file_parent)}, - "plain"); + "raw"); git_header_html(undef, $expires); if (defined $hash_base && (my %co = parse_commit($hash_base))) { git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); @@ -3093,7 +3113,7 @@ sub git_blobdiff { -type => 'text/plain', -charset => 'utf-8', -expires => $expires, - -content_disposition => qq(inline; filename="${file_name}.patch")); + -content_disposition => qq(inline; filename=") . quotemeta($file_name) . qq(.patch")); print "X-Git-Url: " . $cgi->self_url() . "\n\n"; @@ -3113,8 +3133,8 @@ sub git_blobdiff { } else { while (my $line = <$fd>) { - $line =~ s!a/($hash|$hash_parent)!a/$diffinfo{'from_file'}!g; - $line =~ s!b/($hash|$hash_parent)!b/$diffinfo{'to_file'}!g; + $line =~ s!a/($hash|$hash_parent)!'a/'.esc_html($diffinfo{'from_file'})!eg; + $line =~ s!b/($hash|$hash_parent)!'b/'.esc_html($diffinfo{'to_file'})!eg; print $line; @@ -3176,7 +3196,7 @@ sub git_commitdiff { my $formats_nav = $cgi->a({-href => href(action=>"commitdiff_plain", hash=>$hash, hash_parent=>$hash_parent)}, - "plain"); + "raw"); git_header_html(undef, $expires); git_print_page_nav('commitdiff','', $hash,$co{'tree'},$hash, $formats_nav); @@ -3543,7 +3563,7 @@ XML if (!($line =~ m/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/)) { next; } - my $file = validate_input(unquote($7)); + my $file = esc_html(unquote($7)); $file = decode("utf8", $file, Encode::FB_DEFAULT); print "$file
\n"; }