Bug 1517703 - Part 2 - Use ReferrerInfo in loadURIOptions from js r=Gijs
authorThomas Nguyen <tnguyen@mozilla.com>
Tue, 12 Feb 2019 19:35:24 +0000
changeset 458782 586348ccba9b
parent 458781 64c8b805491a
child 458783 f1c16e2af72f
push id35548
push useropoprus@mozilla.com
push dateWed, 13 Feb 2019 09:48:26 +0000
treeherdermozilla-central@93e37c529818 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs
bugs1517703
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1517703 - Part 2 - Use ReferrerInfo in loadURIOptions from js r=Gijs Differential Revision: https://phabricator.services.mozilla.com/D17922
browser/base/content/browser.js
browser/base/content/tabbrowser.js
browser/base/content/utilityOverlay.js
browser/components/sessionstore/ContentRestore.jsm
browser/components/sessionstore/test/browser_491168.js
devtools/client/responsive.html/browser/web-navigation.js
toolkit/actors/WebNavigationChild.jsm
toolkit/components/reader/ReaderMode.jsm
toolkit/components/remotebrowserutils/RemoteWebNavigation.js
toolkit/components/remotebrowserutils/tests/browser/browser_RemoteWebNavigation.js
toolkit/components/viewsource/content/viewSource-content.js
toolkit/content/widgets/browser-custom-element.js
toolkit/modules/E10SUtils.jsm
toolkit/modules/sessionstore/SessionHistory.jsm
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1036,19 +1036,18 @@ function _createNullPrincipalFromTabUser
 // load a URI or redirect it to the correct process.
 function _loadURI(browser, uri, params = {}) {
   if (!uri) {
     uri = "about:blank";
   }
 
   let {
     flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
-    referrerURI,
-    referrerPolicy = Ci.nsIHttpChannel.REFERRER_POLICY_UNSET,
     triggeringPrincipal,
+    referrerInfo,
     postData,
     userContextId,
   } = params || {};
 
   if (!triggeringPrincipal) {
     throw new Error("Must load with a triggering Principal");
   }
 
@@ -1071,18 +1070,17 @@ function _loadURI(browser, uri, params =
 
   // !requiredRemoteType means we're loading in the parent/this process.
   if (!requiredRemoteType) {
     browser.inLoadURI = true;
   }
   let loadURIOptions = {
     triggeringPrincipal,
     loadFlags: flags,
-    referrerURI,
-    referrerPolicy,
+    referrerInfo,
     postData,
   };
   try {
     if (!mustChangeProcess) {
       if (userContextId) {
         browser.webNavigation.setOriginAttributesBeforeLoading({
           userContextId,
           privateBrowsingId: PrivateBrowsingUtils.isBrowserPrivate(browser) ? 1 : 0,
@@ -1101,18 +1099,17 @@ function _loadURI(browser, uri, params =
       }
 
       let loadParams = {
         uri,
         triggeringPrincipal: triggeringPrincipal
           ? gSerializationHelper.serializeToString(triggeringPrincipal)
           : null,
         flags,
-        referrer: referrerURI ? referrerURI.spec : null,
-        referrerPolicy,
+        referrerInfo: E10SUtils.serializeReferrerInfo(referrerInfo),
         remoteType: requiredRemoteType,
         postData,
         newFrameloader,
       };
 
       if (userContextId) {
         loadParams.userContextId = userContextId;
       }
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -2610,22 +2610,26 @@ window._gBrowser = {
         flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL;
       }
       if (allowMixedContent) {
         flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_MIXED_CONTENT;
       }
       if (!allowInheritPrincipal) {
         flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
       }
+
+      let ReferrerInfo = Components.Constructor("@mozilla.org/referrer-info;1",
+                                                "nsIReferrerInfo",
+                                                "init");
       try {
         b.loadURI(aURI, {
           flags,
           triggeringPrincipal,
-          referrerURI: noReferrer ? null : referrerURI,
-          referrerPolicy,
+          referrerInfo: new ReferrerInfo(
+            referrerPolicy, !noReferrer, referrerURI),
           charset,
           postData,
         });
       } catch (ex) {
         Cu.reportError(ex);
       }
     }
 
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -506,21 +506,24 @@ function openLinkIn(url, where, params) 
     // When navigating a recording tab, use a new content process in order to
     // start a new recording.
     if (targetBrowser.hasAttribute("recordExecution") &&
         targetBrowser.currentURI.spec != "about:blank") {
       w.gBrowser.updateBrowserRemoteness(targetBrowser, true,
                                          { recordExecution: "*", newFrameloader: true });
     }
 
+    let ReferrerInfo = Components.Constructor("@mozilla.org/referrer-info;1",
+                                              "nsIReferrerInfo",
+                                              "init");
     targetBrowser.loadURI(url, {
       triggeringPrincipal: aTriggeringPrincipal,
+      referrerInfo: new ReferrerInfo(
+        aReferrerPolicy, !aNoReferrer, aReferrerURI),
       flags,
-      referrerURI: aNoReferrer ? null : aReferrerURI,
-      referrerPolicy: aReferrerPolicy,
       postData: aPostData,
       userContextId: aUserContextId,
     });
 
     // Don't focus the content area if focus is in the address bar and we're
     // loading the New Tab page.
     focusUrlBar = w.document.activeElement == w.gURLBar.inputField &&
                   w.isBlankPageURL(url);
--- a/browser/components/sessionstore/ContentRestore.jsm
+++ b/browser/components/sessionstore/ContentRestore.jsm
@@ -7,17 +7,18 @@
 var EXPORTED_SYMBOLS = ["ContentRestore"];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm", this);
 
 ChromeUtils.defineModuleGetter(this, "SessionHistory",
   "resource://gre/modules/sessionstore/SessionHistory.jsm");
 ChromeUtils.defineModuleGetter(this, "Utils",
   "resource://gre/modules/sessionstore/Utils.jsm");
-
+ChromeUtils.defineModuleGetter(this, "E10SUtils",
+  "resource://gre/modules/E10SUtils.jsm");
 /**
  * This module implements the content side of session restoration. The chrome
  * side is handled by SessionStore.jsm. The functions in this module are called
  * by content-sessionStore.js based on messages received from SessionStore.jsm
  * (or, in one case, based on a "load" event). Each tab has its own
  * ContentRestore instance, constructed by content-sessionStore.js.
  *
  * In a typical restore, content-sessionStore.js will call the following based
@@ -186,35 +187,47 @@ ContentRestoreInternal.prototype = {
         // was redirected into this process, resume that load within our process.
         if (loadArguments.redirectLoadSwitchId) {
           webNavigation.resumeRedirectedLoad(loadArguments.redirectLoadSwitchId);
           return true;
         }
 
         // A load has been redirected to a new process so get history into the
         // same state it was before the load started then trigger the load.
-        let referrer = loadArguments.referrer ?
-                       Services.io.newURI(loadArguments.referrer) : null;
-        let referrerPolicy = ("referrerPolicy" in loadArguments
+        // Referrer information is now stored as a referrerInfo property. We
+        // should also cope with the old format of passing `referrer` and
+        // `referrerPolicy` separately.
+        let referrerInfo = loadArguments.referrerInfo;
+        if (referrerInfo) {
+          referrerInfo = E10SUtils.deserializeReferrerInfo(referrerInfo);
+        } else {
+          let referrer = loadArguments.referrer ?
+            Services.io.newURI(loadArguments.referrer) : null;
+          let referrerPolicy = ("referrerPolicy" in loadArguments
             ? loadArguments.referrerPolicy
             : Ci.nsIHttpChannel.REFERRER_POLICY_UNSET);
+          let ReferrerInfo = Components.Constructor(
+            "@mozilla.org/referrer-info;1",
+            "nsIReferrerInfo",
+            "init");
+          referrerInfo = new ReferrerInfo(referrerPolicy, true, referrer);
+        }
         let postData = loadArguments.postData ?
                        Utils.makeInputStream(loadArguments.postData) : null;
         let triggeringPrincipal = loadArguments.triggeringPrincipal
                                   ? Utils.deserializePrincipal(loadArguments.triggeringPrincipal)
                                   : Services.scriptSecurityManager.createNullPrincipal({});
 
         if (loadArguments.userContextId) {
           webNavigation.setOriginAttributesBeforeLoading({ userContextId: loadArguments.userContextId });
         }
         let loadURIOptions = {
           triggeringPrincipal,
           loadFlags: loadArguments.flags,
-          referrerURI: referrer,
-          referrerPolicy,
+          referrerInfo,
           postData,
         };
         webNavigation.loadURI(loadArguments.uri, loadURIOptions);
       } else if (tabData.userTypedValue && tabData.userTypedClear) {
         // If the user typed a URL into the URL bar and hit enter right before
         // we crashed, we want to start loading that page again. A non-zero
         // userTypedClear value means that the load had started.
         // Load userTypedValue and fix up the URL if it's partial/broken.
--- a/browser/components/sessionstore/test/browser_491168.js
+++ b/browser/components/sessionstore/test/browser_491168.js
@@ -1,45 +1,74 @@
 "use strict";
 
 const REFERRER1 = "http://example.org/?" + Date.now();
 const REFERRER2 = "http://example.org/?" + Math.random();
+const REFERRER3 = "http://example.org/?" + Math.random();
 
 add_task(async function() {
   async function checkDocumentReferrer(referrer, msg) {
     await ContentTask.spawn(gBrowser.selectedBrowser, { referrer, msg }, async function(args) {
       Assert.equal(content.document.referrer, args.referrer, args.msg);
     });
   }
 
+  let ReferrerInfo = Components.Constructor("@mozilla.org/referrer-info;1",
+                                            "nsIReferrerInfo",
+                                            "init");
   // Add a new tab.
   let tab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:blank");
   let browser = tab.linkedBrowser;
   await promiseBrowserLoaded(browser);
 
   // Load a new URI with a specific referrer.
-  let referrerURI = Services.io.newURI(REFERRER1);
+  let referrerInfo1 = new ReferrerInfo(
+    Ci.nsIHttpChannel.REFERRER_POLICY_UNSET,
+    true,
+    Services.io.newURI(REFERRER1));
   browser.loadURI("http://example.org", {
-    referrerURI,
+    referrerInfo: referrerInfo1,
     triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({}),
   });
   await promiseBrowserLoaded(browser);
 
   await TabStateFlusher.flush(browser);
   let tabState = JSON.parse(ss.getTabState(tab));
-  is(tabState.entries[0].referrer, REFERRER1,
+  let actualReferrerInfo = E10SUtils.
+    deserializeReferrerInfo(tabState.entries[0].referrerInfo);
+  is(actualReferrerInfo.originalReferrer.spec, REFERRER1,
      "Referrer retrieved via getTabState matches referrer set via loadURI.");
 
-  tabState.entries[0].referrer = REFERRER2;
+  let referrerInfo2 = new ReferrerInfo(
+    Ci.nsIHttpChannel.REFERRER_POLICY_UNSET,
+    true,
+    Services.io.newURI(REFERRER2));
+
+  tabState.entries[0].referrerInfo = E10SUtils.serializeReferrerInfo(referrerInfo2);
   await promiseTabState(tab, tabState);
 
   await checkDocumentReferrer(REFERRER2,
-    "document.referrer matches referrer set via setTabState.");
+    "document.referrer matches referrer set via setTabState using referrerInfo.");
   gBrowser.removeCurrentTab();
 
   // Restore the closed tab.
   tab = ss.undoCloseTab(window, 0);
   await promiseTabRestored(tab);
 
   await checkDocumentReferrer(REFERRER2,
     "document.referrer is still correct after closing and reopening the tab.");
+
+  tabState.entries[0].referrerInfo = null;
+  tabState.entries[0].referrer =  REFERRER3;
+  await promiseTabState(tab, tabState);
+
+  await checkDocumentReferrer(REFERRER3,
+    "document.referrer matches referrer set via setTabState using referrer.");
+  gBrowser.removeCurrentTab();
+
+  // Restore the closed tab.
+  tab = ss.undoCloseTab(window, 0);
+  await promiseTabRestored(tab);
+
+  await checkDocumentReferrer(REFERRER3,
+    "document.referrer is still correct after closing and reopening the tab.");
   gBrowser.removeCurrentTab();
 });
--- a/devtools/client/responsive.html/browser/web-navigation.js
+++ b/devtools/client/responsive.html/browser/web-navigation.js
@@ -1,20 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const { Ci, Cu, Cr } = require("chrome");
+const { Cc, Ci, Cu, Cr } = require("chrome");
 const ChromeUtils = require("ChromeUtils");
 const Services = require("Services");
 const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
 const { Utils } = require("resource://gre/modules/sessionstore/Utils.jsm");
 const Telemetry = require("devtools/client/shared/telemetry");
+const { E10SUtils } = require("resource://gre/modules/E10SUtils.jsm");
 
 const telemetry = new Telemetry();
 
 function readInputStreamToString(stream) {
   return NetUtil.readInputStreamToString(stream, stream.available());
 }
 
 /**
@@ -66,21 +67,24 @@ BrowserElementWebNavigation.prototype = 
                             Ci.nsIHttpChannel.REFERRER_POLICY_UNSET,
                             postData, headers, null,
                             Services.scriptSecurityManager.createNullPrincipal({}));
   },
 
   loadURIWithOptions(uri, flags, referrer, referrerPolicy, postData, headers,
                      baseURI, triggeringPrincipal) {
     // No equivalent in the current BrowserElement API
+    let referrerInfo = Cc["@mozilla.org/referrer-info;1"]
+                         .createInstance(Ci.nsIReferrerInfo);
+    referrerInfo.init(referrerPolicy, true, referrer);
+    referrerInfo = E10SUtils.serializeReferrerInfo(referrerInfo);
     this._sendMessage("WebNavigation:LoadURI", {
       uri,
       flags,
-      referrer: referrer ? referrer.spec : null,
-      referrerPolicy: referrerPolicy,
+      referrerInfo,
       postData: postData ? readInputStreamToString(postData) : null,
       headers: headers ? readInputStreamToString(headers) : null,
       baseURI: baseURI ? baseURI.spec : null,
       triggeringPrincipal: Utils.serializePrincipal(
                            triggeringPrincipal ||
                            Services.scriptSecurityManager.createNullPrincipal({})),
       requestTime: telemetry.msSystemNow(),
     });
--- a/toolkit/actors/WebNavigationChild.jsm
+++ b/toolkit/actors/WebNavigationChild.jsm
@@ -9,16 +9,18 @@ var EXPORTED_SYMBOLS = ["WebNavigationCh
 const {ActorChild} = ChromeUtils.import("resource://gre/modules/ActorChild.jsm");
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "AppConstants",
                                "resource://gre/modules/AppConstants.jsm");
 ChromeUtils.defineModuleGetter(this, "Utils",
                                "resource://gre/modules/sessionstore/Utils.jsm");
+ChromeUtils.defineModuleGetter(this, "E10SUtils",
+                               "resource://gre/modules/E10SUtils.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter",
                                    "@mozilla.org/xre/app-info;1",
                                    "nsICrashReporter");
 
 class WebNavigationChild extends ActorChild {
   get webNavigation() {
     return this.mm.docShell.QueryInterface(Ci.nsIWebNavigation);
@@ -36,17 +38,17 @@ class WebNavigationChild extends ActorCh
         this.gotoIndex(message.data.index);
         break;
       case "WebNavigation:LoadURI":
         let histogram = Services.telemetry.getKeyedHistogramById("FX_TAB_REMOTE_NAVIGATION_DELAY_MS");
         histogram.add("WebNavigation:LoadURI",
                       Services.telemetry.msSystemNow() - message.data.requestTime);
 
         this.loadURI(message.data.uri, message.data.flags,
-                     message.data.referrer, message.data.referrerPolicy,
+                     message.data.referrerInfo,
                      message.data.postData, message.data.headers,
                      message.data.baseURI, message.data.triggeringPrincipal);
         break;
       case "WebNavigation:SetOriginAttributes":
         this.setOriginAttributes(message.data.originAttributes);
         break;
       case "WebNavigation:Reload":
         this.reload(message.data.flags);
@@ -78,32 +80,30 @@ class WebNavigationChild extends ActorCh
       this._wrapURIChangeCall(() => this.webNavigation.goForward());
     }
   }
 
   gotoIndex(index) {
     this._wrapURIChangeCall(() => this.webNavigation.gotoIndex(index));
   }
 
-  loadURI(uri, flags, referrer, referrerPolicy, postData, headers, baseURI, triggeringPrincipal) {
+  loadURI(uri, flags, referrerInfo, postData, headers, baseURI, triggeringPrincipal) {
     if (AppConstants.MOZ_CRASHREPORTER && CrashReporter.enabled) {
       let annotation = uri;
       try {
         let url = Services.io.newURI(uri);
         // If the current URI contains a username/password, remove it.
         url = url.mutate()
                  .setUserPass("")
                  .finalize();
         annotation = url.spec;
       } catch (ex) { /* Ignore failures to parse and failures
                       on about: URIs. */ }
       CrashReporter.annotateCrashReport("URL", annotation);
     }
-    if (referrer)
-      referrer = Services.io.newURI(referrer);
     if (postData)
       postData = Utils.makeInputStream(postData);
     if (headers)
       headers = Utils.makeInputStream(headers);
     if (baseURI)
       baseURI = Services.io.newURI(baseURI);
     this._assert(triggeringPrincipal, "We need a triggering principal to continue loading", new Error().lineNumber);
     if (triggeringPrincipal)
@@ -111,18 +111,17 @@ class WebNavigationChild extends ActorCh
     this._assert(triggeringPrincipal, "Unable to deserialize passed triggering principal", new Error().lineNumber);
     if (!triggeringPrincipal) {
       triggeringPrincipal = Services.scriptSecurityManager.getSystemPrincipal({});
     }
 
     let loadURIOptions = {
       triggeringPrincipal,
       loadFlags: flags,
-      referrerURI: referrer,
-      referrerPolicy,
+      referrerInfo: E10SUtils.deserializeReferrerInfo(referrerInfo),
       postData,
       headers,
       baseURI,
     };
     this._wrapURIChangeCall(() => {
       return this.webNavigation.loadURI(uri, loadURIOptions);
     });
   }
--- a/toolkit/components/reader/ReaderMode.jsm
+++ b/toolkit/components/reader/ReaderMode.jsm
@@ -95,20 +95,24 @@ var ReaderMode = {
       referrerURI = Services.io.newURI(url);
       principal = Services.scriptSecurityManager.createCodebasePrincipal(
         referrerURI, win.document.nodePrincipal.originAttributes);
     } catch (e) {
       Cu.reportError(e);
       return;
     }
     let flags = webNav.LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
+    let ReferrerInfo = Components.Constructor("@mozilla.org/referrer-info;1",
+                                              "nsIReferrerInfo",
+                                              "init");
     let loadURIOptions = {
       triggeringPrincipal: principal,
       loadFlags: flags,
-      referrerURI,
+      referrerInfo: new ReferrerInfo(
+        Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, true, referrerURI),
     };
     webNav.loadURI(originalURL, loadURIOptions);
   },
 
   /**
    * Returns original URL from an about:reader URL.
    *
    * @param url An about:reader URL.
--- a/toolkit/components/remotebrowserutils/RemoteWebNavigation.js
+++ b/toolkit/components/remotebrowserutils/RemoteWebNavigation.js
@@ -8,16 +8,18 @@ const {XPCOMUtils} = ChromeUtils.import(
 ChromeUtils.defineModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 ChromeUtils.defineModuleGetter(this, "NetUtil",
   "resource://gre/modules/NetUtil.jsm");
 ChromeUtils.defineModuleGetter(this, "Utils",
   "resource://gre/modules/sessionstore/Utils.jsm");
 ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
+ChromeUtils.defineModuleGetter(this, "E10SUtils",
+  "resource://gre/modules/E10SUtils.jsm");
 
 function makeURI(url) {
   return Services.io.newURI(url);
 }
 
 function RemoteWebNavigation() {
   this.wrappedJSObject = this;
 }
@@ -89,18 +91,17 @@ RemoteWebNavigation.prototype = {
         // Can't setup speculative connection for this uri string for some
         // reason (such as failing to parse the URI), just ignore it.
       }
     }
 
     this._sendMessage("WebNavigation:LoadURI", {
       uri: aURI,
       flags: aLoadURIOptions.loadFlags,
-      referrer: aLoadURIOptions.referrerURI ? aLoadURIOptions.referrerURI.spec : null,
-      referrerPolicy: aLoadURIOptions.referrerPolicy,
+      referrerInfo: E10SUtils.serializeReferrerInfo(aLoadURIOptions.referrerInfo),
       postData: aLoadURIOptions.postData ? Utils.serializeInputStream(aLoadURIOptions.postData) : null,
       headers: aLoadURIOptions.headers ? Utils.serializeInputStream(aLoadURIOptions.headers) : null,
       baseURI: aLoadURIOptions.baseURI ? aLoadURIOptions.baseURI.spec : null,
       triggeringPrincipal: Utils.serializePrincipal(
                            aLoadURIOptions.triggeringPrincipal || Services.scriptSecurityManager.createNullPrincipal({})),
       requestTime: Services.telemetry.msSystemNow(),
     });
   },
--- a/toolkit/components/remotebrowserutils/tests/browser/browser_RemoteWebNavigation.js
+++ b/toolkit/components/remotebrowserutils/tests/browser/browser_RemoteWebNavigation.js
@@ -10,19 +10,24 @@ function waitForLoad(uri) {
 function waitForPageShow(browser = gBrowser.selectedBrowser) {
   return BrowserTestUtils.waitForContentEvent(browser, "pageshow", true);
 }
 
 // Tests that loadURI accepts a referrer and it is included in the load.
 add_task(async function test_referrer() {
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   let browser = gBrowser.selectedBrowser;
+  let ReferrerInfo = Components.Constructor("@mozilla.org/referrer-info;1",
+                                            "nsIReferrerInfo",
+                                            "init");
+
   let loadURIOptionsWithReferrer = {
     triggeringPrincipal: SYSTEMPRINCIPAL,
-    referrerURI: Services.io.newURI(DUMMY2),
+    referrerInfo: new ReferrerInfo(
+      Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, true, Services.io.newURI(DUMMY2)),
   };
   browser.webNavigation.loadURI(DUMMY1, loadURIOptionsWithReferrer);
   await waitForLoad(DUMMY1);
 
   await ContentTask.spawn(browser, [ DUMMY1, DUMMY2 ], function([dummy1, dummy2]) {
     is(content.location.href, dummy1, "Should have loaded the right URL");
     is(content.document.referrer, dummy2, "Should have the right referrer");
   });
--- a/toolkit/components/viewsource/content/viewSource-content.js
+++ b/toolkit/components/viewsource/content/viewSource-content.js
@@ -594,22 +594,20 @@ var ViewSourceContent = {
    * @param drawSelection true to highlight the selection
    * @param baseURI base URI of the original document
    */
   viewSourceWithSelection(uri, drawSelection, baseURI) {
     this.needsDrawSelection = drawSelection;
 
     // all our content is held by the data:URI and URIs are internally stored as utf-8 (see nsIURI.idl)
     let loadFlags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
-    let referrerPolicy = Ci.nsIHttpChannel.REFERRER_POLICY_UNSET;
     let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
     let loadURIOptions = {
       triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
       loadFlags,
-      referrerPolicy,
       baseURI: Services.io.newURI(baseURI),
     };
     webNav.loadURI(uri, loadURIOptions);
   },
 
   /**
    * Using special markers left in the serialized source, this helper makes the
    * underlying markup of the selected fragment to automatically appear as
--- a/toolkit/content/widgets/browser-custom-element.js
+++ b/toolkit/content/widgets/browser-custom-element.js
@@ -794,30 +794,27 @@ class MozBrowser extends MozElementMixin
 
   /**
    * throws exception for unknown schemes
    */
   loadURI(aURI, aParams) {
     if (!aURI) {
       aURI = "about:blank";
     }
-
     let {
       flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
-        referrerURI,
-        referrerPolicy = Ci.nsIHttpChannel.REFERRER_POLICY_UNSET,
+        referrerInfo,
         triggeringPrincipal,
         postData,
         headers,
     } = aParams || {};
     let loadURIOptions = {
       triggeringPrincipal,
-      referrerURI,
+      referrerInfo,
       loadFlags: flags,
-      referrerPolicy,
       postData,
       headers,
     };
     this._wrapURIChangeCall(() =>
       this.webNavigation.loadURI(aURI, loadURIOptions));
   }
 
   gotoIndex(aIndex) {
--- a/toolkit/modules/E10SUtils.jsm
+++ b/toolkit/modules/E10SUtils.jsm
@@ -12,16 +12,19 @@ const {XPCOMUtils} = ChromeUtils.import(
 XPCOMUtils.defineLazyPreferenceGetter(this, "useSeparateFileUriProcess",
                                       "browser.tabs.remote.separateFileUriProcess", false);
 XPCOMUtils.defineLazyPreferenceGetter(this, "allowLinkedWebInFileUriProcess",
                                       "browser.tabs.remote.allowLinkedWebInFileUriProcess", false);
 XPCOMUtils.defineLazyPreferenceGetter(this, "useSeparatePrivilegedContentProcess",
                                       "browser.tabs.remote.separatePrivilegedContentProcess", false);
 XPCOMUtils.defineLazyPreferenceGetter(this, "useHttpResponseProcessSelection",
                                       "browser.tabs.remote.useHTTPResponseProcessSelection", false);
+XPCOMUtils.defineLazyServiceGetter(this, "serializationHelper",
+                                   "@mozilla.org/network/serialization-helper;1",
+                                   "nsISerializationHelper");
 ChromeUtils.defineModuleGetter(this, "Utils",
                                "resource://gre/modules/sessionstore/Utils.jsm");
 
 function getAboutModule(aURL) {
   // Needs to match NS_GetAboutModuleName
   let moduleName = aURL.pathQueryRef.replace(/[#?].*/, "").toLowerCase();
   let contract = "@mozilla.org/network/protocol/about;1?what=" + moduleName;
   try {
@@ -398,9 +401,45 @@ var E10SUtils = {
     try {
       handlingUserInput = aWindow.windowUtils
                                  .setHandlingUserInput(aIsHandling);
       aCallback();
     } finally {
       handlingUserInput.destruct();
     }
   },
+
+  /**
+   * Serialize referrerInfo.
+   *
+   * @param {nsIReferrerInfo} The referrerInfo to serialize.
+   * @return {String} The base64 encoded referrerInfo.
+   */
+  serializeReferrerInfo(referrerInfo) {
+    let serialized = null;
+    if (referrerInfo) {
+      try {
+        serialized = serializationHelper.serializeToString(referrerInfo);
+      } catch (e) {
+        debug(`Failed to serialize referrerInfo '${referrerInfo}' ${e}`);
+      }
+    }
+    return serialized;
+  },
+  /**
+   * Deserialize a base64 encoded referrerInfo
+   *
+   * @param {String} referrerInfo_b64 A base64 encoded serialized referrerInfo.
+   * @return {nsIReferrerInfo} A deserialized referrerInfo.
+   */
+  deserializeReferrerInfo(referrerInfo_b64) {
+    let deserialized = null;
+    if (referrerInfo_b64) {
+      try {
+        deserialized = serializationHelper.deserializeObject(referrerInfo_b64);
+        deserialized.QueryInterface(Ci.nsIReferrerInfo);
+      } catch (e) {
+        debug(`Failed to deserialize referrerInfo_b64 '${referrerInfo_b64}' ${e}`);
+      }
+    }
+    return deserialized;
+  },
 };
--- a/toolkit/modules/sessionstore/SessionHistory.jsm
+++ b/toolkit/modules/sessionstore/SessionHistory.jsm
@@ -6,16 +6,18 @@
 
 var EXPORTED_SYMBOLS = ["SessionHistory"];
 
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "Utils",
   "resource://gre/modules/sessionstore/Utils.jsm");
+ChromeUtils.defineModuleGetter(this, "E10SUtils",
+  "resource://gre/modules/E10SUtils.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "uuidGenerator",
   "@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
 
 function debug(msg) {
   Services.console.logStringMessage("SessionHistory: " + msg);
 }
 
 /**
@@ -138,19 +140,18 @@ var SessionHistoryInternal = {
     }
 
     entry.cacheKey = shEntry.cacheKey;
     entry.ID = shEntry.ID;
     entry.docshellUUID = shEntry.docshellID.toString();
 
     // We will include the property only if it's truthy to save a couple of
     // bytes when the resulting object is stringified and saved to disk.
-    if (shEntry.referrerURI) {
-      entry.referrer = shEntry.referrerURI.spec;
-      entry.referrerPolicy = shEntry.referrerPolicy;
+    if (shEntry.referrerInfo) {
+      entry.referrerInfo = E10SUtils.serializeReferrerInfo(shEntry.referrerInfo);
     }
 
     if (shEntry.originalURI) {
       entry.originalURI = shEntry.originalURI.spec;
     }
 
     if (shEntry.resultPrincipalURI) {
       entry.resultPrincipalURI = shEntry.resultPrincipalURI.spec;
@@ -333,20 +334,29 @@ var SessionHistoryInternal = {
 
     shEntry.URI = Services.io.newURI(entry.url);
     shEntry.title = entry.title || entry.url;
     if (entry.subframe)
       shEntry.isSubFrame = entry.subframe || false;
     shEntry.setLoadTypeAsHistory();
     if (entry.contentType)
       shEntry.contentType = entry.contentType;
-    if (entry.referrer) {
-      shEntry.referrerURI = Services.io.newURI(entry.referrer);
-      shEntry.referrerPolicy = entry.referrerPolicy;
+    // Referrer information is now stored as a referrerInfo property. We should
+    // also cope with the old format of passing `referrer` and `referrerPolicy`
+    // separately.
+    if (entry.referrerInfo) {
+      shEntry.referrerInfo = E10SUtils.deserializeReferrerInfo(entry.referrerInfo);
+    } else if (entry.referrer) {
+      let ReferrerInfo = Components.Constructor("@mozilla.org/referrer-info;1",
+                                                "nsIReferrerInfo",
+                                                "init");
+      shEntry.referrerInfo = new ReferrerInfo(
+        entry.referrerPolicy, true, Services.io.newURI(entry.referrer));
     }
+
     if (entry.originalURI) {
       shEntry.originalURI = Services.io.newURI(entry.originalURI);
     }
     if (typeof entry.resultPrincipalURI === "undefined" && entry.loadReplace) {
       // This is backward compatibility code for stored sessions saved prior to
       // introduction of the resultPrincipalURI property.  The equivalent of this
       // property non-null value used to be the URL while the LOAD_REPLACE flag
       // was set.