diff --git a/parser/html/nsHtml5SpeculativeLoad.cpp b/parser/html/nsHtml5SpeculativeLoad.cpp
index bdc963a9fc0..0a1462d806d 100644
--- a/parser/html/nsHtml5SpeculativeLoad.cpp
+++ b/parser/html/nsHtml5SpeculativeLoad.cpp
@@ -27,6 +27,9 @@ nsHtml5SpeculativeLoad::Perform(nsHtml5TreeOpExecutor* aExecutor)
case eSpeculativeLoadBase:
aExecutor->SetSpeculationBase(mUrl);
break;
+ case eSpeculativeLoadCSP:
+ aExecutor->AddSpeculationCSP(mMetaCSP);
+ break;
case eSpeculativeLoadMetaReferrer:
aExecutor->SetSpeculationReferrerPolicy(mReferrerPolicy);
break;
diff --git a/parser/html/nsHtml5SpeculativeLoad.h b/parser/html/nsHtml5SpeculativeLoad.h
index 0eef9874400..57dcc2697d2 100644
--- a/parser/html/nsHtml5SpeculativeLoad.h
+++ b/parser/html/nsHtml5SpeculativeLoad.h
@@ -15,6 +15,7 @@ enum eHtml5SpeculativeLoad {
eSpeculativeLoadUninitialized,
#endif
eSpeculativeLoadBase,
+ eSpeculativeLoadCSP,
eSpeculativeLoadMetaReferrer,
eSpeculativeLoadImage,
eSpeculativeLoadOpenPicture,
@@ -41,6 +42,14 @@ class nsHtml5SpeculativeLoad {
mUrl.Assign(aUrl);
}
+ inline void InitMetaCSP(const nsAString& aCSP) {
+ NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
+ "Trying to reinitialize a speculative load!");
+ mOpCode = eSpeculativeLoadCSP;
+ mMetaCSP.Assign(
+ nsContentUtils::TrimWhitespace(aCSP));
+ }
+
inline void InitMetaReferrerPolicy(const nsAString& aReferrerPolicy) {
NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
"Trying to reinitialize a speculative load!");
@@ -187,6 +196,8 @@ class nsHtml5SpeculativeLoad {
eHtml5SpeculativeLoad mOpCode;
nsString mUrl;
nsString mReferrerPolicy;
+ nsString mMetaCSP;
+
/**
* If mOpCode is eSpeculativeLoadStyle or eSpeculativeLoadScript[FromHead]
* then this is the value of the "charset" attribute. For
diff --git a/parser/html/nsHtml5TreeBuilderCppSupplement.h b/parser/html/nsHtml5TreeBuilderCppSupplement.h
index ae2de676775..cc26449067f 100644
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -236,6 +236,14 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName,
}
} else if (nsHtml5Atoms::meta == aName) {
if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
+ "content-security-policy",
+ aAttributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) {
+ nsString* csp = aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
+ if (csp) {
+ mSpeculativeLoadQueue.AppendElement()->InitMetaCSP(*csp);
+ }
+ }
+ else if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
"referrer",
aAttributes->getValue(nsHtml5AttributeName::ATTR_NAME))) {
nsString* referrerPolicy = aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp
index 7f489ea90c1..2408cced895 100644
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -6,13 +6,16 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/Likely.h"
+#include "mozilla/dom/nsCSPService.h"
#include "nsError.h"
#include "nsHtml5TreeOpExecutor.h"
#include "nsScriptLoader.h"
#include "nsIContentViewer.h"
+#include "nsIContentSecurityPolicy.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShell.h"
+#include "nsIDOMDocument.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptSecurityManager.h"
#include "nsIWebShellServices.h"
@@ -1014,6 +1017,43 @@ nsHtml5TreeOpExecutor::SetSpeculationReferrerPolicy(const nsAString& aReferrerPo
return SetSpeculationReferrerPolicy(policy);
}
+void
+nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP)
+{
+ if (!CSPService::sCSPEnabled) {
+ return;
+ }
+
+ NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+ nsIPrincipal* principal = mDocument->NodePrincipal();
+ nsCOMPtr preloadCsp;
+ nsresult rv = principal->GetPreloadCsp(getter_AddRefs(preloadCsp));
+ NS_ENSURE_SUCCESS_VOID(rv);
+ if (!preloadCsp) {
+ preloadCsp = do_CreateInstance("@mozilla.org/cspcontext;1", &rv);
+ NS_ENSURE_SUCCESS_VOID(rv);
+
+ // Store the request context for violation reports
+ nsCOMPtr domDoc = do_QueryInterface(mDocument);
+ rv = preloadCsp->SetRequestContext(domDoc, nullptr);
+ NS_ENSURE_SUCCESS_VOID(rv);
+
+ // set the new csp
+ rv = principal->SetPreloadCsp(preloadCsp);
+ NS_ENSURE_SUCCESS_VOID(rv);
+ }
+
+ // please note that meta CSPs and CSPs delivered through a header need
+ // to be joined together.
+ rv = preloadCsp->AppendPolicy(aCSP,
+ false, // csp via meta tag can not be report only
+ true); // delivered through the meta tag
+ NS_ENSURE_SUCCESS_VOID(rv);
+
+ mDocument->ApplySettingsFromCSP(true);
+}
+
void
nsHtml5TreeOpExecutor::SetSpeculationReferrerPolicy(ReferrerPolicy aReferrerPolicy)
{
diff --git a/parser/html/nsHtml5TreeOpExecutor.h b/parser/html/nsHtml5TreeOpExecutor.h
index e9f0e886815..c4b6a45943b 100644
--- a/parser/html/nsHtml5TreeOpExecutor.h
+++ b/parser/html/nsHtml5TreeOpExecutor.h
@@ -275,6 +275,8 @@ class nsHtml5TreeOpExecutor final : public nsHtml5DocumentBuilder,
void SetSpeculationReferrerPolicy(ReferrerPolicy aReferrerPolicy);
void SetSpeculationReferrerPolicy(const nsAString& aReferrerPolicy);
+ void AddSpeculationCSP(const nsAString& aCSP);
+
void AddBase(const nsAString& aURL);
static void InitializeStatics();