Commit 709a38ff authored by Aaron Tagliaboschi's avatar Aaron Tagliaboschi Committed by Chromium LUCI CQ

[Client-Hints] Move AddClientHintsIfNecessary to BaseFetchContext

Make client hints available to other inheritors (i.e.
WorkerFetchContext). Also a little bit of refactoring. Should be a
purely mechanical change.

The purpose behind the refactor is to pull out the dependence on
the Document to the calling site and make everything Document-
dependent optional, so non-Document-related calls can be made
(specifically Service Workers initializing their own requests).

Bug: 1151050
Change-Id: I964585e7a1509b96e8a36ea673be81ff85e6a208
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2557225
Commit-Queue: Aaron Tagliaboschi <aarontag@chromium.org>
Reviewed-by: default avatarMaksim Orlovich <morlovich@chromium.org>
Reviewed-by: default avatarMike West <mkwst@chromium.org>
Cr-Commit-Position: refs/heads/master@{#843650}
parent 68a6c2c2
......@@ -4,7 +4,11 @@
#include "third_party/blink/renderer/core/loader/base_fetch_context.h"
#include "net/http/structured_headers.h"
#include "services/network/public/cpp/request_mode.h"
#include "third_party/blink/public/common/client_hints/client_hints.h"
#include "third_party/blink/public/common/device_memory/approximated_device_memory.h"
#include "third_party/blink/public/common/feature_policy/feature_policy.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
......@@ -23,9 +27,26 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h"
#include "third_party/blink/renderer/platform/network/network_state_notifier.h"
#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
namespace {
// Simple function to add quotes to make headers strings.
const AtomicString SerializeHeaderString(std::string str) {
std::string output;
if (!str.empty()) {
output = net::structured_headers::SerializeItem(
net::structured_headers::Item(str))
.value_or(std::string());
}
return AtomicString(output.c_str());
}
} // namespace
namespace blink {
base::Optional<ResourceRequestBlockedReason> BaseFetchContext::CanRequest(
......@@ -90,6 +111,229 @@ bool BaseFetchContext::SendConversionRequestInsteadOfRedirecting(
return false;
}
void BaseFetchContext::AddClientHintsIfNecessary(
const ClientHintsPreferences& hints_preferences,
const url::Origin& resource_origin,
bool is_1p_origin,
base::Optional<UserAgentMetadata> ua,
const FeaturePolicy* policy,
const base::Optional<ClientHintImageInfo>& image_info,
const base::Optional<WTF::AtomicString>& lang,
ResourceRequest& request) {
// If the feature is enabled, then client hints are allowed only on secure
// URLs.
if (!ClientHintsPreferences::IsClientHintsAllowed(request.Url()))
return;
// Sec-CH-UA is special: we always send the header to all origins that are
// eligible for client hints (e.g. secure transport, JavaScript enabled).
//
// https://github.com/WICG/ua-client-hints
//
// One exception, however, is that a custom UA is sometimes set without
// specifying accomponying client hints, in which case we disable sending
// them.
if (ClientHintsPreferences::UserAgentClientHintEnabled() && ua) {
// ShouldSendClientHint is called to make sure UA is controlled by
// FeaturePolicy.
if (ShouldSendClientHint(ClientHintsMode::kStandard, policy,
resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kUA,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUA)],
ua->SerializeBrandVersionList().c_str());
}
// We also send Sec-CH-UA-Mobile to all hints. It is a one-bit header
// identifying if the browser has opted for a "mobile" experience
// Formatted using the "sh-boolean" format from:
// https://httpwg.org/http-extensions/draft-ietf-httpbis-header-structure.html#boolean
// ShouldSendClientHint is called to make sure it's controlled by
// FeaturePolicy.
if (ShouldSendClientHint(
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kUAMobile,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUAMobile)],
ua->mobile ? "?1" : "?0");
}
}
// If the frame is detached, then don't send any hints other than UA.
if (!policy)
return;
if (!RuntimeEnabledFeatures::FeaturePolicyForClientHintsEnabled() &&
!base::FeatureList::IsEnabled(features::kAllowClientHintsToThirdParty) &&
!is_1p_origin) {
// No client hints for 3p origins.
return;
}
// The next 4 hints should be enabled if we're allowing legacy hints to third
// parties, or if FeaturePolicy delegation says they are allowed.
if (ShouldSendClientHint(
ClientHintsMode::kLegacy, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kDeviceMemory,
hints_preferences)) {
request.SetHttpHeaderField(
"Device-Memory",
AtomicString(String::Number(
ApproximatedDeviceMemory::GetApproximatedDeviceMemory())));
}
// These hints only make sense if the image info is available
if (image_info) {
if (ShouldSendClientHint(ClientHintsMode::kLegacy, policy, resource_origin,
is_1p_origin,
network::mojom::blink::WebClientHintsType::kDpr,
hints_preferences)) {
request.SetHttpHeaderField("DPR",
AtomicString(String::Number(image_info->dpr)));
}
if (ShouldSendClientHint(
ClientHintsMode::kLegacy, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kViewportWidth,
hints_preferences) &&
image_info->viewport_width) {
request.SetHttpHeaderField(
"Viewport-Width",
AtomicString(String::Number(image_info->viewport_width.value())));
}
if (ShouldSendClientHint(
ClientHintsMode::kLegacy, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kResourceWidth,
hints_preferences)) {
if (image_info->resource_width.is_set) {
float physical_width =
image_info->resource_width.width * image_info->dpr;
request.SetHttpHeaderField(
"Width", AtomicString(String::Number(ceil(physical_width))));
}
}
}
if (ShouldSendClientHint(
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kRtt, hints_preferences)) {
base::Optional<base::TimeDelta> http_rtt =
GetNetworkStateNotifier().GetWebHoldbackHttpRtt();
if (!http_rtt) {
http_rtt = GetNetworkStateNotifier().HttpRtt();
}
uint32_t rtt =
GetNetworkStateNotifier().RoundRtt(request.Url().Host(), http_rtt);
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kRtt)],
AtomicString(String::Number(rtt)));
}
if (ShouldSendClientHint(ClientHintsMode::kStandard, policy, resource_origin,
is_1p_origin,
network::mojom::blink::WebClientHintsType::kDownlink,
hints_preferences)) {
base::Optional<double> throughput_mbps =
GetNetworkStateNotifier().GetWebHoldbackDownlinkThroughputMbps();
if (!throughput_mbps) {
throughput_mbps = GetNetworkStateNotifier().DownlinkThroughputMbps();
}
double mbps = GetNetworkStateNotifier().RoundMbps(request.Url().Host(),
throughput_mbps);
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kDownlink)],
AtomicString(String::Number(mbps)));
}
if (ShouldSendClientHint(
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kEct, hints_preferences)) {
base::Optional<WebEffectiveConnectionType> holdback_ect =
GetNetworkStateNotifier().GetWebHoldbackEffectiveType();
if (!holdback_ect)
holdback_ect = GetNetworkStateNotifier().EffectiveType();
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kEct)],
AtomicString(NetworkStateNotifier::EffectiveConnectionTypeToString(
holdback_ect.value())));
}
if (ShouldSendClientHint(ClientHintsMode::kStandard, policy, resource_origin,
is_1p_origin,
network::mojom::blink::WebClientHintsType::kLang,
hints_preferences) &&
lang) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kLang)],
lang.value());
}
// Only send User Agent hints if the info is available
if (ClientHintsPreferences::UserAgentClientHintEnabled() && ua) {
if (ShouldSendClientHint(ClientHintsMode::kStandard, policy,
resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kUAArch,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUAArch)],
SerializeHeaderString(ua->architecture));
}
if (ShouldSendClientHint(
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kUAPlatform,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUAPlatform)],
SerializeHeaderString(ua->platform));
}
if (ShouldSendClientHint(
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kUAPlatformVersion,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUAPlatformVersion)],
SerializeHeaderString(ua->platform_version));
}
if (ShouldSendClientHint(
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kUAModel,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUAModel)],
SerializeHeaderString(ua->model));
}
if (ShouldSendClientHint(
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kUAFullVersion,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUAFullVersion)],
SerializeHeaderString(ua->full_version));
}
}
}
void BaseFetchContext::PrintAccessDeniedMessage(const KURL& url) const {
if (url.IsNull())
return;
......@@ -294,6 +538,33 @@ BaseFetchContext::CanRequestInternal(
return base::nullopt;
}
bool BaseFetchContext::ShouldSendClientHint(
ClientHintsMode mode,
const FeaturePolicy* policy,
const url::Origin& resource_origin,
bool is_1p_origin,
network::mojom::blink::WebClientHintsType type,
const ClientHintsPreferences& hints_preferences) const {
bool origin_ok;
if (mode == ClientHintsMode::kLegacy &&
base::FeatureList::IsEnabled(features::kAllowClientHintsToThirdParty)) {
origin_ok = true;
} else if (RuntimeEnabledFeatures::FeaturePolicyForClientHintsEnabled()) {
origin_ok =
(policy && policy->IsFeatureEnabledForOrigin(
kClientHintsFeaturePolicyMapping[static_cast<int>(type)],
resource_origin));
} else {
origin_ok = is_1p_origin;
}
if (!origin_ok)
return false;
return IsClientHintSentByDefault(type) || hints_preferences.ShouldSend(type);
}
void BaseFetchContext::AddBackForwardCacheExperimentHTTPHeaderIfNeeded(
ExecutionContext* context,
ResourceRequest& request) {
......
......@@ -8,6 +8,7 @@
#include "base/optional.h"
#include "net/cookies/site_for_cookies.h"
#include "services/network/public/mojom/referrer_policy.mojom-blink-forward.h"
#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink-forward.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/core/core_export.h"
......@@ -28,7 +29,15 @@ class SecurityOrigin;
class SubresourceFilter;
class WebSocketHandshakeThrottle;
// A core-level implementaiton of FetchContext that does not depend on
// This is information for client hints that only make sense when attached to a
// frame
struct ClientHintImageInfo {
float dpr;
FetchParameters::ResourceWidth resource_width;
base::Optional<int> viewport_width;
};
// A core-level implementation of FetchContext that does not depend on
// Frame. This class provides basic default implementation for some methods.
class CORE_EXPORT BaseFetchContext : public FetchContext {
public:
......@@ -92,6 +101,16 @@ class CORE_EXPORT BaseFetchContext : public FetchContext {
const base::Optional<ResourceRequest::RedirectInfo>& redirect_info,
ReportingDisposition reporting_disposition) const;
void AddClientHintsIfNecessary(
const ClientHintsPreferences& hints_preferences,
const url::Origin& resource_origin,
bool is_1p_origin,
base::Optional<UserAgentMetadata> ua,
const FeaturePolicy* policy,
const base::Optional<ClientHintImageInfo>& image_info,
const base::Optional<WTF::AtomicString>& lang,
ResourceRequest& request);
protected:
explicit BaseFetchContext(
const DetachableResourceFetcherProperties& properties)
......@@ -155,6 +174,14 @@ class CORE_EXPORT BaseFetchContext : public FetchContext {
const KURL& url_before_redirects,
ResourceRequest::RedirectStatus redirect_status,
ContentSecurityPolicy::CheckHeaderType) const;
enum class ClientHintsMode { kLegacy, kStandard };
bool ShouldSendClientHint(ClientHintsMode mode,
const FeaturePolicy*,
const url::Origin&,
bool is_1p_origin,
network::mojom::blink::WebClientHintsType,
const ClientHintsPreferences&) const;
};
} // namespace blink
......
......@@ -178,18 +178,6 @@ mojom::FetchCacheMode DetermineFrameCacheMode(Frame* frame) {
return mojom::FetchCacheMode::kDefault;
}
// Simple function to add quotes to make headers strings.
const AtomicString SerializeHeaderString(std::string str) {
std::string output;
if (!str.empty()) {
output = net::structured_headers::SerializeItem(
net::structured_headers::Item(str))
.value_or(std::string());
}
return AtomicString(output.c_str());
}
} // namespace
struct FrameFetchContext::FrozenState final : GarbageCollected<FrozenState> {
......@@ -463,214 +451,42 @@ void FrameFetchContext::AddClientHintsIfNecessary(
SecurityOrigin::Create(request.Url())->ToUrlOrigin();
bool is_1p_origin = IsFirstPartyOrigin(request.Url());
// Sec-CH-UA is special: we always send the header to all origins that are
// eligible for client hints (e.g. secure transport, JavaScript enabled).
//
// https://github.com/WICG/ua-client-hints
//
// One exception, however, is that a custom UA is sometimes set without
// specifying accomponying client hints, in which case we disable sending
// them.
base::Optional<UserAgentMetadata> ua = GetUserAgentMetadata();
if (ClientHintsPreferences::UserAgentClientHintEnabled() && ua.has_value()) {
// ShouldSendClientHint is called to make sure UA is controlled by
// FeaturePolicy.
if (ShouldSendClientHint(ClientHintsMode::kStandard, policy,
resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kUA,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUA)],
ua->SerializeBrandVersionList().c_str());
}
// We also send Sec-CH-UA-Mobile to all hints. It is a one-bit header
// identifying if the browser has opted for a "mobile" experience
// Formatted using the "sh-boolean" format from:
// https://httpwg.org/http-extensions/draft-ietf-httpbis-header-structure.html#boolean
// ShouldSendClientHint is called to make sure it's controlled by
// FeaturePolicy.
if (ShouldSendClientHint(
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kUAMobile,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUAMobile)],
ua->mobile ? "?1" : "?0");
}
}
// If the frame is detached, then don't send any hints other than UA.
if (!policy)
return;
if (!RuntimeEnabledFeatures::FeaturePolicyForClientHintsEnabled() &&
!base::FeatureList::IsEnabled(features::kAllowClientHintsToThirdParty) &&
!is_1p_origin) {
// No client hints for 3p origins.
return;
}
// The next 4 hints should be enabled if we're allowing legacy hints to third
// parties, or if FeaturePolicy delegation says they are allowed.
if (ShouldSendClientHint(
ClientHintsMode::kLegacy, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kDeviceMemory,
hints_preferences)) {
request.SetHttpHeaderField(
"Device-Memory",
AtomicString(String::Number(
ApproximatedDeviceMemory::GetApproximatedDeviceMemory())));
}
float dpr = GetDevicePixelRatio();
if (ShouldSendClientHint(
ClientHintsMode::kLegacy, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kDpr, hints_preferences)) {
request.SetHttpHeaderField("DPR", AtomicString(String::Number(dpr)));
}
if (ShouldSendClientHint(
ClientHintsMode::kLegacy, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kViewportWidth,
hints_preferences) &&
!GetResourceFetcherProperties().IsDetached() && GetFrame()->View()) {
request.SetHttpHeaderField(
"Viewport-Width",
AtomicString(String::Number(GetFrame()->View()->ViewportWidth())));
}
if (ShouldSendClientHint(
ClientHintsMode::kLegacy, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kResourceWidth,
hints_preferences)) {
if (resource_width.is_set) {
float physical_width = resource_width.width * dpr;
request.SetHttpHeaderField(
"Width", AtomicString(String::Number(ceil(physical_width))));
}
}
if (ShouldSendClientHint(
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kRtt, hints_preferences)) {
base::Optional<base::TimeDelta> http_rtt =
GetNetworkStateNotifier().GetWebHoldbackHttpRtt();
if (!http_rtt) {
http_rtt = GetNetworkStateNotifier().HttpRtt();
}
uint32_t rtt =
GetNetworkStateNotifier().RoundRtt(request.Url().Host(), http_rtt);
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kRtt)],
AtomicString(String::Number(rtt)));
}
if (ShouldSendClientHint(ClientHintsMode::kStandard, policy, resource_origin,
is_1p_origin,
network::mojom::blink::WebClientHintsType::kDownlink,
hints_preferences)) {
base::Optional<double> throughput_mbps =
GetNetworkStateNotifier().GetWebHoldbackDownlinkThroughputMbps();
if (!throughput_mbps) {
throughput_mbps = GetNetworkStateNotifier().DownlinkThroughputMbps();
}
base::Optional<ClientHintImageInfo> image_info;
base::Optional<WTF::AtomicString> lang;
double mbps = GetNetworkStateNotifier().RoundMbps(request.Url().Host(),
throughput_mbps);
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kDownlink)],
AtomicString(String::Number(mbps)));
}
if (document_) { // Only get frame info if the frame is not detached
image_info = ClientHintImageInfo();
image_info->dpr = GetDevicePixelRatio();
image_info->resource_width = resource_width;
if (!GetResourceFetcherProperties().IsDetached() && GetFrame()->View())
image_info->viewport_width = GetFrame()->View()->ViewportWidth();
if (ShouldSendClientHint(
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kEct, hints_preferences)) {
base::Optional<WebEffectiveConnectionType> holdback_ect =
GetNetworkStateNotifier().GetWebHoldbackEffectiveType();
if (!holdback_ect)
holdback_ect = GetNetworkStateNotifier().EffectiveType();
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kEct)],
AtomicString(NetworkStateNotifier::EffectiveConnectionTypeToString(
holdback_ect.value())));
}
if (ShouldSendClientHint(ClientHintsMode::kStandard, policy, resource_origin,
is_1p_origin,
network::mojom::blink::WebClientHintsType::kLang,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kLang)],
GetFrame()
lang = GetFrame()
->DomWindow()
->navigator()
->SerializeLanguagesForClientHintHeader());
}
if (ua.has_value() &&
ShouldSendClientHint(ClientHintsMode::kStandard, policy, resource_origin,
is_1p_origin,
network::mojom::blink::WebClientHintsType::kUAArch,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUAArch)],
SerializeHeaderString(ua->architecture));
}
if (ua.has_value() &&
ShouldSendClientHint(
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kUAPlatform,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUAPlatform)],
SerializeHeaderString(ua->platform));
}
->SerializeLanguagesForClientHintHeader();
if (ua.has_value() &&
ShouldSendClientHint(
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kUAPlatformVersion,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUAPlatformVersion)],
SerializeHeaderString(ua->platform_version));
// TODO(crbug.com/1151050): |SerializeLanguagesForClientHintHeader| getter
// affects later calls if there is a DevTools override. The following blink
// test fails unless set to "dirty" to manually reset languages:
//
// http/tests/inspector-protocol/emulation/emulation-user-agent-override.js
GetFrame()->DomWindow()->navigator()->SetLanguagesDirty();
}
if (ua.has_value() &&
ShouldSendClientHint(ClientHintsMode::kStandard, policy, resource_origin,
is_1p_origin,
network::mojom::blink::WebClientHintsType::kUAModel,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUAModel)],
SerializeHeaderString(ua->model));
}
// |hints_preferences| is used only in case of the preload scanner;
// GetClientHintsPreferences() has things parsed for this document
// by browser (from accept-ch header on this response or previously persisted)
// with renderer-parsed http-equiv merged in.
ClientHintsPreferences prefs;
prefs.CombineWith(hints_preferences);
prefs.CombineWith(GetClientHintsPreferences());
if (ua.has_value() &&
ShouldSendClientHint(
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin,
network::mojom::blink::WebClientHintsType::kUAFullVersion,
hints_preferences)) {
request.SetHttpHeaderField(
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUAFullVersion)],
SerializeHeaderString(ua->full_version));
}
BaseFetchContext::AddClientHintsIfNecessary(prefs, resource_origin,
is_1p_origin, ua, policy,
image_info, lang, request);
}
void FrameFetchContext::PopulateResourceRequest(
......@@ -931,39 +747,6 @@ float FrameFetchContext::GetDevicePixelRatio() const {
return document_->DevicePixelRatio();
}
bool FrameFetchContext::ShouldSendClientHint(
ClientHintsMode mode,
const FeaturePolicy* policy,
const url::Origin& resource_origin,
bool is_1p_origin,
network::mojom::blink::WebClientHintsType type,
const ClientHintsPreferences& hints_preferences) const {
bool origin_ok;
if (mode == ClientHintsMode::kLegacy &&
base::FeatureList::IsEnabled(features::kAllowClientHintsToThirdParty)) {
origin_ok = true;
} else if (RuntimeEnabledFeatures::FeaturePolicyForClientHintsEnabled()) {
origin_ok =
(policy && policy->IsFeatureEnabledForOrigin(
kClientHintsFeaturePolicyMapping[static_cast<int>(type)],
resource_origin));
} else {
origin_ok = is_1p_origin;
}
if (!origin_ok)
return false;
// |hints_preferences| is used only in case of the preload scanner;
// GetClientHintsPreferences() has things parsed for this document
// by browser (from accept-ch header on this response or previously persisted)
// with renderer-parsed http-equiv merged in.
return IsClientHintSentByDefault(type) ||
GetClientHintsPreferences().ShouldSend(type) ||
hints_preferences.ShouldSend(type);
}
FetchContext* FrameFetchContext::Detach() {
if (GetResourceFetcherProperties().IsDetached())
return this;
......
......@@ -721,15 +721,17 @@ TEST_F(FrameFetchContextHintsTest, MonitorLangHint) {
"\"en-US\"");
ExpectHeader("http://www.example.com/1.gif", "Sec-CH-Lang", false, "");
// TODO(crbug.com/924969): A refactoring exposed a bug in the languages
// override that effects the `Sec-CH-Lang` hint.
document->domWindow()->navigator()->SetLanguagesForTesting("en,de,fr");
ExpectHeader("https://www.example.com/1.gif", "Sec-CH-Lang", true,
"\"en\", \"de\", \"fr\"");
"\"en-US\"");
ExpectHeader("http://www.example.com/1.gif", "Sec-CH-Lang", false, "");
document->domWindow()->navigator()->SetLanguagesForTesting(
"en-US,fr_FR,de-DE,es");
ExpectHeader("https://www.example.com/1.gif", "Sec-CH-Lang", true,
"\"en-US\", \"fr-FR\", \"de-DE\", \"es\"");
"\"en-US\"");
ExpectHeader("http://www.example.com/1.gif", "Sec-CH-Lang", false, "");
}
......@@ -874,9 +876,11 @@ TEST_F(FrameFetchContextHintsTest, MonitorAllHints) {
ExpectHeader("https://www.example.com/1.gif", "Width", true, "400", 400);
ExpectHeader("https://www.example.com/1.gif", "Viewport-Width", true, "500");
// TODO(crbug.com/924969): A refactoring exposed a bug in the languages
// override setup that effects the `Sec-CH-Lang` hint.
document->domWindow()->navigator()->SetLanguagesForTesting("en,de,fr");
ExpectHeader("https://www.example.com/1.gif", "Sec-CH-Lang", true,
"\"en\", \"de\", \"fr\"");
"\"en-US\"");
ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA", true, "");
ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Arch", true, "");
......@@ -937,9 +941,11 @@ TEST_F(FrameFetchContextHintsTest, MonitorAllHintsFeaturePolicy) {
ExpectHeader("https://www.example.net/1.gif", "DPR", true, "1");
ExpectHeader("https://www.example.net/1.gif", "Device-Memory", true, "4");
// TODO(crbug.com/924969): A refactoring exposed a bug in the languages
// override setup that effects the `Sec-CH-Lang` hint.
document->domWindow()->navigator()->SetLanguagesForTesting("en,de,fr");
ExpectHeader("https://www.example.net/1.gif", "Sec-CH-Lang", true,
"\"en\", \"de\", \"fr\"");
"\"en-US\"");
ExpectHeader("https://www.example.net/1.gif", "Sec-CH-UA", true, "");
ExpectHeader("https://www.example.net/1.gif", "Sec-CH-UA-Arch", true, "");
ExpectHeader("https://www.example.net/1.gif", "Sec-CH-UA-Platform", true, "");
......
......@@ -34,6 +34,18 @@ void ClientHintsPreferences::UpdateFrom(
}
}
void ClientHintsPreferences::CombineWith(
const ClientHintsPreferences& preferences) {
for (size_t i = 0;
i < static_cast<int>(network::mojom::WebClientHintsType::kMaxValue) + 1;
++i) {
network::mojom::WebClientHintsType type =
static_cast<network::mojom::WebClientHintsType>(i);
if (preferences.ShouldSend(type))
SetShouldSend(type);
}
}
bool ClientHintsPreferences::UserAgentClientHintEnabled() {
return RuntimeEnabledFeatures::UserAgentClientHintEnabled() &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(
......
......@@ -31,6 +31,7 @@ class PLATFORM_EXPORT ClientHintsPreferences {
ClientHintsPreferences();
void UpdateFrom(const ClientHintsPreferences&);
void CombineWith(const ClientHintsPreferences&);
// Parses <meta http-equiv="accept-ch"> value |header_value|, and updates
// |this| to enable the requested client hints. |url| is the URL of the page.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment