X-Git-Url: https://git.ladys.computer/Gitweb/blobdiff_plain/d5325663a7cdc64230cabcf41dff257130114ad6312eee12f54af9a9a2bad02f..6317f81da0e9724817a39531276527bbe33a2aa68a051fbabaa8ef209f8c8384:/gitweb.perl diff --git a/gitweb.perl b/gitweb.perl index bd24010..3a8a2f0 100755 --- a/gitweb.perl +++ b/gitweb.perl @@ -666,13 +666,25 @@ sub read_config_file { return; } -our ($GITWEB_CONFIG, $GITWEB_CONFIG_SYSTEM); +our ($GITWEB_CONFIG, $GITWEB_CONFIG_SYSTEM, $GITWEB_CONFIG_COMMON); sub evaluate_gitweb_config { our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++"; our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++"; + our $GITWEB_CONFIG_COMMON = $ENV{'GITWEB_CONFIG_COMMON'} || "++GITWEB_CONFIG_COMMON++"; - # use first config file that exists - read_config_file($GITWEB_CONFIG) or + # Protect agains duplications of file names, to not read config twice. + # Only one of $GITWEB_CONFIG and $GITWEB_CONFIG_SYSTEM is used, so + # there possibility of duplication of filename there doesn't matter. + $GITWEB_CONFIG = "" if ($GITWEB_CONFIG eq $GITWEB_CONFIG_COMMON); + $GITWEB_CONFIG_SYSTEM = "" if ($GITWEB_CONFIG_SYSTEM eq $GITWEB_CONFIG_COMMON); + + # Common system-wide settings for convenience. + # Those settings can be ovverriden by GITWEB_CONFIG or GITWEB_CONFIG_SYSTEM. + read_config_file($GITWEB_CONFIG_COMMON); + + # Use first config file that exists. This means use the per-instance + # GITWEB_CONFIG if exists, otherwise use GITWEB_SYSTEM_CONFIG. + read_config_file($GITWEB_CONFIG) and return; read_config_file($GITWEB_CONFIG_SYSTEM); } @@ -1506,6 +1518,17 @@ sub esc_path { return $str; } +# Sanitize for use in XHTML + application/xml+xhtm (valid XML 1.0) +sub sanitize { + my $str = shift; + + return undef unless defined $str; + + $str = to_utf8($str); + $str =~ s|([[:cntrl:]])|($1 =~ /[\t\n\r]/ ? $1 : quot_cec($1))|eg; + return $str; +} + # Make control characters "printable", using character escape codes (CEC) sub quot_cec { my $cntrl = shift; @@ -2515,6 +2538,13 @@ sub git_get_project_config { # key sanity check return unless ($key); + # only subsection, if exists, is case sensitive, + # and not lowercased by 'git config -z -l' + if (my ($hi, $mi, $lo) = ($key =~ /^([^.]*)\.(.*)\.([^.]*)$/)) { + $key = join(".", lc($hi), $mi, lc($lo)); + } else { + $key = lc($key); + } $key =~ s/^gitweb\.//; return if ($key =~ m/\W/); @@ -3685,6 +3715,20 @@ sub get_page_title { return $title; } +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'; + } +} + sub print_feed_meta { if (defined $project) { my %href_params = get_feed_info(); @@ -3730,24 +3774,90 @@ sub print_feed_meta { } } +sub print_header_links { + my $status = shift; + + # print out each stylesheet that exist, providing backwards capability + # for those people who defined $stylesheet in a config file + if (defined $stylesheet) { + print ''."\n"; + } else { + foreach my $stylesheet (@stylesheets) { + next unless $stylesheet; + print ''."\n"; + } + } + print_feed_meta() + if ($status eq '200 OK'); + if (defined $favicon) { + print qq(\n); + } +} + +sub print_nav_breadcrumbs { + my %opts = @_; + + print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / "; + if (defined $project) { + print $cgi->a({-href => href(action=>"summary")}, esc_html($project)); + if (defined $action) { + my $action_print = $action ; + if (defined $opts{-action_extra}) { + $action_print = $cgi->a({-href => href(action=>$action)}, + $action); + } + print " / $action_print"; + } + if (defined $opts{-action_extra}) { + print " / $opts{-action_extra}"; + } + print "\n"; + } +} + +sub print_search_form { + if (!defined $searchtext) { + $searchtext = ""; + } + my $search_hash; + if (defined $hash_base) { + $search_hash = $hash_base; + } elsif (defined $hash) { + $search_hash = $hash; + } else { + $search_hash = "HEAD"; + } + my $action = $my_uri; + my $use_pathinfo = gitweb_check_feature('pathinfo'); + if ($use_pathinfo) { + $action .= "/".esc_url($project); + } + print $cgi->startform(-method => "get", -action => $action) . + "
\n" . + (!$use_pathinfo && + $cgi->input({-name=>"p", -value=>$project, -type=>"hidden"}) . "\n") . + $cgi->input({-name=>"a", -value=>"search", -type=>"hidden"}) . "\n" . + $cgi->input({-name=>"h", -value=>$search_hash, -type=>"hidden"}) . "\n" . + $cgi->popup_menu(-name => 'st', -default => 'commit', + -values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) . + $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) . + " search:\n", + $cgi->textfield(-name => "s", -value => $searchtext) . "\n" . + "" . + $cgi->checkbox(-name => 'sr', -value => 1, -label => 're', + -checked => $search_use_regexp) . + "" . + "
" . + $cgi->end_form() . "\n"; +} + sub git_header_html { my $status = shift || "200 OK"; my $expires = shift; my %opts = @_; my $title = get_page_title(); - my $content_type; - # 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) { - $content_type = 'application/xhtml+xml'; - } else { - $content_type = 'text/html'; - } + my $content_type = get_content_type_html(); print $cgi->header(-type=>$content_type, -charset => 'utf-8', -status=> $status, -expires => $expires) unless ($opts{'-no_http_header'}); @@ -3769,22 +3879,7 @@ EOF if ($ENV{'PATH_INFO'}) { print "\n"; } - # print out each stylesheet that exist, providing backwards capability - # for those people who defined $stylesheet in a config file - if (defined $stylesheet) { - print ''."\n"; - } else { - foreach my $stylesheet (@stylesheets) { - next unless $stylesheet; - print ''."\n"; - } - } - print_feed_meta() - if ($status eq '200 OK'); - if (defined $favicon) { - print qq(\n); - } - + print_header_links($status); print "\n" . "\n"; @@ -3801,59 +3896,12 @@ EOF -alt => "git", -class => "logo"})); } - print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / "; - if (defined $project) { - print $cgi->a({-href => href(action=>"summary")}, esc_html($project)); - if (defined $action) { - my $action_print = $action ; - if (defined $opts{-action_extra}) { - $action_print = $cgi->a({-href => href(action=>$action)}, - $action); - } - print " / $action_print"; - } - if (defined $opts{-action_extra}) { - print " / $opts{-action_extra}"; - } - print "\n"; - } + print_nav_breadcrumbs(%opts); print "\n"; my $have_search = gitweb_check_feature('search'); if (defined $project && $have_search) { - if (!defined $searchtext) { - $searchtext = ""; - } - my $search_hash; - if (defined $hash_base) { - $search_hash = $hash_base; - } elsif (defined $hash) { - $search_hash = $hash; - } else { - $search_hash = "HEAD"; - } - my $action = $my_uri; - my $use_pathinfo = gitweb_check_feature('pathinfo'); - if ($use_pathinfo) { - $action .= "/".esc_url($project); - } - print $cgi->startform(-method => "get", -action => $action) . - "
\n" . - (!$use_pathinfo && - $cgi->input({-name=>"p", -value=>$project, -type=>"hidden"}) . "\n") . - $cgi->input({-name=>"a", -value=>"search", -type=>"hidden"}) . "\n" . - $cgi->input({-name=>"h", -value=>$search_hash, -type=>"hidden"}) . "\n" . - $cgi->popup_menu(-name => 'st', -default => 'commit', - -values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) . - $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) . - " search:\n", - $cgi->textfield(-name => "s", -value => $searchtext) . "\n" . - "" . - $cgi->checkbox(-name => 'sr', -value => 1, -label => 're', - -checked => $search_use_regexp) . - "" . - "
" . - $cgi->end_form() . "\n"; + print_search_form(); } } @@ -6341,7 +6389,16 @@ sub git_blob_plain { # want to be sure not to break that by serving the image as an # attachment (though Firefox 3 doesn't seem to care). my $sandbox = $prevent_xss && - $type !~ m!^(?:text/plain|image/(?:gif|png|jpeg))(?:[ ;]|$)!; + $type !~ m!^(?:text/[a-z]+|image/(?:gif|png|jpeg))(?:[ ;]|$)!; + + # serve text/* as text/plain + if ($prevent_xss && + ($type =~ m!^text/[a-z]+\b(.*)$! || + ($type =~ m!^[a-z]+/[a-z]\+xml\b(.*)$! && -T $fd))) { + my $rest = $1; + $rest = defined $rest ? $rest : ''; + $type = "text/plain$rest"; + } print $cgi->header( -type => $type, @@ -6439,7 +6496,8 @@ sub git_blob { $nr++; $line = untabify($line); printf qq!
%4i %s
\n!, - $nr, href(-replay => 1), $nr, $nr, $syntax ? $line : esc_html($line, -nbsp=>1); + $nr, esc_attr(href(-replay => 1)), $nr, $nr, + $syntax ? sanitize($line) : esc_html($line, -nbsp=>1); } } close $fd