Bug 1496034 - Apply bz's comments to FeaturePolicy, r=bz

This commit is contained in:
Andrea Marchesini
2018-10-12 09:36:33 +02:00
parent f8add49a23
commit b51e9d489e
20 changed files with 640 additions and 306 deletions

View File

@@ -3024,27 +3024,19 @@ nsIDocument::InitFeaturePolicy(nsIChannel* aChannel)
return NS_OK; return NS_OK;
} }
nsAutoString origin; mFeaturePolicy->SetDefaultOrigin(NodePrincipal());
nsresult rv = nsContentUtils::GetUTFOrigin(NodePrincipal(), origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mFeaturePolicy->SetDefaultOrigin(origin);
RefPtr<FeaturePolicy> parentPolicy = nullptr; RefPtr<FeaturePolicy> parentPolicy = nullptr;
if (mDocumentContainer) { if (mDocumentContainer) {
nsPIDOMWindowOuter* containerWindow = mDocumentContainer->GetWindow(); nsPIDOMWindowOuter* containerWindow = mDocumentContainer->GetWindow();
if (containerWindow) { if (containerWindow) {
nsCOMPtr<nsINode> node = containerWindow->GetFrameElementInternal(); nsCOMPtr<nsINode> node = containerWindow->GetFrameElementInternal();
if (node) { HTMLIFrameElement* iframe = HTMLIFrameElement::FromNodeOrNull(node);
HTMLIFrameElement* iframe = HTMLIFrameElement::FromNode(node);
if (iframe) { if (iframe) {
parentPolicy = iframe->Policy(); parentPolicy = iframe->Policy();
} }
} }
} }
}
if (parentPolicy) { if (parentPolicy) {
// Let's inherit the policy from the parent HTMLIFrameElement if it exists. // Let's inherit the policy from the parent HTMLIFrameElement if it exists.
@@ -3052,7 +3044,7 @@ nsIDocument::InitFeaturePolicy(nsIChannel* aChannel)
} }
nsCOMPtr<nsIHttpChannel> httpChannel; nsCOMPtr<nsIHttpChannel> httpChannel;
rv = GetHttpChannelHelper(aChannel, getter_AddRefs(httpChannel)); nsresult rv = GetHttpChannelHelper(aChannel, getter_AddRefs(httpChannel));
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return rv; return rv;
} }
@@ -3067,8 +3059,7 @@ nsIDocument::InitFeaturePolicy(nsIChannel* aChannel)
value); value);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
mFeaturePolicy->SetDeclaredPolicy(this, NS_ConvertUTF8toUTF16(value), mFeaturePolicy->SetDeclaredPolicy(this, NS_ConvertUTF8toUTF16(value),
origin, EmptyString(), NodePrincipal(), nullptr);
false /* 'src' enabled */);
} }
return NS_OK; return NS_OK;
@@ -10231,7 +10222,8 @@ nsIDocument::Policy() const
MOZ_ASSERT(StaticPrefs::dom_security_featurePolicy_enabled()); MOZ_ASSERT(StaticPrefs::dom_security_featurePolicy_enabled());
// The policy is created when the document is initialized. We _must_ have a // 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); MOZ_ASSERT(mFeaturePolicy);
return mFeaturePolicy; return mFeaturePolicy;
} }

View File

@@ -8,6 +8,7 @@
#include "mozilla/dom/HTMLIFrameElementBinding.h" #include "mozilla/dom/HTMLIFrameElementBinding.h"
#include "mozilla/dom/FeaturePolicy.h" #include "mozilla/dom/FeaturePolicy.h"
#include "mozilla/MappedDeclarations.h" #include "mozilla/MappedDeclarations.h"
#include "mozilla/NullPrincipal.h"
#include "mozilla/StaticPrefs.h" #include "mozilla/StaticPrefs.h"
#include "nsMappedAttributes.h" #include "nsMappedAttributes.h"
#include "nsAttrValueInlines.h" #include "nsAttrValueInlines.h"
@@ -22,6 +23,24 @@ NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(IFrame)
namespace mozilla { namespace mozilla {
namespace dom { 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 // static
const DOMTokenListSupportedToken HTMLIFrameElement::sSupportedSandboxTokens[] = { const DOMTokenListSupportedToken HTMLIFrameElement::sSupportedSandboxTokens[] = {
#define SANDBOX_KEYWORD(string, atom, flags) string, #define SANDBOX_KEYWORD(string, atom, flags) string,
@@ -34,10 +53,9 @@ HTMLIFrameElement::HTMLIFrameElement(already_AddRefed<mozilla::dom::NodeInfo>&&
FromParser aFromParser) FromParser aFromParser)
: nsGenericHTMLFrameElement(std::move(aNodeInfo), aFromParser) : nsGenericHTMLFrameElement(std::move(aNodeInfo), aFromParser)
{ {
if (StaticPrefs::dom_security_featurePolicy_enabled()) { // We always need a featurePolicy, even if not exposed.
mFeaturePolicy = new FeaturePolicy(this); mFeaturePolicy = new FeaturePolicy(this);
} }
}
HTMLIFrameElement::~HTMLIFrameElement() HTMLIFrameElement::~HTMLIFrameElement()
{ {
@@ -174,6 +192,7 @@ HTMLIFrameElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
} }
if ((aName == nsGkAtoms::allow || if ((aName == nsGkAtoms::allow ||
aName == nsGkAtoms::src || aName == nsGkAtoms::src ||
aName == nsGkAtoms::srcdoc ||
aName == nsGkAtoms::sandbox || aName == nsGkAtoms::sandbox ||
aName == nsGkAtoms::allowpaymentrequest) && aName == nsGkAtoms::allowpaymentrequest) &&
StaticPrefs::dom_security_featurePolicy_enabled()) { StaticPrefs::dom_security_featurePolicy_enabled()) {
@@ -236,41 +255,29 @@ HTMLIFrameElement::Policy() const
} }
nsresult nsresult
HTMLIFrameElement::GetFeaturePolicyDefaultOrigin(nsAString& aDefaultOrigin) const HTMLIFrameElement::GetFeaturePolicyDefaultOrigin(nsIPrincipal** aPrincipal) const
{ {
aDefaultOrigin.Truncate(); nsCOMPtr<nsIPrincipal> principal;
nsresult rv; if (HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc)) {
nsAutoString src; principal = NodePrincipal();
GetURIAttr(nsGkAtoms::src, nullptr, src); }
if (!principal) {
nsCOMPtr<nsIURI> nodeURI; nsCOMPtr<nsIURI> nodeURI;
if (!src.IsEmpty()) { if (GetURIAttr(nsGkAtoms::src, nullptr, getter_AddRefs(nodeURI)) &&
nsCOMPtr<nsIURI> baseURI = OwnerDoc()->GetBaseURI(); nodeURI) {
principal =
rv = NS_NewURI(getter_AddRefs(nodeURI), src, BasePrincipal::CreateCodebasePrincipal(nodeURI,
OwnerDoc()->GetDocumentCharacterSet(), BasePrincipal::Cast(NodePrincipal())->OriginAttributesRef());
baseURI);
if (NS_WARN_IF(NS_FAILED(rv))) {
nodeURI = nullptr;
} }
} }
if (!nodeURI) { if (!principal) {
if (OwnerDoc()->GetSandboxFlags() & SANDBOXED_ORIGIN) { principal = NodePrincipal();
return NS_OK;
} }
nodeURI = OwnerDoc()->GetDocumentURI(); principal.forget(aPrincipal);
}
nsAutoString origin;
rv = nsContentUtils::GetUTFOrigin(nodeURI, origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
aDefaultOrigin.Assign(origin);
return NS_OK; return NS_OK;
} }
@@ -281,29 +288,22 @@ HTMLIFrameElement::RefreshFeaturePolicy()
mFeaturePolicy->ResetDeclaredPolicy(); mFeaturePolicy->ResetDeclaredPolicy();
// The origin can change if 'src' attribute changes. // The origin can change if 'src' attribute changes.
nsAutoString origin; nsCOMPtr<nsIPrincipal> origin;
nsresult rv = GetFeaturePolicyDefaultOrigin(origin); nsresult rv = GetFeaturePolicyDefaultOrigin(getter_AddRefs(origin));
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return; return;
} }
MOZ_ASSERT(origin);
mFeaturePolicy->SetDefaultOrigin(origin); mFeaturePolicy->SetDefaultOrigin(origin);
nsAutoString allow; nsAutoString allow;
GetAttr(nsGkAtoms::allow, allow); GetAttr(nsGkAtoms::allow, allow);
if (!allow.IsEmpty()) { 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. // Set or reset the FeaturePolicy directives.
mFeaturePolicy->SetDeclaredPolicy(OwnerDoc(), allow, documentOrigin, mFeaturePolicy->SetDeclaredPolicy(OwnerDoc(), allow, NodePrincipal(),
origin, true /* 'src' enabled */); origin);
} }
mFeaturePolicy->InheritPolicy(OwnerDoc()->Policy()); mFeaturePolicy->InheritPolicy(OwnerDoc()->Policy());

View File

@@ -8,6 +8,7 @@
#define mozilla_dom_HTMLIFrameElement_h #define mozilla_dom_HTMLIFrameElement_h
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/dom/FeaturePolicy.h"
#include "nsGenericHTMLFrameElement.h" #include "nsGenericHTMLFrameElement.h"
#include "nsDOMTokenList.h" #include "nsDOMTokenList.h"
@@ -23,7 +24,8 @@ public:
NS_IMPL_FROMNODE_HTML_WITH_TAG(HTMLIFrameElement, iframe) NS_IMPL_FROMNODE_HTML_WITH_TAG(HTMLIFrameElement, iframe)
// nsISupports // nsISupports
NS_INLINE_DECL_REFCOUNTING_INHERITED(HTMLIFrameElement, NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLIFrameElement,
nsGenericHTMLFrameElement) nsGenericHTMLFrameElement)
// Element // Element
@@ -223,8 +225,13 @@ private:
void RefreshFeaturePolicy(); 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 nsresult
GetFeaturePolicyDefaultOrigin(nsAString& aDefaultOrigin) const; GetFeaturePolicyDefaultOrigin(nsIPrincipal** aDefaultOrigin) const;
/** /**
* This function is called by AfterSetAttr and OnAttrSetButNotChanged. * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
@@ -236,6 +243,8 @@ private:
* @param aNotify Whether we plan to notify document observers. * @param aNotify Whether we plan to notify document observers.
*/ */
void AfterMaybeChangeAttr(int32_t aNamespaceID, nsAtom* aName, bool aNotify); void AfterMaybeChangeAttr(int32_t aNamespaceID, nsAtom* aName, bool aNotify);
RefPtr<mozilla::dom::FeaturePolicy> mFeaturePolicy;
}; };
} // namespace dom } // namespace dom

