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();