]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/WWW.pm
daemon: do more immortal allocations up front
[public-inbox.git] / lib / PublicInbox / WWW.pm
index 251979d5db6ee88af2defb614f2eed43ea5edb6e..2434f2f581b2b0fbd1d48d1a08881bf0a1c1187b 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2014-2019 all contributors <meta@public-inbox.org>
+# Copyright (C) 2014-2020 all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 #
 # Main web interface for mailing list archives
@@ -19,9 +19,9 @@ use PublicInbox::Config;
 use PublicInbox::Hval;
 use URI::Escape qw(uri_unescape);
 use PublicInbox::MID qw(mid_escape);
-require PublicInbox::Git;
 use PublicInbox::GitHTTPBackend;
 use PublicInbox::UserContent;
+use PublicInbox::WwwStatic qw(r path_info_raw);
 
 # TODO: consider a routing tree now that we have more endpoints:
 our $INBOX_RE = qr!\A/([\w\-][\w\.\-]*)!;
@@ -42,17 +42,6 @@ sub run {
        PublicInbox::WWW->new->call($req->env);
 }
 
-my %path_re_cache;
-
-sub path_re ($) {
-       my $sn = $_[0]->{SCRIPT_NAME};
-       $path_re_cache{$sn} ||= do {
-               $sn = '/'.$sn unless index($sn, '/') == 0;
-               $sn =~ s!/\z!!;
-               qr!\A(?:https?://[^/]+)?\Q$sn\E(/[^\?\#]+)!;
-       };
-}
-
 sub call {
        my ($self, $env) = @_;
        my $ctx = { env => $env, www => $self };
@@ -67,9 +56,7 @@ sub call {
                $k => $v;
        } split(/[&;]+/, $env->{QUERY_STRING});
 
-       # avoiding $env->{PATH_INFO} here since that's already decoded
-       my ($path_info) = ($env->{REQUEST_URI} =~ path_re($env));
-       $path_info //= $env->{PATH_INFO};
+       my $path_info = path_info_raw($env);
        my $method = $env->{REQUEST_METHOD};
 
        if ($method eq 'POST') {
@@ -82,8 +69,8 @@ sub call {
                        return invalid_inbox($ctx, $1) || mbox_results($ctx);
                }
        }
-       elsif ($method !~ /\AGET|HEAD\z/) {
-               return r(405, 'Method Not Allowed');
+       elsif ($method !~ /\A(?:GET|HEAD)\z/) {
+               return r(405);
        }
 
        # top-level indices and feeds
@@ -97,6 +84,8 @@ sub call {
                invalid_inbox($ctx, $1) || get_atom($ctx);
        } elsif ($path_info =~ m!$INBOX_RE/new\.html\z!o) {
                invalid_inbox($ctx, $1) || get_new($ctx);
+       } elsif ($path_info =~ m!$INBOX_RE/description\z!o) {
+               get_description($ctx, $1);
        } elsif ($path_info =~ m!$INBOX_RE/(?:(?:git/)?([0-9]+)(?:\.git)?/)?
                                ($PublicInbox::GitHTTPBackend::ANY)\z!ox) {
                my ($epoch, $path) = ($2, $3);
@@ -143,31 +132,47 @@ sub call {
        }
 }
 
-# for CoW-friendliness, MOOOOO!
+# for CoW-friendliness, MOOOOO!  Even for single-process setups,
+# we want to get all immortal allocations done early to avoid heap
+# fragmentation since common allocators favor a large contiguous heap.
 sub preload {
        my ($self) = @_;
+       require PublicInbox::ExtMsg;
        require PublicInbox::Feed;
        require PublicInbox::View;
        require PublicInbox::SearchThread;
        require PublicInbox::MIME;
-       require Digest::SHA;
-       require POSIX;
+       require PublicInbox::Mbox;
+       require PublicInbox::ViewVCS;
+       require PublicInbox::WwwText;
+       require PublicInbox::WwwAttach;
        eval {
                require PublicInbox::Search;
                PublicInbox::Search::load_xapian();
        };
-       foreach (qw(PublicInbox::SearchView
-                       PublicInbox::Mbox IO::Compress::Gzip
-                       PublicInbox::NewsWWW)) {
+       foreach (qw(PublicInbox::SearchView PublicInbox::MboxGz)) {
                eval "require $_;";
        }
        if (ref($self)) {
+               my $pi_config = $self->{pi_config};
+               if (defined($pi_config->{'publicinbox.cgitrc'})) {
+                       $pi_config->limiter('-cgit');
+               }
                $self->cgit;
                $self->stylesheets_prepare($_) for ('', '../', '../../');
                $self->www_listing;
+               $self->news_www;
+               $pi_config->each_inbox(\&preload_inbox);
        }
 }
 
+sub preload_inbox {
+       my $ibx = shift;
+       $ibx->cloneurl;
+       $ibx->description;
+       $ibx->base_url;
+}
+
 # private functions below
 
 sub r404 {
@@ -176,12 +181,9 @@ sub r404 {
                require PublicInbox::ExtMsg;
                return PublicInbox::ExtMsg::ext_msg($ctx);
        }
-       r(404, 'Not Found');
+       r(404);
 }
 
-# simple response for errors
-sub r { [ $_[0], ['Content-Type' => 'text/plain'], [ join(' ', @_, "\n") ] ] }
-
 sub news_cgit_fallback ($) {
        my ($ctx) = @_;
        my $www = $ctx->{www};
@@ -636,4 +638,13 @@ sub get_css ($$$) {
        [ 200, $h, [ $css ] ];
 }
 
+sub get_description {
+       my ($ctx, $inbox) = @_;
+       invalid_inbox($ctx, $inbox) || do {
+               my $d = $ctx->{-inbox}->description . "\n";
+               [ 200, [ 'Content-Length', bytes::length($d),
+                       'Content-Type', 'text/plain' ], [ $d ] ];
+       };
+}
+
 1;