about summary refs log tree commit homepage
path: root/lib/PublicInbox/Repobrowse.pm
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2016-01-15 22:04:30 +0000
committerEric Wong <e@80x24.org>2016-04-05 18:58:27 +0000
commitbe3e0f48796ddb342d4eeb4838c5eedb9aaf79b9 (patch)
treef452e544fafa4b4181540daae4636d5a853cc760 /lib/PublicInbox/Repobrowse.pm
parentb01b50858cac10ff8cd9722fd5be9bcaf314b83c (diff)
downloadpublic-inbox-be3e0f48796ddb342d4eeb4838c5eedb9aaf79b9.tar.gz
For human-visible HTML pages, avoid the trailing slash as that
can reduce cache hits in both the server (using varnish) and
clients.  Typical web browsers are all capable of following
301 redirects without difficulty or human interaction.

We do not redirect for endpoints which may be consumed by
automated tools as that may cause compatibility problems.  For
example, curl(1) does not automatically follow redirects and
needs the "-L" flag to do so.
Diffstat (limited to 'lib/PublicInbox/Repobrowse.pm')
-rw-r--r--lib/PublicInbox/Repobrowse.pm47
1 files changed, 39 insertions, 8 deletions
diff --git a/lib/PublicInbox/Repobrowse.pm b/lib/PublicInbox/Repobrowse.pm
index 9e97593b..f344e0f8 100644
--- a/lib/PublicInbox/Repobrowse.pm
+++ b/lib/PublicInbox/Repobrowse.pm
@@ -35,6 +35,32 @@ sub new {
 # simple response for errors
 sub r { [ $_[0], ['Content-Type' => 'text/plain'], [ join(' ', @_, "\n") ] ] }
 
+# Remove trailing slash in URLs which regular humans are likely to read
+# in an attempt to improve cache hit ratios.  Do not redirect
+# plain|patch|blob|fallback endpoints since those could be using
+# automated tools which may not follow redirects automatically
+# (e.g. curl does not follow 301 unless given "-L")
+my %NO_TSLASH = map { $_ => 1 } qw(Log Commit Tree Summary Tag);
+sub no_tslash {
+        my ($cgi) = @_;
+        my ($base, $uri);
+        if (ref($cgi) eq 'CGI') {
+                $base = $cgi->url(-base);
+                $uri = $ENV{REQUEST_URI};
+        } else { # Plack::Request
+                $base = $cgi->base;
+                $base =~ s!/+\z!!;
+                $uri = $cgi->request_uri;
+        }
+        if ($uri !~ s!/+\z!!) {
+                warn "W: buggy redirect? base=$base request_uri=$uri\n";
+        }
+        my $url = $base . $uri;
+        [ 301,
+          [ Location => $url, 'Content-Type' => 'text/plain' ],
+          [ "Redirecting to $url\n" ] ]
+}
+
 sub run {
         my ($self, $cgi, $method) = @_;
         return r(405, 'Method Not Allowed') if ($method !~ /\AGET|HEAD\z/);
@@ -59,9 +85,8 @@ sub run {
                 extra => \@extra, # path
                 cgi => $cgi,
                 rconfig => $rconfig,
-                tslash => 0,
         };
-
+        my $tslash = 0;
         my $cmd = shift @extra;
         my $vcs_lc = $repo_info->{vcs};
         my $vcs = $VCS{$vcs_lc} or return r404();
@@ -77,8 +102,7 @@ sub run {
                 $mod = 'Summary';
                 $cmd = 'summary';
                 if ($path_info =~ m!/\z!) {
-                        $req->{tslash} = $path_info =~ tr!/!!;
-                        $req->{relcmd} = '';
+                        $tslash = $path_info =~ tr!/!!;
                 } else {
                         my @repo = split('/', $repo_path);
                         if (@repo > 1) {
@@ -88,13 +112,20 @@ sub run {
                         }
                 }
         }
-        $mod = load_once("PublicInbox::Repobrowse$vcs$mod");
-        $vcs = load_once("PublicInbox::$vcs");
-        $repo_info->{$vcs_lc} ||= $vcs->new($repo_info->{path});
         while (@extra && $extra[-1] eq '') {
                 pop @extra;
-                ++$req->{tslash};
+                ++$tslash;
         }
+
+        if ($tslash && $path_info ne '/' && $NO_TSLASH{$mod}) {
+                return no_tslash($cgi);
+        }
+
+        $req->{tslash} = $tslash;
+        $mod = load_once("PublicInbox::Repobrowse$vcs$mod");
+        $vcs = load_once("PublicInbox::$vcs");
+        $repo_info->{$vcs_lc} ||= $vcs->new($repo_info->{path});
+
         $req->{expath} = join('/', @extra);
         my $rv = eval { $mod->new->call($cmd, $req) }; # RepobrowseBase::call
         $rv || r404();