0

[UA-CH] Implement Sec-CH-UA-Bitness client hint header

Intent to Implement and Ship:
https://groups.google.com/a/chromium.org/g/blink-dev/c/dafizBGwWMw
https://github.com/WICG/ua-client-hints/issues/105

To be honest, the only real point of interest is
`content/common/user_agent.cc`, which is where `GetLowEntropyCpuBitness`
is implemented. Everything else is various levels of plumbing to set up
a new Client Hint header, populate it, test it, and add a new
Permissions Policy to control it.

Bug: 1199809
Change-Id: I0e7f36c8915720cb46e06452a85092a64bde8f06
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2840423
Commit-Queue: Aaron Tagliaboschi <aarontag@chromium.org>
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
Reviewed-by: Yoav Weiss <yoavweiss@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Colin Blundell <blundell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#894021}
This commit is contained in:
Aaron Tagliaboschi
2021-06-18 23:15:07 +00:00
committed by Chromium LUCI CQ
parent a7194e8769
commit 1649e103a6
38 changed files with 128 additions and 49 deletions

@ -61,7 +61,7 @@
namespace {
const unsigned expected_client_hints_number = 13u;
const unsigned expected_client_hints_number = 14u;
const int32_t uma_histogram_max_value = 1471228928;
// An interceptor that records count of fetches and client hint headers for

@ -891,6 +891,8 @@ TEST_F(SessionServiceTest, PersistUserAgentOverrides) {
client_hints_override.full_version = "18.0.1025.45";
client_hints_override.platform = "Linux";
client_hints_override.architecture = "x86_64";
// Doesn't have to match, just needs to be different than the default
client_hints_override.bitness = "8";
SerializedNavigationEntry nav1 =
ContentTestHelper::CreateNavigation("http://google.com", "abc");

@ -93,6 +93,7 @@ class TabRestoreServiceImplTest : public ChromeRenderViewHostTestHarness {
user_agent_override_.ua_metadata_override->full_version = "18.0.1025.45";
user_agent_override_.ua_metadata_override->platform = "Linux";
user_agent_override_.ua_metadata_override->architecture = "x86_64";
user_agent_override_.ua_metadata_override->bitness = "32";
}
~TabRestoreServiceImplTest() override {}

@ -1,3 +1,3 @@
HTTP/1.1 200 OK
Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-platform-version,sec-ch-ua-model,sec-ch-ua-full-version,sec-ch-prefers-color-scheme
Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-platform-version,sec-ch-ua-model,sec-ch-ua-full-version,sec-ch-prefers-color-scheme,sec-ch-ua-bitness
Accept-CH-Lifetime: 3600

@ -1,3 +1,3 @@
HTTP/1.1 200 OK
Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-platform-version,sec-ch-ua-model,sec-ch-ua-full-version,sec-ch-prefers-color-scheme
Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-platform-version,sec-ch-ua-model,sec-ch-ua-full-version,sec-ch-prefers-color-scheme,sec-ch-ua-bitness
Accept-CH-Lifetime: 1

@ -1,2 +1,2 @@
HTTP/1.1 200 OK
Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-platform-version,sec-ch-ua-model,sec-ch-ua-full-version,sec-ch-prefers-color-scheme
Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-platform-version,sec-ch-ua-model,sec-ch-ua-full-version,sec-ch-prefers-color-scheme,sec-ch-ua-bitness

@ -1,2 +1,2 @@
HTTP/1.1 200 OK
Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-platform-version,sec-ch-ua-model,sec-ch-ua-full-version,sec-ch-prefers-color-scheme
Accept-CH: dpr,device-memory,viewport-width,rtt,downlink,ect,lang,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-platform-version,sec-ch-ua-model,sec-ch-ua-full-version,sec-ch-prefers-color-scheme,sec-ch-ua-bitness

@ -2,7 +2,7 @@
<!-- This is split in two since data from header may round trip quickly
enough from browser to be used, so this makes sure we actually merge -->
<meta http-equiv="Accept-CH" content="lang,sec-ch-ua-arch,sec-ch-ua-platform">
<meta http-equiv="Accept-CH" content="sec-ch-ua-platform-version,sec-ch-ua-model,sec-ch-ua-full-version,sec-ch-prefers-color-scheme">
<meta http-equiv="Accept-CH" content="sec-ch-ua-platform-version,sec-ch-ua-model,sec-ch-ua-full-version,sec-ch-prefers-color-scheme,sec-ch-ua-bitness">
<link rel="icon" href="data:;base64,=">
<!-- A subresource! -->
<img src="non-existing-image.jpg"></img>

@ -1,5 +1,5 @@
<html>
<meta http-equiv="Accept-CH" content="dpr,device-memory,viewport-width,rtt,downlink,ect,lang,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-model,sec-ch-ua-full-version">
<meta http-equiv="Accept-CH" content="dpr,device-memory,viewport-width,rtt,downlink,ect,lang,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-model,sec-ch-ua-full-version,sec-ch-ua-bitness">
<meta http-equiv="Accept-CH-Lifetime" content="3600">
<link rel="icon" href="data:;base64,=">
</html>

@ -1,5 +1,5 @@
<html>
<meta http-equiv="Accept-CH" content="dpr,device-memory,viewport-width,rtt,downlink,ect,lang,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-model,sec-ch-ua-full-version">
<meta http-equiv="Accept-CH" content="dpr,device-memory,viewport-width,rtt,downlink,ect,lang,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-model,sec-ch-ua-full-version,sec-ch-ua-bitness">
<link rel="icon" href="data:;base64,=">
<head></head>
Empty file which uses link-rel to disable favicon fetches. The corresponding

@ -1,5 +1,5 @@
<html>
<meta http-equiv="Accept-CH" content="dpr,device-memory,viewport-width,rtt,downlink,ect,lang,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-platform-version,sec-ch-ua-model,sec-ch-ua-full-version,sec-ch-prefers-color-scheme">
<meta http-equiv="Accept-CH" content="dpr,device-memory,viewport-width,rtt,downlink,ect,lang,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-platform-version,sec-ch-ua-model,sec-ch-ua-full-version,sec-ch-prefers-color-scheme,sec-ch-ua-bitness">
<link rel="icon" href="data:;base64,=">
<head></head>
Empty file which uses link-rel to disable favicon fetches. The corresponding

@ -142,7 +142,6 @@ blink::UserAgentMetadata GetUserAgentMetadata() {
metadata.platform = GetPlatformForUAMetadata();
metadata.architecture = content::GetLowEntropyCpuArchitecture();
metadata.model = content::BuildModelInfo();
metadata.mobile = false;
#if defined(OS_ANDROID)
metadata.mobile = base::CommandLine::ForCurrentProcess()->HasSwitch(
@ -153,6 +152,11 @@ blink::UserAgentMetadata GetUserAgentMetadata() {
base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
metadata.platform_version =
base::StringPrintf("%d.%d.%d", major, minor, bugfix);
// These methods use the same information as the User-Agent string, but are
// "low entropy" in that they reduce the number of options for output to a
// set number. For more information, see the respective headers.
metadata.architecture = content::GetLowEntropyCpuArchitecture();
metadata.bitness = content::GetLowEntropyCpuBitness();
return metadata;
}
@ -171,9 +175,12 @@ void SetDesktopUserAgentOverride(content::WebContents* web_contents,
spoofed_ua.ua_metadata_override->platform = "Linux";
spoofed_ua.ua_metadata_override->platform_version =
std::string(); // match content::GetOSVersion(false) on Linux
spoofed_ua.ua_metadata_override->architecture = "x86";
spoofed_ua.ua_metadata_override->model = std::string();
spoofed_ua.ua_metadata_override->mobile = false;
// Match the above "CpuInfo" string, which is also the most common Linux
// CPU architecture and bitness.`
spoofed_ua.ua_metadata_override->architecture = "x86";
spoofed_ua.ua_metadata_override->bitness = "64";
web_contents->SetUserAgentOverride(spoofed_ua, override_in_new_tabs);
}

@ -305,6 +305,7 @@ TEST(UserAgentUtilsTest, UserAgentMetadata) {
#endif
EXPECT_EQ(metadata.architecture, content::GetLowEntropyCpuArchitecture());
EXPECT_EQ(metadata.model, content::BuildModelInfo());
EXPECT_EQ(metadata.bitness, content::GetLowEntropyCpuBitness());
}
TEST(UserAgentUtilsTest, GenerateBrandVersionList) {

@ -556,6 +556,11 @@ void UpdateNavigationRequestClientUaHeadersImpl(
AddUAHeader(headers, network::mojom::WebClientHintsType::kUAModel,
SerializeHeaderString(ua_metadata->model));
}
if (ShouldAddClientHint(data,
network::mojom::WebClientHintsType::kUABitness)) {
AddUAHeader(headers, network::mojom::WebClientHintsType::kUABitness,
SerializeHeaderString(ua_metadata->bitness));
}
} else if (call_type == ClientUaHeaderCallType::kAfterCreated) {
RemoveClientHintHeader(network::mojom::WebClientHintsType::kUA, headers);
RemoveClientHintHeader(network::mojom::WebClientHintsType::kUAMobile,
@ -570,6 +575,8 @@ void UpdateNavigationRequestClientUaHeadersImpl(
network::mojom::WebClientHintsType::kUAPlatformVersion, headers);
RemoveClientHintHeader(network::mojom::WebClientHintsType::kUAModel,
headers);
RemoveClientHintHeader(network::mojom::WebClientHintsType::kUABitness,
headers);
}
}
@ -678,7 +685,7 @@ void AddRequestClientHintsHeaders(
// If possible, logic should be added above so that the request headers for
// the newly added client hint can be added to the request.
static_assert(
network::mojom::WebClientHintsType::kPrefersColorScheme ==
network::mojom::WebClientHintsType::kUABitness ==
network::mojom::WebClientHintsType::kMaxValue,
"Consider adding client hint request headers from the browser process");

@ -6,6 +6,7 @@
#include <stdint.h>
#include "base/containers/contains.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@ -125,11 +126,7 @@ std::string GetLowEntropyCpuArchitecture() {
return "arm";
}
#elif defined(OS_POSIX) && !defined(OS_ANDROID)
// This extra cpu_info_str variable is required to make sure the compiler
// doesn't optimize the copy away and have the StringPiece point at the
// internal std::string, resulting in a memory violation.
std::string cpu_info_str = BuildCpuInfo();
base::StringPiece cpu_info = cpu_info_str;
std::string cpu_info = BuildCpuInfo();
if (base::StartsWith(cpu_info, "arm") ||
base::StartsWith(cpu_info, "aarch")) {
return "arm";
@ -142,6 +139,21 @@ std::string GetLowEntropyCpuArchitecture() {
return std::string();
}
std::string GetLowEntropyCpuBitness() {
#if defined(OS_WIN)
return (base::win::OSInfo::GetInstance()->GetArchitecture() ==
base::win::OSInfo::X86_ARCHITECTURE)
? "32"
: "64";
#elif defined(OS_MAC)
return "64";
#elif defined(OS_POSIX) && !defined(OS_ANDROID)
return base::Contains(BuildCpuInfo(), "64") ? "64" : "32";
#else
return std::string();
#endif
}
std::string GetOSVersion(IncludeAndroidBuildNumber include_android_build_number,
IncludeAndroidModel include_android_model) {
std::string os_version;

@ -88,6 +88,7 @@ IPC_STRUCT_TRAITS_BEGIN(blink::UserAgentMetadata)
IPC_STRUCT_TRAITS_MEMBER(architecture)
IPC_STRUCT_TRAITS_MEMBER(model)
IPC_STRUCT_TRAITS_MEMBER(mobile)
IPC_STRUCT_TRAITS_MEMBER(bitness)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(blink::UserAgentOverride)

@ -47,6 +47,10 @@ CONTENT_EXPORT std::string BuildCpuInfo();
// most common cases.
CONTENT_EXPORT std::string GetLowEntropyCpuArchitecture();
// Takes the cpu info (see BuildCpuInfo()) and extracts the CPU bitness for
// most common cases.
CONTENT_EXPORT std::string GetLowEntropyCpuBitness();
// Builds a User-agent compatible string that describes the OS and CPU type.
// On Android, the string will only include the build number and model if
// relevant enums indicate they should be included.

@ -220,6 +220,8 @@ blink::UserAgentMetadata GetShellUserAgentMetadata() {
metadata.architecture = BuildCpuInfo();
metadata.model = BuildModelInfo();
metadata.bitness = GetLowEntropyCpuBitness();
return metadata;
}

@ -33,7 +33,8 @@ const char* const kClientHintsNameMapping[] = {"device-memory",
"sec-ch-ua-mobile",
"sec-ch-ua-full-version",
"sec-ch-ua-platform-version",
"sec-ch-prefers-color-scheme"};
"sec-ch-prefers-color-scheme",
"sec-ch-ua-bitness"};
const size_t kClientHintsMappingsCount = base::size(kClientHintsNameMapping);

@ -466,6 +466,7 @@ bool IsCorsSafelistedHeader(const std::string& name, const std::string& value) {
//
// https://tomayac.github.io/user-preference-media-features-headers/#sec-ch-prefers-color-scheme
"sec-ch-prefers-color-scheme",
"sec-ch-ua-bitness",
};
if (std::find(std::begin(safe_names), std::end(safe_names), lower_name) ==
std::end(safe_names))

@ -32,6 +32,7 @@ enum WebClientHintsType {
kUAFullVersion = 13,
kUAPlatformVersion = 14,
kPrefersColorScheme = 15,
kUABitness = 16,
// Warning: Before adding a new client hint, read the warning at the top.
};

@ -19,24 +19,23 @@
namespace blink {
const char* const kClientHintsHeaderMapping[] = {
"device-memory",
"dpr",
"width",
"viewport-width",
"rtt",
"downlink",
"ect",
"sec-ch-lang",
"sec-ch-ua",
"sec-ch-ua-arch",
"sec-ch-ua-platform",
"sec-ch-ua-model",
"sec-ch-ua-mobile",
"sec-ch-ua-full-version",
"sec-ch-ua-platform-version",
"sec-ch-prefers-color-scheme",
};
const char* const kClientHintsHeaderMapping[] = {"device-memory",
"dpr",
"width",
"viewport-width",
"rtt",
"downlink",
"ect",
"sec-ch-lang",
"sec-ch-ua",
"sec-ch-ua-arch",
"sec-ch-ua-platform",
"sec-ch-ua-model",
"sec-ch-ua-mobile",
"sec-ch-ua-full-version",
"sec-ch-ua-platform-version",
"sec-ch-prefers-color-scheme",
"sec-ch-ua-bitness"};
const unsigned kClientHintsNumberOfLegacyHints = 4;
@ -60,6 +59,7 @@ const mojom::PermissionsPolicyFeature kClientHintsPermissionsPolicyMapping[] = {
mojom::PermissionsPolicyFeature::kClientHintUAFullVersion,
mojom::PermissionsPolicyFeature::kClientHintUAPlatformVersion,
mojom::PermissionsPolicyFeature::kClientHintPrefersColorScheme,
mojom::PermissionsPolicyFeature::kClientHintUABitness,
};
const size_t kClientHintsMappingsCount = base::size(kClientHintsHeaderMapping);
@ -117,6 +117,7 @@ absl::optional<std::vector<network::mojom::WebClientHintsType>> FilterAcceptCH(
case network::mojom::WebClientHintsType::kUAModel:
case network::mojom::WebClientHintsType::kUAMobile:
case network::mojom::WebClientHintsType::kUAFullVersion:
case network::mojom::WebClientHintsType::kUABitness:
if (permit_ua_hints)
result.push_back(hint);
break;

@ -127,11 +127,11 @@ TEST(ClientHintsTest, FindClientHintsToRemoveLegacy) {
std::vector<std::string> removed_headers;
FindClientHintsToRemove(nullptr, GURL(), &removed_headers);
EXPECT_THAT(removed_headers,
UnorderedElementsAre("rtt", "downlink", "ect", "sec-ch-lang",
"sec-ch-ua-arch", "sec-ch-ua-platform",
"sec-ch-ua-model", "sec-ch-ua-full-version",
"sec-ch-ua-platform-version",
"sec-ch-prefers-color-scheme"));
UnorderedElementsAre(
"rtt", "downlink", "ect", "sec-ch-lang", "sec-ch-ua-arch",
"sec-ch-ua-platform", "sec-ch-ua-model",
"sec-ch-ua-full-version", "sec-ch-ua-platform-version",
"sec-ch-prefers-color-scheme", "sec-ch-ua-bitness"));
}
// Checks that the removed header list includes legacy headers but not the
@ -142,12 +142,12 @@ TEST(ClientHintsTest, FindClientHintsToRemoveNoLegacy) {
features::kAllowClientHintsToThirdParty);
std::vector<std::string> removed_headers;
FindClientHintsToRemove(nullptr, GURL(), &removed_headers);
EXPECT_THAT(
removed_headers,
UnorderedElementsAre(
"device-memory", "dpr", "width", "viewport-width", "rtt", "downlink",
"ect", "sec-ch-lang", "sec-ch-ua-arch", "sec-ch-ua-platform",
"sec-ch-ua-model", "sec-ch-ua-full-version",
"sec-ch-ua-platform-version", "sec-ch-prefers-color-scheme"));
EXPECT_THAT(removed_headers,
UnorderedElementsAre(
"device-memory", "dpr", "width", "viewport-width", "rtt",
"downlink", "ect", "sec-ch-lang", "sec-ch-ua-arch",
"sec-ch-ua-platform", "sec-ch-ua-model",
"sec-ch-ua-full-version", "sec-ch-ua-platform-version",
"sec-ch-prefers-color-scheme", "sec-ch-ua-bitness"));
}
} // namespace blink

@ -61,6 +61,7 @@ absl::optional<std::string> UserAgentMetadata::Marshal(
out.WriteString(in->architecture);
out.WriteString(in->model);
out.WriteBool(in->mobile);
out.WriteString(in->bitness);
return std::string(reinterpret_cast<const char*>(out.data()), out.size());
}
@ -102,6 +103,8 @@ absl::optional<UserAgentMetadata> UserAgentMetadata::Demarshal(
return absl::nullopt;
if (!in.ReadBool(&out.mobile))
return absl::nullopt;
if (!in.ReadString(&out.bitness))
return absl::nullopt;
return absl::make_optional(std::move(out));
}
@ -114,7 +117,7 @@ bool operator==(const UserAgentMetadata& a, const UserAgentMetadata& b) {
a.full_version == b.full_version && a.platform == b.platform &&
a.platform_version == b.platform_version &&
a.architecture == b.architecture && a.model == b.model &&
a.mobile == b.mobile;
a.mobile == b.mobile && a.bitness == b.bitness;
}
bool operator==(const UserAgentOverride& a, const UserAgentOverride& b) {

@ -24,6 +24,7 @@ blink::UserAgentMetadata MakeToEncode() {
to_encode.architecture = "Z80";
to_encode.model = "unofficial";
to_encode.mobile = false;
to_encode.bitness = "8";
return to_encode;
}

@ -53,6 +53,10 @@ bool StructTraits<blink::mojom::UserAgentMetadataDataView,
out->model = string;
out->mobile = data.mobile();
if (!data.ReadBitness(&string))
return false;
out->bitness = string;
return true;
}

@ -47,6 +47,7 @@ struct BLINK_COMMON_EXPORT UserAgentMetadata {
std::string architecture;
std::string model;
bool mobile = false;
std::string bitness;
};
// Used when customizing the sent User-Agent and Sec-CH-UA-* for

@ -63,6 +63,10 @@ struct BLINK_COMMON_EXPORT StructTraits<blink::mojom::UserAgentMetadataDataView,
return data.mobile;
}
static const std::string& bitness(const ::blink::UserAgentMetadata& data) {
return data.bitness;
}
static bool Read(blink::mojom::UserAgentMetadataDataView data,
::blink::UserAgentMetadata* out);
};

@ -6546,6 +6546,7 @@ domain Page
ch-rtt
ch-ua
ch-ua-arch
ch-ua-bitness
ch-ua-platform
ch-ua-model
ch-ua-mobile

@ -144,6 +144,8 @@ enum PermissionsPolicyFeature {
// Controls use of Multi-Screen Window Placement API.
kWindowPlacement = 86,
kClientHintUABitness = 87,
// Don't change assigned numbers of any item, and don't reuse removed slots.
// Add new features at the end of the enum.
// Also, run update_permissions_policy_enum.py in

@ -20,6 +20,7 @@ struct UserAgentMetadata {
string architecture;
string model;
bool mobile;
string bitness;
};
// See UserAgentOverride in

@ -3257,6 +3257,7 @@ enum WebFeature {
kExplicitPointerCaptureClickTargetDiff = 3942,
kControlledNonBlobURLWorkerWillBeUncontrolled = 3943,
kMediaMetaThemeColor = 3944,
kClientHintsUABitness = 3945,
// Add new features immediately above this line. Don't change assigned
// numbers of any item, and don't reuse removed slots.

@ -334,6 +334,16 @@ void BaseFetchContext::AddClientHintsIfNecessary(
network::mojom::blink::WebClientHintsType::kUAFullVersion)],
SerializeHeaderString(ua->full_version));
}
if (ShouldSendClientHint(
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kUABitness,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUABitness)],
SerializeHeaderString(ua->bitness));
}
}
if (ShouldSendClientHint(

@ -33,6 +33,7 @@ static constexpr WebFeature kWebFeatureMapping[] = {
WebFeature::kClientHintsUAFullVersion,
WebFeature::kClientHintsUAPlatformVersion,
WebFeature::kClientHintsPrefersColorScheme,
WebFeature::kClientHintsUABitness,
};
static_assert(static_cast<int>(network::mojom::WebClientHintsType::kMaxValue) +

@ -95,6 +95,11 @@
permissions_policy_name: "ch-ua-arch",
depends_on: ["FeaturePolicyForClientHints"],
},
{
name: "ClientHintUABitness",
permissions_policy_name: "ch-ua-bitness",
depends_on: ["FeaturePolicyForClientHints"],
},
{
name: "ClientHintUAPlatform",
permissions_policy_name: "ch-ua-platform",

@ -13,6 +13,7 @@ ch-prefers-color-scheme
ch-rtt
ch-ua
ch-ua-arch
ch-ua-bitness
ch-ua-full-version
ch-ua-mobile
ch-ua-model

@ -15,6 +15,7 @@ ch-prefers-color-scheme
ch-rtt
ch-ua
ch-ua-arch
ch-ua-bitness
ch-ua-full-version
ch-ua-mobile
ch-ua-model

@ -32981,6 +32981,7 @@ Called by update_use_counter_feature_enum.py.-->
<int value="3942" label="ExplicitPointerCaptureClickTargetDiff"/>
<int value="3943" label="ControlledNonBlobURLWorkerWillBeUncontrolled"/>
<int value="3944" label="MediaMetaThemeColor"/>
<int value="3945" label="ClientHintsUABitness"/>
</enum>
<enum name="FeaturePolicyAllowlistType">
@ -33087,6 +33088,7 @@ Called by update_permissions_policy_enum.py.-->
<int value="84" label="DirectSockets"/>
<int value="85" label="ClientHintPrefersColorScheme"/>
<int value="86" label="WindowPlacement"/>
<int value="87" label="ClientHintUABitness"/>
</enum>
<enum name="FeaturePolicyImageCompressionFormat">