Fix PolyGerrit URLs to support prefixed URL

This updates most of polygerrit links to use the implementation added in
I2b2d704fe33c90ea2f2a2183fc79897642a48175 .

Change-Id: Ib3bb694969e903fd76a1dad13cfb642bde086142
diff --git a/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/raw/index.html.soy b/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/raw/index.html.soy
index 7b828b6..4d8c43b 100644
--- a/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/raw/index.html.soy
+++ b/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/raw/index.html.soy
@@ -27,6 +27,8 @@
   <meta name="description" content="Gerrit Code Review">{\n}
   <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">{\n}
 
+  <script>window.CANONICAL_PATH = '{$canonicalPath}';</script>{\n}
+
   // SourceCodePro fonts are used in styles/fonts.css
   // @see https://github.com/w3c/preload/issues/32 regarding crossorigin
   <link rel="preload" href="{$staticResourcePath}/fonts/SourceCodePro-Regular.woff2" as="font" type="font/woff2" crossorigin>{\n}
diff --git a/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior.html b/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior.html
new file mode 100644
index 0000000..2ec8538
--- /dev/null
+++ b/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior.html
@@ -0,0 +1,37 @@
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<script>
+(function(window) {
+  'use strict';
+
+  /** @polymerBehavior Gerrit.BaseUrlBehavior */
+  var BaseUrlBehavior = {
+    getBaseUrl: function() {
+      return window.CANONICAL_PATH || '';
+    },
+
+    computeGwtUrl: function(path) {
+      var base = this.getBaseUrl();
+      var clientPath = path.substring(base.length);
+      return base + '/?polygerrit=0#' + clientPath;
+    },
+  };
+
+  window.Gerrit = window.Gerrit || {};
+  window.Gerrit.BaseUrlBehavior = BaseUrlBehavior;
+})(window);
+</script>
diff --git a/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior_test.html b/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior_test.html
new file mode 100644
index 0000000..1e277bc
--- /dev/null
+++ b/polygerrit-ui/app/behaviors/base-url-behavior/base-url-behavior_test.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+<title>keyboard-shortcut-behavior</title>
+
+<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
+<script src="../../bower_components/web-component-tester/browser.js"></script>
+
+<link rel="import" href="../../bower_components/iron-test-helpers/iron-test-helpers.html">
+<script>
+  window.CANONICAL_PATH = '/r';
+</script>
+<link rel="import" href="base-url-behavior.html">
+
+<test-fixture id="basic">
+  <template>
+    <test-element></test-element>
+  </template>
+</test-fixture>
+
+<test-fixture id="within-overlay">
+  <template>
+    <gr-overlay>
+      <test-element></test-element>
+    </gr-overlay>
+  </template>
+</test-fixture>
+
+<script>
+  suite('base-url-behavior tests', function() {
+    var element;
+    var overlay;
+
+    suiteSetup(function() {
+      // Define a Polymer element that uses this behavior.
+      Polymer({
+        is: 'test-element',
+        behaviors: [
+          Gerrit.BaseUrlBehavior,
+        ],
+      });
+    });
+
+    setup(function() {
+      element = fixture('basic');
+      overlay = fixture('within-overlay');
+    });
+
+    test('getBaseUrl', function() {
+      assert.deepEqual(element.getBaseUrl(), '/r');
+    });
+
+    test('computeGwtUrl', function() {
+      assert.deepEqual(
+        element.computeGwtUrl('/r/c/1/'),
+        '/r/?polygerrit=0#/c/1/'
+      );
+    });
+  });
+</script>
\ No newline at end of file
diff --git a/polygerrit-ui/app/behaviors/rest-client-behavior.html b/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior.html
similarity index 90%
rename from polygerrit-ui/app/behaviors/rest-client-behavior.html
rename to polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior.html
index b7cf467..f71fe8f 100644
--- a/polygerrit-ui/app/behaviors/rest-client-behavior.html
+++ b/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior.html
@@ -13,7 +13,8 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
-<link rel="import" href="../bower_components/polymer/polymer.html">
+<link rel="import" href="../../bower_components/polymer/polymer.html">
+<link rel="import" href="../base-url-behavior/base-url-behavior.html">
 <script>
 (function(window) {
   'use strict';
@@ -99,7 +100,7 @@
     },
 
     changeBaseURL: function(changeNum, patchNum) {
-      var v = '/changes/' + changeNum;
+      var v =  this.getBaseUrl() + '/changes/' + changeNum;
       if (patchNum) {
         v += '/revisions/' + patchNum;
       }
@@ -107,7 +108,7 @@
     },
 
     changePath: function(changeNum) {
-      return '/c/' + changeNum;
+      return this.getBaseUrl() + '/c/' + changeNum;
     },
 
     changeIsOpen: function(status) {
@@ -134,6 +135,9 @@
   };
 
   window.Gerrit = window.Gerrit || {};
-  window.Gerrit.RESTClientBehavior = RESTClientBehavior;
+  window.Gerrit.RESTClientBehavior = [
+    Gerrit.BaseUrlBehavior,
+    RESTClientBehavior
+  ];
 })(window);
 </script>
