Bug 1496034 - Apply bz's comments to FeaturePolicy, r=bz
authorAndrea Marchesini <amarchesini@mozilla.com>
Fri, 12 Oct 2018 09:36:33 +0200
changeset 496595 402b42c38c70da770675e64c3f5bc005a98d3b84
parent 496568 ee4f12cc7136126f1d4adec65432a76123f11212
child 496596 fa33c65b62229b11f418a9f9850f01c59b650d2f
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1496034
milestone64.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 1496034 - Apply bz's comments to FeaturePolicy, r=bz
dom/base/nsDocument.cpp
dom/html/HTMLIFrameElement.cpp
dom/html/HTMLIFrameElement.h
dom/html/nsGenericHTMLFrameElement.cpp
dom/html/nsGenericHTMLFrameElement.h
dom/security/featurepolicy/Feature.cpp
dom/security/featurepolicy/Feature.h
dom/security/featurepolicy/FeaturePolicy.cpp
dom/security/featurepolicy/FeaturePolicy.h
dom/security/featurepolicy/FeaturePolicyParser.cpp
dom/security/featurepolicy/FeaturePolicyParser.h
dom/security/featurepolicy/FeaturePolicyUtils.cpp
dom/security/featurepolicy/FeaturePolicyUtils.h
dom/security/featurepolicy/test/gtest/TestFeaturePolicyParser.cpp
testing/web-platform/meta/feature-policy/feature-policy-frame-policy-allowed-for-self.https.sub.html.ini
testing/web-platform/tests/feature-policy/feature-policy-frame-policy-allowed-for-all.https.sub.html
testing/web-platform/tests/feature-policy/feature-policy-frame-policy-allowed-for-self.https.sub.html
testing/web-platform/tests/feature-policy/feature-policy-frame-policy-allowed-for-some.https.sub.html
testing/web-platform/tests/feature-policy/feature-policy-frame-policy-disallowed-for-all.https.sub.html
testing/web-platform/tests/feature-policy/resources/featurepolicy.js
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3019,61 +3019,52 @@ nsIDocument::InitFeaturePolicy(nsIChanne
   // we need to create a policy here so getting the policy within
   // ::Policy() can *always* return a non null policy
   mFeaturePolicy = new FeaturePolicy(this);
 
   if (!StaticPrefs::dom_security_featurePolicy_enabled()) {
     return NS_OK;
   }
 
-  nsAutoString origin;
-  nsresult rv = nsContentUtils::GetUTFOrigin(NodePrincipal(), origin);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  mFeaturePolicy->SetDefaultOrigin(origin);
+  mFeaturePolicy->SetDefaultOrigin(NodePrincipal());
 
   RefPtr<FeaturePolicy> parentPolicy = nullptr;
   if (mDocumentContainer) {
     nsPIDOMWindowOuter* containerWindow = mDocumentContainer->GetWindow();
     if (containerWindow) {
       nsCOMPtr<nsINode> node = containerWindow->GetFrameElementInternal();
-      if (node) {
-        HTMLIFrameElement* iframe = HTMLIFrameElement::FromNode(node);
-        if (iframe) {
-          parentPolicy = iframe->Policy();
-        }
+      HTMLIFrameElement* iframe = HTMLIFrameElement::FromNodeOrNull(node);
+      if (iframe) {
+        parentPolicy = iframe->Policy();
       }
     }
   }
 
   if (parentPolicy) {
     // Let's inherit the policy from the parent HTMLIFrameElement if it exists.
     mFeaturePolicy->InheritPolicy(parentPolicy);
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel;
-  rv = GetHttpChannelHelper(aChannel, getter_AddRefs(httpChannel));
+  nsresult rv = GetHttpChannelHelper(aChannel, getter_AddRefs(httpChannel));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (!httpChannel) {
     return NS_OK;
   }
 
   // query the policy from the header
   nsAutoCString value;
   rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Feature-Policy"),
                                       value);
   if (NS_SUCCEEDED(rv)) {
     mFeaturePolicy->SetDeclaredPolicy(this, NS_ConvertUTF8toUTF16(value),
-                                      origin, EmptyString(),
-                                      false /* 'src' enabled */);
+                                      NodePrincipal(), nullptr);
   }
 
   return NS_OK;
 }
 
 void
 nsDocument::StopDocumentLoad()
 {
@@ -10226,17 +10217,18 @@ nsIDocument::MaybeResolveReadyForIdle()
 }
 
 FeaturePolicy*
 nsIDocument::Policy() const
 {
   MOZ_ASSERT(StaticPrefs::dom_security_featurePolicy_enabled());
 
   // The policy is created when the document is initialized. We _must_ have a
-  // policy here.
+  // policy here even if the featurePolicy pref is off. If this assertion fails,
+  // it means that ::Policy() is called before ::StartDocumentLoad().
   MOZ_ASSERT(mFeaturePolicy);
   return mFeaturePolicy;
 }
 
 nsIDOMXULCommandDispatcher*
 nsIDocument::GetCommandDispatcher()
 {
   // Only chrome documents are allowed to use command dispatcher.
--- a/dom/html/HTMLIFrameElement.cpp
+++ b/dom/html/HTMLIFrameElement.cpp
@@ -3,45 +3,63 @@
 /* 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/HTMLIFrameElement.h"
 #include "mozilla/dom/HTMLIFrameElementBinding.h"
 #include "mozilla/dom/FeaturePolicy.h"
 #include "mozilla/MappedDeclarations.h"
+#include "mozilla/NullPrincipal.h"
 #include "mozilla/StaticPrefs.h"
 #include "nsMappedAttributes.h"
 #include "nsAttrValueInlines.h"
 #include "nsError.h"
 #include "nsStyleConsts.h"
 #include "nsContentUtils.h"
 #include "nsSandboxFlags.h"
 #include "nsNetUtil.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(IFrame)
 
 namespace mozilla {
 namespace dom {
 
+NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLIFrameElement)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLIFrameElement,
+                                                  nsGenericHTMLFrameElement)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFeaturePolicy)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLIFrameElement,
+                                                nsGenericHTMLFrameElement)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFeaturePolicy)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_ADDREF_INHERITED(HTMLIFrameElement, nsGenericHTMLFrameElement)
+NS_IMPL_RELEASE_INHERITED(HTMLIFrameElement, nsGenericHTMLFrameElement)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLIFrameElement)
+NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLFrameElement)
+
 // static
 const DOMTokenListSupportedToken HTMLIFrameElement::sSupportedSandboxTokens[] = {
 #define SANDBOX_KEYWORD(string, atom, flags) string,
 #include "IframeSandboxKeywordList.h"
 #undef SANDBOX_KEYWORD
   nullptr
 };
 
 HTMLIFrameElement::HTMLIFrameElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                                      FromParser aFromParser)
   : nsGenericHTMLFrameElement(std::move(aNodeInfo), aFromParser)
 {
-  if (StaticPrefs::dom_security_featurePolicy_enabled()) {
-    mFeaturePolicy = new FeaturePolicy(this);
-  }
+  // We always need a featurePolicy, even if not exposed.
+  mFeaturePolicy = new FeaturePolicy(this);
 }
 
 HTMLIFrameElement::~HTMLIFrameElement()
 {
 }
 
 NS_IMPL_ELEMENT_CLONE(HTMLIFrameElement)
 
@@ -169,16 +187,17 @@ HTMLIFrameElement::AfterSetAttr(int32_t 
         // If we have an nsFrameLoader, apply the new sandbox flags.
         // Since this is called after the setter, the sandbox flags have
         // alreay been updated.
         mFrameLoader->ApplySandboxFlags(GetSandboxFlags());
       }
     }
     if ((aName == nsGkAtoms::allow ||
          aName == nsGkAtoms::src ||
+         aName == nsGkAtoms::srcdoc ||
          aName == nsGkAtoms::sandbox ||
          aName == nsGkAtoms::allowpaymentrequest) &&
         StaticPrefs::dom_security_featurePolicy_enabled()) {
       RefreshFeaturePolicy();
     }
   }
   return nsGenericHTMLFrameElement::AfterSetAttr(aNameSpaceID, aName,
                                                  aValue, aOldValue,
@@ -231,84 +250,65 @@ HTMLIFrameElement::WrapNode(JSContext* a
 FeaturePolicy*
 HTMLIFrameElement::Policy() const
 {
   MOZ_ASSERT(StaticPrefs::dom_security_featurePolicy_enabled());
   return mFeaturePolicy;
 }
 
 nsresult
-HTMLIFrameElement::GetFeaturePolicyDefaultOrigin(nsAString& aDefaultOrigin) const
+HTMLIFrameElement::GetFeaturePolicyDefaultOrigin(nsIPrincipal** aPrincipal) const
 {
-  aDefaultOrigin.Truncate();
+  nsCOMPtr<nsIPrincipal> principal;
 
-  nsresult rv;
-  nsAutoString src;
-  GetURIAttr(nsGkAtoms::src, nullptr, src);
+  if (HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc)) {
+    principal = NodePrincipal();
+  }
 
-  nsCOMPtr<nsIURI> nodeURI;
-  if (!src.IsEmpty()) {
-    nsCOMPtr<nsIURI> baseURI = OwnerDoc()->GetBaseURI();
-
-    rv = NS_NewURI(getter_AddRefs(nodeURI), src,
-                   OwnerDoc()->GetDocumentCharacterSet(),
-                   baseURI);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      nodeURI = nullptr;
+  if (!principal) {
+    nsCOMPtr<nsIURI> nodeURI;
+    if (GetURIAttr(nsGkAtoms::src, nullptr, getter_AddRefs(nodeURI)) &&
+        nodeURI) {
+      principal =
+        BasePrincipal::CreateCodebasePrincipal(nodeURI,
+                                               BasePrincipal::Cast(NodePrincipal())->OriginAttributesRef());
     }
   }
 
-  if (!nodeURI) {
-    if (OwnerDoc()->GetSandboxFlags() & SANDBOXED_ORIGIN) {
-      return NS_OK;
-    }
-
-    nodeURI = OwnerDoc()->GetDocumentURI();
+  if (!principal) {
+    principal = NodePrincipal();
   }
 
-  nsAutoString origin;
-  rv = nsContentUtils::GetUTFOrigin(nodeURI, origin);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
-  }
-
-  aDefaultOrigin.Assign(origin);
+  principal.forget(aPrincipal);
   return NS_OK;
 }
 
 void
 HTMLIFrameElement::RefreshFeaturePolicy()
 {
   MOZ_ASSERT(StaticPrefs::dom_security_featurePolicy_enabled());
   mFeaturePolicy->ResetDeclaredPolicy();
 
   // The origin can change if 'src' attribute changes.
-  nsAutoString origin;
-  nsresult rv = GetFeaturePolicyDefaultOrigin(origin);
+  nsCOMPtr<nsIPrincipal> origin;
+  nsresult rv = GetFeaturePolicyDefaultOrigin(getter_AddRefs(origin));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
+  MOZ_ASSERT(origin);
   mFeaturePolicy->SetDefaultOrigin(origin);
 
   nsAutoString allow;
   GetAttr(nsGkAtoms::allow, allow);
 
   if (!allow.IsEmpty()) {
-    nsAutoString documentOrigin;
-    if (OwnerDoc()->GetSandboxFlags() ^ SANDBOXED_ORIGIN) {
-      nsresult rv = nsContentUtils::GetUTFOrigin(NodePrincipal(), documentOrigin);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return;
-      }
-    }
-
     // Set or reset the FeaturePolicy directives.
-    mFeaturePolicy->SetDeclaredPolicy(OwnerDoc(), allow, documentOrigin,
-                                      origin, true /* 'src' enabled */);
+    mFeaturePolicy->SetDeclaredPolicy(OwnerDoc(), allow, NodePrincipal(),
+                                      origin);
   }
 
   mFeaturePolicy->InheritPolicy(OwnerDoc()->Policy());
 
   if (AllowPaymentRequest()) {
     mFeaturePolicy->MaybeSetAllowedPolicy(NS_LITERAL_STRING("payment"));
   }
 
