Merge mozilla-inbound to mozilla-central. a=merge
authorDorel Luca <dluca@mozilla.com>
Mon, 25 Feb 2019 03:43:20 +0200
changeset 518709 5727cf4eeb37
parent 518692 3a2ced4fbd98 (current diff)
parent 518708 8130341d3ec8 (diff)
child 518710 a238fb5cc415
child 518719 aee528adc1f7
child 518724 d097a90b5d4a
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone67.0a1
first release with
nightly linux32
5727cf4eeb37 / 67.0a1 / 20190225014816 / files
nightly linux64
5727cf4eeb37 / 67.0a1 / 20190225014816 / files
nightly mac
5727cf4eeb37 / 67.0a1 / 20190225014816 / files
nightly win32
5727cf4eeb37 / 67.0a1 / 20190225014816 / files
nightly win64
5727cf4eeb37 / 67.0a1 / 20190225014816 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central. a=merge
browser/base/content/browser.js
taskcluster/ci/searchfox/kind.yml
--- a/browser/actors/ClickHandlerChild.jsm
+++ b/browser/actors/ClickHandlerChild.jsm
@@ -9,16 +9,18 @@ const {ActorChild} = ChromeUtils.import(
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 ChromeUtils.defineModuleGetter(this, "BrowserUtils",
                                "resource://gre/modules/BrowserUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
                                "resource://gre/modules/PrivateBrowsingUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "WebNavigationFrames",
                                "resource://gre/modules/WebNavigationFrames.jsm");
+ChromeUtils.defineModuleGetter(this, "E10SUtils",
+                               "resource://gre/modules/E10SUtils.jsm");
 
 class ClickHandlerChild extends ActorChild {
   handleEvent(event) {
     if (!event.isTrusted || event.defaultPrevented || event.button == 2) {
       return;
     }
 
     let originalTarget = event.originalTarget;
@@ -43,23 +45,30 @@ class ClickHandlerChild extends ActorChi
     if (node) {
       let referrerAttrValue = Services.netUtils.parseAttributePolicyString(node.
                               getAttribute("referrerpolicy"));
       if (referrerAttrValue !== Ci.nsIHttpChannel.REFERRER_POLICY_UNSET) {
         referrerPolicy = referrerAttrValue;
       }
     }
 
+    // Bug 965637, query the CSP from the doc instead of the Principal
+    let csp = ownerDoc.nodePrincipal.csp;
+    if (csp) {
+      csp = E10SUtils.serializeCSP(csp);
+    }
+
     let frameOuterWindowID = WebNavigationFrames.getFrameId(ownerDoc.defaultView);
 
     let json = { button: event.button, shiftKey: event.shiftKey,
                  ctrlKey: event.ctrlKey, metaKey: event.metaKey,
                  altKey: event.altKey, href: null, title: null,
                  frameOuterWindowID, referrerPolicy,
                  triggeringPrincipal: principal,
+                 csp,
                  originAttributes: principal ? principal.originAttributes : {},
                  isContentWindowPrivate: PrivateBrowsingUtils.isContentWindowPrivate(ownerDoc.defaultView)};
 
     if (href) {
       try {
         BrowserUtils.urlSecurityCheck(href, principal);
       } catch (e) {
         return;
--- a/browser/actors/ContextMenuChild.jsm
+++ b/browser/actors/ContextMenuChild.jsm
@@ -761,16 +761,19 @@ class ContextMenuChild extends ActorChil
     context.onTextInput         = false;
     context.onVideo             = false;
 
     // Remember the node and its owner document that was clicked
     // This may be modifed before sending to nsContextMenu
     context.target = node;
 
     context.principal = context.target.ownerDocument.nodePrincipal;
+    // Bug 965637, query the CSP from the doc instead of the Principal
+    context.csp = E10SUtils.serializeCSP(context.target.ownerDocument.nodePrincipal.csp);
+
     context.frameOuterWindowID = WebNavigationFrames.getFrameId(context.target.ownerGlobal);
 
     // Check if we are in a synthetic document (stand alone image, video, etc.).
     context.inSyntheticDoc = context.target.ownerDocument.mozSyntheticDocument;
 
     context.shouldInitInlineSpellCheckerUINoChildren = false;
     context.shouldInitInlineSpellCheckerUIWithChildren = false;
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1051,16 +1051,17 @@ function _loadURI(browser, uri, params =
   }
 
   let {
     flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
     triggeringPrincipal,
     referrerInfo,
     postData,
     userContextId,
+    csp,
   } = params || {};
 
   if (!triggeringPrincipal) {
     throw new Error("Must load with a triggering Principal");
   }
 
   let {
     uriObject,
@@ -1080,16 +1081,17 @@ function _loadURI(browser, uri, params =
   }
 
   // !requiredRemoteType means we're loading in the parent/this process.
   if (!requiredRemoteType) {
     browser.inLoadURI = true;
   }
   let loadURIOptions = {
     triggeringPrincipal,
+    csp,
     loadFlags: flags,
     referrerInfo,
     postData,
   };
   try {
     if (!mustChangeProcess) {
       if (userContextId) {
         browser.webNavigation.setOriginAttributesBeforeLoading({
@@ -1114,16 +1116,17 @@ function _loadURI(browser, uri, params =
         triggeringPrincipal: triggeringPrincipal
           ? gSerializationHelper.serializeToString(triggeringPrincipal)
           : null,
         flags,
         referrerInfo: E10SUtils.serializeReferrerInfo(referrerInfo),
         remoteType: requiredRemoteType,
         postData,
         newFrameloader,
+        csp: csp ? gSerializationHelper.serializeToString(csp) : null,
       };
 
       if (userContextId) {
         loadParams.userContextId = userContextId;
       }
 
       LoadInOtherProcess(browser, loadParams);
     }
@@ -1683,28 +1686,30 @@ var gBrowserInit = {
         try {
           gBrowser.loadTabs(uriToLoad, {
             inBackground: false,
             replace: true,
             // See below for the semantics of window.arguments. Only the minimum is supported.
             userContextId: window.arguments[6],
             triggeringPrincipal: window.arguments[8] || Services.scriptSecurityManager.getSystemPrincipal(),
             allowInheritPrincipal: window.arguments[9],
+            csp: window.arguments[10],
           });
         } catch (e) {}
       } else if (window.arguments.length >= 3) {
         // window.arguments[1]: unused (bug 871161)
         //                 [2]: referrer (nsIURI | string)
         //                 [3]: postData (nsIInputStream)
         //                 [4]: allowThirdPartyFixup (bool)
         //                 [5]: referrerPolicy (int)
         //                 [6]: userContextId (int)
         //                 [7]: originPrincipal (nsIPrincipal)
         //                 [8]: triggeringPrincipal (nsIPrincipal)
         //                 [9]: allowInheritPrincipal (bool)
+        //                [10]: csp (nsIContentSecurityPolicy)
         let referrerURI = window.arguments[2];
         if (typeof(referrerURI) == "string") {
           try {
             referrerURI = makeURI(referrerURI);
           } catch (e) {
             referrerURI = null;
           }
         }
@@ -1714,17 +1719,17 @@ var gBrowserInit = {
             window.arguments[6] : Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID);
         loadURI(uriToLoad, referrerURI, window.arguments[3] || null,
                 window.arguments[4] || false, referrerPolicy, userContextId,
                 // pass the origin principal (if any) and force its use to create
                 // an initial about:blank viewer if present:
                 window.arguments[7], !!window.arguments[7], window.arguments[8],
                 // TODO fix allowInheritPrincipal to default to false.
                 // Default to true unless explicitly set to false because of bug 1475201.
-                window.arguments[9] !== false);
+                window.arguments[9] !== false, window.arguments[10]);
         window.focus();
       } else {
         // Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3.
         // Such callers expect that window.arguments[0] is handled as a single URI.
         loadOneOrMoreURIs(uriToLoad, Services.scriptSecurityManager.getSystemPrincipal());
       }
     });
   },
@@ -2433,30 +2438,31 @@ function BrowserCloseTabOrWindow(event) 
 
 function BrowserTryToCloseWindow() {
   if (WindowIsClosing())
     window.close(); // WindowIsClosing does all the necessary checks
 }
 
 function loadURI(uri, referrer, postData, allowThirdPartyFixup, referrerPolicy,
                  userContextId, originPrincipal, forceAboutBlankViewerInCurrent,
-                 triggeringPrincipal, allowInheritPrincipal = false) {
+                 triggeringPrincipal, allowInheritPrincipal = false, csp = null) {
   if (!triggeringPrincipal) {
     throw new Error("Must load with a triggering Principal");
   }
 
   try {
     openLinkIn(uri, "current",
                { referrerURI: referrer,
                  referrerPolicy,
                  postData,
                  allowThirdPartyFixup,
                  userContextId,
                  originPrincipal,
                  triggeringPrincipal,
+                 csp,
                  forceAboutBlankViewerInCurrent,
                  allowInheritPrincipal,
                });
   } catch (e) {
     Cu.reportError(e);
   }
 }
 
@@ -4658,34 +4664,34 @@ var XULBrowserWindow = {
   },
 
   // Called before links are navigated to to allow us to retarget them if needed.
   onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab) {
     return BrowserUtils.onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab);
   },
 
   // Check whether this URI should load in the current process
-  shouldLoadURI(aDocShell, aURI, aReferrer, aHasPostData, aTriggeringPrincipal) {
+  shouldLoadURI(aDocShell, aURI, aReferrer, aHasPostData, aTriggeringPrincipal, aCsp) {
     if (!gMultiProcessBrowser)
       return true;
 
     let browser = aDocShell.QueryInterface(Ci.nsIDocShellTreeItem)
                            .sameTypeRootTreeItem
                            .QueryInterface(Ci.nsIDocShell)
                            .chromeEventHandler;
 
     // Ignore loads that aren't in the main tabbrowser
     if (browser.localName != "browser" || !browser.getTabBrowser || browser.getTabBrowser() != gBrowser)
       return true;
 
     if (!E10SUtils.shouldLoadURI(aDocShell, aURI, aReferrer, aHasPostData)) {
       // XXX: Do we want to complain if we have post data but are still
       // redirecting the load? Perhaps a telemetry probe? Theoretically we
       // shouldn't do this, as it throws out data. See bug 1348018.
-      E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, false);
+      E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, false, null, aCsp);
       return false;
     }
 
     return true;
   },
 
   onProgressChange(aWebProgress, aRequest,
                              aCurSelfProgress, aMaxSelfProgress,
@@ -5391,17 +5397,17 @@ function nsBrowserAccess() { }
 
 nsBrowserAccess.prototype = {
   QueryInterface: ChromeUtils.generateQI([Ci.nsIBrowserDOMWindow]),
 
   _openURIInNewTab(aURI, aReferrer, aReferrerPolicy, aIsPrivate,
                    aIsExternal, aForceNotRemote = false,
                    aUserContextId = Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID,
                    aOpenerWindow = null, aOpenerBrowser = null,
-                   aTriggeringPrincipal = null, aNextTabParentId = 0, aName = "") {
+                   aTriggeringPrincipal = null, aNextTabParentId = 0, aName = "", aCsp = null) {
     let win, needToFocusWin;
 
     // try the current window.  if we're in a popup, fall back on the most recent browser window
     if (window.toolbar.visible)
       win = window;
     else {
       win = BrowserWindowTracker.getTopWindow({private: aIsPrivate});
       needToFocusWin = true;
@@ -5427,16 +5433,17 @@ nsBrowserAccess.prototype = {
                                       userContextId: aUserContextId,
                                       fromExternal: aIsExternal,
                                       inBackground: loadInBackground,
                                       forceNotRemote: aForceNotRemote,
                                       opener: aOpenerWindow,
                                       openerBrowser: aOpenerBrowser,
                                       nextTabParentId: aNextTabParentId,
                                       name: aName,
+                                      csp: aCsp,
                                       });
     let browser = win.gBrowser.getBrowserForTab(tab);
 
     if (needToFocusWin || (!loadInBackground && aIsExternal))
       win.focus();
 
     return browser;
   },
@@ -5486,16 +5493,18 @@ nsBrowserAccess.prototype = {
         aWhere = Services.prefs.getIntPref("browser.link.open_newwindow");
     }
 
     let referrer = aOpener ? makeURI(aOpener.location.href) : null;
     let referrerPolicy = Ci.nsIHttpChannel.REFERRER_POLICY_UNSET;
     if (aOpener && aOpener.document) {
       referrerPolicy = aOpener.document.referrerPolicy;
     }
+    // Bug 965637, query the CSP from the doc instead of the Principal
+    let csp = aTriggeringPrincipal.csp;
     let isPrivate = aOpener
                   ? PrivateBrowsingUtils.isContentWindowPrivate(aOpener)
                   : PrivateBrowsingUtils.isWindowPrivate(window);
 
     switch (aWhere) {
       case Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW :
         // FIXME: Bug 408379. So how come this doesn't send the
         // referrer like the other loads do?
@@ -5524,28 +5533,30 @@ nsBrowserAccess.prototype = {
         let forceNotRemote = !!aOpener;
         let userContextId = aOpener && aOpener.document
                               ? aOpener.document.nodePrincipal.originAttributes.userContextId
                               : Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID;
         let openerWindow = (aFlags & Ci.nsIBrowserDOMWindow.OPEN_NO_OPENER) ? null : aOpener;
         let browser = this._openURIInNewTab(aURI, referrer, referrerPolicy,
                                             isPrivate, isExternal,
                                             forceNotRemote, userContextId,
-                                            openerWindow, null, aTriggeringPrincipal);
+                                            openerWindow, null, aTriggeringPrincipal,
+                                            0, "", csp);
         if (browser)
           newWindow = browser.contentWindow;
         break;
       default : // OPEN_CURRENTWINDOW or an illegal value
         newWindow = window.content;
         if (aURI) {
           let loadflags = isExternal ?
                             Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL :
                             Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
           gBrowser.loadURI(aURI.spec, {
             triggeringPrincipal: aTriggeringPrincipal,
+            csp,
             flags: loadflags,
             referrerURI: referrer,
             referrerPolicy,
           });
         }
         if (!Services.prefs.getBoolPref("browser.tabs.loadDivertedInBackground"))
           window.focus();
     }
@@ -5583,17 +5594,17 @@ nsBrowserAccess.prototype = {
 
     let referrer = aParams.referrer ? makeURI(aParams.referrer) : null;
     return this._openURIInNewTab(aURI, referrer,
                                  aParams.referrerPolicy,
                                  aParams.isPrivate,
                                  isExternal, false,
                                  userContextId, null, aParams.openerBrowser,
                                  aParams.triggeringPrincipal,
-                                 aNextTabParentId, aName);
+                                 aNextTabParentId, aName, aParams.csp);
   },
 
   isTabContentWindow(aWindow) {
     return gBrowser.browsers.some(browser => browser.contentWindow == aWindow);
   },
 
   canClose() {
     return CanCloseWindow();
@@ -6135,25 +6146,29 @@ function handleLinkClick(event, href, li
                             getAttribute("referrerpolicy"));
     if (referrerAttrValue != Ci.nsIHttpChannel.REFERRER_POLICY_UNSET) {
       referrerPolicy = referrerAttrValue;
     }
   }
 
   let frameOuterWindowID = WebNavigationFrames.getFrameId(doc.defaultView);
 
+  // Bug 965637, query the CSP from the doc instead of the Principal
+  let csp = doc.nodePrincipal.csp;
+
   urlSecurityCheck(href, doc.nodePrincipal);
   let params = {
     charset: doc.characterSet,
     allowMixedContent: persistAllowMixedContentInChildTab,
     referrerURI,
     referrerPolicy,
     noReferrer: BrowserUtils.linkHasNoReferrer(linkNode),
     originPrincipal: doc.nodePrincipal,
     triggeringPrincipal: doc.nodePrincipal,
+    csp,
     frameOuterWindowID,
   };
 
   // The new tab/window must use the same userContextId
   if (doc.nodePrincipal.originAttributes.userContextId) {
     params.userContextId = doc.nodePrincipal.originAttributes.userContextId;
   }
 
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 var {PrivateBrowsingUtils} = ChromeUtils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 var {BrowserUtils} = ChromeUtils.import("resource://gre/modules/BrowserUtils.jsm");
 var {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
+  E10SUtils: "resource://gre/modules/E10SUtils.jsm",
   SpellCheckHelper: "resource://gre/modules/InlineSpellChecker.jsm",
   LoginHelper: "resource://gre/modules/LoginHelper.jsm",
   LoginManagerContextMenu: "resource://gre/modules/LoginManagerContextMenu.jsm",
   WebNavigationFrames: "resource://gre/modules/WebNavigationFrames.jsm",
   ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm",
   DevToolsShim: "chrome://devtools-startup/content/DevToolsShim.jsm",
   NetUtil: "resource://gre/modules/NetUtil.jsm",
 });
@@ -226,16 +227,18 @@ nsContextMenu.prototype = {
 
     this.inSyntheticDoc = context.inSyntheticDoc;
     this.inAboutDevtoolsToolbox = context.inAboutDevtoolsToolbox;
 
 
     // Everything after this isn't sent directly from ContextMenu
     this.ownerDoc = this.target.ownerDocument;
 
+    this.csp = E10SUtils.deserializeCSP(context.csp);
+
     // Remember the CSS selectors corresponding to clicked node. gContextMenuContentData
     // can be null if the menu was triggered by tests in which case use an empty array.
     this.targetSelectors = gContextMenuContentData
                            ? gContextMenuContentData.popupNodeSelectors
                            : [];
 
     if (this.isRemote) {
       this.browser = gContextMenuContentData.browser;
@@ -772,16 +775,17 @@ nsContextMenu.prototype = {
   inspectA11Y() {
     return DevToolsShim.inspectA11Y(gBrowser.selectedTab, this.targetSelectors);
   },
 
   _openLinkInParameters(extra) {
     let params = { charset: gContextMenuContentData.charSet,
                    originPrincipal: this.principal,
                    triggeringPrincipal: this.principal,
+                   csp: this.csp,
                    referrerURI: gContextMenuContentData.documentURIObject,
                    referrerPolicy: gContextMenuContentData.referrerPolicy,
                    frameOuterWindowID: gContextMenuContentData.frameOuterWindowID,
                    noReferrer: this.linkHasNoReferrer || this.onPlainTextLink };
     for (let p in extra) {
       params[p] = extra[p];
     }
 
--- a/browser/base/content/tab-content.js
+++ b/browser/base/content/tab-content.js
@@ -29,32 +29,32 @@ if (Services.prefs.getBoolPref("browser.
 }
 
 var WebBrowserChrome = {
   onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab) {
     return BrowserUtils.onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab);
   },
 
   // Check whether this URI should load in the current process
-  shouldLoadURI(aDocShell, aURI, aReferrer, aHasPostData, aTriggeringPrincipal) {
+  shouldLoadURI(aDocShell, aURI, aReferrer, aHasPostData, aTriggeringPrincipal, aCsp) {
     if (!E10SUtils.shouldLoadURI(aDocShell, aURI, aReferrer, aHasPostData)) {
-      E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, false);
+      E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, false, null, aCsp);
       return false;
     }
 
     return true;
   },
 
   shouldLoadURIInThisProcess(aURI) {
     return E10SUtils.shouldLoadURIInThisProcess(aURI);
   },
 
   // Try to reload the currently active or currently loading page in a new process.
-  reloadInFreshProcess(aDocShell, aURI, aReferrer, aTriggeringPrincipal, aLoadFlags) {
-    E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, true, aLoadFlags);
+  reloadInFreshProcess(aDocShell, aURI, aReferrer, aTriggeringPrincipal, aLoadFlags, aCsp) {
+    E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, true, aLoadFlags, aCsp);
     return true;
   },
 };
 
 if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
   let tabchild = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsITabChild);
   tabchild.webBrowserChrome = WebBrowserChrome;
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -1396,16 +1396,17 @@ window._gBrowser = {
     var aSameProcessAsFrameLoader;
     var aOriginPrincipal;
     var aOpener;
     var aOpenerBrowser;
     var aCreateLazyBrowser;
     var aNextTabParentId;
     var aFocusUrlBar;
     var aName;
+    var aCsp;
     if (arguments.length == 2 &&
         typeof arguments[1] == "object" &&
         !(arguments[1] instanceof Ci.nsIURI)) {
       let params = arguments[1];
       aTriggeringPrincipal = params.triggeringPrincipal;
       aReferrerURI = params.referrerURI;
       aReferrerPolicy = params.referrerPolicy;
       aCharset = params.charset;
@@ -1424,16 +1425,17 @@ window._gBrowser = {
       aSameProcessAsFrameLoader = params.sameProcessAsFrameLoader;
       aOriginPrincipal = params.originPrincipal;
       aOpener = params.opener;
       aOpenerBrowser = params.openerBrowser;
       aCreateLazyBrowser = params.createLazyBrowser;
       aNextTabParentId = params.nextTabParentId;
       aFocusUrlBar = params.focusUrlBar;
       aName = params.name;
+      aCsp = params.csp;
     }
 
     // all callers of loadOneTab need to pass a valid triggeringPrincipal.
     if (!aTriggeringPrincipal) {
       throw new Error("Required argument triggeringPrincipal missing within loadOneTab");
     }
 
     var bgLoad = (aLoadInBackground != null) ? aLoadInBackground :
@@ -1460,32 +1462,34 @@ window._gBrowser = {
       userContextId: aUserContextId,
       originPrincipal: aOriginPrincipal,
       sameProcessAsFrameLoader: aSameProcessAsFrameLoader,
       opener: aOpener,
       openerBrowser: aOpenerBrowser,
       nextTabParentId: aNextTabParentId,
       focusUrlBar: aFocusUrlBar,
       name: aName,
+      csp: aCsp,
     });
     if (!bgLoad)
       this.selectedTab = tab;
 
     return tab;
   },
 
   loadTabs(aURIs, {
     allowInheritPrincipal,
     allowThirdPartyFixup,
     inBackground,
     newIndex,
     postDatas,
     replace,
     targetTab,
     triggeringPrincipal,
+    csp,
     userContextId,
   } = {}) {
     if (!aURIs.length) {
       return;
     }
 
     // The tab selected after this new tab is closed (i.e. the new tab's
     // "owner") is the next adjacent tab (i.e. not the previously viewed tab)
@@ -1533,31 +1537,33 @@ window._gBrowser = {
       if (!allowInheritPrincipal) {
         flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
       }
       try {
         browser.loadURI(aURIs[0], {
           flags,
           postData: postDatas && postDatas[0],
           triggeringPrincipal,
+          csp,
         });
       } catch (e) {
         // Ignore failure in case a URI is wrong, so we can continue
         // opening the next ones.
       }
     } else {
       let params = {
         allowInheritPrincipal,
         ownerTab: owner,
         skipAnimation: multiple,
         allowThirdPartyFixup,
         postData: postDatas && postDatas[0],
         userContextId,
         triggeringPrincipal,
         bulkOrderedOpen: multiple,
+        csp,
       };
       if (newIndex > -1) {
         params.index = newIndex;
       }
       firstTabAdded = this.addTab(aURIs[0], params);
       if (newIndex > -1) {
         targetTabIndex = firstTabAdded._tPos;
       }
@@ -1568,16 +1574,17 @@ window._gBrowser = {
       let params = {
         allowInheritPrincipal,
         skipAnimation: true,
         allowThirdPartyFixup,
         postData: postDatas && postDatas[i],
         userContextId,
         triggeringPrincipal,
         bulkOrderedOpen: true,
+        csp,
       };
       if (targetTabIndex > -1) {
         params.index = ++tabNum;
       }
       this.addTab(aURIs[i], params);
     }
 
     if (firstTabAdded && !inBackground) {
@@ -2306,16 +2313,17 @@ window._gBrowser = {
     relatedToCurrent,
     sameProcessAsFrameLoader,
     skipAnimation,
     skipBackgroundNotify,
     triggeringPrincipal,
     userContextId,
     recordExecution,
     replayExecution,
+    csp,
   } = {}) {
     // all callers of addTab that pass a params object need to pass
     // a valid triggeringPrincipal.
     if (!triggeringPrincipal) {
       throw new Error("Required argument triggeringPrincipal missing within addTab");
     }
 
 
@@ -2622,16 +2630,17 @@ window._gBrowser = {
       try {
         b.loadURI(aURI, {
           flags,
           triggeringPrincipal,
           referrerInfo: new ReferrerInfo(
             referrerPolicy, !noReferrer, referrerURI),
           charset,
           postData,
+          csp,
         });
       } catch (ex) {
         Cu.reportError(ex);
       }
     }
 
     // This field is updated regardless if we actually animate
     // since it's important that we keep this count correct in all cases.
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -314,16 +314,17 @@ function openLinkIn(url, where, params) 
   var aSkipTabAnimation     = params.skipTabAnimation;
   var aAllowPinnedTabHostChange = !!params.allowPinnedTabHostChange;
   var aNoReferrer           = params.noReferrer;
   var aAllowPopups          = !!params.allowPopups;
   var aUserContextId        = params.userContextId;
   var aIndicateErrorPageLoad = params.indicateErrorPageLoad;
   var aPrincipal            = params.originPrincipal;
   var aTriggeringPrincipal  = params.triggeringPrincipal;
+  var aCsp                  = params.csp;
   var aForceAboutBlankViewerInCurrent =
       params.forceAboutBlankViewerInCurrent;
   var aResolveOnNewTabCreated = params.resolveOnNewTabCreated;
 
   if (!aTriggeringPrincipal) {
     throw new Error("Must load with a triggering Principal");
   }
 
@@ -425,16 +426,18 @@ function openLinkIn(url, where, params) 
     sa.appendElement(charset);
     sa.appendElement(referrerURISupports);
     sa.appendElement(aPostData);
     sa.appendElement(allowThirdPartyFixupSupports);
     sa.appendElement(referrerPolicySupports);
     sa.appendElement(userContextIdSupports);
     sa.appendElement(aPrincipal);
     sa.appendElement(aTriggeringPrincipal);
+    sa.appendElement(null); // allowInheritPrincipal
+    sa.appendElement(aCsp);
 
     const sourceWindow = (w || window);
     let win;
     if (params.frameOuterWindowID != undefined && sourceWindow) {
       // Only notify it as a WebExtensions' webNavigation.onCreatedNavigationTarget
       // event if it contains the expected frameOuterWindowID params.
       // (e.g. we should not notify it as a onCreatedNavigationTarget if the user is
       // opening a new window using the keyboard shortcut).
@@ -543,16 +546,17 @@ function openLinkIn(url, where, params) 
                                          { recordExecution: "*", newFrameloader: true });
     }
 
     let ReferrerInfo = Components.Constructor("@mozilla.org/referrer-info;1",
                                               "nsIReferrerInfo",
                                               "init");
     targetBrowser.loadURI(url, {
       triggeringPrincipal: aTriggeringPrincipal,
+      csp: aCsp,
       referrerInfo: new ReferrerInfo(
         aReferrerPolicy, !aNoReferrer, aReferrerURI),
       flags,
       postData: aPostData,
       userContextId: aUserContextId,
     });
 
     // Don't focus the content area if focus is in the address bar and we're
@@ -577,16 +581,17 @@ function openLinkIn(url, where, params) 
       relatedToCurrent: aRelatedToCurrent,
       skipAnimation: aSkipTabAnimation,
       allowMixedContent: aAllowMixedContent,
       noReferrer: aNoReferrer,
       userContextId: aUserContextId,
       originPrincipal: aPrincipal,
       triggeringPrincipal: aTriggeringPrincipal,
       allowInheritPrincipal: aAllowInheritPrincipal,
+      csp: aCsp,
       focusUrlBar,
     });
     targetBrowser = tabUsedForLoad.linkedBrowser;
 
     if (aResolveOnNewTabCreated) {
       aResolveOnNewTabCreated(targetBrowser);
     }
 
--- a/browser/components/extensions/parent/ext-windows.js
+++ b/browser/components/extensions/parent/ext-windows.js
@@ -221,16 +221,18 @@ this.windows = class extends ExtensionAP
             args.appendElement(userContextIdSupports); // userContextId
           } else {
             args.appendElement(null);
           }
 
           args.appendElement(context.principal); // originPrincipal - not important.
           args.appendElement(principal); // triggeringPrincipal
           args.appendElement(Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool)); // allowInheritPrincipal
+          // Bug 965637, query the CSP from the doc instead of the Principal
+          args.appendElement(principal.csp); // csp
 
           let features = ["chrome"];
 
           if (createData.type === null || createData.type == "normal") {
             features.push("dialog=no", "all");
           } else {
             // All other types create "popup"-type windows by default.
             features.push("dialog", "resizable", "minimizable", "centerscreen", "titlebar", "close");
--- a/browser/components/sessionstore/ContentRestore.jsm
+++ b/browser/components/sessionstore/ContentRestore.jsm
@@ -209,25 +209,27 @@ ContentRestoreInternal.prototype = {
             "@mozilla.org/referrer-info;1",
             "nsIReferrerInfo",
             "init");
           referrerInfo = new ReferrerInfo(referrerPolicy, true, referrer);
         }
         let postData = loadArguments.postData ?
                        E10SUtils.makeInputStream(loadArguments.postData) : null;
         let triggeringPrincipal = E10SUtils.deserializePrincipal(loadArguments.triggeringPrincipal, () => Services.scriptSecurityManager.createNullPrincipal({}));
+        let csp = loadArguments.csp ? E10SUtils.deserializeCSP(loadArguments.csp) : null;
 
         if (loadArguments.userContextId) {
           webNavigation.setOriginAttributesBeforeLoading({ userContextId: loadArguments.userContextId });
         }
         let loadURIOptions = {
           triggeringPrincipal,
           loadFlags: loadArguments.flags,
           referrerInfo,
           postData,
+          csp,
         };
         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.
         let loadURIOptions = {
--- a/browser/modules/ContentClick.jsm
+++ b/browser/modules/ContentClick.jsm
@@ -8,16 +8,18 @@
 var EXPORTED_SYMBOLS = [ "ContentClick" ];
 
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 ChromeUtils.defineModuleGetter(this, "PlacesUIUtils",
                                "resource:///modules/PlacesUIUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
                                "resource://gre/modules/PrivateBrowsingUtils.jsm");
+ChromeUtils.defineModuleGetter(this, "E10SUtils",
+                               "resource://gre/modules/E10SUtils.jsm");
 
 var ContentClick = {
   // Listeners are added in BrowserGlue.jsm
   receiveMessage(message) {
     switch (message.name) {
       case "Content:Click":
         this.contentAreaClick(message.json, message.target);
         break;
@@ -71,16 +73,17 @@ var ContentClick = {
       charset: browser.characterSet,
       referrerURI: browser.documentURI,
       referrerPolicy: json.referrerPolicy,
       noReferrer: json.noReferrer,
       allowMixedContent: json.allowMixedContent,
       isContentWindowPrivate: json.isContentWindowPrivate,
       originPrincipal: json.originPrincipal,
       triggeringPrincipal: json.triggeringPrincipal,
+      csp: json.csp ? E10SUtils.deserializeCSP(json.csp) : null,
       frameOuterWindowID: json.frameOuterWindowID,
     };
 
     // The new tab/window must use the same userContextId.
     if (json.originAttributes.userContextId) {
       params.userContextId = json.originAttributes.userContextId;
     }
 
--- a/caps/nsIPrincipal.idl
+++ b/caps/nsIPrincipal.idl
@@ -146,22 +146,23 @@ interface nsIPrincipal : nsISerializable
      *                                   loadee inherits the principal of the
      *                                   loader.
      * @throws NS_ERROR_DOM_BAD_URI if the load is not allowed.
      */
     void checkMayLoad(in nsIURI uri, in boolean report,
                       in boolean allowIfInheritsPrincipal);
 
     /**
-     * A Content Security Policy associated with this principal.
-     * Use this function to query the associated CSP with this principal.
-     * Please *only* use this function to *set* a CSP when you know exactly what you are doing.
+     * A Content Security Policy associated with this principal. Use this function to
+     * query the associated CSP with this principal, but please *only* use this
+     * function to *set* a CSP when you know exactly what you are doing.
      * Most likely you want to call ensureCSP instead of setCSP.
      */
-    [noscript] attribute nsIContentSecurityPolicy csp;
+    readonly attribute nsIContentSecurityPolicy csp;
+    [noscript] void setCsp(in nsIContentSecurityPolicy aCsp);
 
     /*
      * Use this function to query a CSP associated with this principal.
      * If no CSP is associated with this principal then one is created
      * internally and setRequestContext is called on the CSP using aDocument.
      *
      * Please note if aDocument is null, then setRequestContext on the
      * CSP object is called using the current principal.
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -3911,16 +3911,17 @@ nsresult nsDocShell::LoadURI(const nsASt
   }
 
   loadState->SetLoadFlags(extraFlags);
   loadState->SetFirstParty(true);
   loadState->SetPostDataStream(postData);
   loadState->SetHeadersStream(aLoadURIOptions.mHeaders);
   loadState->SetBaseURI(aLoadURIOptions.mBaseURI);
   loadState->SetTriggeringPrincipal(aLoadURIOptions.mTriggeringPrincipal);
+  loadState->SetCsp(aLoadURIOptions.mCsp);
   loadState->SetForceAllowDataURI(forceAllowDataURI);
 
   if (fixupInfo) {
     nsAutoString searchProvider, keyword;
     fixupInfo->GetKeywordProviderName(searchProvider);
     fixupInfo->GetKeywordAsSent(keyword);
     MaybeNotifyKeywordSearchLoading(searchProvider, keyword);
   }
@@ -4553,16 +4554,23 @@ nsDocShell::Reload(uint32_t aReloadFlags
     uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
     nsAutoString srcdoc;
     nsCOMPtr<nsIURI> baseURI;
     nsCOMPtr<nsIURI> originalURI;
     nsCOMPtr<nsIURI> resultPrincipalURI;
     bool loadReplace = false;
 
     nsIPrincipal* triggeringPrincipal = doc->NodePrincipal();
+    // Currently the NodePrincipal holds the CSP for that document,
+    // after Bug 965637 we can query the CSP directly from the doc
+    // instead of doc->NodePrincipal().
+    nsCOMPtr<nsIContentSecurityPolicy> csp;
+    rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
+    NS_ENSURE_SUCCESS(rv, rv);
+
     nsAutoString contentTypeHint;
     doc->GetContentType(contentTypeHint);
 
     if (doc->IsSrcdocDocument()) {
       doc->GetSrcdocData(srcdoc);
       flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
       baseURI = doc->GetBaseURI();
     }
@@ -4595,16 +4603,17 @@ nsDocShell::Reload(uint32_t aReloadFlags
 
     RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(currentURI);
     loadState->SetReferrerInfo(mReferrerInfo);
     loadState->SetOriginalURI(originalURI);
     loadState->SetMaybeResultPrincipalURI(emplacedResultPrincipalURI);
     loadState->SetLoadReplace(loadReplace);
     loadState->SetTriggeringPrincipal(triggeringPrincipal);
     loadState->SetPrincipalToInherit(triggeringPrincipal);
+    loadState->SetCsp(csp);
     loadState->SetLoadFlags(flags);
     loadState->SetTypeHint(NS_ConvertUTF16toUTF8(contentTypeHint));
     loadState->SetLoadType(loadType);
     loadState->SetFirstParty(true);
     loadState->SetSrcdocData(srcdoc);
     loadState->SetSourceDocShell(this);
     loadState->SetBaseURI(baseURI);
     rv = InternalLoad(loadState, nullptr, nullptr);
@@ -5785,23 +5794,31 @@ nsDocShell::ForceRefreshURI(nsIURI* aURI
   if (!principal) {
     RefPtr<Document> doc = GetDocument();
     if (!doc) {
       return NS_ERROR_FAILURE;
     }
     principal = doc->NodePrincipal();
   }
   loadState->SetTriggeringPrincipal(principal);
+  // Currently the principal (NodePrincipal) holds the CSP for that
+  // document, after Bug 965637 we can query the CSP directly from
+  // the doc instead of the principal.
+  nsCOMPtr<nsIContentSecurityPolicy> csp;
+  nsresult rv = principal->GetCsp(getter_AddRefs(csp));
+  NS_ENSURE_SUCCESS(rv, rv);
+  loadState->SetCsp(csp);
+
   loadState->SetPrincipalIsExplicit(true);
 
   /* Check if this META refresh causes a redirection
    * to another site.
    */
   bool equalUri = false;
-  nsresult rv = aURI->Equals(mCurrentURI, &equalUri);
+  rv = aURI->Equals(mCurrentURI, &equalUri);
   if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh &&
       aDelay <= REFRESH_REDIRECT_TIMER) {
     /* It is a META refresh based redirection within the threshold time
      * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
      * Pass a REPLACE flag to LoadURI().
      */
     loadState->SetLoadType(LOAD_NORMAL_REPLACE);
 
@@ -6345,17 +6362,17 @@ nsDocShell::OnStateChange(nsIWebProgress
             static_cast<nsDocShell*>(parent.get())->ClearFrameHistory(entry);
           }
         }
 
         // This is a document.write(). Get the made-up url
         // from the channel and store it in session history.
         // Pass false for aCloneChildren, since we're creating
         // a new DOM here.
-        AddToSessionHistory(uri, wcwgChannel, nullptr, nullptr, false,
+        AddToSessionHistory(uri, wcwgChannel, nullptr, nullptr, nullptr, false,
                             getter_AddRefs(mLSHE));
         SetCurrentURI(uri, aRequest, true, 0);
         // Save history state of the previous page
         PersistLayoutHistoryState();
         // We'll never get an Embed() for this load, so just go ahead
         // and SetHistoryEntry now.
         SetHistoryEntry(&mOSHE, mLSHE);
       }
@@ -6850,16 +6867,23 @@ nsresult nsDocShell::EndPageLoad(nsIWebP
 
           nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
           MOZ_ASSERT(loadInfo, "loadInfo is required on all channels");
           nsCOMPtr<nsIPrincipal> triggeringPrincipal =
               loadInfo->TriggeringPrincipal();
 
           LoadURIOptions loadURIOptions;
           loadURIOptions.mTriggeringPrincipal = triggeringPrincipal;
+          // Currently we query the CSP from the triggeringPrincipal within
+          // the loadInfo. After Bug 965637, we can query the CSP from the
+          // loadInfo, which internally queries the CSP from the Client.
+          nsCOMPtr<nsIContentSecurityPolicy> csp;
+          nsresult rv = triggeringPrincipal->GetCsp(getter_AddRefs(csp));
+          NS_ENSURE_SUCCESS(rv, rv);
+          loadURIOptions.mCsp = csp;
           loadURIOptions.mPostData = newPostData;
           return LoadURI(newSpecW, loadURIOptions);
         }
       }
     }
 
     // Well, fixup didn't work :-(
     // It is time to throw an error dialog box, and be done with it...
@@ -8074,17 +8098,17 @@ nsresult nsDocShell::CreateContentViewer
 
     mFailedChannel = nullptr;
     mFailedURI = nullptr;
 
     // Create an shistory entry for the old load.
     if (failedURI) {
       errorOnLocationChangeNeeded =
           OnNewURI(failedURI, failedChannel, triggeringPrincipal, nullptr,
-                   mLoadType, false, false, false);
+                   mLoadType, nullptr, false, false, false);
     }
 
     // Be sure to have a correct mLSHE, it may have been cleared by
     // EndPageLoad. See bug 302115.
     if (mSessionHistory && !mLSHE) {
       int32_t idx = mSessionHistory->LegacySHistory()->GetRequestedIndex();
       if (idx == -1) {
         idx = mSessionHistory->Index();
@@ -8732,16 +8756,17 @@ nsresult nsDocShell::PerformRetargeting(
       aLoadState->GetMaybeResultPrincipalURI(resultPrincipalURI);
 
       loadState->SetMaybeResultPrincipalURI(resultPrincipalURI);
       loadState->SetKeepResultPrincipalURIIfSet(
           aLoadState->KeepResultPrincipalURIIfSet());
       // LoadReplace will always be false due to asserts above, skip setting
       // it.
       loadState->SetTriggeringPrincipal(aLoadState->TriggeringPrincipal());
+      loadState->SetCsp(aLoadState->Csp());
       loadState->SetInheritPrincipal(
           aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL));
       // Explicit principal because we do not want any guesses as to what the
       // principal to inherit is: it should be aTriggeringPrincipal.
       loadState->SetPrincipalIsExplicit(true);
       loadState->SetLoadType(LOAD_LINK);
       loadState->SetForceAllowDataURI(
           aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI));
@@ -8937,33 +8962,42 @@ nsresult nsDocShell::MaybeHandleSameDocu
   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
   doc->SetDocumentURI(aLoadState->URI());
 
   /* This is a anchor traversal within the same page.
    * call OnNewURI() so that, this traversal will be
    * recorded in session and global history.
    */
   nsCOMPtr<nsIPrincipal> newURITriggeringPrincipal, newURIPrincipalToInherit;
+  nsCOMPtr<nsIContentSecurityPolicy> newCsp;
   if (mOSHE) {
     newURITriggeringPrincipal = mOSHE->GetTriggeringPrincipal();
     newURIPrincipalToInherit = mOSHE->GetPrincipalToInherit();
+    newCsp = mOSHE->GetCsp();
   } else {
     newURITriggeringPrincipal = aLoadState->TriggeringPrincipal();
     newURIPrincipalToInherit = doc->NodePrincipal();
+    // This is a same-document navigation hence we query the CSP
+    // from the current document. Please note that currently the
+    // NodePrincipal holds the CSP for that document, after
+    // Bug 965637 we can query the CSP directly from
+    // the doc instead of the NodePrincipal.
+    nsresult rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(newCsp));
+    NS_ENSURE_SUCCESS(rv, rv);
   }
   // Pass true for aCloneSHChildren, since we're not
   // changing documents here, so all of our subframes are
   // still relevant to the new session history entry.
   //
   // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
   // flag on firing onLocationChange(...).
   // Anyway, aCloneSHChildren param is simply reflecting
   // doSameDocumentNavigation in this scope.
   OnNewURI(aLoadState->URI(), nullptr, newURITriggeringPrincipal,
-           newURIPrincipalToInherit, mLoadType, true, true, true);
+           newURIPrincipalToInherit, mLoadType, newCsp, true, true, true);
 
   nsCOMPtr<nsIInputStream> postData;
   uint32_t cacheKey = 0;
 
   bool scrollRestorationIsManual = false;
   if (mOSHE) {
     /* save current position of scroller(s) (bug 59774) */
     mOSHE->SetScrollPosition(scrollPos.x, scrollPos.y);
@@ -9322,17 +9356,17 @@ nsresult nsDocShell::InternalLoad(nsDocS
     bool shouldLoad;
     nsCOMPtr<nsIURI> referrer;
     nsIReferrerInfo* referrerInfo = aLoadState->GetReferrerInfo();
     if (referrerInfo) {
       referrerInfo->GetOriginalReferrer(getter_AddRefs(referrer));
     }
     rv = browserChrome3->ShouldLoadURI(
         this, aLoadState->URI(), referrer, !!aLoadState->PostDataStream(),
-        aLoadState->TriggeringPrincipal(), &shouldLoad);
+        aLoadState->TriggeringPrincipal(), aLoadState->Csp(), &shouldLoad);
     if (NS_SUCCEEDED(rv) && !shouldLoad) {
       return NS_OK;
     }
   }
 
   // Whenever a top-level browsing context is navigated, the user agent MUST
   // lock the orientation of the document to the document's default
   // orientation. We don't explicitly check for a top-level browsing context