diff --git a/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior_test.html b/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior_test.html
new file mode 100644
index 0000000..2b3e858
--- /dev/null
+++ b/polygerrit-ui/app/behaviors/rest-client-behavior/rest-client-behavior_test.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+<title>keyboard-shortcut-behavior</title>
+
+<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
+<script src="../../bower_components/web-component-tester/browser.js"></script>
+<script>
+  window.CANONICAL_PATH = '/r';
+</script>
+
+<link rel="import" href="../../bower_components/iron-test-helpers/iron-test-helpers.html">
+<link rel="import" href="../base-url-behavior/base-url-behavior.html">
+<link rel="import" href="rest-client-behavior.html">
+
+<test-fixture id="basic">
+  <template>
+    <test-element></test-element>
+  </template>
+</test-fixture>
+
+<test-fixture id="within-overlay">
+  <template>
+    <gr-overlay>
+      <test-element></test-element>
+    </gr-overlay>
+  </template>
+</test-fixture>
+
+<script>
+  suite('rest-client-behavior tests', function() {
+    var element;
+    var overlay;
+
+    suiteSetup(function() {
+      // Define a Polymer element that uses this behavior.
+      Polymer({
+        is: 'test-element',
+        behaviors: [
+          Gerrit.BaseUrlBehavior,
+          Gerrit.RESTClientBehavior,
+        ],
+      });
+    });
+
+    setup(function() {
+      element = fixture('basic');
+      overlay = fixture('within-overlay');
+    });
+
+    test('changeBaseURL', function() {
+      assert.deepEqual(
+        element.changeBaseURL('1', '1'),
+        '/r/changes/1/revisions/1'
+      );
+    });
+
+    test('changePath', function() {
+      assert.deepEqual(element.changePath('1'), '/r/c/1');
+    });
+  });
+</script>
\ No newline at end of file
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
index 8e2b192..d50e0b3 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
@@ -13,9 +13,10 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 <link rel="import" href="../../../behaviors/gr-change-table-behavior/gr-change-table-behavior.html">
 <link rel="import" href="../../../behaviors/gr-url-encoding-behavior.html">