--- a/dom/html/HTMLIFrameElement.h
+++ b/dom/html/HTMLIFrameElement.h
@@ -3,33 +3,35 @@
 /* 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_HTMLIFrameElement_h
 #define mozilla_dom_HTMLIFrameElement_h
 
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/FeaturePolicy.h"
 #include "nsGenericHTMLFrameElement.h"
 #include "nsDOMTokenList.h"
 
 namespace mozilla {
 namespace dom {
 
 class HTMLIFrameElement final : public nsGenericHTMLFrameElement
 {
 public:
   explicit HTMLIFrameElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                              FromParser aFromParser = NOT_FROM_PARSER);
 
   NS_IMPL_FROMNODE_HTML_WITH_TAG(HTMLIFrameElement, iframe)
 
   // nsISupports
-  NS_INLINE_DECL_REFCOUNTING_INHERITED(HTMLIFrameElement,
-                                       nsGenericHTMLFrameElement)
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLIFrameElement,
+                                           nsGenericHTMLFrameElement)
 
   // Element
   virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override
   {
     return true;
   }
 
   // nsIContent
@@ -218,27 +220,34 @@ protected:
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
                                     MappedDeclarations&);
 
   static const DOMTokenListSupportedToken sSupportedSandboxTokens[];
 
   void RefreshFeaturePolicy();
 
+  // Implements the declared-origin algorithm as described in Feature-Policy
+  // spec: https://wicg.github.io/feature-policy/#declared-origin
+  // If this iframe has a 'src' attribute, the origin will be the parsing of its
+  // value as URL. If the URL is invalid, or 'src' attribute doesn't exist, the
+  // origin will be the document's origin.
   nsresult
-  GetFeaturePolicyDefaultOrigin(nsAString& aDefaultOrigin) const;
+  GetFeaturePolicyDefaultOrigin(nsIPrincipal** aDefaultOrigin) const;
 
   /**
    * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
    * This function will be called by AfterSetAttr whether the attribute is being
    * set or unset.
    *
    * @param aNamespaceID the namespace of the attr being set
    * @param aName the localname of the attribute being set
    * @param aNotify Whether we plan to notify document observers.
    */
   void AfterMaybeChangeAttr(int32_t aNamespaceID, nsAtom* aName, bool aNotify);
+
+  RefPtr<mozilla::dom::FeaturePolicy> mFeaturePolicy;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/html/nsGenericHTMLFrameElement.cpp
+++ b/dom/html/nsGenericHTMLFrameElement.cpp
@@ -30,29 +30,27 @@ using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
                                                   nsGenericHTMLElement)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpenerWindow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserElementAPI)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFeaturePolicy)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGenericHTMLFrameElement,
                                                 nsGenericHTMLElement)
   if (tmp->mFrameLoader) {
     tmp->mFrameLoader->Destroy();
   }
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameLoader)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpenerWindow)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserElementAPI)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFeaturePolicy)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(nsGenericHTMLFrameElement,
                                              nsGenericHTMLElement,
                                              nsIFrameLoaderOwner,
                                              nsIDOMMozBrowserFrame,
                                              nsIMozBrowserFrame,
                                              nsGenericHTMLFrameElement)
--- a/dom/html/nsGenericHTMLFrameElement.h
+++ b/dom/html/nsGenericHTMLFrameElement.h
@@ -5,17 +5,16 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsGenericHTMLFrameElement_h
 #define nsGenericHTMLFrameElement_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/nsBrowserElement.h"
-#include "mozilla/dom/FeaturePolicy.h"
 
 #include "nsFrameLoader.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMEventListener.h"
 #include "nsIFrameLoaderOwner.h"
 #include "nsIMozBrowserFrame.h"
 
 namespace mozilla {
@@ -123,19 +122,16 @@ protected:
                                           const nsAttrValueOrString& aValue,
                                           bool aNotify) override;
 
   RefPtr<nsFrameLoader> mFrameLoader;
   nsCOMPtr<nsPIDOMWindowOuter> mOpenerWindow;
 
   nsCOMPtr<nsIPrincipal> mSrcTriggeringPrincipal;
 
