From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 634DA20305 for ; Fri, 5 Apr 2019 20:04:30 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 2/5] cgit: serve static css, logo, favicon directly Date: Fri, 5 Apr 2019 20:04:26 +0000 Message-Id: <20190405200429.16973-3-e@80x24.org> In-Reply-To: <20190405200429.16973-1-e@80x24.org> References: <20190405200429.16973-1-e@80x24.org> List-Id: We can reduce the configuration needed to run cgit by reusing the static file handling logic of the dumb git HTTP protocol. I hate logos and icons, so don't expect public-inbox.org or 80x24.org to ever have those to waste users' bandwidth with :P But I expect other users to find this useful. --- lib/PublicInbox/Cgit.pm | 41 ++++++++++++++++++++++++-- lib/PublicInbox/Config.pm | 10 +++++++ lib/PublicInbox/GitHTTPBackend.pm | 62 +++++++++++++++++++++------------------ 3 files changed, 81 insertions(+), 32 deletions(-) diff --git a/lib/PublicInbox/Cgit.pm b/lib/PublicInbox/Cgit.pm index 9ba9e14..8922ec5 100644 --- a/lib/PublicInbox/Cgit.pm +++ b/lib/PublicInbox/Cgit.pm @@ -13,17 +13,45 @@ use PublicInbox::GitHTTPBackend; *input_prepare = *PublicInbox::GitHTTPBackend::input_prepare; *parse_cgi_headers = *PublicInbox::GitHTTPBackend::parse_cgi_headers; *serve = *PublicInbox::GitHTTPBackend::serve; +*static_result = *PublicInbox::GitHTTPBackend::static_result; use warnings; use PublicInbox::Qspawn; +use Plack::MIME; + +sub locate_cgit ($) { + my ($pi_config) = @_; + my $cgit_bin = $pi_config->{'publicinbox.cgitbin'}; + my $cgit_data = $pi_config->{'publicinbox.cgitdata'}; + + # /var/www/htdocs/cgit is the default install path from cgit.git + # /usr/{lib,share}/cgit is where Debian puts cgit + # TODO: check other distros for common paths + unless (defined $cgit_bin) { + foreach (qw(/var/www/htdocs/cgit /usr/lib/cgit)) { + my $x = "$_/cgit.cgi"; + next unless -x $x; + $cgit_bin = $x; + last; + } + } + unless (defined $cgit_data) { + foreach my $d (qw(/var/www/htdocs/cgit /usr/share/cgit)) { + my $f = "$d/cgit.css"; + next unless -f $f; + $cgit_data = $d; + last; + } + } + ($cgit_bin, $cgit_data); +} sub new { my ($class, $pi_config) = @_; - my $cgit_bin = $pi_config->{'publicinbox.cgitbin'} || - # Debian default location: - '/usr/lib/cgit/cgit.cgi'; + my ($cgit_bin, $cgit_data) = locate_cgit($pi_config); my $self = bless { cmd => [ $cgit_bin ], + cgit_data => $cgit_data, pi_config => $pi_config, }, $class; @@ -39,6 +67,9 @@ sub new { while (my ($nick, $repo) = each %$code_repos) { $self->{"\0$nick"} = $repo; } + my $cgit_static = $pi_config->{-cgit_static}; + my $static = join('|', map { quotemeta $_ } keys %$cgit_static); + $self->{static} = qr/\A($static)\z/; $self; } @@ -66,6 +97,10 @@ sub call { if (my $git = $self->{"\0$nick"}) { return serve($env, $git, $path); } + } elsif ($path_info =~ m!$self->{static}!) { + my $f = $1; + my $type = Plack::MIME->mime_type($f); + return static_result($env, [], "$self->{cgit_data}$f", $type); } my $cgi_env = { PATH_INFO => $path_info }; diff --git a/lib/PublicInbox/Config.pm b/lib/PublicInbox/Config.pm index 9f1e57a..2c1c511 100644 --- a/lib/PublicInbox/Config.pm +++ b/lib/PublicInbox/Config.pm @@ -234,6 +234,12 @@ sub scan_path_coderepo { sub parse_cgitrc { my ($self, $cgitrc, $nesting) = @_; + if ($nesting == 0) { + # defaults: + my %s = map { $_ => 1 } qw(/cgit.css /cgit.png + /favicon.ico /robots.txt); + $self->{-cgit_static} = \%s; + } # same limit as cgit/configfile.c::parse_configfile return if $nesting > 8; @@ -263,6 +269,10 @@ sub parse_cgitrc { $self->{-cgit_scan_hidden_path} = $1; } elsif (m!\Ascan-path=(.+)\z!) { scan_path_coderepo($self, '', $1); + + } elsif (m!\A(?:css|favicon|logo|repo\.logo)=(/.+)\z!) { + # absolute paths for static files via PublicInbox::Cgit + $self->{-cgit_static}->{$1} = 1; } } cgit_repo_merge($self, $repo) if $repo; diff --git a/lib/PublicInbox/GitHTTPBackend.pm b/lib/PublicInbox/GitHTTPBackend.pm index cd8cdf8..57944a0 100644 --- a/lib/PublicInbox/GitHTTPBackend.pm +++ b/lib/PublicInbox/GitHTTPBackend.pm @@ -80,46 +80,26 @@ sub cache_one_year { 'Cache-Control', 'public, max-age=31536000'; } -sub serve_dumb { - my ($env, $git, $path) = @_; - - my @h; - my $type; - if ($path =~ m!\Aobjects/[a-f0-9]{2}/[a-f0-9]{38}\z!) { - $type = 'application/x-git-loose-object'; - cache_one_year(\@h); - } elsif ($path =~ m!\Aobjects/pack/pack-[a-f0-9]{40}\.pack\z!) { - $type = 'application/x-git-packed-objects'; - cache_one_year(\@h); - } elsif ($path =~ m!\Aobjects/pack/pack-[a-f0-9]{40}\.idx\z!) { - $type = 'application/x-git-packed-objects-toc'; - cache_one_year(\@h); - } elsif ($path =~ /\A(?:$TEXT)\z/o) { - $type = 'text/plain'; - push @h, @no_cache; - } else { - return r(404); - } - - my $f = $git->{git_dir} . '/' . $path; +sub static_result ($$$$) { + my ($env, $h, $f, $type) = @_; return r(404) unless -f $f && -r _; # just in case it's a FIFO :P - my $size = -s _; # TODO: If-Modified-Since and Last-Modified? open my $in, '<', $f or return r(404); + my $size = -s $in; my $len = $size; my $code = 200; - push @h, 'Content-Type', $type; + push @$h, 'Content-Type', $type; if (($env->{HTTP_RANGE} || '') =~ /\bbytes=(\d*)-(\d*)\z/) { - ($code, $len) = prepare_range($env, $in, \@h, $1, $2, $size); + ($code, $len) = prepare_range($env, $in, $h, $1, $2, $size); if ($code == 416) { - push @h, 'Content-Range', "bytes */$size"; - return [ 416, \@h, [] ]; + push @$h, 'Content-Range', "bytes */$size"; + return [ 416, $h, [] ]; } } - push @h, 'Content-Length', $len; + push @$h, 'Content-Length', $len; my $n = 65536; - [ $code, \@h, Plack::Util::inline_object(close => sub { close $in }, + [ $code, $h, Plack::Util::inline_object(close => sub { close $in }, getline => sub { return if $len == 0; $n = $len if $len < $n; @@ -138,6 +118,30 @@ sub serve_dumb { })] } +sub serve_dumb { + my ($env, $git, $path) = @_; + + my $h = []; + my $type; + if ($path =~ m!\Aobjects/[a-f0-9]{2}/[a-f0-9]{38}\z!) { + $type = 'application/x-git-loose-object'; + cache_one_year($h); + } elsif ($path =~ m!\Aobjects/pack/pack-[a-f0-9]{40}\.pack\z!) { + $type = 'application/x-git-packed-objects'; + cache_one_year($h); + } elsif ($path =~ m!\Aobjects/pack/pack-[a-f0-9]{40}\.idx\z!) { + $type = 'application/x-git-packed-objects-toc'; + cache_one_year($h); + } elsif ($path =~ /\A(?:$TEXT)\z/o) { + $type = 'text/plain'; + push @$h, @no_cache; + } else { + return r(404); + } + + static_result($env, $h, "$git->{git_dir}/$path", $type); +} + sub prepare_range { my ($env, $in, $h, $beg, $end, $size) = @_; my $code = 200; -- EW