-<link rel="import" href="../../../behaviors/rest-client-behavior.html">
+<link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../../styles/gr-change-list-styles.html">
 <link rel="import" href="../../shared/gr-account-link/gr-account-link.html">
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
index 280de86..566dfe0 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
@@ -34,6 +34,7 @@
     },
 
     behaviors: [
+      Gerrit.BaseUrlBehavior,
       Gerrit.ChangeTableBehavior,
       Gerrit.RESTClientBehavior,
       Gerrit.URLEncodingBehavior,
@@ -41,7 +42,7 @@
 
     _computeChangeURL: function(changeNum) {
       if (!changeNum) { return ''; }
-      return '/c/' + changeNum + '/';
+      return this.getBaseUrl() + '/c/' + changeNum + '/';
     },
 
     _computeLabelTitle: function(change, labelName) {
@@ -101,7 +102,7 @@
     },
 
     _computeProjectURL: function(project) {
-      return '/q/status:open+project:' +
+      return this.getBaseUrl() + '/q/status:open+project:' +
           this.encodeURL(project, false);
     },
 
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.html b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.html
index c9a8d64..8a95fa8 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.html
@@ -14,10 +14,10 @@
 limitations under the License.
 -->
 
-<link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../../behaviors/gr-change-table-behavior/gr-change-table-behavior.html">
 <link rel="import" href="../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html">
-<link rel="import" href="../../../behaviors/rest-client-behavior.html">
+<link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html">
+<link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../../styles/gr-change-list-styles.html">
 <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 <link rel="import" href="../gr-change-list-item/gr-change-list-item.html">
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
index 05306ae..71ccb04 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
@@ -14,9 +14,9 @@
 limitations under the License.
 -->
 
+<link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../../bower_components/iron-input/iron-input.html">
-<link rel="import" href="../../../behaviors/rest-client-behavior.html">
 
 <link rel="import" href="../../shared/gr-button/gr-button.html">
 <link rel="import" href="../../shared/gr-dropdown/gr-dropdown.html">
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.html b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.html
index 5f11219..4ecd4b7 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.html
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.html
@@ -14,9 +14,10 @@
 limitations under the License.
 -->
 
-<link rel="import" href="../../../bower_components/polymer/polymer.html">
-<link rel="import" href="../../../behaviors/rest-client-behavior.html">
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 <link rel="import" href="../../../behaviors/gr-url-encoding-behavior.html">
+<link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html">
+<link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../shared/gr-account-chip/gr-account-chip.html">
 <link rel="import" href="../../shared/gr-label/gr-label.html">
 <link rel="import" href="../../shared/gr-date-formatter/gr-date-formatter.html">
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
index 6caed12..834069e 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
@@ -47,6 +47,7 @@
     },
 
     behaviors: [
+      Gerrit.BaseUrlBehavior,
       Gerrit.RESTClientBehavior,
       Gerrit.URLEncodingBehavior,
     ],
@@ -234,7 +235,8 @@
     },
 
     _computeProjectURL: function(project) {
-      return '/q/status:open+project:' + this.encodeURL(project, false);
+      return this.getBaseUrl() + '/q/status:open+project:' +
+        this.encodeURL(project, false);
     },
 
     _computeBranchURL: function(project, branch) {
@@ -244,15 +246,16 @@
       } else {
         status = this.change.status.toLowerCase();
       }
-      return '/q/project:' + this.encodeURL(project, false) +
+      return this.getBaseUrl() + '/q/project:' +
+        this.encodeURL(project, false) +
           ' branch:' + this.encodeURL(branch, false) +
