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 @@ ...@@ -4,7 +4,11 @@
#include "third_party/blink/renderer/core/loader/base_fetch_context.h" #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 "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/common/features.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.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" #include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
...@@ -23,9 +27,26 @@ ...@@ -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_fetcher_properties.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.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/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/scheme_registry.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.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 { namespace blink {
base::Optional<ResourceRequestBlockedReason> BaseFetchContext::CanRequest( base::Optional<ResourceRequestBlockedReason> BaseFetchContext::CanRequest(
...@@ -90,6 +111,229 @@ bool BaseFetchContext::SendConversionRequestInsteadOfRedirecting( ...@@ -90,6 +111,229 @@ bool BaseFetchContext::SendConversionRequestInsteadOfRedirecting(
return false; 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 { void BaseFetchContext::PrintAccessDeniedMessage(const KURL& url) const {
if (url.IsNull()) if (url.IsNull())
return; return;
...@@ -294,6 +538,33 @@ BaseFetchContext::CanRequestInternal( ...@@ -294,6 +538,33 @@ BaseFetchContext::CanRequestInternal(
return base::nullopt; 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( void BaseFetchContext::AddBackForwardCacheExperimentHTTPHeaderIfNeeded(
ExecutionContext* context, ExecutionContext* context,
ResourceRequest& request) { ResourceRequest& request) {
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/optional.h" #include "base/optional.h"
#include "net/cookies/site_for_cookies.h" #include "net/cookies/site_for_cookies.h"
#include "services/network/public/mojom/referrer_policy.mojom-blink-forward.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/mojom/fetch/fetch_api_request.mojom-blink-forward.h"
#include "third_party/blink/public/platform/web_url_request.h" #include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/core_export.h"
...@@ -28,7 +29,15 @@ class SecurityOrigin; ...@@ -28,7 +29,15 @@ class SecurityOrigin;
class SubresourceFilter; class SubresourceFilter;
class WebSocketHandshakeThrottle; 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. // Frame. This class provides basic default implementation for some methods.
class CORE_EXPORT BaseFetchContext : public FetchContext { class CORE_EXPORT BaseFetchContext : public FetchContext {
public: public:
...@@ -92,6 +101,16 @@ class CORE_EXPORT BaseFetchContext : public FetchContext { ...@@ -92,6 +101,16 @@ class CORE_EXPORT BaseFetchContext : public FetchContext {
const base::Optional<ResourceRequest::RedirectInfo>& redirect_info, const base::Optional<ResourceRequest::RedirectInfo>& redirect_info,
ReportingDisposition reporting_disposition) const; 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: protected:
explicit BaseFetchContext( explicit BaseFetchContext(
const DetachableResourceFetcherProperties& properties) const DetachableResourceFetcherProperties& properties)
...@@ -155,6 +174,14 @@ class CORE_EXPORT BaseFetchContext : public FetchContext { ...@@ -155,6 +174,14 @@ class CORE_EXPORT BaseFetchContext : public FetchContext {
const KURL& url_before_redirects, const KURL& url_before_redirects,
ResourceRequest::RedirectStatus redirect_status, ResourceRequest::RedirectStatus redirect_status,
ContentSecurityPolicy::CheckHeaderType) const; 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 } // namespace blink
......
...@@ -178,18 +178,6 @@ mojom::FetchCacheMode DetermineFrameCacheMode(Frame* frame) { ...@@ -178,18 +178,6 @@ mojom::FetchCacheMode DetermineFrameCacheMode(Frame* frame) {
return mojom::FetchCacheMode::kDefault; 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 } // namespace
struct FrameFetchContext::FrozenState final : GarbageCollected<FrozenState> { struct FrameFetchContext::FrozenState final : GarbageCollected<FrozenState> {
...@@ -463,214 +451,42 @@ void FrameFetchContext::AddClientHintsIfNecessary( ...@@ -463,214 +451,42 @@ void FrameFetchContext::AddClientHintsIfNecessary(
SecurityOrigin::Create(request.Url())->ToUrlOrigin(); SecurityOrigin::Create(request.Url())->ToUrlOrigin();
bool is_1p_origin = IsFirstPartyOrigin(request.Url()); 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(); 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, base::Optional<ClientHintImageInfo> image_info;
is_1p_origin, base::Optional<WTF::AtomicString> lang;
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(), if (document_) { // Only get frame info if the frame is not detached
throughput_mbps); image_info = ClientHintImageInfo();
request.SetHttpHeaderField( image_info->dpr = GetDevicePixelRatio();
blink::kClientHintsHeaderMapping[static_cast<size_t>( image_info->resource_width = resource_width;
network::mojom::blink::WebClientHintsType::kDownlink)], if (!GetResourceFetcherProperties().IsDetached() && GetFrame()->View())
AtomicString(String::Number(mbps))); image_info->viewport_width = GetFrame()->View()->ViewportWidth();
}
if (ShouldSendClientHint( lang = GetFrame()
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()
->DomWindow() ->DomWindow()
->navigator() ->navigator()
->SerializeLanguagesForClientHintHeader()); ->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));
}
if (ua.has_value() && // TODO(crbug.com/1151050): |SerializeLanguagesForClientHintHeader| getter
ShouldSendClientHint( // affects later calls if there is a DevTools override. The following blink
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin, // test fails unless set to "dirty" to manually reset languages:
network::mojom::blink::WebClientHintsType::kUAPlatformVersion, //
hints_preferences)) { // http/tests/inspector-protocol/emulation/emulation-user-agent-override.js
request.SetHttpHeaderField( GetFrame()->DomWindow()->navigator()->SetLanguagesDirty();
blink::kClientHintsHeaderMapping[static_cast<size_t>(
network::mojom::blink::WebClientHintsType::kUAPlatformVersion)],
SerializeHeaderString(ua->platform_version));
} }
if (ua.has_value() && // |hints_preferences| is used only in case of the preload scanner;
ShouldSendClientHint(ClientHintsMode::kStandard, policy, resource_origin, // GetClientHintsPreferences() has things parsed for this document
is_1p_origin, // by browser (from accept-ch header on this response or previously persisted)
network::mojom::blink::WebClientHintsType::kUAModel, // with renderer-parsed http-equiv merged in.
hints_preferences)) { ClientHintsPreferences prefs;
request.SetHttpHeaderField( prefs.CombineWith(hints_preferences);
blink::kClientHintsHeaderMapping[static_cast<size_t>( prefs.CombineWith(GetClientHintsPreferences());
network::mojom::blink::WebClientHintsType::kUAModel)],
SerializeHeaderString(ua->model));
}
if (ua.has_value() && BaseFetchContext::AddClientHintsIfNecessary(prefs, resource_origin,
ShouldSendClientHint( is_1p_origin, ua, policy,
ClientHintsMode::kStandard, policy, resource_origin, is_1p_origin, image_info, lang, request);
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 FrameFetchContext::PopulateResourceRequest( void FrameFetchContext::PopulateResourceRequest(
...@@ -931,39 +747,6 @@ float FrameFetchContext::GetDevicePixelRatio() const { ...@@ -931,39 +747,6 @@ float FrameFetchContext::GetDevicePixelRatio() const {
return document_->DevicePixelRatio(); 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() { FetchContext* FrameFetchContext::Detach() {
if (GetResourceFetcherProperties().IsDetached()) if (GetResourceFetcherProperties().IsDetached())
return this; return this;
......
...@@ -721,15 +721,17 @@ TEST_F(FrameFetchContextHintsTest, MonitorLangHint) { ...@@ -721,15 +721,17 @@ TEST_F(FrameFetchContextHintsTest, MonitorLangHint) {
"\"en-US\""); "\"en-US\"");
ExpectHeader("http://www.example.com/1.gif", "Sec-CH-Lang", false, ""); 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"); document->domWindow()->navigator()->SetLanguagesForTesting("en,de,fr");
ExpectHeader("https://www.example.com/1.gif", "Sec-CH-Lang", true, 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, ""); ExpectHeader("http://www.example.com/1.gif", "Sec-CH-Lang", false, "");
document->domWindow()->navigator()->SetLanguagesForTesting( document->domWindow()->navigator()->SetLanguagesForTesting(
"en-US,fr_FR,de-DE,es"); "en-US,fr_FR,de-DE,es");
ExpectHeader("https://www.example.com/1.gif", "Sec-CH-Lang", true, 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, ""); ExpectHeader("http://www.example.com/1.gif", "Sec-CH-Lang", false, "");
} }
...@@ -874,9 +876,11 @@ TEST_F(FrameFetchContextHintsTest, MonitorAllHints) { ...@@ -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", "Width", true, "400", 400);
ExpectHeader("https://www.example.com/1.gif", "Viewport-Width", true, "500"); 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"); document->domWindow()->navigator()->SetLanguagesForTesting("en,de,fr");
ExpectHeader("https://www.example.com/1.gif", "Sec-CH-Lang", true, 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", true, "");
ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Arch", true, ""); ExpectHeader("https://www.example.com/1.gif", "Sec-CH-UA-Arch", true, "");
...@@ -937,9 +941,11 @@ TEST_F(FrameFetchContextHintsTest, MonitorAllHintsFeaturePolicy) { ...@@ -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", "DPR", true, "1");
ExpectHeader("https://www.example.net/1.gif", "Device-Memory", true, "4"); 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"); document->domWindow()->navigator()->SetLanguagesForTesting("en,de,fr");
ExpectHeader("https://www.example.net/1.gif", "Sec-CH-Lang", true, 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", true, "");
ExpectHeader("https://www.example.net/1.gif", "Sec-CH-UA-Arch", 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, ""); ExpectHeader("https://www.example.net/1.gif", "Sec-CH-UA-Platform", true, "");
......
...@@ -34,6 +34,18 @@ void ClientHintsPreferences::UpdateFrom( ...@@ -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() { bool ClientHintsPreferences::UserAgentClientHintEnabled() {
return RuntimeEnabledFeatures::UserAgentClientHintEnabled() && return RuntimeEnabledFeatures::UserAgentClientHintEnabled() &&
!base::CommandLine::ForCurrentProcess()->HasSwitch( !base::CommandLine::ForCurrentProcess()->HasSwitch(
......
...@@ -31,6 +31,7 @@ class PLATFORM_EXPORT ClientHintsPreferences { ...@@ -31,6 +31,7 @@ class PLATFORM_EXPORT ClientHintsPreferences {
ClientHintsPreferences(); ClientHintsPreferences();
void UpdateFrom(const ClientHintsPreferences&); void UpdateFrom(const ClientHintsPreferences&);
void CombineWith(const ClientHintsPreferences&);
// Parses <meta http-equiv="accept-ch"> value |header_value|, and updates // 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. // |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