Filter out Origin-trial features from Feature Policy JS API
Bug: 939953
Change-Id: I856d141f02b483c5fcb8a506e2ed66308395ea99
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1511828
Commit-Queue: Ian Clelland <iclelland@chromium.org>
Reviewed-by: Luna Lu <loonybear@chromium.org>
Cr-Commit-Position: refs/heads/master@{#639602}
diff --git a/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc b/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc
index b8da5b0..6aefc32 100644
--- a/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc
+++ b/third_party/blink/renderer/core/feature_policy/dom_feature_policy.cc
@@ -7,13 +7,17 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/feature_policy/feature_policy.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
namespace blink {
-bool DOMFeaturePolicy::allowsFeature(const String& feature) const {
- if (GetDefaultFeatureNameMap().Contains(feature)) {
+bool DOMFeaturePolicy::allowsFeature(ScriptState* script_state,
+ const String& feature) const {
+ ExecutionContext* execution_context =
+ script_state ? ExecutionContext::From(script_state) : nullptr;
+ if (GetAvailableFeatures(execution_context).Contains(feature)) {
auto feature_name = GetDefaultFeatureNameMap().at(feature);
mojom::PolicyValueType feature_type =
GetPolicy()->GetFeatureList().at(feature_name).second;
@@ -25,8 +29,11 @@
return false;
}
-bool DOMFeaturePolicy::allowsFeature(const String& feature,
+bool DOMFeaturePolicy::allowsFeature(ScriptState* script_state,
+ const String& feature,
const String& url) const {
+ ExecutionContext* execution_context =
+ script_state ? ExecutionContext::From(script_state) : nullptr;
scoped_refptr<const SecurityOrigin> origin =
SecurityOrigin::CreateFromString(url);
if (!origin || origin->IsOpaque()) {
@@ -36,7 +43,7 @@
return false;
}
- if (!GetDefaultFeatureNameMap().Contains(feature)) {
+ if (!GetAvailableFeatures(execution_context).Contains(feature)) {
AddWarningForUnrecognizedFeature(feature);
return false;
}
@@ -49,29 +56,34 @@
origin->ToUrlOrigin(), value);
}
-Vector<String> DOMFeaturePolicy::features() const {
- Vector<String> features;
- for (const auto& entry : GetDefaultFeatureNameMap())
- features.push_back(entry.key);
- return features;
+Vector<String> DOMFeaturePolicy::features(ScriptState* script_state) const {
+ ExecutionContext* execution_context =
+ script_state ? ExecutionContext::From(script_state) : nullptr;
+ return GetAvailableFeatures(execution_context);
}
-Vector<String> DOMFeaturePolicy::allowedFeatures() const {
+Vector<String> DOMFeaturePolicy::allowedFeatures(
+ ScriptState* script_state) const {
+ ExecutionContext* execution_context =
+ script_state ? ExecutionContext::From(script_state) : nullptr;
Vector<String> allowed_features;
- for (const auto& entry : GetDefaultFeatureNameMap()) {
- auto feature_name = entry.value;
+ for (const String& feature : GetAvailableFeatures(execution_context)) {
+ auto feature_name = GetDefaultFeatureNameMap().at(feature);
mojom::PolicyValueType feature_type =
GetPolicy()->GetFeatureList().at(feature_name).second;
PolicyValue value = PolicyValue::CreateMaxPolicyValue(feature_type);
if (GetPolicy()->IsFeatureEnabled(feature_name, value))
- allowed_features.push_back(entry.key);
+ allowed_features.push_back(feature);
}
return allowed_features;
}
Vector<String> DOMFeaturePolicy::getAllowlistForFeature(
+ ScriptState* script_state,
const String& feature) const {
- if (GetDefaultFeatureNameMap().Contains(feature)) {
+ ExecutionContext* execution_context =
+ script_state ? ExecutionContext::From(script_state) : nullptr;
+ if (GetAvailableFeatures(execution_context).Contains(feature)) {
auto feature_name = GetDefaultFeatureNameMap().at(feature);
auto feature_type = GetPolicy()->GetFeatureList().at(feature_name).second;
diff --git a/third_party/blink/renderer/core/feature_policy/dom_feature_policy.h b/third_party/blink/renderer/core/feature_policy/dom_feature_policy.h
index e9766df..adac437 100644
--- a/third_party/blink/renderer/core/feature_policy/dom_feature_policy.h
+++ b/third_party/blink/renderer/core/feature_policy/dom_feature_policy.h
@@ -13,6 +13,7 @@
namespace blink {
class Document;
+class ScriptState;
class SecurityOrigin;
// DOMFeaturePolicy provides an interface for feature policy introspection of a
@@ -26,17 +27,20 @@
// Implementation of methods of the policy interface:
// Returns whether or not the given feature is allowed on the origin of the
// document that owns the policy.
- bool allowsFeature(const String& feature) const;
+ bool allowsFeature(ScriptState* script_state, const String& feature) const;
// Returns whether or not the given feature is allowed on the origin of the
// given URL.
- bool allowsFeature(const String& feature, const String& url) const;
+ bool allowsFeature(ScriptState* script_state,
+ const String& feature,
+ const String& url) const;
// Returns a list of feature names that are supported by the user agent.
- Vector<String> features() const;
+ Vector<String> features(ScriptState* script_state) const;
// Returns a list of feature names that are allowed on the self origin.
- Vector<String> allowedFeatures() const;
+ Vector<String> allowedFeatures(ScriptState* script_state) const;
// Returns a list of feature name that are allowed on the origin of the given
// URL.
- Vector<String> getAllowlistForFeature(const String& url) const;
+ Vector<String> getAllowlistForFeature(ScriptState* script_state,
+ const String& url) const;
// Inform the DOMFeaturePolicy object when the container policy on its frame
// element has changed.
diff --git a/third_party/blink/renderer/core/feature_policy/feature_policy.cc b/third_party/blink/renderer/core/feature_policy/feature_policy.cc
index e7ea055..cd38b8d 100644
--- a/third_party/blink/renderer/core/feature_policy/feature_policy.cc
+++ b/third_party/blink/renderer/core/feature_policy/feature_policy.cc
@@ -305,6 +305,8 @@
mojom::FeaturePolicyFeature::kSpeaker);
default_feature_name_map.Set("sync-xhr",
mojom::FeaturePolicyFeature::kSyncXHR);
+ default_feature_name_map.Set("frobulate",
+ mojom::FeaturePolicyFeature::kFrobulate);
// Under origin trial: Should be made conditional on WebVR and WebXR
// runtime flags once it is out of trial.
ASSERT_ORIGIN_TRIAL(WebVR);
@@ -391,6 +393,15 @@
return default_feature_name_map;
}
+const Vector<String> GetAvailableFeatures(ExecutionContext* execution_context) {
+ Vector<String> available_features;
+ for (const auto& feature : GetDefaultFeatureNameMap()) {
+ if (!IsOriginTrialDisabled(feature.key, execution_context))
+ available_features.push_back(feature.key);
+ }
+ return available_features;
+}
+
const String& GetNameForFeature(mojom::FeaturePolicyFeature feature) {
for (const auto& entry : GetDefaultFeatureNameMap()) {
if (entry.value == feature)
diff --git a/third_party/blink/renderer/core/feature_policy/feature_policy.h b/third_party/blink/renderer/core/feature_policy/feature_policy.h
index 9cf3ee59..54e5521 100644
--- a/third_party/blink/renderer/core/feature_policy/feature_policy.h
+++ b/third_party/blink/renderer/core/feature_policy/feature_policy.h
@@ -26,6 +26,10 @@
typedef HashMap<String, mojom::FeaturePolicyFeature> FeatureNameMap;
CORE_EXPORT const FeatureNameMap& GetDefaultFeatureNameMap();
+// Returns the list of features which are currently available in this context,
+// including any features which have been made available by an origin trial.
+CORE_EXPORT const Vector<String> GetAvailableFeatures(ExecutionContext*);
+
// Converts a header policy string into a vector of allowlists, one for each
// feature specified. Unrecognized features are filtered out. If |messages| is
// not null, then any message in the input will cause a warning message to be
diff --git a/third_party/blink/renderer/core/feature_policy/feature_policy.idl b/third_party/blink/renderer/core/feature_policy/feature_policy.idl
index e2f45f8..cebf39d 100644
--- a/third_party/blink/renderer/core/feature_policy/feature_policy.idl
+++ b/third_party/blink/renderer/core/feature_policy/feature_policy.idl
@@ -8,8 +8,8 @@
RuntimeEnabled=FeaturePolicyJavaScriptInterface,
ImplementedAs=DOMFeaturePolicy
] interface FeaturePolicy {
- [MeasureAs=FeaturePolicyJSAPI] boolean allowsFeature(DOMString feature, optional DOMString url);
- [MeasureAs=FeaturePolicyJSAPI] sequence<DOMString> features();
- [MeasureAs=FeaturePolicyJSAPI] sequence<DOMString> allowedFeatures();
- [MeasureAs=FeaturePolicyJSAPI] sequence<DOMString> getAllowlistForFeature(DOMString feature);
+ [MeasureAs=FeaturePolicyJSAPI, CallWith=ScriptState] boolean allowsFeature(DOMString feature, optional DOMString url);
+ [MeasureAs=FeaturePolicyJSAPI, CallWith=ScriptState] sequence<DOMString> features();
+ [MeasureAs=FeaturePolicyJSAPI, CallWith=ScriptState] sequence<DOMString> allowedFeatures();
+ [MeasureAs=FeaturePolicyJSAPI, CallWith=ScriptState] sequence<DOMString> getAllowlistForFeature(DOMString feature);
};
diff --git a/third_party/blink/renderer/core/feature_policy/policy_test.cc b/third_party/blink/renderer/core/feature_policy/policy_test.cc
index 3101b3d..b7a13b6e 100644
--- a/third_party/blink/renderer/core/feature_policy/policy_test.cc
+++ b/third_party/blink/renderer/core/feature_policy/policy_test.cc
@@ -57,40 +57,42 @@
};
TEST_F(DocumentPolicyTest, TestAllowsFeature) {
- EXPECT_FALSE(GetPolicy()->allowsFeature("badfeature"));
- EXPECT_FALSE(GetPolicy()->allowsFeature("midi"));
- EXPECT_FALSE(GetPolicy()->allowsFeature("midi", kSelfOrigin));
- EXPECT_TRUE(GetPolicy()->allowsFeature("fullscreen"));
- EXPECT_TRUE(GetPolicy()->allowsFeature("fullscreen", kOriginA));
- EXPECT_TRUE(GetPolicy()->allowsFeature("payment"));
- EXPECT_FALSE(GetPolicy()->allowsFeature("payment", kOriginA));
- EXPECT_FALSE(GetPolicy()->allowsFeature("payment", kOriginB));
- EXPECT_TRUE(GetPolicy()->allowsFeature("camera"));
- EXPECT_TRUE(GetPolicy()->allowsFeature("camera", kOriginA));
- EXPECT_TRUE(GetPolicy()->allowsFeature("camera", kOriginB));
- EXPECT_FALSE(GetPolicy()->allowsFeature("camera", "https://badorigin.com"));
- EXPECT_TRUE(GetPolicy()->allowsFeature("geolocation", kSelfOrigin));
- EXPECT_TRUE(GetPolicy()->allowsFeature("sync-xhr"));
- EXPECT_TRUE(GetPolicy()->allowsFeature("sync-xhr", kOriginA));
+ EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "badfeature"));
+ EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "midi"));
+ EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "midi", kSelfOrigin));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "fullscreen"));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "fullscreen", kOriginA));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "payment"));
+ EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "payment", kOriginA));
+ EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "payment", kOriginB));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "camera"));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "camera", kOriginA));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "camera", kOriginB));
+ EXPECT_FALSE(
+ GetPolicy()->allowsFeature(nullptr, "camera", "https://badorigin.com"));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "geolocation", kSelfOrigin));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "sync-xhr"));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "sync-xhr", kOriginA));
}
TEST_F(DocumentPolicyTest, TestGetAllowList) {
- EXPECT_THAT(GetPolicy()->getAllowlistForFeature("camera"),
+ EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "camera"),
UnorderedElementsAre(kSelfOrigin, kOriginA, kOriginB));
- EXPECT_THAT(GetPolicy()->getAllowlistForFeature("payment"),
+ EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "payment"),
UnorderedElementsAre(kSelfOrigin));
- EXPECT_THAT(GetPolicy()->getAllowlistForFeature("geolocation"),
+ EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "geolocation"),
UnorderedElementsAre(kSelfOrigin));
- EXPECT_THAT(GetPolicy()->getAllowlistForFeature("fullscreen"),
+ EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "fullscreen"),
UnorderedElementsAre("*"));
- EXPECT_TRUE(GetPolicy()->getAllowlistForFeature("badfeature").IsEmpty());
- EXPECT_TRUE(GetPolicy()->getAllowlistForFeature("midi").IsEmpty());
- EXPECT_THAT(GetPolicy()->getAllowlistForFeature("sync-xhr"),
+ EXPECT_TRUE(
+ GetPolicy()->getAllowlistForFeature(nullptr, "badfeature").IsEmpty());
+ EXPECT_TRUE(GetPolicy()->getAllowlistForFeature(nullptr, "midi").IsEmpty());
+ EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "sync-xhr"),
UnorderedElementsAre("*"));
}
TEST_F(DocumentPolicyTest, TestAllowedFeatures) {
- Vector<String> allowed_features = GetPolicy()->allowedFeatures();
+ Vector<String> allowed_features = GetPolicy()->allowedFeatures(nullptr);
EXPECT_TRUE(allowed_features.Contains("fullscreen"));
EXPECT_TRUE(allowed_features.Contains("payment"));
EXPECT_TRUE(allowed_features.Contains("camera"));
@@ -103,41 +105,43 @@
}
TEST_F(IFramePolicyTest, TestAllowsFeature) {
- EXPECT_FALSE(GetPolicy()->allowsFeature("badfeature"));
- EXPECT_FALSE(GetPolicy()->allowsFeature("midi"));
- EXPECT_FALSE(GetPolicy()->allowsFeature("midi", kSelfOrigin));
- EXPECT_TRUE(GetPolicy()->allowsFeature("fullscreen"));
- EXPECT_FALSE(GetPolicy()->allowsFeature("fullscreen", kOriginA));
- EXPECT_TRUE(GetPolicy()->allowsFeature("fullscreen", kSelfOrigin));
- EXPECT_TRUE(GetPolicy()->allowsFeature("payment"));
- EXPECT_FALSE(GetPolicy()->allowsFeature("payment", kOriginA));
- EXPECT_FALSE(GetPolicy()->allowsFeature("payment", kOriginB));
- EXPECT_TRUE(GetPolicy()->allowsFeature("camera"));
- EXPECT_FALSE(GetPolicy()->allowsFeature("camera", kOriginA));
- EXPECT_FALSE(GetPolicy()->allowsFeature("camera", kOriginB));
- EXPECT_FALSE(GetPolicy()->allowsFeature("camera", "https://badorigin.com"));
- EXPECT_TRUE(GetPolicy()->allowsFeature("geolocation", kSelfOrigin));
- EXPECT_TRUE(GetPolicy()->allowsFeature("sync-xhr"));
- EXPECT_TRUE(GetPolicy()->allowsFeature("sync-xhr", kOriginA));
+ EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "badfeature"));
+ EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "midi"));
+ EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "midi", kSelfOrigin));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "fullscreen"));
+ EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "fullscreen", kOriginA));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "fullscreen", kSelfOrigin));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "payment"));
+ EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "payment", kOriginA));
+ EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "payment", kOriginB));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "camera"));
+ EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "camera", kOriginA));
+ EXPECT_FALSE(GetPolicy()->allowsFeature(nullptr, "camera", kOriginB));
+ EXPECT_FALSE(
+ GetPolicy()->allowsFeature(nullptr, "camera", "https://badorigin.com"));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "geolocation", kSelfOrigin));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "sync-xhr"));
+ EXPECT_TRUE(GetPolicy()->allowsFeature(nullptr, "sync-xhr", kOriginA));
}
TEST_F(IFramePolicyTest, TestGetAllowList) {
- EXPECT_THAT(GetPolicy()->getAllowlistForFeature("camera"),
+ EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "camera"),
UnorderedElementsAre(kSelfOrigin));
- EXPECT_THAT(GetPolicy()->getAllowlistForFeature("payment"),
+ EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "payment"),
UnorderedElementsAre(kSelfOrigin));
- EXPECT_THAT(GetPolicy()->getAllowlistForFeature("geolocation"),
+ EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "geolocation"),
UnorderedElementsAre(kSelfOrigin));
- EXPECT_THAT(GetPolicy()->getAllowlistForFeature("fullscreen"),
+ EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "fullscreen"),
UnorderedElementsAre(kSelfOrigin));
- EXPECT_TRUE(GetPolicy()->getAllowlistForFeature("badfeature").IsEmpty());
- EXPECT_TRUE(GetPolicy()->getAllowlistForFeature("midi").IsEmpty());
- EXPECT_THAT(GetPolicy()->getAllowlistForFeature("sync-xhr"),
+ EXPECT_TRUE(
+ GetPolicy()->getAllowlistForFeature(nullptr, "badfeature").IsEmpty());
+ EXPECT_TRUE(GetPolicy()->getAllowlistForFeature(nullptr, "midi").IsEmpty());
+ EXPECT_THAT(GetPolicy()->getAllowlistForFeature(nullptr, "sync-xhr"),
UnorderedElementsAre("*"));
}
TEST_F(IFramePolicyTest, TestAllowedFeatures) {
- Vector<String> allowed_features = GetPolicy()->allowedFeatures();
+ Vector<String> allowed_features = GetPolicy()->allowedFeatures(nullptr);
EXPECT_TRUE(allowed_features.Contains("fullscreen"));
EXPECT_TRUE(allowed_features.Contains("payment"));
EXPECT_TRUE(allowed_features.Contains("camera"));
@@ -156,7 +160,7 @@
SecurityOrigin::CreateFromString(kOriginA), nullptr);
GetPolicy()->UpdateContainerPolicy(
container_policy, SecurityOrigin::CreateFromString(kOriginA));
- Vector<String> allowed_features = GetPolicy()->allowedFeatures();
+ Vector<String> allowed_features = GetPolicy()->allowedFeatures(nullptr);
EXPECT_TRUE(allowed_features.Contains("fullscreen"));
EXPECT_FALSE(allowed_features.Contains("payment"));
EXPECT_TRUE(allowed_features.Contains("geolocation"));
diff --git a/third_party/blink/web_tests/http/tests/feature-policy/no_origin_trial_policy.php b/third_party/blink/web_tests/http/tests/feature-policy/no_origin_trial_policy.php
new file mode 100644
index 0000000..56568fa
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/feature-policy/no_origin_trial_policy.php
@@ -0,0 +1,33 @@
+<?php
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+header("Feature-Policy: frobulate *");
+?>
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(function() {
+ assert_false(document.featurePolicy.allowsFeature("frobulate"));
+}, 'Test featurePolicy.allowsFeature() on unavailable origin trial feature');
+
+test(function() {
+ assert_false(document.featurePolicy.allowsFeature("frobulate", "https://www.example.com"));
+}, 'Test featurePolicy.allowsFeature() on unavailable origin trial feature for specific origin');
+
+test(function() {
+ assert_false(document.featurePolicy.features().includes("frobulate"));
+}, 'Test featurePolicy.features() should not include origin trial feature');
+
+test(function() {
+ assert_false(document.featurePolicy.allowedFeatures().includes("frobulate"));
+}, 'Test featurePolicy.allowedFeatures() should not include origin trial feature');
+
+test(function() {
+ assert_array_equals(
+ document.featurePolicy.getAllowlistForFeature("frobulate"), [])
+}, "Origin trial features should not have an allowlist.");
+
+</script>
diff --git a/third_party/blink/web_tests/http/tests/feature-policy/origin_trial_policy.php b/third_party/blink/web_tests/http/tests/feature-policy/origin_trial_policy.php
new file mode 100644
index 0000000..52903ed
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/feature-policy/origin_trial_policy.php
@@ -0,0 +1,40 @@
+<?php
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+header("Feature-Policy: frobulate *");
+
+// TODO(iclelland): Generate this sample token during the build. The token
+// below will expire in 2033, but it would be better to always have a token which
+// is guaranteed to be valid when the tests are run.
+// Generate this token with the command:
+// generate_token.py http://127.0.0.1:8000 Frobulate -expire-timestamp=2000000000
+header("Origin-Trial: AlCoOPbezqtrGMzSzbLQC4c+oPqO6yuioemcBPjgcXajF8jtmZr4B8tJRPAARPbsX6hDeVyXCKHzEJfpBXvZgQEAAABReyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiRnJvYnVsYXRlIiwgImV4cGlyeSI6IDIwMDAwMDAwMDB9");
+?>
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(function() {
+ assert_true(document.featurePolicy.allowsFeature("frobulate"));
+}, 'Test featurePolicy.allowsFeature() on origin trial feature');
+
+test(function() {
+ assert_true(document.featurePolicy.allowsFeature("frobulate", "https://www.example.com"));
+}, 'Test featurePolicy.allowsFeature() on origin trial feature for specific origin');
+
+test(function() {
+ assert_true(document.featurePolicy.features().includes("frobulate"));
+}, 'Test featurePolicy.features() includes origin trial feature');
+
+test(function() {
+ assert_true(document.featurePolicy.allowedFeatures().includes("frobulate"));
+}, 'Test featurePolicy.allowedFeatures() includes origin trial feature');
+
+test(function() {
+ assert_array_equals(
+ document.featurePolicy.getAllowlistForFeature("frobulate"), ["*"])
+}, "Origin trial feature is allowed for all in main frame");
+
+</script>