]> Sergey Matveev's repositories - public-inbox.git/blob - public-inbox-cgi
Makefile.PL: add parallel test target
[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 Encode qw(decode_utf8);
17 use PublicInbox::Config;
18 our $LISTNAME_RE = qr!\A/([\w\.\-]+)!;
19 our $pi_config;
20 BEGIN {
21         $pi_config = PublicInbox::Config->new;
22         # TODO: detect and reload config as needed
23         if ($ENV{MOD_PERL}) {
24                 CGI->compile;
25         }
26 }
27
28 binmode STDOUT, ':utf8';
29
30 my $ret = main();
31
32 my ($status, $headers, $body) = @$ret;
33 if (@ARGV && $ARGV[0] eq 'static') {
34         print $body;
35 } else { # CGI
36         print "Status: $status\r\n";
37         while (my ($k, $v) = each %$headers) {
38                 print "$k: $v\r\n";
39         }
40         print "\r\n", $body;
41 }
42
43 # TODO: plack support
44
45 # private functions below
46
47 sub main {
48         my $cgi = CGI->new;
49         if ($cgi->request_method !~ /\AGET|HEAD\z/) {
50                 return r("405 Method Not Allowed");
51         }
52         my $path_info = decode_utf8($ENV{PATH_INFO});
53         if ($path_info eq "/") {
54                 r("404 Not Found");
55         } elsif ($path_info =~ m!$LISTNAME_RE/?\z!o) {
56                 get_list_log($cgi, $1);
57         } elsif ($path_info =~ m!$LISTNAME_RE/all\z!o) {
58                 get_list_all($cgi, $1);
59         } elsif ($path_info =~ m!$LISTNAME_RE/index\.atom\.xml\z!o) {
60                 get_atom_index($cgi, $1);
61         } elsif ($path_info =~ m!$LISTNAME_RE/all\.atom\.xml\z!o) {
62                 get_atom_all($cgi, $1);
63         } elsif ($path_info =~ m!$LISTNAME_RE/mid/(\S+)\.txt\z!o) {
64                 get_mid_txt($cgi, $1, $2);
65         } elsif ($path_info =~ m!$LISTNAME_RE/mid/(\S+)\.html\z!o) {
66                 get_mid_html($cgi, $1, $2);
67         } elsif ($path_info =~ m!$LISTNAME_RE/mid/(\S+)\z!o) {
68                 redirect_mid_html($cgi, $1, $2);
69         } else {
70                 r("404 Not Found");
71         }
72 }
73
74 # simple response for errors
75 sub r { [ $_[0], { 'Content-Type' => 'text/plain' }, '' ] }
76
77 # /$LISTNAME/all.atom.xml       -> Atom feed, includes replies
78 sub get_atom_all {
79         my ($cgi, $listname) = @_;
80         my $git_dir = $pi_config->get($listname, "mainrepo");
81         defined $git_dir or return r("404 Not Found");
82
83         require PublicInbox::Feed;
84         [ '200 OK',
85           { 'Content-Type' => 'application/xml; charset=us-ascii' },
86           PublicInbox::Feed->generate({
87                         git_dir => $git_dir,
88                         pi_config => $pi_config,
89                         listname => $listname,
90                         cgi => $cgi
91                 })
92         ];
93 }
94
95 # /$LISTNAME/index.atom.xml     -> Atom feed
96 sub get_atom_index {
97         my ($cgi, $listname) = @_;
98         my $git_dir = $pi_config->get($listname, "mainrepo");
99         defined $git_dir or return r("404 Not Found");
100
101         require PublicInbox::Feed;
102         [ '200 OK',
103           { 'Content-Type' => 'application/xml; charset=us-ascii' },
104           PublicInbox::Feed->generate({
105                         git_dir => $git_dir,
106                         pi_config => $pi_config,
107                         listname => $listname,
108                         cgi => $cgi,
109                         top => 1
110                 })
111         ];
112 }