View File

@@ -35,7 +35,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpenerWindow) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpenerWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserElementAPI) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserElementAPI)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFeaturePolicy)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGenericHTMLFrameElement, NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGenericHTMLFrameElement,
@@ -47,7 +46,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGenericHTMLFrameElement,
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameLoader) NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameLoader)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpenerWindow) NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpenerWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserElementAPI) NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserElementAPI)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFeaturePolicy)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(nsGenericHTMLFrameElement, NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(nsGenericHTMLFrameElement,

View File

@@ -10,7 +10,6 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h" #include "mozilla/ErrorResult.h"
#include "mozilla/dom/nsBrowserElement.h" #include "mozilla/dom/nsBrowserElement.h"
#include "mozilla/dom/FeaturePolicy.h"
#include "nsFrameLoader.h" #include "nsFrameLoader.h"
#include "nsGenericHTMLElement.h" #include "nsGenericHTMLElement.h"
@@ -128,9 +127,6 @@ protected:
nsCOMPtr<nsIPrincipal> mSrcTriggeringPrincipal; nsCOMPtr<nsIPrincipal> mSrcTriggeringPrincipal;
// Used by <iframe> only.
RefPtr<mozilla::dom::FeaturePolicy> mFeaturePolicy;
/** /**
* True if we have already loaded the frame's original src * True if we have already loaded the frame's original src
*/ */

View File

@@ -5,18 +5,20 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Feature.h" #include "Feature.h"
#include "mozilla/BasePrincipal.h"
using namespace mozilla::dom; namespace mozilla {
namespace dom {
void void
Feature::GetWhiteListedOrigins(nsTArray<nsString>& aList) const Feature::GetAllowList(nsTArray<nsCOMPtr<nsIPrincipal>>& aList) const
{ {
MOZ_ASSERT(mPolicy == eWhiteList); MOZ_ASSERT(mPolicy == eAllowList);
aList.AppendElements(mWhiteListedOrigins); aList.AppendElements(mAllowList);
} }
bool bool
Feature::Allows(const nsAString& aOrigin) const Feature::Allows(nsIPrincipal* aPrincipal) const
{ {
if (mPolicy == eNone) { if (mPolicy == eNone) {
return false; return false;
@@ -26,18 +28,12 @@ Feature::Allows(const nsAString& aOrigin) const
return true; return true;
} }
for (const nsString& whiteListedOrigin : mWhiteListedOrigins) { return AllowListContains(aPrincipal);
if (whiteListedOrigin.Equals(aOrigin)) {
return true;
}
}
return false;
} }
Feature::Feature(const nsAString& aFeatureName) Feature::Feature(const nsAString& aFeatureName)
: mFeatureName(aFeatureName) : mFeatureName(aFeatureName)
, mPolicy(eWhiteList) , mPolicy(eAllowList)
{} {}
Feature::~Feature() = default; Feature::~Feature() = default;
@@ -52,7 +48,7 @@ void
Feature::SetAllowsNone() Feature::SetAllowsNone()
{ {
mPolicy = eNone; mPolicy = eNone;
mWhiteListedOrigins.Clear(); mAllowList.Clear();
} }
bool bool
@@ -65,7 +61,7 @@ void
Feature::SetAllowsAll() Feature::SetAllowsAll()
{ {
mPolicy = eAll; mPolicy = eAll;
mWhiteListedOrigins.Clear(); mAllowList.Clear();
} }
bool bool
@@ -75,24 +71,38 @@ Feature::AllowsAll() const
} }
void void
Feature::AppendOriginToWhiteList(const nsAString& aOrigin) Feature::AppendToAllowList(nsIPrincipal* aPrincipal)
{ {
mPolicy = eWhiteList; MOZ_ASSERT(aPrincipal);
mWhiteListedOrigins.AppendElement(aOrigin);
mPolicy = eAllowList;
mAllowList.AppendElement(aPrincipal);
} }
bool bool
Feature::WhiteListContains(const nsAString& aOrigin) const Feature::AllowListContains(nsIPrincipal* aPrincipal) const
{ {
if (!IsWhiteList()) { MOZ_ASSERT(aPrincipal);
if (!HasAllowList()) {
return false; return false;
} }
return mWhiteListedOrigins.Contains(aOrigin); for (nsIPrincipal* principal : mAllowList) {
if (BasePrincipal::Cast(principal)->Subsumes(aPrincipal,
BasePrincipal::ConsiderDocumentDomain)) {
return true;
}
}
return false;
} }
bool bool
Feature::IsWhiteList() const Feature::HasAllowList() const
{ {
return mPolicy == eWhiteList; return mPolicy == eAllowList;
} }
} // dom namespace
} // mozilla namespace

