X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FNewsWWW.pm;h=be1d43efa6312b549d701188184cedae5cc47160;hb=11eec3365d537b20ade6923eaa5fdd18206d4342;hp=dfc002171e650325d23d70fa5a7a6a3f352296fb;hpb=15a56c73e3b5c540d1f9d65058c9aba3ff840cdd;p=public-inbox.git diff --git a/lib/PublicInbox/NewsWWW.pm b/lib/PublicInbox/NewsWWW.pm index dfc00217..be1d43ef 100644 --- a/lib/PublicInbox/NewsWWW.pm +++ b/lib/PublicInbox/NewsWWW.pm @@ -1,15 +1,16 @@ -# Copyright (C) 2016 all contributors +# Copyright (C) 2016-2019 all contributors # License: AGPL-3.0+ # # Plack app redirector for mapping /$NEWSGROUP requests to -# the appropriate /$LISTNAME in PublicInbox::WWW because some +# the appropriate /$INBOX in PublicInbox::WWW because some # auto-linkifiers cannot handle nntp:// redirects properly. # This is also used directly by PublicInbox::WWW package PublicInbox::NewsWWW; use strict; use warnings; use PublicInbox::Config; -use URI::Escape qw(uri_escape_utf8); +use PublicInbox::MID qw(mid_escape); +use PublicInbox::Hval qw(prurl); sub new { my ($class, $pi_config) = @_; @@ -17,64 +18,67 @@ sub new { bless { pi_config => $pi_config }, $class; } +sub redirect ($$) { + my ($code, $url) = @_; + [ $code, + [ Location => $url, 'Content-Type' => 'text/plain' ], + [ "Redirecting to $url\n" ] ] +} + +sub try_inbox { + my ($ibx, $arg) = @_; + return if scalar(@$arg) > 1; + + # do not pass $env since HTTP_HOST may differ + my $url = $ibx->base_url or return; + + my ($mid) = @$arg; + eval { $ibx->mm->num_for($mid) } or return; + + # 302 since the same message may show up on + # multiple inboxes and inboxes can be added/reordered + $arg->[1] = redirect(302, $url .= mid_escape($mid) . '/'); +} + sub call { my ($self, $env) = @_; - my $ng_map = $self->newsgroup_map; - my $path = $env->{PATH_INFO}; - $path =~ s!\A/+!!; - $path =~ s!/+\z!!; # some links may have the article number in them: # /inbox.foo.bar/123456 - my ($ng, $article) = split(m!/+!, $path, 2); - if (my $info = $ng_map->{$ng}) { - my $url = PublicInbox::Hval::prurl($env, $info->{url}); + my (undef, @parts) = split(m!/!, $env->{PATH_INFO}); + my ($ng, $article) = @parts; + my $pi_config = $self->{pi_config}; + if (my $ibx = $pi_config->lookup_newsgroup($ng)) { + my $url = prurl($env, $ibx->{url}); my $code = 301; - my $h = [ Location => $url, 'Content-Type' => 'text/plain' ]; - if (defined $article && $article =~ /\A\d+\z/) { - my $mid = eval { ng_mid_for($ng, $info, $article) }; + if (defined $article && $article =~ /\A[0-9]+\z/) { + my $mid = eval { $ibx->mm->mid_for($article) }; if (defined $mid) { # article IDs are not stable across clones, # do not encourage caching/bookmarking them $code = 302; - $url .= uri_escape_utf8($mid) . '/'; + $url .= mid_escape($mid) . '/'; } } - - return [ $code, $h, [ "Redirecting to $url\n" ] ] + return redirect($code, $url); } - [ 404, [ 'Content-Type' => 'text/plain' ], [] ]; -} -sub ng_mid_for { - my ($ng, $info, $article) = @_; - # may fail due to lack of Danga::Socket - # for defer_weaken: - require PublicInbox::NewsGroup; - $ng = $info->{ng} ||= - PublicInbox::NewsGroup->new($ng, $info->{git_dir}, ''); - $ng->mm->mid_for($article); -} + my $res; + my @try = (join('/', @parts)); -sub newsgroup_map { - my ($self) = @_; - my $rv; - $rv = $self->{ng_map} and return $rv; - my $pi_config = $self->{pi_config}; - my %ng_map; - foreach my $k (keys %$pi_config) { - $k =~ /\Apublicinbox\.([^\.]+)\.mainrepo\z/ or next; - my $listname = $1; - my $git_dir = $pi_config->{"publicinbox.$listname.mainrepo"}; - my $url = $pi_config->{"publicinbox.$listname.url"}; - defined $url or next; - my $ng = $pi_config->{"publicinbox.$listname.newsgroup"}; - next if (!defined $ng) || ($ng eq ''); # disabled + # trailing slash is in the rest of our WWW, so maybe some users + # will assume it: + if ($parts[-1] eq '') { + pop @parts; + push @try, join('/', @parts); + } - $url =~ m!/\z! or $url .= '/'; - $ng_map{$ng} = { url => $url, git_dir => $git_dir }; + foreach my $mid (@try) { + my $arg = [ $mid ]; + $pi_config->each_inbox(\&try_inbox, $arg); + defined($res = $arg->[1]) and last; } - $self->{ng_map} = \%ng_map; + $res || [ 404, [qw(Content-Type text/plain)], ["404 Not Found\n"] ]; } 1;