@@ -9909,16 +9943,46 @@ nsresult nsDocShell::DoURILoad(nsDocShel
   }
 
   // Navigational requests that are same origin need to be upgraded in case
   // upgrade-insecure-requests is present. Please note that in that case
   // the triggeringPrincipal is holding the CSP that potentially
   // holds upgrade-insecure-requests.
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   aLoadState->TriggeringPrincipal()->GetCsp(getter_AddRefs(csp));
+
+#ifdef DEBUG
+  {
+    // After Bug 965637 we move the CSP from the Principal into the Client,
+    // hence we need an explicit CSP argument passed to docshell. Let's make
+    // sure the explicit CSP is the same as the CSP on the Principal.
+    uint32_t principalCSPCount = 0;
+    if (csp) {
+      csp->GetPolicyCount(&principalCSPCount);
+    }
+
+    nsCOMPtr<nsIContentSecurityPolicy> argsCSP = aLoadState->Csp();
+    uint32_t argCSPCount = 0;
+    if (argsCSP) {
+      argsCSP->GetPolicyCount(&argCSPCount);
+    }
+
+    MOZ_ASSERT(principalCSPCount == argCSPCount,
+               "Different PolicyCount for CSP as arg and Principal");
+
+    nsAutoString principalPolicyStr, argPolicyStr;
+    for (uint32_t i = 0; i < principalCSPCount; ++i) {
+      csp->GetPolicyString(i, principalPolicyStr);
+      argsCSP->GetPolicyString(i, argPolicyStr);
+      MOZ_ASSERT(principalPolicyStr.Equals(argPolicyStr),
+                 "Different PolicyStr for CSP as arg and Principal");
+    }
+  }
+#endif
+
   if (csp) {
     bool upgradeInsecureRequests = false;
     csp->GetUpgradeInsecureRequests(&upgradeInsecureRequests);
     if (upgradeInsecureRequests) {
       // only upgrade if the navigation is same origin
       nsCOMPtr<nsIPrincipal> resultPrincipal;
       rv = nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(
           channel, getter_AddRefs(resultPrincipal));
@@ -10539,16 +10603,17 @@ void nsDocShell::SetupReferrerInfoFromCh
       }
     }
   }
 }
 
 bool nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
                           nsIPrincipal* aTriggeringPrincipal,
                           nsIPrincipal* aPrincipalToInherit, uint32_t aLoadType,