-          ' status:' + this.encodeURL(status, false);
+              ' status:' + this.encodeURL(status, false);
     },
 
     _computeTopicHref: function(topic) {
       var encodedTopic = encodeURIComponent('\"' + topic + '\"');
-      return '/q/topic:' + encodeURIComponent(encodedTopic) +
-          '+(status:open OR status:merged)';
+      return this.getBaseUrl() + '/q/topic:' +
+        encodeURIComponent(encodedTopic) + '+(status:open OR status:merged)';
     },
 
     _handleTopicRemoved: function() {
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
index 22f742d..cec9487 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
@@ -14,10 +14,11 @@
 limitations under the License.
 -->
 
-<link rel="import" href="../../../bower_components/polymer/polymer.html">
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 <link rel="import" href="../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.html">
 <link rel="import" href="../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html">
-<link rel="import" href="../../../behaviors/rest-client-behavior.html">
+<link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html">
+<link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../shared/gr-account-link/gr-account-link.html">
 <link rel="import" href="../../shared/gr-select/gr-select.html">
 <link rel="import" href="../../shared/gr-button/gr-button.html">
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
index 8a317ab..8ce7a83 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
@@ -162,6 +162,7 @@
     },
 
     behaviors: [
+      Gerrit.BaseUrlBehavior,
       Gerrit.KeyboardShortcutBehavior,
       Gerrit.PatchSetBehavior,
       Gerrit.RESTClientBehavior,
@@ -588,7 +589,7 @@
     },
 
     _computeChangePermalink: function(changeNum) {
-      return '/' + changeNum;
+      return this.getBaseUrl() + '/' + changeNum;
     },
 
     _computeChangeStatus: function(change, patchNum) {
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html
index 08e2e21..c38cf18 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.html
@@ -14,6 +14,7 @@
 limitations under the License.
 -->
 
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 <link rel="import" href="../../../behaviors/gr-path-list-behavior/gr-path-list-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../shared/gr-formatted-text/gr-formatted-text.html">
diff --git a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
index ecd4dcc..f1fb0fd 100644
--- a/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
+++ b/polygerrit-ui/app/elements/change/gr-comment-list/gr-comment-list.js
@@ -16,7 +16,11 @@
 
   Polymer({
     is: 'gr-comment-list',
-    behaviors: [Gerrit.PathListBehavior],
+
+    behaviors: [
+      Gerrit.BaseUrlBehavior,
+      Gerrit.PathListBehavior,
+    ],
 
     properties: {
       changeNum: Number,
@@ -31,7 +35,8 @@
     },
 
     _computeFileDiffURL: function(file, changeNum, patchNum) {
-      return '/c/' + changeNum + '/' + patchNum + '/' + file;
+      return this.getBaseUrl() + '/c/' + changeNum +
+        '/' + patchNum + '/' + file;
     },
 
     _isOnParent: function(comment) {
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.html b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.html
index bcd9053..0e97d36 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.html
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.html
@@ -14,9 +14,9 @@
 limitations under the License.
 -->
 
+<link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../../bower_components/iron-input/iron-input.html">
-<link rel="import" href="../../../behaviors/rest-client-behavior.html">
 <link rel="import" href="../../shared/gr-button/gr-button.html">
 <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
index 75d86f4..b20c82c 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
@@ -14,6 +14,7 @@
 limitations under the License.
 -->
 
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 <link rel="import" href="../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html">
 <link rel="import" href="../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.html">
 <link rel="import" href="../../../behaviors/gr-url-encoding-behavior.html">
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
index d06a695..73dd969 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.js
@@ -111,6 +111,7 @@
     },
 
     behaviors: [
+      Gerrit.BaseUrlBehavior,
       Gerrit.KeyboardShortcutBehavior,
       Gerrit.PatchSetBehavior,
       Gerrit.URLEncodingBehavior,
@@ -604,7 +605,7 @@
     },
 
     _computeDiffURL: function(changeNum, patchRange, path) {
-      return this.encodeURL('/c/' + changeNum + '/' +
+      return this.encodeURL(this.getBaseUrl() + '/c/' + changeNum + '/' +
           this._patchRangeStr(patchRange) + '/' + path, true);
     },
 
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.html b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.html
index e7d7cf9..c9d5cd8 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.html
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.html
@@ -14,8 +14,9 @@
 limitations under the License.
 -->
 
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
+<link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
-<link rel="import" href="../../../behaviors/rest-client-behavior.html">
 <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 
 <dom-module id="gr-related-changes-list">
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
index 5a9642e..8501b20 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
@@ -62,6 +62,7 @@
     },
 
     behaviors: [
+      Gerrit.BaseUrlBehavior,
       Gerrit.RESTClientBehavior,
     ],
 
@@ -160,7 +161,7 @@
     },
 
     _computeChangeURL: function(changeNum, patchNum) {
-      var urlStr = '/c/' + changeNum;
+      var urlStr = this.getBaseUrl() + '/c/' + changeNum;
       if (patchNum != null) {
         urlStr += '/' + patchNum;
       }
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.html b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.html
index f9ec01c..842de22 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.html
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.html
@@ -15,7 +15,7 @@
 -->
 
 <link rel="import" href="../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html">
-<link rel="import" href="../../../behaviors/rest-client-behavior.html">
+<link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../../bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html">
 <link rel="import" href="../../../bower_components/iron-selector/iron-selector.html">
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
index dc66bb6..1e6596b 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
@@ -14,6 +14,7 @@
 limitations under the License.
 -->
 
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 
 <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js
index c9abac2..487074e 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js
@@ -96,6 +96,10 @@
       },
     },
 
+    behaviors: [
+      Gerrit.BaseUrlBehavior,
+    ],
+
     observers: [
       '_accountLoaded(_account)',
     ],
@@ -114,14 +118,23 @@
     },
 
     _handleLocationChange: function(e) {
-      this._loginURL = '/login/' + encodeURIComponent(
-          window.location.pathname +
-          window.location.search +
-          window.location.hash);
+      if (this.getBaseUrl()) {
+        // Strip the canonical path from the path since needing canonical in
+        // the path is uneeded and breaks the url.
+        this._loginURL = this.getBaseUrl() + '/login/' + encodeURIComponent(
+            '/' + window.location.pathname.substring(this.getBaseUrl().length) +
+            window.location.search +
+            window.location.hash);
+      } else {
+        this._loginURL = '/login/' + encodeURIComponent(
+            window.location.pathname +
+            window.location.search +
+            window.location.hash);
+      }
     },
 
     _computeRelativeURL: function(path) {
-      return '//' + window.location.host + path;
+      return '//' + window.location.host + this.getBaseUrl() + path;
     },
 
     _computeLinks: function(defaultLinks, userLinks, adminLinks) {
diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.html b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.html
index d10567c..d5d33ab 100644
--- a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.html
+++ b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.html
@@ -14,6 +14,7 @@
 limitations under the License.
 -->
 
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../shared/gr-js-api-interface/gr-js-api-interface.html">
 
diff --git a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js
index 780f3b9..1f96014 100644
--- a/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js
+++ b/polygerrit-ui/app/elements/core/gr-reporting/gr-reporting.js
@@ -79,6 +79,10 @@
       },
     },
 
