X-Git-Url: https://git.chrismorgan.info/gitweb/blobdiff_plain/eb1be1167778836f191cb5888a1348cf8f33f40f..997771613b0b40fa6b973e741773e564fd241534:/gitweb.cgi diff --git a/gitweb.cgi b/gitweb.cgi index 16e2e3c..28a64ea 100755 --- a/gitweb.cgi +++ b/gitweb.cgi @@ -519,18 +519,6 @@ our %feature = ( 'override' => 0, 'default' => [0]}, - # Enable and configure ability to change common timezone for dates - # in gitweb output via JavaScript. Enabled by default. - # Project specific override is not supported. - 'javascript-timezone' => { - 'override' => 0, - 'default' => [ - 'local', # default timezone: 'utc', 'local', or '(-|+)HHMM' format, - # or undef to turn off this feature - 'gitweb_tz', # name of cookie where to store selected timezone - 'datetime', # CSS class used to mark up dates for manipulation - ]}, - # Syntax highlighting support. This is based on Daniel Svensson's # and Sham Chukoury's work in gitweb-xmms2.git. # It requires the 'highlight' program present in $PATH, @@ -1874,7 +1862,7 @@ sub esc_html_hl_regions { $out .= esc_html(substr($str, $pos, $begin - $pos), %opts) if ($begin - $pos > 0); - $out .= $cgi->span({-class => $css_class}, $escaped); + $out .= "$escaped"; $pos = $end; } @@ -1904,7 +1892,7 @@ sub esc_html_match_hl { my @matches = matchpos_list($str, $regexp); return esc_html($str) unless @matches; - return esc_html_hl_regions($str, 'match', @matches); + return esc_html_hl_regions($str, undef, @matches); } @@ -1936,7 +1924,7 @@ sub esc_html_match_hl_chopped { push @filtered, $m; } - return esc_html_hl_regions($chopped . $tail, 'match', @filtered); + return esc_html_hl_regions($chopped . $tail, undef, @filtered); } ## ---------------------------------------------------------------------- @@ -3044,7 +3032,7 @@ sub git_populate_project_tagcloud { $title =~ s/^/ /g; $title =~ s/$/ /g; if (defined $matched && $matched eq $ctag) { - $title = qq($title); + $title = qq($title); } $cloud->add($title, href(project=>undef, ctag=>$ctag), $ctags_lc{$ctag}->{count}); @@ -3054,7 +3042,7 @@ sub git_populate_project_tagcloud { foreach my $ctag (keys %ctags_lc) { my $title = esc_html($ctags_lc{$ctag}->{topname}, -nbsp=>1); if (defined $matched && $matched eq $ctag) { - $title = qq($title); + $title = qq($title); } $cloud->{$ctag}{count} = $ctags_lc{$ctag}->{count}; $cloud->{$ctag}{ctag} = @@ -3594,12 +3582,13 @@ sub parse_commit_text { $co{'age'} = $age; $co{'age_string'} = age_string($age); my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday) = gmtime($co{'committer_epoch'}); + $co{'age_string_iso8601'} = sprintf "%4i-%02u-%02i %02u:%02u:%02uZ", 1900 + $year, $mon+1, $mday, $hour, $min, $sec; if ($age > 60*60*24*7*2) { $co{'age_string_date'} = sprintf "%4i-%02u-%02i", 1900 + $year, $mon+1, $mday; - $co{'age_string_age'} = $co{'age_string'}; + $co{'age_string_age'} = "$co{'age_string_iso8601'} ($co{'age_string'})"; } else { $co{'age_string_date'} = $co{'age_string'}; - $co{'age_string_age'} = sprintf "%4i-%02u-%02i", 1900 + $year, $mon+1, $mday; + $co{'age_string_age'} = $co{'age_string_iso8601'}; } return %co; } @@ -4026,40 +4015,36 @@ sub run_highlighter { ## functions printing HTML: header, footer, error page sub get_page_title { - my $title = to_utf8($site_name); - + # Formats: + # SITE_NAME + # SITE_NAME - projects in FILTER + # PROJECT - SITE_NAME + # PROJECT ACTION - SITE_NAME + # FILENAME - PROJECT ACTION - SITE_NAME + my $title; unless (defined $project) { + $title = to_utf8($site_name); if (defined $project_filter) { $title .= " - projects in '" . esc_path($project_filter) . "'"; } return $title; } - $title .= " - " . to_utf8($project); - - return $title unless (defined $action); - $title .= "/$action"; # $action is US-ASCII (7bit ASCII) + $title = to_utf8($project); - return $title unless (defined $file_name); - $title .= " - " . esc_path($file_name); - if ($action eq "tree" && $file_name !~ m|/$|) { - $title .= "/"; + if (defined $action) { + $title .= " $action"; # $action is US-ASCII (7bit ASCII) + if (defined $file_name) { + $title = " - " . $title; + if ($action eq "tree" && $file_name !~ m|/$|) { + $title = "/" . $title; + } + $title = esc_path($file_name) . $title; + } } - return $title; -} + $title .= " - " . to_utf8($site_name); -sub get_content_type_html { - # require explicit support from the UA if we are to send the page as - # 'application/xhtml+xml', otherwise send it as plain old 'text/html'. - # we have to do this because MSIE sometimes globs '*/*', pretending to - # support xhtml+xml but choking when it gets what it asked for. - if (defined $cgi->http('HTTP_ACCEPT') && - $cgi->http('HTTP_ACCEPT') =~ m/(,|;|\s|^)application\/xhtml\+xml(,|;|\s|$)/ && - $cgi->Accept('application/xhtml+xml') != 0) { - return 'application/xhtml+xml'; - } else { - return 'text/html'; - } + return $title; } sub print_feed_meta { @@ -4101,11 +4086,11 @@ sub print_feed_meta { } else { printf(''."\n", - esc_attr($site_name), + esc_attr(to_utf8($site_name)), esc_attr(href(project=>undef, action=>"project_index"))); printf(''."\n", - esc_attr($site_name), + esc_attr(to_utf8($site_name)), esc_attr(href(project=>undef, action=>"opml"))); } } @@ -4116,17 +4101,17 @@ sub print_header_links { # print out each stylesheet that exist, providing backwards capability # for those people who defined $stylesheet in a config file if (defined $stylesheet) { - print ''."\n"; + print ''."\n"; } else { foreach my $stylesheet (@stylesheets) { next unless $stylesheet; - print ''."\n"; + print ''."\n"; } } print_feed_meta() if ($status eq '200 OK'); if (defined $favicon) { - print qq(\n); + print qq(\n); } } @@ -4187,8 +4172,7 @@ sub print_search_form { if ($use_pathinfo) { $action .= "/".esc_url($project); } - print $cgi->start_form(-method => "get", -action => $action) . - "
\n" . + print $cgi->start_form(-method => "get", -action => $action, -role => "search") . (!$use_pathinfo && $cgi->input({-name=>"p", -value=>$project, -type=>"hidden"}) . "\n") . $cgi->input({-name=>"a", -value=>"search", -type=>"hidden"}) . "\n" . @@ -4202,7 +4186,6 @@ sub print_search_form { $cgi->checkbox(-name => 'sr', -value => 1, -label => 're', -checked => $search_use_regexp) . "" . - "
" . $cgi->end_form() . "\n"; } @@ -4212,27 +4195,25 @@ sub git_header_html { my %opts = @_; my $title = get_page_title(); - my $content_type = get_content_type_html(); - print $cgi->header(-type=>$content_type, -charset => 'utf-8', + # I wanted to switch to text/html, but it uses nested in a couple of places (e.g. log refs are links inside the commit summary link), which is invalid but works in the XML syntax. Pity. + # (Various other invalid HTML is produced that HTML would have fixed but XHTML allows to be broken, like table > tr, lacking tbody.) + # TODO: reduce the doctype to , but that takes replacing entities like ⋅ with ⋅. + print $cgi->header(-type => 'application/xhtml+xml', -charset => 'utf-8', -status=> $status, -expires => $expires) unless ($opts{'-no_http_header'}); - my $mod_perl_version = $ENV{'MOD_PERL'} ? " $ENV{'MOD_PERL'}" : ''; print < - - - + - - + $title EOF # the stylesheet, favicon etc urls won't work correctly with path_info # unless we set the appropriate base URL if ($ENV{'PATH_INFO'}) { - print "\n"; + print "\n"; } print_header_links($status); @@ -4240,14 +4221,11 @@ EOF print to_utf8($site_html_head_string); } - print "\n" . - "\n"; - if (defined $site_header && -f $site_header) { insert_file($site_header); } - print "
\n"; + print "\n\n
\n"; if (defined $logo) { print $cgi->a({-href => esc_url($logo_url), -title => $logo_label}, @@ -4257,18 +4235,23 @@ EOF -class => "logo"})); } print_nav_breadcrumbs(%opts); - print "
\n"; + print "\n"; + + print "\n"; } sub git_footer_html { my $feed_class = 'rss_logo'; - print "
\n"; + print "
\n"; if (defined $project) { my $descr = git_get_project_description($project); if (defined $descr) { @@ -4296,7 +4279,7 @@ sub git_footer_html { project_filter => $project_filter), -class => $feed_class}, "TXT") . "\n"; } - print "
\n"; # class="page_footer" + print "\n"; # class="page_footer" if (defined $t0 && gitweb_check_feature('timed')) { print "
\n"; @@ -4309,35 +4292,31 @@ sub git_footer_html { $number_of_git_cmds. ' git commands '. " to generate.\n"; - print "
\n"; # class="page_footer" + print "\n"; } if (defined $site_footer && -f $site_footer) { insert_file($site_footer); } - print qq!\n!; if (defined $action && $action eq 'blame_incremental') { - print qq!\n!; + print qq!\n!; } else { - my ($jstimezone, $tz_cookie, $datetime_class) = - gitweb_get_feature('javascript-timezone'); - - print qq!\n!; + print qq!\n!; } - print qq!};\n!. - qq!\n!; } print "\n" . @@ -4371,6 +4350,7 @@ sub die_error { 503 => '503 Service Unavailable', ); git_header_html($http_responses{$status}, undef, %opts); + git_end_subhead_html(); print <