+                          nsIContentSecurityPolicy* aCsp,
                           bool aFireOnLocationChange, bool aAddToGlobalHistory,
                           bool aCloneSHChildren) {
   MOZ_ASSERT(aURI, "uri is null");
   MOZ_ASSERT(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set");
 
   MOZ_ASSERT(!aPrincipalToInherit ||
              (aPrincipalToInherit && aTriggeringPrincipal));
 
@@ -10714,17 +10779,17 @@ bool nsDocShell::OnNewURI(nsIURI* aURI, 
   if (updateSHistory) {
     // Update session history if necessary...
     if (!mLSHE && (mItemType == typeContent) && mURIResultedInDocument) {
       /* This is  a fresh page getting loaded for the first time
        *.Create a Entry for it and add it to SH, if this is the
        * rootDocShell
        */
       (void)AddToSessionHistory(aURI, aChannel, aTriggeringPrincipal,
-                                aPrincipalToInherit, aCloneSHChildren,
+                                aPrincipalToInherit, aCsp, aCloneSHChildren,
                                 getter_AddRefs(mLSHE));
     }
   } else if (mSessionHistory && mLSHE && mURIResultedInDocument) {
     // Even if we don't add anything to SHistory, ensure the current index
     // points to the same SHEntry as our mLSHE.
     int32_t index = mSessionHistory->LegacySHistory()->GetRequestedIndex();
     if (index == -1) {
       index = mSessionHistory->Index();
@@ -10800,17 +10865,17 @@ bool nsDocShell::OnLoadingSite(nsIChanne
   // If this a redirect, use the final url (uri)
   // else use the original url
   //
   // Note that this should match what documents do (see Document::Reset).
   NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   NS_ENSURE_TRUE(uri, false);
 
   // Pass false for aCloneSHChildren, since we're loading a new page here.
-  return OnNewURI(uri, aChannel, nullptr, nullptr, mLoadType,
+  return OnNewURI(uri, aChannel, nullptr, nullptr, mLoadType, nullptr,
                   aFireOnLocationChange, aAddToGlobalHistory, false);
 }
 
 void nsDocShell::SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
   mReferrerInfo = aReferrerInfo;  // This assigment addrefs
 }
 
 //*****************************************************************************
@@ -11005,21 +11070,27 @@ nsDocShell::AddState(JS::Handle<JS::Valu
   nsCOMPtr<nsISHEntry> newSHEntry;
   if (!aReplace) {
     // Save the current scroll position (bug 590573).
     nsPoint scrollPos = GetCurScrollPos();
     mOSHE->SetScrollPosition(scrollPos.x, scrollPos.y);
 
     bool scrollRestorationIsManual = mOSHE->GetScrollRestorationIsManual();
 
+    // Currently the NodePrincipal holds the CSP for that document,
+    // after Bug 965637 we can query the CSP directly from
+    // the doc instead of the NodePrincipal.
+    nsCOMPtr<nsIContentSecurityPolicy> csp;
+    document->NodePrincipal()->GetCsp(getter_AddRefs(csp));
+
     // Since we're not changing which page we have loaded, pass
     // true for aCloneChildren.
     rv = AddToSessionHistory(newURI, nullptr,
                              document->NodePrincipal(),  // triggeringPrincipal
-                             nullptr, true, getter_AddRefs(newSHEntry));
+                             nullptr, csp, true, getter_AddRefs(newSHEntry));
     NS_ENSURE_SUCCESS(rv, rv);
 
     NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
 
     // Session history entries created by pushState inherit scroll restoration
     // mode from the current entry.
     newSHEntry->SetScrollRestorationIsManual(scrollRestorationIsManual);
 
@@ -11182,16 +11253,17 @@ bool nsDocShell::ShouldAddToSessionHisto
   }
 
   return true;
 }
 
 nsresult nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
                                          nsIPrincipal* aTriggeringPrincipal,
                                          nsIPrincipal* aPrincipalToInherit,
+                                         nsIContentSecurityPolicy* aCsp,
                                          bool aCloneChildren,
                                          nsISHEntry** aNewEntry) {
   MOZ_ASSERT(aURI, "uri is null");
   MOZ_ASSERT(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set");
 
 #if defined(DEBUG)
   if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
     nsAutoCString chanName;
@@ -11248,16 +11320,17 @@ nsresult nsDocShell::AddToSessionHistory
   nsCOMPtr<nsIURI> originalURI;
   nsCOMPtr<nsIURI> resultPrincipalURI;
   bool loadReplace = false;
   nsCOMPtr<nsIURI> referrerURI;
   uint32_t referrerPolicy = RP_Unset;
   uint32_t cacheKey = 0;
   nsCOMPtr<nsIPrincipal> triggeringPrincipal = aTriggeringPrincipal;
   nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit;
+  nsCOMPtr<nsIContentSecurityPolicy> csp = aCsp;
   bool expired = false;
   bool discardLayoutState = false;
   nsCOMPtr<nsICacheInfoChannel> cacheChannel;
   if (aChannel) {
     cacheChannel = do_QueryInterface(aChannel);
 
     /* If there is a caching channel, get the Cache Key and store it
      * in SH.
@@ -11287,16 +11360,24 @@ nsresult nsDocShell::AddToSessionHistory
 
       discardLayoutState = ShouldDiscardLayoutState(httpChannel);
     }
 
     nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
     if (!triggeringPrincipal) {
       triggeringPrincipal = loadInfo->TriggeringPrincipal();
     }
+    if (!csp && triggeringPrincipal) {
+      // Currently if no CSP is passed explicitly we query the CSP from
+      // the triggeringPrincipal from within the loadinfo. After Bug 965637,
+      // we can query the CSP from the loadInfo directly in case the CSP is
+      // not passed explicitly. Internally the loadinfo queries the CSP
+      // from the Client.
+      triggeringPrincipal->GetCsp(getter_AddRefs(csp));
+    }
 
     loadInfo->GetResultPrincipalURI(getter_AddRefs(resultPrincipalURI));
 
     // For now keep storing just the principal in the SHEntry.
     if (!principalToInherit) {
       if (loadInfo->GetLoadingSandboxed()) {
         if (loadInfo->LoadingPrincipal()) {
           principalToInherit = NullPrincipal::CreateWithInheritedAttributes(
@@ -11316,17 +11397,17 @@ nsresult nsDocShell::AddToSessionHistory
   // Title is set in nsDocShell::SetTitle()
   entry->Create(aURI,                 // uri
                 EmptyString(),        // Title
                 inputStream,          // Post data stream
                 nullptr,              // LayoutHistory state
                 cacheKey,             // CacheKey
                 mContentTypeHint,     // Content-type
                 triggeringPrincipal,  // Channel or provided principal
-                principalToInherit, mHistoryID, mDynamicallyCreated);
+                principalToInherit, csp, mHistoryID, mDynamicallyCreated);
 
   entry->SetOriginalURI(originalURI);
   entry->SetResultPrincipalURI(resultPrincipalURI);
   entry->SetLoadReplace(loadReplace);
   entry->SetReferrerInfo(new ReferrerInfo(referrerURI, referrerPolicy));
   nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel);
   if (inStrmChan) {
     bool isSrcdocChannel;
@@ -11434,16 +11515,17 @@ nsresult nsDocShell::LoadHistoryEntry(ns
   nsCOMPtr<nsIURI> originalURI = aEntry->GetOriginalURI();
   nsCOMPtr<nsIURI> resultPrincipalURI = aEntry->GetResultPrincipalURI();
   bool loadReplace = aEntry->GetLoadReplace();
   nsCOMPtr<nsIInputStream> postData = aEntry->GetPostData();
   nsAutoCString contentType;
   aEntry->GetContentType(contentType);
   nsCOMPtr<nsIPrincipal> triggeringPrincipal = aEntry->GetTriggeringPrincipal();
   nsCOMPtr<nsIPrincipal> principalToInherit = aEntry->GetPrincipalToInherit();
+  nsCOMPtr<nsIContentSecurityPolicy> csp = aEntry->GetCsp();
   nsCOMPtr<nsIReferrerInfo> referrerInfo = aEntry->GetReferrerInfo();
 
   // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
   // that's the only thing holding a ref to aEntry that will cause aEntry to
   // die while we're loading it.  So hold a strong ref to aEntry here, just
   // in case.
   nsCOMPtr<nsISHEntry> kungFuDeathGrip(aEntry);
   nsresult rv;
@@ -11527,16 +11609,17 @@ nsresult nsDocShell::LoadHistoryEntry(ns
   loadState->SetLoadFlags(flags);
   loadState->SetTypeHint(contentType);
   loadState->SetPostDataStream(postData);
   loadState->SetLoadType(aLoadType);
   loadState->SetSHEntry(aEntry);
   loadState->SetFirstParty(true);
   loadState->SetSrcdocData(srcdoc);
   loadState->SetBaseURI(baseURI);
+  loadState->SetCsp(csp);
 
   rv = InternalLoad(loadState,
                     nullptr,   // No nsIDocShell
                     nullptr);  // No nsIRequest
   return rv;
 }
 
 NS_IMETHODIMP
@@ -12341,33 +12424,34 @@ nsresult nsDocShell::EnsureCommandHandle
 
 class OnLinkClickEvent : public Runnable {
  public:
   OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent, nsIURI* aURI,
                    const nsAString& aTargetSpec, const nsAString& aFileName,
                    nsIInputStream* aPostDataStream,
                    nsIInputStream* aHeadersDataStream, bool aNoOpenerImplied,
                    bool aIsUserTriggered, bool aIsTrusted,
-                   nsIPrincipal* aTriggeringPrincipal);
+                   nsIPrincipal* aTriggeringPrincipal,
+                   nsIContentSecurityPolicy* aCsp);
 
   NS_IMETHOD Run() override {
     nsAutoPopupStatePusher popupStatePusher(mPopupState);
 
     // We need to set up an AutoJSAPI here for the following reason: When we
     // do OnLinkClickSync we'll eventually end up in
     // nsGlobalWindow::OpenInternal which only does popup blocking if
     // !LegacyIsCallerChromeOrNativeCode(). So we need to fake things so that
     // we don't look like native code as far as LegacyIsCallerNativeCode() is
     // concerned.
     AutoJSAPI jsapi;
     if (mIsTrusted || jsapi.Init(mContent->OwnerDoc()->GetScopeObject())) {
       mHandler->OnLinkClickSync(mContent, mURI, mTargetSpec, mFileName,
                                 mPostDataStream, mHeadersDataStream,
                                 mNoOpenerImplied, nullptr, nullptr,
-                                mIsUserTriggered, mTriggeringPrincipal);
+                                mIsUserTriggered, mTriggeringPrincipal, mCsp);
     }
     return NS_OK;
   }
 
  private:
   RefPtr<nsDocShell> mHandler;
   nsCOMPtr<nsIURI> mURI;
   nsString mTargetSpec;
@@ -12375,48 +12459,46 @@ class OnLinkClickEvent : public Runnable
   nsCOMPtr<nsIInputStream> mPostDataStream;
   nsCOMPtr<nsIInputStream> mHeadersDataStream;
   nsCOMPtr<nsIContent> mContent;
   PopupBlocker::PopupControlState mPopupState;
   bool mNoOpenerImplied;
   bool mIsUserTriggered;
   bool mIsTrusted;
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
+  nsCOMPtr<nsIContentSecurityPolicy> mCsp;
 };
 
-OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
-                                   nsIURI* aURI, const nsAString& aTargetSpec,
-                                   const nsAString& aFileName,
-                                   nsIInputStream* aPostDataStream,
-                                   nsIInputStream* aHeadersDataStream,
-                                   bool aNoOpenerImplied, bool aIsUserTriggered,
-                                   bool aIsTrusted,
-                                   nsIPrincipal* aTriggeringPrincipal)
+OnLinkClickEvent::OnLinkClickEvent(
+    nsDocShell* aHandler, nsIContent* aContent, nsIURI* aURI,
+    const nsAString& aTargetSpec, const nsAString& aFileName,
+    nsIInputStream* aPostDataStream, nsIInputStream* aHeadersDataStream,
+    bool aNoOpenerImplied, bool aIsUserTriggered, bool aIsTrusted,
+    nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp)
     : mozilla::Runnable("OnLinkClickEvent"),
       mHandler(aHandler),
       mURI(aURI),
       mTargetSpec(aTargetSpec),
       mFileName(aFileName),
       mPostDataStream(aPostDataStream),
       mHeadersDataStream(aHeadersDataStream),
       mContent(aContent),
       mPopupState(PopupBlocker::GetPopupControlState()),
       mNoOpenerImplied(aNoOpenerImplied),
       mIsUserTriggered(aIsUserTriggered),
       mIsTrusted(aIsTrusted),
-      mTriggeringPrincipal(aTriggeringPrincipal) {}
-
-NS_IMETHODIMP
-nsDocShell::OnLinkClick(nsIContent* aContent, nsIURI* aURI,
-                        const nsAString& aTargetSpec,
-                        const nsAString& aFileName,
-                        nsIInputStream* aPostDataStream,
-                        nsIInputStream* aHeadersDataStream,
-                        bool aIsUserTriggered, bool aIsTrusted,
-                        nsIPrincipal* aTriggeringPrincipal) {
+      mTriggeringPrincipal(aTriggeringPrincipal),
+      mCsp(aCsp) {}
+
+NS_IMETHODIMP
+nsDocShell::OnLinkClick(
+    nsIContent* aContent, nsIURI* aURI, const nsAString& aTargetSpec,
+    const nsAString& aFileName, nsIInputStream* aPostDataStream,
+    nsIInputStream* aHeadersDataStream, bool aIsUserTriggered, bool aIsTrusted,
+    nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp) {
 #ifndef ANDROID
   MOZ_ASSERT(aTriggeringPrincipal, "Need a valid triggeringPrincipal");
 #endif
   NS_ASSERTION(NS_IsMainThread(), "wrong thread");
 
   if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI)) {
     return NS_OK;
   }
@@ -12447,38 +12529,36 @@ nsDocShell::OnLinkClick(nsIContent* aCon
       noOpenerImplied = true;
     }
   }
 
   if (NS_FAILED(rv)) {
     target = aTargetSpec;
   }
 
-  nsCOMPtr<nsIRunnable> ev =
-      new OnLinkClickEvent(this, aContent, aURI, target, aFileName,
-                           aPostDataStream, aHeadersDataStream, noOpenerImplied,
-                           aIsUserTriggered, aIsTrusted, aTriggeringPrincipal);
+  nsCOMPtr<nsIRunnable> ev = new OnLinkClickEvent(
+      this, aContent, aURI, target, aFileName, aPostDataStream,
+      aHeadersDataStream, noOpenerImplied, aIsUserTriggered, aIsTrusted,
+      aTriggeringPrincipal, aCsp);
   return DispatchToTabGroup(TaskCategory::UI, ev.forget());
 }
 
 static bool IsElementAnchorOrArea(nsIContent* aContent) {
   // Make sure we are dealing with either an <A> or <AREA> element in the HTML
   // or XHTML namespace.
   return aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area);
 }
 
 NS_IMETHODIMP
-nsDocShell::OnLinkClickSync(nsIContent* aContent, nsIURI* aURI,
-                            const nsAString& aTargetSpec,
-                            const nsAString& aFileName,
-                            nsIInputStream* aPostDataStream,
-                            nsIInputStream* aHeadersDataStream,
-                            bool aNoOpenerImplied, nsIDocShell** aDocShell,
-                            nsIRequest** aRequest, bool aIsUserTriggered,
-                            nsIPrincipal* aTriggeringPrincipal) {
+nsDocShell::OnLinkClickSync(
+    nsIContent* aContent, nsIURI* aURI, const nsAString& aTargetSpec,
+    const nsAString& aFileName, nsIInputStream* aPostDataStream,
+    nsIInputStream* aHeadersDataStream, bool aNoOpenerImplied,
+    nsIDocShell** aDocShell, nsIRequest** aRequest, bool aIsUserTriggered,
+    nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp) {
   // Initialize the DocShell / Request
   if (aDocShell) {
     *aDocShell = nullptr;
   }
   if (aRequest) {
     *aRequest = nullptr;
   }
 
@@ -12519,16 +12599,24 @@ nsDocShell::OnLinkClickSync(nsIContent* 
     }
   }
 
   // if the triggeringPrincipal is not passed explicitly, then we
   // fall back to using doc->NodePrincipal() as the triggeringPrincipal.
   nsCOMPtr<nsIPrincipal> triggeringPrincipal =
       aTriggeringPrincipal ? aTriggeringPrincipal : aContent->NodePrincipal();
 
+  nsCOMPtr<nsIContentSecurityPolicy> csp = aCsp;
+  if (!csp) {
+    // Currently, if no csp is passed explicitly we fall back to querying the
+    // CSP from the NodePrincipal(). After Bug 965637 we can fall back to
+    // querying the CSP from the document (aContent->OwnerDoc()).
+    aContent->NodePrincipal()->GetCsp(getter_AddRefs(csp));
+  }
+
   uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
   if (IsElementAnchorOrArea(aContent)) {
     MOZ_ASSERT(aContent->IsHTMLElement());
     nsAutoString referrer;
     aContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, referrer);
     nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(
         referrer);
 
@@ -12630,16 +12718,17 @@ nsDocShell::OnLinkClickSync(nsIContent* 
 
   bool sendReferrer = !(flags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER);
   nsCOMPtr<nsIReferrerInfo> referrerInfo =
       new ReferrerInfo(referrer, refererPolicy, sendReferrer);
   RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(aURI);
   loadState->SetReferrerInfo(referrerInfo);
   loadState->SetTriggeringPrincipal(triggeringPrincipal);
   loadState->SetPrincipalToInherit(aContent->NodePrincipal());
+  loadState->SetCsp(csp);
   loadState->SetLoadFlags(flags);
   loadState->SetTarget(aTargetSpec);
   loadState->SetTypeHint(NS_ConvertUTF16toUTF8(typeHint));
   loadState->SetFileName(aFileName);
   loadState->SetPostDataStream(aPostDataStream);
   loadState->SetHeadersStream(aHeadersDataStream);
   loadState->SetLoadType(loadType);
   loadState->SetFirstParty(true);
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -212,24 +212,26 @@ class nsDocShell final : public nsDocLoa
 
   // nsILinkHandler
   NS_IMETHOD OnLinkClick(nsIContent* aContent, nsIURI* aURI,
                          const nsAString& aTargetSpec,
                          const nsAString& aFileName,
                          nsIInputStream* aPostDataStream,
                          nsIInputStream* aHeadersDataStream,
                          bool aIsUserTriggered, bool aIsTrusted,
-                         nsIPrincipal* aTriggeringPrincipal) override;
+                         nsIPrincipal* aTriggeringPrincipal,
+                         nsIContentSecurityPolicy* aCsp) override;
   NS_IMETHOD OnLinkClickSync(
       nsIContent* aContent, nsIURI* aURI, const nsAString& aTargetSpec,
       const nsAString& aFileName, nsIInputStream* aPostDataStream = 0,
       nsIInputStream* aHeadersDataStream = 0, bool aNoOpenerImplied = false,
       nsIDocShell** aDocShell = 0, nsIRequest** aRequest = 0,
       bool aIsUserTriggered = false,
-      nsIPrincipal* aTriggeringPrincipal = nullptr) override;
+      nsIPrincipal* aTriggeringPrincipal = nullptr,
+      nsIContentSecurityPolicy* aCsp = nullptr) override;
   NS_IMETHOD OnOverLink(nsIContent* aContent, nsIURI* aURI,
                         const nsAString& aTargetSpec) override;
   NS_IMETHOD OnLeaveLink() override;
 
   // Don't use NS_DECL_NSILOADCONTEXT because some of nsILoadContext's methods
   // are shared with nsIDocShell (appID, etc.) and can't be declared twice.
   NS_IMETHOD GetAssociatedWindow(mozIDOMWindowProxy**) override;
   NS_IMETHOD GetTopWindow(mozIDOMWindowProxy**) override;
@@ -497,20 +499,25 @@ class nsDocShell final : public nsDocLoa
   bool ShouldAddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel);
 
   // Either aChannel or aOwner must be null. If aChannel is
   // present, the owner should be gotten from it.
   // If aCloneChildren is true, then our current session history's
   // children will be cloned onto the new entry. This should be
   // used when we aren't actually changing the document while adding
   // the new session history entry.
-
+  // aCsp is the CSP to be used for the load. That is *not* the CSP
+  // that will be applied to subresource loads within that document
+  // but the CSP for the document load itself. E.g. if that CSP
+  // includes upgrade-insecure-requests, then the new top-level load
+  // will be upgraded to HTTPS.
   nsresult AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
                                nsIPrincipal* aTriggeringPrincipal,
                                nsIPrincipal* aPrincipalToInherit,
+                               nsIContentSecurityPolicy* aCsp,
                                bool aCloneChildren, nsISHEntry** aNewEntry);
 
   nsresult AddChildSHEntryToParent(nsISHEntry* aNewEntry, int32_t aChildOffset,
                                    bool aCloneChildren);
 
   nsresult AddChildSHEntryInternal(nsISHEntry* aCloneRef, nsISHEntry* aNewEntry,
                                    int32_t aChildOffset, uint32_t aLoadType,
                                    bool aCloneChildren);
@@ -565,21 +572,26 @@ class nsDocShell final : public nsDocLoa
   // but did not because aFireOnLocationChange was false on entry.
   // In this case it is the caller's responsibility to ensure
   // FireOnLocationChange is called.
   // In all other cases false is returned.
   // Either aChannel or aTriggeringPrincipal must be null. If aChannel is
   // present, the owner should be gotten from it.
   // If OnNewURI calls AddToSessionHistory, it will pass its
   // aCloneSHChildren argument as aCloneChildren.
+  // aCsp is the CSP to be used for the load. That is *not* the CSP
+  // that will be applied to subresource loads within that document
+  // but the CSP for the document load itself. E.g. if that CSP
+  // includes upgrade-insecure-requests, then the new top-level load
+  // will be upgraded to HTTPS.
   bool OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
                 nsIPrincipal* aTriggeringPrincipal,
                 nsIPrincipal* aPrincipalToInherit, uint32_t aLoadType,
-                bool aFireOnLocationChange, bool aAddToGlobalHistory,
-                bool aCloneSHChildren);
+                nsIContentSecurityPolicy* aCsp, bool aFireOnLocationChange,
+                bool aAddToGlobalHistory, bool aCloneSHChildren);
 
   // Helper method that is called when a new document (including any
   // sub-documents - ie. frames) has been completely loaded.
   nsresult EndPageLoad(nsIWebProgress* aProgress, nsIChannel* aChannel,
                        nsresult aResult);
 
   // Builds an error page URI (e.g. about:neterror?etc) for the given aURI
   // and displays it via the LoadErrorPage() overload below.
--- a/docshell/base/nsDocShellLoadState.cpp
+++ b/docshell/base/nsDocShellLoadState.cpp
@@ -57,16 +57,17 @@ nsDocShellLoadState::nsDocShellLoadState
   mReferrerInfo =
       new ReferrerInfo(aLoadState.Referrer(), aLoadState.ReferrerPolicy(),
                        aLoadState.SendReferrer());
   mURI = aLoadState.URI();
   mOriginalURI = aLoadState.OriginalURI();
   mBaseURI = aLoadState.BaseURI();
   mTriggeringPrincipal = aLoadState.TriggeringPrincipal();
   mPrincipalToInherit = aLoadState.PrincipalToInherit();
+  mCsp = aLoadState.Csp();
 }
 
 nsDocShellLoadState::~nsDocShellLoadState() {}
 
 nsresult nsDocShellLoadState::CreateFromPendingChannel(
     nsIChildChannel* aPendingChannel, nsDocShellLoadState** aResult) {
   nsCOMPtr<nsIChannel> channel = do_QueryInterface(aPendingChannel);
   if (NS_WARN_IF(!channel)) {
@@ -162,16 +163,22 @@ nsIPrincipal* nsDocShellLoadState::Princ
   return mPrincipalToInherit;
 }
 
 void nsDocShellLoadState::SetPrincipalToInherit(
     nsIPrincipal* aPrincipalToInherit) {
   mPrincipalToInherit = aPrincipalToInherit;
 }
 
+void nsDocShellLoadState::SetCsp(nsIContentSecurityPolicy* aCsp) {
+  mCsp = aCsp;
+}
+
+nsIContentSecurityPolicy* nsDocShellLoadState::Csp() const { return mCsp; }
+
 bool nsDocShellLoadState::InheritPrincipal() const { return mInheritPrincipal; }
 
 void nsDocShellLoadState::SetInheritPrincipal(bool aInheritPrincipal) {
   mInheritPrincipal = aInheritPrincipal;
 }
 
 bool nsDocShellLoadState::PrincipalIsExplicit() const {
   return mPrincipalIsExplicit;
@@ -454,13 +461,14 @@ DocShellLoadStateInit nsDocShellLoadStat
   loadState.FileName() = mFileName;
   loadState.IsFromProcessingFrameAttributes() =
       mIsFromProcessingFrameAttributes;
   loadState.URI() = mURI;
   loadState.OriginalURI() = mOriginalURI;
   loadState.BaseURI() = mBaseURI;
   loadState.TriggeringPrincipal() = mTriggeringPrincipal;
   loadState.PrincipalToInherit() = mPrincipalToInherit;
+  loadState.Csp() = mCsp;
   loadState.Referrer() = mReferrerInfo->GetOriginalReferrer();
   loadState.SendReferrer() = mReferrerInfo->GetSendReferrer();
   loadState.ReferrerPolicy() = mReferrerInfo->GetReferrerPolicy();
   return loadState;
 }
--- a/docshell/base/nsDocShellLoadState.h
+++ b/docshell/base/nsDocShellLoadState.h
@@ -8,16 +8,17 @@
 #define nsDocShellLoadState_h__
 
 // Helper Classes
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsDocShellLoadTypes.h"
 #include "mozilla/net/ReferrerPolicy.h"
 
+class nsIContentSecurityPolicy;
 class nsIInputStream;
 class nsISHEntry;
 class nsIURI;
 class nsIDocShell;
 class nsIChildChannel;
 class nsIReferrerInfo;
 class OriginAttibutes;
 namespace mozilla {
@@ -73,16 +74,20 @@ class nsDocShellLoadState final {
   bool LoadReplace() const;
 
   void SetLoadReplace(bool aLoadReplace);
 
   nsIPrincipal* TriggeringPrincipal() const;
 
   void SetTriggeringPrincipal(nsIPrincipal* aTriggeringPrincipal);
 
+  nsIContentSecurityPolicy* Csp() const;
+
+  void SetCsp(nsIContentSecurityPolicy* aCsp);
+
   bool InheritPrincipal() const;
 
   void SetInheritPrincipal(bool aInheritPrincipal);
 
   bool PrincipalIsExplicit() const;
 
   void SetPrincipalIsExplicit(bool aPrincipalIsExplicit);
 
@@ -221,16 +226,23 @@ class nsDocShellLoadState final {
   // load to occur. In most cases the referrer and the triggeringPrincipal's URI
   // will be identical.
   //
   // Please note that this is the principal that is used for security checks. If
   // the argument aURI is provided by the web, then please do not pass a
   // SystemPrincipal as the triggeringPrincipal.
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
 
+  // The CSP of the load, that is, the CSP of the entity responsible for causing
+  // the load to occur. Most likely this is the CSP of the document that started
+  // the load. In case the entity starting the load did not use a CSP, then mCsp
+  // can be null. Please note that this is also the CSP that will be applied to
+  // the load in case the load encounters a server side redirect.
+  nsCOMPtr<nsIContentSecurityPolicy> mCsp;
+
   // If a refresh is caused by http-equiv="refresh" we want to set
   // aResultPrincipalURI, but we do not want to overwrite the channel's
   // ResultPrincipalURI, if it has already been set on the channel by a protocol
   // handler.
   bool mKeepResultPrincipalURIIfSet;
 
   // If set LOAD_REPLACE flag will be set on the channel. If aOriginalURI is
   // null, this argument is ignored.
--- a/docshell/base/nsDocShellTreeOwner.cpp
+++ b/docshell/base/nsDocShellTreeOwner.cpp
@@ -901,16 +901,19 @@ nsDocShellTreeOwner::HandleEvent(Event* 
             if (!url.IsEmpty()) {
 #ifndef ANDROID
               MOZ_ASSERT(triggeringPrincipal,
                          "nsDocShellTreeOwner::HandleEvent: Need a valid "
                          "triggeringPrincipal");
 #endif
               LoadURIOptions loadURIOptions;
               loadURIOptions.mTriggeringPrincipal = triggeringPrincipal;
+              nsCOMPtr<nsIContentSecurityPolicy> csp;
+              handler->GetCSP(dragEvent, getter_AddRefs(csp));
+              loadURIOptions.mCsp = csp;
               webnav->LoadURI(url, loadURIOptions);
             }
           }
 
           for (uint32_t i = 0; i < linksCount; i++) {
             NS_RELEASE(links[i]);
           }
           free(links);
--- a/docshell/base/nsILinkHandler.h
+++ b/docshell/base/nsILinkHandler.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsILinkHandler_h___
 #define nsILinkHandler_h___
 
 #include "nsISupports.h"
 #include "mozilla/EventForwards.h"
 
 class nsIContent;
+class nsIContentSecurityPolicy;
 class nsIDocShell;
 class nsIInputStream;
 class nsIRequest;
 
 #define NS_ILINKHANDLER_IID                          \
   {                                                  \
     0xceb9aade, 0x43da, 0x4f1a, {                    \
       0xac, 0x8a, 0xc7, 0x09, 0xfb, 0x22, 0x46, 0x64 \
@@ -37,24 +38,30 @@ class nsILinkHandler : public nsISupport
    *        string)
    * @param aFileName non-null when the link should be downloaded as the given
    * file
    * @param aPostDataStream the POST data to send
    * @param aHeadersDataStream ???
    * @param aIsTrusted false if the triggerer is an untrusted DOM event.
    * @param aTriggeringPrincipal, if not passed explicitly we fall back to
    *        the document's principal.
+   * @param aCsp, the CSP to be used for the load, that is the CSP of the
+   *        entity responsible for causing the load to occur. Most likely
+   *        this is the CSP of the document that started the load. In case
+   *        aCsp was not passed explicitly we fall back to using
+   *        aContent's document's CSP if that document holds any.
    */
   NS_IMETHOD OnLinkClick(nsIContent* aContent, nsIURI* aURI,
                          const nsAString& aTargetSpec,
                          const nsAString& aFileName,
                          nsIInputStream* aPostDataStream,
                          nsIInputStream* aHeadersDataStream,
                          bool aIsUserTriggered, bool aIsTrusted,
-                         nsIPrincipal* aTriggeringPrincipal) = 0;
+                         nsIPrincipal* aTriggeringPrincipal,
+                         nsIContentSecurityPolicy* aCsp) = 0;
 
   /**
    * Process a click on a link.
    *
    * Works the same as OnLinkClick() except it happens immediately rather than
    * through an event.
    *
    * @param aContent the content for the frame that generated the trigger
@@ -65,24 +72,30 @@ class nsILinkHandler : public nsISupport
    * file
    * @param aPostDataStream the POST data to send
    * @param aHeadersDataStream ???
    * @param aNoOpenerImplied if the link implies "noopener"
    * @param aDocShell (out-param) the DocShell that the request was opened on
    * @param aRequest the request that was opened
    * @param aTriggeringPrincipal, if not passed explicitly we fall back to
    *        the document's principal.
+   * @param aCsp, the CSP to be used for the load, that is the CSP of the
+   *        entity responsible for causing the load to occur. Most likely
+   *        this is the CSP of the document that started the load. In case
+   *        aCsp was not passed explicitly we fall back to using
+   *        aContent's document's CSP if that document holds any.
    */
   NS_IMETHOD OnLinkClickSync(
       nsIContent* aContent, nsIURI* aURI, const nsAString& aTargetSpec,
       const nsAString& aFileName, nsIInputStream* aPostDataStream = 0,
       nsIInputStream* aHeadersDataStream = 0, bool aNoOpenerImplied = false,
       nsIDocShell** aDocShell = 0, nsIRequest** aRequest = 0,
       bool aIsUserTriggered = false,
-      nsIPrincipal* aTriggeringPrincipal = nullptr) = 0;
+      nsIPrincipal* aTriggeringPrincipal = nullptr,
+      nsIContentSecurityPolicy* aCsp = nullptr) = 0;
 
   /**
    * Process a mouse-over a link.
    *
    * @param aContent the linked content.
    * @param aURI an URI object that defines the destination for the link
    * @param aTargetSpec indicates where the link is targeted (it may be an empty
    *        string)
--- a/docshell/shistory/nsISHEntry.idl
+++ b/docshell/shistory/nsISHEntry.idl
@@ -6,16 +6,17 @@
 /**
  * The interface to nsISHentry. Each document or subframe in
  * Session History will have a nsISHEntry associated with it which will
  * hold all information required to recreate the document from history
  */
 
 #include "nsISupports.idl"
 
+interface nsIContentSecurityPolicy;
 interface nsIMutableArray;
 interface nsILayoutHistoryState;
 interface nsIContentViewer;
 interface nsIURI;
 interface nsIInputStream;
 interface nsIDocShellTreeItem;
 interface nsIStructuredCloneContainer;
 interface nsIBFCacheEntry;
@@ -144,16 +145,23 @@ interface nsISHEntry : nsISupports
 
     /**
      * Get the principal, if any, that is used when the inherit flag
      * is set.
      */
     [infallible] attribute nsIPrincipal principalToInherit;
 
     /**
+     * Get the csp, if any, that was used for this document load. That
+     * is not the CSP that was applied to subresource loads within the
+     * document, but the CSP that was applied to this document load.
+     */
+    [infallible] attribute nsIContentSecurityPolicy csp;
+
+    /**
      * Get/set data associated with this history state via a pushState() call,
      * serialized using structured clone.
      **/
     [infallible] attribute nsIStructuredCloneContainer stateData;
 
     /**
      * The history ID of the docshell.
      */
@@ -272,16 +280,17 @@ interface nsISHEntry : nsISupports
 
     /** Additional ways to create an entry */
     [noscript] void create(in nsIURI URI, in AString title,
                            in nsIInputStream inputStream,
                            in nsILayoutHistoryState layoutHistoryState,
                            in unsigned long cacheKey, in ACString contentType,
                            in nsIPrincipal triggeringPrincipal,
                            in nsIPrincipal principalToInherit,
+                           in nsIContentSecurityPolicy aCsp,
                            in nsIDRef docshellID,
                            in boolean dynamicCreation);
 
     nsISHEntry clone();
 
     /** Return any content viewer present in or below this node in the
         nsSHEntry tree.  This will differ from contentViewer in the case
         where a child nsSHEntry has the content viewer for this tree. */
--- a/docshell/shistory/nsSHEntry.cpp
+++ b/docshell/shistory/nsSHEntry.cpp
@@ -3,16 +3,17 @@
 /* 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/. */
 
 #include "nsSHEntry.h"
 
 #include <algorithm>
 
+#include "nsIContentSecurityPolicy.h"
 #include "nsDocShellEditorData.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsIContentViewer.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIInputStream.h"
 #include "nsILayoutHistoryState.h"
 #include "nsIStructuredCloneContainer.h"
 #include "nsIURI.h"
@@ -379,33 +380,35 @@ nsSHEntry::SetContentType(const nsACStri
 }
 
 NS_IMETHODIMP
 nsSHEntry::Create(nsIURI* aURI, const nsAString& aTitle,
                   nsIInputStream* aInputStream,
                   nsILayoutHistoryState* aLayoutHistoryState,
                   uint32_t aCacheKey, const nsACString& aContentType,
                   nsIPrincipal* aTriggeringPrincipal,
-                  nsIPrincipal* aPrincipalToInherit, const nsID& aDocShellID,
+                  nsIPrincipal* aPrincipalToInherit,
+                  nsIContentSecurityPolicy* aCsp, const nsID& aDocShellID,
                   bool aDynamicCreation) {
   MOZ_ASSERT(
       aTriggeringPrincipal,
       "need a valid triggeringPrincipal to create a session history entry");
 
   mURI = aURI;
   mTitle = aTitle;
   mPostData = aInputStream;
 
   // Set the LoadType by default to loadHistory during creation
   mLoadType = LOAD_HISTORY;
 
   mShared->mCacheKey = aCacheKey;
   mShared->mContentType = aContentType;
   mShared->mTriggeringPrincipal = aTriggeringPrincipal;
   mShared->mPrincipalToInherit = aPrincipalToInherit;
+  mShared->mCsp = aCsp;
   mShared->mDocShellID = aDocShellID;
   mShared->mDynamicallyCreated = aDynamicCreation;
 
   // By default all entries are set false for subframe flag.
   // nsDocShell::CloneAndReplace() which creates entries for
   // all subframe navigations, sets the flag to true.
   mShared->mIsFrameNavigation = false;
 
@@ -491,16 +494,28 @@ nsSHEntry::GetPrincipalToInherit(nsIPrin
 
 NS_IMETHODIMP
 nsSHEntry::SetPrincipalToInherit(nsIPrincipal* aPrincipalToInherit) {
   mShared->mPrincipalToInherit = aPrincipalToInherit;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsSHEntry::GetCsp(nsIContentSecurityPolicy** aCsp) {
+  NS_IF_ADDREF(*aCsp = mShared->mCsp);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSHEntry::SetCsp(nsIContentSecurityPolicy* aCsp) {
+  mShared->mCsp = aCsp;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsSHEntry::GetBFCacheEntry(nsIBFCacheEntry** aEntry) {
   NS_IF_ADDREF(*aEntry = mShared);
   return NS_OK;
 }
 
 bool nsSHEntry::HasBFCacheEntry(nsIBFCacheEntry* aEntry) {
   return static_cast<nsIBFCacheEntry*>(mShared) == aEntry;
 }
--- a/docshell/shistory/nsSHEntryShared.cpp
+++ b/docshell/shistory/nsSHEntryShared.cpp
@@ -65,16 +65,17 @@ NS_IMPL_ISUPPORTS(nsSHEntryShared, nsIBF
 already_AddRefed<nsSHEntryShared> nsSHEntryShared::Duplicate(
     nsSHEntryShared* aEntry) {
   RefPtr<nsSHEntryShared> newEntry = new nsSHEntryShared();
 
   newEntry->mDocShellID = aEntry->mDocShellID;
   newEntry->mChildShells.AppendObjects(aEntry->mChildShells);
   newEntry->mTriggeringPrincipal = aEntry->mTriggeringPrincipal;
   newEntry->mPrincipalToInherit = aEntry->mPrincipalToInherit;
+  newEntry->mCsp = aEntry->mCsp;
   newEntry->mContentType.Assign(aEntry->mContentType);
   newEntry->mIsFrameNavigation = aEntry->mIsFrameNavigation;
   newEntry->mSaveLayoutState = aEntry->mSaveLayoutState;
   newEntry->mSticky = aEntry->mSticky;
   newEntry->mDynamicallyCreated = aEntry->mDynamicallyCreated;
   newEntry->mCacheKey = aEntry->mCacheKey;
   newEntry->mLastTouched = aEntry->mLastTouched;
 
--- a/docshell/shistory/nsSHEntryShared.h
+++ b/docshell/shistory/nsSHEntryShared.h
@@ -75,16 +75,17 @@ class nsSHEntryShared final : public nsI
   // See nsISHEntry.idl for an explanation of these members.
 
   // These members are copied by nsSHEntryShared::Duplicate().  If you add a
   // member here, be sure to update the Duplicate() implementation.
   nsID mDocShellID;
   nsCOMArray<nsIDocShellTreeItem> mChildShells;
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
+  nsCOMPtr<nsIContentSecurityPolicy> mCsp;
   nsCString mContentType;
 
   uint32_t mCacheKey;
   uint32_t mLastTouched;
 
   // These members aren't copied by nsSHEntryShared::Duplicate() because
   // they're specific to a particular content viewer.
   uint64_t mID;
--- a/docshell/shistory/nsSHistory.cpp
+++ b/docshell/shistory/nsSHistory.cpp
@@ -1491,16 +1491,18 @@ nsresult nsSHistory::InitiateLoad(nsISHE
 
   loadState->SetLoadReplace(aFrameEntry->GetLoadReplace());
 
   loadState->SetLoadFlags(nsIWebNavigation::LOAD_FLAGS_NONE);
   nsCOMPtr<nsIPrincipal> triggeringPrincipal =
       aFrameEntry->GetTriggeringPrincipal();
   loadState->SetTriggeringPrincipal(triggeringPrincipal);
   loadState->SetFirstParty(false);
+  nsCOMPtr<nsIContentSecurityPolicy> csp = aFrameEntry->GetCsp();
+  loadState->SetCsp(csp);
 
   // Time to initiate a document load
   return aFrameDS->LoadURI(loadState);
 }
 
 NS_IMETHODIMP_(void)
 nsSHistory::SetRootDocShell(nsIDocShell* aDocShell) {
   mRootDocShell = aDocShell;
--- a/dom/base/ContentAreaDropListener.jsm
+++ b/dom/base/ContentAreaDropListener.jsm
@@ -195,16 +195,37 @@ ContentAreaDropListener.prototype =
 
   getTriggeringPrincipal: function(aEvent)
   {
     let dataTransfer = aEvent.dataTransfer;
     return this._getTriggeringPrincipalFromDataTransfer(dataTransfer, true);
 
   },
 
+  getCSP: function(aEvent)
+  {
+    let sourceNode = aEvent.dataTransfer.mozSourceNode;
+    if (sourceNode &&
+        (sourceNode.localName !== "browser" ||
+         sourceNode.namespaceURI !== "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul")) {
+      // Use sourceNode's principal only if the sourceNode is not browser.
+      //
+      // If sourceNode is browser, the actual triggering principal may be
+      // differ than sourceNode's principal, since sourceNode's principal is
+      // top level document's one and the drag may be triggered from a frame
+      // with different principal.
+      if (sourceNode.nodePrincipal) {
+        // Currently we query the CSP from the nodePrincipal. After Bug 965637 we can
+        // query the CSP directly from the sourceNode.
+        return sourceNode.nodePrincipal.csp;
+      }
+    }
+    return null;
+  },
+
   canDropLink: function(aEvent, aAllowSameDocument)
   {
     if (this._eventTargetIsDisabled(aEvent))
       return false;
 
     let dataTransfer = aEvent.dataTransfer;
     let types = dataTransfer.types;
     if (!types.includes("application/x-moz-file") &&
--- a/dom/base/Location.cpp
+++ b/dom/base/Location.cpp
@@ -146,16 +146,25 @@ already_AddRefed<nsDocShellLoadState> Lo
     triggeringPrincipal = &aSubjectPrincipal;
   }
 
   // Create load info
   RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(aURI);
 
   loadState->SetTriggeringPrincipal(triggeringPrincipal);
 
+  // Currently we query the CSP from the triggeringPrincipal, which is the
+  // doc->NodePrincipal() in case there is a doc. In that case we can query
+  // the CSP directly from the doc after Bug 965637. In case there is no doc,
+  // then we also do not need to query the CSP, because only documents can have
+  // a CSP attached.
+  nsCOMPtr<nsIContentSecurityPolicy> csp;
+  triggeringPrincipal->GetCsp(getter_AddRefs(csp));
+  loadState->SetCsp(csp);
+
   if (sourceURI) {
     nsCOMPtr<nsIReferrerInfo> referrerInfo =
         new ReferrerInfo(sourceURI, referrerPolicy);
     loadState->SetReferrerInfo(referrerInfo);
   }
 
   return loadState.forget();
 }
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -5174,20 +5174,27 @@ void nsContentUtils::TriggerLink(nsICont
          !aContent->IsSVGElement(nsGkAtoms::a)) ||
         !aContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::download,
                                         fileName) ||
         NS_FAILED(
             aContent->NodePrincipal()->CheckMayLoad(aLinkURI, false, true))) {
       fileName.SetIsVoid(true);  // No actionable download attribute was found.
     }
 
+    // Currently we query the CSP from the triggeringPrincipal, which is
+    // aContent->NodePrincipal(). After Bug 965637 we can query the CSP
+    // directly from the doc instead (aContent->OwnerDoc()).
+    nsCOMPtr<nsIPrincipal> triggeringPrincipal = aContent->NodePrincipal();
+    nsCOMPtr<nsIContentSecurityPolicy> csp;
+    triggeringPrincipal->GetCsp(getter_AddRefs(csp));
+
     handler->OnLinkClick(
         aContent, aLinkURI, fileName.IsVoid() ? aTargetSpec : EmptyString(),
         fileName, nullptr, nullptr, EventStateManager::IsHandlingUserInput(),
-        aIsTrusted, aContent->NodePrincipal());
+        aIsTrusted, triggeringPrincipal, csp);
   }
 }
 
 /* static */
 void nsContentUtils::GetLinkLocation(Element* aElement,
                                      nsString& aLocationString) {
   nsCOMPtr<nsIURI> hrefURI = aElement->GetHrefURI();
   if (hrefURI) {
@@ -9807,16 +9814,25 @@ nsContentUtils::LookupCustomElementDefin
 
   nsCOMPtr<nsIURI> referrer;
   rv = aChannel->GetReferrer(getter_AddRefs(referrer));
   NS_ENSURE_SUCCESS(rv, false);
 
   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
   nsCOMPtr<nsIPrincipal> triggeringPrincipal = loadInfo->TriggeringPrincipal();
 
+  // Currently we query the CSP from the triggeringPrincipal within the
+  // loadInfo. After Bug 965637, we can query the CSP from the loadInfo, which
+  // internally queries the CSP from the Client.
+  nsCOMPtr<nsIContentSecurityPolicy> csp;
+  if (triggeringPrincipal) {
+    rv = triggeringPrincipal->GetCsp(getter_AddRefs(csp));
+    NS_ENSURE_SUCCESS(rv, false);
+  }
+
   // Get the channel's load flags, and use them to generate nsIWebNavigation
   // load flags. We want to make sure to propagate the refresh and cache busting
   // flags.
   nsLoadFlags channelLoadFlags;
   aChannel->GetLoadFlags(&channelLoadFlags);
 
   uint32_t webnavLoadFlags = nsIWebNavigation::LOAD_FLAGS_NONE;
   if (channelLoadFlags & nsIRequest::LOAD_BYPASS_CACHE) {
@@ -9824,17 +9840,17 @@ nsContentUtils::LookupCustomElementDefin
     webnavLoadFlags |= nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY;
   } else if (channelLoadFlags & nsIRequest::VALIDATE_ALWAYS) {
     webnavLoadFlags |= nsIWebNavigation::LOAD_FLAGS_IS_REFRESH;
   }
 
   // Actually perform the cross process load
   bool reloadSucceeded = false;
   rv = wbc3->ReloadInFreshProcess(docShell, uri, referrer, triggeringPrincipal,
-                                  webnavLoadFlags, &reloadSucceeded);
+                                  webnavLoadFlags, csp, &reloadSucceeded);
   NS_ENSURE_SUCCESS(rv, false);
 
   return reloadSucceeded;
 }
 
 /* static */ void nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
     Document* aDocument, nsTArray<nsIContent*>& aElements) {
   MOZ_ASSERT(aDocument);
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -391,16 +391,23 @@ nsresult nsFrameLoader::ReallyStartLoadi
   // is very important; needed to prevent XSS attacks on documents loaded in
   // subframes!
   if (mTriggeringPrincipal) {
     loadState->SetTriggeringPrincipal(mTriggeringPrincipal);
   } else {
     loadState->SetTriggeringPrincipal(mOwnerContent->NodePrincipal());
   }
 
+  // Currently we query the CSP from the principal, but after
+  // Bug 1529877 we should query the CSP from within GetURL and
+  // store it as a member, similar to mTriggeringPrincipal.
+  nsCOMPtr<nsIContentSecurityPolicy> csp;
+  loadState->TriggeringPrincipal()->GetCsp(getter_AddRefs(csp));
+  loadState->SetCsp(csp);
+
   nsCOMPtr<nsIURI> referrer;
 
   nsAutoString srcdoc;
   bool isSrcdoc =
       mOwnerContent->IsHTMLElement(nsGkAtoms::iframe) &&
       mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::srcdoc, srcdoc);
 
   if (isSrcdoc) {
--- a/dom/base/nsIDroppedLinkHandler.idl
+++ b/dom/base/nsIDroppedLinkHandler.idl
@@ -1,14 +1,15 @@
 /* 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/. */
 
 #include "nsISupports.idl"
 #include "nsIPrincipal.idl"
+#include "nsIContentSecurityPolicy.idl"
 
 webidl DragEvent;
 webidl DataTransfer;
 
 [scriptable, uuid(69E14F91-2E09-4CA6-A511-A715C99A2804)]
 interface nsIDroppedLinkItem : nsISupports
 {
   /**
@@ -100,9 +101,14 @@ interface nsIDroppedLinkHandler : nsISup
                   [optional] out unsigned long aCount,
                   [retval, array, size_is(aCount)] out nsIDroppedLinkItem aLinks);
 
   /**
    * Given a drop event aEvent, determines the triggering principal for the
    * event and returns it.
    */
   nsIPrincipal getTriggeringPrincipal(in DragEvent aEvent);
+
+  /**
+   * Given a drop event aEvent, determines the CSP for the event and returns it.
+   */
+  nsIContentSecurityPolicy getCSP(in DragEvent aEvent);
 };
--- a/dom/base/nsOpenURIInFrameParams.cpp
+++ b/dom/base/nsOpenURIInFrameParams.cpp
@@ -68,16 +68,29 @@ nsOpenURIInFrameParams::GetTriggeringPri
 NS_IMETHODIMP
 nsOpenURIInFrameParams::SetTriggeringPrincipal(
     nsIPrincipal* aTriggeringPrincipal) {
   NS_ENSURE_TRUE(aTriggeringPrincipal, NS_ERROR_INVALID_ARG);
   mTriggeringPrincipal = aTriggeringPrincipal;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsOpenURIInFrameParams::GetCsp(nsIContentSecurityPolicy** aCsp) {
+  NS_IF_ADDREF(*aCsp = mCsp);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsOpenURIInFrameParams::SetCsp(nsIContentSecurityPolicy* aCsp) {
+  NS_ENSURE_TRUE(aCsp, NS_ERROR_INVALID_ARG);
+  mCsp = aCsp;
+  return NS_OK;
+}
+
 nsresult nsOpenURIInFrameParams::GetOpenerBrowser(Element** aOpenerBrowser) {
   RefPtr<Element> owner = mOpenerBrowser;
   owner.forget(aOpenerBrowser);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsOpenURIInFrameParams::GetOpenerOriginAttributes(
--- a/dom/base/nsOpenURIInFrameParams.h
+++ b/dom/base/nsOpenURIInFrameParams.h
@@ -26,9 +26,10 @@ class nsOpenURIInFrameParams final : pub
  private:
   ~nsOpenURIInFrameParams();
 
   mozilla::OriginAttributes mOpenerOriginAttributes;
   RefPtr<Element> mOpenerBrowser;
   nsString mReferrer;
   uint32_t mReferrerPolicy;
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
+  nsCOMPtr<nsIContentSecurityPolicy> mCsp;
 };
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1843,16 +1843,18 @@ def addExternalIface(iface, nativeType=N
         domInterface['nativeType'] = nativeType
     if not headerFile is None:
         domInterface['headerFile'] = headerFile
     domInterface['notflattened'] = notflattened
     DOMInterfaces[iface] = domInterface
 
 addExternalIface('Cookie', nativeType='nsICookie2',
                  headerFile='nsICookie2.h', notflattened=True)
+addExternalIface('ContentSecurityPolicy', nativeType='nsIContentSecurityPolicy',
+                 notflattened=True)
 addExternalIface('HitRegionOptions', nativeType='nsISupports')
 addExternalIface('imgINotificationObserver', nativeType='imgINotificationObserver')
 addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
 addExternalIface('LoadContext', nativeType='nsILoadContext', notflattened=True)
 addExternalIface('LoadInfo', nativeType='nsILoadInfo',
                  headerFile='nsILoadInfo.h', notflattened=True)
 addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
 addExternalIface('XULControllers', nativeType='nsIControllers', notflattened=True)
--- a/dom/clients/manager/ClientNavigateOpChild.cpp
+++ b/dom/clients/manager/ClientNavigateOpChild.cpp
@@ -225,16 +225,26 @@ RefPtr<ClientOpPromise> ClientNavigateOp
     return ClientOpPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR,
                                             __func__);
   }
 
   RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState(url);
   nsCOMPtr<nsIReferrerInfo> referrerInfo =
       new ReferrerInfo(doc->GetDocumentURI(), doc->GetReferrerPolicy());
   loadState->SetTriggeringPrincipal(principal);
+
+  // Currently we query the CSP from the principal, which is the
+  // doc->NodePrincipal(). After Bug 965637 we can query the CSP
+  // from the doc directly.
+  if (principal) {
+    nsCOMPtr<nsIContentSecurityPolicy> csp;
+    principal->GetCsp(getter_AddRefs(csp));
+    loadState->SetCsp(csp);
+  }
+
   loadState->SetReferrerInfo(referrerInfo);
   loadState->SetLoadType(LOAD_STOP_CONTENT);
   loadState->SetSourceDocShell(docShell);
   loadState->SetLoadFlags(nsIWebNavigation::LOAD_FLAGS_NONE);
   loadState->SetFirstParty(true);
   rv = docShell->LoadURI(loadState);
   if (NS_FAILED(rv)) {
     return ClientOpPromise::CreateAndReject(rv, __func__);
--- a/dom/interfaces/base/nsIBrowserDOMWindow.idl
+++ b/dom/interfaces/base/nsIBrowserDOMWindow.idl
@@ -4,25 +4,27 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface mozIDOMWindowProxy;
 interface nsIDOMWindow;
 interface nsIURI;
 interface nsIPrincipal;
+interface nsIContentSecurityPolicy;
 webidl Element;
 
 [scriptable, uuid(e774db14-79ac-4156-a7a3-aa3fd0a22c10)]
 interface nsIOpenURIInFrameParams : nsISupports
 {
   attribute AString referrer;
   attribute unsigned long referrerPolicy;
   readonly attribute boolean isPrivate;
   attribute nsIPrincipal triggeringPrincipal;
+  attribute nsIContentSecurityPolicy csp;
 
   // The browser or frame element in the parent process which holds the
   // opener window in the content process. May be null.
   readonly attribute Element openerBrowser;
 
   [implicit_jscontext]
   readonly attribute jsval openerOriginAttributes;
 };
new file mode 100644
--- /dev/null
+++ b/dom/ipc/CSPMessageUtils.cpp
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "mozilla/dom/CSPMessageUtils.h"
+#include "nsISerializable.h"
+#include "nsSerializationHelper.h"
+
+namespace IPC {
+
+void ParamTraits<nsIContentSecurityPolicy>::Write(
+    Message* aMsg, nsIContentSecurityPolicy* aParam) {
+  bool isNull = !aParam;
+  WriteParam(aMsg, isNull);
+  if (isNull) {
+    return;
+  }
+
+  nsCString cspString;
+  nsresult rv = NS_SerializeToString(aParam, cspString);
+  if (NS_FAILED(rv)) {
+    MOZ_CRASH("Unable to serialize csp.");
+    return;
+  }
+
+  WriteParam(aMsg, cspString);
+}
+
+bool ParamTraits<nsIContentSecurityPolicy>::Read(
+    const Message* aMsg, PickleIterator* aIter,
+    RefPtr<nsIContentSecurityPolicy>* aResult) {
+  bool isNull;
+  if (!ReadParam(aMsg, aIter, &isNull)) {
+    return false;
+  }
+
+  if (isNull) {
+    *aResult = nullptr;
+    return true;
+  }
+
+  nsCString cspString;
+  if (!ReadParam(aMsg, aIter, &cspString)) {
+    return false;
+  }
+
+  nsCOMPtr<nsISupports> iSupports;
+  nsresult rv = NS_DeserializeObject(cspString, getter_AddRefs(iSupports));
+  NS_ENSURE_SUCCESS(rv, false);
+
+  nsCOMPtr<nsIContentSecurityPolicy> csp = do_QueryInterface(iSupports);
+  NS_ENSURE_TRUE(csp, false);
+
+  *aResult = csp.forget();
+  return true;
+}
+
+}  // namespace IPC
new file mode 100644
--- /dev/null
+++ b/dom/ipc/CSPMessageUtils.h
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_dom_csp_message_utils_h__
+#define mozilla_dom_csp_message_utils_h__
+
+#include "ipc/IPCMessageUtils.h"
+#include "nsCOMPtr.h"
+#include "nsIContentSecurityPolicy.h"
+
+namespace IPC {
+
+template <>
+struct ParamTraits<nsIContentSecurityPolicy> {
+  static void Write(Message* aMsg, nsIContentSecurityPolicy* aParam);
+  static bool Read(const Message* aMsg, PickleIterator* aIter,
+                   RefPtr<nsIContentSecurityPolicy>* aResult);
+};
+
+}  // namespace IPC
+
+#endif  // mozilla_dom_csp_message_utils_h__
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -750,37 +750,44 @@ ContentChild::ProvideWindow(mozIDOMWindo
                             nsDocShellLoadState* aLoadState, bool* aWindowIsNew,
                             mozIDOMWindowProxy** aReturn) {
   return ProvideWindowCommon(nullptr, aParent, false, aChromeFlags,
                              aCalledFromJS, aPositionSpecified, aSizeSpecified,
                              aURI, aName, aFeatures, aForceNoOpener, aLoadState,
                              aWindowIsNew, aReturn);
 }
 
-static nsresult GetCreateWindowParams(mozIDOMWindowProxy* aParent,
-                                      nsDocShellLoadState* aLoadState,
-                                      nsACString& aBaseURIString,
-                                      float* aFullZoom,
-                                      uint32_t* aReferrerPolicy,
-                                      nsIPrincipal** aTriggeringPrincipal) {
+static nsresult GetCreateWindowParams(
+    mozIDOMWindowProxy* aParent, nsDocShellLoadState* aLoadState,
+    nsACString& aBaseURIString, float* aFullZoom, uint32_t* aReferrerPolicy,
+    nsIPrincipal** aTriggeringPrincipal, nsIContentSecurityPolicy** aCsp) {
   *aFullZoom = 1.0f;
-  if (!aTriggeringPrincipal) {
-    NS_ERROR("aTriggeringPrincipal is null");
+  if (!aTriggeringPrincipal || !aCsp) {
+    NS_ERROR("aTriggeringPrincipal || aCsp is null");
     return NS_ERROR_FAILURE;
   }
   auto* opener = nsPIDOMWindowOuter::From(aParent);
   if (!opener) {
     nsCOMPtr<nsIPrincipal> nullPrincipal =
         NullPrincipal::CreateWithoutOriginAttributes();
     NS_ADDREF(*aTriggeringPrincipal = nullPrincipal);
     return NS_OK;
   }
 
   nsCOMPtr<Document> doc = opener->GetDoc();
   NS_ADDREF(*aTriggeringPrincipal = doc->NodePrincipal());
+
+  // Currently we query the CSP from the doc->NodePrincipal(). After
+  // Bug 965637 we can query the CSP from the doc directly.
+  nsCOMPtr<nsIContentSecurityPolicy> csp;
+  doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
+  if (csp) {
+    csp.forget(aCsp);
+  }
+
   nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
   if (!baseURI) {
     NS_ERROR("Document didn't return a base URI");
     return NS_ERROR_FAILURE;
   }
 
   baseURI->GetSpec(aBaseURIString);
   if (aLoadState) {
@@ -851,30 +858,31 @@ nsresult ContentChild::ProvideWindowComm
   }
 
   // If we're in a content process and we have noopener set, there's no reason
   // to load in our process, so let's load it elsewhere!
   if (loadInDifferentProcess) {
     nsAutoCString baseURIString;
     float fullZoom;
     nsCOMPtr<nsIPrincipal> triggeringPrincipal;
+    nsCOMPtr<nsIContentSecurityPolicy> csp;
     uint32_t referrerPolicy = mozilla::net::RP_Unset;
-    rv = GetCreateWindowParams(aParent, aLoadState, baseURIString, &fullZoom,
-                               &referrerPolicy,
-                               getter_AddRefs(triggeringPrincipal));
+    rv = GetCreateWindowParams(
+        aParent, aLoadState, baseURIString, &fullZoom, &referrerPolicy,
+        getter_AddRefs(triggeringPrincipal), getter_AddRefs(csp));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     OptionalURIParams uriToLoad;
     SerializeURI(aURI, uriToLoad);
     Unused << SendCreateWindowInDifferentProcess(
         aTabOpener, aChromeFlags, aCalledFromJS, aPositionSpecified,
         aSizeSpecified, uriToLoad, features, baseURIString, fullZoom, name,
-        Principal(triggeringPrincipal), referrerPolicy);
+        Principal(triggeringPrincipal), csp, referrerPolicy);
 
     // We return NS_ERROR_ABORT, so that the caller knows that we've abandoned
     // the window open as far as it is concerned.
     return NS_ERROR_ABORT;
   }
 
   if (aTabOpener) {
     PopupIPCTabContext context;
@@ -1050,35 +1058,37 @@ nsresult ContentChild::ProvideWindowComm
     // CreateWindowPromise, and this code depends on that fact.
     newChild->SendBrowserFrameOpenWindow(aTabOpener, NS_ConvertUTF8toUTF16(url),
                                          name, NS_ConvertUTF8toUTF16(features),
                                          std::move(resolve), std::move(reject));
   } else {
     nsAutoCString baseURIString;
     float fullZoom;
     nsCOMPtr<nsIPrincipal> triggeringPrincipal;
+    nsCOMPtr<nsIContentSecurityPolicy> csp;
     uint32_t referrerPolicy = mozilla::net::RP_Unset;
-    rv = GetCreateWindowParams(aParent, aLoadState, baseURIString, &fullZoom,
-                               &referrerPolicy,
-                               getter_AddRefs(triggeringPrincipal));
+    rv = GetCreateWindowParams(
+        aParent, aLoadState, baseURIString, &fullZoom, &referrerPolicy,
+        getter_AddRefs(triggeringPrincipal), getter_AddRefs(csp));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     OptionalURIParams uriToLoad;
     if (aURI) {
       SerializeURI(aURI, uriToLoad);
     } else {
       uriToLoad = mozilla::void_t();
     }
 
     SendCreateWindow(aTabOpener, newChild, aChromeFlags, aCalledFromJS,
                      aPositionSpecified, aSizeSpecified, uriToLoad, features,
                      baseURIString, fullZoom, Principal(triggeringPrincipal),
-                     referrerPolicy, std::move(resolve), std::move(reject));
+                     csp, referrerPolicy, std::move(resolve),
+                     std::move(reject));
   }
 
   // =======================
   // Begin Nested Event Loop
   // =======================
 
   // We have to wait for a response from either SendCreateWindow or
   // SendBrowserFrameOpenWindow with information we're going to need to return
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -127,16 +127,17 @@
 #include "nsEmbedCID.h"
 #include "nsFrameLoader.h"
 #include "nsFrameMessageManager.h"
 #include "nsHashPropertyBag.h"
 #include "nsIAlertsService.h"
 #include "nsIClipboard.h"
 #include "nsICookie.h"
 #include "nsContentPermissionHelper.h"
+#include "nsIContentSecurityPolicy.h"
 #include "nsIContentProcess.h"
 #include "nsICycleCollectorListener.h"
 #include "nsIDocShellTreeOwner.h"
 #include "mozilla/dom/Document.h"
 #include "nsGeolocation.h"
 #include "nsIDragService.h"
 #include "mozilla/dom/WakeLock.h"
 #include "nsIDOMWindow.h"
@@ -4601,17 +4602,17 @@ bool ContentParent::DeallocPWebBrowserPe
 mozilla::ipc::IPCResult ContentParent::CommonCreateWindow(
     PBrowserParent* aThisTab, bool aSetOpener, const uint32_t& aChromeFlags,
     const bool& aCalledFromJS, const bool& aPositionSpecified,
     const bool& aSizeSpecified, nsIURI* aURIToLoad, const nsCString& aFeatures,
     const nsCString& aBaseURI, const float& aFullZoom,
     uint64_t aNextTabParentId, const nsString& aName, nsresult& aResult,
     nsCOMPtr<nsITabParent>& aNewTabParent, bool* aWindowIsNew,
     int32_t& aOpenLocation, nsIPrincipal* aTriggeringPrincipal,
-    uint32_t aReferrerPolicy, bool aLoadURI)
+    uint32_t aReferrerPolicy, bool aLoadURI, nsIContentSecurityPolicy* aCsp)
 
 {
   // The content process should never be in charge of computing whether or
   // not a window should be private or remote - the parent will do that.
   const uint32_t badFlags = nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW |
                             nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW |
                             nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME |
                             nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
@@ -4685,16 +4686,17 @@ mozilla::ipc::IPCResult ContentParent::C
     RefPtr<Element> openerElement = do_QueryObject(frame);
 
     nsCOMPtr<nsIOpenURIInFrameParams> params =
         new nsOpenURIInFrameParams(openerOriginAttributes, openerElement);
     params->SetReferrer(NS_ConvertUTF8toUTF16(aBaseURI));
     MOZ_ASSERT(aTriggeringPrincipal, "need a valid triggeringPrincipal");
     params->SetTriggeringPrincipal(aTriggeringPrincipal);
     params->SetReferrerPolicy(aReferrerPolicy);
+    params->SetCsp(aCsp);
 
     RefPtr<Element> el;
 
     if (aLoadURI) {
       aResult = browserDOMWin->OpenURIInFrame(
           aURIToLoad, params, aOpenLocation, nsIBrowserDOMWindow::OPEN_NEW,
           aNextTabParentId, aName, getter_AddRefs(el));
     } else {
@@ -4801,18 +4803,18 @@ mozilla::ipc::IPCResult ContentParent::C
 }
 
 mozilla::ipc::IPCResult ContentParent::RecvCreateWindow(
     PBrowserParent* aThisTab, PBrowserParent* aNewTab,
     const uint32_t& aChromeFlags, const bool& aCalledFromJS,
     const bool& aPositionSpecified, const bool& aSizeSpecified,
     const OptionalURIParams& aURIToLoad, const nsCString& aFeatures,
     const nsCString& aBaseURI, const float& aFullZoom,
-    const IPC::Principal& aTriggeringPrincipal, const uint32_t& aReferrerPolicy,
-    CreateWindowResolver&& aResolve) {
+    const IPC::Principal& aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp,
+    const uint32_t& aReferrerPolicy, CreateWindowResolver&& aResolve) {
   nsresult rv = NS_OK;
   CreatedWindowInfo cwi;
 
   // We always expect to open a new window here. If we don't, it's an error.
   cwi.windowOpened() = true;
   cwi.maxTouchPoints() = 0;
   cwi.hasSiblings() = false;
 
@@ -4848,17 +4850,17 @@ mozilla::ipc::IPCResult ContentParent::R
 
   nsCOMPtr<nsITabParent> newRemoteTab;
   int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
   mozilla::ipc::IPCResult ipcResult = CommonCreateWindow(
       aThisTab, /* aSetOpener = */ true, aChromeFlags, aCalledFromJS,
       aPositionSpecified, aSizeSpecified, uriToLoad, aFeatures, aBaseURI,
       aFullZoom, nextTabParentId, VoidString(), rv, newRemoteTab,
       &cwi.windowOpened(), openLocation, aTriggeringPrincipal, aReferrerPolicy,
-      /* aLoadUri = */ false);
+      /* aLoadUri = */ false, aCsp);
   if (!ipcResult) {
     return ipcResult;
   }
 
   if (NS_WARN_IF(NS_FAILED(rv)) || !newRemoteTab) {
     return IPC_OK();
   }
 
@@ -4882,30 +4884,31 @@ mozilla::ipc::IPCResult ContentParent::R
 }
 
 mozilla::ipc::IPCResult ContentParent::RecvCreateWindowInDifferentProcess(
     PBrowserParent* aThisTab, const uint32_t& aChromeFlags,
     const bool& aCalledFromJS, const bool& aPositionSpecified,
     const bool& aSizeSpecified, const OptionalURIParams& aURIToLoad,
     const nsCString& aFeatures, const nsCString& aBaseURI,
     const float& aFullZoom, const nsString& aName,
-    const IPC::Principal& aTriggeringPrincipal,
+    const IPC::Principal& aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp,
     const uint32_t& aReferrerPolicy) {
   nsCOMPtr<nsITabParent> newRemoteTab;
   bool windowIsNew;
   nsCOMPtr<nsIURI> uriToLoad = DeserializeURI(aURIToLoad);
   int32_t openLocation = nsIBrowserDOMWindow::OPEN_NEWWINDOW;
+
   nsresult rv;
   mozilla::ipc::IPCResult ipcResult = CommonCreateWindow(
       aThisTab, /* aSetOpener = */ false, aChromeFlags, aCalledFromJS,
       aPositionSpecified, aSizeSpecified, uriToLoad, aFeatures, aBaseURI,
       aFullZoom,
       /* aNextTabParentId = */ 0, aName, rv, newRemoteTab, &windowIsNew,
       openLocation, aTriggeringPrincipal, aReferrerPolicy,
-      /* aLoadUri = */ true);
+      /* aLoadUri = */ true, aCsp);
   if (!ipcResult) {
     return ipcResult;
   }
 
   if (NS_FAILED(rv)) {
     NS_WARNING("Call to CommonCreateWindow failed.");
   }
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -514,26 +514,27 @@ class ContentParent final : public PCont
 
   mozilla::ipc::IPCResult RecvCreateWindow(
       PBrowserParent* aThisTabParent, PBrowserParent* aNewTab,
       const uint32_t& aChromeFlags, const bool& aCalledFromJS,
       const bool& aPositionSpecified, const bool& aSizeSpecified,
       const OptionalURIParams& aURIToLoad, const nsCString& aFeatures,
       const nsCString& aBaseURI, const float& aFullZoom,
       const IPC::Principal& aTriggeringPrincipal,
-      const uint32_t& aReferrerPolicy, CreateWindowResolver&& aResolve);
+      nsIContentSecurityPolicy* aCsp, const uint32_t& aReferrerPolicy,
+      CreateWindowResolver&& aResolve);
 
   mozilla::ipc::IPCResult RecvCreateWindowInDifferentProcess(
       PBrowserParent* aThisTab, const uint32_t& aChromeFlags,
       const bool& aCalledFromJS, const bool& aPositionSpecified,
       const bool& aSizeSpecified, const OptionalURIParams& aURIToLoad,
       const nsCString& aFeatures, const nsCString& aBaseURI,
       const float& aFullZoom, const nsString& aName,
       const IPC::Principal& aTriggeringPrincipal,
-      const uint32_t& aReferrerPolicy);
+      nsIContentSecurityPolicy* aCsp, const uint32_t& aReferrerPolicy);
 
   static void BroadcastBlobURLRegistration(
       const nsACString& aURI, BlobImpl* aBlobImpl, nsIPrincipal* aPrincipal,
       ContentParent* aIgnoreThisCP = nullptr);
 
   static void BroadcastBlobURLUnregistration(
       const nsACString& aURI, ContentParent* aIgnoreThisCP = nullptr);
 
@@ -691,17 +692,17 @@ class ContentParent final : public PCont
       PBrowserParent* aThisTab, bool aSetOpener, const uint32_t& aChromeFlags,
       const bool& aCalledFromJS, const bool& aPositionSpecified,
       const bool& aSizeSpecified, nsIURI* aURIToLoad,
       const nsCString& aFeatures, const nsCString& aBaseURI,
       const float& aFullZoom, uint64_t aNextTabParentId, const nsString& aName,
       nsresult& aResult, nsCOMPtr<nsITabParent>& aNewTabParent,
       bool* aWindowIsNew, int32_t& aOpenLocation,
       nsIPrincipal* aTriggeringPrincipal, uint32_t aReferrerPolicy,
-      bool aLoadUri);
+      bool aLoadUri, nsIContentSecurityPolicy* aCsp);
 
   FORWARD_SHMEM_ALLOCATOR_TO(PContentParent)
 
   enum RecordReplayState { eNotRecordingOrReplaying, eRecording, eReplaying };
 
   explicit ContentParent(int32_t aPluginID)
       : ContentParent(nullptr, EmptyString(), eNotRecordingOrReplaying,
                       EmptyString(), aPluginID) {}
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -24,16 +24,17 @@ using CSSToLayoutDeviceScale from "Units
 using CSSRect from "Units.h";
 using CSSSize from "Units.h";
 using mozilla::LayoutDeviceIntPoint from "Units.h";
 using hal::ScreenOrientation from "mozilla/HalScreenConfiguration.h";
 using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
 using refcounted class nsIPrincipal from "mozilla/dom/PermissionMessageUtils.h";
 using refcounted class mozilla::dom::BrowsingContext from "mozilla/dom/BrowsingContext.h";
 using refcounted class nsIURI from "mozilla/ipc/URIUtils.h";
+using refcounted class nsIContentSecurityPolicy from "mozilla/dom/CSPMessageUtils.h";
 
 namespace mozilla {
 namespace dom {
 
 struct MessagePortIdentifier
 {
   nsID uuid;
   nsID destinationUuid;
@@ -214,16 +215,23 @@ struct DocShellLoadStateInit
   uint32_t LoadType;
   nsString Target;
   nsIURI BaseURI;
   uint32_t LoadFlags;
   bool FirstParty;
   nsCString TypeHint;
   nsString FileName;
   bool IsFromProcessingFrameAttributes;
+  // The Content Security Policy of the load, that is, the CSP of the entity
+  // responsible for causing the load to occur. Most likely this is the CSP
+  // of the document that started the load. In case the entity starting the
+  // load did not use a CSP, then Csp can be null. Please note that this is
+  // also the CSP that will be applied to the load in case the load
+  // encounters a server side redirect.
+  nsIContentSecurityPolicy Csp;
   // Fields missing due to lack of need or serialization
   // nsCOMPtr<nsISHEntry> mSHEntry;
   // nsCOMPtr<nsIDocShell> mSourceDocShell;
   // bool mIsSrcDocLoad; // useless without sourcedocshell
   // nsString mSrcdocData; // useless without sourcedocshell
   // nsIInputStream PostDataStream; // will be used after IPC transaction
   // nsIInputStream HeadersStream; // will be used after IPC transaction
   // nsIChannel pendingRedirectedChannel; // sent through other mechanism
--- a/dom/ipc/MemoryReportRequest.cpp
+++ b/dom/ipc/MemoryReportRequest.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
+#include "nsMemoryReporterManager.h"
 #include "MemoryReportRequest.h"
+#include "mozilla/ipc/FileDescriptorUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 MemoryReportRequestHost::MemoryReportRequestHost(uint32_t aGeneration)
     : mGeneration(aGeneration), mSuccess(false) {
   MOZ_COUNT_CTOR(MemoryReportRequestHost);
   mReporterManager = nsMemoryReporterManager::GetOrCreate();
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1133,31 +1133,33 @@ parent:
                        bool aCalledFromJS,
                        bool aPositionSpecified,
                        bool aSizeSpecified,
                        OptionalURIParams aURIToLoad,
                        nsCString aFeatures,
                        nsCString aBaseURI,
                        float aFullZoom,
                        Principal aTriggeringPrincipal,
+                       nsIContentSecurityPolicy aCsp,
                        uint32_t aReferrerPolicy)
         returns (CreatedWindowInfo window);
 
     async CreateWindowInDifferentProcess(
       PBrowser aThisTab,
       uint32_t aChromeFlags,
       bool aCalledFromJS,
       bool aPositionSpecified,
       bool aSizeSpecified,
       OptionalURIParams aURIToLoad,
       nsCString aFeatures,
       nsCString aBaseURI,
       float aFullZoom,
       nsString aName,
       Principal aTriggeringPrincipal,
+      nsIContentSecurityPolicy aCsp,
       uint32_t aReferrerPolicy);
 
     /**
      * Tells the parent to ungrab the pointer on the default display.
      *
      * This is for GTK platforms where we have to ensure the pointer ungrab happens in the
      * chrome process as that's the process that receives the pointer event.
      */
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -33,16 +33,17 @@ EXPORTS.mozilla.dom += [
     'CoalescedWheelData.h',
     'ContentBridgeChild.h',
     'ContentBridgeParent.h',
     'ContentChild.h',
     'ContentParent.h',
     'ContentProcess.h',
     'ContentProcessManager.h',
     'CPOWManagerGetter.h',
+    'CSPMessageUtils.h',
     'DocShellMessageUtils.h',
     'FilePickerParent.h',
     'JSWindowActorChild.h',
     'JSWindowActorParent.h',
     'JSWindowActorService.h',
     'MemoryReportRequest.h',
     'nsIContentChild.h',
     'nsIContentParent.h',
@@ -70,16 +71,17 @@ UNIFIED_SOURCES += [
     'CoalescedMouseData.cpp',
     'CoalescedWheelData.cpp',
     'ColorPickerParent.cpp',
     'ContentBridgeChild.cpp',
     'ContentBridgeParent.cpp',
     'ContentParent.cpp',
     'ContentProcess.cpp',
     'ContentProcessManager.cpp',
+    'CSPMessageUtils.cpp',
     'DocShellMessageUtils.cpp',
     'FilePickerParent.cpp',
     'JSWindowActorChild.cpp',
     'JSWindowActorParent.cpp',
     'JSWindowActorService.cpp',
     'MemMapSnapshot.cpp',
     'MemoryReportRequest.cpp',
     'MMPrinter.cpp',
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -438,20 +438,25 @@ NS_IMETHODIMP nsPluginInstanceOwner::Get
     mozilla::OriginAttributes attrs =
         BasePrincipal::Cast(content->NodePrincipal())->OriginAttributesRef();
     triggeringPrincipal = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
   } else {
     triggeringPrincipal =
         NullPrincipal::CreateWithInheritedAttributes(content->NodePrincipal());
   }
 
+  // Currently we query the CSP from the NodePrincipal. After Bug 965637
+  // we can query the CSP from the doc directly (content->OwerDoc()).
+  nsCOMPtr<nsIContentSecurityPolicy> csp;
+  content->NodePrincipal()->GetCsp(getter_AddRefs(csp));
+
   rv = lh->OnLinkClick(content, uri, unitarget, VoidString(), aPostStream,
                        headersDataStream,
                        /* isUserTriggered */ false,
-                       /* isTrusted */ true, triggeringPrincipal);
+                       /* isTrusted */ true, triggeringPrincipal, csp);
 
   return rv;
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::GetDocument(Document** aDocument) {
   nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
   if (!aDocument || !content) {
     return NS_ERROR_NULL_POINTER;
--- a/dom/webidl/LoadURIOptions.webidl
+++ b/dom/webidl/LoadURIOptions.webidl
@@ -1,28 +1,38 @@
 /* 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/. */
 
+interface ContentSecurityPolicy;
 interface Principal;
 interface URI;
 interface InputStream;
 interface ReferrerInfo;
 
 /**
  * This dictionary holds load arguments for docshell loads.
  */
 
 dictionary LoadURIOptions {
   /**
    * The principal that initiated the load.
    */
   Principal? triggeringPrincipal = null;
 
   /**
+   * The CSP to be used for the load. That is *not* the CSP that will
+   * be applied to subresource loads within that document but the CSP
+   * for the document load itself. E.g. if that CSP includes
+   * upgrade-insecure-requests, then the new top-level load will
+   * be upgraded to HTTPS.
+   */
+  ContentSecurityPolicy? csp = null;
+
+  /**
    * Flags modifying load behaviour.  This parameter is a bitwise
    * combination of the load flags defined in nsIWebNavigation.idl.
    */
    long loadFlags = 0;
 
   /**
    * The referring info of the load.  If this argument is null, then the
    * referrer URI and referrer policy will be inferred internally.
--- a/mobile/android/chrome/geckoview/GeckoViewNavigationChild.js
+++ b/mobile/android/chrome/geckoview/GeckoViewNavigationChild.js
@@ -72,45 +72,37 @@ class GeckoViewNavigationChild extends G
 
   // nsIWebBrowserChrome
   onBeforeLinkTraversal(aOriginalTarget, aLinkURI, aLinkNode, aIsAppTab) {
     debug `onBeforeLinkTraversal ${aLinkURI.displaySpec}`;
     return BrowserUtils.onBeforeLinkTraversal(aOriginalTarget, aLinkURI, aLinkNode, aIsAppTab);
   }
 
   // nsIWebBrowserChrome
-  shouldLoadURI(aDocShell, aURI, aReferrer, aHasPostData, aTriggeringPrincipal) {
+  shouldLoadURI(aDocShell, aURI, aReferrer, aHasPostData, aTriggeringPrincipal, aCsp) {
     debug `shouldLoadURI ${aURI.displaySpec}`;
 
-    // We currently only support one remoteType, "web", so we only need to bail out
-    // if we want to load this URI in the parent.
-    // const remoteType = E10SUtils.getRemoteTypeForURIObject(aURI, true);
-    // if (!remoteType) {
-    //   E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, false);
-    //   return false;
-    // }
-
     if (!E10SUtils.shouldLoadURI(aDocShell, aURI, aReferrer, aHasPostData)) {
-      E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, false);
+      E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, false, null, aCsp);
       return false;
     }
 
     return true;
   }
 
   // nsIWebBrowserChrome
   shouldLoadURIInThisProcess(aURI) {
     debug `shouldLoadURIInThisProcess ${aURI.displaySpec}`;
     return E10SUtils.shouldLoadURIInThisProcess(aURI);
   }
 
   // nsIWebBrowserChrome
-  reloadInFreshProcess(aDocShell, aURI, aReferrer, aTriggeringPrincipal, aLoadFlags) {
+  reloadInFreshProcess(aDocShell, aURI, aReferrer, aTriggeringPrincipal, aLoadFlags, aCsp) {
     debug `reloadInFreshProcess ${aURI.displaySpec}`;
-    E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, true, aLoadFlags);
+    E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, true, aLoadFlags, aCsp);
     return true;
   }
 
   handleEvent(aEvent) {
     switch (aEvent.type) {
       case "DOMContentLoaded": {
         // TODO: Remove this when we have a better story re: interactive error pages.
         let target = aEvent.originalTarget;
--- a/taskcluster/ci/searchfox/kind.yml
+++ b/taskcluster/ci/searchfox/kind.yml
@@ -46,16 +46,17 @@ jobs:
             script: "mozharness/scripts/fx_desktop_build.py"
             tooltool-downloads: public
             keep-artifacts: false
         toolchains:
             - linux64-clang
             - linux64-node
             - linux64-rust
             - linux64-cbindgen
+            - linux64-nasm
 
     macosx64-searchfox/debug:
         description: "MacOS X x64 Debug Cross-compile Searchfox"
         index:
             job-name: macosx64-searchfox-debug
         treeherder:
             platform: osx-cross/debug
         worker-type: aws-provisioner-v1/gecko-{level}-b-linux
@@ -81,16 +82,17 @@ jobs:
             - linux64-cctools-port
             - linux64-clang
             - linux64-hfsplus
             - linux64-libdmg
             - linux64-llvm-dsymutil
             - linux64-node
             - linux64-rust-macos
             - linux64-cbindgen
+            - linux64-nasm
 
     win64-searchfox/debug:
         description: "Win64 Searchfox Debug (clang-cl)"
         index:
             product: firefox
             job-name: win64-searchfox-debug
         treeherder:
             platform: windows2012-64/debug
@@ -150,8 +152,9 @@ jobs:
             - android-ndk-linux
             - android-sdk-linux
             - linux64-clang
             - linux64-rust-android
             - linux64-rust-size
             - linux64-cbindgen
             - linux64-sccache
             - linux64-node
+            - linux64-nasm
--- a/toolkit/actors/WebNavigationChild.jsm
+++ b/toolkit/actors/WebNavigationChild.jsm
@@ -35,20 +35,18 @@ class WebNavigationChild extends ActorCh
       case "WebNavigation:GotoIndex":
         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.referrerInfo,
-                     message.data.postData, message.data.headers,
-                     message.data.baseURI, message.data.triggeringPrincipal);
+        this.loadURI(message.data);
+
         break;
       case "WebNavigation:SetOriginAttributes":
         this.setOriginAttributes(message.data.originAttributes);
         break;
       case "WebNavigation:Reload":
         this.reload(message.data.flags);
         break;
       case "WebNavigation:Stop":
@@ -78,17 +76,28 @@ class WebNavigationChild extends ActorCh
       this._wrapURIChangeCall(() => this.webNavigation.goForward());
     }
   }
 
   gotoIndex(index) {
     this._wrapURIChangeCall(() => this.webNavigation.gotoIndex(index));
   }
 
-  loadURI(uri, flags, referrerInfo, postData, headers, baseURI, triggeringPrincipal) {
+  loadURI(params) {
+    let {
+      uri,
+      flags,
+      referrerInfo,
+      postData,
+      headers,
+      baseURI,
+      triggeringPrincipal,
+      csp,
+    } = params || {};
+
     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();
@@ -104,19 +113,23 @@ class WebNavigationChild extends ActorCh
     if (baseURI)
       baseURI = Services.io.newURI(baseURI);
     this._assert(triggeringPrincipal, "We need a triggering principal to continue loading", new Error().lineNumber);
 
     triggeringPrincipal = E10SUtils.deserializePrincipal(triggeringPrincipal, () => {
       this._assert(false, "Unable to deserialize passed triggering principal", new Error().lineNumber);
       return Services.scriptSecurityManager.getSystemPrincipal({});
     });
+    if (csp) {
+      csp = E10SUtils.deserializeCSP(csp);
+    }
 
     let loadURIOptions = {
       triggeringPrincipal,
+      csp,
       loadFlags: flags,
       referrerInfo: E10SUtils.deserializeReferrerInfo(referrerInfo),
       postData,
       headers,
       baseURI,
     };
     this._wrapURIChangeCall(() => {
       return this.webNavigation.loadURI(uri, loadURIOptions);
--- a/toolkit/components/browser/nsIWebBrowserChrome3.idl
+++ b/toolkit/components/browser/nsIWebBrowserChrome3.idl
@@ -4,16 +4,17 @@
 
 #include "nsIWebBrowserChrome2.idl"
 #include "nsIURI.idl"
 
 interface nsIDocShell;
 interface nsIInputStream;
 interface nsIRunnable;
 interface nsIPrincipal;
+interface nsIContentSecurityPolicy;
 
 webidl Node;
 
 /**
  * nsIWebBrowserChrome3 is an extension to nsIWebBrowserChrome2.
  */
 [scriptable, uuid(542b6625-35a9-426a-8257-c12a345383b0)]
 interface nsIWebBrowserChrome3 : nsIWebBrowserChrome2
@@ -47,30 +48,38 @@ interface nsIWebBrowserChrome3 : nsIWebB
    * @param aReferrer
    *        The referrer of the load.
    * @param aHasPostData
    *        True if the load which is being asked about has associated post data
    *        which would be discarded if the load was redirected across process
    *        boundaries.
    * @param aTriggeringPrincipal
    *        The principal that initiated the load of aURI.
+   * @param aCsp
+   *        The CSP to be used for that load. That is the CSP that e.g. upgrades
+   *        the load to HTTPS in case upgrade-insecure-requests is set.
    */
-  bool shouldLoadURI(in nsIDocShell    aDocShell,
-                     in nsIURI         aURI,
-                     in nsIURI         aReferrer,
-                     in boolean        aHasPostData,
-                     in nsIPrincipal   aTriggeringPrincipal);
+  bool shouldLoadURI(in nsIDocShell              aDocShell,
+                     in nsIURI                   aURI,
+                     in nsIURI                   aReferrer,
+                     in boolean                  aHasPostData,
+                     in nsIPrincipal             aTriggeringPrincipal,
+                     in nsIContentSecurityPolicy aCsp);
 
   bool shouldLoadURIInThisProcess(in nsIURI aURI);
 
   /**
    * Attempts to load the currently loaded page into a fresh process to increase
    * available memory.
    *
    * @param aDocShell
    *        The docshell performing the load.
+   * @param aCsp
+   *        The CSP to be used for that load. That is the CSP that e.g. upgrades
+   *        the load to HTTPS in case upgrade-insecure-requests is set.
    */
   bool reloadInFreshProcess(in nsIDocShell aDocShell,
                             in nsIURI aURI,
                             in nsIURI aReferrer,
                             in nsIPrincipal aTriggeringPrincipal,
-                            in uint32_t aLoadFlags);
+                            in uint32_t aLoadFlags,
+                            in nsIContentSecurityPolicy aCsp);
 };
--- a/toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm
+++ b/toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm
@@ -93,16 +93,17 @@ RemoteWebNavigation.prototype = {
       uri: aURI,
       flags: aLoadURIOptions.loadFlags,
       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: E10SUtils.serializePrincipal(
                            aLoadURIOptions.triggeringPrincipal || Services.scriptSecurityManager.createNullPrincipal({})),
+      csp: aLoadURIOptions.csp ? E10SUtils.serializeCSP(aLoadURIOptions.csp) : null,
       requestTime: Services.telemetry.msSystemNow(),
     });
   },
   setOriginAttributesBeforeLoading(aOriginAttributes) {
     this._sendMessage("WebNavigation:SetOriginAttributes", {
       originAttributes: aOriginAttributes,
     });
   },
--- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp
+++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp
@@ -1079,16 +1079,25 @@ nsresult nsWindowWatcher::OpenWindowInte
     }
     if (doc) {
       nsCOMPtr<nsIReferrerInfo> referrerInfo =
           new ReferrerInfo(doc->GetDocumentURI(), doc->GetReferrerPolicy());
       loadState->SetReferrerInfo(referrerInfo);
     }
   }
 
+  // Currently we query the CSP from the subjectPrincipal. After Bug 965637
+  // we should query the CSP from the doc, similar to the referrerInfo above.
+  if (subjectPrincipal && loadState) {
+    nsCOMPtr<nsIContentSecurityPolicy> csp;
+    rv = subjectPrincipal->GetCsp(getter_AddRefs(csp));
+    NS_ENSURE_SUCCESS(rv, rv);
+    loadState->SetCsp(csp);
+  }
+
   if (isNewToplevelWindow) {
     // Notify observers that the window is open and ready.
     // The window has not yet started to load a document.
     nsCOMPtr<nsIObserverService> obsSvc =
         mozilla::services::GetObserverService();
     if (obsSvc) {
       obsSvc->NotifyObservers(*aResult, "toplevel-window-ready", nullptr);
     }
--- a/toolkit/modules/DateTimePickerPanel.jsm
+++ b/toolkit/modules/DateTimePickerPanel.jsm
@@ -94,17 +94,17 @@ var DateTimePickerPanel = class {
           break;
         }
     }
   }
 
   initPicker(detail) {
     // TODO: When bug 1376616 lands, replace this.setGregorian with
     //       mozIntl.Locale for setting calendar to Gregorian
-    const locale = this.setGregorian(Services.locale.appLocaleAsBCP47);
+    const locale = this.setGregorian(Services.locale.regionalPrefsLocales[0]);
     const dir = Services.intl.getLocaleInfo(locale).direction;
 
     switch (this.type) {
       case "time":
         {
           const { hour, minute } = detail.value;
           const format = detail.format || "12";
 
@@ -120,18 +120,17 @@ var DateTimePickerPanel = class {
               step: detail.step,
             },
           });
           break;
         }
       case "date":
         {
           const { year, month, day } = detail.value;
-          const { firstDayOfWeek, weekends } =
-          this.getCalendarInfo(locale);
+          const { firstDayOfWeek, weekends } = this.getCalendarInfo(locale);
           const monthStrings = this.getDisplayNames(
             locale, [
               "dates/gregorian/months/january",
               "dates/gregorian/months/february",
               "dates/gregorian/months/march",
               "dates/gregorian/months/april",
               "dates/gregorian/months/may",
               "dates/gregorian/months/june",
--- a/toolkit/modules/E10SUtils.jsm
+++ b/toolkit/modules/E10SUtils.jsm
@@ -101,16 +101,56 @@ var E10SUtils = {
 
   useHttpResponseProcessSelection() {
     return useHttpResponseProcessSelection;
   },
   useCrossOriginOpenerPolicy() {
     return useCrossOriginOpenerPolicy;
   },
 
+  /**
+   * Serialize csp data.
+   *
+   * @param {nsIContentSecurity} csp. The csp to serialize.
+   * @return {String} The base64 encoded csp data.
+   */
+  serializeCSP(csp) {
+    let serializedCSP = null;
+
+    try {
+      if (csp) {
+        serializedCSP = serializationHelper.serializeToString(csp);
+      }
+    } catch (e) {
+      debug(`Failed to serialize csp '${csp}' ${e}`);
+    }
+    return serializedCSP;
+  },
+
+  /**
+   * Deserialize a base64 encoded csp (serialized with
+   * Utils::serializeCSP).
+   *
+   * @param {String} csp_b64 A base64 encoded serialized csp.
+   * @return {nsIContentSecurityPolicy} A deserialized csp.
+   */
+  deserializeCSP(csp_b64) {
+    if (!csp_b64)
+      return null;
+
+    try {
+      let csp = serializationHelper.deserializeObject(csp_b64);
+      csp.QueryInterface(Ci.nsIContentSecurityPolicy);
+      return csp;
+    } catch (e) {
+      debug(`Failed to deserialize csp_b64 '${csp_b64}' ${e}`);
+    }
+    return null;
+  },
+
   canLoadURIInRemoteType(aURL, aRemoteType = DEFAULT_REMOTE_TYPE,
                          aPreferredRemoteType = undefined) {
     // We need a strict equality here because the value of `NOT_REMOTE` is
     // `null`, and there is a possibility that `undefined` is passed as an
     // argument, which might result a load in the parent process.
     if (aPreferredRemoteType === undefined) {
       aPreferredRemoteType = aRemoteType === NOT_REMOTE
         ? NOT_REMOTE
@@ -457,27 +497,28 @@ var E10SUtils = {
       return remoteType ==
         this.getRemoteTypeForURIObject(aURI, true, remoteType, webNav.currentURI);
     }
 
     // If the URI can be loaded in the current process then continue
     return this.shouldLoadURIInThisProcess(aURI);
   },
 
-  redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, aFreshProcess, aFlags) {
+  redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, aFreshProcess, aFlags, aCsp) {
     // Retarget the load to the correct process
     let messageManager = aDocShell.messageManager;
     let sessionHistory = aDocShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory;
 
     messageManager.sendAsyncMessage("Browser:LoadURI", {
       loadOptions: {
         uri: aURI.spec,
         flags: aFlags || Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
         referrer: aReferrer ? aReferrer.spec : null,
         triggeringPrincipal: this.serializePrincipal(aTriggeringPrincipal || Services.scriptSecurityManager.createNullPrincipal({})),
+        csp: aCsp ? this.serializeCSP(aCsp) : null,
         reloadInFreshProcess: !!aFreshProcess,
       },
       historyIndex: sessionHistory.legacySHistory.requestedIndex,
     });
     return false;
   },
 
   wrapHandlingUserInput(aWindow, aIsHandling, aCallback) {
--- a/toolkit/modules/sessionstore/SessionHistory.jsm
+++ b/toolkit/modules/sessionstore/SessionHistory.jsm
@@ -219,16 +219,20 @@ var SessionHistoryInternal = {
     if (shEntry.principalToInherit) {
       entry.principalToInherit_base64 = E10SUtils.serializePrincipal(shEntry.principalToInherit);
     }
 
     if (shEntry.triggeringPrincipal) {
       entry.triggeringPrincipal_base64 = E10SUtils.serializePrincipal(shEntry.triggeringPrincipal);
     }
 
+    if (shEntry.csp) {
+      entry.csp = E10SUtils.serializeCSP(shEntry.csp);
+    }
+
     entry.docIdentifier = shEntry.BFCacheEntry.ID;
 
     if (shEntry.stateData != null) {
       entry.structuredCloneState = shEntry.stateData.getDataAsBase64();
       entry.structuredCloneVersion = shEntry.stateData.formatVersion;
     }
 
     if (shEntry.childCount > 0 && !shEntry.hasDynamicallyAddedChild()) {
@@ -455,16 +459,19 @@ var SessionHistoryInternal = {
         // This won't always work however is safe to use.
         debug("Couldn't deserialize the triggeringPrincipal, falling back to NullPrincipal");
         return Services.scriptSecurityManager.createNullPrincipal({});
       });
     }
     if (entry.principalToInherit_base64) {
       shEntry.principalToInherit = E10SUtils.deserializePrincipal(entry.principalToInherit_base64);
     }
+    if (entry.csp) {
+      shEntry.csp = E10SUtils.deserializeCSP(entry.csp);
+    }
 
     if (entry.children) {
       for (var i = 0; i < entry.children.length; i++) {
         // XXXzpao Wallpaper patch for bug 514751
         if (!entry.children[i].url)
           continue;
 
         // We're getting sessionrestore.js files with a cycle in the
--- a/xpfe/appshell/nsContentTreeOwner.cpp
+++ b/xpfe/appshell/nsContentTreeOwner.cpp
@@ -357,41 +357,43 @@ NS_IMETHODIMP nsContentTreeOwner::OnBefo
                                                    linkNode, isAppTab, _retval);
 
   _retval = originalTarget;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsContentTreeOwner::ShouldLoadURI(
     nsIDocShell* aDocShell, nsIURI* aURI, nsIURI* aReferrer, bool aHasPostData,
-    nsIPrincipal* aTriggeringPrincipal, bool* _retval) {
+    nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp,
+    bool* _retval) {
   NS_ENSURE_STATE(mXULWindow);
 
   nsCOMPtr<nsIXULBrowserWindow> xulBrowserWindow;
   mXULWindow->GetXULBrowserWindow(getter_AddRefs(xulBrowserWindow));
 
   if (xulBrowserWindow)
     return xulBrowserWindow->ShouldLoadURI(aDocShell, aURI, aReferrer,
                                            aHasPostData, aTriggeringPrincipal,
-                                           _retval);
+                                           aCsp, _retval);
 
   *_retval = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsContentTreeOwner::ShouldLoadURIInThisProcess(nsIURI* aURI,
                                                              bool* aRetVal) {
   MOZ_ASSERT_UNREACHABLE("Should only be called in child process.");
   *aRetVal = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsContentTreeOwner::ReloadInFreshProcess(
     nsIDocShell* aDocShell, nsIURI* aURI, nsIURI* aReferrer,
-    nsIPrincipal* aTriggeringPrincipal, uint32_t aLoadFlags, bool* aRetVal) {
+    nsIPrincipal* aTriggeringPrincipal, uint32_t aLoadFlags,
+    nsIContentSecurityPolicy* aCsp, bool* aRetVal) {
   NS_WARNING("Cannot reload in fresh process from a nsContentTreeOwner!");
   *aRetVal = false;
   return NS_OK;
 }
 
 //*****************************************************************************
 // nsContentTreeOwner::nsIWebBrowserChrome2
 //*****************************************************************************
--- a/xpfe/appshell/nsIXULBrowserWindow.idl
+++ b/xpfe/appshell/nsIXULBrowserWindow.idl
@@ -9,16 +9,17 @@
 
 interface nsIBrowser;
 interface nsIRequest;
 interface nsIInputStream;
 interface nsIDocShell;
 interface nsITabParent;
 interface nsIPrincipal;
 interface mozIDOMWindowProxy;
+interface nsIContentSecurityPolicy;
 webidl Element;
 webidl Node;
 
 /**
  * The nsIXULBrowserWindow supplies the methods that may be called from the
  * internals of the browser area to tell the containing xul window to update
  * its ui. 
  */
@@ -56,22 +57,26 @@ interface nsIXULBrowserWindow : nsISuppo
    * @param aReferrer
    *        The referrer of the load.
    * @param aHasPostData
    *        True if the load which is being asked about has associated post data
    *        which would be discarded if the load was redirected across process
    *        boundaries.
    * @param aTriggeringPrincipal
    *        The principal that initiated the load of aURI.
+   * @param aCsp
+   *        The CSP to be used for that load. That is the CSP that e.g. upgrades
+   *        the load to HTTPS in case upgrade-insecure-requests is set
    */
   bool shouldLoadURI(in nsIDocShell    aDocShell,
                      in nsIURI         aURI,
                      in nsIURI         aReferrer,
                      in boolean        aHasPostData,
-                     in nsIPrincipal   aTriggeringPrincipal);
+                     in nsIPrincipal   aTriggeringPrincipal,
+                     in nsIContentSecurityPolicy aCsp);
   /**
    * Show/hide a tooltip (when the user mouses over a link, say).
    */
   void showTooltip(in long x, in long y, in AString tooltip, in AString direction,
                    in Element browser);
   void hideTooltip();
 
   /**