+    behaviors: [
+      Gerrit.BaseUrlBehavior,
+    ],
+
     get performanceTiming() {
       return window.performance.timing;
     },
@@ -154,11 +158,11 @@
       var page = '';
       var pathname = this._getPathname();
       if (pathname.indexOf('/q/') === 0) {
-        page = '/q/';
+        page = this.getBaseUrl() + '/q/';
       } else if (pathname.match(CHANGE_VIEW_REGEX)) { // change view
-        page = '/c/';
+        page = this.getBaseUrl() + '/c/';
       } else if (pathname.match(DIFF_VIEW_REGEX)) { // diff view
-        page = '/c//COMMIT_MSG';
+        page = this.getBaseUrl() + '/c//COMMIT_MSG';
       } else {
         // Ignore other page changes.
         return;
@@ -172,7 +176,7 @@
     },
 
     _getPathname: function() {
-      return window.location.pathname;
+      return '/' + window.location.pathname.substring(this.getBaseUrl().length);
     },
 
     /**
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.html b/polygerrit-ui/app/elements/core/gr-router/gr-router.html
index bd79419..5a494b1 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.html
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.html
@@ -13,6 +13,7 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 <link rel="import" href="../gr-reporting/gr-reporting.html">
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.js b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
index eb650ca..1e3481f 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
@@ -33,6 +33,11 @@
     getReporting().pageLoaded();
   };
 
+  var base = window.Gerrit.BaseUrlBehavior.getBaseUrl();
+  if (base) {
+    page.base(base);
+  }
+
   window.addEventListener('WebComponentsReady', function() {
     getReporting().timeEnd('WebComponentsReady');
   });
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
index 9ec52d2..1204170 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
@@ -14,11 +14,12 @@
 limitations under the License.
 -->
 
-<link rel="import" href="../../../bower_components/polymer/polymer.html">
-<link rel="import" href="../../../bower_components/iron-dropdown/iron-dropdown.html">
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 <link rel="import" href="../../../behaviors/gr-url-encoding-behavior.html">
 <link rel="import" href="../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html">
-<link rel="import" href="../../../behaviors/rest-client-behavior.html">
+<link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html">
+<link rel="import" href="../../../bower_components/iron-dropdown/iron-dropdown.html">
+<link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../shared/gr-button/gr-button.html">
 <link rel="import" href="../../shared/gr-overlay/gr-overlay.html">
 <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
index b795d64..fcbbe23 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
@@ -106,6 +106,7 @@
     },
 
     behaviors: [
+      Gerrit.BaseUrlBehavior,
       Gerrit.KeyboardShortcutBehavior,
       Gerrit.RESTClientBehavior,
       Gerrit.URLEncodingBehavior,
@@ -502,8 +503,8 @@
     },
 
     _getDiffURL: function(changeNum, patchRange, path) {
-      return '/c/' + changeNum + '/' + this._patchRangeStr(patchRange) + '/' +
-          this.encodeURL(path, true);
+      return this.getBaseUrl() + '/c/' + changeNum + '/' +
+          this._patchRangeStr(patchRange) + '/' + this.encodeURL(path, true);
     },
 
     _computeDiffURL: function(changeNum, patchRangeRecord, path) {
@@ -528,7 +529,7 @@
     },
 
     _getChangePath: function(changeNum, patchRange, revisions) {
-      var base = '/c/' + changeNum + '/';
+      var base = this.getBaseUrl() + '/c/' + changeNum + '/';
 
       // The change may not have loaded yet, making revisions unavailable.
       if (!revisions) {
diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html
index 6811397..bc88b14 100644
--- a/polygerrit-ui/app/elements/gr-app.html
+++ b/polygerrit-ui/app/elements/gr-app.html
@@ -14,8 +14,9 @@
 limitations under the License.
 -->
 
-<link rel="import" href="../bower_components/polymer/polymer.html">
+<link rel="import" href="../behaviors/base-url-behavior/base-url-behavior.html">
 <link rel="import" href="../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html">
+<link rel="import" href="../bower_components/polymer/polymer.html">
 <link rel="import" href="../styles/app-theme.html">
 <link rel="import" href="./plugins/gr-plugin-host/gr-plugin-host.html">
 
@@ -151,7 +152,7 @@
             rel="noopener" target="_blank">Send feedback</a>
         <template is="dom-if" if="[[_computeShowGwtUiLink(_serverConfig)]]">
           |
-          <a id="gwtLink" href$="/?polygerrit=0#[[_path]]" rel="external">Old UI</a>
+          <a id="gwtLink" href$="[[computeGwtUrl(_path)]]" rel="external">Old UI</a>
         </template>
         | Press &ldquo;?&rdquo; for keyboard shortcuts
       </div>
diff --git a/polygerrit-ui/app/elements/gr-app.js b/polygerrit-ui/app/elements/gr-app.js
index c24e2aa..acf38c7 100644
--- a/polygerrit-ui/app/elements/gr-app.js
+++ b/polygerrit-ui/app/elements/gr-app.js
@@ -71,6 +71,7 @@
     ],
 
     behaviors: [
+      Gerrit.BaseUrlBehavior,
       Gerrit.KeyboardShortcutBehavior,
     ],
 
diff --git a/polygerrit-ui/app/elements/gr-app_test.html b/polygerrit-ui/app/elements/gr-app_test.html
index 5aacc77..2eb835d 100644
--- a/polygerrit-ui/app/elements/gr-app_test.html
+++ b/polygerrit-ui/app/elements/gr-app_test.html
@@ -72,8 +72,10 @@
       element._path = '/test/path';
       flush(function() {
         var gwtLink = element.$$('#gwtLink');
-        assert.equal(gwtLink.href,
-            'http://' + location.host + '/?polygerrit=0#/test/path');
+        assert.equal(
+          gwtLink.href,
+          'http://' + location.host + element.getBaseUrl() + '/?polygerrit=0#/test/path'
+        );
         done();
       });
     });
@@ -89,8 +91,11 @@
 
       flush(function() {
         var gwtLink = element.$$('#gwtLink');
-        assert.equal(gwtLink.href,
-            'http://' + location.host + '/?polygerrit=0#/c/1/1/testfile.txt@2');
+        assert.equal(
+          gwtLink.href,
+          'http://' + location.host + element.getBaseUrl() +
+            '/?polygerrit=0#/c/1/1/testfile.txt@2'
+        );
         done();
       });
     });
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.html b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.html
index 8d89692..20b6e3f 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.html
@@ -14,6 +14,7 @@
 limitations under the License.
 -->
 
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../gr-account-label/gr-account-label.html">
 
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js
index 3ff4ace..69beb78 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.js
@@ -25,10 +25,14 @@
       },
     },
 
+    behaviors: [
+      Gerrit.BaseUrlBehavior,
+    ],
+
     _computeOwnerLink: function(account) {
       if (!account) { return; }
       var accountID = account.email || account._account_id;
-      return '/q/owner:' + encodeURIComponent(accountID);
+      return this.getBaseUrl() + '/q/owner:' + encodeURIComponent(accountID);
     },
 
     _computeShowEmail: function(account) {
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
index db07de4..0a555cf 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
@@ -14,6 +14,7 @@
 limitations under the License.
 -->
 
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <link rel="import" href="../../../bower_components/iron-dropdown/iron-dropdown.html">
 <link rel="import" href="../../shared/gr-button/gr-button.html">
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
index 9b87f03..e84357f 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.js
@@ -56,6 +56,10 @@
       _hasAvatars: String,
     },
 
+    behaviors: [
+      Gerrit.BaseUrlBehavior,
+    ],
+
     attached: function() {
       this.$.restAPI.getConfig().then(function(cfg) {
         this._hasAvatars = !!(cfg && cfg.plugin && cfg.plugin.has_avatars);
@@ -79,7 +83,7 @@
     },
 
     _computeURLHelper: function(host, path) {
-      return '//' + host + path;
+      return '//' + host + this.getBaseUrl() + path;
     },
 
     _computeRelativeURL: function(path) {
diff --git a/polygerrit-ui/app/elements/shared/gr-placeholder/gr-placeholder.html b/polygerrit-ui/app/elements/shared/gr-placeholder/gr-placeholder.html
index 2e624cc..2c8be31a 100644
--- a/polygerrit-ui/app/elements/shared/gr-placeholder/gr-placeholder.html
+++ b/polygerrit-ui/app/elements/shared/gr-placeholder/gr-placeholder.html
@@ -14,6 +14,7 @@
 limitations under the License.
 -->
 
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 
 <dom-module id="gr-placeholder">
@@ -44,7 +45,7 @@
       <h1>[[title]]</h1>
       <section>
         This page is not yet implemented in PolyGerrit. View it in the
-        <a id="gwtLink" href$="/?polygerrit=0#[[path]]" rel="external">
+        <a id="gwtLink" href$="[[computeGwtUrl(path)]]" rel="external">
         Old UI</a>
       </section>
     </main>
diff --git a/polygerrit-ui/app/elements/shared/gr-placeholder/gr-placeholder.js b/polygerrit-ui/app/elements/shared/gr-placeholder/gr-placeholder.js
index 0ea2979..9b60061 100644
--- a/polygerrit-ui/app/elements/shared/gr-placeholder/gr-placeholder.js
+++ b/polygerrit-ui/app/elements/shared/gr-placeholder/gr-placeholder.js
@@ -21,5 +21,9 @@
       path: String,
       title: String,
     },
+
+    behaviors: [
+      Gerrit.BaseUrlBehavior,
+    ],
   });
 })();
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.html
index 07ff632..1e5fdaa 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.html
@@ -14,6 +14,7 @@
 limitations under the License.
 -->
 
+<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
 <link rel="import" href="../../../behaviors/gr-path-list-behavior/gr-path-list-behavior.html">
 <link rel="import" href="../../../bower_components/polymer/polymer.html">
 <script src="../../../bower_components/es6-promise/dist/es6-promise.min.js"></script>
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index 7cb29a1..0e3019a 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -82,7 +82,11 @@
 
   Polymer({
     is: 'gr-rest-api-interface',
-    behaviors: [Gerrit.PathListBehavior],
+
+    behaviors: [
+      Gerrit.BaseUrlBehavior,
+      Gerrit.PathListBehavior,
+    ],
 
     /**
      * Fired when an server error occurs.
@@ -152,7 +156,7 @@
     },
 
     _urlWithParams: function(url, opt_params) {
-      if (!opt_params) { return url; }
+      if (!opt_params) { return this.getBaseUrl() + url; }
 
       var params = [];
       for (var p in opt_params) {
@@ -167,7 +171,7 @@
             encodeURIComponent(values[i]));
         }
       }
-      return url + '?' + params.join('&');
+      return this.getBaseUrl() + url + '?' + params.join('&');
     },
 
     getResponseObject: function(response) {
@@ -694,7 +698,7 @@
         }
         options.body = opt_body;
       }
-      return fetch(url, options).then(function(response) {
+      return fetch(this.getBaseUrl() + url, options).then(function(response) {
         if (!response.ok) {
           if (opt_errFn) {
             opt_errFn.call(opt_ctx || null, response);
@@ -907,7 +911,7 @@
     },
 
     _fetchB64File: function(url) {
-      return fetch(url, {credentials: 'same-origin'}).then(function(response) {
+      return fetch(this.getBaseUrl() + url, {credentials: 'same-origin'}).then(function(response) {
         var type = response.headers.get('X-FYI-Content-Type');
         return response.text()
           .then(function(text) {
diff --git a/polygerrit-ui/app/test/index.html b/polygerrit-ui/app/test/index.html
index ca50bbc..3770d4d 100644
--- a/polygerrit-ui/app/test/index.html
+++ b/polygerrit-ui/app/test/index.html
@@ -114,6 +114,8 @@
 
   // Behaviors tests.
   [
+    'base-url-behavior/base-url-behavior_test.html',
+    'rest-client-behavior/rest-client-behavior_test.html',
     'gr-change-table-behavior/gr-change-table-behavior_test.html',
     'gr-patch-set-behavior/gr-patch-set-behavior_test.html',
     'gr-path-list-behavior/gr-path-list-behavior_test.html',