-  // Used by <iframe> only.
-  RefPtr<mozilla::dom::FeaturePolicy> mFeaturePolicy;
-
   /**
    * True if we have already loaded the frame's original src
    */
   bool mSrcLoadHappened;
 
   /**
    * True when the element is created by the parser using the
    * NS_FROM_PARSER_NETWORK flag.
--- a/dom/security/featurepolicy/Feature.cpp
+++ b/dom/security/featurepolicy/Feature.cpp
@@ -1,98 +1,108 @@
 /* -*- 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 "Feature.h"
+#include "mozilla/BasePrincipal.h"
 
-using namespace mozilla::dom;
+namespace mozilla {
+namespace dom {
 
 void
-Feature::GetWhiteListedOrigins(nsTArray<nsString>& aList) const
+Feature::GetAllowList(nsTArray<nsCOMPtr<nsIPrincipal>>& aList) const
 {
-  MOZ_ASSERT(mPolicy == eWhiteList);
-  aList.AppendElements(mWhiteListedOrigins);
+  MOZ_ASSERT(mPolicy == eAllowList);
+  aList.AppendElements(mAllowList);
 }
 
 bool
-Feature::Allows(const nsAString& aOrigin) const
+Feature::Allows(nsIPrincipal* aPrincipal) const
 {
   if (mPolicy == eNone) {
     return false;
   }
 
   if (mPolicy == eAll) {
     return true;
   }
 
-  for (const nsString& whiteListedOrigin : mWhiteListedOrigins) {
-    if (whiteListedOrigin.Equals(aOrigin)) {
-      return true;
-    }
-  }
-
-  return false;
+  return AllowListContains(aPrincipal);
 }
 
 Feature::Feature(const nsAString& aFeatureName)
   : mFeatureName(aFeatureName)
-  , mPolicy(eWhiteList)
+  , mPolicy(eAllowList)
 {}
 
 Feature::~Feature() = default;
 
 const nsAString&
 Feature::Name() const
 {
   return mFeatureName;
 }
 
 void
 Feature::SetAllowsNone()
 {
   mPolicy = eNone;
-  mWhiteListedOrigins.Clear();
+  mAllowList.Clear();
 }
 
 bool
 Feature::AllowsNone() const
 {
   return mPolicy == eNone;
 }
 
 void
 Feature::SetAllowsAll()
 {
   mPolicy = eAll;
-  mWhiteListedOrigins.Clear();
+  mAllowList.Clear();
 }
 
 bool
 Feature::AllowsAll() const
 {
   return mPolicy == eAll;
 }
 
 void
-Feature::AppendOriginToWhiteList(const nsAString& aOrigin)
+Feature::AppendToAllowList(nsIPrincipal* aPrincipal)
 {
-  mPolicy = eWhiteList;
-  mWhiteListedOrigins.AppendElement(aOrigin);
+  MOZ_ASSERT(aPrincipal);
+
+  mPolicy = eAllowList;
+  mAllowList.AppendElement(aPrincipal);
 }
 
 bool
-Feature::WhiteListContains(const nsAString& aOrigin) const
+Feature::AllowListContains(nsIPrincipal* aPrincipal) const
 {
-  if (!IsWhiteList()) {
+  MOZ_ASSERT(aPrincipal);
+
+  if (!HasAllowList()) {
     return false;
   }
 
-  return mWhiteListedOrigins.Contains(aOrigin);
+  for (nsIPrincipal* principal : mAllowList) {
+    if (BasePrincipal::Cast(principal)->Subsumes(aPrincipal,
+                                                 BasePrincipal::ConsiderDocumentDomain)) {
+      return true;
+    }
+  }
+
+  return false;
 }
 
 bool
-Feature::IsWhiteList() const
+Feature::HasAllowList() const
 {
-  return mPolicy == eWhiteList;
+  return mPolicy == eAllowList;
 }
+
+} // dom namespace
+} // mozilla namespace
--- a/dom/security/featurepolicy/Feature.h
+++ b/dom/security/featurepolicy/Feature.h
@@ -6,16 +6,18 @@
 
 #ifndef mozilla_dom_Feature_h
 #define mozilla_dom_Feature_h
 
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsCOMPtr.h"
 
+class nsIPrincipal;
+
 namespace mozilla {
 namespace dom {
 
 class Feature final
 {
 public:
   explicit Feature(const nsAString& aFeatureName);
 
@@ -32,45 +34,45 @@ public:
 
   void
   SetAllowsAll();
 
   bool
   AllowsAll() const;
 
   void
-  AppendOriginToWhiteList(const nsAString& aOrigin);
+  AppendToAllowList(nsIPrincipal* aPrincipal);
 
   void
-  GetWhiteListedOrigins(nsTArray<nsString>& aList) const;
+  GetAllowList(nsTArray<nsCOMPtr<nsIPrincipal>>& aList) const;
 
   bool
-  WhiteListContains(const nsAString& aOrigin) const;
+  AllowListContains(nsIPrincipal* aPrincipal) const;
 
   bool
-  IsWhiteList() const;
+  HasAllowList() const;
 
   bool
-  Allows(const nsAString& aOrigin) const;
+  Allows(nsIPrincipal* aPrincipal) const;
 
 private:
   nsString mFeatureName;
 
   enum Policy {
     // denotes a policy of "feature 'none'"
     eNone,
 
     // denotes a policy of "feature *"
     eAll,
 
     // denotes a policy of "feature bar.com foo.com"
-    eWhiteList,
+    eAllowList,
   };
 
   Policy mPolicy;
 
-  nsTArray<nsString> mWhiteListedOrigins;
+  nsTArray<nsCOMPtr<nsIPrincipal>> mAllowList;
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_Feature_h
--- a/dom/security/featurepolicy/FeaturePolicy.cpp
+++ b/dom/security/featurepolicy/FeaturePolicy.cpp
@@ -4,18 +4,20 @@
  * 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 "FeaturePolicy.h"
 #include "mozilla/dom/FeaturePolicyBinding.h"
 #include "mozilla/dom/FeaturePolicyParser.h"
 #include "mozilla/dom/FeaturePolicyUtils.h"
 #include "nsContentUtils.h"
+#include "nsNetUtil.h"
 
-using namespace mozilla::dom;
+namespace mozilla {
+namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FeaturePolicy, mParentNode)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(FeaturePolicy)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(FeaturePolicy)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FeaturePolicy)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
@@ -29,17 +31,17 @@ void
 FeaturePolicy::InheritPolicy(FeaturePolicy* aParentPolicy)
 {
   MOZ_ASSERT(aParentPolicy);
 
   mInheritedDeniedFeatureNames.Clear();
 
   RefPtr<FeaturePolicy> dest = this;
   RefPtr<FeaturePolicy> src = aParentPolicy;
-  nsString origin = mDefaultOrigin;
+  nsCOMPtr<nsIPrincipal> origin = mDefaultOrigin;
   FeaturePolicyUtils::ForEachFeature([dest, src, origin](const char* aFeatureName) {
     nsString featureName;
     featureName.AppendASCII(aFeatureName);
 
     // If the destination has a declared feature (via the HTTP header or 'allow'
     // attribute) we allow the feature only if both parent FeaturePolicy and this
     // one allow the current origin.
     if (dest->HasDeclaredFeature(featureName)) {
@@ -81,27 +83,25 @@ FeaturePolicy::HasDeclaredFeature(const 
   }
 
   return false;
 }
 
 void
 FeaturePolicy::SetDeclaredPolicy(nsIDocument* aDocument,
                                  const nsAString& aPolicyString,
-                                 const nsAString& aSelfOrigin,
-                                 const nsAString& aSrcOrigin,
-                                 bool aSrcEnabled)
+                                 nsIPrincipal* aSelfOrigin,
+                                 nsIPrincipal* aSrcOrigin)
 {
   ResetDeclaredPolicy();
 
   Unused << NS_WARN_IF(!FeaturePolicyParser::ParseString(aPolicyString,
                                                          aDocument,
                                                          aSelfOrigin,
                                                          aSrcOrigin,
-                                                         aSrcEnabled,
                                                          mFeatures));
 }
 
 void
 FeaturePolicy::ResetDeclaredPolicy()
 {
   mFeatures.Clear();
 }
@@ -111,39 +111,69 @@ FeaturePolicy::WrapObject(JSContext* aCx
 {
   return Policy_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 bool
 FeaturePolicy::AllowsFeature(const nsAString& aFeatureName,
                              const Optional<nsAString>& aOrigin) const
 {
-  return AllowsFeatureInternal(aFeatureName,
-                               aOrigin.WasPassed()
-                                 ? aOrigin.Value()
-                                 : mDefaultOrigin);
+  nsCOMPtr<nsIPrincipal> origin;
+  if (aOrigin.WasPassed()) {
+    nsCOMPtr<nsIURI> uri;
+    nsresult rv = NS_NewURI(getter_AddRefs(uri), aOrigin.Value());
+    if (NS_FAILED(rv)) {
+      return false;
+    }
+    origin = BasePrincipal::CreateCodebasePrincipal(uri,
+                                                    BasePrincipal::Cast(mDefaultOrigin)->OriginAttributesRef());
+  } else {
+    origin = mDefaultOrigin;
+  }
+
+  if (NS_WARN_IF(!origin)) {
+    return false;
+  }
+
+  return AllowsFeatureInternal(aFeatureName, origin);
 }
 
 bool
 FeaturePolicy::AllowsFeatureInternal(const nsAString& aFeatureName,
-                                     const nsAString& aOrigin) const
+                                     nsIPrincipal* aOrigin) const
 {
+  MOZ_ASSERT(aOrigin);
+
   // Let's see if have to disable this feature because inherited policy.
   if (HasInheritedDeniedFeature(aFeatureName)) {
     return false;
   }
 
   for (const Feature& feature : mFeatures) {
     if (feature.Name().Equals(aFeatureName)) {
       return feature.Allows(aOrigin);
     }
   }
 
-  return FeaturePolicyUtils::AllowDefaultFeature(aFeatureName, mDefaultOrigin,
-                                                 aOrigin);
+  switch (FeaturePolicyUtils::DefaultAllowListFeature(aFeatureName)) {
+    case FeaturePolicyUtils::FeaturePolicyValue::eAll:
+      return true;
+
+    case FeaturePolicyUtils::FeaturePolicyValue::eSelf:
+      return BasePrincipal::Cast(mDefaultOrigin)->Subsumes(aOrigin,
+                                                           BasePrincipal::ConsiderDocumentDomain);
+
+    case FeaturePolicyUtils::FeaturePolicyValue::eNone:
+      return false;
+
+    default:
+      MOZ_CRASH("Unknown default value");
+  }
+
+  return false;
 }
 
 void
 FeaturePolicy::AllowedFeatures(nsTArray<nsString>& aAllowedFeatures)
 {
   RefPtr<FeaturePolicy> self = this;
   FeaturePolicyUtils::ForEachFeature([self, &aAllowedFeatures](const char* aFeatureName) {
     nsString featureName;
@@ -165,26 +195,54 @@ FeaturePolicy::GetAllowlistForFeature(co
 
   for (const Feature& feature : mFeatures) {
     if (feature.Name().Equals(aFeatureName)) {
       if (feature.AllowsAll()) {
         aList.AppendElement(NS_LITERAL_STRING("*"));
         return;
       }
 
-      feature.GetWhiteListedOrigins(aList);
+      nsTArray<nsCOMPtr<nsIPrincipal>> list;
+      feature.GetAllowList(list);
+
+      for (nsIPrincipal* principal : list) {
+        nsAutoCString originNoSuffix;
+        nsresult rv = principal->GetOriginNoSuffix(originNoSuffix);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return;
+        }
+
+        aList.AppendElement(NS_ConvertUTF8toUTF16(originNoSuffix));
+      }
       return;
     }
   }
 
-  nsString defaultAllowList;
-  FeaturePolicyUtils::DefaultAllowListFeature(aFeatureName, mDefaultOrigin,
-                                              defaultAllowList);
-   if (!defaultAllowList.IsEmpty()) {
-    aList.AppendElement(defaultAllowList);
+  switch (FeaturePolicyUtils::DefaultAllowListFeature(aFeatureName)) {
+    case FeaturePolicyUtils::FeaturePolicyValue::eAll:
+      aList.AppendElement(NS_LITERAL_STRING("*"));
+      return;
+
+    case FeaturePolicyUtils::FeaturePolicyValue::eSelf:
+    {
+      nsAutoCString originNoSuffix;
+      nsresult rv = mDefaultOrigin->GetOriginNoSuffix(originNoSuffix);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return;
+      }
+
+      aList.AppendElement(NS_ConvertUTF8toUTF16(originNoSuffix));
+      return;
+    }
+
+    case FeaturePolicyUtils::FeaturePolicyValue::eNone:
+      return;
+
+    default:
+      MOZ_CRASH("Unknown default value");
   }
 }
 
 void
 FeaturePolicy::MaybeSetAllowedPolicy(const nsAString& aFeatureName)
 {
   MOZ_ASSERT(FeaturePolicyUtils::IsSupportedFeature(aFeatureName));
 
@@ -192,8 +250,11 @@ FeaturePolicy::MaybeSetAllowedPolicy(con
     return;
   }
 
   Feature feature(aFeatureName);
   feature.SetAllowsAll();
 
   mFeatures.AppendElement(feature);
 }
+
+} // dom namespace
+} // mozilla namespace
--- a/dom/security/featurepolicy/FeaturePolicy.h
+++ b/dom/security/featurepolicy/FeaturePolicy.h
@@ -25,22 +25,22 @@
  *
  * FeaturePolicy is composed by a set of directives configured by the
  * 'Feature-Policy' HTTP Header and the 'allow' attribute in HTMLIFrameElements.
  * Both header and attribute are parsed by FeaturePolicyParser which returns an
  * array of Feature objects. Each Feature object has a feature name and one of
  * these policies:
  * - eNone - the feature is fully disabled.
  * - eAll - the feature is allowed.
- * - eWhitelist - the feature is allowed for a list of origins.
+ * - eAllowList - the feature is allowed for a list of origins.
  *
  * An interesting element of FeaturePolicy is the inheritance: each context
  * inherits the feature-policy directives from the parent context, if it exists.
  * When a context inherits a policy for feature X, it only knows if that feature
- * is allowed or denied (it ignores the list of whitelist origins for instance).
+ * is allowed or denied (it ignores the list of allowed origins for instance).
  * This information is stored in an array of inherited feature strings because
  * we care only to know when they are denied.
  *
  * FeaturePolicy can be reset if the 'allow' or 'src' attributes change in
  * HTMLIFrameElements. 'src' attribute is important to compute correcly
  * the features via FeaturePolicy 'src' keyword.
  *
  * When FeaturePolicy must decide if feature X is allowed or denied for the
@@ -67,44 +67,41 @@ class FeaturePolicy final : public nsISu
   friend class FeaturePolicyUtils;
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FeaturePolicy)
 
   explicit FeaturePolicy(nsINode* aNode);
 
-  // A FeaturePolicy must have a default origin, if not in a sandboxed context.
+  // A FeaturePolicy must have a default origin.
   // This method must be called before any other exposed WebIDL method or before
   // checking if a feature is allowed.
   void
-  SetDefaultOrigin(const nsAString& aOrigin)
+  SetDefaultOrigin(nsIPrincipal* aPrincipal)
   {
-    // aOrigin can be an empty string if this is a opaque origin.
-    mDefaultOrigin = aOrigin;
+    mDefaultOrigin = aPrincipal;
   }
 
-  const nsAString& DefaultOrigin() const
+  nsIPrincipal* DefaultOrigin() const
   {
-    // Returns an empty string if this is an opaque origin.
     return mDefaultOrigin;
   }
 
   // Inherits the policy from the 'parent' context if it exists.
   void
   InheritPolicy(FeaturePolicy* aParentFeaturePolicy);
 
   // Sets the declarative part of the policy. This can be from the HTTP header
   // or for the 'allow' HTML attribute.
   void
   SetDeclaredPolicy(nsIDocument* aDocument,
                     const nsAString& aPolicyString,
-                    const nsAString& aSelfOrigin,
-                    const nsAString& aSrcOrigin,
-                    bool aSrcEnabled);
+                    nsIPrincipal* aSelfOrigin,
+                    nsIPrincipal* aSrcOrigin);
 
   // This method creates a policy for aFeatureName allowing it to '*' if it
   // doesn't exist yet. It's used by HTMLIFrameElement to enable features by
   // attributes.
   void
   MaybeSetAllowedPolicy(const nsAString& aFeatureName);
 
   // Clears all the declarative policy directives. This is needed when the
@@ -135,38 +132,42 @@ public:
 
   void
   GetAllowlistForFeature(const nsAString& aFeatureName,
                          nsTArray<nsString>& aList) const;
 
 private:
   ~FeaturePolicy() = default;
 
+  // This method returns true if the aFeatureName is allowed for aOrigin,
+  // following the feature-policy directives. See the comment at the top of this
+  // file.
   bool
   AllowsFeatureInternal(const nsAString& aFeatureName,
-                        const nsAString& aOrigin) const;
+                        nsIPrincipal* aOrigin) const;
 
   // Inherits a single denied feature from the parent context.
   void
   SetInheritedDeniedFeature(const nsAString& aFeatureName);
 
   bool
   HasInheritedDeniedFeature(const nsAString& aFeatureName) const;
 
+  // This returns true if we have a declared feature policy for aFeatureName.
   bool
   HasDeclaredFeature(const nsAString& aFeatureName) const;
 
   nsCOMPtr<nsINode> mParentNode;
 
   // This is set in sub-contexts when the parent blocks some feature for the
   // current context.
   nsTArray<nsString> mInheritedDeniedFeatureNames;
 
   // Feature policy for the current context.
   nsTArray<Feature> mFeatures;
 
-  nsString mDefaultOrigin;
+  nsCOMPtr<nsIPrincipal> mDefaultOrigin;
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_FeaturePolicy_h
--- a/dom/security/featurepolicy/FeaturePolicyParser.cpp
+++ b/dom/security/featurepolicy/FeaturePolicyParser.cpp
@@ -8,18 +8,18 @@
 
 #include "mozilla/dom/Feature.h"
 #include "mozilla/dom/FeaturePolicyUtils.h"
 #include "mozilla/dom/PolicyTokenizer.h"
 #include "nsIScriptError.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 
-using namespace mozilla;
-using namespace mozilla::dom;
+namespace mozilla {
+namespace dom {
 
 namespace {
 
 void
 ReportToConsoleUnsupportedFeature(nsIDocument* aDocument,
                                   const nsString& aFeatureName)
 {
   const char16_t* params[] = { aFeatureName.get() };
@@ -60,21 +60,22 @@ ReportToConsoleInvalidAllowValue(nsIDocu
                                   params, ArrayLength(params));
 }
 
 } // anonymous
 
 /* static */ bool
 FeaturePolicyParser::ParseString(const nsAString& aPolicy,
                                  nsIDocument* aDocument,
-                                 const nsAString& aSelfOrigin,
-                                 const nsAString& aSrcOrigin,
-                                 bool aSrcEnabled,
+                                 nsIPrincipal* aSelfOrigin,
+                                 nsIPrincipal* aSrcOrigin,
                                  nsTArray<Feature>& aParsedFeatures)
 {
+  MOZ_ASSERT(aSelfOrigin);
+
   nsTArray<nsTArray<nsString>> tokens;
   PolicyTokenizer::tokenizePolicy(aPolicy, tokens);
 
   nsTArray<Feature> parsedFeatures;
 
   for (const nsTArray<nsString>& featureTokens : tokens) {
     if (featureTokens.IsEmpty()) {
       continue;
@@ -83,19 +84,18 @@ FeaturePolicyParser::ParseString(const n
     if (!FeaturePolicyUtils::IsSupportedFeature(featureTokens[0])) {
       ReportToConsoleUnsupportedFeature(aDocument, featureTokens[0]);
       continue;
     }
 
     Feature feature(featureTokens[0]);
 
     if (featureTokens.Length() == 1) {
-      if (aSrcEnabled) {
-        // Note that this src origin can be empty if opaque.
-        feature.AppendOriginToWhiteList(aSrcOrigin);
+      if (aSrcOrigin) {
+        feature.AppendToAllowList(aSrcOrigin);
       } else {
         ReportToConsoleInvalidEmptyAllowValue(aDocument, featureTokens[0]);
         continue;
       }
     } else {
       // we gotta start at 1 here
       for (uint32_t i = 1; i < featureTokens.Length(); ++i) {
         const nsString& curVal = featureTokens[i];
@@ -105,46 +105,41 @@ FeaturePolicyParser::ParseString(const n
         }
 
         if (curVal.EqualsLiteral("*")) {
           feature.SetAllowsAll();
           break;
         }
 
         if (curVal.LowerCaseEqualsASCII("'self'")) {
-          // Opaque origins are passed as empty string.
-          if (!aSelfOrigin.IsEmpty()) {
-            feature.AppendOriginToWhiteList(aSelfOrigin);
-          }
+          feature.AppendToAllowList(aSelfOrigin);
           continue;
         }
 
-        if (aSrcEnabled && curVal.LowerCaseEqualsASCII("'src'")) {
-          // Opaque origins are passed as empty string.
-          if (!aSrcOrigin.IsEmpty()) {
-            feature.AppendOriginToWhiteList(aSrcOrigin);
-          }
+        if (aSrcOrigin && curVal.LowerCaseEqualsASCII("'src'")) {
+          feature.AppendToAllowList(aSrcOrigin);
           continue;
         }
 
         nsCOMPtr<nsIURI> uri;
         nsresult rv = NS_NewURI(getter_AddRefs(uri), curVal);
         if (NS_FAILED(rv)) {
           ReportToConsoleInvalidAllowValue(aDocument, curVal);
           continue;
         }
 
-        nsAutoString origin;
-        rv = nsContentUtils::GetUTFOrigin(uri, origin);
-        if (NS_WARN_IF(NS_FAILED(rv))) {
+        nsCOMPtr<nsIPrincipal> origin =
+          BasePrincipal::CreateCodebasePrincipal(uri,
+                                                 BasePrincipal::Cast(aSelfOrigin)->OriginAttributesRef());
+        if (NS_WARN_IF(!origin)) {
           ReportToConsoleInvalidAllowValue(aDocument, curVal);
           continue;
         }
 
-        feature.AppendOriginToWhiteList(origin);
+        feature.AppendToAllowList(origin);
       }
     }
 
     // No duplicate!
     bool found = false;
     for (const Feature& parsedFeature : parsedFeatures) {
       if (parsedFeature.Name() == feature.Name()) {
         found = true;
@@ -155,8 +150,11 @@ FeaturePolicyParser::ParseString(const n
     if (!found) {
       parsedFeatures.AppendElement(feature);
     }
   }
 
   aParsedFeatures.SwapElements(parsedFeatures);
   return true;
 }
+
+} // dom namespace
+} // mozilla namespace
--- a/dom/security/featurepolicy/FeaturePolicyParser.h
+++ b/dom/security/featurepolicy/FeaturePolicyParser.h
@@ -5,33 +5,32 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_FeaturePolicyParser_h
 #define mozilla_dom_FeaturePolicyParser_h
 
 #include "nsString.h"
 
 class nsIDocument;
-class nsIURI;
+class nsIPrincipal;
 
 namespace mozilla {
 namespace dom {
 
 class Feature;
 
 class FeaturePolicyParser final
 {
 public:
-  // aSelfOrigin must not be empty. if aSrcOrigin is empty, the parsing will not
+  // aSelfOrigin must not be null. if aSrcOrigin is null, the parsing will not
   // support 'src' as valid allow directive value.
   static bool
   ParseString(const nsAString& aPolicy,
               nsIDocument* aDocument,
-              const nsAString& aSelfOrigin,
-              const nsAString& aSrcOrigin,
-              bool aSrcEnabled,
+              nsIPrincipal* aSelfOrigin,
+              nsIPrincipal* aSrcOrigin,
               nsTArray<Feature>& aParsedFeatures);
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_FeaturePolicyParser_h
--- a/dom/security/featurepolicy/FeaturePolicyUtils.cpp
+++ b/dom/security/featurepolicy/FeaturePolicyUtils.cpp
@@ -4,43 +4,40 @@
  * 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 "FeaturePolicyUtils.h"
 #include "mozilla/dom/FeaturePolicy.h"
 #include "mozilla/StaticPrefs.h"
 #include "nsIDocument.h"
 
-using namespace mozilla::dom;
+namespace mozilla {
+namespace dom {
 
 struct FeatureMap {
   const char* mFeatureName;
-
-  enum {
-    eAll,
-    eSelf,
-  } mDefaultAllowList;
+  FeaturePolicyUtils::FeaturePolicyValue mDefaultAllowList;
 };
 
 /*
  * IMPORTANT: Do not change this list without review from a DOM peer _AND_ a
  * DOM Security peer!
  */
 static FeatureMap sSupportedFeatures[] = {
-  { "autoplay", FeatureMap::eAll },
-  { "camera", FeatureMap::eAll  },
-  { "encrypted-media", FeatureMap::eAll  },
-  { "fullscreen", FeatureMap::eAll  },
-  { "geolocation", FeatureMap::eAll  },
-  { "microphone", FeatureMap::eAll  },
-  { "midi", FeatureMap::eAll  },
-  { "payment", FeatureMap::eAll  },
+  { "autoplay", FeaturePolicyUtils::FeaturePolicyValue::eAll },
+  { "camera", FeaturePolicyUtils::FeaturePolicyValue::eAll  },
+  { "encrypted-media", FeaturePolicyUtils::FeaturePolicyValue::eAll  },
+  { "fullscreen", FeaturePolicyUtils::FeaturePolicyValue::eAll  },
+  { "geolocation", FeaturePolicyUtils::FeaturePolicyValue::eAll  },
+  { "microphone", FeaturePolicyUtils::FeaturePolicyValue::eAll  },
+  { "midi", FeaturePolicyUtils::FeaturePolicyValue::eAll  },
+  { "payment", FeaturePolicyUtils::FeaturePolicyValue::eAll  },
   // TODO: not supported yet!!!
-  { "speaker", FeatureMap::eAll  },
-  { "vr", FeatureMap::eAll  },
+  { "speaker", FeaturePolicyUtils::FeaturePolicyValue::eAll  },
+  { "vr", FeaturePolicyUtils::FeaturePolicyValue::eAll  },
 };
 
 /* static */ bool
 FeaturePolicyUtils::IsSupportedFeature(const nsAString& aFeatureName)
 {
   uint32_t numFeatures = (sizeof(sSupportedFeatures) / sizeof(sSupportedFeatures[0]));
   for (uint32_t i = 0; i < numFeatures; ++i) {
     if (aFeatureName.LowerCaseEqualsASCII(sSupportedFeatures[i].mFeatureName)) {
@@ -54,61 +51,27 @@ FeaturePolicyUtils::IsSupportedFeature(c
 FeaturePolicyUtils::ForEachFeature(const std::function<void(const char*)>& aCallback)
 {
   uint32_t numFeatures = (sizeof(sSupportedFeatures) / sizeof(sSupportedFeatures[0]));
   for (uint32_t i = 0; i < numFeatures; ++i) {
     aCallback(sSupportedFeatures[i].mFeatureName);
   }
 }
 
-/* static */ void
-FeaturePolicyUtils::DefaultAllowListFeature(const nsAString& aFeatureName,
-                                            const nsAString& aDefaultOrigin,
-                                            nsAString& aDefaultAllowList)
+/* static */ FeaturePolicyUtils::FeaturePolicyValue
+FeaturePolicyUtils::DefaultAllowListFeature(const nsAString& aFeatureName)
 {
   uint32_t numFeatures = (sizeof(sSupportedFeatures) / sizeof(sSupportedFeatures[0]));
   for (uint32_t i = 0; i < numFeatures; ++i) {
     if (aFeatureName.LowerCaseEqualsASCII(sSupportedFeatures[i].mFeatureName)) {
-      switch (sSupportedFeatures[i].mDefaultAllowList) {
-        case FeatureMap::eAll:
-          aDefaultAllowList.AppendASCII("*");
-          return;
-
-        case FeatureMap::eSelf:
-          aDefaultAllowList = aDefaultOrigin;
-          return;
-
-        default:
-          MOZ_CRASH("Unknown default value");
-      }
-    }
-  }
-}
-
-/* static */ bool
-FeaturePolicyUtils::AllowDefaultFeature(const nsAString& aFeatureName,
-                                        const nsAString& aDefaultOrigin,
-                                        const nsAString& aOrigin)
-{
-  uint32_t numFeatures = (sizeof(sSupportedFeatures) / sizeof(sSupportedFeatures[0]));
-  for (uint32_t i = 0; i < numFeatures; ++i) {
-    if (aFeatureName.LowerCaseEqualsASCII(sSupportedFeatures[i].mFeatureName)) {
-      switch (sSupportedFeatures[i].mDefaultAllowList) {
-        case FeatureMap::eAll:
-          return true;
-        case FeatureMap::eSelf:
-          return aDefaultOrigin == aOrigin;
-        default:
-          MOZ_CRASH("Unknown default value");
-      }
-      return true;
+      return sSupportedFeatures[i].mDefaultAllowList;
     }
   }
 
-  return false;
+  return FeaturePolicyValue::eNone;
 }
 
 /* static */ bool
 FeaturePolicyUtils::IsFeatureAllowed(nsIDocument* aDocument,
                                      const nsAString& aFeatureName)
 {
   MOZ_ASSERT(aDocument);
 
@@ -120,8 +83,11 @@ FeaturePolicyUtils::IsFeatureAllowed(nsI
     return true;
   }
 
   FeaturePolicy* policy = aDocument->Policy();
   MOZ_ASSERT(policy);
 
   return policy->AllowsFeatureInternal(aFeatureName, policy->DefaultOrigin());
 }
+
+} // dom namespace
+} // mozilla namespace
--- a/dom/security/featurepolicy/FeaturePolicyUtils.h
+++ b/dom/security/featurepolicy/FeaturePolicyUtils.h
@@ -13,33 +13,44 @@
 class nsIDocument;
 
 namespace mozilla {
 namespace dom {
 
 class FeaturePolicyUtils final
 {
 public:
+  enum FeaturePolicyValue
+  {
+    // Feature always allowed.
+    eAll,
+
+    // Feature allowed for documents that are same-origin with this one.
+    eSelf,
+
+    // Feature denied.
+    eNone,
+  };
+
+  // This method returns true if aFeatureName is allowed for aDocument.
+  // Use this method everywhere you need to check feature-policy directives.
   static bool
   IsFeatureAllowed(nsIDocument* aDocument,
                    const nsAString& aFeatureName);
 
+  // Returns true if aFeatureName is a known feature policy name.
   static bool
   IsSupportedFeature(const nsAString& aFeatureName);
 
+  // Runs aCallback for each known feature policy, with the feature name as
+  // argument.
   static void
   ForEachFeature(const std::function<void(const char*)>& aCallback);
 
-  static void
-  DefaultAllowListFeature(const nsAString& aFeatureName,
-                          const nsAString& aDefaultOrigin,
-                          nsAString& aDefaultAllowList);
-
-  static bool
-  AllowDefaultFeature(const nsAString& aFeatureName,
-                      const nsAString& aDefaultOrigin,
-                      const nsAString& aOrigin);
+  // Returns the default policy value for aFeatureName.
+  static FeaturePolicyValue
+  DefaultAllowListFeature(const nsAString& aFeatureName);
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_FeaturePolicyUtils_h
--- a/dom/security/featurepolicy/test/gtest/TestFeaturePolicyParser.cpp
+++ b/dom/security/featurepolicy/test/gtest/TestFeaturePolicyParser.cpp
@@ -1,124 +1,134 @@
 /* -*- 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 "gtest/gtest.h"
+#include "mozilla/BasePrincipal.h"
 #include "mozilla/dom/Feature.h"
 #include "mozilla/dom/FeaturePolicyParser.h"
 #include "nsNetUtil.h"
 #include "nsTArray.h"
 
+using namespace mozilla;
 using namespace mozilla::dom;
 
-#define URL_SELF NS_LITERAL_STRING("https://example.com")
-#define URL_EXAMPLE_COM NS_LITERAL_STRING("http://example.com")
-#define URL_EXAMPLE_NET NS_LITERAL_STRING("http://example.net")
+#define URL_SELF NS_LITERAL_CSTRING("https://example.com")
+#define URL_EXAMPLE_COM NS_LITERAL_CSTRING("http://example.com")
+#define URL_EXAMPLE_NET NS_LITERAL_CSTRING("http://example.net")
 
 void
 CheckParser(const nsAString& aInput, bool aExpectedResults,
             uint32_t aExpectedFeatures, nsTArray<Feature>& aParsedFeatures)
 {
+  nsCOMPtr<nsIPrincipal> principal =
+    mozilla::BasePrincipal::CreateCodebasePrincipal(URL_SELF);
   nsTArray<Feature> parsedFeatures;
   ASSERT_TRUE(FeaturePolicyParser::ParseString(aInput,
                                                nullptr,
-                                               URL_SELF,
-                                               EmptyString(),
-                                               true, // 'src' enabled
+                                               principal,
+                                               principal,
                                                parsedFeatures) == aExpectedResults);
   ASSERT_TRUE(parsedFeatures.Length() == aExpectedFeatures);
 
   parsedFeatures.SwapElements(aParsedFeatures);
 }
 
 TEST(FeaturePolicyParser, Basic)
 {
+  nsCOMPtr<nsIPrincipal> selfPrincipal =
+    mozilla::BasePrincipal::CreateCodebasePrincipal(URL_SELF);
+  nsCOMPtr<nsIPrincipal> exampleComPrincipal =
+    mozilla::BasePrincipal::CreateCodebasePrincipal(URL_EXAMPLE_COM);
+  nsCOMPtr<nsIPrincipal> exampleNetPrincipal =
+    mozilla::BasePrincipal::CreateCodebasePrincipal(URL_EXAMPLE_NET);
+
   nsTArray<Feature> parsedFeatures;
 
   // Empty string is a valid policy.
   CheckParser(EmptyString(), true, 0, parsedFeatures);
 
   // Empty string with spaces is still valid.
   CheckParser(NS_LITERAL_STRING("   "), true, 0, parsedFeatures);
 
   // Non-Existing features with no allowed values
   CheckParser(NS_LITERAL_STRING("non-existing-feature"), true, 0, parsedFeatures);
   CheckParser(NS_LITERAL_STRING("non-existing-feature;another-feature"), true,
               0, parsedFeatures);
 
   // Existing feature with no allowed values
   CheckParser(NS_LITERAL_STRING("camera"), true, 1, parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
-  ASSERT_TRUE(parsedFeatures[0].IsWhiteList());
+  ASSERT_TRUE(parsedFeatures[0].HasAllowList());
 
   // Some spaces.
   CheckParser(NS_LITERAL_STRING(" camera "), true, 1, parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
-  ASSERT_TRUE(parsedFeatures[0].IsWhiteList());
+  ASSERT_TRUE(parsedFeatures[0].HasAllowList());
 
   // A random ;
   CheckParser(NS_LITERAL_STRING("camera;"), true, 1, parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
-  ASSERT_TRUE(parsedFeatures[0].IsWhiteList());
+  ASSERT_TRUE(parsedFeatures[0].HasAllowList());
 
   // Another random ;
   CheckParser(NS_LITERAL_STRING(";camera;"), true, 1, parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
-  ASSERT_TRUE(parsedFeatures[0].IsWhiteList());
+  ASSERT_TRUE(parsedFeatures[0].HasAllowList());
 
   // 2 features
   CheckParser(NS_LITERAL_STRING("camera;microphone"), true, 2, parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
-  ASSERT_TRUE(parsedFeatures[0].IsWhiteList());
+  ASSERT_TRUE(parsedFeatures[0].HasAllowList());
   ASSERT_TRUE(parsedFeatures[1].Name().Equals(NS_LITERAL_STRING("microphone")));
-  ASSERT_TRUE(parsedFeatures[1].IsWhiteList());
+  ASSERT_TRUE(parsedFeatures[1].HasAllowList());
 
   // 2 features with spaces
   CheckParser(NS_LITERAL_STRING(" camera ; microphone "), true, 2,
               parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
-  ASSERT_TRUE(parsedFeatures[0].IsWhiteList());
+  ASSERT_TRUE(parsedFeatures[0].HasAllowList());
   ASSERT_TRUE(parsedFeatures[1].Name().Equals(NS_LITERAL_STRING("microphone")));
-  ASSERT_TRUE(parsedFeatures[1].IsWhiteList());
+  ASSERT_TRUE(parsedFeatures[1].HasAllowList());
 
   // 3 features, but only 2 exist.
   CheckParser(NS_LITERAL_STRING("camera;microphone;foobar"), true, 2,
               parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
-  ASSERT_TRUE(parsedFeatures[0].IsWhiteList());
+  ASSERT_TRUE(parsedFeatures[0].HasAllowList());
   ASSERT_TRUE(parsedFeatures[1].Name().Equals(NS_LITERAL_STRING("microphone")));
-  ASSERT_TRUE(parsedFeatures[1].IsWhiteList());
+  ASSERT_TRUE(parsedFeatures[1].HasAllowList());
 
   // Multiple spaces around the value
   CheckParser(NS_LITERAL_STRING("camera      'self'"), true, 1,
               parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
-  ASSERT_TRUE(parsedFeatures[0].WhiteListContains(URL_SELF));
+  ASSERT_TRUE(parsedFeatures[0].AllowListContains(selfPrincipal));
 
   // Multiple spaces around the value
   CheckParser(NS_LITERAL_STRING("camera      'self'    "), true, 1,
               parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
-  ASSERT_TRUE(parsedFeatures[0].WhiteListContains(URL_SELF));
+  ASSERT_TRUE(parsedFeatures[0].AllowListContains(selfPrincipal));
 
   // No final '
   CheckParser(NS_LITERAL_STRING("camera      'self"), true, 1,
               parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
-  ASSERT_TRUE(parsedFeatures[0].IsWhiteList());
-  ASSERT_TRUE(!parsedFeatures[0].WhiteListContains(URL_SELF));
+  ASSERT_TRUE(parsedFeatures[0].HasAllowList());
+  ASSERT_TRUE(!parsedFeatures[0].AllowListContains(selfPrincipal));
 
   // Lowercase/Uppercase
   CheckParser(NS_LITERAL_STRING("camera      'selF'"), true, 1,
               parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
-  ASSERT_TRUE(parsedFeatures[0].WhiteListContains(URL_SELF));
+  ASSERT_TRUE(parsedFeatures[0].AllowListContains(selfPrincipal));
 
   // Lowercase/Uppercase
   CheckParser(NS_LITERAL_STRING("camera * 'self' none' a.com 123"), true, 1,
               parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
   ASSERT_TRUE(parsedFeatures[0].AllowsAll());
 
   // After a 'none' we don't continue the parsing.
@@ -131,32 +141,32 @@ TEST(FeaturePolicyParser, Basic)
   CheckParser(NS_LITERAL_STRING("camera * a.com b.org c.net d.co.uk"), true, 1,
               parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
   ASSERT_TRUE(parsedFeatures[0].AllowsAll());
 
   // 'self'
   CheckParser(NS_LITERAL_STRING("camera 'self'"), true, 1, parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
-  ASSERT_TRUE(parsedFeatures[0].WhiteListContains(URL_SELF));
+  ASSERT_TRUE(parsedFeatures[0].AllowListContains(selfPrincipal));
 
   // A couple of URLs
   CheckParser(NS_LITERAL_STRING("camera http://example.com http://example.net"), true, 1,
               parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
-  ASSERT_TRUE(!parsedFeatures[0].WhiteListContains(URL_SELF));
-  ASSERT_TRUE(parsedFeatures[0].WhiteListContains(URL_EXAMPLE_COM));
-  ASSERT_TRUE(parsedFeatures[0].WhiteListContains(URL_EXAMPLE_NET));
+  ASSERT_TRUE(!parsedFeatures[0].AllowListContains(selfPrincipal));
+  ASSERT_TRUE(parsedFeatures[0].AllowListContains(exampleComPrincipal));
+  ASSERT_TRUE(parsedFeatures[0].AllowListContains(exampleNetPrincipal));
 
   // A couple of URLs + self
   CheckParser(NS_LITERAL_STRING("camera http://example.com 'self' http://example.net"), true, 1,
               parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
-  ASSERT_TRUE(parsedFeatures[0].WhiteListContains(URL_SELF));
-  ASSERT_TRUE(parsedFeatures[0].WhiteListContains(URL_EXAMPLE_COM));
-  ASSERT_TRUE(parsedFeatures[0].WhiteListContains(URL_EXAMPLE_NET));
+  ASSERT_TRUE(parsedFeatures[0].AllowListContains(selfPrincipal));
+  ASSERT_TRUE(parsedFeatures[0].AllowListContains(exampleComPrincipal));
+  ASSERT_TRUE(parsedFeatures[0].AllowListContains(exampleNetPrincipal));
 
   // A couple of URLs but then *
   CheckParser(NS_LITERAL_STRING("camera http://example.com 'self' http://example.net *"), true, 1,
               parsedFeatures);
   ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
   ASSERT_TRUE(parsedFeatures[0].AllowsAll());
 }
--- a/testing/web-platform/meta/feature-policy/feature-policy-frame-policy-allowed-for-self.https.sub.html.ini
+++ b/testing/web-platform/meta/feature-policy/feature-policy-frame-policy-allowed-for-self.https.sub.html.ini
@@ -26,9 +26,8 @@
   [Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8443 https://www.example.com" and header policy = "Feature-Policy: fullscreen 'none';".]
     expected: FAIL
 
   [Test frame policy on cross origin iframe with allow = "*" and allowfullscreen.]
     expected: FAIL
 
   [Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8443 https://www.example.com" and allowfullscreen.]
     expected: FAIL
-
--- a/testing/web-platform/tests/feature-policy/feature-policy-frame-policy-allowed-for-all.https.sub.html
+++ b/testing/web-platform/tests/feature-policy/feature-policy-frame-policy-allowed-for-all.https.sub.html
@@ -5,80 +5,141 @@
   <script src=/feature-policy/resources/featurepolicy.js></script>
   <!-- Feature-Policy: fullscreen *; -->
   <script>
   'use strict';
   var same_origin = 'https://{{domains[]}}:{{ports[https][0]}}';
   var cross_origin = 'https://{{domains[www]}}:{{ports[https][0]}}';
   var same_origin_src = '/feature-policy/resources/feature-policy-allowedfeatures.html';
   var cross_origin_src = cross_origin + same_origin_src;
+  var data_src = 'data:text/html,<h1>data: URL</h1>';
   var policies = [
-    {allow: "*", sameOriginTestExpect: true, crossOriginTestExpect: true},
-    {allow: "'self'", sameOriginTestExpect: true, crossOriginTestExpect: false},
-    {allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false},
-    {allow: "'self' " + cross_origin + " https://www.example.com", sameOriginTestExpect: true, crossOriginTestExpect: true}];
+    {allow: "*", sameOriginTestExpect: true, crossOriginTestExpect: true, dataOriginTestExpect: true},
+    {allow: "'self'", sameOriginTestExpect: true, crossOriginTestExpect: false, dataOriginTestExpect: false},
+    {allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false, dataOriginTestExpect: false},
+    {allow: "'self' " + cross_origin + " https://www.example.com", sameOriginTestExpect: true, crossOriginTestExpect: true, dataOriginTestExpect: false}];
   var pipe_front = '?pipe=sub|header(Feature-Policy,fullscreen ';
   var pipe_end = ';)';
   var header_policies = ["*", "'self'", "'none'"];
 
   // Test that frame.policy inherits from parent's header policy when allow
   // attribute is not specified.
   test(function() {
-    test_frame_policy('fullscreen', same_origin_src, true);
+    test_frame_policy('fullscreen', same_origin_src, undefined, true);
   }, 'Test frame policy on same origin iframe inherit from header policy.');
   test(function() {
-    test_frame_policy('fullscreen', cross_origin_src, true);
+    test_frame_policy('fullscreen', cross_origin_src, undefined, true);
   }, 'Test frame policy on cross origin iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', undefined, true, true);
+  }, 'Test frame policy on srcdoc iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', same_origin_src, true, true);
+  }, 'Test frame policy on srcdoc+ same origin iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', cross_origin_src, true, true);
+  }, 'Test frame policy on srcdoc+ cross origin iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', data_src, undefined, true);
+  }, 'Test frame policy on data: URL cross origin iframe inherit from header policy.');
 
   // Test frame policy with allow attribute set to be one of the policies above.
   for (var i = 0; i < policies.length; i++) {
     test(function() {
       test_frame_policy(
-        'fullscreen', same_origin_src, policies[i].sameOriginTestExpect,
+        'fullscreen', same_origin_src, undefined,
+        policies[i].sameOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';');
     }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + '".');
     test(function() {
       test_frame_policy(
-        'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect,
+        'fullscreen', cross_origin_src, undefined,
+        policies[i].crossOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';');
     }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', undefined, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on srcdoc iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', same_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on srcdoc + same origin iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', cross_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on srcdoc + cross origin iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', data_src, undefined, policies[i].dataOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on data: URL cross origin iframe with allow = "' + policies[i].allow + '".');
   }
 
   // Test that the header policy of the iframe document does not change the
   // frame policy.
   for (var i = 0; i < policies.length; i++) {
     for (var j = 0; j < header_policies.length; j++) {
       test(function() {
         test_frame_policy(
           'fullscreen',
           same_origin_src + pipe_front + header_policies[j] + pipe_end,
-          policies[i].sameOriginTestExpect,
+          undefined, policies[i].sameOriginTestExpect,
           'fullscreen ' + policies[i].allow + ';');
       }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
          '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
       test(function() {
         test_frame_policy(
           'fullscreen',
           cross_origin_src + pipe_front + header_policies[j] + pipe_end,
-          policies[i].crossOriginTestExpect,
+          undefined, policies[i].crossOriginTestExpect,
           'fullscreen ' + policies[i].allow + ';');
       }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
          '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
     }
   }
 
   // Test that the allow attribute overrides allowfullscreen.
   for (var i = 0; i < policies.length; i++) {
     test(function() {
       test_frame_policy(
-        'fullscreen', same_origin_src, policies[i].sameOriginTestExpect,
+        'fullscreen', same_origin_src, undefined,
+        policies[i].sameOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
     }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
        '" and allowfullscreen.');
     test(function() {
       test_frame_policy(
-        'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect,
+        'fullscreen', cross_origin_src, undefined,
+        policies[i].crossOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
     }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
        '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', undefined, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on srcdoc iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', same_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on srcdoc + same origin iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', cross_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on srcdoc + cross origin iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', data_src, undefined, policies[i].dataOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on data: URL cross origin iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
   }
   </script>
 </body>
--- a/testing/web-platform/tests/feature-policy/feature-policy-frame-policy-allowed-for-self.https.sub.html
+++ b/testing/web-platform/tests/feature-policy/feature-policy-frame-policy-allowed-for-self.https.sub.html
@@ -5,98 +5,175 @@
   <script src=/feature-policy/resources/featurepolicy.js></script>
   <!-- Feature-Policy: fullscreen 'self'; -->
   <script>
   'use strict';
   var same_origin = 'https://{{domains[]}}:{{ports[https][0]}}';
   var cross_origin = 'https://{{domains[www]}}:{{ports[https][0]}}';
   var same_origin_src = '/feature-policy/resources/feature-policy-allowedfeatures.html';
   var cross_origin_src = cross_origin + same_origin_src;
+  var data_src = 'data:text/html,<h1>data: URL</h1>';
   var policies = [
-    {allow: "*", sameOriginTestExpect: true, crossOriginTestExpect: true},
-    {allow: "'self'", sameOriginTestExpect: true, crossOriginTestExpect: false},
-    {allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false},
-    {allow: "'self' " + cross_origin + " https://www.example.com", sameOriginTestExpect: true, crossOriginTestExpect: true}];
+    {allow: "*", sameOriginTestExpect: true, crossOriginTestExpect: true, dataOriginTestExpect: false},
+    {allow: "'self'", sameOriginTestExpect: true, crossOriginTestExpect: false, dataOriginTestExpect: false},
+    {allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false, dataOriginTestExpect: false},
+    {allow: "'self' " + cross_origin + " https://www.example.com", sameOriginTestExpect: true, crossOriginTestExpect: true, dataOriginTestExpect: false}];
   var pipe_front = '?pipe=sub|header(Feature-Policy,fullscreen ';
   var pipe_end = ';)';
   var header_policies = ["*", "'self'", "'none'"];
 
   // Test that frame.policy inherits from parent's header policy when allow
   // attribute is not specified.
   test(function() {
-    test_frame_policy('fullscreen', same_origin_src, true);
+    test_frame_policy('fullscreen', same_origin_src, undefined, true);
   }, 'Test frame policy on same origin iframe inherit from header policy.');
   test(function() {
-    test_frame_policy('fullscreen', cross_origin_src, false);
+    test_frame_policy('fullscreen', cross_origin_src, undefined, false);
   }, 'Test frame policy on cross origin iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', undefined, true, true);
+  }, 'Test frame policy on srcdoc iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', same_origin_src, true, true);
+  }, 'Test frame policy on srcdoc + same origin iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', cross_origin_src, true, true);
+  }, 'Test frame policy on srcdoc + cross origin iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', data_src, undefined, false);
+  }, 'Test frame policy on data: URL cross origin iframe inherit from header policy.');
 
   // Test that frame policy can be used for sandboxed frames
   test(function() {
     test_frame_policy(
-      'fullscreen', same_origin_src, false, undefined, false, true);
+      'fullscreen', same_origin_src, undefined, false, undefined, false, true);
     }, 'Test frame policy on sandboxed iframe with no allow attribute.');
   test(function() {
     test_frame_policy(
-      'fullscreen', same_origin_src, true, 'fullscreen', false, true);
+      'fullscreen', same_origin_src, undefined, true, 'fullscreen', false, true);
     }, 'Test frame policy on sandboxed iframe with allow="fullscreen".');
   test(function() {
     test_frame_policy(
-      'fullscreen', same_origin_src, true, 'fullscreen \'src\'', false, true);
+      'fullscreen', same_origin_src, undefined, true, 'fullscreen \'src\'', false, true);
     }, 'Test frame policy on sandboxed iframe with allow="fullscreen \'src\'".');
   test(function() {
     test_frame_policy(
-      'fullscreen', cross_origin_src, false, 'fullscreen ' + cross_origin, false, true);
+      'fullscreen', cross_origin_src, undefined, false, 'fullscreen ' + cross_origin, false, true);
     }, 'Test frame policy on sandboxed iframe with allow="fullscreen ' + cross_origin + '".');
+  test(function() {
+    test_frame_policy(
+      'fullscreen', undefined, true, true, 'fullscreen', false, true);
+    }, 'Test frame policy on srcdoc sandboxed iframe with allow="fullscreen".');
+  test(function() {
+    test_frame_policy(
+      'fullscreen', same_origin_src, true, true, 'fullscreen', false, true);
+    }, 'Test frame policy on srcdoc + same origin sandboxed iframe with allow="fullscreen".');
+  test(function() {
+    test_frame_policy(
+      'fullscreen', cross_origin_src, true, true, 'fullscreen', false, true);
+    }, 'Test frame policy on srcdoc + cross origin sandboxed iframe with allow="fullscreen".');
+  test(function() {
+    test_frame_policy(
+      'fullscreen', data_src, undefined, false, 'fullscreen ' + cross_origin, false, true);
+    }, 'Test frame policy on sandboxed srcdoc iframe with allow="fullscreen ' + cross_origin + '".');
 
   // Test frame policy with allow attribute set to be one of the policies above.
   for (var i = 0; i < policies.length; i++) {
     test(function() {
       test_frame_policy(
-        'fullscreen', same_origin_src, policies[i].sameOriginTestExpect,
+        'fullscreen', same_origin_src, undefined,
+        policies[i].sameOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';');
     }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + '".');
     test(function() {
       test_frame_policy(
-        'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect,
+        'fullscreen', cross_origin_src, undefined,
+        policies[i].crossOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';');
     }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', undefined, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on srcdoc iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', same_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on srcdoc + same origin iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', cross_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on srcdoc + cross origin iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', data_src, undefined, policies[i].dataOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on data: URL origin iframe with allow = "' + policies[i].allow + '".');
   }
 
   // Test that the header policy of the iframe document does not change the
   // frame policy.
   for (var i = 0; i < policies.length; i++) {
     for (var j = 0; j < header_policies.length; j++) {
       test(function() {
         test_frame_policy(
           'fullscreen',
           same_origin_src + pipe_front + header_policies[j] + pipe_end,
-          policies[i].sameOriginTestExpect,
+          undefined, policies[i].sameOriginTestExpect,
           'fullscreen ' + policies[i].allow + ';');
       }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
          '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
       test(function() {
         test_frame_policy(
           'fullscreen',
           cross_origin_src + pipe_front + header_policies[j] + pipe_end,
-          policies[i].crossOriginTestExpect,
+          undefined, policies[i].crossOriginTestExpect,
           'fullscreen ' + policies[i].allow + ';');
       }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
          '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
     }
   }
 
   // Test that the allow attribute overrides allowfullscreen.
   for (var i = 0; i < policies.length; i++) {
     test(function() {
       test_frame_policy(
-        'fullscreen', same_origin_src, policies[i].sameOriginTestExpect,
+        'fullscreen', same_origin_src, undefined,
+        policies[i].sameOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
     }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
        '" and allowfullscreen.');
     test(function() {
       test_frame_policy(
-        'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect,
+        'fullscreen', cross_origin_src, undefined,
+        policies[i].crossOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
     }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
        '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', undefined, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on srcdoc iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', same_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on srcdoc + same origin iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', cross_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on srcdoc + cross origin iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', data_src, undefined, policies[i].dataOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on data: URL origin iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
   }
   </script>
 </body>
--- a/testing/web-platform/tests/feature-policy/feature-policy-frame-policy-allowed-for-some.https.sub.html
+++ b/testing/web-platform/tests/feature-policy/feature-policy-frame-policy-allowed-for-some.https.sub.html
@@ -7,103 +7,180 @@
   <script>
   'use strict';
   var same_origin = 'https://{{domains[]}}:{{ports[https][0]}}';
   var cross_origin = 'https://{{domains[www]}}:{{ports[https][0]}}';
   var cross_origin1 = 'https://{{domains[www1]}}:{{ports[https][0]}}';
   var same_origin_src = '/feature-policy/resources/feature-policy-allowedfeatures.html';
   var cross_origin_src = cross_origin + same_origin_src;
   var cross_origin_src1 = cross_origin1 + same_origin_src;
+  var data_src = 'data:text/html,<h1>data: URL</h1>';
   // Test feature policy with same_origin_src and cross_origin_src.
   var policies = [
-    {allow: "*", sameOriginTestExpect: true, crossOriginTestExpect: true, crossOrigin1TestExpect: true},
-    {allow: "'self'", sameOriginTestExpect: true, crossOriginTestExpect: false, crossOrigin1TestExpect: false},
-    {allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false, crossOrigin1TestExpect: false},
-    {allow: "'self' " + cross_origin + " https://www.example.com", sameOriginTestExpect: true, crossOriginTestExpect: true, crossOrigin1TestExpect: false}];
+    {allow: "*", sameOriginTestExpect: true, crossOriginTestExpect: true, crossOrigin1TestExpect: true, dataOriginTestExpect: false},
+    {allow: "'self'", sameOriginTestExpect: true, crossOriginTestExpect: false, crossOrigin1TestExpect: false, dataOriginTestExpect: false},
+    {allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false, crossOrigin1TestExpect: false, dataOriginTestExpect: false},
+    {allow: "'self' " + cross_origin + " https://www.example.com", sameOriginTestExpect: true, crossOriginTestExpect: true, crossOrigin1TestExpect: false, dataOriginTestExpect: false}];
   var pipe_front = '?pipe=sub|header(Feature-Policy,fullscreen ';
   var pipe_end = ';)';
   var header_policies = ["*", "'self'", "'none'"];
 
   // Test that frame.policy inherits from parent's header policy when allow
   // attribute is not specified.
   test(function() {
-    test_frame_policy('fullscreen', same_origin_src, true);
+    test_frame_policy('fullscreen', same_origin_src, undefined, true);
   }, 'Test frame policy on same origin iframe inherit from header policy.');
   test(function() {
-    test_frame_policy('fullscreen', cross_origin_src, true);
+    test_frame_policy('fullscreen', cross_origin_src, undefined, true);
   }, 'Test frame policy on cross origin iframe inherit from header policy.');
   test(function() {
-    test_frame_policy('fullscreen', cross_origin_src1, false);
+    test_frame_policy('fullscreen', cross_origin_src1, undefined, false);
   }, 'Test frame policy on another cross origin iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', undefined, true, true);
+  }, 'Test frame policy on srcdoc iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', same_origin_src, true, true);
+  }, 'Test frame policy on srcdoc + same origin iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', cross_origin_src, true, true);
+  }, 'Test frame policy on srcdoc + cross origin iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', cross_origin_src1, true, true);
+  }, 'Test frame policy on srcdoc + another cross origin iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', data_src, undefined, false);
+  }, 'Test frame policy on data: URL cross origin iframe inherit from header policy.');
 
   // Test frame policy with allow attribute set to be one of the policies above.
   for (var i = 0; i < policies.length; i++) {
     test(function() {
       test_frame_policy(
-        'fullscreen', same_origin_src, policies[i].sameOriginTestExpect,
+        'fullscreen', same_origin_src, undefined,
+        policies[i].sameOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';');
     }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + '".');
     test(function() {
       test_frame_policy(
-        'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect,
+        'fullscreen', cross_origin_src, undefined,
+        policies[i].crossOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';');
     }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow + '".');
     test(function() {
       test_frame_policy(
-        'fullscreen', cross_origin_src1, policies[i].crossOrigin1TestExpect,
+        'fullscreen', cross_origin_src1, undefined,
+        policies[i].crossOrigin1TestExpect,
         'fullscreen ' + policies[i].allow + ';');
     }, 'Test frame policy on another cross origin iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', undefined, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on srcdoc iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', same_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on srcdoc + same origin iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', cross_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on srcdoc + cross origin iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', cross_origin_src1, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on srcdoc + another cross origin iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', data_src, undefined, policies[i].dataOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on data: URL cross origin iframe with allow = "' + policies[i].allow + '".');
   }
 
   // Test that the header policy of the iframe document does not change the
   // frame policy.
   for (var i = 0; i < policies.length; i++) {
     for (var j = 0; j < header_policies.length; j++) {
       test(function() {
         test_frame_policy(
           'fullscreen',
           same_origin_src + pipe_front + header_policies[j] + pipe_end,
-          policies[i].sameOriginTestExpect,
+          undefined, policies[i].sameOriginTestExpect,
           'fullscreen ' + policies[i].allow + ';');
       }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
          '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
       test(function() {
         test_frame_policy(
           'fullscreen',
           cross_origin_src + pipe_front + header_policies[j] + pipe_end,
-          policies[i].crossOriginTestExpect,
+          undefined, policies[i].crossOriginTestExpect,
           'fullscreen ' + policies[i].allow + ';');
       }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
          '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
       test(function() {
         test_frame_policy(
           'fullscreen',
           cross_origin_src1 + pipe_front + header_policies[j] + pipe_end,
-          policies[i].crossOrigin1TestExpect,
+          undefined, policies[i].crossOrigin1TestExpect,
           'fullscreen ' + policies[i].allow + ';');
       }, 'Test frame policy on another cross origin iframe with allow = "' + policies[i].allow +
          '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
     }
   }
 
   // Test that the allow attribute overrides allowfullscreen.
   for (var i = 0; i < policies.length; i++) {
     test(function() {
       test_frame_policy(
-        'fullscreen', same_origin_src, policies[i].sameOriginTestExpect,
+        'fullscreen', same_origin_src, undefined,
+        policies[i].sameOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
     }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
        '" and allowfullscreen.');
     test(function() {
       test_frame_policy(
-        'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect,
+        'fullscreen', cross_origin_src, undefined,
+        policies[i].crossOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
     }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
        '" and allowfullscreen.');
     test(function() {
       test_frame_policy(
-        'fullscreen', cross_origin_src1, policies[i].crossOrigin1TestExpect,
+        'fullscreen', cross_origin_src1, undefined,
+        policies[i].crossOrigin1TestExpect,
         'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
     }, 'Test frame policy on another cross origin iframe with allow = "' + policies[i].allow +
        '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', undefined, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on srcdoc iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', same_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on srcdoc + same origin iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', cross_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on srcdoc + cross origin iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', cross_origin_src1, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on srcdoc + another cross origin iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', data_src, undefined, policies[i].dataOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on data: URL cross origin iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
   }
   </script>
 </body>
--- a/testing/web-platform/tests/feature-policy/feature-policy-frame-policy-disallowed-for-all.https.sub.html
+++ b/testing/web-platform/tests/feature-policy/feature-policy-frame-policy-disallowed-for-all.https.sub.html
@@ -5,80 +5,141 @@
   <script src=/feature-policy/resources/featurepolicy.js></script>
   <!-- Feature-Policy: fullscreen 'none'; -->
   <script>
   'use strict';
   var same_origin = 'https://{{domains[]}}:{{ports[https][0]}}';
   var cross_origin = 'https://{{domains[www]}}:{{ports[https][0]}}';
   var same_origin_src = '/feature-policy/resources/feature-policy-allowedfeatures.html';
   var cross_origin_src = cross_origin + same_origin_src;
+  var data_src = 'data:text/html,<h1>data: URL</h1>';
   var policies = [
-    {allow: "*", sameOriginTestExpect: false, crossOriginTestExpect: false},
-    {allow: "'self'", sameOriginTestExpect: false, crossOriginTestExpect: false},
-    {allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false},
-    {allow: "'self' " + cross_origin + " https://www.example.com", sameOriginTestExpect: false, crossOriginTestExpect: false}];
+    {allow: "*", sameOriginTestExpect: false, crossOriginTestExpect: false, dataOriginTestExpect: false},
+    {allow: "'self'", sameOriginTestExpect: false, crossOriginTestExpect: false, dataOriginTestExpect: false},
+    {allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false, dataOriginTestExpect: false},
+    {allow: "'self' " + cross_origin + " https://www.example.com", sameOriginTestExpect: false, crossOriginTestExpect: false, dataOriginTestExpect: false}];
   var pipe_front = '?pipe=sub|header(Feature-Policy,fullscreen ';
   var pipe_end = ';)';
   var header_policies = ["*", "'self'", "'none'"];
 
   // Test that frame.policy inherits from parent's header policy when allow
   // attribute is not specified.
   test(function() {
-    test_frame_policy('fullscreen', same_origin_src, false);
+    test_frame_policy('fullscreen', same_origin_src, undefined, false);
   }, 'Test frame policy on same origin iframe inherit from header policy.');
   test(function() {
-    test_frame_policy('fullscreen', cross_origin_src, false);
+    test_frame_policy('fullscreen', cross_origin_src, undefined, false);
   }, 'Test frame policy on cross origin iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', undefined, true, false);
+  }, 'Test frame policy on srcdoc iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', same_origin_src, true, false);
+  }, 'Test frame policy on srcdoc + same origin iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', cross_origin_src, true, false);
+  }, 'Test frame policy on srcdoc + cross origin iframe inherit from header policy.');
+  test(function() {
+    test_frame_policy('fullscreen', data_src, undefined, false);
+  }, 'Test frame policy on data: URL cross origin iframe inherit from header policy.');
 
   // Test frame policy with allow attribute set to be one of the policies above.
   for (var i = 0; i < policies.length; i++) {
     test(function() {
       test_frame_policy(
-        'fullscreen', same_origin_src, policies[i].sameOriginTestExpect,
+        'fullscreen', same_origin_src, undefined,
+        policies[i].sameOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';');
     }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + '".');
     test(function() {
       test_frame_policy(
-        'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect,
+        'fullscreen', cross_origin_src, undefined,
+        policies[i].crossOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';');
     }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', undefined, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on srcdoc iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', same_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on srcdoc + same origin iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', cross_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on srcdoc + cross origin iframe with allow = "' + policies[i].allow + '".');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', data_src, undefined, policies[i].dataOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';');
+    }, 'Test frame policy on data: URL cross origin iframe with allow = "' + policies[i].allow + '".');
   }
 
   // Test that the header policy of the iframe document does not change the
   // frame policy.
   for (var i = 0; i < policies.length; i++) {
     for (var j = 0; j < header_policies.length; j++) {
       test(function() {
         test_frame_policy(
           'fullscreen',
           same_origin_src + pipe_front + header_policies[j] + pipe_end,
-          policies[i].sameOriginTestExpect,
+          undefined, policies[i].sameOriginTestExpect,
           'fullscreen ' + policies[i].allow + ';');
       }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
          '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
       test(function() {
         test_frame_policy(
           'fullscreen',
           cross_origin_src + pipe_front + header_policies[j] + pipe_end,
-          policies[i].crossOriginTestExpect,
+          undefined, policies[i].crossOriginTestExpect,
           'fullscreen ' + policies[i].allow + ';');
       }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
          '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
     }
   }
 
   // Test that the allow attribute overrides allowfullscreen.
   for (var i = 0; i < policies.length; i++) {
     test(function() {
       test_frame_policy(
-        'fullscreen', same_origin_src, policies[i].sameOriginTestExpect,
+        'fullscreen', same_origin_src, undefined,
+        policies[i].sameOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
     }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
        '" and allowfullscreen.');
     test(function() {
       test_frame_policy(
-        'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect,
+        'fullscreen', cross_origin_src, undefined,
+        policies[i].crossOriginTestExpect,
         'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
     }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
        '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', undefined, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on srcdoc iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', same_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on srcdoc + same origin iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', cross_origin_src, true, policies[i].sameOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on srcdoc + cross origin iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
+    test(function() {
+      test_frame_policy(
+        'fullscreen', data_src, undefined, policies[i].dataOriginTestExpect,
+        'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
+    }, 'Test frame policy on data: URL cross origin iframe with allow = "' + policies[i].allow +
+       '" and allowfullscreen.');
   }
   </script>
 </body>
--- a/testing/web-platform/tests/feature-policy/resources/featurepolicy.js
+++ b/testing/web-platform/tests/feature-policy/resources/featurepolicy.js
@@ -391,37 +391,43 @@ function test_subframe_header_policy(
   }, test_name);
 }
 
 // This function tests that frame policy allows a given feature correctly. A
 // feature is allowed in a frame either through inherited policy or specified
 // by iframe allow attribute.
 // Arguments:
 //     feature: feature name.
-//     src: the URL to load in the frame.
+//     src: the URL to load in the frame. If undefined, the iframe will have a
+//         srcdoc="" attribute
 //     test_expect: boolean value of whether the feature should be allowed.
 //     allow: optional, the allow attribute (container policy) of the iframe.
 //     allowfullscreen: optional, boolean value of allowfullscreen attribute.
 //     sandbox: optional boolean. If true, the frame will be sandboxed (with
 //         allow-scripts, so that tests can run in it.)
 function test_frame_policy(
-    feature, src, test_expect, allow, allowfullscreen, sandbox) {
+    feature, src, srcdoc, test_expect, allow, allowfullscreen, sandbox) {
   let frame = document.createElement('iframe');
   document.body.appendChild(frame);
   // frame_policy should be dynamically updated as allow and allowfullscreen is
   // updated.
   var frame_policy = frame.policy;
   if (typeof allow !== 'undefined') {
     frame.setAttribute('allow', allow);
   }
   if (!!allowfullscreen) {
     frame.setAttribute('allowfullscreen', true);
   }
   if (!!sandbox) {
     frame.setAttribute('sandbox', 'allow-scripts');
   }
-  frame.src = src;
+  if (!!src) {
+    frame.src = src;
+  }
+  if (!!srcdoc) {
+    frame.srcdoc = "<h1>Hello world!</h1>";
+  }
   if (test_expect) {
     assert_true(frame_policy.allowedFeatures().includes(feature));
   } else {
     assert_false(frame_policy.allowedFeatures().includes(feature));
   }
 }