Add general proxy support (fixes #259)

Change-Id: I63a3eb1e14a35067522fa8ee9efc905059dea087
diff --git a/lib/Kalamar.pm b/lib/Kalamar.pm
index 462e9ba..313055a 100644
--- a/lib/Kalamar.pm
+++ b/lib/Kalamar.pm
@@ -400,8 +400,32 @@
   $r->get('/contact')->mail_to_chiffre('documentation#contact');
 
   # API proxy route
-  $r->any('/api/v#apiv' => [apiv => ['1.0']])->name('proxy')->to('Proxy#pass');
-  $r->any('/api/v#apiv/*api_path' => [apiv => ['1.0']])->to('Proxy#pass');
+  $r->any('/api/v#apiv' => [apiv => ['1.0']])->name('proxy')->to('Proxy#api_pass');
+  $r->any('/api/v#apiv/*proxy_path' => [apiv => ['1.0']])->to('Proxy#api_pass');
+
+  # General proxy mounts
+  my $proxies = $conf->{'proxies'} // [];
+  foreach (@$proxies) {
+    next if $_ eq 'PROXY_STUB';
+
+    my $root_path = Mojo::Path->new($_->{root_path})
+      ->canonicalize->leading_slash(1)
+      ->trailing_slash(1);
+
+    my %stash_hash = (
+      service   => $_->{service},
+      root_path => $root_path,
+      mount     => $_->{mount},
+    );
+
+    $r->any($root_path)->name($_->{service})->to(
+      'Proxy#pass', %stash_hash
+    );
+
+    $r->any($root_path . '*proxy_path')->to(
+      'Proxy#pass', %stash_hash
+    );
+  };
 
   # Match route
   # Corpus route
diff --git a/lib/Kalamar/Controller/Proxy.pm b/lib/Kalamar/Controller/Proxy.pm
index 675a06a..18e6c30 100644
--- a/lib/Kalamar/Controller/Proxy.pm
+++ b/lib/Kalamar/Controller/Proxy.pm
@@ -1,12 +1,34 @@
 package Kalamar::Controller::Proxy;
 use Mojo::Base 'Mojolicious::Controller';
 
-# Pass proxy command to API
-sub pass {
+sub api_pass {
   my $c = shift;
 
   my $apiv = $c->stash('apiv');
-  my $path = $c->stash('api_path') // '';
+
+  # Get API request for proxying
+  # External URL!
+  my $base_url = Mojo::URL->new($c->korap->api($apiv));
+  $c->stash('root_path', $base_url->to_string);
+
+  $c->stash(service => 'proxy');
+
+  return $c->pass($base_url);
+};
+
+# Pass proxy command to API
+sub pass {
+  my $c = shift;
+  my $base_url = shift // Mojo::URL->new($c->stash('mount'));
+
+  my $base_path = $base_url->path->trailing_slash(1);
+
+  my $proxy_path = Mojo::Path->new(
+    $c->stash('proxy_path') ? $c->stash('proxy_path') : ''
+  )->leading_slash(0);
+
+  $base_path = $base_path->merge($proxy_path);
+  $base_url = $base_url->path($base_path);
 
   # Get the original request
   my $req = $c->req;
@@ -25,8 +47,7 @@
   # Get parameters of the request
   my $params = $req->query_params->clone;
 
-  # Get API request for proxying
-  my $url = Mojo::URL->new($c->korap->api($apiv))->path($path)->query($params);
+  my $url = $base_url->query($params);
 
   # Resend headers
   my $tx = $c->kalamar_ua->build_tx(
@@ -39,15 +60,16 @@
     before_korap_request => ($c, $tx)
   );
 
-  my $h = $c->res->headers;
-  $h->access_control_allow_origin('*');
+  my $origin = $c->req->headers->origin;
 
   # Retrieve CORS header
   if ($c->req->method eq 'OPTIONS') {
 
+    my $h = $c->res->headers;
     # Remember this option for a day
     $h->header('Access-Control-Max-Age' => '86400');
     $h->header('Access-Control-Allow-Headers' => '*');
+    $h->header('Access-Control-Allow-Origin', $origin || '*');
     $h->header('Access-Control-Allow-Methods' => 'GET, OPTIONS');
     return $c->render(
       status => 204,
@@ -75,7 +97,7 @@
       my $h = $c->res->headers;
       $h->header('X-Proxy' => 'Kalamar');
       $h->header('X-Robots' => 'noindex');
-      $h->access_control_allow_origin('*');
+      $h->header('Access-Control-Allow-Origin', $origin || '*');
       $h->header('Access-Control-Allow-Methods' => 'GET, OPTIONS');
 
       # Response is a redirect
@@ -83,16 +105,16 @@
 
         # Rewrite redirect location to surface URL
         my $location_url = $h->location;
-        my $base_url = Mojo::URL->new($c->korap->api)->to_abs->to_string;
+        my $root_path = $c->stash('root_path');
 
         # Remove the api part
         # ".*?" is just required for non-absolute base_urls
-        $location_url =~ s/^.*?${base_url}//;
+        $location_url =~ s/^.*?${root_path}//;
 
         # Turn the rewritten location into a URL object
         $location_url = Mojo::URL->new($location_url);
 
-        my $proxy_url = $c->url_for('proxy');
+        my $proxy_url = $c->url_for($c->stash('service') || 'proxy');
         $proxy_url->path->trailing_slash(1);
 
         # Rebase to proxy path