From 513defd67b678c8b8f2ab571e44d20a30b49c6f8 Mon Sep 17 00:00:00 2001
From: Eric Wong <e@80x24.org>
Date: Mon, 14 Apr 2014 07:53:53 +0000
Subject: [PATCH] cgi: 301 for list-indices without trailing slash

It is common to type upper-level URLs without the slash,
redirect users to the correct page for usability.
---
 public-inbox.cgi | 21 +++++++++++++++++++++
 t/cgi.t          |  8 ++++++++
 2 files changed, 29 insertions(+)

diff --git a/public-inbox.cgi b/public-inbox.cgi
index 1765cf45..17eb5b7b 100755
--- a/public-inbox.cgi
+++ b/public-inbox.cgi
@@ -46,6 +46,12 @@ if (@ARGV && $ARGV[0] eq 'static') {
 # private functions below
 
 sub main {
+	# some servers (Ruby webrick) include scheme://host[:port] here,
+	# which confuses CGI.pm when generating self_url.
+	# RFC 3875 does not mention REQUEST_URI at all,
+	# so nuke it since CGI.pm functions without it.
+	delete $ENV{REQUEST_URI};
+
 	my $cgi = CGI->new;
 	my %ctx;
 	if ($cgi->request_method !~ /\AGET|HEAD\z/) {
@@ -77,6 +83,8 @@ sub main {
 	} elsif ($path_info =~ m!$LISTNAME_RE/f/(\S+)\z!o) {
 		redirect_mid_html($cgi, $1, $2);
 
+	} elsif ($path_info =~ m!$LISTNAME_RE\z!o) {
+		invalid_list(\%ctx, $1) || redirect_list_index(\%ctx, $cgi);
 	} else {
 		r404();
 	}
@@ -182,6 +190,19 @@ sub get_full_html {
 		PublicInbox::View->as_html(Email::MIME->new($$x))];
 }
 
+sub redirect_list_index {
+	my ($ctx, $cgi) = @_;
+	do_redirect($cgi->self_url . "/");
+}
+
+sub do_redirect {
+	my ($url) = @_;
+	[ '301 Moved Permanently',
+	  { Location => $url, 'Content-Type' => 'text/plain' },
+	  "Redirecting to $url\n"
+	]
+}
+
 # only used for CGI and static file generation modes
 sub set_binmode {
 	my ($headers) = @_;
diff --git a/t/cgi.t b/t/cgi.t
index ae7cc730..c8755541 100644
--- a/t/cgi.t
+++ b/t/cgi.t
@@ -181,6 +181,14 @@ EOF
 		"slashy URL generated correctly");
 }
 
+# redirect list-name-only URLs
+{
+	local $ENV{HOME} = $home;
+	my $res = cgi_run("/test");
+	like($res->{head}, qr/Status: 301 Moved/, "redirected status");
+	like($res->{head}, qr!/test/!, "redirected with slash");
+}
+
 done_testing();
 
 sub run_with_env {
-- 
2.50.0