View File

@@ -11,6 +11,8 @@
#include "nsTArray.h" #include "nsTArray.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
class nsIPrincipal;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@@ -37,19 +39,19 @@ public:
AllowsAll() const; AllowsAll() const;
void void
AppendOriginToWhiteList(const nsAString& aOrigin); AppendToAllowList(nsIPrincipal* aPrincipal);
void void
GetWhiteListedOrigins(nsTArray<nsString>& aList) const; GetAllowList(nsTArray<nsCOMPtr<nsIPrincipal>>& aList) const;
bool bool
WhiteListContains(const nsAString& aOrigin) const; AllowListContains(nsIPrincipal* aPrincipal) const;
bool bool
IsWhiteList() const; HasAllowList() const;
bool bool
Allows(const nsAString& aOrigin) const; Allows(nsIPrincipal* aPrincipal) const;
private: private:
nsString mFeatureName; nsString mFeatureName;
@@ -62,12 +64,12 @@ private:
eAll, eAll,
// denotes a policy of "feature bar.com foo.com" // denotes a policy of "feature bar.com foo.com"
eWhiteList, eAllowList,
}; };
Policy mPolicy; Policy mPolicy;
nsTArray<nsString> mWhiteListedOrigins; nsTArray<nsCOMPtr<nsIPrincipal>> mAllowList;
}; };
} // dom namespace } // dom namespace

View File

@@ -9,8 +9,10 @@
#include "mozilla/dom/FeaturePolicyParser.h" #include "mozilla/dom/FeaturePolicyParser.h"
#include "mozilla/dom/FeaturePolicyUtils.h" #include "mozilla/dom/FeaturePolicyUtils.h"
#include "nsContentUtils.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_COLLECTION_WRAPPERCACHE(FeaturePolicy, mParentNode)
NS_IMPL_CYCLE_COLLECTING_ADDREF(FeaturePolicy) NS_IMPL_CYCLE_COLLECTING_ADDREF(FeaturePolicy)
@@ -34,7 +36,7 @@ FeaturePolicy::InheritPolicy(FeaturePolicy* aParentPolicy)
RefPtr<FeaturePolicy> dest = this; RefPtr<FeaturePolicy> dest = this;
RefPtr<FeaturePolicy> src = aParentPolicy; RefPtr<FeaturePolicy> src = aParentPolicy;
nsString origin = mDefaultOrigin; nsCOMPtr<nsIPrincipal> origin = mDefaultOrigin;
FeaturePolicyUtils::ForEachFeature([dest, src, origin](const char* aFeatureName) { FeaturePolicyUtils::ForEachFeature([dest, src, origin](const char* aFeatureName) {
nsString featureName; nsString featureName;
featureName.AppendASCII(aFeatureName); featureName.AppendASCII(aFeatureName);
@@ -86,9 +88,8 @@ FeaturePolicy::HasDeclaredFeature(const nsAString& aFeatureName) const
void void
FeaturePolicy::SetDeclaredPolicy(nsIDocument* aDocument, FeaturePolicy::SetDeclaredPolicy(nsIDocument* aDocument,
const nsAString& aPolicyString, const nsAString& aPolicyString,
const nsAString& aSelfOrigin, nsIPrincipal* aSelfOrigin,
const nsAString& aSrcOrigin, nsIPrincipal* aSrcOrigin)
bool aSrcEnabled)
{ {
ResetDeclaredPolicy(); ResetDeclaredPolicy();
@@ -96,7 +97,6 @@ FeaturePolicy::SetDeclaredPolicy(nsIDocument* aDocument,
aDocument, aDocument,
aSelfOrigin, aSelfOrigin,
aSrcOrigin, aSrcOrigin,
aSrcEnabled,
mFeatures)); mFeatures));
} }
@@ -116,16 +116,32 @@ bool
FeaturePolicy::AllowsFeature(const nsAString& aFeatureName, FeaturePolicy::AllowsFeature(const nsAString& aFeatureName,
const Optional<nsAString>& aOrigin) const const Optional<nsAString>& aOrigin) const
{ {
return AllowsFeatureInternal(aFeatureName, nsCOMPtr<nsIPrincipal> origin;
aOrigin.WasPassed() if (aOrigin.WasPassed()) {
? aOrigin.Value() nsCOMPtr<nsIURI> uri;
: mDefaultOrigin); 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 bool
FeaturePolicy::AllowsFeatureInternal(const nsAString& aFeatureName, 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. // Let's see if have to disable this feature because inherited policy.
if (HasInheritedDeniedFeature(aFeatureName)) { if (HasInheritedDeniedFeature(aFeatureName)) {
return false; return false;
@@ -137,8 +153,22 @@ FeaturePolicy::AllowsFeatureInternal(const nsAString& aFeatureName,
} }
} }
return FeaturePolicyUtils::AllowDefaultFeature(aFeatureName, mDefaultOrigin, switch (FeaturePolicyUtils::DefaultAllowListFeature(aFeatureName)) {
aOrigin); 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 void
@@ -170,16 +200,44 @@ FeaturePolicy::GetAllowlistForFeature(const nsAString& aFeatureName,
return; 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; return;
} }
} }
nsString defaultAllowList; switch (FeaturePolicyUtils::DefaultAllowListFeature(aFeatureName)) {
FeaturePolicyUtils::DefaultAllowListFeature(aFeatureName, mDefaultOrigin, case FeaturePolicyUtils::FeaturePolicyValue::eAll:
defaultAllowList); aList.AppendElement(NS_LITERAL_STRING("*"));
if (!defaultAllowList.IsEmpty()) { return;
aList.AppendElement(defaultAllowList);
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");
} }
} }
@@ -197,3 +255,6 @@ FeaturePolicy::MaybeSetAllowedPolicy(const nsAString& aFeatureName)
mFeatures.AppendElement(feature); mFeatures.AppendElement(feature);
} }
} // dom namespace
} // mozilla namespace

View File

@@ -30,12 +30,12 @@
* these policies: * these policies:
* - eNone - the feature is fully disabled. * - eNone - the feature is fully disabled.
* - eAll - the feature is allowed. * - 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 * An interesting element of FeaturePolicy is the inheritance: each context
* inherits the feature-policy directives from the parent context, if it exists. * 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 * 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 * This information is stored in an array of inherited feature strings because
* we care only to know when they are denied. * we care only to know when they are denied.
* *
@@ -72,19 +72,17 @@ public:
explicit FeaturePolicy(nsINode* aNode); 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 // This method must be called before any other exposed WebIDL method or before
// checking if a feature is allowed. // checking if a feature is allowed.
void void
SetDefaultOrigin(const nsAString& aOrigin) SetDefaultOrigin(nsIPrincipal* aPrincipal)
{ {
// aOrigin can be an empty string if this is a opaque origin. mDefaultOrigin = aPrincipal;
mDefaultOrigin = aOrigin;
} }
const nsAString& DefaultOrigin() const nsIPrincipal* DefaultOrigin() const
{ {
// Returns an empty string if this is an opaque origin.
return mDefaultOrigin; return mDefaultOrigin;
} }
@@ -97,9 +95,8 @@ public:
void void
SetDeclaredPolicy(nsIDocument* aDocument, SetDeclaredPolicy(nsIDocument* aDocument,
const nsAString& aPolicyString, const nsAString& aPolicyString,
const nsAString& aSelfOrigin, nsIPrincipal* aSelfOrigin,
const nsAString& aSrcOrigin, nsIPrincipal* aSrcOrigin);
bool aSrcEnabled);
// This method creates a policy for aFeatureName allowing it to '*' if it // 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 // doesn't exist yet. It's used by HTMLIFrameElement to enable features by
@@ -140,9 +137,12 @@ public:
private: private:
~FeaturePolicy() = default; ~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 bool
AllowsFeatureInternal(const nsAString& aFeatureName, AllowsFeatureInternal(const nsAString& aFeatureName,
const nsAString& aOrigin) const; nsIPrincipal* aOrigin) const;
// Inherits a single denied feature from the parent context. // Inherits a single denied feature from the parent context.
void void
@@ -151,6 +151,7 @@ private:
bool bool
HasInheritedDeniedFeature(const nsAString& aFeatureName) const; HasInheritedDeniedFeature(const nsAString& aFeatureName) const;
// This returns true if we have a declared feature policy for aFeatureName.
bool bool
HasDeclaredFeature(const nsAString& aFeatureName) const; HasDeclaredFeature(const nsAString& aFeatureName) const;
@@ -163,7 +164,7 @@ private:
// Feature policy for the current context. // Feature policy for the current context.
nsTArray<Feature> mFeatures; nsTArray<Feature> mFeatures;
nsString mDefaultOrigin; nsCOMPtr<nsIPrincipal> mDefaultOrigin;
}; };
} // dom namespace } // dom namespace

