Improve proxy for redirects

Change-Id: I3d62dd698ced3d406fd4ff8377de1a01a0fde319
diff --git a/Changes b/Changes
index 3e6d12f..45365b1 100755
--- a/Changes
+++ b/Changes
@@ -1,6 +1,7 @@
-0.38 2020-02-04
+0.38 2020-02-05
         - Support X-Forwarded-Host name for proxy.
         - Document API URI.
+        - Improve redirect handling in proxy.
 
 0.37 2020-01-16
         - Removed deprecated 'kalamar_test_port' helper.
diff --git a/lib/Kalamar/Controller/Proxy.pm b/lib/Kalamar/Controller/Proxy.pm
index af1eb75..2078d85 100644
--- a/lib/Kalamar/Controller/Proxy.pm
+++ b/lib/Kalamar/Controller/Proxy.pm
@@ -39,7 +39,7 @@
     before_korap_request => ($c, $tx)
   );
 
-  # Start proxy transaction and cache failure
+  # Start proxy transaction and catch failure
   $c->proxy->start_p($tx)->catch(
     sub {
       my $err = shift;
@@ -48,6 +48,10 @@
         status => 400
       );
     }
+  )->finally(
+    sub {
+      $c->rendered;
+    }
   )->wait;
 
   $tx->res->content->once(
@@ -55,6 +59,30 @@
       my $headers = $c->res->headers;
       $headers->header('X-Proxy' => 'Kalamar');
 
+      # Response is a redirect
+      if ($c->res->is_redirect) {
+
+        # Rewrite redirect location to surface URL
+        my $location_url = $c->res->headers->location;
+        my $base_url = Mojo::URL->new($c->korap->api)->to_abs->to_string;
+
+        # Remove the api part
+        # ".*?" is just required for non-absolute base_urls
+        $location_url =~ s/^.*?${base_url}//;
+
+        # Turn the rewritten location into a URL object
+        $location_url = Mojo::URL->new($location_url);
+
+        my $proxy_url = $c->url_for('proxy');
+        $proxy_url->path->trailing_slash(1);
+
+        # Rebase to proxy path
+        my $loc_based = $location_url->base($proxy_url->to_abs);
+
+        # Reset location
+        $c->res->headers->location($loc_based->to_abs);
+      };
+
       # Workaround for a proxy problem when
       # another proxy, e.g. Apache, manages multiple
       # connections
diff --git a/t/proxy.t b/t/proxy.t
index 7c54127..1dc1d08 100644
--- a/t/proxy.t
+++ b/t/proxy.t
@@ -118,5 +118,22 @@
   ->content_is('Proxy error: Inactivity timeout')
   ;
 
+$t->get_ok('/api/v1.0/redirect-target-a')
+  ->status_is(200)
+  ->content_is('Redirect Target!')
+  ;
+
+$t->get_ok('/api/v1.0/redirect')
+  ->status_is(308)
+  ->content_is('')
+  ;
+
+$t->ua->max_redirects(2);
+
+$t->get_ok('/api/v1.0/redirect')
+  ->status_is(200)
+  ->content_is('Redirect Target!')
+  ;
+
 done_testing;
 __END__
diff --git a/t/server/mock.pl b/t/server/mock.pl
index 2e14035..a1f0596 100644
--- a/t/server/mock.pl
+++ b/t/server/mock.pl
@@ -100,6 +100,20 @@
 };
 
 
+get '/v1.0/redirect-target-a' => sub {
+  shift->render(text => 'Redirect Target!');
+} => 'redirect-target';
+
+
+# Base page
+get '/v1.0/redirect' => sub {
+  my $c = shift;
+  $c->res->code(308);
+  $c->res->headers->location($c->url_for('redirect-target')->to_abs);
+  return $c->render(text => '');
+};
+
+
 # Search fixtures
 get '/v1.0/search' => sub {
   my $c = shift;