Bug 1228754, r=mak r=bz, a=sylvestre
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Mon, 22 Feb 2016 09:32:11 +0000
changeset 313190 80ce3f1ffe03
parent 313189 4a5d8ade4e3e
child 313191 20afdf1337fc
push id1040
push userraliiev@mozilla.com
push date2016-02-29 17:11 +0000
treeherdermozilla-release@8c3167321162 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmak, bz, sylvestre
bugs1228754
milestone45.0
Bug 1228754, r=mak r=bz, a=sylvestre

MozReview-Commit-ID: IGGW2RGiN3u
browser/base/content/browser.js
browser/base/content/test/urlbar/browser.ini
browser/base/content/test/urlbar/browser_urlbar_blanking.js
browser/base/content/test/urlbar/file_blank_but_not_blank.html
browser/base/moz.build
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2417,20 +2417,22 @@ function URLBarSetURI(aURI) {
     let uri = aURI || gBrowser.currentURI;
     // Strip off "wyciwyg://" and passwords for the location bar
     try {
       uri = Services.uriFixup.createExposableURI(uri);
     } catch (e) {}
 
     // Replace initial page URIs with an empty string
     // only if there's no opener (bug 370555).
-    if (gInitialPages.indexOf(uri.spec) != -1)
-      value = gBrowser.selectedBrowser.hasContentOpener ? uri.spec : "";
-    else
+    if (gInitialPages.indexOf(uri.spec) != -1 &&
+        checkEmptyPageOrigin(gBrowser.selectedBrowser, uri)) {
+      value = "";
+    } else {
       value = losslessDecodeURI(uri);
+    }
 
     valid = !isBlankPageURL(uri.spec);
   }
 
   gURLBar.value = value;
   gURLBar.valueIsTyped = !valid;
   SetPageProxyState(valid ? "valid" : "invalid");
 }
