0

Add race-network-and-cache source to SW router rule mojo and database class.

This CL adds a new race-network-and-cache source to ServiceWorker router
rule mojo and to service worker database class for read/write.

This CL also changes ServiceWorkerRouterSource design by removing
ServiceWorkerRouterRaceSourceEnum and rename RaceSource to
RaceNetworkAndFetchEventSource and SW DB proto accordingly to avoid
confusion with the RaceSource enum.

To support race-network-and-cache source in
https://github.com/WICG/service-worker-static-routing-api/blob/main/final-form.md#race-network-and-cache-storage

Future CLs include changes to ServiceWorker evaluator, resource loaders,
IDL and DevTools.

Bug: 370844790
Change-Id: I13269bcfe6a453fe6dbb89df10b814ee5ef1a125
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6374322
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Liang Zhao <lzhao@microsoft.com>
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
Reviewed-by: Yoshisato Yanagisawa <yyanagisawa@chromium.org>
Commit-Queue: Monica Chintala <monicach@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#1444967}
This commit is contained in:
Monica Chintala
2025-04-09 14:55:17 -07:00
committed by Chromium LUCI CQ
parent fe934d032f
commit 2b0c5e35c7
24 changed files with 296 additions and 259 deletions

@ -148,6 +148,8 @@ namespace {
// set a low write buffer size to trigger compaction more often.
constexpr size_t kWriteBufferSize = 512 * 1024;
using RouterSourceType = network::mojom::ServiceWorkerRouterSourceType;
class ServiceWorkerEnv : public leveldb_env::ChromiumEnv {
public:
ServiceWorkerEnv() : ChromiumEnv(storage::CreateFilesystemProxy()) {}
@ -2788,40 +2790,22 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ParseRegistrationData(
return Status::kErrorCorrupted;
case ServiceWorkerRegistrationData::RouterRules::RuleV1::Source::
kNetworkSource:
source.type =
network::mojom::ServiceWorkerRouterSourceType::kNetwork;
source.type = RouterSourceType::kNetwork;
source.network_source.emplace();
break;
case ServiceWorkerRegistrationData::RouterRules::RuleV1::Source::
kRaceSource: {
source.type = network::mojom::ServiceWorkerRouterSourceType::kRace;
blink::ServiceWorkerRouterRaceSource race_source;
if (s.race_source().has_target()) {
switch (s.race_source().target()) {
case ServiceWorkerRegistrationData::RouterRules::RuleV1::
Source::RaceSource::kNetworkAndFetchHandler:
race_source.target = blink::ServiceWorkerRouterRaceSource::
TargetEnum::kNetworkAndFetchHandler;
kRaceNetworkAndFetchEventSource:
source.type = RouterSourceType::kRaceNetworkAndFetchEvent;
source.race_network_and_fetch_event_source.emplace();
break;
}
} else {
// This happens when reading an old registration.
// It means kNetworkAndFetchHandler.
race_source.target = blink::ServiceWorkerRouterRaceSource::
TargetEnum::kNetworkAndFetchHandler;
}
source.race_source = race_source;
break;
}
case ServiceWorkerRegistrationData::RouterRules::RuleV1::Source::
kFetchEventSource:
source.type =
network::mojom::ServiceWorkerRouterSourceType::kFetchEvent;
source.type = RouterSourceType::kFetchEvent;
source.fetch_event_source.emplace();
break;
case ServiceWorkerRegistrationData::RouterRules::RuleV1::Source::
kCacheSource: {
source.type = network::mojom::ServiceWorkerRouterSourceType::kCache;
source.type = RouterSourceType::kCache;
blink::ServiceWorkerRouterCacheSource cache_source;
if (s.cache_source().has_cache_name()) {
cache_source.cache_name = s.cache_source().cache_name();
@ -2829,6 +2813,21 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ParseRegistrationData(
source.cache_source = cache_source;
break;
}
case ServiceWorkerRegistrationData::RouterRules::RuleV1::Source::
kRaceNetworkAndCacheSource: {
source.type = RouterSourceType::kRaceNetworkAndCache;
source.race_network_and_cache_source.emplace();
const auto& cache_source =
s.race_network_and_cache_source().cache_source();
blink::ServiceWorkerRouterCacheSource cache_source_data;
if (cache_source.has_cache_name()) {
cache_source_data.cache_name = cache_source.cache_name();
}
source.race_network_and_cache_source->cache_source =
cache_source_data;
break;
}
}
router_rule.sources.emplace_back(source);
}
@ -3028,31 +3027,33 @@ void ServiceWorkerDatabase::WriteRegistrationDataInBatch(
ServiceWorkerRegistrationData::RouterRules::RuleV1::Source* source =
v1->add_source();
switch (s.type) {
case network::mojom::ServiceWorkerRouterSourceType::kNetwork:
case RouterSourceType::kNetwork:
source->mutable_network_source();
break;
case network::mojom::ServiceWorkerRouterSourceType::kRace: {
auto* race_source = source->mutable_race_source();
switch (s.race_source->target) {
case blink::ServiceWorkerRouterRaceSource::TargetEnum::
kNetworkAndFetchHandler:
race_source->set_target(
ServiceWorkerRegistrationData::RouterRules::RuleV1::Source::
RaceSource::kNetworkAndFetchHandler);
case RouterSourceType::kRaceNetworkAndFetchEvent:
source->mutable_race_network_and_fetch_event_source();
break;
}
break;
}
case network::mojom::ServiceWorkerRouterSourceType::kFetchEvent:
case RouterSourceType::kFetchEvent:
source->mutable_fetch_event_source();
break;
case network::mojom::ServiceWorkerRouterSourceType::kCache: {
case RouterSourceType::kCache: {
auto* cache_source = source->mutable_cache_source();
if (s.cache_source->cache_name) {
cache_source->set_cache_name(*s.cache_source->cache_name);
}
break;
}
case RouterSourceType::kRaceNetworkAndCache: {
auto* race_network_and_cache_source =
source->mutable_race_network_and_cache_source();
auto* cache_source =
race_network_and_cache_source->mutable_cache_source();
if (s.race_network_and_cache_source->cache_source.cache_name) {
cache_source->set_cache_name(
*s.race_network_and_cache_source->cache_source.cache_name);
}
break;
}
}
}
}

@ -207,21 +207,24 @@ message ServiceWorkerRegistrationData {
}
message Source {
message NetworkSource {}
message RaceSource {
enum Target {
kNetworkAndFetchHandler = 0;
}
optional Target target = 1;
message RaceNetworkAndFetchEventSource {
reserved 1; // Deprecated
reserved "target"; // Deprecated
}
message FetchEventSource {}
message CacheSource {
optional string cache_name = 1;
}
message RaceNetworkAndCacheSource {
required CacheSource cache_source = 1;
}
oneof source {
NetworkSource network_source = 1;
RaceSource race_source = 2;
RaceNetworkAndFetchEventSource race_network_and_fetch_event_source =
2;
FetchEventSource fetch_event_source = 3;
CacheSource cache_source = 4;
RaceNetworkAndCacheSource race_network_and_cache_source = 5;
}
}
repeated Condition condition = 1;

@ -3827,13 +3827,9 @@ TEST(ServiceWorkerDatabaseTest, RouterRulesStoreRestore) {
}
{
blink::ServiceWorkerRouterSource source;
source.type = network::mojom::ServiceWorkerRouterSourceType::kRace;
{
blink::ServiceWorkerRouterRaceSource race_source;
race_source.target = blink::ServiceWorkerRouterRaceSource::TargetEnum::
kNetworkAndFetchHandler;
source.race_source = race_source;
}
source.type = network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent;
source.race_network_and_fetch_event_source.emplace();
rule.sources.push_back(source);
}
{
@ -3856,6 +3852,31 @@ TEST(ServiceWorkerDatabaseTest, RouterRulesStoreRestore) {
source.cache_source = cache_source;
rule.sources.push_back(source);
}
{
// Race network and cache without cache_name.
blink::ServiceWorkerRouterSource source;
source.type =
network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndCache;
source.race_network_and_cache_source.emplace();
blink::ServiceWorkerRouterCacheSource cache_source;
source.race_network_and_cache_source->cache_source = cache_source;
rule.sources.push_back(source);
}
{
// Race network and cache with cache_name.
blink::ServiceWorkerRouterSource source;
source.type =
network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndCache;
source.race_network_and_cache_source.emplace();
blink::ServiceWorkerRouterCacheSource cache_source;
cache_source.cache_name = "example_cache_name";
source.race_network_and_cache_source->cache_source = cache_source;
rule.sources.push_back(source);
}
router_rules.rules.emplace_back(rule);
store_and_restore(router_rules);
@ -3958,57 +3979,4 @@ TEST(ServiceWorkerDatabaseTest, RouterRulesLegacyPathname) {
}
}
TEST(ServiceWorkerDatabaseTest, EnsureNetworkAndFetchHandlerSet) {
std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
ServiceWorkerRegistrationData data;
data.set_registration_id(1);
data.set_scope_url("https://example.com");
data.set_script_url("https://example.com/sw");
data.set_version_id(1);
data.set_is_active(true);
data.set_has_fetch_handler(true);
data.set_last_update_check_time(
base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
database->next_avail_registration_id_ = 2;
database->next_avail_version_id_ = 2;
blink::StorageKey key =
blink::StorageKey::CreateFromStringForTesting(data.scope_url());
{
{
auto* rules = data.mutable_router_rules();
// service_worker_internals::kRouterRuleVersion
// in service_worker_database.cc
rules->set_version(1);
auto* v1 = rules->add_v1();
auto* condition = v1->add_condition();
auto* request = condition->mutable_request();
request->set_method("GET");
auto* source = v1->add_source();
source->mutable_race_source();
}
// Write the serialization.
std::string value;
ASSERT_TRUE(data.SerializeToString(&value));
// Parse the serialized data.
RegistrationDataPtr registration;
ASSERT_EQ(ServiceWorkerDatabase::Status::kOk,
database->ParseRegistrationData(value, key, &registration));
EXPECT_FALSE(registration->router_rules->rules.empty());
// RaceSource should have kNetworkAndFetchHandler target if nothing
// defined.
blink::ServiceWorkerRouterRaceSource race_source;
race_source.target = blink::ServiceWorkerRouterRaceSource::TargetEnum::
kNetworkAndFetchHandler;
EXPECT_EQ(race_source,
registration->router_rules->rules[0].sources[0].race_source);
}
}
} // namespace storage

@ -2095,13 +2095,17 @@ String BuildServiceWorkerRouterSourceType(
switch (type) {
case network::mojom::ServiceWorkerRouterSourceType::kNetwork:
return protocol::Network::ServiceWorkerRouterSourceEnum::Network;
case network::mojom::ServiceWorkerRouterSourceType::kRace:
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent:
return protocol::Network::ServiceWorkerRouterSourceEnum::
RaceNetworkAndFetchHandler;
case network::mojom::ServiceWorkerRouterSourceType::kFetchEvent:
return protocol::Network::ServiceWorkerRouterSourceEnum::FetchEvent;
case network::mojom::ServiceWorkerRouterSourceType::kCache:
return protocol::Network::ServiceWorkerRouterSourceEnum::Cache;
case network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndCache:
return protocol::Network::ServiceWorkerRouterSourceEnum::
RaceNetworkAndCache;
}
}

@ -5231,8 +5231,8 @@ IN_PROC_BROWSER_TEST_P(
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
entry,
MainResourceLoadCompletedUkmEntry::kMatchedFirstRouterSourceTypeName,
static_cast<std::int64_t>(
network::mojom::ServiceWorkerRouterSourceType::kRace));
static_cast<std::int64_t>(network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent));
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
entry, MainResourceLoadCompletedUkmEntry::kActualRouterSourceTypeName,
@ -5606,8 +5606,8 @@ IN_PROC_BROWSER_TEST_P(
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
entry,
MainResourceLoadCompletedUkmEntry::kMatchedFirstRouterSourceTypeName,
static_cast<std::int64_t>(
network::mojom::ServiceWorkerRouterSourceType::kRace));
static_cast<std::int64_t>(network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent));
ukm::TestAutoSetUkmRecorder::ExpectEntryMetric(
entry, MainResourceLoadCompletedUkmEntry::kActualRouterSourceTypeName,

@ -253,7 +253,6 @@ void ServiceWorkerMainResourceLoader::StartRequest(
RaceNetworkRequestMode race_network_request_mode =
RaceNetworkRequestMode::kDefault;
std::optional<blink::ServiceWorkerRouterRaceSource> race_source;
// Check if registered static router rules match the request.
if (active_worker->router_evaluator()) {
CHECK(active_worker->router_evaluator()->IsValid());
@ -328,9 +327,9 @@ void ServiceWorkerMainResourceLoader::StartRequest(
}
return;
}
case network::mojom::ServiceWorkerRouterSourceType::kRace:
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent:
race_network_request_mode = RaceNetworkRequestMode::kForced;
race_source = sources[0].race_source;
break;
case network::mojom::ServiceWorkerRouterSourceType::kFetchEvent:
race_network_request_mode = RaceNetworkRequestMode::kSkipped;
@ -364,6 +363,10 @@ void ServiceWorkerMainResourceLoader::StartRequest(
},
active_worker));
return;
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndCache:
// TODO(crbug.com/370844790): implement race network and cache
break;
}
}
}
@ -384,8 +387,6 @@ void ServiceWorkerMainResourceLoader::StartRequest(
}
if (race_network_request_mode == RaceNetworkRequestMode::kForced) {
CHECK_EQ(race_source->target, blink::ServiceWorkerRouterRaceSource::
TargetEnum::kNetworkAndFetchHandler);
if (base::FeatureList::IsEnabled(
features::
kServiceWorkerStaticRouterRaceNetworkRequestPerformanceImprovement)) {
@ -944,7 +945,8 @@ void ServiceWorkerMainResourceLoader::DidDispatchFetchEvent(
if (auto* route_info = response_head_->service_worker_router_info.get()) {
if (route_info->matched_source_type &&
*route_info->matched_source_type ==
network::mojom::ServiceWorkerRouterSourceType::kRace) {
network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent) {
route_info->actual_source_type =
network::mojom::ServiceWorkerRouterSourceType::kFetchEvent;
} else {
@ -1221,7 +1223,8 @@ void ServiceWorkerMainResourceLoader::SetCommitResponsibility(
if (response_head_ && response_head_->service_worker_router_info &&
response_head_->service_worker_router_info->matched_source_type &&
*response_head_->service_worker_router_info->matched_source_type ==
network::mojom::ServiceWorkerRouterSourceType::kRace &&
network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent &&
fetch_response_from == FetchResponseFrom::kWithoutServiceWorker) {
response_head_->service_worker_router_info->actual_source_type =
network::mojom::ServiceWorkerRouterSourceType::kNetwork;

@ -617,15 +617,20 @@ class ServiceWorkerMainResourceLoaderTest : public testing::Test {
case network::mojom::ServiceWorkerRouterSourceType::kNetwork:
source.network_source.emplace();
break;
case network::mojom::ServiceWorkerRouterSourceType::kRace:
source.race_source.emplace();
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent:
source.race_network_and_fetch_event_source.emplace();
break;
case network::mojom::ServiceWorkerRouterSourceType::kCache:
case network::mojom::ServiceWorkerRouterSourceType::kCache: {
blink::ServiceWorkerRouterCacheSource cache_source;
cache_source.cache_name = kTestCacheName;
source.cache_source = cache_source;
break;
}
case network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndCache:
// TODO(crbug.com/370844790): implement race network and cache
break;
}
rule.sources.emplace_back(source);
rules.rules.emplace_back(rule);
EXPECT_EQ(version_->SetupRouterEvaluator(rules),
@ -1536,7 +1541,8 @@ TEST_F(ServiceWorkerMainResourceLoaderTest, StaticRoutingNetwork) {
TEST_F(ServiceWorkerMainResourceLoaderTest, StaticRoutingRaceNetworkWin) {
base::HistogramTester histogram_tester;
SetupStaticRoutingRules(network::mojom::ServiceWorkerRouterSourceType::kRace);
SetupStaticRoutingRules(
network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndFetchEvent);
service_worker_->DeferResponse();
SetupNetworkResponse();
@ -1559,7 +1565,7 @@ TEST_F(ServiceWorkerMainResourceLoaderTest, StaticRoutingRaceNetworkWin) {
auto expected_info = CreateResponseInfoFromServiceWorker();
expected_info->was_fetched_via_service_worker = false;
auto expected_router_info = CreateExpectedMatchingServiceWorkerRouterInfo(
network::mojom::ServiceWorkerRouterSourceType::kRace);
network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndFetchEvent);
expected_router_info->actual_source_type =
network::mojom::ServiceWorkerRouterSourceType::kNetwork;
expected_info->service_worker_router_info = std::move(expected_router_info);
@ -1587,7 +1593,8 @@ TEST_F(ServiceWorkerMainResourceLoaderTest, StaticRoutingRaceNetworkWin) {
TEST_F(ServiceWorkerMainResourceLoaderTest, StaticRoutingRaceFetchWin) {
base::HistogramTester histogram_tester;
SetupStaticRoutingRules(network::mojom::ServiceWorkerRouterSourceType::kRace);
SetupStaticRoutingRules(
network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndFetchEvent);
SetupErrorNetworkResponse();
@ -1603,7 +1610,7 @@ TEST_F(ServiceWorkerMainResourceLoaderTest, StaticRoutingRaceFetchWin) {
EXPECT_EQ(200, info->headers->response_code());
auto expected_info = CreateResponseInfoFromServiceWorker();
auto expected_router_info = CreateExpectedMatchingServiceWorkerRouterInfo(
network::mojom::ServiceWorkerRouterSourceType::kRace);
network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndFetchEvent);
expected_router_info->actual_source_type =
network::mojom::ServiceWorkerRouterSourceType::kFetchEvent;
expected_info->service_worker_router_info = std::move(expected_router_info);

@ -92,8 +92,10 @@ bool ServiceWorkerResourceLoader::ShouldRecordServiceWorkerFetchStart() {
switch (*matched_router_source_type_) {
case network::mojom::ServiceWorkerRouterSourceType::kNetwork:
case network::mojom::ServiceWorkerRouterSourceType::kCache:
case network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndCache:
return false;
case network::mojom::ServiceWorkerRouterSourceType::kRace:
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent:
case network::mojom::ServiceWorkerRouterSourceType::kFetchEvent:
// These source should start ServiceWorker and trigger fetch-event.
return true;

@ -243,8 +243,9 @@ bool IsValidSources(
return false;
}
break;
case network::mojom::ServiceWorkerRouterSourceType::kRace:
if (!s.race_source) {
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent:
if (!s.race_network_and_fetch_event_source) {
RecordSetupError(
ServiceWorkerRouterEvaluatorErrorEnums::kInvalidSource);
return false;
@ -264,6 +265,13 @@ bool IsValidSources(
return false;
}
break;
case network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndCache:
if (!s.race_network_and_cache_source) {
RecordSetupError(
ServiceWorkerRouterEvaluatorErrorEnums::kInvalidSource);
return false;
}
break;
}
}
return true;
@ -733,9 +741,8 @@ void ServiceWorkerRouterEvaluator::Compile() {
(s.type ==
network::mojom::ServiceWorkerRouterSourceType::kFetchEvent);
bool has_race_network_and_fetch_event =
(s.type == network::mojom::ServiceWorkerRouterSourceType::kRace &&
s.race_source->target == blink::ServiceWorkerRouterRaceSource::
TargetEnum::kNetworkAndFetchHandler);
(s.type == network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent);
require_fetch_handler_ |=
(has_fetch_event | has_race_network_and_fetch_event);
has_non_fetch_event_source_ |= !has_fetch_event;
@ -795,10 +802,8 @@ base::Value ServiceWorkerRouterEvaluator::ToValue() const {
case network::mojom::ServiceWorkerRouterSourceType::kNetwork:
source.Append("network");
break;
case network::mojom::ServiceWorkerRouterSourceType::kRace:
CHECK_EQ(s.race_source->target,
blink::ServiceWorkerRouterRaceSource::TargetEnum::
kNetworkAndFetchHandler);
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent:
source.Append("race-network-and-fetch-handler");
break;
case network::mojom::ServiceWorkerRouterSourceType::kFetchEvent:
@ -813,6 +818,10 @@ base::Value ServiceWorkerRouterEvaluator::ToValue() const {
source.Append("cache");
}
break;
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndCache:
// TODO(crbug.com/370844790): implement race network and cache
break;
}
}
rule.Set("condition", std::move(condition));

@ -280,8 +280,9 @@ TEST(ServiceWorkerRouterEvaluator, ChooseMatchedRoute) {
}
{
blink::ServiceWorkerRouterSource source;
source.type = network::mojom::ServiceWorkerRouterSourceType::kRace;
source.race_source.emplace();
source.type = network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent;
source.race_network_and_fetch_event_source.emplace();
rule.sources.push_back(source);
}
rules.rules.push_back(rule);
@ -299,7 +300,8 @@ TEST(ServiceWorkerRouterEvaluator, ChooseMatchedRoute) {
// Four sources rule should match because of *.css URLPattern.
EXPECT_TRUE(eval_result.has_value());
EXPECT_EQ(1U, eval_result->sources.size());
EXPECT_EQ(network::mojom::ServiceWorkerRouterSourceType::kRace,
EXPECT_EQ(
network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndFetchEvent,
eval_result->sources[0].type);
}
@ -1356,8 +1358,9 @@ TEST(ServiceWorkerRouterEvaluator, ToValueBasicSimpleRule) {
}
{
blink::ServiceWorkerRouterSource source;
source.type = network::mojom::ServiceWorkerRouterSourceType::kRace;
source.race_source.emplace();
source.type = network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent;
source.race_network_and_fetch_event_source.emplace();
rule.sources.push_back(source);
}
{

@ -392,7 +392,6 @@ void ServiceWorkerSubresourceLoader::DispatchFetchEvent() {
kForced,
kSkipped
} race_network_request_mode = kDefault;
std::optional<blink::ServiceWorkerRouterRaceSource> race_source;
if (controller_connector_->router_evaluator()) {
response_head_->service_worker_router_info =
@ -422,9 +421,9 @@ void ServiceWorkerSubresourceLoader::DispatchFetchEvent() {
OnFallback(std::nullopt, std::move(timing));
}
return;
case network::mojom::ServiceWorkerRouterSourceType::kRace:
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent:
race_network_request_mode = kForced;
race_source = sources[0].race_source;
break;
case network::mojom::ServiceWorkerRouterSourceType::kFetchEvent:
race_network_request_mode = kSkipped;
@ -437,6 +436,10 @@ void ServiceWorkerSubresourceLoader::DispatchFetchEvent() {
&ServiceWorkerSubresourceLoader::DidCacheStorageMatch,
weak_factory_.GetWeakPtr(), base::TimeTicks::Now()));
return;
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndCache:
// TODO(crbug.com/370844790): implement race network and cache
break;
}
}
}
@ -490,8 +493,6 @@ void ServiceWorkerSubresourceLoader::DispatchFetchEvent() {
switch (race_network_request_mode) {
case kForced:
CHECK_EQ(race_source->target, blink::ServiceWorkerRouterRaceSource::
TargetEnum::kNetworkAndFetchHandler);
if (StartRaceNetworkRequest()) {
SetDispatchedPreloadType(DispatchedPreloadType::kRaceNetworkRequest);
}
@ -1367,7 +1368,8 @@ void ServiceWorkerSubresourceLoader::SetCommitResponsibility(
if (response_head_ && response_head_->service_worker_router_info &&
response_head_->service_worker_router_info->matched_source_type &&
*response_head_->service_worker_router_info->matched_source_type ==
network::mojom::ServiceWorkerRouterSourceType::kRace &&
network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent &&
fetch_response_from == FetchResponseFrom::kWithoutServiceWorker) {
response_head_->service_worker_router_info->actual_source_type =
network::mojom::ServiceWorkerRouterSourceType::kNetwork;

@ -13,11 +13,13 @@ enum ServiceWorkerRouterSourceType {
// Network is used as a source.
kNetwork = 0,
// Race network and fetch handler.
kRace = 1,
kRaceNetworkAndFetchEvent = 1,
// Fetch Event is used as a source.
kFetchEvent = 2,
// Cache is used as a source.
kCache = 3,
// Race network and cache.
kRaceNetworkAndCache = 4,
};
// The initial status of service worker on navigation request.

@ -49,16 +49,6 @@ bool ServiceWorkerRouterCondition::operator==(
return get() == other.get();
}
bool ServiceWorkerRouterRaceSource::operator==(
const ServiceWorkerRouterRaceSource& other) const {
return target == other.target;
}
bool ServiceWorkerRouterCacheSource::operator==(
const ServiceWorkerRouterCacheSource& other) const {
return cache_name == other.cache_name;
}
bool ServiceWorkerRouterSource::operator==(
const ServiceWorkerRouterSource& other) const {
if (type != other.type) {
@ -67,12 +57,17 @@ bool ServiceWorkerRouterSource::operator==(
switch (type) {
case network::mojom::ServiceWorkerRouterSourceType::kNetwork:
return network_source == other.network_source;
case network::mojom::ServiceWorkerRouterSourceType::kRace:
return race_source == other.race_source;
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent:
return race_network_and_fetch_event_source ==
other.race_network_and_fetch_event_source;
case network::mojom::ServiceWorkerRouterSourceType::kFetchEvent:
return fetch_event_source == other.fetch_event_source;
case network::mojom::ServiceWorkerRouterSourceType::kCache:
return cache_source == other.cache_source;
case network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndCache:
return race_network_and_cache_source ==
other.race_network_and_cache_source;
}
}

@ -83,16 +83,6 @@ bool StructTraits<blink::mojom::ServiceWorkerRouterConditionDataView,
return true;
}
bool StructTraits<blink::mojom::ServiceWorkerRouterRaceSourceDataView,
blink::ServiceWorkerRouterRaceSource>::
Read(blink::mojom::ServiceWorkerRouterRaceSourceDataView data,
blink::ServiceWorkerRouterRaceSource* out) {
if (!data.ReadTarget(&out->target)) {
return false;
}
return true;
}
bool StructTraits<blink::mojom::ServiceWorkerRouterCacheSourceDataView,
blink::ServiceWorkerRouterCacheSource>::
Read(blink::mojom::ServiceWorkerRouterCacheSourceDataView data,
@ -103,6 +93,18 @@ bool StructTraits<blink::mojom::ServiceWorkerRouterCacheSourceDataView,
return true;
}
bool StructTraits<
blink::mojom::ServiceWorkerRouterRaceNetworkAndCacheSourceDataView,
blink::ServiceWorkerRouterRaceNetworkAndCacheSource>::
Read(
blink::mojom::ServiceWorkerRouterRaceNetworkAndCacheSourceDataView data,
blink::ServiceWorkerRouterRaceNetworkAndCacheSource* out) {
if (!data.ReadCacheSource(&out->cache_source)) {
return false;
}
return true;
}
blink::mojom::ServiceWorkerRouterSourceDataView::Tag
UnionTraits<blink::mojom::ServiceWorkerRouterSourceDataView,
blink::ServiceWorkerRouterSource>::
@ -110,12 +112,17 @@ UnionTraits<blink::mojom::ServiceWorkerRouterSourceDataView,
switch (data.type) {
case network::mojom::ServiceWorkerRouterSourceType::kNetwork:
return blink::mojom::ServiceWorkerRouterSource::Tag::kNetworkSource;
case network::mojom::ServiceWorkerRouterSourceType::kRace:
return blink::mojom::ServiceWorkerRouterSource::Tag::kRaceSource;
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent:
return blink::mojom::ServiceWorkerRouterSource::Tag::
kRaceNetworkAndFetchEventSource;
case network::mojom::ServiceWorkerRouterSourceType::kFetchEvent:
return blink::mojom::ServiceWorkerRouterSource::Tag::kFetchEventSource;
case network::mojom::ServiceWorkerRouterSourceType::kCache:
return blink::mojom::ServiceWorkerRouterSource::Tag::kCacheSource;
case network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndCache:
return blink::mojom::ServiceWorkerRouterSource::Tag::
kRaceNetworkAndCacheSource;
}
}
@ -128,9 +135,11 @@ bool UnionTraits<blink::mojom::ServiceWorkerRouterSourceDataView,
out->type = network::mojom::ServiceWorkerRouterSourceType::kNetwork;
out->network_source.emplace();
return true;
case blink::mojom::ServiceWorkerRouterSource::Tag::kRaceSource:
out->type = network::mojom::ServiceWorkerRouterSourceType::kRace;
out->race_source.emplace();
case blink::mojom::ServiceWorkerRouterSource::Tag::
kRaceNetworkAndFetchEventSource:
out->type = network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent;
out->race_network_and_fetch_event_source.emplace();
return true;
case blink::mojom::ServiceWorkerRouterSource::Tag::kFetchEventSource:
out->type = network::mojom::ServiceWorkerRouterSourceType::kFetchEvent;
@ -142,6 +151,15 @@ bool UnionTraits<blink::mojom::ServiceWorkerRouterSourceDataView,
return false;
}
return true;
case blink::mojom::ServiceWorkerRouterSource::Tag::
kRaceNetworkAndCacheSource:
out->type =
network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndCache;
if (!data.ReadRaceNetworkAndCacheSource(
&out->race_network_and_cache_source)) {
return false;
}
return true;
}
return false;
}

@ -78,8 +78,9 @@ TEST(ServiceWorkerRouterRulesTest, SimpleRoundTrip) {
}
{
blink::ServiceWorkerRouterSource source;
source.type = network::mojom::ServiceWorkerRouterSourceType::kRace;
source.race_source.emplace();
source.type = network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent;
source.race_network_and_fetch_event_source.emplace();
rule.sources.push_back(source);
}
{
@ -102,6 +103,25 @@ TEST(ServiceWorkerRouterRulesTest, SimpleRoundTrip) {
source.cache_source = cache_source;
rule.sources.push_back(source);
}
{
blink::ServiceWorkerRouterSource source;
source.type =
network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndCache;
source.race_network_and_cache_source.emplace();
blink::ServiceWorkerRouterCacheSource cache_source;
source.race_network_and_cache_source->cache_source = cache_source;
rule.sources.push_back(source);
}
{
blink::ServiceWorkerRouterSource source;
source.type =
network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndCache;
source.race_network_and_cache_source.emplace();
blink::ServiceWorkerRouterCacheSource cache_source;
cache_source.cache_name = "example cache name";
source.race_network_and_cache_source->cache_source = cache_source;
rule.sources.push_back(source);
}
rules.rules.push_back(rule);
}
TestRoundTrip(rules);

@ -198,27 +198,20 @@ class BLINK_COMMON_EXPORT ServiceWorkerRouterCondition {
// Network source structure.
// TODO(crbug.com/1371756): implement fields in the proposal.
struct BLINK_COMMON_EXPORT ServiceWorkerRouterNetworkSource {
bool operator==(const ServiceWorkerRouterNetworkSource& other) const {
return true;
}
bool operator==(const ServiceWorkerRouterNetworkSource& other) const =
default;
};
// Race two sources.
struct BLINK_COMMON_EXPORT ServiceWorkerRouterRaceSource {
// Enum to explain which sources race.
enum class TargetEnum {
kNetworkAndFetchHandler = 0,
};
TargetEnum target = TargetEnum::kNetworkAndFetchHandler;
bool operator==(const ServiceWorkerRouterRaceSource& other) const;
// Race network and fetch event sources.
struct BLINK_COMMON_EXPORT ServiceWorkerRouterRaceNetworkAndFetchEventSource {
bool operator==(const ServiceWorkerRouterRaceNetworkAndFetchEventSource&
other) const = default;
};
// Fetch handler source structure.
struct BLINK_COMMON_EXPORT ServiceWorkerRouterFetchEventSource {
bool operator==(const ServiceWorkerRouterFetchEventSource& other) const {
return true;
}
bool operator==(const ServiceWorkerRouterFetchEventSource& other) const =
default;
};
// Cache source structure.
@ -228,7 +221,15 @@ struct BLINK_COMMON_EXPORT ServiceWorkerRouterCacheSource {
// tracks are used for matching as if CacheStorage.match().
std::optional<std::string> cache_name;
bool operator==(const ServiceWorkerRouterCacheSource& other) const;
bool operator==(const ServiceWorkerRouterCacheSource& other) const = default;
};
// Race network and cache sources.
struct BLINK_COMMON_EXPORT ServiceWorkerRouterRaceNetworkAndCacheSource {
ServiceWorkerRouterCacheSource cache_source;
bool operator==(const ServiceWorkerRouterRaceNetworkAndCacheSource& other)
const = default;
};
// This represents a source of the router rule.
@ -237,9 +238,12 @@ struct BLINK_COMMON_EXPORT ServiceWorkerRouterSource {
network::mojom::ServiceWorkerRouterSourceType type;
std::optional<ServiceWorkerRouterNetworkSource> network_source;
std::optional<ServiceWorkerRouterRaceSource> race_source;
std::optional<ServiceWorkerRouterRaceNetworkAndFetchEventSource>
race_network_and_fetch_event_source;
std::optional<ServiceWorkerRouterFetchEventSource> fetch_event_source;
std::optional<ServiceWorkerRouterCacheSource> cache_source;
std::optional<ServiceWorkerRouterRaceNetworkAndCacheSource>
race_network_and_cache_source;
bool operator==(const ServiceWorkerRouterSource& other) const;
};

@ -183,43 +183,13 @@ struct BLINK_COMMON_EXPORT
};
template <>
struct BLINK_COMMON_EXPORT
EnumTraits<blink::mojom::ServiceWorkerRouterRaceSourceEnum,
blink::ServiceWorkerRouterRaceSource::TargetEnum> {
static blink::mojom::ServiceWorkerRouterRaceSourceEnum ToMojom(
blink::ServiceWorkerRouterRaceSource::TargetEnum input) {
switch (input) {
case blink::ServiceWorkerRouterRaceSource::TargetEnum::
kNetworkAndFetchHandler:
return blink::mojom::ServiceWorkerRouterRaceSourceEnum::
kNetworkAndFetchHandler;
}
}
static bool FromMojom(
blink::mojom::ServiceWorkerRouterRaceSourceEnum input,
blink::ServiceWorkerRouterRaceSource::TargetEnum* output) {
switch (input) {
case blink::mojom::ServiceWorkerRouterRaceSourceEnum::
kNetworkAndFetchHandler:
*output = blink::ServiceWorkerRouterRaceSource::TargetEnum::
kNetworkAndFetchHandler;
break;
}
return true;
}
};
template <>
struct BLINK_COMMON_EXPORT
StructTraits<blink::mojom::ServiceWorkerRouterRaceSourceDataView,
blink::ServiceWorkerRouterRaceSource> {
static blink::ServiceWorkerRouterRaceSource::TargetEnum target(
const blink::ServiceWorkerRouterRaceSource& data) {
return data.target;
}
static bool Read(blink::mojom::ServiceWorkerRouterRaceSourceDataView data,
blink::ServiceWorkerRouterRaceSource* out);
struct BLINK_COMMON_EXPORT StructTraits<
blink::mojom::ServiceWorkerRouterRaceNetworkAndFetchEventSourceDataView,
blink::ServiceWorkerRouterRaceNetworkAndFetchEventSource> {
static bool Read(
blink::mojom::ServiceWorkerRouterRaceNetworkAndFetchEventSourceDataView
data,
blink::ServiceWorkerRouterRaceNetworkAndFetchEventSource* out);
};
template <>
@ -246,6 +216,20 @@ struct BLINK_COMMON_EXPORT
blink::ServiceWorkerRouterCacheSource* out);
};
template <>
struct BLINK_COMMON_EXPORT StructTraits<
blink::mojom::ServiceWorkerRouterRaceNetworkAndCacheSourceDataView,
blink::ServiceWorkerRouterRaceNetworkAndCacheSource> {
static const blink::ServiceWorkerRouterCacheSource& cache_source(
const blink::ServiceWorkerRouterRaceNetworkAndCacheSource& data) {
return data.cache_source;
}
static bool Read(
blink::mojom::ServiceWorkerRouterRaceNetworkAndCacheSourceDataView data,
blink::ServiceWorkerRouterRaceNetworkAndCacheSource* out);
};
template <>
struct BLINK_COMMON_EXPORT
UnionTraits<blink::mojom::ServiceWorkerRouterSourceDataView,
@ -258,9 +242,10 @@ struct BLINK_COMMON_EXPORT
return *data.network_source;
}
static const blink::ServiceWorkerRouterRaceSource& race_source(
static const blink::ServiceWorkerRouterRaceNetworkAndFetchEventSource&
race_network_and_fetch_event_source(
const blink::ServiceWorkerRouterSource& data) {
return *data.race_source;
return *data.race_network_and_fetch_event_source;
}
static const blink::ServiceWorkerRouterFetchEventSource& fetch_event_source(
@ -273,6 +258,11 @@ struct BLINK_COMMON_EXPORT
return *data.cache_source;
}
static const blink::ServiceWorkerRouterRaceNetworkAndCacheSource&
race_network_and_cache_source(const blink::ServiceWorkerRouterSource& data) {
return *data.race_network_and_cache_source;
}
static bool Read(blink::mojom::ServiceWorkerRouterSourceDataView data,
blink::ServiceWorkerRouterSource* out);
};

@ -6334,6 +6334,7 @@ domain Network
cache
fetch-event
race-network-and-fetch-handler
race-network-and-cache
experimental type ServiceWorkerRouterInfo extends object
properties

@ -91,29 +91,13 @@ struct ServiceWorkerRouterCondition {
struct ServiceWorkerRouterNetworkSource {
};
// Enum to represent the race targets.
// We aim to implement other race-* sources, which are not in the specification
// yet. race-network-and-fetch-event has already been in the specification.
// https://w3c.github.io/ServiceWorker/#dom-routersourceenum-race-network-and-fetch-handler
// race-cache-and-network has already been proposed.
// https://github.com/WICG/service-worker-static-routing-api/pull/34.
// However, it can technically be expanded to race arbitrary two or three of
// "network", "fetch-event", or "cache". Please stay tuned.
enum ServiceWorkerRouterRaceSourceEnum {
// Race network source and the fetch handler.
// https://w3c.github.io/ServiceWorker/#dom-routersourceenum-race-network-and-fetch-handler
kNetworkAndFetchHandler = 0,
};
// This source is used when the browser should allow a network source and
// the fetch handler to race, allowing the first one to respond to service
// the request.
// https://w3c.github.io/ServiceWorker/#dom-routersourceenum-race-network-and-fetch-handler
// TODO(crbug.com/1371756): implement fields in the full picture.
// https://github.com/WICG/service-worker-static-routing-api
struct ServiceWorkerRouterRaceSource {
// Target to race.
ServiceWorkerRouterRaceSourceEnum target;
struct ServiceWorkerRouterRaceNetworkAndFetchEventSource {
};
// This is used for explicitly running the fetch event listeners.
@ -132,15 +116,25 @@ struct ServiceWorkerRouterCacheSource {
string? cache_name;
};
// This source is used when the browser should allow a network source and
// the response should be retrieved from the cache storage to race, allowing
// the first one to respond to service the request.
// https://github.com/WICG/service-worker-static-routing-api
struct ServiceWorkerRouterRaceNetworkAndCacheSource {
// Cache source information.
ServiceWorkerRouterCacheSource cache_source;
};
// This represents a source of the router rule.
// https://w3c.github.io/ServiceWorker/#typedefdef-routersource
// TODO(crbug.com/1371756): implement other sources in the full picture.
// https://github.com/WICG/service-worker-static-routing-api
union ServiceWorkerRouterSource {
ServiceWorkerRouterNetworkSource network_source;
ServiceWorkerRouterRaceSource race_source;
ServiceWorkerRouterRaceNetworkAndFetchEventSource race_network_and_fetch_event_source;
ServiceWorkerRouterFetchEventSource fetch_event_source;
ServiceWorkerRouterCacheSource cache_source;
ServiceWorkerRouterRaceNetworkAndCacheSource race_network_and_cache_source;
};
// This represents a ServiceWorker static routing API's router rule.

@ -628,13 +628,17 @@ String BuildServiceWorkerRouterSourceType(
switch (type) {
case network::mojom::ServiceWorkerRouterSourceType::kNetwork:
return protocol::Network::ServiceWorkerRouterSourceEnum::Network;
case network::mojom::ServiceWorkerRouterSourceType::kRace:
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent:
return protocol::Network::ServiceWorkerRouterSourceEnum::
RaceNetworkAndFetchHandler;
case network::mojom::ServiceWorkerRouterSourceType::kFetchEvent:
return protocol::Network::ServiceWorkerRouterSourceEnum::FetchEvent;
case network::mojom::ServiceWorkerRouterSourceType::kCache:
return protocol::Network::ServiceWorkerRouterSourceEnum::Cache;
case network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndCache:
return protocol::Network::ServiceWorkerRouterSourceEnum::
RaceNetworkAndCache;
}
}

@ -293,10 +293,9 @@ std::optional<ServiceWorkerRouterSource> RouterSourceEnumToBlink(
return std::nullopt;
}
ServiceWorkerRouterSource source;
source.type = network::mojom::ServiceWorkerRouterSourceType::kRace;
source.race_source.emplace();
source.race_source->target = blink::ServiceWorkerRouterRaceSource::
TargetEnum::kNetworkAndFetchHandler;
source.type = network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent;
source.race_network_and_fetch_event_source.emplace();
return source;
}
case V8RouterSourceEnum::Enum::kFetchEvent: {

@ -417,8 +417,9 @@ TEST(ServiceWorkerRouterTypeConverterTest, Race) {
expected_rule.condition =
blink::ServiceWorkerRouterCondition::WithUrlPattern(expected_url_pattern);
blink::ServiceWorkerRouterSource expected_source;
expected_source.type = network::mojom::ServiceWorkerRouterSourceType::kRace;
expected_source.race_source.emplace();
expected_source.type =
network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndFetchEvent;
expected_source.race_network_and_fetch_event_source.emplace();
expected_rule.sources.emplace_back(expected_source);
V8TestingScope scope;

@ -3541,9 +3541,13 @@ void ResourceFetcher::UpdateServiceWorkerSubresourceMetrics(
case network::mojom::ServiceWorkerRouterSourceType::kNetwork:
metrics.matched_network_router_source_count++;
break;
case network::mojom::ServiceWorkerRouterSourceType::kRace:
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent:
metrics.matched_race_network_and_fetch_router_source_count++;
break;
case network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndCache:
// TODO(crbug.com/370844790): implement race network and cache
break;
}
}

@ -20,12 +20,15 @@ String ServiceWorkerRouterInfo::GetRouterSourceTypeString(
switch (source) {
case network::mojom::ServiceWorkerRouterSourceType::kNetwork:
return "network";
case network::mojom::ServiceWorkerRouterSourceType::kRace:
case network::mojom::ServiceWorkerRouterSourceType::
kRaceNetworkAndFetchEvent:
return "race-network-and-fetch-handler";
case network::mojom::ServiceWorkerRouterSourceType::kCache:
return "cache";
case network::mojom::ServiceWorkerRouterSourceType::kFetchEvent:
return "fetch-event";
case network::mojom::ServiceWorkerRouterSourceType::kRaceNetworkAndCache:
return "race-network-and-cache";
}
}