Skip to content

Commit

Permalink
Feature control for Speculation Rules + Prefetch Proxy.
Browse files Browse the repository at this point in the history
This makes the Blink runtime-enabled features "SpeculationRules"
controllable by a second, "SpeculationRulesPrefetchProxy", which is
linked to an origin trial name. That trial can be enabled only if
the browser-side blink::features::kSpeculationRulesPrefetchProxy
is also enabled (universally, via Finch, etc).

This slightly awkward division exists because we are considering
a possibly overlapping experiment launch of other pre* capabilities
which might share the speculation rules API surface, and it's not
necessarily desirable for enabling one to also enable the other.

This setup makes subsequently landing such a change, without breaking
origin trial tokens issued for the purposes of a prefetch proxy
experiment, straightforward -- they could create a parallel browser
feature and OT-controlled REF, and forward information about which
trials were enabled in their messages to the browser.

Bug: 1190167
Change-Id: Ic04876fef47ada104b00f8c2a039c8c1d3b302a6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2773722
Reviewed-by: Ryan Sturm <ryansturm@chromium.org>
Reviewed-by: Ian Clelland <iclelland@chromium.org>
Commit-Queue: Jeremy Roman <jbroman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#865799}
  • Loading branch information
jeremyroman authored and Chromium LUCI CQ committed Mar 23, 2021
1 parent 55a65af commit 49c675c
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 0 deletions.
6 changes: 6 additions & 0 deletions third_party/blink/common/features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,12 @@ const base::Feature kWebRtcH264WithOpenH264FFmpeg{
const base::Feature kServiceWorkerUpdateDelay{
"ServiceWorkerUpdateDelay", base::FEATURE_DISABLED_BY_DEFAULT};

// Enable the use of Speculation Rules in access the private prefetch proxy
// (chrome/browser/prefetch/prefetch_proxy/).
// https://crbug.com/1190167
const base::Feature kSpeculationRulesPrefetchProxy{
"SpeculationRulesPrefetchProxy", base::FEATURE_DISABLED_BY_DEFAULT};

// Freeze scheduler task queues in background after allowed grace time.
// "stop" is a legacy name.
const base::Feature kStopInBackground {
Expand Down
1 change: 1 addition & 0 deletions third_party/blink/public/common/features.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ BLINK_COMMON_EXPORT extern const base::Feature kWebRtcH264WithOpenH264FFmpeg;

BLINK_COMMON_EXPORT extern const base::Feature kResourceLoadViaDataPipe;
BLINK_COMMON_EXPORT extern const base::Feature kServiceWorkerUpdateDelay;
BLINK_COMMON_EXPORT extern const base::Feature kSpeculationRulesPrefetchProxy;
BLINK_COMMON_EXPORT extern const base::Feature kStopInBackground;
BLINK_COMMON_EXPORT extern const base::Feature
kFreezeBackgroundTabOnNetworkIdle;
Expand Down
1 change: 1 addition & 0 deletions third_party/blink/renderer/core/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -1577,6 +1577,7 @@ source_set("unit_tests") {
"scroll/scrollbar_test_suite.h",
"scroll/scrollbar_theme_overlay_test.cc",
"speculation_rules/speculation_rule_set_test.cc",
"speculation_rules/speculation_rules_origin_trial_test.cc",
"streams/miscellaneous_operations_test.cc",
"streams/queue_with_sizes_test.cc",
"streams/readable_stream_test.cc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,10 @@ bool OriginTrialContext::CanEnableTrialFromName(const StringView& trial_name) {
!base::FeatureList::IsEnabled(features::kInterestCohortAPIOriginTrial)) {
return false;
}
if (trial_name == "SpeculationRulesPrefetchProxy" &&
!base::FeatureList::IsEnabled(features::kSpeculationRulesPrefetchProxy)) {
return false;
}
return true;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Copyright 2021 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.

#include <vector>
#include "base/bind.h"
#include "base/stl_util.h"
#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/origin_trials/origin_trial_policy.h"
#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/html/html_head_element.h"
#include "third_party/blink/renderer/core/html/html_meta_element.h"
#include "third_party/blink/renderer/core/html/html_script_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/speculation_rules/document_speculation_rules.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"

namespace blink {
namespace {

constexpr char kOriginTrialPublicKey[] = {
0x75, 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2,
0x9a, 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f,
0x64, 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0,
};

// Generated by:
// tools/origin_trials/generate_token.py --version 3 --expire-days 3650 \
// https://speculationrules.test SpeculationRulesPrefetchProxy
// Token details:
// Version: 3
// Origin: https://speculationrules.test:443
// Is Subdomain: None
// Is Third Party: None
// Usage Restriction: None
// Feature: SpeculationRulesPrefetchProxy
// Expiry: 1931530579 (2031-03-17 16:16:19 UTC)
// Signature (Base64):
// wi1W6f/KsmwaJn7GrnT8LrPRtGPkcRHwkgf6goMPozWlsFFM6tZq/jaTZCe34llBgwy2YYqzc58s3oz3sIFmAw==

constexpr char kSpeculationRulesPrefetchProxyToken[] =
"A8ItVun/yrJsGiZ+xq50/C6z0bRj5HER8JIH+oKDD6M1pbBRTOrWav42k2Qnt+JZQY"
"MMtmGKs3OfLN6M97CBZgMAAABxeyJvcmlnaW4iOiAiaHR0cHM6Ly9zcGVjdWxhdGlv"
"bnJ1bGVzLnRlc3Q6NDQzIiwgImZlYXR1cmUiOiAiU3BlY3VsYXRpb25SdWxlc1ByZW"
"ZldGNoUHJveHkiLCAiZXhwaXJ5IjogMTkzMTUzMDU3OX0=";

constexpr char kSimplePrefetchProxyRuleSet[] =
R"({
"prefetch": [{
"source": "list",
"urls": ["//example.com/index2.html"],
"requires": ["anonymous-client-ip-when-cross-origin"]
}]
})";

class ScopedOriginTrialPolicy : public OriginTrialPolicy {
public:
ScopedOriginTrialPolicy() {
TrialTokenValidator::SetOriginTrialPolicyGetter(WTF::BindRepeating(
[](OriginTrialPolicy* self) { return self; }, base::Unretained(this)));
}
~ScopedOriginTrialPolicy() override {
TrialTokenValidator::ResetOriginTrialPolicyGetter();
}
bool IsOriginTrialsSupported() const override { return true; }
std::vector<base::StringPiece> GetPublicKeys() const override {
return {{kOriginTrialPublicKey, base::size(kOriginTrialPublicKey)}};
}
bool IsOriginSecure(const GURL& url) const override { return true; }
};

// Similar to SpeculationRuleSettest.PropagatesToDocument.
::testing::AssertionResult DocumentAcceptsRuleSet(const char* trial_token,
const char* json) {
DummyPageHolder page_holder;
Document& document = page_holder.GetDocument();

// Clear the security origin and set a secure one, recomputing the security
// state.
SecurityContext& security_context =
page_holder.GetFrame().DomWindow()->GetSecurityContext();
security_context.SetSecurityOriginForTesting(nullptr);
security_context.SetSecurityOrigin(
SecurityOrigin::CreateFromString("https://speculationrules.test"));
EXPECT_EQ(security_context.GetSecureContextMode(),
SecureContextMode::kSecureContext);

// Enable scripts so that <script> is not ignored.
page_holder.GetFrame().GetSettings()->SetScriptEnabled(true);

HTMLMetaElement* meta = MakeGarbageCollected<HTMLMetaElement>(document);
meta->setAttribute(html_names::kHttpEquivAttr, "Origin-Trial");
meta->setAttribute(html_names::kContentAttr, trial_token);
document.head()->appendChild(meta);

HTMLScriptElement* script =
MakeGarbageCollected<HTMLScriptElement>(document, CreateElementFlags());
script->setAttribute(html_names::kTypeAttr, "speculationrules");
script->setText(json);
document.head()->appendChild(script);

auto* supplement = DocumentSpeculationRules::FromIfExists(document);
return (supplement && !supplement->rule_sets().IsEmpty())
? ::testing::AssertionSuccess() << "a rule set was found"
: ::testing::AssertionFailure() << "no rule set was found";
}

// Without the corresponding base::Feature, this trial token should not be
// accepted.
TEST(SpeculationRulesOriginTrialTest, RequiresBaseFeature) {
base::test::ScopedFeatureList scoped_features;
scoped_features.InitAndDisableFeature(
features::kSpeculationRulesPrefetchProxy);
ScopedOriginTrialPolicy using_test_keys;

EXPECT_FALSE(DocumentAcceptsRuleSet(kSpeculationRulesPrefetchProxyToken,
kSimplePrefetchProxyRuleSet));
}

// Without a valid origin trial token, this feature should not be exposed.
TEST(SpeculationRulesOriginTrialTest, RequiresValidToken) {
base::test::ScopedFeatureList scoped_features;
scoped_features.InitAndEnableFeature(
features::kSpeculationRulesPrefetchProxy);
ScopedOriginTrialPolicy using_test_keys;

EXPECT_FALSE(
DocumentAcceptsRuleSet("invalid token", kSimplePrefetchProxyRuleSet));
}

// With the feature and a matching token, speculation rules should be turned on.
TEST(SpeculationRulesOriginTrialTest, BaseFeatureAndValidTokenSuffice) {
base::test::ScopedFeatureList scoped_features;
scoped_features.InitAndEnableFeature(
features::kSpeculationRulesPrefetchProxy);
ScopedOriginTrialPolicy using_test_keys;

EXPECT_TRUE(DocumentAcceptsRuleSet(kSpeculationRulesPrefetchProxyToken,
kSimplePrefetchProxyRuleSet));
}

} // namespace
} // namespace blink
12 changes: 12 additions & 0 deletions third_party/blink/renderer/platform/runtime_enabled_features.json5
Original file line number Diff line number Diff line change
Expand Up @@ -1915,8 +1915,20 @@
name: "SkipTouchEventFilter",
settable_from_internals: true,
},
// An origin trial feature name is required for this, even though it's
// actually enabled by the more specific trial. Having these as separate
// features will allow Blink to distinguish for which thing the trial
// was enabled.
{
name: "SpeculationRules",
implied_by: ["SpeculationRulesPrefetchProxy"],
origin_trial_feature_name: "SpeculationRules__DONOTUSE",
},
// Origin trial to enable Speculation Rules for access to the prefetch proxy.
// https://crbug.com/1190167
{
name: "SpeculationRulesPrefetchProxy",
origin_trial_feature_name: "SpeculationRulesPrefetchProxy",
},
{
name: "SrcsetMaxDensity",
Expand Down

0 comments on commit 49c675c

Please sign in to comment.