View File

@@ -13,8 +13,8 @@
#include "nsIURI.h" #include "nsIURI.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
using namespace mozilla; namespace mozilla {
using namespace mozilla::dom; namespace dom {
namespace { namespace {
@@ -65,11 +65,12 @@ ReportToConsoleInvalidAllowValue(nsIDocument* aDocument,
/* static */ bool /* static */ bool
FeaturePolicyParser::ParseString(const nsAString& aPolicy, FeaturePolicyParser::ParseString(const nsAString& aPolicy,
nsIDocument* aDocument, nsIDocument* aDocument,
const nsAString& aSelfOrigin, nsIPrincipal* aSelfOrigin,
const nsAString& aSrcOrigin, nsIPrincipal* aSrcOrigin,
bool aSrcEnabled,
nsTArray<Feature>& aParsedFeatures) nsTArray<Feature>& aParsedFeatures)
{ {
MOZ_ASSERT(aSelfOrigin);
nsTArray<nsTArray<nsString>> tokens; nsTArray<nsTArray<nsString>> tokens;
PolicyTokenizer::tokenizePolicy(aPolicy, tokens); PolicyTokenizer::tokenizePolicy(aPolicy, tokens);
@@ -88,9 +89,8 @@ FeaturePolicyParser::ParseString(const nsAString& aPolicy,
Feature feature(featureTokens[0]); Feature feature(featureTokens[0]);
if (featureTokens.Length() == 1) { if (featureTokens.Length() == 1) {
if (aSrcEnabled) { if (aSrcOrigin) {
// Note that this src origin can be empty if opaque. feature.AppendToAllowList(aSrcOrigin);
feature.AppendOriginToWhiteList(aSrcOrigin);
} else { } else {
ReportToConsoleInvalidEmptyAllowValue(aDocument, featureTokens[0]); ReportToConsoleInvalidEmptyAllowValue(aDocument, featureTokens[0]);
continue; continue;
@@ -110,18 +110,12 @@ FeaturePolicyParser::ParseString(const nsAString& aPolicy,
} }
if (curVal.LowerCaseEqualsASCII("'self'")) { if (curVal.LowerCaseEqualsASCII("'self'")) {
// Opaque origins are passed as empty string. feature.AppendToAllowList(aSelfOrigin);
if (!aSelfOrigin.IsEmpty()) {
feature.AppendOriginToWhiteList(aSelfOrigin);
}
continue; continue;
} }
if (aSrcEnabled && curVal.LowerCaseEqualsASCII("'src'")) { if (aSrcOrigin && curVal.LowerCaseEqualsASCII("'src'")) {
// Opaque origins are passed as empty string. feature.AppendToAllowList(aSrcOrigin);
if (!aSrcOrigin.IsEmpty()) {
feature.AppendOriginToWhiteList(aSrcOrigin);
}
continue; continue;
} }
@@ -132,14 +126,15 @@ FeaturePolicyParser::ParseString(const nsAString& aPolicy,
continue; continue;
} }
nsAutoString origin; nsCOMPtr<nsIPrincipal> origin =
rv = nsContentUtils::GetUTFOrigin(uri, origin); BasePrincipal::CreateCodebasePrincipal(uri,
if (NS_WARN_IF(NS_FAILED(rv))) { BasePrincipal::Cast(aSelfOrigin)->OriginAttributesRef());
if (NS_WARN_IF(!origin)) {
ReportToConsoleInvalidAllowValue(aDocument, curVal); ReportToConsoleInvalidAllowValue(aDocument, curVal);
continue; continue;
} }
feature.AppendOriginToWhiteList(origin); feature.AppendToAllowList(origin);
} }
} }
@@ -160,3 +155,6 @@ FeaturePolicyParser::ParseString(const nsAString& aPolicy,
aParsedFeatures.SwapElements(parsedFeatures); aParsedFeatures.SwapElements(parsedFeatures);
return true; return true;
} }
} // dom namespace
} // mozilla namespace

View File

@@ -10,7 +10,7 @@
#include "nsString.h" #include "nsString.h"
class nsIDocument; class nsIDocument;
class nsIURI; class nsIPrincipal;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@@ -20,14 +20,13 @@ class Feature;
class FeaturePolicyParser final class FeaturePolicyParser final
{ {
public: 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. // support 'src' as valid allow directive value.
static bool static bool
ParseString(const nsAString& aPolicy, ParseString(const nsAString& aPolicy,
nsIDocument* aDocument, nsIDocument* aDocument,
const nsAString& aSelfOrigin, nsIPrincipal* aSelfOrigin,
const nsAString& aSrcOrigin, nsIPrincipal* aSrcOrigin,
bool aSrcEnabled,
nsTArray<Feature>& aParsedFeatures); nsTArray<Feature>& aParsedFeatures);
}; };

View File

@@ -9,15 +9,12 @@
#include "mozilla/StaticPrefs.h" #include "mozilla/StaticPrefs.h"
#include "nsIDocument.h" #include "nsIDocument.h"
using namespace mozilla::dom; namespace mozilla {
namespace dom {
struct FeatureMap { struct FeatureMap {
const char* mFeatureName; const char* mFeatureName;
FeaturePolicyUtils::FeaturePolicyValue mDefaultAllowList;
enum {
eAll,
eSelf,
} mDefaultAllowList;
}; };
/* /*
@@ -25,17 +22,17 @@ struct FeatureMap {
* DOM Security peer! * DOM Security peer!
*/ */
static FeatureMap sSupportedFeatures[] = { static FeatureMap sSupportedFeatures[] = {
{ "autoplay", FeatureMap::eAll }, { "autoplay", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "camera", FeatureMap::eAll }, { "camera", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "encrypted-media", FeatureMap::eAll }, { "encrypted-media", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "fullscreen", FeatureMap::eAll }, { "fullscreen", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "geolocation", FeatureMap::eAll }, { "geolocation", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "microphone", FeatureMap::eAll }, { "microphone", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "midi", FeatureMap::eAll }, { "midi", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "payment", FeatureMap::eAll }, { "payment", FeaturePolicyUtils::FeaturePolicyValue::eAll },
// TODO: not supported yet!!! // TODO: not supported yet!!!
{ "speaker", FeatureMap::eAll }, { "speaker", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "vr", FeatureMap::eAll }, { "vr", FeaturePolicyUtils::FeaturePolicyValue::eAll },
}; };
/* static */ bool /* static */ bool
@@ -59,51 +56,17 @@ FeaturePolicyUtils::ForEachFeature(const std::function<void(const char*)>& aCall
} }
} }
/* static */ void /* static */ FeaturePolicyUtils::FeaturePolicyValue
FeaturePolicyUtils::DefaultAllowListFeature(const nsAString& aFeatureName, FeaturePolicyUtils::DefaultAllowListFeature(const nsAString& aFeatureName)
const nsAString& aDefaultOrigin,
nsAString& aDefaultAllowList)
{ {
uint32_t numFeatures = (sizeof(sSupportedFeatures) / sizeof(sSupportedFeatures[0])); uint32_t numFeatures = (sizeof(sSupportedFeatures) / sizeof(sSupportedFeatures[0]));
for (uint32_t i = 0; i < numFeatures; ++i) { for (uint32_t i = 0; i < numFeatures; ++i) {
if (aFeatureName.LowerCaseEqualsASCII(sSupportedFeatures[i].mFeatureName)) { if (aFeatureName.LowerCaseEqualsASCII(sSupportedFeatures[i].mFeatureName)) {
switch (sSupportedFeatures[i].mDefaultAllowList) { return sSupportedFeatures[i].mDefaultAllowList;
case FeatureMap::eAll:
aDefaultAllowList.AppendASCII("*");
return;
case FeatureMap::eSelf:
aDefaultAllowList = aDefaultOrigin;
return;
default:
MOZ_CRASH("Unknown default value");
}
}
} }
} }
/* static */ bool return FeaturePolicyValue::eNone;
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 false;
} }
/* static */ bool /* static */ bool
@@ -125,3 +88,6 @@ FeaturePolicyUtils::IsFeatureAllowed(nsIDocument* aDocument,
return policy->AllowsFeatureInternal(aFeatureName, policy->DefaultOrigin()); return policy->AllowsFeatureInternal(aFeatureName, policy->DefaultOrigin());
} }
} // dom namespace
} // mozilla namespace

