X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FWWW.pm;h=d0e20fb54da4a82768d899c53fb693415b759a67;hb=6dec9bf8c0e1b859703d7a5dfb87052cf4e87846;hp=e3b589cb78d4475c39eba9d8ca6c6f8e89e9610d;hpb=82d793d96cc37d5b3cf562c7081bfacb05d1e4cd;p=public-inbox.git
diff --git a/lib/PublicInbox/WWW.pm b/lib/PublicInbox/WWW.pm
index e3b589cb..d0e20fb5 100644
--- a/lib/PublicInbox/WWW.pm
+++ b/lib/PublicInbox/WWW.pm
@@ -1,4 +1,4 @@
-# Copyright (C) 2014-2020 all contributors
+# Copyright (C) all contributors
# License: AGPL-3.0+
#
# Main web interface for mailing list archives
@@ -11,10 +11,8 @@
# - Must not rely on static content
# - UTF-8 is only for user-content, 7-bit US-ASCII for us
package PublicInbox::WWW;
-use 5.010_001;
use strict;
-use warnings;
-use bytes (); # only for bytes::length
+use v5.10.1;
use PublicInbox::Config;
use PublicInbox::Hval;
use URI::Escape qw(uri_unescape);
@@ -25,16 +23,15 @@ use PublicInbox::WwwStatic qw(r path_info_raw);
use PublicInbox::Eml;
# TODO: consider a routing tree now that we have more endpoints:
-our $INBOX_RE = qr!\A/([\w\-][\w\.\-]*)!;
+our $INBOX_RE = qr!\A/([\w\-][\w\.\-\+]*)!;
our $MID_RE = qr!([^/]+)!;
our $END_RE = qr!(T/|t/|t\.mbox(?:\.gz)?|t\.atom|raw|)!;
our $ATTACH_RE = qr!([0-9][0-9\.]*)-($PublicInbox::Hval::FN)!;
our $OID_RE = qr![a-f0-9]{7,}!;
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;
}
# backwards compatibility, do not use
@@ -51,10 +48,9 @@ sub call {
%{$ctx->{qp}} = map {
utf8::decode($_);
tr/+/ /;
- my ($k, $v) = split('=', $_, 2);
- $v = uri_unescape($v // '');
+ my ($k, $v) = split(/=/, $_, 2);
# none of the keys we care about will need escaping
- $k => $v;
+ ($k // '', uri_unescape($v // ''))
} split(/[&;]+/, $env->{QUERY_STRING});
my $path_info = path_info_raw($env);
@@ -68,6 +64,10 @@ sub call {
serve_git($ctx, $epoch, $path);
} elsif ($path_info =~ m!$INBOX_RE/(\w+)\.sql\.gz\z!o) {
return get_altid_dump($ctx, $1, $2);
+ } elsif ($path_info =~ m!$INBOX_RE/$MID_RE/$ATTACH_RE\z!o) {
+ my ($idx, $fn) = ($3, $4);
+ return invalid_inbox_mid($ctx, $1, $2) ||
+ get_attach($ctx, $idx, $fn);
} elsif ($path_info =~ m!$INBOX_RE/!o) {
return invalid_inbox($ctx, $1) || mbox_results($ctx);
}
@@ -135,7 +135,8 @@ sub call {
# convenience redirects order matters
} elsif ($path_info =~ m!$INBOX_RE/([^/]{2,})\z!o) {
r301($ctx, $1, $2);
-
+ } elsif ($path_info =~ m!\A/\+/([a-zA-Z0-9_\-\.]+)\.css\z!) {
+ get_css($ctx, undef, $1); # for WwwListing
} else {
legacy_redirects($ctx, $path_info);
}
@@ -169,25 +170,17 @@ sub preload {
eval "require PublicInbox::$_;";
}
if (ref($self)) {
- my $pi_config = $self->{pi_config};
- if (defined($pi_config->{'publicinbox.cgitrc'})) {
- $pi_config->limiter('-cgit');
+ my $pi_cfg = $self->{pi_cfg};
+ if (defined($pi_cfg->{'publicinbox.cgitrc'})) {
+ $pi_cfg->limiter('-cgit');
}
+ $pi_cfg->ALL and require PublicInbox::Isearch;
$self->cgit;
$self->stylesheets_prepare($_) for ('', '../', '../../');
$self->news_www;
- $pi_config->each_inbox(\&preload_inbox);
}
}
-sub preload_inbox {
- my $ibx = shift;
- $ibx->altid_map;
- $ibx->cloneurl;
- $ibx->description;
- $ibx->base_url;
-}
-
# private functions below
sub r404 {
@@ -204,15 +197,18 @@ sub news_cgit_fallback ($) {
my $www = $ctx->{www};
my $env = $ctx->{env};
my $res = $www->news_www->call($env);
- $res->[0] == 404 ? $www->cgit->call($env) : $res;
+ $res = $www->cgit->call($env) if $res->[0] == 404;
+ $res = $www->coderepo->srv($ctx) if $res->[0] == 404;
+ $res;
}
# returns undef if valid, array ref response if invalid
sub invalid_inbox ($$) {
my ($ctx, $inbox) = @_;
- my $ibx = $ctx->{www}->{pi_config}->lookup_name($inbox);
+ my $ibx = $ctx->{www}->{pi_cfg}->lookup_name($inbox) //
+ $ctx->{www}->{pi_cfg}->lookup_ei($inbox);
if (defined $ibx) {
- $ctx->{-inbox} = $ibx;
+ $ctx->{ibx} = $ibx;
return;
}
@@ -230,11 +226,11 @@ sub invalid_inbox_mid {
return $ret if $ret;
my $mid = $ctx->{mid} = uri_unescape($mid_ue);
- my $ibx = $ctx->{-inbox};
+ my $ibx = $ctx->{ibx};
if ($mid =~ m!\A([a-f0-9]{2})([a-f0-9]{38})\z!) {
my ($x2, $x38) = ($1, $2);
# this is horrifically wasteful for legacy URLs:
- my $str = $ctx->{-inbox}->msg_by_path("$x2/$x38") or return;
+ my $str = $ctx->{ibx}->msg_by_path("$x2/$x38") or return;
my $s = PublicInbox::Eml->new($str);
$mid = PublicInbox::MID::mid_clean($s->header_raw('Message-ID'));
return r301($ctx, $inbox, mid_escape($mid));
@@ -272,7 +268,7 @@ sub get_index {
sub get_mid_txt {
my ($ctx) = @_;
require PublicInbox::Mbox;
- PublicInbox::Mbox::emit_raw($ctx) || r404($ctx);
+ PublicInbox::Mbox::emit_raw($ctx) || r(404);
}
# /$INBOX/$MESSAGE_ID/ -> HTML content (short quotes)
@@ -285,7 +281,7 @@ sub get_mid_html {
# /$INBOX/$MESSAGE_ID/t/
sub get_thread {
my ($ctx, $flat) = @_;
- $ctx->{-inbox}->over or return need($ctx, 'Overview');
+ $ctx->{ibx}->over or return need($ctx, 'Overview');
$ctx->{flat} = $flat;
require PublicInbox::View;
PublicInbox::View::thread_html($ctx);
@@ -310,6 +306,7 @@ sub get_vcs_object ($$$;$) {
my ($ctx, $inbox, $oid, $filename) = @_;
my $r404 = invalid_inbox($ctx, $inbox);
return $r404 if $r404;
+ return r(404) if !$ctx->{www}->{pi_cfg}->repo_objs($ctx->{ibx});
require PublicInbox::ViewVCS;
PublicInbox::ViewVCS::show($ctx, $oid, $filename);
}
@@ -325,7 +322,7 @@ sub get_altid_dump {
sub need {
my ($ctx, $extra) = @_;
require PublicInbox::WwwStream;
- PublicInbox::WwwStream::html_oneshot($ctx, 501, \<$extra is not available for this public-inbox
Return to index
EOF
@@ -338,7 +335,7 @@ EOF
# especially on older systems. Stick to zlib since that's what git uses.
sub get_thread_mbox {
my ($ctx, $sfx) = @_;
- my $over = $ctx->{-inbox}->over or return need($ctx, 'Overview');
+ my $over = $ctx->{ibx}->over or return need($ctx, 'Overview');
require PublicInbox::Mbox;
PublicInbox::Mbox::thread_mbox($ctx, $over, $sfx);
}
@@ -347,7 +344,7 @@ sub get_thread_mbox {
# /$INBOX/$MESSAGE_ID/t.atom -> thread as Atom feed
sub get_thread_atom {
my ($ctx) = @_;
- $ctx->{-inbox}->over or return need($ctx, 'Overview');
+ $ctx->{ibx}->over or return need($ctx, 'Overview');
require PublicInbox::Feed;
PublicInbox::Feed::generate_thread_atom($ctx);
}
@@ -412,11 +409,11 @@ sub legacy_redirects {
sub r301 {
my ($ctx, $inbox, $mid_ue, $suffix) = @_;
- my $ibx = $ctx->{-inbox};
+ my $ibx = $ctx->{ibx};
unless ($ibx) {
my $r404 = invalid_inbox($ctx, $inbox);
return $r404 if $r404;
- $ibx = $ctx->{-inbox};
+ $ibx = $ctx->{ibx};
}
my $url = $ibx->base_url($ctx->{env});
my $qs = $ctx->{env}->{QUERY_STRING};
@@ -453,7 +450,7 @@ sub msg_page {
sub serve_git {
my ($ctx, $epoch, $path) = @_;
my $env = $ctx->{env};
- my $ibx = $ctx->{-inbox};
+ my $ibx = $ctx->{ibx};
my $git = defined $epoch ? $ibx->git_epoch($epoch) : $ibx->git;
$git ? PublicInbox::GitHTTPBackend::serve($env, $git, $path) : r404();
}
@@ -461,7 +458,7 @@ sub serve_git {
sub mbox_results {
my ($ctx) = @_;
if ($ctx->{env}->{QUERY_STRING} =~ /(?:\A|[&;])q=/) {
- $ctx->{-inbox}->search or return need($ctx, 'search');
+ $ctx->{ibx}->isrch or return need($ctx, 'search');
require PublicInbox::SearchView;
return PublicInbox::SearchView::mbox_results($ctx);
}
@@ -478,20 +475,20 @@ sub serve_mbox_range {
sub news_www {
my ($self) = @_;
- $self->{news_www} ||= do {
+ $self->{news_www} //= do {
require PublicInbox::NewsWWW;
- PublicInbox::NewsWWW->new($self->{pi_config});
+ PublicInbox::NewsWWW->new($self->{pi_cfg});
}
}
sub cgit {
my ($self) = @_;
- $self->{cgit} ||= do {
- my $pi_config = $self->{pi_config};
+ $self->{cgit} //= do {
+ my $pi_cfg = $self->{pi_cfg};
- if (defined($pi_config->{'publicinbox.cgitrc'})) {
+ if (defined($pi_cfg->{'publicinbox.cgitrc'})) {
require PublicInbox::Cgit;
- PublicInbox::Cgit->new($pi_config);
+ PublicInbox::Cgit->new($pi_cfg);
} else {
require Plack::Util;
Plack::Util::inline_object(call => sub { r404() });
@@ -499,13 +496,21 @@ sub cgit {
}
}
+sub coderepo {
+ my ($self) = @_;
+ $self->{coderepo} //= do {
+ require PublicInbox::WwwCoderepo;
+ PublicInbox::WwwCoderepo->new($self->{pi_cfg});
+ }
+}
+
# GET $INBOX/manifest.js.gz
sub get_inbox_manifest ($$$) {
my ($ctx, $inbox, $key) = @_;
my $r404 = invalid_inbox($ctx, $inbox);
return $r404 if $r404;
require PublicInbox::ManifestJsGz;
- PublicInbox::ManifestJsGz->response($ctx);
+ PublicInbox::ManifestJsGz::per_inbox($ctx);
}
sub get_attach {
@@ -537,7 +542,7 @@ sub stylesheets_prepare ($$) {
} || sub { $_[0] };
my $css_map = {};
- my $stylesheets = $self->{pi_config}->{css} || [];
+ my $stylesheets = $self->{pi_cfg}->{css} || [];
my $links = [];
my $inline_ok = 1;
@@ -628,24 +633,25 @@ sub style {
};
}
-# /$INBOX/$KEY.css endpoint
+# /$INBOX/$KEY.css and /+/$KEY.css endpoints
# CSS is configured globally for all inboxes, but we access them on
# a per-inbox basis. This allows administrators to setup per-inbox
# static routes to intercept the request before it hits PSGI
+# inbox == undef => top-level WwwListing
sub get_css ($$$) {
my ($ctx, $inbox, $key) = @_;
- my $r404 = invalid_inbox($ctx, $inbox);
+ my $r404 = defined($inbox) ? invalid_inbox($ctx, $inbox) : undef;
return $r404 if $r404;
my $self = $ctx->{www};
- my $css_map = $self->{-css_map} || stylesheets_prepare($self, '');
+ my $css_map = $self->{-css_map} ||
+ stylesheets_prepare($self, defined($inbox) ? '' : '+/');
my $css = $css_map->{$key};
- if (!defined($css) && $key eq 'userContent') {
+ if (!defined($css) && defined($inbox) && $key eq 'userContent') {
my $env = $ctx->{env};
- $css = PublicInbox::UserContent::sample($ctx->{-inbox}, $env);
+ $css = PublicInbox::UserContent::sample($ctx->{ibx}, $env);
}
defined $css or return r404();
- my $h = [ 'Content-Length', bytes::length($css),
- 'Content-Type', 'text/css' ];
+ my $h = [ 'Content-Length', length($css), 'Content-Type', 'text/css' ];
PublicInbox::GitHTTPBackend::cache_one_year($h);
[ 200, $h, [ $css ] ];
}
@@ -653,10 +659,20 @@ sub get_css ($$$) {
sub get_description {
my ($ctx, $inbox) = @_;
invalid_inbox($ctx, $inbox) || do {
- my $d = $ctx->{-inbox}->description . "\n";
- [ 200, [ 'Content-Length', bytes::length($d),
+ my $d = $ctx->{ibx}->description . "\n";
+ utf8::encode($d);
+ [ 200, [ 'Content-Length', length($d),
'Content-Type', 'text/plain' ], [ $d ] ];
};
}
+sub event_step { # called via requeue
+ my ($self) = @_;
+ # gzf = PublicInbox::GzipFilter == $ctx
+ my $gzf = shift(@{$self->{-low_prio_q}}) // return;
+ PublicInbox::DS::requeue($self) if scalar(@{$self->{-low_prio_q}});
+ my $http = $gzf->{env}->{'psgix.io'}; # PublicInbox::HTTP
+ $http->next_step($gzf->can('async_next'));
+}
+
1;