@@ -4393,7 +4373,6 @@ EOF sub git_print_page_nav { my ($current, $suppress, $head, $treehead, $treebase, $extra) = @_; - $extra = '' if !defined $extra; # pager or formats my @navs = qw(summary shortlog log commit commitdiff tree); if ($suppress) { @@ -4435,10 +4414,11 @@ sub git_print_page_nav { print "
\n" . (join " | ", map { $_ eq $current ? - $_ : $cgi->a({-href => ($arg{$_}{_href} ? $arg{$_}{_href} : href(%{$arg{$_}}))}, "$_") + $cgi->span({-class => "current"}, $_) : $cgi->a({-href => ($arg{$_}{_href} ? $arg{$_}{_href} : href(%{$arg{$_}}))}, "$_") } @navs); - print "
\n$extra
\n" . - "
\n"; + print "
\n$extra" if defined $extra; # pager or formats + print "\n"; + git_end_subhead_html(); } # returns a submenu for the navigation of the refs views (tags, heads, @@ -4499,7 +4479,7 @@ sub git_print_header_div { sub format_repo_url { my ($name, $url) = @_; - return "$name$url\n"; + return "$name$url\n"; } # Group output by placing it in a DIV element and adding a header. @@ -4542,23 +4522,8 @@ sub git_print_section { sub format_timestamp_html { my $date = shift; - my $strtime = $date->{'rfc2822'}; - - my (undef, undef, $datetime_class) = - gitweb_get_feature('javascript-timezone'); - if ($datetime_class) { - $strtime = qq!$strtime!; - } - my $localtime_format = '(%02d:%02d %s)'; - if ($date->{'hour_local'} < 6) { - $localtime_format = '(%02d:%02d %s)'; - } - $strtime .= ' ' . - sprintf($localtime_format, - $date->{'hour_local'}, $date->{'minute_local'}, $date->{'tz_local'}); - - return $strtime; + return qq!!; } # Outputs the author name and date in long form @@ -4588,7 +4553,7 @@ sub git_print_authorship_rows { @people = ('author', 'committer') unless @people; foreach my $who (@people) { my %wd = parse_date($co->{"${who}_epoch"}, $co->{"${who}_tz"}); - print "$who" . + print "$who" . format_search_author($co->{"${who}_name"}, $who, esc_html($co->{"${who}_name"})) . " " . format_search_author($co->{"${who}_email"}, $who, @@ -4687,11 +4652,6 @@ sub git_print_log { print format_log_line_html($line) . "
\n"; } - - if ($opts{'-final_empty_line'}) { - # end with single empty line - print "
\n" unless $skip_blank_line; - } } # return link target (what link points to) @@ -4888,11 +4848,11 @@ sub git_difftree_body { my ($difftree, $hash, @parents) = @_; my ($parent) = $parents[0]; my $have_blame = gitweb_check_feature('blame'); - print "
\n"; if ($#{$difftree} > 10) { + print "
\n"; print(($#{$difftree} + 1) . " files changed:\n"); + print "
\n"; } - print "
\n"; print " 1 ? "combined " : "") . @@ -5917,13 +5877,15 @@ sub git_log_body { $from = 0 unless defined $from; $to = $#{$commitlist} if (!defined $to || $#{$commitlist} < $to); + print "
\n"; for (my $i = 0; $i <= $to; $i++) { my %co = %{$commitlist->[$i]}; next if !%co; my $commit = $co{'id'}; my $ref = format_ref_marker($refs, $commit); + print "
\n"; git_print_header_div('commit', - "$co{'age_string'}" . + "" . esc_html($co{'title'}) . $ref, $commit); print "
\n" . @@ -5933,15 +5895,16 @@ sub git_log_body { $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " . $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree") . - "
\n" . "
\n"; git_print_authorship(\%co, -tag => 'span'); - print "
\n\n"; + print "\n"; print "
\n"; - git_print_log($co{'comment'}, -final_empty_line=> 1); + git_print_log($co{'comment'}); print "
\n"; + print "
\n"; } + print "
\n"; if ($extra) { print "
\n"; print "$extra\n"; @@ -5969,7 +5932,7 @@ sub git_shortlog_body { } $alternate ^= 1; # git_summary() used print "
\n" . - print "\n" . + print "\n" . format_author_html('td', \%co, 10) . "\n"; } $alternate ^= 1; - print "\n" . + print "\n" . # shortlog: format_author_html('td', \%co, 10) format_author_html('td', \%co, 15, 3) . "\n" . + print "\n" . "\n" . "\n"; } $alternate ^= 1; - print "\n" . + print "\n" . format_author_html('td', \%co, 15, 5) . "\n" . @@ -6539,6 +6502,7 @@ sub git_project_list { } git_header_html(); + git_end_subhead_html(); if (defined $home_text && -f $home_text) { print "
\n"; insert_file($home_text); @@ -6628,14 +6592,13 @@ sub git_summary { git_header_html(); git_print_page_nav('summary','', $head); - print "
 
\n"; print "
$co{'age_string'}$co{'age_string_date'}"; print format_subject_html($co{'title'}, $co{'title_short'}, href(action=>"commit", hash=>$commit), $ref); @@ -6018,7 +5981,7 @@ sub git_history_body { print "
$co{'age_string_date'}"; # originally git_history used chop_str($co{'title'}, 50) @@ -6348,7 +6311,7 @@ sub git_search_changes { $alternate ^= 1; %co = parse_commit($set{'commit'}); my $author = chop_and_escape_str($co{'author_name'}, 15, 5); - print "$co{'age_string_date'}$author" . $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), @@ -6360,7 +6323,7 @@ sub git_search_changes { print $cgi->a({-href => href(action=>"blob", hash_base=>$co{'id'}, hash=>$set{'to_id'}, file_name=>$set{'to_file'}), -class => "list"}, - "" . esc_path($set{'file'}) . "") . + "" . esc_path($set{'file'}) . "") . "
\n"; } } @@ -6435,17 +6398,17 @@ sub git_search_files { $ltext = untabify($ltext); if ($ltext =~ m/^(.*)($search_regexp)(.*)$/i) { $ltext = esc_html($1, -nbsp=>1); - $ltext .= ''; + $ltext .= ''; $ltext .= esc_html($2, -nbsp=>1); - $ltext .= ''; + $ltext .= ''; $ltext .= esc_html($3, -nbsp=>1); } else { $ltext = esc_html($ltext, -nbsp=>1); } print "
" . $cgi->a({-href => $file_href.'#l'.$lno, - -class => "linenr"}, sprintf('%4i', $lno)) . - ' ' . $ltext . "
\n"; + -class => "linenr"}, sprintf('%4i ', $lno)) . + $ltext . "\n"; } } if ($lastfile) { @@ -6482,7 +6445,7 @@ sub git_search_grep_body { print "
$co{'age_string_date'}" . $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), @@ -6502,7 +6465,7 @@ sub git_search_grep_body { $match = esc_html($match); $trail = esc_html($trail); - print "$lead$match$trail
"; + print "$lead$match$trail
"; } } print "
\n" . - "\n"; + "\n"; if ($owner and not $omit_owner) { - print "\n"; + print "\n"; } if (defined $cd{'rfc2822'}) { - print "" . + print "" . "\n"; } @@ -6658,7 +6621,7 @@ sub git_summary { # without ability to add tags, don't show if there are none my $cloud = git_populate_project_tagcloud($ctags); print "" . - "" . + "" . "" . "\n"; } @@ -6666,51 +6629,66 @@ sub git_summary { print "
description" . esc_html($descr) . "
description" . esc_html($descr) . "
owner" . esc_html($owner) . "
owner" . esc_html($owner) . "
last change
last change".format_timestamp_html(\%cd)."
content tagscontent tags".git_show_project_tagcloud($cloud, 48)."
\n"; + print("
\n"); + # If XSS prevention is on, we don't include README.html. # TODO: Allow a readme in some safe format. if (!$prevent_xss && -s "$projectroot/$project/README.html") { + print("
\n"); print "
readme
\n" . "
\n"; insert_file("$projectroot/$project/README.html"); print "\n
\n"; # class="readme" + print("
\n"); } # we need to request one more than 16 (0..15) to check if # those 16 are all my @commitlist = $head ? parse_commits($head, 17) : (); if (@commitlist) { + print("
\n"); git_print_header_div('shortlog'); git_shortlog_body(\@commitlist, 0, 15, $refs, $#commitlist <= 15 ? undef : $cgi->a({-href => href(action=>"shortlog")}, "...")); + print("
\n"); } if (@taglist) { + print("
\n"); git_print_header_div('tags'); git_tags_body(\@taglist, 0, 15, $#taglist <= 15 ? undef : $cgi->a({-href => href(action=>"tags")}, "...")); + print("
\n"); } if (@headlist) { + print("
\n"); git_print_header_div('heads'); git_heads_body(\@headlist, $head, 0, 15, $#headlist <= 15 ? undef : $cgi->a({-href => href(action=>"heads")}, "...")); + print("
\n"); } if (%remotedata) { + print("
\n"); git_print_header_div('remotes'); git_remotes_body(\%remotedata, 15, $head); + print("
\n"); } if (@forklist) { + print("
\n"); git_print_header_div('forks'); git_project_list_body(\@forklist, 'age', 0, 15, $#forklist <= 15 ? undef : $cgi->a({-href => href(action=>"forks")}, "..."), 'no_header'); + print("
\n"); } + print("
\n"); git_footer_html(); } @@ -6729,7 +6707,7 @@ sub git_tag { print "
\n" . "\n" . "\n" . - "\n" . + "\n" . "\n" . "
objectobject" . $cgi->a({-class => "list", -href => href(action=>$tag{'type'}, hash=>$tag{'object'})}, $tag{'object'}) . "" . $cgi->a({-href => href(action=>$tag{'type'}, hash=>$tag{'object'})}, @@ -7177,9 +7155,8 @@ sub git_blob { git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); } else { - print "
\n" . - "

\n" . - "
".esc_html($hash)."
\n"; + git_end_subhead_html(); + print "
".esc_html($hash)."
\n"; } git_print_page_path($file_name, "blob", $hash_base); print "
\n"; @@ -7198,7 +7175,7 @@ sub git_blob { chomp $line; $nr++; $line = untabify($line); - printf qq!
%4i %s
\n!, + printf qq!\n!, $nr, esc_attr(href(-replay => 1)), $nr, $nr, $highlight ? sanitize($line) : esc_html($line, -nbsp=>1); } @@ -7260,8 +7237,7 @@ sub git_tree { git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base); } else { undef $hash_base; - print "
\n"; - print "

\n"; + git_end_subhead_html(); print "
".esc_html($hash)."
\n"; } if (defined $file_name) { @@ -7608,9 +7584,9 @@ sub git_commit { print "
\n" . "\n"; git_print_authorship_rows(\%co); - print "\n"; + print "\n"; print "" . - "" . + "" . "" . - "" . + "" . "
commit$co{'id'}
commit$co{'id'}
treetree" . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash), class => "list"}, $co{'tree'}) . @@ -7627,7 +7603,7 @@ sub git_commit { foreach my $par (@$parents) { print "
parentparent" . $cgi->a({-href => href(action=>"commit", hash=>$par), class => "list"}, $par) . @@ -7785,7 +7761,8 @@ sub git_blobdiff { git_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav); git_print_header_div('commit', esc_html($co{'title'}), $hash_base); } else { - print "

$formats_nav
\n"; + print "

$formats_nav
\n"; + git_end_subhead_html(); print "
".esc_html("$hash vs $hash_parent")."
\n"; } if (defined $file_name) { @@ -8023,7 +8000,7 @@ sub git_commitdiff { print "
\n"; if (@{$co{'comment'}} > 1) { print "
\n"; - git_print_log($co{'comment'}, -final_empty_line=> 1, -remove_title => 1); + git_print_log($co{'comment'}, -remove_title => 1); print "
\n"; # class="log" } @@ -8241,7 +8218,7 @@ sub git_feed { return if ($cgi->request_method() eq 'HEAD'); # header variables - my $title = "$site_name - $project/$action"; + my $title = to_utf8($site_name) . " - $project/$action"; my $feed_type = 'log'; if (defined $hash) { $title .= " - '$hash'"; @@ -8404,7 +8381,7 @@ sub git_opml { -charset => 'utf-8', -content_disposition => 'inline; filename="opml.xml"'); - my $title = esc_html($site_name); + my $title = esc_html(to_utf8($site_name)); my $filter = " within subdirectory "; if (defined $project_filter) { $filter .= esc_html($project_filter);