]> Sergey Matveev's repositories - public-inbox.git/blob - public-inbox-cgi
cgi: make internal interface more Plack-like
[public-inbox.git] / public-inbox-cgi
1 #!/usr/bin/perl -w
2 # Copyright (C) 2014, Eric Wong <normalperson@yhbt.net> and all contributors
3 # License: AGPLv3 or later (https://www.gnu.org/licenses/agpl-3.0.txt)
4 #
5 # We focus on the lowest common denominators here:
6 # - targeted at text-only console browsers (lynx, w3m, etc..)
7 # - Only basic HTML, CSS only for line-wrapping <pre> text content for GUIs
8 # - No JavaScript, graphics or icons allowed.
9 # - Must not rely on static content
10 # - UTF-8 is only for user-content, 7-bit US-ASCII for us
11
12 use 5.008;
13 use strict;
14 use warnings;
15 use CGI qw(:cgi :escapeHTML -nosticky); # PSGI/FastCGI/mod_perl compat
16 use CGI::Util qw(unescape);
17 use Encode;
18 use PublicInbox::Config;
19 our $LISTNAME_RE = qr!\A/([\w\.\-]+)!;
20 our $pi_config;
21 BEGIN {
22         $pi_config = PublicInbox::Config->new;
23         # TODO: detect and reload config as needed
24         if ($ENV{MOD_PERL}) {
25                 CGI->compile;
26         }
27 }
28
29 binmode STDOUT, ':utf8';
30
31 my $ret = main();
32
33 my ($status, $headers, $body) = @$ret;
34 if (@ARGV && $ARGV[0] eq 'static') {
35         print $body;
36 } else { # CGI
37         print "Status: $status\r\n";
38         while (my ($k, $v) = each %$headers) {
39                 print "$k: $v\r\n";
40         }
41         print "\r\n", $body;
42 }
43
44 # TODO: plack support
45
46 # private functions below
47
48 sub main {
49         my $cgi = CGI->new;
50         if ($cgi->request_method !~ /\AGET|HEAD\z/) {
51                 return r("405 Method Not Allowed");
52         }
53         my $path_info = decode_utf8($ENV{PATH_INFO});
54         if ($path_info eq "/") {
55                 r("404 Not Found");
56         } elsif ($path_info =~ m!$LISTNAME_RE/?\z!o) {
57                 get_list_log($cgi, $1);
58         } elsif ($path_info =~ m!$LISTNAME_RE/all\z!o) {
59                 get_list_all($cgi, $1);
60         } elsif ($path_info =~ m!$LISTNAME_RE/index\.atom\.xml\z!o) {
61                 get_atom_index($cgi, $1);
62         } elsif ($path_info =~ m!$LISTNAME_RE/all\.atom\.xml\z!o) {
63                 get_atom_all($cgi, $1);
64         } elsif ($path_info =~ m!$LISTNAME_RE/mid/(\S+)\.txt\z!o) {
65                 get_mid_txt($cgi, $1, $2);
66         } elsif ($path_info =~ m!$LISTNAME_RE/mid/(\S+)\.html\z!o) {
67                 get_mid_html($cgi, $1, $2);
68         } elsif ($path_info =~ m!$LISTNAME_RE/mid/(\S+)\z!o) {
69                 redirect_mid_html($cgi, $1, $2);
70         } else {
71                 r("404 Not Found");
72         }
73 }
74
75 # simple response for errors
76 sub r { [ $_[0], { 'Content-Type' => 'text/plain' }, '' ] }
77
78 # /$LISTNAME/all.atom.xml       -> Atom feed, includes replies
79 sub get_atom_all {
80         my ($cgi, $listname) = @_;
81         my $git_dir = $pi_config->get($listname, "mainrepo");
82         defined $git_dir or return r("404 Not Found");
83
84         require PublicInbox::Feed;
85         [ '200 OK',
86           { 'Content-Type' => 'application/xml; charset=us-ascii' },
87           PublicInbox::Feed->generate({
88                         git_dir => $git_dir,
89                         pi_config => $pi_config,
90                         listname => $listname,
91                         cgi => $cgi
92                 })
93         ];
94 }
95
96 # /$LISTNAME/index.atom.xml     -> Atom feed
97 sub get_atom_index {
98         my ($cgi, $listname) = @_;
99         my $git_dir = $pi_config->get($listname, "mainrepo");
100         defined $git_dir or return r("404 Not Found");
101
102         require PublicInbox::Feed;
103         [ '200 OK',
104           { 'Content-Type' => 'application/xml; charset=us-ascii' },
105           PublicInbox::Feed->generate({
106                         git_dir => $git_dir,
107                         pi_config => $pi_config,
108                         listname => $listname,
109                         cgi => $cgi,
110                         top => 1
111                 })
112         ];
113 }