@@ -4497,17 +4499,17 @@ var XULBrowserWindow = {
     this.hideOverLinkImmediately = false;
 
     // We should probably not do this if the value has changed since the user
     // searched
     // Update urlbar only if a new page was loaded on the primary content area
     // Do not update urlbar if there was a subframe navigation
 
     if (aWebProgress.isTopLevel) {
-      if ((location == "about:blank" && !gBrowser.selectedBrowser.hasContentOpener) ||
+      if ((location == "about:blank" && checkEmptyPageOrigin()) ||
           location == "") {  // Second condition is for new tabs, otherwise
                              // reload function is enabled until tab is refreshed.
         this.reloadCommand.setAttribute("disabled", "true");
       } else {
         this.reloadCommand.removeAttribute("disabled");
       }
 
       if (gURLBar) {
@@ -6604,25 +6606,76 @@ function undoCloseWindow(aIndex) {
 function isTabEmpty(aTab) {
   if (aTab.hasAttribute("busy"))
     return false;
 
   let browser = aTab.linkedBrowser;
   if (!isBlankPageURL(browser.currentURI.spec))
     return false;
 
-  if (browser.hasContentOpener)
+  if (!checkEmptyPageOrigin(browser))
     return false;
 
   if (browser.canGoForward || browser.canGoBack)
     return false;
 
   return true;
 }
 
+/**
+ * Check whether a page can be considered as 'empty', that its URI
+ * reflects its origin, and that if it's loaded in a tab, that tab
+ * could be considered 'empty' (e.g. like the result of opening
+ * a 'blank' new tab).
+ *
+ * We have to do more than just check the URI, because especially
+ * for things like about:blank, it is possible that the opener or
+ * some other page has control over the contents of the page.
+ *
+ * @param browser {Browser}
+ *        The browser whose page we're checking (the selected browser
+ *        in this window if omitted).
+ * @param uri {nsIURI}
+ *        The URI against which we're checking (the browser's currentURI
+ *        if omitted).
+ *
+ * @return false if the page was opened by or is controlled by arbitrary web
+ *         content, unless that content corresponds with the URI.
+ *         true if the page is blank and controlled by a principal matching
+ *         that URI (or the system principal if the principal has no URI)
+ */
+function checkEmptyPageOrigin(browser = gBrowser.selectedBrowser,
+                              uri = browser.currentURI) {
+  // If another page opened this page with e.g. window.open, this page might
+  // be controlled by its opener - return false.
+  if (browser.hasContentOpener) {
+    return false;
+  }
+  let contentPrincipal = browser.contentPrincipal;
+  if (gMultiProcessBrowser && browser.isRemoteBrowser &&
+      !contentPrincipal && uri.spec == "about:blank") {
+    // Need to specialcase this because of how stopping an about:blank
+    // load from chrome on e10s causes a permanently null contentPrincipal,
+    // see bug 1249362.
+    return true;
+  }
+  // Not all principals have URIs...
+  if (contentPrincipal.URI) {
+    // A manually entered about:blank URI is slightly magical:
+    if (uri.spec == "about:blank" && contentPrincipal.isNullPrincipal) {
+      return true;
+    }
+    return contentPrincipal.URI.equals(uri);
+  }
+  // ... so for those that don't have them, enforce that the page has the
+  // system principal (this matches e.g. on about:newtab).
+  let ssm = Services.scriptSecurityManager;
+  return ssm.isSystemPrincipal(contentPrincipal);
+}
+
 function BrowserOpenSyncTabs() {
   if (Services.prefs.getBoolPref("services.sync.syncedTabsUIRefresh")) {
     gSyncUI.openSyncedTabsPanel();
   } else {
     switchToTabHavingURI("about:sync-tabs", true);
   }
 }
 
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser.ini
@@ -0,0 +1,3 @@
+[browser_urlbar_blanking.js]
+support-files =
+  file_blank_but_not_blank.html
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/urlbar/browser_urlbar_blanking.js
@@ -0,0 +1,35 @@
+"use strict";
+
+add_task(function*() {
+  for (let page of gInitialPages) {
+    if (page == "about:newtab") {
+      // New tab preloading makes this a pain to test, so skip
+      continue;
+    }
+    let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, page);
+    ok(!gURLBar.value, "The URL bar should be empty if we load a plain " + page + " page.");
+    yield BrowserTestUtils.removeTab(tab);
+  }
+});
+
+add_task(function*() {
+  const URI = "http://www.example.com/browser/browser/base/content/test/urlbar/file_blank_but_not_blank.html";
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, URI);
+  is(gURLBar.value, URI, "The URL bar should match the URI");
+  let browserLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+  ContentTask.spawn(tab.linkedBrowser, null, function() {
+    content.document.querySelector('a').click();
+  });
+  yield browserLoaded;
+  ok(gURLBar.value.startsWith("javascript"), "The URL bar should have the JS URI");
+  // When reloading, the javascript: uri we're using will throw an exception.
+  // That's deliberate, so we need to tell mochitest to ignore it:
+  SimpleTest.expectUncaughtException(true);
+  yield ContentTask.spawn(tab.linkedBrowser, null, function*() {
+    // This is sync, so by the time we return we should have changed the URL bar.
+    content.location.reload();
+  });
+  ok(!!gURLBar.value, "URL bar should not be blank.");
+  yield BrowserTestUtils.removeTab(tab);
+  SimpleTest.expectUncaughtException(false);
+});
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/urlbar/file_blank_but_not_blank.html
@@ -0,0 +1,2 @@
+<script>var q = 1;</script>
+<a href="javascript:q">Click me</a>
--- a/browser/base/moz.build
+++ b/browser/base/moz.build
@@ -18,16 +18,17 @@ BROWSER_CHROME_MANIFESTS += [
     'content/test/alerts/browser.ini',
     'content/test/chat/browser.ini',
     'content/test/general/browser.ini',
     'content/test/newtab/browser.ini',
     'content/test/plugins/browser.ini',
     'content/test/popupNotifications/browser.ini',
     'content/test/referrer/browser.ini',
     'content/test/social/browser.ini',
+    'content/test/urlbar/browser.ini',
 ]
 
 DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
 DEFINES['MOZ_APP_VERSION_DISPLAY'] = CONFIG['MOZ_APP_VERSION_DISPLAY']
 
 DEFINES['APP_LICENSE_BLOCK'] = '%s/content/overrides/app-license.html' % SRCDIR
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3', 'cocoa'):