View File

@@ -18,25 +18,36 @@ namespace dom {
class FeaturePolicyUtils final class FeaturePolicyUtils final
{ {
public: 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 static bool
IsFeatureAllowed(nsIDocument* aDocument, IsFeatureAllowed(nsIDocument* aDocument,
const nsAString& aFeatureName); const nsAString& aFeatureName);
// Returns true if aFeatureName is a known feature policy name.
static bool static bool
IsSupportedFeature(const nsAString& aFeatureName); IsSupportedFeature(const nsAString& aFeatureName);
// Runs aCallback for each known feature policy, with the feature name as
// argument.
static void static void
ForEachFeature(const std::function<void(const char*)>& aCallback); ForEachFeature(const std::function<void(const char*)>& aCallback);
static void // Returns the default policy value for aFeatureName.
DefaultAllowListFeature(const nsAString& aFeatureName, static FeaturePolicyValue
const nsAString& aDefaultOrigin, DefaultAllowListFeature(const nsAString& aFeatureName);
nsAString& aDefaultAllowList);
static bool
AllowDefaultFeature(const nsAString& aFeatureName,
const nsAString& aDefaultOrigin,
const nsAString& aOrigin);
}; };
} // dom namespace } // dom namespace

View File

@@ -5,27 +5,30 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */ * You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/dom/Feature.h" #include "mozilla/dom/Feature.h"
#include "mozilla/dom/FeaturePolicyParser.h" #include "mozilla/dom/FeaturePolicyParser.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "nsTArray.h" #include "nsTArray.h"
using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
#define URL_SELF NS_LITERAL_STRING("https://example.com") #define URL_SELF NS_LITERAL_CSTRING("https://example.com")
#define URL_EXAMPLE_COM NS_LITERAL_STRING("http://example.com") #define URL_EXAMPLE_COM NS_LITERAL_CSTRING("http://example.com")
#define URL_EXAMPLE_NET NS_LITERAL_STRING("http://example.net") #define URL_EXAMPLE_NET NS_LITERAL_CSTRING("http://example.net")
void void
CheckParser(const nsAString& aInput, bool aExpectedResults, CheckParser(const nsAString& aInput, bool aExpectedResults,
uint32_t aExpectedFeatures, nsTArray<Feature>& aParsedFeatures) uint32_t aExpectedFeatures, nsTArray<Feature>& aParsedFeatures)
{ {
nsCOMPtr<nsIPrincipal> principal =
mozilla::BasePrincipal::CreateCodebasePrincipal(URL_SELF);
nsTArray<Feature> parsedFeatures; nsTArray<Feature> parsedFeatures;
ASSERT_TRUE(FeaturePolicyParser::ParseString(aInput, ASSERT_TRUE(FeaturePolicyParser::ParseString(aInput,
nullptr, nullptr,
URL_SELF, principal,
EmptyString(), principal,
true, // 'src' enabled
parsedFeatures) == aExpectedResults); parsedFeatures) == aExpectedResults);
ASSERT_TRUE(parsedFeatures.Length() == aExpectedFeatures); ASSERT_TRUE(parsedFeatures.Length() == aExpectedFeatures);
@@ -34,6 +37,13 @@ CheckParser(const nsAString& aInput, bool aExpectedResults,
TEST(FeaturePolicyParser, Basic) 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; nsTArray<Feature> parsedFeatures;
// Empty string is a valid policy. // Empty string is a valid policy.
@@ -50,70 +60,70 @@ TEST(FeaturePolicyParser, Basic)
// Existing feature with no allowed values // Existing feature with no allowed values
CheckParser(NS_LITERAL_STRING("camera"), true, 1, parsedFeatures); CheckParser(NS_LITERAL_STRING("camera"), true, 1, parsedFeatures);
ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera"))); ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
ASSERT_TRUE(parsedFeatures[0].IsWhiteList()); ASSERT_TRUE(parsedFeatures[0].HasAllowList());
// Some spaces. // Some spaces.
CheckParser(NS_LITERAL_STRING(" camera "), true, 1, parsedFeatures); CheckParser(NS_LITERAL_STRING(" camera "), true, 1, parsedFeatures);
ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera"))); ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
ASSERT_TRUE(parsedFeatures[0].IsWhiteList()); ASSERT_TRUE(parsedFeatures[0].HasAllowList());
// A random ; // A random ;
CheckParser(NS_LITERAL_STRING("camera;"), true, 1, parsedFeatures); CheckParser(NS_LITERAL_STRING("camera;"), true, 1, parsedFeatures);
ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera"))); ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
ASSERT_TRUE(parsedFeatures[0].IsWhiteList()); ASSERT_TRUE(parsedFeatures[0].HasAllowList());
// Another random ; // Another random ;
CheckParser(NS_LITERAL_STRING(";camera;"), true, 1, parsedFeatures); CheckParser(NS_LITERAL_STRING(";camera;"), true, 1, parsedFeatures);
ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera"))); ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
ASSERT_TRUE(parsedFeatures[0].IsWhiteList()); ASSERT_TRUE(parsedFeatures[0].HasAllowList());
// 2 features // 2 features
CheckParser(NS_LITERAL_STRING("camera;microphone"), true, 2, parsedFeatures); CheckParser(NS_LITERAL_STRING("camera;microphone"), true, 2, parsedFeatures);
ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera"))); 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].Name().Equals(NS_LITERAL_STRING("microphone")));
ASSERT_TRUE(parsedFeatures[1].IsWhiteList()); ASSERT_TRUE(parsedFeatures[1].HasAllowList());
// 2 features with spaces // 2 features with spaces
CheckParser(NS_LITERAL_STRING(" camera ; microphone "), true, 2, CheckParser(NS_LITERAL_STRING(" camera ; microphone "), true, 2,
parsedFeatures); parsedFeatures);
ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera"))); 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].Name().Equals(NS_LITERAL_STRING("microphone")));
ASSERT_TRUE(parsedFeatures[1].IsWhiteList()); ASSERT_TRUE(parsedFeatures[1].HasAllowList());
// 3 features, but only 2 exist. // 3 features, but only 2 exist.
CheckParser(NS_LITERAL_STRING("camera;microphone;foobar"), true, 2, CheckParser(NS_LITERAL_STRING("camera;microphone;foobar"), true, 2,
parsedFeatures); parsedFeatures);
ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera"))); 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].Name().Equals(NS_LITERAL_STRING("microphone")));
ASSERT_TRUE(parsedFeatures[1].IsWhiteList()); ASSERT_TRUE(parsedFeatures[1].HasAllowList());
// Multiple spaces around the value // Multiple spaces around the value
CheckParser(NS_LITERAL_STRING("camera 'self'"), true, 1, CheckParser(NS_LITERAL_STRING("camera 'self'"), true, 1,
parsedFeatures); parsedFeatures);
ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera"))); 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 // Multiple spaces around the value
CheckParser(NS_LITERAL_STRING("camera 'self' "), true, 1, CheckParser(NS_LITERAL_STRING("camera 'self' "), true, 1,
parsedFeatures); parsedFeatures);
ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera"))); 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 ' // No final '
CheckParser(NS_LITERAL_STRING("camera 'self"), true, 1, CheckParser(NS_LITERAL_STRING("camera 'self"), true, 1,
parsedFeatures); parsedFeatures);
ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera"))); ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
ASSERT_TRUE(parsedFeatures[0].IsWhiteList()); ASSERT_TRUE(parsedFeatures[0].HasAllowList());
ASSERT_TRUE(!parsedFeatures[0].WhiteListContains(URL_SELF)); ASSERT_TRUE(!parsedFeatures[0].AllowListContains(selfPrincipal));
// Lowercase/Uppercase // Lowercase/Uppercase
CheckParser(NS_LITERAL_STRING("camera 'selF'"), true, 1, CheckParser(NS_LITERAL_STRING("camera 'selF'"), true, 1,
parsedFeatures); parsedFeatures);
ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera"))); 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 // Lowercase/Uppercase
CheckParser(NS_LITERAL_STRING("camera * 'self' none' a.com 123"), true, 1, CheckParser(NS_LITERAL_STRING("camera * 'self' none' a.com 123"), true, 1,
@@ -136,23 +146,23 @@ TEST(FeaturePolicyParser, Basic)
// 'self' // 'self'
CheckParser(NS_LITERAL_STRING("camera 'self'"), true, 1, parsedFeatures); CheckParser(NS_LITERAL_STRING("camera 'self'"), true, 1, parsedFeatures);
ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera"))); 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 // A couple of URLs
CheckParser(NS_LITERAL_STRING("camera http://example.com http://example.net"), true, 1, CheckParser(NS_LITERAL_STRING("camera http://example.com http://example.net"), true, 1,
parsedFeatures); parsedFeatures);
ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera"))); ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
ASSERT_TRUE(!parsedFeatures[0].WhiteListContains(URL_SELF)); ASSERT_TRUE(!parsedFeatures[0].AllowListContains(selfPrincipal));
ASSERT_TRUE(parsedFeatures[0].WhiteListContains(URL_EXAMPLE_COM)); ASSERT_TRUE(parsedFeatures[0].AllowListContains(exampleComPrincipal));
ASSERT_TRUE(parsedFeatures[0].WhiteListContains(URL_EXAMPLE_NET)); ASSERT_TRUE(parsedFeatures[0].AllowListContains(exampleNetPrincipal));
// A couple of URLs + self // A couple of URLs + self
CheckParser(NS_LITERAL_STRING("camera http://example.com 'self' http://example.net"), true, 1, CheckParser(NS_LITERAL_STRING("camera http://example.com 'self' http://example.net"), true, 1,
parsedFeatures); parsedFeatures);
ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera"))); ASSERT_TRUE(parsedFeatures[0].Name().Equals(NS_LITERAL_STRING("camera")));
ASSERT_TRUE(parsedFeatures[0].WhiteListContains(URL_SELF)); ASSERT_TRUE(parsedFeatures[0].AllowListContains(selfPrincipal));
ASSERT_TRUE(parsedFeatures[0].WhiteListContains(URL_EXAMPLE_COM)); ASSERT_TRUE(parsedFeatures[0].AllowListContains(exampleComPrincipal));
ASSERT_TRUE(parsedFeatures[0].WhiteListContains(URL_EXAMPLE_NET)); ASSERT_TRUE(parsedFeatures[0].AllowListContains(exampleNetPrincipal));
// A couple of URLs but then * // A couple of URLs but then *
CheckParser(NS_LITERAL_STRING("camera http://example.com 'self' http://example.net *"), true, 1, CheckParser(NS_LITERAL_STRING("camera http://example.com 'self' http://example.net *"), true, 1,

View File

@@ -31,4 +31,3 @@
[Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8443 https://www.example.com" and allowfullscreen.] [Test frame policy on cross origin iframe with allow = "'self' https://www.web-platform.test:8443 https://www.example.com" and allowfullscreen.]
expected: FAIL expected: FAIL

View File

@@ -10,11 +10,12 @@
var cross_origin = 'https://{{domains[www]}}:{{ports[https][0]}}'; var cross_origin = 'https://{{domains[www]}}:{{ports[https][0]}}';
var same_origin_src = '/feature-policy/resources/feature-policy-allowedfeatures.html'; var same_origin_src = '/feature-policy/resources/feature-policy-allowedfeatures.html';
var cross_origin_src = cross_origin + same_origin_src; var cross_origin_src = cross_origin + same_origin_src;
var data_src = 'data:text/html,<h1>data: URL</h1>';
var policies = [ var policies = [
{allow: "*", sameOriginTestExpect: true, crossOriginTestExpect: true}, {allow: "*", sameOriginTestExpect: true, crossOriginTestExpect: true, dataOriginTestExpect: true},
{allow: "'self'", sameOriginTestExpect: true, crossOriginTestExpect: false}, {allow: "'self'", sameOriginTestExpect: true, crossOriginTestExpect: false, dataOriginTestExpect: false},
{allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false}, {allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false, dataOriginTestExpect: false},
{allow: "'self' " + cross_origin + " https://www.example.com", sameOriginTestExpect: true, crossOriginTestExpect: true}]; {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_front = '?pipe=sub|header(Feature-Policy,fullscreen ';
var pipe_end = ';)'; var pipe_end = ';)';
var header_policies = ["*", "'self'", "'none'"]; var header_policies = ["*", "'self'", "'none'"];
@@ -22,24 +23,58 @@
// Test that frame.policy inherits from parent's header policy when allow // Test that frame.policy inherits from parent's header policy when allow
// attribute is not specified. // attribute is not specified.
test(function() { 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 frame policy on same origin iframe inherit from header policy.');
test(function() { 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 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. // Test frame policy with allow attribute set to be one of the policies above.
for (var i = 0; i < policies.length; i++) { for (var i = 0; i < policies.length; i++) {
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', same_origin_src, policies[i].sameOriginTestExpect, 'fullscreen', same_origin_src, undefined,
policies[i].sameOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + '".'); }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + '".');
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect, 'fullscreen', cross_origin_src, undefined,
policies[i].crossOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on cross origin iframe with allow = "' + 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 // Test that the header policy of the iframe document does not change the
@@ -50,7 +85,7 @@
test_frame_policy( test_frame_policy(
'fullscreen', 'fullscreen',
same_origin_src + pipe_front + header_policies[j] + pipe_end, same_origin_src + pipe_front + header_policies[j] + pipe_end,
policies[i].sameOriginTestExpect, undefined, policies[i].sameOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
'" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".'); '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
@@ -58,7 +93,7 @@
test_frame_policy( test_frame_policy(
'fullscreen', 'fullscreen',
cross_origin_src + pipe_front + header_policies[j] + pipe_end, cross_origin_src + pipe_front + header_policies[j] + pipe_end,
policies[i].crossOriginTestExpect, undefined, policies[i].crossOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
'" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".'); '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
@@ -69,16 +104,42 @@
for (var i = 0; i < policies.length; i++) { for (var i = 0; i < policies.length; i++) {
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', same_origin_src, policies[i].sameOriginTestExpect, 'fullscreen', same_origin_src, undefined,
policies[i].sameOriginTestExpect,
'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true); 'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
}, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
'" and allowfullscreen.'); '" and allowfullscreen.');
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect, 'fullscreen', cross_origin_src, undefined,
policies[i].crossOriginTestExpect,
'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true); 'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
}, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
'" and allowfullscreen.'); '" 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> </script>
</body> </body>

View File

@@ -10,11 +10,12 @@
var cross_origin = 'https://{{domains[www]}}:{{ports[https][0]}}'; var cross_origin = 'https://{{domains[www]}}:{{ports[https][0]}}';
var same_origin_src = '/feature-policy/resources/feature-policy-allowedfeatures.html'; var same_origin_src = '/feature-policy/resources/feature-policy-allowedfeatures.html';
var cross_origin_src = cross_origin + same_origin_src; var cross_origin_src = cross_origin + same_origin_src;
var data_src = 'data:text/html,<h1>data: URL</h1>';
var policies = [ var policies = [
{allow: "*", sameOriginTestExpect: true, crossOriginTestExpect: true}, {allow: "*", sameOriginTestExpect: true, crossOriginTestExpect: true, dataOriginTestExpect: false},
{allow: "'self'", sameOriginTestExpect: true, crossOriginTestExpect: false}, {allow: "'self'", sameOriginTestExpect: true, crossOriginTestExpect: false, dataOriginTestExpect: false},
{allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false}, {allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false, dataOriginTestExpect: false},
{allow: "'self' " + cross_origin + " https://www.example.com", sameOriginTestExpect: true, crossOriginTestExpect: true}]; {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_front = '?pipe=sub|header(Feature-Policy,fullscreen ';
var pipe_end = ';)'; var pipe_end = ';)';
var header_policies = ["*", "'self'", "'none'"]; var header_policies = ["*", "'self'", "'none'"];
@@ -22,42 +23,92 @@
// Test that frame.policy inherits from parent's header policy when allow // Test that frame.policy inherits from parent's header policy when allow
// attribute is not specified. // attribute is not specified.
test(function() { 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 frame policy on same origin iframe inherit from header policy.');
test(function() { 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 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 that frame policy can be used for sandboxed frames
test(function() { test(function() {
test_frame_policy( 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 frame policy on sandboxed iframe with no allow attribute.');
test(function() { test(function() {
test_frame_policy( 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 frame policy on sandboxed iframe with allow="fullscreen".');
test(function() { test(function() {
test_frame_policy( 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 frame policy on sandboxed iframe with allow="fullscreen \'src\'".');
test(function() { test(function() {
test_frame_policy( 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 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. // Test frame policy with allow attribute set to be one of the policies above.
for (var i = 0; i < policies.length; i++) { for (var i = 0; i < policies.length; i++) {
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', same_origin_src, policies[i].sameOriginTestExpect, 'fullscreen', same_origin_src, undefined,
policies[i].sameOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + '".'); }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + '".');
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect, 'fullscreen', cross_origin_src, undefined,
policies[i].crossOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on cross origin iframe with allow = "' + 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 // Test that the header policy of the iframe document does not change the
@@ -68,7 +119,7 @@
test_frame_policy( test_frame_policy(
'fullscreen', 'fullscreen',
same_origin_src + pipe_front + header_policies[j] + pipe_end, same_origin_src + pipe_front + header_policies[j] + pipe_end,
policies[i].sameOriginTestExpect, undefined, policies[i].sameOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
'" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".'); '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
@@ -76,7 +127,7 @@
test_frame_policy( test_frame_policy(
'fullscreen', 'fullscreen',
cross_origin_src + pipe_front + header_policies[j] + pipe_end, cross_origin_src + pipe_front + header_policies[j] + pipe_end,
policies[i].crossOriginTestExpect, undefined, policies[i].crossOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
'" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".'); '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
@@ -87,16 +138,42 @@
for (var i = 0; i < policies.length; i++) { for (var i = 0; i < policies.length; i++) {
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', same_origin_src, policies[i].sameOriginTestExpect, 'fullscreen', same_origin_src, undefined,
policies[i].sameOriginTestExpect,
'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true); 'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
}, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
'" and allowfullscreen.'); '" and allowfullscreen.');
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect, 'fullscreen', cross_origin_src, undefined,
policies[i].crossOriginTestExpect,
'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true); 'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
}, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
'" and allowfullscreen.'); '" 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> </script>
</body> </body>

View File

@@ -12,12 +12,13 @@
var same_origin_src = '/feature-policy/resources/feature-policy-allowedfeatures.html'; var same_origin_src = '/feature-policy/resources/feature-policy-allowedfeatures.html';
var cross_origin_src = cross_origin + same_origin_src; var cross_origin_src = cross_origin + same_origin_src;
var cross_origin_src1 = cross_origin1 + 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. // Test feature policy with same_origin_src and cross_origin_src.
var policies = [ var policies = [
{allow: "*", sameOriginTestExpect: true, crossOriginTestExpect: true, crossOrigin1TestExpect: true}, {allow: "*", sameOriginTestExpect: true, crossOriginTestExpect: true, crossOrigin1TestExpect: true, dataOriginTestExpect: false},
{allow: "'self'", sameOriginTestExpect: true, crossOriginTestExpect: false, crossOrigin1TestExpect: false}, {allow: "'self'", sameOriginTestExpect: true, crossOriginTestExpect: false, crossOrigin1TestExpect: false, dataOriginTestExpect: false},
{allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false, crossOrigin1TestExpect: 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}]; {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_front = '?pipe=sub|header(Feature-Policy,fullscreen ';
var pipe_end = ';)'; var pipe_end = ';)';
var header_policies = ["*", "'self'", "'none'"]; var header_policies = ["*", "'self'", "'none'"];
@@ -25,32 +26,75 @@
// Test that frame.policy inherits from parent's header policy when allow // Test that frame.policy inherits from parent's header policy when allow
// attribute is not specified. // attribute is not specified.
test(function() { 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 frame policy on same origin iframe inherit from header policy.');
test(function() { 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 frame policy on cross origin iframe inherit from header policy.');
test(function() { 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 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. // Test frame policy with allow attribute set to be one of the policies above.
for (var i = 0; i < policies.length; i++) { for (var i = 0; i < policies.length; i++) {
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', same_origin_src, policies[i].sameOriginTestExpect, 'fullscreen', same_origin_src, undefined,
policies[i].sameOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + '".'); }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + '".');
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect, 'fullscreen', cross_origin_src, undefined,
policies[i].crossOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow + '".'); }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow + '".');
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', cross_origin_src1, policies[i].crossOrigin1TestExpect, 'fullscreen', cross_origin_src1, undefined,
policies[i].crossOrigin1TestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on another cross origin iframe with allow = "' + 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 // Test that the header policy of the iframe document does not change the
@@ -61,7 +105,7 @@
test_frame_policy( test_frame_policy(
'fullscreen', 'fullscreen',
same_origin_src + pipe_front + header_policies[j] + pipe_end, same_origin_src + pipe_front + header_policies[j] + pipe_end,
policies[i].sameOriginTestExpect, undefined, policies[i].sameOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
'" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".'); '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
@@ -69,7 +113,7 @@
test_frame_policy( test_frame_policy(
'fullscreen', 'fullscreen',
cross_origin_src + pipe_front + header_policies[j] + pipe_end, cross_origin_src + pipe_front + header_policies[j] + pipe_end,
policies[i].crossOriginTestExpect, undefined, policies[i].crossOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
'" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".'); '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
@@ -77,7 +121,7 @@
test_frame_policy( test_frame_policy(
'fullscreen', 'fullscreen',
cross_origin_src1 + pipe_front + header_policies[j] + pipe_end, cross_origin_src1 + pipe_front + header_policies[j] + pipe_end,
policies[i].crossOrigin1TestExpect, undefined, policies[i].crossOrigin1TestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on another cross origin iframe with allow = "' + 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] + ';".'); '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
@@ -88,22 +132,55 @@
for (var i = 0; i < policies.length; i++) { for (var i = 0; i < policies.length; i++) {
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', same_origin_src, policies[i].sameOriginTestExpect, 'fullscreen', same_origin_src, undefined,
policies[i].sameOriginTestExpect,
'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true); 'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
}, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
'" and allowfullscreen.'); '" and allowfullscreen.');
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect, 'fullscreen', cross_origin_src, undefined,
policies[i].crossOriginTestExpect,
'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true); 'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
}, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
'" and allowfullscreen.'); '" and allowfullscreen.');
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', cross_origin_src1, policies[i].crossOrigin1TestExpect, 'fullscreen', cross_origin_src1, undefined,
policies[i].crossOrigin1TestExpect,
'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true); 'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
}, 'Test frame policy on another cross origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on another cross origin iframe with allow = "' + policies[i].allow +
'" and allowfullscreen.'); '" 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> </script>
</body> </body>

View File

@@ -10,11 +10,12 @@
var cross_origin = 'https://{{domains[www]}}:{{ports[https][0]}}'; var cross_origin = 'https://{{domains[www]}}:{{ports[https][0]}}';
var same_origin_src = '/feature-policy/resources/feature-policy-allowedfeatures.html'; var same_origin_src = '/feature-policy/resources/feature-policy-allowedfeatures.html';
var cross_origin_src = cross_origin + same_origin_src; var cross_origin_src = cross_origin + same_origin_src;
var data_src = 'data:text/html,<h1>data: URL</h1>';
var policies = [ var policies = [
{allow: "*", sameOriginTestExpect: false, crossOriginTestExpect: false}, {allow: "*", sameOriginTestExpect: false, crossOriginTestExpect: false, dataOriginTestExpect: false},
{allow: "'self'", sameOriginTestExpect: false, crossOriginTestExpect: false}, {allow: "'self'", sameOriginTestExpect: false, crossOriginTestExpect: false, dataOriginTestExpect: false},
{allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false}, {allow: "'none'", sameOriginTestExpect: false, crossOriginTestExpect: false, dataOriginTestExpect: false},
{allow: "'self' " + cross_origin + " https://www.example.com", sameOriginTestExpect: false, crossOriginTestExpect: 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_front = '?pipe=sub|header(Feature-Policy,fullscreen ';
var pipe_end = ';)'; var pipe_end = ';)';
var header_policies = ["*", "'self'", "'none'"]; var header_policies = ["*", "'self'", "'none'"];
@@ -22,24 +23,58 @@
// Test that frame.policy inherits from parent's header policy when allow // Test that frame.policy inherits from parent's header policy when allow
// attribute is not specified. // attribute is not specified.
test(function() { 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 frame policy on same origin iframe inherit from header policy.');
test(function() { 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 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. // Test frame policy with allow attribute set to be one of the policies above.
for (var i = 0; i < policies.length; i++) { for (var i = 0; i < policies.length; i++) {
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', same_origin_src, policies[i].sameOriginTestExpect, 'fullscreen', same_origin_src, undefined,
policies[i].sameOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + '".'); }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + '".');
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect, 'fullscreen', cross_origin_src, undefined,
policies[i].crossOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on cross origin iframe with allow = "' + 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 // Test that the header policy of the iframe document does not change the
@@ -50,7 +85,7 @@
test_frame_policy( test_frame_policy(
'fullscreen', 'fullscreen',
same_origin_src + pipe_front + header_policies[j] + pipe_end, same_origin_src + pipe_front + header_policies[j] + pipe_end,
policies[i].sameOriginTestExpect, undefined, policies[i].sameOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
'" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".'); '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
@@ -58,7 +93,7 @@
test_frame_policy( test_frame_policy(
'fullscreen', 'fullscreen',
cross_origin_src + pipe_front + header_policies[j] + pipe_end, cross_origin_src + pipe_front + header_policies[j] + pipe_end,
policies[i].crossOriginTestExpect, undefined, policies[i].crossOriginTestExpect,
'fullscreen ' + policies[i].allow + ';'); 'fullscreen ' + policies[i].allow + ';');
}, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
'" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".'); '" and header policy = "Feature-Policy: fullscreen ' + header_policies[j] + ';".');
@@ -69,16 +104,42 @@
for (var i = 0; i < policies.length; i++) { for (var i = 0; i < policies.length; i++) {
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', same_origin_src, policies[i].sameOriginTestExpect, 'fullscreen', same_origin_src, undefined,
policies[i].sameOriginTestExpect,
'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true); 'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
}, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on same origin iframe with allow = "' + policies[i].allow +
'" and allowfullscreen.'); '" and allowfullscreen.');
test(function() { test(function() {
test_frame_policy( test_frame_policy(
'fullscreen', cross_origin_src, policies[i].crossOriginTestExpect, 'fullscreen', cross_origin_src, undefined,
policies[i].crossOriginTestExpect,
'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true); 'fullscreen ' + policies[i].allow + ';', /*allowfullscreen*/true);
}, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow + }, 'Test frame policy on cross origin iframe with allow = "' + policies[i].allow +
'" and allowfullscreen.'); '" 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> </script>
</body> </body>

View File

@@ -396,14 +396,15 @@ function test_subframe_header_policy(
// by iframe allow attribute. // by iframe allow attribute.
// Arguments: // Arguments:
// feature: feature name. // 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. // test_expect: boolean value of whether the feature should be allowed.
// allow: optional, the allow attribute (container policy) of the iframe. // allow: optional, the allow attribute (container policy) of the iframe.
// allowfullscreen: optional, boolean value of allowfullscreen attribute. // allowfullscreen: optional, boolean value of allowfullscreen attribute.
// sandbox: optional boolean. If true, the frame will be sandboxed (with // sandbox: optional boolean. If true, the frame will be sandboxed (with
// allow-scripts, so that tests can run in it.) // allow-scripts, so that tests can run in it.)
function test_frame_policy( function test_frame_policy(
feature, src, test_expect, allow, allowfullscreen, sandbox) { feature, src, srcdoc, test_expect, allow, allowfullscreen, sandbox) {
let frame = document.createElement('iframe'); let frame = document.createElement('iframe');
document.body.appendChild(frame); document.body.appendChild(frame);
// frame_policy should be dynamically updated as allow and allowfullscreen is // frame_policy should be dynamically updated as allow and allowfullscreen is
@@ -418,7 +419,12 @@ function test_frame_policy(
if (!!sandbox) { if (!!sandbox) {
frame.setAttribute('sandbox', 'allow-scripts'); frame.setAttribute('sandbox', 'allow-scripts');
} }
if (!!src) {
frame.src = src; frame.src = src;
}
if (!!srcdoc) {
frame.srcdoc = "<h1>Hello world!</h1>";
}
if (test_expect) { if (test_expect) {
assert_true(frame_policy.allowedFeatures().includes(feature)); assert_true(frame_policy.allowedFeatures().includes(feature));
} else { } else {