about summary refs log tree commit homepage
path: root/lib/PublicInbox/NewsWWW.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/PublicInbox/NewsWWW.pm')
-rw-r--r--lib/PublicInbox/NewsWWW.pm44
1 files changed, 31 insertions, 13 deletions
diff --git a/lib/PublicInbox/NewsWWW.pm b/lib/PublicInbox/NewsWWW.pm
index 6bed0103..d13731ae 100644
--- a/lib/PublicInbox/NewsWWW.pm
+++ b/lib/PublicInbox/NewsWWW.pm
@@ -1,4 +1,4 @@
-# Copyright (C) 2016-2020 all contributors <meta@public-inbox.org>
+# Copyright (C) 2016-2021 all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 #
 # Plack app redirector for mapping /$NEWSGROUP requests to
@@ -13,9 +13,8 @@ use PublicInbox::MID qw(mid_escape);
 use PublicInbox::Hval qw(prurl);
 
 sub new {
-        my ($class, $pi_config) = @_;
-        $pi_config ||= PublicInbox::Config->new;
-        bless { pi_config => $pi_config }, $class;
+        my ($class, $pi_cfg) = @_;
+        bless { pi_cfg => $pi_cfg // PublicInbox::Config->new }, $class;
 }
 
 sub redirect ($$) {
@@ -46,9 +45,11 @@ sub call {
         # some links may have the article number in them:
         # /inbox.foo.bar/123456
         my (undef, @parts) = split(m!/!, $env->{PATH_INFO});
+        @parts or return
+                [ 404, [qw(Content-Type text/plain)], ["404 Not Found\n"] ];
         my ($ng, $article) = @parts;
-        my $pi_config = $self->{pi_config};
-        if (my $ibx = $pi_config->lookup_newsgroup($ng)) {
+        my $pi_cfg = $self->{pi_cfg};
+        if (my $ibx = $pi_cfg->lookup_newsgroup($ng)) {
                 my $url = prurl($env, $ibx->{url});
                 my $code = 301;
                 if (defined $article && $article =~ /\A[0-9]+\z/) {
@@ -63,7 +64,6 @@ sub call {
                 return redirect($code, $url);
         }
 
-        my $res;
         my @try = (join('/', @parts));
 
         # trailing slash is in the rest of our WWW, so maybe some users
@@ -72,13 +72,31 @@ sub call {
                 pop @parts;
                 push @try, join('/', @parts);
         }
-
-        foreach my $mid (@try) {
-                my $arg = [ $mid ];
-                $pi_config->each_inbox(\&try_inbox, $arg);
-                defined($res = $arg->[1]) and last;
+        my $ALL = $pi_cfg->ALL;
+        if (my $over = $ALL ? $ALL->over : undef) {
+                my $by_eidx_key = $pi_cfg->{-by_eidx_key};
+                for my $mid (@try) {
+                        my ($id, $prev);
+                        while (my $x = $over->next_by_mid($mid, \$id, \$prev)) {
+                                my $xr3 = $over->get_xref3($x->{num});
+                                for (@$xr3) {
+                                        s/:[0-9]+:$x->{blob}\z// or next;
+                                        my $ibx = $by_eidx_key->{$_} // next;
+                                        my $url = $ALL->base_url($env) //
+                                                        $ibx->base_url // next;
+                                        $url .= mid_escape($mid) . '/';
+                                        return redirect(302, $url);
+                                }
+                        }
+                }
+        } else { # slow path, scan every inbox
+                for my $mid (@try) {
+                        my $arg = [ $mid ]; # [1] => result
+                        $pi_cfg->each_inbox(\&try_inbox, $arg);
+                        return $arg->[1] if $arg->[1];
+                }
         }
-        $res || [ 404, [qw(Content-Type text/plain)], ["404 Not Found\n"] ];
+        [ 404, [qw(Content-Type text/plain)], ["404 Not Found\n"] ];
 }
 
 1;