Currently it shows estimated size of cache, and provides link to clearing cache. Cache administration page is visible only on local computer; the same is true with respect to ability to clear cache. Those are bare beginnings of autorization framework. Signed-off-by: Jakub Narebski <jnareb@xxxxxxxxx> --- Differences from v4: * action_is_cacheable() (is_cacheable() in previous version) now uses %actions_info hash. * Adding actions related to gitweb cache administration is now done in configure_caching() subroutine. * cache_admin_auth_ok() now returns true also for running gitweb as script, when REMOTE_ADDR environment variable is not define. It also covers situation where non-standard (not in RFC 3875) SERVER_ADDR is not defined. This is "frontend" (interface) patch for gitweb cache management. This is very much work in progress, sent to git mailing list as a proof of concept. Would something like that (perhaps with more advanced authorization for admin) be useful? The 'cache' page looks like this: Cache location Size ------------------+---------+-------------- cache/gitweb 14 KiB [Clear cache] ------------------+---------+-------------- where '[Clear cache]' is a submit button. gitweb/gitweb.perl | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 115 insertions(+), 4 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index fee8739..c413797 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -24,6 +24,8 @@ use Encode; use Fcntl qw(:mode :flock); use File::Find qw(); use File::Basename qw(basename); +use POSIX; + binmode STDOUT, ':utf8'; our $t0; @@ -851,6 +853,10 @@ sub evaluate_actions_info { map { $actions_info{$_}{'output_format'} = undef } qw(blob_plain object); $actions_info{'snapshot'}{'output_format'} = 'binary'; + + # specify uncacheable actions + map { $actions_info{$_}{'uncacheable'} = 1 } + qw(cache clear_cache); } sub action_outputs_html { @@ -858,6 +864,11 @@ sub action_outputs_html { return $actions_info{$action}{'output_format'} eq 'html'; } +sub action_is_cacheable { + my $action = shift; + return !$actions_info{$action}{'uncacheable'}; +} + # fill %input_params with the CGI parameters. All values except for 'opt' # should be single values, but opt can be an array. We should probably # build an array of parameters that can be multi-valued, but since for the time @@ -1178,12 +1189,13 @@ sub dispatch { if (!defined($actions{$action})) { die_error(400, "Unknown action"); } - if ($action !~ m/^(?:opml|project_list|project_index)$/ && + if ($action !~ m/^(?:opml|project_list|project_index|cache|clear_cache)$/ && !$project) { die_error(400, "Project needed"); } - if ($caching_enabled) { + if ($caching_enabled && + action_is_cacheable($action)) { # human readable key identifying gitweb output my $output_key = href(-replay => 1, -full => 1, -path_info => 0); @@ -1204,11 +1216,11 @@ sub run_request { evaluate_uri(); evaluate_gitweb_config(); - evaluate_actions_info(); evaluate_git_version(); check_loadavg(); configure_caching() if ($caching_enabled); + evaluate_actions_info(); # $projectroot and $projects_list might be set in gitweb config file $projects_list ||= $projectroot; @@ -1311,6 +1323,10 @@ sub configure_caching { 'depth' => $cache_options{'cache_depth'}, }); } + + # some actions are available only if cache is turned on + $actions{'cache'} = \&git_cache_admin; + $actions{'clear_cache'} = \&git_cache_clear; } run(); @@ -3673,7 +3689,7 @@ sub git_header_html { my $expires = shift; my %opts = @_; - my $title = get_page_title(); + my $title = $opts{'-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'. @@ -7325,3 +7341,98 @@ XML </opml> XML } + +# see Number::Bytes::Human +sub human_readable_size { + my $bytes = shift || return; + + my @units = ('', 'KiB', 'MiB', 'GiB', 'TiB'); + my $block = 1024; + + my $x = $bytes; + my $unit; + foreach (@units) { + $unit = $_, last if POSIX::ceil($x) < $block; + $x /= $block; + } + + my $num; + if ($x < 10.0) { + $num = sprintf("%.1f", POSIX::ceil($x*10)/10); + } else { + $num = sprintf("%d", POSIX::ceil($x)); + } + + return "$num $unit"; +} + +sub cache_admin_auth_ok { + if (defined $ENV{'REMOTE_ADDR'}) { + if (defined $ENV{'SERVER_ADDR'}) { + # SERVER_ADDR is not in RFC 3875 + return $ENV{'SERVER_ADDR'} eq $ENV{'REMOTE_ADDR'}; + } elsif ($ENV{'REMOTE_ADDR'} =~ m!^(?:127\.0\.0\.1|::1/128)$!) { + # localhost in IPv4 or IPv6 + return 1; + } + } else { + # REMOTE_ADDR not defined, probably calling gitweb as script + return 1; + } + + # restrict all but specified cases + return 0; +} + +sub git_cache_admin { + $caching_enabled + or die_error(403, "Caching disabled"); + cache_admin_auth_ok() + or die_error(403, "Cache administration not allowed"); + $cache && ref($cache) + or die_error(500, "Cache is not present"); + + git_header_html(undef, undef, + -title => to_utf8($site_name) . " - Gitweb cache"); + + print <<'EOF_HTML'; +<table class="cache_admin"> +<tr><th>Cache location</th><th>Size</th><th> </th></tr> +EOF_HTML + print '<tr class="light">' . + '<td class="path">' . esc_path($cache->path_to_namespace()) . '</td>' . + '<td>'; + my $size; + $size = $cache->size() if (!defined $size && $cache->can('size')); + $size = $cache->get_size() if (!defined $size && $cache->can('get_size')); + if (defined $size) { + print human_readable_size($size); + } + print '</td><td>'; + if ($cache->can('clear')) { + print $cgi->start_form({-method => "POST", + -action => $my_uri, + -enctype => CGI::URL_ENCODED}) . + $cgi->input({-name=>"a", -value=>"clear_cache", -type=>"hidden"}) . + $cgi->submit({-label => 'Clear cache'}) . + $cgi->end_form(); + } + print <<'EOF_HTML'; +</td></tr> +</table> +EOF_HTML + + git_footer_html(); +} + +sub git_cache_clear { + if (cache_admin_auth_ok() && $cache && + $cgi->request_method() eq 'POST') { + + $cache->clear(); + } + + #print "cleared"; + print $cgi->redirect(-uri => href(action=>'cache', -full=>1), + -status => '303 See Other'); +} -- 1.7.3 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html