Bug 1518454: Part 1, backend changes, add CSP to loadURIOptions dictionary and pass CSP explicitly from frontend to docshell. r=bz
authorChristoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
Thu, 21 Feb 2019 16:00:32 +0100
changeset 518705 9b18d986ef299f2dbcc8bbed379d117179c0040d
parent 518704 78bd492048c2b34664f9810660ec42567e32e4d7
child 518706 530bf099ee9db334bfaa4a14e2a0ce15fb8dcc14
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)
reviewersbz
bugs1518454
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1518454: Part 1, backend changes, add CSP to loadURIOptions dictionary and pass CSP explicitly from frontend to docshell. r=bz
caps/nsIPrincipal.idl
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsDocShellLoadState.cpp
docshell/base/nsDocShellLoadState.h
docshell/base/nsDocShellTreeOwner.cpp
docshell/base/nsILinkHandler.h
docshell/shistory/nsISHEntry.idl
docshell/shistory/nsSHEntry.cpp
docshell/shistory/nsSHEntryShared.cpp
docshell/shistory/nsSHEntryShared.h
docshell/shistory/nsSHistory.cpp
dom/base/ContentAreaDropListener.jsm
dom/base/Location.cpp
dom/base/nsContentUtils.cpp
dom/base/nsFrameLoader.cpp
dom/base/nsIDroppedLinkHandler.idl
dom/base/nsOpenURIInFrameParams.cpp
dom/base/nsOpenURIInFrameParams.h
dom/bindings/Bindings.conf
dom/clients/manager/ClientNavigateOpChild.cpp
dom/interfaces/base/nsIBrowserDOMWindow.idl
dom/ipc/CSPMessageUtils.cpp
dom/ipc/CSPMessageUtils.h
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/DOMTypes.ipdlh
dom/ipc/MemoryReportRequest.cpp
dom/ipc/PContent.ipdl
dom/ipc/moz.build
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/webidl/LoadURIOptions.webidl
toolkit/components/browser/nsIWebBrowserChrome3.idl
toolkit/components/windowwatcher/nsWindowWatcher.cpp
xpfe/appshell/nsContentTreeOwner.cpp
xpfe/appshell/nsIXULBrowserWindow.idl
--- 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/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/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/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();
 
   /**