blob: e4241bf6bbc60019d309377e25a06b0faaf41937 [file] [log] [blame]
Tarun Bansal0b8b7afd2017-08-25 03:52:161// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Tarun Bansal62efba12018-05-04 22:58:355#include <cctype>
Peter Boström924f8032021-04-02 20:36:026#include <memory>
Tarun Bansal62efba12018-05-04 22:58:357
Mike West2fddeeb72019-02-15 11:29:488#include "base/base_switches.h"
Tarun Bansal229647bd002018-02-27 17:33:369#include "base/bind.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1610#include "base/command_line.h"
Jan Wilken Dörrieb5a41c32020-12-09 18:55:4711#include "base/containers/contains.h"
Tarun Bansalbef6d652018-10-02 18:41:0112#include "base/metrics/field_trial_param_associator.h"
Gabriel Charetteb71eec892017-09-14 22:52:5613#include "base/run_loop.h"
Mike Weste555be862019-02-20 16:17:3014#include "base/strings/string_util.h"
Callum May7d88ff3e2019-11-12 18:21:4615#include "base/synchronization/lock.h"
Devlin Cronin626d80c2018-06-01 01:08:3616#include "base/test/metrics/histogram_tester.h"
Tarun Bansal5c28afb2018-03-17 02:55:2017#include "build/build_config.h"
Tarun Bansala61f0f62017-10-24 23:53:0518#include "chrome/browser/content_settings/cookie_settings_factory.h"
Tarun Bansal1965b042017-09-07 04:59:1919#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
François Beaufort34e299e2021-05-26 05:54:3320#include "chrome/browser/devtools/protocol/devtools_protocol_test_support.h"
Aaron Tagliaboschi8f3a28302020-06-24 03:08:2621#include "chrome/browser/policy/policy_test_utils.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1622#include "chrome/browser/profiles/profile.h"
Tarun Bansal1965b042017-09-07 04:59:1923#include "chrome/browser/ui/browser.h"
Maks Orlovich73f374d2020-04-02 12:46:1324#include "chrome/browser/ui/browser_commands.h"
Aaron Tagliaboschi25625c22021-05-11 18:13:5925#include "chrome/test/base/chrome_test_utils.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1626#include "chrome/test/base/in_process_browser_test.h"
27#include "chrome/test/base/ui_test_utils.h"
Carlos Caballerob4283202020-08-10 14:40:4628#include "components/content_settings/browser/page_specific_content_settings.h"
Tarun Bansala61f0f62017-10-24 23:53:0529#include "components/content_settings/core/browser/cookie_settings.h"
Tarun Bansal1965b042017-09-07 04:59:1930#include "components/content_settings/core/browser/host_content_settings_map.h"
Tarun Bansala61f0f62017-10-24 23:53:0531#include "components/content_settings/core/common/pref_names.h"
John Abd-El-Malekec1fc69e2021-01-28 19:14:4132#include "components/embedder_support/user_agent_utils.h"
John Abd-El-Malek161073c2020-06-12 20:40:2833#include "components/metrics/content/subprocess_metrics_provider.h"
Aaron Tagliaboschi25625c22021-05-11 18:13:5934#include "components/page_load_metrics/browser/page_load_metrics_test_waiter.h"
Aaron Tagliaboschi8f3a28302020-06-24 03:08:2635#include "components/policy/core/common/policy_map.h"
36#include "components/policy/core/common/policy_pref_names.h"
37#include "components/policy/policy_constants.h"
Tarun Bansala61f0f62017-10-24 23:53:0538#include "components/prefs/pref_service.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1639#include "content/public/browser/browser_thread.h"
Maks Orlovich73f374d2020-04-02 12:46:1340#include "content/public/browser/navigation_entry.h"
Changwan Ryu434c3a32019-07-30 23:42:5841#include "content/public/browser/render_view_host.h"
Tarun Bansalbef6d652018-10-02 18:41:0142#include "content/public/common/content_features.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1643#include "content/public/common/content_switches.h"
Peter Kasting919ce652020-05-07 10:22:3644#include "content/public/test/browser_test.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1645#include "content/public/test/browser_test_utils.h"
46#include "content/public/test/test_utils.h"
Tarun Bansal229647bd002018-02-27 17:33:3647#include "content/public/test/url_loader_interceptor.h"
48#include "net/dns/mock_host_resolver.h"
49#include "net/http/http_request_headers.h"
Tarun Bansal7f3fe8c2018-04-06 22:37:4750#include "net/nqe/effective_connection_type.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1651#include "net/test/embedded_test_server/embedded_test_server.h"
Tarun Bansal1965b042017-09-07 04:59:1952#include "net/test/embedded_test_server/http_request.h"
Tarun Bansal229647bd002018-02-27 17:33:3653#include "net/test/embedded_test_server/http_response.h"
Aaron Tagliaboschi603540d22021-04-05 00:37:1454#include "services/network/public/cpp/client_hints.h"
Tarun Bansal74e189d2018-05-07 19:07:3555#include "services/network/public/cpp/cors/cors.h"
Tarun Bansalceab9592018-05-01 18:57:3556#include "services/network/public/cpp/features.h"
Tarun Bansal7f3fe8c2018-04-06 22:37:4757#include "services/network/public/cpp/network_switches.h"
Aaron Tagliaboschi603540d22021-04-05 00:37:1458#include "services/network/public/mojom/web_client_hints_types.mojom-shared.h"
Blink Reformata30d4232018-04-07 15:31:0659#include "third_party/blink/public/common/client_hints/client_hints.h"
Gyuyoung Kim1ac4ca782020-09-11 03:32:5160#include "third_party/blink/public/common/web_preferences/web_preferences.h"
Tarun Bansal229647bd002018-02-27 17:33:3661
62namespace {
63
Aaron Tagliaboschiec5bce62021-06-24 18:50:0964const unsigned expected_client_hints_number = 13u;
Yoav Weiss76e1afb762020-05-14 19:28:1265const int32_t uma_histogram_max_value = 1471228928;
Yoav Weissd33bacb2020-03-12 06:42:2166
Tarun Bansal229647bd002018-02-27 17:33:3667// An interceptor that records count of fetches and client hint headers for
68// requests to https://foo.com/non-existing-image.jpg.
Jay Civelli1ff872d2018-03-09 21:52:1669class ThirdPartyURLLoaderInterceptor {
Tarun Bansal229647bd002018-02-27 17:33:3670 public:
Jay Civelli1ff872d2018-03-09 21:52:1671 explicit ThirdPartyURLLoaderInterceptor(const GURL intercepted_url)
72 : intercepted_url_(intercepted_url),
73 interceptor_(base::BindRepeating(
74 &ThirdPartyURLLoaderInterceptor::InterceptURLRequest,
75 base::Unretained(this))) {}
Tarun Bansal229647bd002018-02-27 17:33:3676
Jay Civelli1ff872d2018-03-09 21:52:1677 ~ThirdPartyURLLoaderInterceptor() = default;
Tarun Bansal229647bd002018-02-27 17:33:3678
79 size_t request_count_seen() const { return request_count_seen_; }
80
81 size_t client_hints_count_seen() const { return client_hints_count_seen_; }
82
83 private:
Jay Civelli1ff872d2018-03-09 21:52:1684 bool InterceptURLRequest(
85 content::URLLoaderInterceptor::RequestParams* params) {
86 if (params->url_request.url != intercepted_url_)
87 return false;
Tarun Bansal229647bd002018-02-27 17:33:3688
Jay Civelli1ff872d2018-03-09 21:52:1689 request_count_seen_++;
Mike West14c11102019-02-04 16:16:4790 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Tarun Bansalf9cf9892018-04-06 04:38:0191 if (params->url_request.headers.HasHeader(
92 blink::kClientHintsHeaderMapping[i])) {
93 client_hints_count_seen_++;
94 }
Tarun Bansal5c28afb2018-03-17 02:55:2095 }
Jay Civelli1ff872d2018-03-09 21:52:1696 return false;
97 }
Tarun Bansal229647bd002018-02-27 17:33:3698
Jay Civelli1ff872d2018-03-09 21:52:1699 GURL intercepted_url_;
100
101 size_t request_count_seen_ = 0u;
102
103 size_t client_hints_count_seen_ = 0u;
104
105 content::URLLoaderInterceptor interceptor_;
106
107 DISALLOW_COPY_AND_ASSIGN(ThirdPartyURLLoaderInterceptor);
Tarun Bansal229647bd002018-02-27 17:33:36108};
109
Tarun Bansal62efba12018-05-04 22:58:35110// Returns true only if |header_value| satisfies ABNF: 1*DIGIT [ "." 1*DIGIT ]
111bool IsSimilarToDoubleABNF(const std::string& header_value) {
112 if (header_value.empty())
113 return false;
114 char first_char = header_value.at(0);
115 if (!isdigit(first_char))
116 return false;
117
118 bool period_found = false;
119 bool digit_found_after_period = false;
120 for (char ch : header_value) {
121 if (isdigit(ch)) {
122 if (period_found) {
123 digit_found_after_period = true;
124 }
125 continue;
126 }
127 if (ch == '.') {
128 if (period_found)
129 return false;
130 period_found = true;
131 continue;
132 }
133 return false;
134 }
135 if (period_found)
136 return digit_found_after_period;
137 return true;
138}
139
140// Returns true only if |header_value| satisfies ABNF: 1*DIGIT
141bool IsSimilarToIntABNF(const std::string& header_value) {
142 if (header_value.empty())
143 return false;
144
145 for (char ch : header_value) {
146 if (!isdigit(ch))
147 return false;
148 }
149 return true;
150}
151
Tarun Bansal229647bd002018-02-27 17:33:36152} // namespace
Tarun Bansal0b8b7afd2017-08-25 03:52:16153
Aaron Tagliaboschi8f3a28302020-06-24 03:08:26154class ClientHintsBrowserTest : public policy::PolicyTest,
Tarun Bansal9a7051f2018-07-10 18:30:05155 public testing::WithParamInterface<bool> {
Tarun Bansal0b8b7afd2017-08-25 03:52:16156 public:
157 ClientHintsBrowserTest()
Mikel Astiz2de748d2019-11-16 10:39:36158 : http_server_(net::EmbeddedTestServer::TYPE_HTTP),
Tarun Bansal3b330b02017-11-09 19:03:14159 https_server_(net::EmbeddedTestServer::TYPE_HTTPS),
Tarun Bansal345418632018-06-29 11:07:04160 https_cross_origin_server_(net::EmbeddedTestServer::TYPE_HTTPS),
Tarun Bansal229647bd002018-02-27 17:33:36161 expect_client_hints_on_main_frame_(false),
162 expect_client_hints_on_subresources_(false),
Mike West2fddeeb72019-02-15 11:29:48163 count_user_agent_hint_headers_seen_(0),
Maks Orlovich5dcc99c2020-02-13 19:07:46164 count_ua_mobile_client_hints_headers_seen_(0),
Aaron Tagliaboschiec5bce62021-06-24 18:50:09165 count_ua_platform_client_hints_headers_seen_(0),
Tarun Bansal229647bd002018-02-27 17:33:36166 count_client_hints_headers_seen_(0),
167 request_interceptor_(nullptr) {
Tarun Bansal3b330b02017-11-09 19:03:14168 http_server_.ServeFilesFromSourceDirectory("chrome/test/data/client_hints");
Tarun Bansal0b8b7afd2017-08-25 03:52:16169 https_server_.ServeFilesFromSourceDirectory(
170 "chrome/test/data/client_hints");
Tarun Bansal345418632018-06-29 11:07:04171 https_cross_origin_server_.ServeFilesFromSourceDirectory(
172 "chrome/test/data/client_hints");
Tarun Bansal1965b042017-09-07 04:59:19173
Tarun Bansal3b330b02017-11-09 19:03:14174 http_server_.RegisterRequestMonitor(
Tarun Bansal345418632018-06-29 11:07:04175 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
176 base::Unretained(this)));
Tarun Bansal1965b042017-09-07 04:59:19177 https_server_.RegisterRequestMonitor(
Tarun Bansal345418632018-06-29 11:07:04178 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
179 base::Unretained(this)));
180 https_cross_origin_server_.RegisterRequestMonitor(
181 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
182 base::Unretained(this)));
Tarun Bansal293a7b6c2018-12-05 17:41:12183 https_cross_origin_server_.RegisterRequestHandler(
184 base::BindRepeating(&ClientHintsBrowserTest::RequestHandlerToRedirect,
185 base::Unretained(this)));
Tarun Bansal345418632018-06-29 11:07:04186 https_server_.RegisterRequestHandler(base::BindRepeating(
187 &ClientHintsBrowserTest::RequestHandlerToFetchCrossOriginIframe,
188 base::Unretained(this)));
Tarun Bansal1965b042017-09-07 04:59:19189
Tarun Bansal3b330b02017-11-09 19:03:14190 EXPECT_TRUE(http_server_.Start());
Tarun Bansal0b8b7afd2017-08-25 03:52:16191 EXPECT_TRUE(https_server_.Start());
Tarun Bansal345418632018-06-29 11:07:04192 EXPECT_TRUE(https_cross_origin_server_.Start());
193
194 EXPECT_NE(https_server_.base_url(), https_cross_origin_server_.base_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:16195
Tarun Bansal3b330b02017-11-09 19:03:14196 accept_ch_with_lifetime_http_local_url_ =
197 http_server_.GetURL("/accept_ch_with_lifetime.html");
Tarun Bansal9a7051f2018-07-10 18:30:05198 http_equiv_accept_ch_with_lifetime_http_local_url_ =
199 http_server_.GetURL("/http_equiv_accept_ch_with_lifetime.html");
Tarun Bansal3b330b02017-11-09 19:03:14200 EXPECT_TRUE(accept_ch_with_lifetime_http_local_url_.SchemeIsHTTPOrHTTPS());
201 EXPECT_FALSE(
202 accept_ch_with_lifetime_http_local_url_.SchemeIsCryptographic());
203
Tarun Bansal1965b042017-09-07 04:59:19204 accept_ch_with_lifetime_url_ =
205 https_server_.GetURL("/accept_ch_with_lifetime.html");
Tarun Bansal73502f92019-04-16 21:21:19206 accept_ch_with_short_lifetime_url_ =
207 https_server_.GetURL("/accept_ch_with_short_lifetime.html");
Tarun Bansal0b8b7afd2017-08-25 03:52:16208
Tarun Bansal1965b042017-09-07 04:59:19209 accept_ch_without_lifetime_url_ =
210 https_server_.GetURL("/accept_ch_without_lifetime.html");
211 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsHTTPOrHTTPS());
212 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal9a7051f2018-07-10 18:30:05213 http_equiv_accept_ch_without_lifetime_url_ =
214 https_server_.GetURL("/http_equiv_accept_ch_without_lifetime.html");
Tarun Bansal1965b042017-09-07 04:59:19215
216 without_accept_ch_without_lifetime_url_ =
217 https_server_.GetURL("/without_accept_ch_without_lifetime.html");
218 EXPECT_TRUE(without_accept_ch_without_lifetime_url_.SchemeIsHTTPOrHTTPS());
219 EXPECT_TRUE(
220 without_accept_ch_without_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal3b330b02017-11-09 19:03:14221
222 without_accept_ch_without_lifetime_local_url_ =
223 http_server_.GetURL("/without_accept_ch_without_lifetime.html");
224 EXPECT_TRUE(
225 without_accept_ch_without_lifetime_local_url_.SchemeIsHTTPOrHTTPS());
226 EXPECT_FALSE(
227 without_accept_ch_without_lifetime_local_url_.SchemeIsCryptographic());
Tarun Bansaladd5e1812018-02-09 19:07:58228
229 without_accept_ch_without_lifetime_img_localhost_ = https_server_.GetURL(
230 "/without_accept_ch_without_lifetime_img_localhost.html");
231 without_accept_ch_without_lifetime_img_foo_com_ = https_server_.GetURL(
232 "/without_accept_ch_without_lifetime_img_foo_com.html");
233 accept_ch_without_lifetime_with_iframe_url_ =
234 https_server_.GetURL("/accept_ch_without_lifetime_with_iframe.html");
Tarun Bansal9a7051f2018-07-10 18:30:05235 http_equiv_accept_ch_without_lifetime_with_iframe_url_ =
236 https_server_.GetURL(
237 "/http_equiv_accept_ch_without_lifetime_with_iframe.html");
Tarun Bansal62cc3542018-06-27 23:53:30238 accept_ch_without_lifetime_with_subresource_url_ = https_server_.GetURL(
239 "/accept_ch_without_lifetime_with_subresource.html");
Tarun Bansal9a7051f2018-07-10 18:30:05240 http_equiv_accept_ch_without_lifetime_with_subresource_url_ =
241 https_server_.GetURL(
242 "/http_equiv_accept_ch_without_lifetime_with_subresource.html");
Tarun Bansal62cc3542018-06-27 23:53:30243 accept_ch_without_lifetime_with_subresource_iframe_url_ =
244 https_server_.GetURL(
245 "/accept_ch_without_lifetime_with_subresource_iframe.html");
Tarun Bansal9a7051f2018-07-10 18:30:05246 http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_ =
247 https_server_.GetURL(
248 "/http_equiv_accept_ch_without_lifetime_with_subresource_iframe."
249 "html");
Tarun Bansal229647bd002018-02-27 17:33:36250 accept_ch_without_lifetime_img_localhost_ =
251 https_server_.GetURL("/accept_ch_without_lifetime_img_localhost.html");
Tarun Bansal9a7051f2018-07-10 18:30:05252 http_equiv_accept_ch_without_lifetime_img_localhost_ = https_server_.GetURL(
253 "/http_equiv_accept_ch_without_lifetime_img_localhost.html");
254 http_equiv_accept_ch_with_lifetime_ =
255 https_server_.GetURL("/http_equiv_accept_ch_with_lifetime.html");
Tarun Bansal293a7b6c2018-12-05 17:41:12256
257 redirect_url_ = https_cross_origin_server_.GetURL("/redirect.html");
Maks Orlovich7a588d82020-05-06 15:17:24258
259 accept_ch_empty_ = https_server_.GetURL("/accept_ch_empty.html");
260 http_equiv_accept_ch_merge_ =
261 https_server_.GetURL("/http_equiv_accept_ch_merge.html");
Tarun Bansal0b8b7afd2017-08-25 03:52:16262 }
263
264 ~ClientHintsBrowserTest() override {}
265
Mike West2fddeeb72019-02-15 11:29:48266 virtual std::unique_ptr<base::FeatureList> EnabledFeatures() {
267 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
Maks Orlovichc66745a2020-06-30 17:40:02268 feature_list->InitializeFromCommandLine(
Aaron Tagliaboschi603540d22021-04-05 00:37:14269 "UserAgentClientHint,LangClientHintHeader,CriticalClientHint,"
François Beaufort1b51d062021-05-18 11:11:23270 "AcceptCHFrame,PrefersColorSchemeClientHintHeader",
Aaron Tagliaboschi603540d22021-04-05 00:37:14271 "");
Mike West2fddeeb72019-02-15 11:29:48272 return feature_list;
273 }
274
275 void SetUp() override {
Maksim Sisov (GMT+3)830244f2020-08-10 12:52:24276 scoped_feature_list_.InitWithFeatureList(EnabledFeatures());
Mike West2fddeeb72019-02-15 11:29:48277 InProcessBrowserTest::SetUp();
278 }
279
Tarun Bansal0b8b7afd2017-08-25 03:52:16280 void SetUpOnMainThread() override {
Tarun Bansal229647bd002018-02-27 17:33:36281 host_resolver()->AddRule("*", "127.0.0.1");
Tarun Bansal229647bd002018-02-27 17:33:36282
Jay Civelli1ff872d2018-03-09 21:52:16283 request_interceptor_ = std::make_unique<ThirdPartyURLLoaderInterceptor>(
284 GURL("https://foo.com/non-existing-image.jpg"));
Tarun Bansal229647bd002018-02-27 17:33:36285 base::RunLoop().RunUntilIdle();
Tarun Bansal0b8b7afd2017-08-25 03:52:16286 }
287
Jay Civelli1ff872d2018-03-09 21:52:16288 void TearDownOnMainThread() override { request_interceptor_.reset(); }
289
Tarun Bansal0b8b7afd2017-08-25 03:52:16290 void SetUpCommandLine(base::CommandLine* cmd) override {
Tarun Bansal7f3fe8c2018-04-06 22:37:47291 cmd->AppendSwitchASCII(network::switches::kForceEffectiveConnectionType,
292 net::kEffectiveConnectionType2G);
Tarun Bansal0b8b7afd2017-08-25 03:52:16293 }
294
Tarun Bansal229647bd002018-02-27 17:33:36295 void SetClientHintExpectationsOnMainFrame(bool expect_client_hints) {
296 expect_client_hints_on_main_frame_ = expect_client_hints;
Tarun Bansal1965b042017-09-07 04:59:19297 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16298
Tarun Bansal229647bd002018-02-27 17:33:36299 void SetClientHintExpectationsOnSubresources(bool expect_client_hints) {
Callum May1d939742020-03-02 17:51:30300 base::AutoLock lock(expect_client_hints_on_subresources_lock_);
Tarun Bansal229647bd002018-02-27 17:33:36301 expect_client_hints_on_subresources_ = expect_client_hints;
Tarun Bansala61f0f62017-10-24 23:53:05302 }
303
Callum May1d939742020-03-02 17:51:30304 bool expect_client_hints_on_subresources() {
305 base::AutoLock lock(expect_client_hints_on_subresources_lock_);
306 return expect_client_hints_on_subresources_;
307 }
308
Tarun Bansalc211d8b2018-03-19 19:21:58309 // Verify that the user is not notified that cookies or JavaScript were
310 // blocked on the webpage due to the checks done by client hints.
311 void VerifyContentSettingsNotNotified() const {
Carlos Caballerob4283202020-08-10 14:40:46312 auto* pscs = content_settings::PageSpecificContentSettings::GetForFrame(
Carlos Caballerod7b759412020-07-31 18:00:08313 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
Carlos Caballerob4283202020-08-10 14:40:46314 EXPECT_FALSE(pscs->IsContentBlocked(ContentSettingsType::COOKIES));
315 EXPECT_FALSE(pscs->IsContentBlocked(ContentSettingsType::JAVASCRIPT));
Tarun Bansalc211d8b2018-03-19 19:21:58316 }
317
Tarun Bansalbef6d652018-10-02 18:41:01318 void SetExpectedEffectiveConnectionType(
319 net::EffectiveConnectionType effective_connection_type) {
320 expected_ect = effective_connection_type;
321 }
322
Changwan Ryu434c3a32019-07-30 23:42:58323 void SetJsEnabledForActiveView(bool enabled) {
Rakina Zata Amni347b70902020-07-22 10:49:04324 content::WebContents* web_contents =
325 browser()->tab_strip_model()->GetActiveWebContents();
Gyuyoung Kim1ac4ca782020-09-11 03:32:51326 blink::web_pref::WebPreferences prefs =
327 web_contents->GetOrCreateWebPreferences();
Changwan Ryu434c3a32019-07-30 23:42:58328 prefs.javascript_enabled = enabled;
Rakina Zata Amni347b70902020-07-22 10:49:04329 web_contents->SetWebPreferences(prefs);
Changwan Ryu434c3a32019-07-30 23:42:58330 }
331
Maks Orlovich7227ce0d2020-02-28 17:13:16332 void TestProfilesIndependent(Browser* browser_a, Browser* browser_b);
333
Tarun Bansal3b330b02017-11-09 19:03:14334 const GURL& accept_ch_with_lifetime_http_local_url() const {
335 return accept_ch_with_lifetime_http_local_url_;
336 }
Tarun Bansal9a7051f2018-07-10 18:30:05337 const GURL& http_equiv_accept_ch_with_lifetime_http_local_url() const {
338 return http_equiv_accept_ch_with_lifetime_http_local_url_;
339 }
Tarun Bansal3b330b02017-11-09 19:03:14340
Tarun Bansal1965b042017-09-07 04:59:19341 // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
342 // headers.
343 const GURL& accept_ch_with_lifetime_url() const {
344 return accept_ch_with_lifetime_url_;
345 }
Tarun Bansal9a7051f2018-07-10 18:30:05346 const GURL& http_equiv_accept_ch_with_lifetime() {
347 return http_equiv_accept_ch_with_lifetime_;
348 }
Tarun Bansal1965b042017-09-07 04:59:19349
Tarun Bansal73502f92019-04-16 21:21:19350 // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
351 // headers. The Accept-CH-Lifetime duration is set very short to 1 second.
352 const GURL& accept_ch_with_short_lifetime() const {
353 return accept_ch_with_short_lifetime_url_;
354 }
355
Tarun Bansal1965b042017-09-07 04:59:19356 // A URL whose response headers include only Accept-CH header.
357 const GURL& accept_ch_without_lifetime_url() const {
358 return accept_ch_without_lifetime_url_;
359 }
Tarun Bansal9a7051f2018-07-10 18:30:05360 const GURL& http_equiv_accept_ch_without_lifetime_url() const {
361 return http_equiv_accept_ch_without_lifetime_url_;
362 }
Tarun Bansal1965b042017-09-07 04:59:19363
364 // A URL whose response headers do not include either Accept-CH or
365 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
366 const GURL& without_accept_ch_without_lifetime_url() const {
367 return without_accept_ch_without_lifetime_url_;
368 }
369
Tarun Bansal3b330b02017-11-09 19:03:14370 // A URL whose response headers do not include either Accept-CH or
371 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
372 const GURL& without_accept_ch_without_lifetime_local_url() const {
373 return without_accept_ch_without_lifetime_local_url_;
374 }
375
Tarun Bansaladd5e1812018-02-09 19:07:58376 // A URL whose response headers do not include either Accept-CH or
377 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
378 // from localhost.
379 const GURL& without_accept_ch_without_lifetime_img_localhost() const {
380 return without_accept_ch_without_lifetime_img_localhost_;
381 }
382
383 // A URL whose response headers do not include either Accept-CH or
384 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
385 // from foo.com.
386 const GURL& without_accept_ch_without_lifetime_img_foo_com() const {
387 return without_accept_ch_without_lifetime_img_foo_com_;
388 }
389
390 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
391 // headers. The response loads accept_ch_with_lifetime_url() in an iframe.
392 const GURL& accept_ch_without_lifetime_with_iframe_url() const {
393 return accept_ch_without_lifetime_with_iframe_url_;
394 }
Tarun Bansal9a7051f2018-07-10 18:30:05395 const GURL& http_equiv_accept_ch_without_lifetime_with_iframe_url() const {
396 return http_equiv_accept_ch_without_lifetime_with_iframe_url_;
397 }
Tarun Bansaladd5e1812018-02-09 19:07:58398
Tarun Bansal62cc3542018-06-27 23:53:30399 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
400 // headers. The response loads accept_ch_with_lifetime_url() as a subresource
401 // in the main frame.
402 const GURL& accept_ch_without_lifetime_with_subresource_url() const {
403 return accept_ch_without_lifetime_with_subresource_url_;
404 }
Tarun Bansal9a7051f2018-07-10 18:30:05405 const GURL& http_equiv_accept_ch_without_lifetime_with_subresource_url()
406 const {
407 return http_equiv_accept_ch_without_lifetime_with_subresource_url_;
408 }
Tarun Bansal62cc3542018-06-27 23:53:30409
410 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
Tarun Bansal9a7051f2018-07-10 18:30:05411 // headers. The response loads accept_ch_with_lifetime_url() or
412 // http_equiv_accept_ch_with_lifetime_url() as a subresource in the iframe.
Tarun Bansal62cc3542018-06-27 23:53:30413 const GURL& accept_ch_without_lifetime_with_subresource_iframe_url() const {
414 return accept_ch_without_lifetime_with_subresource_iframe_url_;
415 }
Tarun Bansal9a7051f2018-07-10 18:30:05416 const GURL&
417 http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url() const {
418 return http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_;
419 }
Tarun Bansal62cc3542018-06-27 23:53:30420
Tarun Bansal9a7051f2018-07-10 18:30:05421 // A URL whose response includes only Accept-CH header. Navigating to
Tarun Bansal229647bd002018-02-27 17:33:36422 // this URL also fetches two images: One from the localhost, and one from
423 // foo.com.
424 const GURL& accept_ch_without_lifetime_img_localhost() const {
425 return accept_ch_without_lifetime_img_localhost_;
426 }
Tarun Bansal9a7051f2018-07-10 18:30:05427 const GURL& http_equiv_accept_ch_without_lifetime_img_localhost() const {
428 return http_equiv_accept_ch_without_lifetime_img_localhost_;
429 }
Tarun Bansal229647bd002018-02-27 17:33:36430
Tarun Bansal293a7b6c2018-12-05 17:41:12431 const GURL& redirect_url() const { return redirect_url_; }
432
Maks Orlovich7a588d82020-05-06 15:17:24433 // A URL to a page with a response containing an empty accept_ch header.
434 const GURL& accept_ch_empty() const { return accept_ch_empty_; }
435
436 // A page where some hints are in accept-ch header, some in http-equiv.
437 const GURL& http_equiv_accept_ch_merge() const {
438 return http_equiv_accept_ch_merge_;
439 }
440
Mike West2fddeeb72019-02-15 11:29:48441 size_t count_user_agent_hint_headers_seen() const {
Callum May7d88ff3e2019-11-12 18:21:46442 base::AutoLock lock(count_headers_lock_);
Mike West2fddeeb72019-02-15 11:29:48443 return count_user_agent_hint_headers_seen_;
444 }
445
Maks Orlovich5dcc99c2020-02-13 19:07:46446 size_t count_ua_mobile_client_hints_headers_seen() const {
447 base::AutoLock lock(count_headers_lock_);
448 return count_ua_mobile_client_hints_headers_seen_;
449 }
450
Aaron Tagliaboschiec5bce62021-06-24 18:50:09451 size_t count_ua_platform_client_hints_headers_seen() const {
452 base::AutoLock lock(count_headers_lock_);
453 return count_ua_platform_client_hints_headers_seen_;
454 }
455
Tarun Bansal1965b042017-09-07 04:59:19456 size_t count_client_hints_headers_seen() const {
Callum May7d88ff3e2019-11-12 18:21:46457 base::AutoLock lock(count_headers_lock_);
Tarun Bansal1965b042017-09-07 04:59:19458 return count_client_hints_headers_seen_;
459 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16460
Tarun Bansal229647bd002018-02-27 17:33:36461 size_t third_party_request_count_seen() const {
462 return request_interceptor_->request_count_seen();
463 }
464
465 size_t third_party_client_hints_count_seen() const {
466 return request_interceptor_->client_hints_count_seen();
467 }
468
Mike Weste555be862019-02-20 16:17:30469 const std::string& main_frame_ua_observed() const {
470 return main_frame_ua_observed_;
471 }
472
Yoav Weissd33bacb2020-03-12 06:42:21473 const std::string& main_frame_ua_full_version_observed() const {
474 return main_frame_ua_full_version_observed_;
475 }
476
Maks Orlovich73f374d2020-04-02 12:46:13477 const std::string& main_frame_ua_mobile_observed() const {
478 return main_frame_ua_mobile_observed_;
479 }
480
481 const std::string& main_frame_ua_platform_observed() const {
482 return main_frame_ua_platform_observed_;
483 }
484
Tarun Bansalea0d8262018-05-21 16:11:50485 base::test::ScopedFeatureList scoped_feature_list_;
486
Tarun Bansal345418632018-06-29 11:07:04487 std::string intercept_iframe_resource_;
Tarun Bansal9a7051f2018-07-10 18:30:05488 bool intercept_to_http_equiv_iframe_ = false;
Callum May7d88ff3e2019-11-12 18:21:46489 mutable base::Lock count_headers_lock_;
Tarun Bansal345418632018-06-29 11:07:04490
Tarun Bansal0b8b7afd2017-08-25 03:52:16491 private:
Tarun Bansal345418632018-06-29 11:07:04492 // Intercepts only the main frame requests that contain
Tarun Bansal293a7b6c2018-12-05 17:41:12493 // "redirect" in the resource path. The intercepted requests
494 // are served an HTML file that fetches an iframe from a cross-origin HTTPS
495 // server.
496 std::unique_ptr<net::test_server::HttpResponse> RequestHandlerToRedirect(
497 const net::test_server::HttpRequest& request) {
498 // Check if it's a main frame request.
499 if (request.relative_url.find(".html") == std::string::npos)
500 return nullptr;
501
502 if (request.GetURL().spec().find("redirect") == std::string::npos)
503 return nullptr;
504
Lei Zhange00db752021-04-17 00:48:46505 auto response = std::make_unique<net::test_server::BasicHttpResponse>();
Tarun Bansal293a7b6c2018-12-05 17:41:12506 response->set_code(net::HTTP_FOUND);
507 response->AddCustomHeader("Location",
508 without_accept_ch_without_lifetime_url().spec());
509 return std::move(response);
510 }
511
512 // Intercepts only the main frame requests that contain
Tarun Bansal345418632018-06-29 11:07:04513 // |intercept_iframe_resource_| in the resource path. The intercepted requests
514 // are served an HTML file that fetches an iframe from a cross-origin HTTPS
515 // server.
516 std::unique_ptr<net::test_server::HttpResponse>
517 RequestHandlerToFetchCrossOriginIframe(
518 const net::test_server::HttpRequest& request) {
519 if (intercept_iframe_resource_.empty())
520 return nullptr;
521
522 // Check if it's a main frame request.
523 if (request.relative_url.find(".html") == std::string::npos)
524 return nullptr;
525
526 if (request.relative_url.find(intercept_iframe_resource_) ==
527 std::string::npos) {
528 return nullptr;
529 }
530
531 const std::string iframe_url =
Tarun Bansal9a7051f2018-07-10 18:30:05532 intercept_to_http_equiv_iframe_
533 ? https_cross_origin_server_
534 .GetURL("/http_equiv_accept_ch_with_lifetime.html")
535 .spec()
536 : https_cross_origin_server_.GetURL("/accept_ch_with_lifetime.html")
537 .spec();
Tarun Bansal345418632018-06-29 11:07:04538
539 std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
540 new net::test_server::BasicHttpResponse());
541 http_response->set_code(net::HTTP_OK);
542 http_response->set_content_type("text/html");
543 http_response->set_content(
544 "<html>"
545 "<link rel='icon' href='data:;base64,='><head></head>"
546 "Empty file which uses link-rel to disable favicon fetches. "
547 "<iframe src='" +
548 iframe_url + "'></iframe></html>");
549
550 return std::move(http_response);
551 }
552
Maks Orlovich73f374d2020-04-02 12:46:13553 static std::string UpdateHeaderObservation(
554 const net::test_server::HttpRequest& request,
555 const std::string& header) {
556 if (request.headers.find(header) != request.headers.end())
557 return request.headers.find(header)->second;
558 else
559 return "";
560 }
561
Tarun Bansal1965b042017-09-07 04:59:19562 // Called by |https_server_|.
563 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
Tarun Bansal6bf54302017-10-02 07:39:14564 bool is_main_frame_navigation =
565 request.GetURL().spec().find(".html") != std::string::npos;
566
Tarun Bansal293a7b6c2018-12-05 17:41:12567 if (is_main_frame_navigation &&
568 request.GetURL().spec().find("redirect") != std::string::npos) {
569 return;
570 }
571
Tarun Bansal229647bd002018-02-27 17:33:36572 if (is_main_frame_navigation) {
Maks Orlovich73f374d2020-04-02 12:46:13573 main_frame_ua_observed_ = UpdateHeaderObservation(request, "sec-ch-ua");
574 main_frame_ua_full_version_observed_ =
575 UpdateHeaderObservation(request, "sec-ch-ua-full-version");
576 main_frame_ua_mobile_observed_ =
577 UpdateHeaderObservation(request, "sec-ch-ua-mobile");
578 main_frame_ua_platform_observed_ =
579 UpdateHeaderObservation(request, "sec-ch-ua-platform");
Yoav Weissd33bacb2020-03-12 06:42:21580
Tarun Bansalf9cf9892018-04-06 04:38:01581 VerifyClientHintsReceived(expect_client_hints_on_main_frame_, request);
Tarun Bansal5c28afb2018-03-17 02:55:20582 if (expect_client_hints_on_main_frame_) {
583 double value = 0.0;
584 EXPECT_TRUE(base::StringToDouble(
585 request.headers.find("device-memory")->second, &value));
586 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35587 EXPECT_TRUE(IsSimilarToDoubleABNF(
588 request.headers.find("device-memory")->second));
Tarun Bansal44ad96882018-03-28 17:47:42589 main_frame_device_memory_observed_ = value;
Tarun Bansal5c28afb2018-03-17 02:55:20590
591 EXPECT_TRUE(
592 base::StringToDouble(request.headers.find("dpr")->second, &value));
593 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35594 EXPECT_TRUE(IsSimilarToDoubleABNF(request.headers.find("dpr")->second));
Tarun Bansal44ad96882018-03-28 17:47:42595 main_frame_dpr_observed_ = value;
596
Tarun Bansal5c28afb2018-03-17 02:55:20597 EXPECT_TRUE(base::StringToDouble(
598 request.headers.find("viewport-width")->second, &value));
Tarun Bansal62efba12018-05-04 22:58:35599 EXPECT_TRUE(
600 IsSimilarToIntABNF(request.headers.find("viewport-width")->second));
Tarun Bansal79df868e2018-03-20 23:01:36601#if !defined(OS_ANDROID)
Tarun Bansal5c28afb2018-03-17 02:55:20602 EXPECT_LT(0.0, value);
Tarun Bansal79df868e2018-03-20 23:01:36603#else
604 EXPECT_EQ(980, value);
Tarun Bansal5c28afb2018-03-17 02:55:20605#endif
Tarun Bansal44ad96882018-03-28 17:47:42606 main_frame_viewport_width_observed_ = value;
Mike Weste555be862019-02-20 16:17:30607
Tarun Bansal7f3fe8c2018-04-06 22:37:47608 VerifyNetworkQualityClientHints(request);
Tarun Bansal5c28afb2018-03-17 02:55:20609 }
Tarun Bansala61f0f62017-10-24 23:53:05610 }
Tarun Bansal6bf54302017-10-02 07:39:14611
Tarun Bansal229647bd002018-02-27 17:33:36612 if (!is_main_frame_navigation) {
Callum May1d939742020-03-02 17:51:30613 VerifyClientHintsReceived(expect_client_hints_on_subresources(), request);
Tarun Bansal5c28afb2018-03-17 02:55:20614
Callum May1d939742020-03-02 17:51:30615 if (expect_client_hints_on_subresources()) {
Tarun Bansal5c28afb2018-03-17 02:55:20616 double value = 0.0;
617 EXPECT_TRUE(base::StringToDouble(
618 request.headers.find("device-memory")->second, &value));
619 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35620 EXPECT_TRUE(IsSimilarToDoubleABNF(
621 request.headers.find("device-memory")->second));
Tarun Bansal44ad96882018-03-28 17:47:42622 if (main_frame_device_memory_observed_ > 0) {
623 EXPECT_EQ(main_frame_device_memory_observed_, value);
624 }
Tarun Bansal5c28afb2018-03-17 02:55:20625
626 EXPECT_TRUE(
627 base::StringToDouble(request.headers.find("dpr")->second, &value));
628 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35629 EXPECT_TRUE(IsSimilarToDoubleABNF(request.headers.find("dpr")->second));
Tarun Bansal44ad96882018-03-28 17:47:42630 if (main_frame_dpr_observed_ > 0) {
631 EXPECT_EQ(main_frame_dpr_observed_, value);
632 }
Tarun Bansal5c28afb2018-03-17 02:55:20633
634 EXPECT_TRUE(base::StringToDouble(
635 request.headers.find("viewport-width")->second, &value));
Tarun Bansal62efba12018-05-04 22:58:35636 EXPECT_TRUE(
637 IsSimilarToIntABNF(request.headers.find("viewport-width")->second));
Tarun Bansal79df868e2018-03-20 23:01:36638#if !defined(OS_ANDROID)
Tarun Bansal5c28afb2018-03-17 02:55:20639 EXPECT_LT(0.0, value);
Tarun Bansal79df868e2018-03-20 23:01:36640#else
641 EXPECT_EQ(980, value);
642#endif
Tarun Bansal44ad96882018-03-28 17:47:42643#if defined(OS_ANDROID)
644 // TODO(tbansal): https://crbug.com/825892: Viewport width on main
645 // frame requests may be incorrect when the Chrome window is not
646 // maximized.
647 if (main_frame_viewport_width_observed_ > 0) {
648 EXPECT_EQ(main_frame_viewport_width_observed_, value);
649 }
650#endif
Tarun Bansal7f3fe8c2018-04-06 22:37:47651 VerifyNetworkQualityClientHints(request);
Tarun Bansal5c28afb2018-03-17 02:55:20652 }
Tarun Bansala61f0f62017-10-24 23:53:05653 }
Tarun Bansal6bf54302017-10-02 07:39:14654
Mike West14c11102019-02-04 16:16:47655 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Jan Wilken Dörriea8cb56302019-06-06 18:59:36656 if (base::Contains(request.headers,
657 blink::kClientHintsHeaderMapping[i])) {
Callum May7d88ff3e2019-11-12 18:21:46658 base::AutoLock lock(count_headers_lock_);
Mike West2fddeeb72019-02-15 11:29:48659 // The user agent hint is special:
660 if (std::string(blink::kClientHintsHeaderMapping[i]) == "sec-ch-ua") {
661 count_user_agent_hint_headers_seen_++;
Maks Orlovich5dcc99c2020-02-13 19:07:46662 } else if (std::string(blink::kClientHintsHeaderMapping[i]) ==
663 "sec-ch-ua-mobile") {
664 count_ua_mobile_client_hints_headers_seen_++;
Aaron Tagliaboschiec5bce62021-06-24 18:50:09665 } else if (std::string(blink::kClientHintsHeaderMapping[i]) ==
666 "sec-ch-ua-platform") {
667 count_ua_platform_client_hints_headers_seen_++;
Mike West2fddeeb72019-02-15 11:29:48668 } else {
669 count_client_hints_headers_seen_++;
670 }
Tarun Bansalf9cf9892018-04-06 04:38:01671 }
672 }
673 }
Tarun Bansal1965b042017-09-07 04:59:19674
Tarun Bansalf9cf9892018-04-06 04:38:01675 void VerifyClientHintsReceived(bool expect_client_hints,
676 const net::test_server::HttpRequest& request) {
Mike West14c11102019-02-04 16:16:47677 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
678 SCOPED_TRACE(testing::Message()
679 << std::string(blink::kClientHintsHeaderMapping[i]));
Tarun Bansalf9cf9892018-04-06 04:38:01680 // Resource width client hint is only attached on image subresources.
681 if (std::string(blink::kClientHintsHeaderMapping[i]) == "width") {
682 continue;
683 }
Mike West2fddeeb72019-02-15 11:29:48684
Aaron Tagliaboschiec5bce62021-06-24 18:50:09685 // `Sec-CH-UA`, `Sec-CH-UA-Mobile`, and `Sec-CH-UA-Platform` is attached
686 // on all requests.
Maks Orlovich5dcc99c2020-02-13 19:07:46687 if (std::string(blink::kClientHintsHeaderMapping[i]) == "sec-ch-ua" ||
688 std::string(blink::kClientHintsHeaderMapping[i]) ==
Aaron Tagliaboschiec5bce62021-06-24 18:50:09689 "sec-ch-ua-mobile" ||
690 std::string(blink::kClientHintsHeaderMapping[i]) ==
691 "sec-ch-ua-platform") {
Mike West2fddeeb72019-02-15 11:29:48692 continue;
693 }
694
Jan Wilken Dörriea8cb56302019-06-06 18:59:36695 EXPECT_EQ(
696 expect_client_hints,
697 base::Contains(request.headers, blink::kClientHintsHeaderMapping[i]));
Tarun Bansalf9cf9892018-04-06 04:38:01698 }
Tarun Bansal1965b042017-09-07 04:59:19699 }
700
Tarun Bansal7f3fe8c2018-04-06 22:37:47701 void VerifyNetworkQualityClientHints(
702 const net::test_server::HttpRequest& request) const {
703 // Effective connection type is forced to 2G using command line in these
704 // tests.
Tarun Bansal509a8dd2018-04-10 17:19:16705 int rtt_value = 0.0;
Tarun Bansal7f3fe8c2018-04-06 22:37:47706 EXPECT_TRUE(
Tarun Bansal509a8dd2018-04-10 17:19:16707 base::StringToInt(request.headers.find("rtt")->second, &rtt_value));
708 EXPECT_LE(0, rtt_value);
Tarun Bansal62efba12018-05-04 22:58:35709 EXPECT_TRUE(IsSimilarToIntABNF(request.headers.find("rtt")->second));
Tarun Bansal509a8dd2018-04-10 17:19:16710 // Verify that RTT value is a multiple of 50 milliseconds.
711 EXPECT_EQ(0, rtt_value % 50);
Tarun Bansalbef6d652018-10-02 18:41:01712 EXPECT_GE(expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G ? 3000 : 500,
713 rtt_value);
Tarun Bansal7f3fe8c2018-04-06 22:37:47714
Tarun Bansal509a8dd2018-04-10 17:19:16715 double mbps_value = 0.0;
716 EXPECT_TRUE(base::StringToDouble(request.headers.find("downlink")->second,
717 &mbps_value));
718 EXPECT_LE(0, mbps_value);
Tarun Bansal62efba12018-05-04 22:58:35719 EXPECT_TRUE(
720 IsSimilarToDoubleABNF(request.headers.find("downlink")->second));
Tarun Bansal509a8dd2018-04-10 17:19:16721 // Verify that the mbps value is a multiple of 0.050 mbps.
722 // Allow for small amount of noise due to double to integer conversions.
723 EXPECT_NEAR(0, (static_cast<int>(mbps_value * 1000)) % 50, 1);
724 EXPECT_GE(10.0, mbps_value);
Tarun Bansal7f3fe8c2018-04-06 22:37:47725
726 EXPECT_FALSE(request.headers.find("ect")->second.empty());
Tarun Bansalceab9592018-05-01 18:57:35727
728 // TODO(tbansal): https://crbug.com/819244: When network servicification is
Tarun Bansal5ac533542018-08-10 19:45:52729 // enabled, the renderer processes do not receive notifications on
730 // change in the network quality. Hence, the network quality client hints
731 // are not set to the correct value on subresources.
732 bool is_main_frame_navigation =
733 request.GetURL().spec().find(".html") != std::string::npos;
John Abd-El-Malek67facbe82019-06-06 22:37:08734 if (is_main_frame_navigation) {
Tarun Bansalceab9592018-05-01 18:57:35735 // Effective connection type is forced to 2G using command line in these
736 // tests. RTT is expected to be 1800 msec but leave some gap to account
737 // for added noise and randomization.
Tarun Bansalbef6d652018-10-02 18:41:01738 if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G) {
739 EXPECT_NEAR(1800, rtt_value, 360);
740 } else if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_3G) {
741 EXPECT_NEAR(450, rtt_value, 90);
742 } else {
743 NOTREACHED();
744 }
Tarun Bansalceab9592018-05-01 18:57:35745
746 // Effective connection type is forced to 2G using command line in these
747 // tests. downlink is expected to be 0.075 Mbps but leave some gap to
748 // account for added noise and randomization.
Tarun Bansalbef6d652018-10-02 18:41:01749 if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G) {
750 EXPECT_NEAR(0.075, mbps_value, 0.05);
751 } else if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_3G) {
752 EXPECT_NEAR(0.4, mbps_value, 0.1);
753 } else {
754 NOTREACHED();
755 }
Tarun Bansalceab9592018-05-01 18:57:35756
Tarun Bansalbef6d652018-10-02 18:41:01757 EXPECT_EQ(expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G ? "2g" : "3g",
758 request.headers.find("ect")->second);
Tarun Bansalceab9592018-05-01 18:57:35759 }
Tarun Bansal7f3fe8c2018-04-06 22:37:47760 }
761
Tarun Bansal3b330b02017-11-09 19:03:14762 net::EmbeddedTestServer http_server_;
Tarun Bansal0b8b7afd2017-08-25 03:52:16763 net::EmbeddedTestServer https_server_;
Tarun Bansal345418632018-06-29 11:07:04764 net::EmbeddedTestServer https_cross_origin_server_;
Tarun Bansal3b330b02017-11-09 19:03:14765 GURL accept_ch_with_lifetime_http_local_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05766 GURL http_equiv_accept_ch_with_lifetime_http_local_url_;
Tarun Bansal1965b042017-09-07 04:59:19767 GURL accept_ch_with_lifetime_url_;
Tarun Bansal73502f92019-04-16 21:21:19768 GURL accept_ch_with_short_lifetime_url_;
Tarun Bansal1965b042017-09-07 04:59:19769 GURL accept_ch_without_lifetime_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05770 GURL http_equiv_accept_ch_without_lifetime_url_;
Tarun Bansal1965b042017-09-07 04:59:19771 GURL without_accept_ch_without_lifetime_url_;
Tarun Bansal3b330b02017-11-09 19:03:14772 GURL without_accept_ch_without_lifetime_local_url_;
Tarun Bansaladd5e1812018-02-09 19:07:58773 GURL accept_ch_without_lifetime_with_iframe_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05774 GURL http_equiv_accept_ch_without_lifetime_with_iframe_url_;
Tarun Bansal62cc3542018-06-27 23:53:30775 GURL accept_ch_without_lifetime_with_subresource_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05776 GURL http_equiv_accept_ch_without_lifetime_with_subresource_url_;
Tarun Bansal62cc3542018-06-27 23:53:30777 GURL accept_ch_without_lifetime_with_subresource_iframe_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05778 GURL http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_;
Tarun Bansaladd5e1812018-02-09 19:07:58779 GURL without_accept_ch_without_lifetime_img_foo_com_;
780 GURL without_accept_ch_without_lifetime_img_localhost_;
Tarun Bansal229647bd002018-02-27 17:33:36781 GURL accept_ch_without_lifetime_img_localhost_;
Tarun Bansal9a7051f2018-07-10 18:30:05782 GURL http_equiv_accept_ch_without_lifetime_img_localhost_;
783 GURL http_equiv_accept_ch_with_lifetime_;
Tarun Bansal293a7b6c2018-12-05 17:41:12784 GURL redirect_url_;
Maks Orlovich7a588d82020-05-06 15:17:24785 GURL accept_ch_empty_;
786 GURL http_equiv_accept_ch_merge_;
Tarun Bansal1965b042017-09-07 04:59:19787
Mike Weste555be862019-02-20 16:17:30788 std::string main_frame_ua_observed_;
Yoav Weissd33bacb2020-03-12 06:42:21789 std::string main_frame_ua_full_version_observed_;
Maks Orlovich73f374d2020-04-02 12:46:13790 std::string main_frame_ua_mobile_observed_;
791 std::string main_frame_ua_platform_observed_;
Mike Weste555be862019-02-20 16:17:30792
Tarun Bansal44ad96882018-03-28 17:47:42793 double main_frame_dpr_observed_ = -1;
794 double main_frame_viewport_width_observed_ = -1;
795 double main_frame_device_memory_observed_ = -1;
796
Tarun Bansal229647bd002018-02-27 17:33:36797 // Expect client hints on all the main frame request.
798 bool expect_client_hints_on_main_frame_;
799 // Expect client hints on all the subresource requests.
Callum May1d939742020-03-02 17:51:30800 bool expect_client_hints_on_subresources_
801 GUARDED_BY(expect_client_hints_on_subresources_lock_);
802
803 base::Lock expect_client_hints_on_subresources_lock_;
Tarun Bansal229647bd002018-02-27 17:33:36804
Mike West2fddeeb72019-02-15 11:29:48805 size_t count_user_agent_hint_headers_seen_;
Maks Orlovich5dcc99c2020-02-13 19:07:46806 size_t count_ua_mobile_client_hints_headers_seen_;
Aaron Tagliaboschiec5bce62021-06-24 18:50:09807 size_t count_ua_platform_client_hints_headers_seen_;
Tarun Bansal1965b042017-09-07 04:59:19808 size_t count_client_hints_headers_seen_;
Tarun Bansala61f0f62017-10-24 23:53:05809
Jay Civelli1ff872d2018-03-09 21:52:16810 std::unique_ptr<ThirdPartyURLLoaderInterceptor> request_interceptor_;
Tarun Bansal229647bd002018-02-27 17:33:36811
Tarun Bansalbef6d652018-10-02 18:41:01812 // Set to 2G in SetUpCommandLine().
813 net::EffectiveConnectionType expected_ect = net::EFFECTIVE_CONNECTION_TYPE_2G;
814
Tarun Bansala61f0f62017-10-24 23:53:05815 DISALLOW_COPY_AND_ASSIGN(ClientHintsBrowserTest);
Tarun Bansal0b8b7afd2017-08-25 03:52:16816};
817
Tarun Bansal9a7051f2018-07-10 18:30:05818// True if testing for http-equiv correctness. When set to true, the tests
819// use webpages that may contain http-equiv Accept-CH and Accept-CH-Lifetime
820// headers. When set to false, the tests use webpages that set the headers in
821// the HTTP response headers.
Ilia Samsonov282c38412019-12-09 08:15:10822INSTANTIATE_TEST_SUITE_P(All,
Victor Costane5e91512019-02-13 08:24:02823 ClientHintsBrowserTest,
824 testing::Bool());
Tarun Bansal9a7051f2018-07-10 18:30:05825
Tarun Bansalea0d8262018-05-21 16:11:50826class ClientHintsAllowThirdPartyBrowserTest : public ClientHintsBrowserTest {
Mike West2fddeeb72019-02-15 11:29:48827 std::unique_ptr<base::FeatureList> EnabledFeatures() override {
828 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
829 feature_list->InitializeFromCommandLine(
François Beaufort1b51d062021-05-18 11:11:23830 "AllowClientHintsToThirdParty,UserAgentClientHint,"
831 "LangClientHintHeader,PrefersColorSchemeClientHintHeader",
Maks Orlovichc66745a2020-06-30 17:40:02832 "");
Mike West2fddeeb72019-02-15 11:29:48833 return feature_list;
Tarun Bansalea0d8262018-05-21 16:11:50834 }
835};
836
Ilia Samsonov282c38412019-12-09 08:15:10837INSTANTIATE_TEST_SUITE_P(All,
Aaron Tagliaboschia09ec442019-09-18 15:29:03838 ClientHintsAllowThirdPartyBrowserTest,
839 testing::Bool());
840
Tarun Bansal74e189d2018-05-07 19:07:35841IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, CorsChecks) {
Mike West14c11102019-02-04 16:16:47842 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Tarun Bansal74e189d2018-05-07 19:07:35843 // Do not test for headers that have not been enabled on the blink "stable"
844 // yet.
845 if (std::string(blink::kClientHintsHeaderMapping[i]) == "rtt" ||
846 std::string(blink::kClientHintsHeaderMapping[i]) == "downlink" ||
847 std::string(blink::kClientHintsHeaderMapping[i]) == "ect") {
848 continue;
849 }
Takashi Toyoshima2e01e692018-11-16 03:23:27850 EXPECT_TRUE(network::cors::IsCorsSafelistedHeader(
Tarun Bansal74e189d2018-05-07 19:07:35851 blink::kClientHintsHeaderMapping[i], "42" /* value */));
852 }
Takashi Toyoshima2e01e692018-11-16 03:23:27853 EXPECT_FALSE(network::cors::IsCorsSafelistedHeader("not-a-client-hint-header",
Tarun Bansal74e189d2018-05-07 19:07:35854 "" /* value */));
855 EXPECT_TRUE(
Takashi Toyoshima2e01e692018-11-16 03:23:27856 network::cors::IsCorsSafelistedHeader("save-data", "on" /* value */));
Tarun Bansal74e189d2018-05-07 19:07:35857}
858
Maks Orlovichf0a2eed2020-05-02 20:08:21859IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, HttpEquivWorks) {
860 const GURL gurl = http_equiv_accept_ch_without_lifetime_img_localhost();
861 base::HistogramTester histogram_tester;
862
863 SetClientHintExpectationsOnMainFrame(false);
864 SetClientHintExpectationsOnSubresources(true);
865
866 ui_test_utils::NavigateToURL(browser(), gurl);
867 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
868}
869
Tarun Bansal0b8b7afd2017-08-25 03:52:16870// Loads a webpage that requests persisting of client hints. Verifies that
871// the browser receives the mojo notification from the renderer and persists the
Maks Orlovichf0a2eed2020-05-02 20:08:21872// client hints to the disk --- unless it's using http-equiv which shouldn't
873// persist.
Tarun Bansal9a7051f2018-07-10 18:30:05874IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest, ClientHintsHttps) {
Tarun Bansal0b8b7afd2017-08-25 03:52:16875 base::HistogramTester histogram_tester;
Tarun Bansal9a7051f2018-07-10 18:30:05876 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
877 : accept_ch_with_lifetime_url();
878 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal0b8b7afd2017-08-25 03:52:16879
Maks Orlovichf0a2eed2020-05-02 20:08:21880 if (GetParam())
881 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
882 else
883 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
Tarun Bansal0b8b7afd2017-08-25 03:52:16884
885 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:28886 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal0b8b7afd2017-08-25 03:52:16887
Maks Orlovichf0a2eed2020-05-02 20:08:21888 if (GetParam()) {
889 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
890 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
891 } else {
892 // client_hints_url() sets the expected number of client hints.
893 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
894 expected_client_hints_number, 1);
895 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:12896 // seconds, but a maximum value is registered instead.
Maks Orlovichf0a2eed2020-05-02 20:08:21897 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:12898 uma_histogram_max_value, 1);
Maks Orlovichf0a2eed2020-05-02 20:08:21899 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16900}
901
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44902IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, PRE_ClientHintsClearSession) {
903 const GURL gurl = accept_ch_with_lifetime_url();
904
905 base::HistogramTester histogram_tester;
906 ContentSettingsForOneType host_settings;
907
908 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:14909 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44910 &host_settings);
911 EXPECT_EQ(0u, host_settings.size());
912
913 // Fetching |gurl| should persist the request for client hints iff using
914 // headers and not http-equiv.
915 ui_test_utils::NavigateToURL(browser(), gurl);
916
917 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
918
919 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:28920 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44921 base::RunLoop().RunUntilIdle();
922
923 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
924 expected_client_hints_number, 1);
925 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:12926 // seconds, but a maximum value is registered instead.
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44927 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:12928 uma_histogram_max_value, 1);
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44929
930 // Clients hints preferences for one origin should be persisted.
931 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:14932 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44933 &host_settings);
934 EXPECT_EQ(1u, host_settings.size());
935
936 SetClientHintExpectationsOnMainFrame(true);
937 SetClientHintExpectationsOnSubresources(true);
938 ui_test_utils::NavigateToURL(browser(),
939 without_accept_ch_without_lifetime_url());
940
941 // The user agent hint is attached to all three requests:
942 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
943 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:09944 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44945
946 // Expected number of hints attached to the image request, and the same number
947 // to the main frame request.
948 EXPECT_EQ(expected_client_hints_number * 2,
949 count_client_hints_headers_seen());
950}
951
952IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, ClientHintsClearSession) {
953 const GURL gurl = accept_ch_with_lifetime_url();
954
955 base::HistogramTester histogram_tester;
956 ContentSettingsForOneType host_settings;
957
958 // Clients hints preferences for one origin should be persisted.
959 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:14960 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44961 &host_settings);
962 EXPECT_EQ(0u, host_settings.size());
963
964 SetClientHintExpectationsOnMainFrame(false);
965 SetClientHintExpectationsOnSubresources(false);
966 ui_test_utils::NavigateToURL(browser(),
967 without_accept_ch_without_lifetime_url());
968
969 // The user agent hint is attached to all three requests:
970 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
971 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:09972 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44973
974 // Expected number of hints attached to the image request, and the same number
975 // to the main frame request.
976 EXPECT_EQ(0u, count_client_hints_headers_seen());
977}
978
Tarun Bansaladd5e1812018-02-09 19:07:58979// Test that client hints are attached to subresources only if they belong
980// to the same host as document host.
Maks Orlovichf0a2eed2020-05-02 20:08:21981IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansaladd5e1812018-02-09 19:07:58982 ClientHintsHttpsSubresourceDifferentOrigin) {
Maks Orlovichf0a2eed2020-05-02 20:08:21983 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:05984
Tarun Bansaladd5e1812018-02-09 19:07:58985 base::HistogramTester histogram_tester;
986
987 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:05988 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansaladd5e1812018-02-09 19:07:58989 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
990
991 // Verify that the client hints settings for localhost have been saved.
992 ContentSettingsForOneType client_hints_settings;
993 HostContentSettingsMap* host_content_settings_map =
994 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
995 host_content_settings_map->GetSettingsForOneType(
Illia Klimov48f643c2020-11-05 20:06:14996 ContentSettingsType::CLIENT_HINTS, &client_hints_settings);
Tarun Bansaladd5e1812018-02-09 19:07:58997 ASSERT_EQ(1U, client_hints_settings.size());
998
999 // Copy the client hints setting for localhost to foo.com.
1000 host_content_settings_map->SetWebsiteSettingDefaultScope(
Darin Fisher42f5e7d2019-10-30 07:15:451001 GURL("https://foo.com/"), GURL(), ContentSettingsType::CLIENT_HINTS,
Illia Klimov48f643c2020-11-05 20:06:141002
Jeremy Romanec48d7a2018-03-01 17:35:091003 std::make_unique<base::Value>(
Oksana Zhuravlovab14dc882018-04-12 17:34:571004 client_hints_settings.at(0).setting_value.Clone()));
Tarun Bansaladd5e1812018-02-09 19:07:581005
1006 // Verify that client hints for the two hosts has been saved.
1007 host_content_settings_map =
1008 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
1009 host_content_settings_map->GetSettingsForOneType(
Illia Klimov48f643c2020-11-05 20:06:141010 ContentSettingsType::CLIENT_HINTS, &client_hints_settings);
Tarun Bansaladd5e1812018-02-09 19:07:581011 ASSERT_EQ(2U, client_hints_settings.size());
1012
1013 // Navigating to without_accept_ch_without_lifetime_img_localhost() should
1014 // attach client hints to the image subresouce contained in that page since
1015 // the image is located on the same server as the document origin.
Tarun Bansal229647bd002018-02-27 17:33:361016 SetClientHintExpectationsOnMainFrame(true);
1017 SetClientHintExpectationsOnSubresources(true);
Tarun Bansaladd5e1812018-02-09 19:07:581018 ui_test_utils::NavigateToURL(
1019 browser(), without_accept_ch_without_lifetime_img_localhost());
1020 base::RunLoop().RunUntilIdle();
1021 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281022 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansaladd5e1812018-02-09 19:07:581023
Maks Orlovich5dcc99c2020-02-13 19:07:461024 // The user agent hint is attached to all three requests, as is UA-mobile:
Mike West2fddeeb72019-02-15 11:29:481025 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461026 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091027 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481028
Yoav Weissd33bacb2020-03-12 06:42:211029 // Expected number of hints attached to the image request, and the same number
1030 // to the main frame request.
1031 EXPECT_EQ(expected_client_hints_number * 2,
1032 count_client_hints_headers_seen());
Tarun Bansaladd5e1812018-02-09 19:07:581033
1034 // Navigating to without_accept_ch_without_lifetime_img_foo_com() should not
1035 // attach client hints to the image subresouce contained in that page since
1036 // the image is located on a different server as the document origin.
Tarun Bansaladd5e1812018-02-09 19:07:581037 ui_test_utils::NavigateToURL(
1038 browser(), without_accept_ch_without_lifetime_img_foo_com());
1039 base::RunLoop().RunUntilIdle();
1040 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281041 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansaladd5e1812018-02-09 19:07:581042
Tarun Bansalb30b7532018-03-14 21:50:381043 // The device-memory and dprheader is attached to the main frame request.
Tarun Bansal5c28afb2018-03-17 02:55:201044#if defined(OS_ANDROID)
Yoav Weissd33bacb2020-03-12 06:42:211045 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal5c28afb2018-03-17 02:55:201046#else
Yoav Weissd33bacb2020-03-12 06:42:211047 EXPECT_EQ(expected_client_hints_number * 3,
1048 count_client_hints_headers_seen());
Tarun Bansal5c28afb2018-03-17 02:55:201049#endif
Mike West2fddeeb72019-02-15 11:29:481050
Aaron Tagliaboschiec5bce62021-06-24 18:50:091051 // Requests to third party servers should have three (3) client hints attached
1052 // (`Sec-CH-UA`, `Sec-CH-UA-Mobile`, `Sec-CH-UA-Platform`).
Tarun Bansal229647bd002018-02-27 17:33:361053 EXPECT_EQ(1u, third_party_request_count_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091054 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansaladd5e1812018-02-09 19:07:581055}
1056
Maks Orlovich7227ce0d2020-02-28 17:13:161057// Test that client hints are attached to subresources checks the right setting
1058// for OTR profile.
Maks Orlovichf0a2eed2020-05-02 20:08:211059IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Maks Orlovich7227ce0d2020-02-28 17:13:161060 ClientHintsHttpsSubresourceOffTheRecord) {
Maks Orlovichf0a2eed2020-05-02 20:08:211061 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich7227ce0d2020-02-28 17:13:161062
1063 base::HistogramTester histogram_tester;
1064
1065 // Add client hints for the embedded test server.
1066 ui_test_utils::NavigateToURL(browser(), gurl);
1067 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1068
1069 // Main profile should get hints for both page and subresources.
1070 SetClientHintExpectationsOnMainFrame(true);
1071 SetClientHintExpectationsOnSubresources(true);
1072 ui_test_utils::NavigateToURL(
1073 browser(), without_accept_ch_without_lifetime_img_localhost());
1074 base::RunLoop().RunUntilIdle();
1075 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281076 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Maks Orlovich7227ce0d2020-02-28 17:13:161077
1078 // The user agent hint is attached to all three requests:
1079 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
1080 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091081 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Maks Orlovich7227ce0d2020-02-28 17:13:161082
Yoav Weissd33bacb2020-03-12 06:42:211083 // Expected number of hints attached to the image request, and the same number
1084 // to the main frame request.
1085 EXPECT_EQ(expected_client_hints_number * 2,
1086 count_client_hints_headers_seen());
Maks Orlovich7227ce0d2020-02-28 17:13:161087
1088 // OTR profile should get neither.
1089 Browser* otr_browser = CreateIncognitoBrowser(browser()->profile());
1090 SetClientHintExpectationsOnMainFrame(false);
1091 SetClientHintExpectationsOnSubresources(false);
1092 ui_test_utils::NavigateToURL(
1093 otr_browser, without_accept_ch_without_lifetime_img_localhost());
1094}
1095
Mike Weste555be862019-02-20 16:17:301096// Verify that we send only major version information in the `Sec-CH-UA` header
Yoav Weissd33bacb2020-03-12 06:42:211097// by default, regardless of opt-in.
Maks Orlovichf0a2eed2020-05-02 20:08:211098IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UserAgentVersion) {
1099 const GURL gurl = accept_ch_with_lifetime_url();
Mike Weste555be862019-02-20 16:17:301100
John Abd-El-Malekec1fc69e2021-01-28 19:14:411101 blink::UserAgentMetadata ua = embedder_support::GetUserAgentMetadata();
Mike Weste555be862019-02-20 16:17:301102
1103 // Navigate to a page that opts-into the header: the value should end with
1104 // the major version, and not contain the full version.
1105 SetClientHintExpectationsOnMainFrame(false);
1106 ui_test_utils::NavigateToURL(browser(), gurl);
Aaron Tagliaboschi9f01b682020-05-05 21:03:171107 std::string expected_ua = ua.SerializeBrandVersionList();
Yoav Weissd33bacb2020-03-12 06:42:211108 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1109 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Mike Weste555be862019-02-20 16:17:301110
Yoav Weissd33bacb2020-03-12 06:42:211111 // Navigate again, after the opt-in: the value should stay the major
Mike Weste555be862019-02-20 16:17:301112 // version.
1113 SetClientHintExpectationsOnMainFrame(true);
1114 ui_test_utils::NavigateToURL(browser(), gurl);
Yoav Weissd33bacb2020-03-12 06:42:211115 std::string expected_full_version = "\"" + ua.full_version + "\"";
1116 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1117 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
Mike Weste555be862019-02-20 16:17:301118}
1119
Maks Orlovichf0a2eed2020-05-02 20:08:211120IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UAHintsTabletMode) {
1121 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich73f374d2020-04-02 12:46:131122
John Abd-El-Malekec1fc69e2021-01-28 19:14:411123 blink::UserAgentMetadata ua = embedder_support::GetUserAgentMetadata();
Maks Orlovich73f374d2020-04-02 12:46:131124
1125 // First request: only minimal hints, no tablet override.
1126 SetClientHintExpectationsOnMainFrame(false);
1127 ui_test_utils::NavigateToURL(browser(), gurl);
Aaron Tagliaboschi9f01b682020-05-05 21:03:171128 std::string expected_ua = ua.SerializeBrandVersionList();
Maks Orlovich73f374d2020-04-02 12:46:131129 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1130 EXPECT_EQ(main_frame_ua_full_version_observed(), "");
1131 EXPECT_EQ(main_frame_ua_mobile_observed(), "?0");
Aaron Tagliaboschiec5bce62021-06-24 18:50:091132 EXPECT_EQ(main_frame_ua_platform_observed(), "\"" + ua.platform + "\"");
Maks Orlovich73f374d2020-04-02 12:46:131133
1134 // Second request: table override, all hints.
1135 chrome::ToggleRequestTabletSite(browser());
1136 SetClientHintExpectationsOnMainFrame(true);
1137 ui_test_utils::NavigateToURL(browser(), gurl);
1138 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1139 std::string expected_full_version = "\"" + ua.full_version + "\"";
1140 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
1141 EXPECT_EQ(main_frame_ua_mobile_observed(), "?1");
1142 EXPECT_EQ(main_frame_ua_platform_observed(), "\"Android\"");
1143}
1144
1145// TODO(morlovich): Move this into WebContentsImplBrowserTest once things are
1146// refactored enough that UA client hints actually work in content/
1147IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UserAgentOverrideClientHints) {
1148 content::WebContents* web_contents =
1149 browser()->tab_strip_model()->GetActiveWebContents();
1150
1151 ASSERT_TRUE(embedded_test_server()->Start());
1152 const std::string kHeaderPath = std::string("/echoheader?") +
1153 net::HttpRequestHeaders::kUserAgent +
1154 "&sec-ch-ua&sec-ch-ua-mobile";
1155 const GURL kUrl(embedded_test_server()->GetURL(kHeaderPath));
1156
1157 web_contents->SetUserAgentOverride(
1158 blink::UserAgentOverride::UserAgentOnly("foo"), false);
1159 // Not enabled first.
1160 ui_test_utils::NavigateToURL(browser(), kUrl);
1161 std::string header_value;
1162 EXPECT_TRUE(ExecuteScriptAndExtractString(
1163 web_contents,
1164 "window.domAutomationController.send(document.body.textContent);",
1165 &header_value));
1166 EXPECT_EQ(std::string::npos, header_value.find("foo")) << header_value;
1167
1168 // Actually turn it on.
1169 web_contents->GetController()
1170 .GetLastCommittedEntry()
1171 ->SetIsOverridingUserAgent(true);
1172
1173 ui_test_utils::NavigateToURL(browser(), kUrl);
1174 EXPECT_TRUE(ExecuteScriptAndExtractString(
1175 web_contents,
1176 "window.domAutomationController.send(document.body.textContent);",
1177 &header_value));
1178 // Since no value was provided for client hints, they are not sent.
1179 EXPECT_EQ("foo\nNone\nNone", header_value);
1180
1181 // Now actually provide values for the hints.
1182 blink::UserAgentOverride ua_override;
1183 ua_override.ua_string_override = "foobar";
1184 ua_override.ua_metadata_override.emplace();
1185 ua_override.ua_metadata_override->mobile = true;
Aaron Tagliaboschi9f01b682020-05-05 21:03:171186 ua_override.ua_metadata_override->brand_version_list.emplace_back(
1187 "Foobarnator", "3.14");
Maks Orlovich73f374d2020-04-02 12:46:131188 web_contents->SetUserAgentOverride(ua_override, false);
1189 ui_test_utils::NavigateToURL(browser(), kUrl);
1190 EXPECT_TRUE(ExecuteScriptAndExtractString(
1191 web_contents,
1192 "window.domAutomationController.send(document.body.textContent);",
1193 &header_value));
Aaron Tagliaboschi9f01b682020-05-05 21:03:171194 EXPECT_EQ("foobar\n\"Foobarnator\";v=\"3.14\"\n?1", header_value);
Maks Orlovich73f374d2020-04-02 12:46:131195}
1196
Maks Orlovich7a588d82020-05-06 15:17:241197IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, EmptyAcceptCH) {
1198 // First navigate to a page that enables hints. No CH for it yet, since
1199 // nothing opted in.
1200 GURL gurl = accept_ch_with_lifetime_url();
1201 SetClientHintExpectationsOnMainFrame(false);
1202 ui_test_utils::NavigateToURL(browser(), gurl);
1203
1204 // Now go to a page with blank Accept-CH. Should get hints from previous
1205 // visit.
1206 gurl = accept_ch_empty();
1207 SetClientHintExpectationsOnMainFrame(true);
1208 ui_test_utils::NavigateToURL(browser(), gurl);
1209
1210 // Visiting again should not expect them since we opted out again.
1211 SetClientHintExpectationsOnMainFrame(false);
1212 ui_test_utils::NavigateToURL(browser(), gurl);
1213}
1214
1215IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, MergeAcceptCH) {
1216 // Go to page where some hints are enabled by headers, some by
1217 // http-equiv. It shouldn't get hints itself (due to first visit),
1218 // but subresources should get all the client hints.
1219 GURL gurl = http_equiv_accept_ch_merge();
1220 SetClientHintExpectationsOnMainFrame(false);
1221 SetClientHintExpectationsOnSubresources(true);
1222 ui_test_utils::NavigateToURL(browser(), gurl);
1223 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
1224}
1225
Maks Orlovich7227ce0d2020-02-28 17:13:161226void ClientHintsBrowserTest::TestProfilesIndependent(Browser* browser_a,
1227 Browser* browser_b) {
Maks Orlovichf0a2eed2020-05-02 20:08:211228 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich7227ce0d2020-02-28 17:13:161229
John Abd-El-Malekec1fc69e2021-01-28 19:14:411230 blink::UserAgentMetadata ua = embedder_support::GetUserAgentMetadata();
Maks Orlovich7227ce0d2020-02-28 17:13:161231
1232 // Navigate |browser_a| to a page that opts-into the header: the value should
1233 // end with the major version, and not contain the full version.
1234 SetClientHintExpectationsOnMainFrame(false);
1235 ui_test_utils::NavigateToURL(browser_a, gurl);
Aaron Tagliaboschi9f01b682020-05-05 21:03:171236 std::string expected_ua = ua.SerializeBrandVersionList();
Yoav Weissd33bacb2020-03-12 06:42:211237 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1238 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Maks Orlovich7227ce0d2020-02-28 17:13:161239
1240 // Try again on |browser_a|, the header should have an effect there.
1241 SetClientHintExpectationsOnMainFrame(true);
1242 ui_test_utils::NavigateToURL(browser_a, gurl);
Yoav Weissd33bacb2020-03-12 06:42:211243 std::string expected_full_version = "\"" + ua.full_version + "\"";
1244 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1245 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
Maks Orlovich7227ce0d2020-02-28 17:13:161246
1247 // Navigate on |browser_b|. That should still only have the major
1248 // version.
1249 SetClientHintExpectationsOnMainFrame(false);
1250 ui_test_utils::NavigateToURL(browser_b, gurl);
Yoav Weissd33bacb2020-03-12 06:42:211251 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1252 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Maks Orlovich7227ce0d2020-02-28 17:13:161253}
1254
1255// Check that client hints attached to navigation inside OTR profiles
1256// use the right settings, regular -> OTR direction.
Maks Orlovichf0a2eed2020-05-02 20:08:211257IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, OffTheRecordIndependent) {
Maks Orlovich7227ce0d2020-02-28 17:13:161258 TestProfilesIndependent(browser(),
1259 CreateIncognitoBrowser(browser()->profile()));
1260}
1261
1262// Check that client hints attached to navigation inside OTR profiles
1263// use the right settings, OTR -> regular direction.
Maks Orlovichf0a2eed2020-05-02 20:08:211264IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, OffTheRecordIndependent2) {
Maks Orlovich7227ce0d2020-02-28 17:13:161265 TestProfilesIndependent(CreateIncognitoBrowser(browser()->profile()),
1266 browser());
1267}
1268
Tarun Bansalea0d8262018-05-21 16:11:501269// Test that client hints are attached to third party subresources if
1270// AllowClientHintsToThirdParty feature is enabled.
Tarun Bansal9a7051f2018-07-10 18:30:051271IN_PROC_BROWSER_TEST_P(ClientHintsAllowThirdPartyBrowserTest,
Tarun Bansalea0d8262018-05-21 16:11:501272 ClientHintsThirdPartyAllowed) {
Yoav Weiss76e1afb762020-05-14 19:28:121273 GURL gurl;
1274 unsigned update_event_count = 0;
1275 if (GetParam()) {
1276 gurl = http_equiv_accept_ch_without_lifetime_img_localhost();
1277 } else {
1278 gurl = accept_ch_without_lifetime_img_localhost();
1279 update_event_count = 1;
1280 }
Tarun Bansal9a7051f2018-07-10 18:30:051281
Tarun Bansalea0d8262018-05-21 16:11:501282 base::HistogramTester histogram_tester;
1283
1284 SetClientHintExpectationsOnMainFrame(false);
1285 SetClientHintExpectationsOnSubresources(true);
1286
1287 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:051288 ui_test_utils::NavigateToURL(browser(), gurl);
Yoav Weiss76e1afb762020-05-14 19:28:121289 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount",
1290 update_event_count);
Tarun Bansalea0d8262018-05-21 16:11:501291
Yoav Weissd33bacb2020-03-12 06:42:211292 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansalea0d8262018-05-21 16:11:501293
1294 // Requests to third party servers should not have client hints attached.
1295 EXPECT_EQ(1u, third_party_request_count_seen());
1296
Aaron Tagliaboschia09ec442019-09-18 15:29:031297 // Device memory, viewport width, DRP, and UA client hints should be sent to
1298 // the third-party when feature "AllowClientHintsToThirdParty" is enabled.
Aaron Tagliaboschiec5bce62021-06-24 18:50:091299 EXPECT_EQ(6u, third_party_client_hints_count_seen());
Tarun Bansalea0d8262018-05-21 16:11:501300}
1301
1302// Test that client hints are not attached to third party subresources if
1303// AllowClientHintsToThirdParty feature is not enabled.
Tarun Bansal9a7051f2018-07-10 18:30:051304IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansalea0d8262018-05-21 16:11:501305 ClientHintsThirdPartyNotAllowed) {
Yoav Weiss76e1afb762020-05-14 19:28:121306 GURL gurl;
1307 unsigned update_event_count = 0;
1308 if (GetParam()) {
1309 gurl = http_equiv_accept_ch_without_lifetime_img_localhost();
1310 } else {
1311 gurl = accept_ch_without_lifetime_img_localhost();
1312 update_event_count = 1;
1313 }
Tarun Bansal9a7051f2018-07-10 18:30:051314
Tarun Bansalea0d8262018-05-21 16:11:501315 base::HistogramTester histogram_tester;
1316
1317 SetClientHintExpectationsOnMainFrame(false);
1318 SetClientHintExpectationsOnSubresources(true);
1319
1320 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:051321 ui_test_utils::NavigateToURL(browser(), gurl);
Yoav Weiss76e1afb762020-05-14 19:28:121322 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount",
1323 update_event_count);
Tarun Bansalea0d8262018-05-21 16:11:501324
Mike West2fddeeb72019-02-15 11:29:481325 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461326 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091327 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:211328 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansalea0d8262018-05-21 16:11:501329
1330 // Requests to third party servers should not have client hints attached.
1331 EXPECT_EQ(1u, third_party_request_count_seen());
1332
1333 // Client hints should not be sent to the third-party when feature
Mike West2fddeeb72019-02-15 11:29:481334 // "AllowClientHintsToThirdParty" is not enabled, with the exception of the
1335 // `Sec-CH-UA` hint, which is sent with every request.
Aaron Tagliaboschiec5bce62021-06-24 18:50:091336 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansalea0d8262018-05-21 16:11:501337}
1338
Tarun Bansaladd5e1812018-02-09 19:07:581339// Loads a HTTPS webpage that does not request persisting of client hints.
Tarun Bansal345418632018-06-29 11:07:041340// A same-origin iframe loaded by the webpage requests persistence of client
Maks Orlovich46619c732020-05-07 10:40:531341// hints. Since that's not a main frame, persistence should not happen.
Maks Orlovichf0a2eed2020-05-02 20:08:211342IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal345418632018-06-29 11:07:041343 PersistenceRequestIframe_SameOrigin) {
Maks Orlovichf0a2eed2020-05-02 20:08:211344 const GURL gurl = accept_ch_without_lifetime_with_iframe_url();
Tarun Bansal345418632018-06-29 11:07:041345 base::HistogramTester histogram_tester;
1346 ContentSettingsForOneType host_settings;
1347
1348 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141349 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal345418632018-06-29 11:07:041350 &host_settings);
1351 EXPECT_EQ(0u, host_settings.size());
1352
Tarun Bansal9a7051f2018-07-10 18:30:051353 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal345418632018-06-29 11:07:041354
Maks Orlovich46619c732020-05-07 10:40:531355 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
Tarun Bansal345418632018-06-29 11:07:041356
1357 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281358 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal345418632018-06-29 11:07:041359
1360 // accept_ch_without_lifetime_with_iframe_url() loads
1361 // accept_ch_with_lifetime() in an iframe. The request to persist client
Maks Orlovich46619c732020-05-07 10:40:531362 // hints from accept_ch_with_lifetime() should not be persisted.
1363 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1364 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
Tarun Bansal345418632018-06-29 11:07:041365}
1366
1367// Loads a HTTPS webpage that does not request persisting of client hints.
1368// An iframe loaded by the webpage from an cross origin server requests
1369// persistence of client hints.
1370// Verify that the request from the cross origin iframe is not honored, and
1371// client hints preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051372IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal345418632018-06-29 11:07:041373 DisregardPersistenceRequestIframe_CrossOrigin) {
Tarun Bansal9a7051f2018-07-10 18:30:051374 const GURL gurl =
1375 GetParam() ? http_equiv_accept_ch_without_lifetime_with_iframe_url()
1376 : accept_ch_without_lifetime_with_iframe_url();
1377
1378 intercept_iframe_resource_ = gurl.path();
1379 intercept_to_http_equiv_iframe_ = GetParam();
1380
Tarun Bansaladd5e1812018-02-09 19:07:581381 base::HistogramTester histogram_tester;
1382 ContentSettingsForOneType host_settings;
1383
1384 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141385 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansaladd5e1812018-02-09 19:07:581386 &host_settings);
1387 EXPECT_EQ(0u, host_settings.size());
1388
Tarun Bansal9a7051f2018-07-10 18:30:051389 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansaladd5e1812018-02-09 19:07:581390
1391 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1392
1393 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281394 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansaladd5e1812018-02-09 19:07:581395
1396 // accept_ch_without_lifetime_with_iframe_url() loads
Tarun Bansal345418632018-06-29 11:07:041397 // accept_ch_with_lifetime() in a cross origin iframe. The request to persist
1398 // client hints from accept_ch_with_lifetime() should be disregarded.
Tarun Bansaladd5e1812018-02-09 19:07:581399 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1400 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1401}
1402
Tarun Bansal62cc3542018-06-27 23:53:301403// Loads a HTTPS webpage that does not request persisting of client hints.
1404// A subresource loaded by the webpage requests persistence of client hints.
1405// Verify that the request from the subresource is not honored, and client hints
1406// preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051407IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal62cc3542018-06-27 23:53:301408 DisregardPersistenceRequestSubresource) {
Tarun Bansal9a7051f2018-07-10 18:30:051409 const GURL gurl =
1410 GetParam() ? http_equiv_accept_ch_without_lifetime_with_subresource_url()
1411 : accept_ch_without_lifetime_with_subresource_url();
1412
Tarun Bansal62cc3542018-06-27 23:53:301413 base::HistogramTester histogram_tester;
1414 ContentSettingsForOneType host_settings;
1415
1416 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141417 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal62cc3542018-06-27 23:53:301418 &host_settings);
1419 EXPECT_EQ(0u, host_settings.size());
1420
Tarun Bansal9a7051f2018-07-10 18:30:051421 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal62cc3542018-06-27 23:53:301422
1423 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1424
1425 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281426 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal62cc3542018-06-27 23:53:301427
1428 // accept_ch_without_lifetime_with_subresource_url() loads
1429 // accept_ch_with_lifetime() as a subresource. The request to persist client
1430 // hints from accept_ch_with_lifetime() should be disregarded.
1431 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1432 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1433}
1434
1435// Loads a HTTPS webpage that does not request persisting of client hints.
1436// A subresource loaded by the webpage in an iframe requests persistence of
1437// client hints. Verify that the request from the subresource in the iframe
1438// is not honored, and client hints preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051439IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal62cc3542018-06-27 23:53:301440 DisregardPersistenceRequestSubresourceIframe) {
Tarun Bansal9a7051f2018-07-10 18:30:051441 const GURL gurl =
1442 GetParam()
1443 ? http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url()
1444 : accept_ch_without_lifetime_with_subresource_iframe_url();
1445
Tarun Bansal62cc3542018-06-27 23:53:301446 base::HistogramTester histogram_tester;
1447 ContentSettingsForOneType host_settings;
1448
1449 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141450 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal62cc3542018-06-27 23:53:301451 &host_settings);
1452 EXPECT_EQ(0u, host_settings.size());
1453
Tarun Bansal9a7051f2018-07-10 18:30:051454 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal62cc3542018-06-27 23:53:301455
1456 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1457
1458 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281459 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal62cc3542018-06-27 23:53:301460
Tarun Bansal9a7051f2018-07-10 18:30:051461 // |gurl| loads accept_ch_with_lifetime() or
1462 // http_equiv_accept_ch_with_lifetime() as a subresource in an iframe. The
1463 // request to persist client hints from accept_ch_with_lifetime() or
1464 // http_equiv_accept_ch_with_lifetime() should be disregarded.
Tarun Bansal62cc3542018-06-27 23:53:301465 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1466 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1467}
1468
Tarun Bansal3b330b02017-11-09 19:03:141469// Loads a HTTP local webpage (which qualifies as a secure context) that
1470// requests persisting of client hints. Verifies that the browser receives the
1471// mojo notification from the renderer and persists the client hints to the
1472// disk.
Maks Orlovichf0a2eed2020-05-02 20:08:211473IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal3b330b02017-11-09 19:03:141474 ClientHintsLifetimeFollowedByNoClientHintHttpLocal) {
Maks Orlovichf0a2eed2020-05-02 20:08:211475 const GURL gurl = accept_ch_with_lifetime_http_local_url();
Tarun Bansal9a7051f2018-07-10 18:30:051476
Tarun Bansal3b330b02017-11-09 19:03:141477 base::HistogramTester histogram_tester;
1478 ContentSettingsForOneType host_settings;
1479
1480 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141481 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3b330b02017-11-09 19:03:141482 &host_settings);
1483 EXPECT_EQ(0u, host_settings.size());
1484
Tarun Bansal9a7051f2018-07-10 18:30:051485 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal3b330b02017-11-09 19:03:141486
1487 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1488
1489 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281490 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal3b330b02017-11-09 19:03:141491
Yoav Weissd33bacb2020-03-12 06:42:211492 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1493 expected_client_hints_number, 1);
Yoav Weiss76e1afb762020-05-14 19:28:121494 // |gurl| sets client hints persist duration to 3600 seconds, but a maximum
1495 // value is registered instead.
Tarun Bansal3b330b02017-11-09 19:03:141496 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121497 uma_histogram_max_value, 1);
Tarun Bansal3b330b02017-11-09 19:03:141498
1499 base::RunLoop().RunUntilIdle();
1500
1501 // Clients hints preferences for one origin should be persisted.
1502 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141503 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3b330b02017-11-09 19:03:141504 &host_settings);
1505 EXPECT_EQ(1u, host_settings.size());
1506
Tarun Bansal229647bd002018-02-27 17:33:361507 SetClientHintExpectationsOnMainFrame(true);
1508 SetClientHintExpectationsOnSubresources(true);
Tarun Bansal3b330b02017-11-09 19:03:141509 ui_test_utils::NavigateToURL(browser(),
1510 without_accept_ch_without_lifetime_local_url());
1511
Mike West2fddeeb72019-02-15 11:29:481512 // The user agent hint is attached to all three requests:
1513 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461514 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091515 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481516
Yoav Weissd33bacb2020-03-12 06:42:211517 // Expected number of hints attached to the image request, and the same number
1518 // to the main frame request.
1519 EXPECT_EQ(expected_client_hints_number * 2,
1520 count_client_hints_headers_seen());
Tarun Bansal3b330b02017-11-09 19:03:141521}
1522
Tarun Bansal0b8b7afd2017-08-25 03:52:161523// Loads a webpage that does not request persisting of client hints.
1524IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, NoClientHintsHttps) {
1525 base::HistogramTester histogram_tester;
Tarun Bansal1965b042017-09-07 04:59:191526 ui_test_utils::NavigateToURL(browser(),
1527 without_accept_ch_without_lifetime_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:161528
1529 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1530
1531 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281532 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal0b8b7afd2017-08-25 03:52:161533
1534 // no_client_hints_url() does not sets the client hints.
1535 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1536 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1537}
1538
Tarun Bansal9a7051f2018-07-10 18:30:051539IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal1965b042017-09-07 04:59:191540 ClientHintsLifetimeFollowedByNoClientHint) {
Tarun Bansal9a7051f2018-07-10 18:30:051541 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1542 : accept_ch_with_lifetime_url();
1543
Tarun Bansal1965b042017-09-07 04:59:191544 base::HistogramTester histogram_tester;
1545 ContentSettingsForOneType host_settings;
1546
1547 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141548 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal1965b042017-09-07 04:59:191549 &host_settings);
1550 EXPECT_EQ(0u, host_settings.size());
1551
Maks Orlovichf0a2eed2020-05-02 20:08:211552 // Fetching |gurl| should persist the request for client hints iff using
1553 // headers and not http-equiv.
Tarun Bansal9a7051f2018-07-10 18:30:051554 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal1965b042017-09-07 04:59:191555
Maks Orlovichf0a2eed2020-05-02 20:08:211556 if (GetParam())
1557 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1558 else
1559 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
Tarun Bansal1965b042017-09-07 04:59:191560
1561 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281562 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal1965b042017-09-07 04:59:191563 base::RunLoop().RunUntilIdle();
1564
Maks Orlovichf0a2eed2020-05-02 20:08:211565 if (GetParam()) {
1566 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1567 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1568 } else {
1569 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1570 expected_client_hints_number, 1);
1571 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:121572 // seconds, but a maximum value is registered instead.
Maks Orlovichf0a2eed2020-05-02 20:08:211573 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121574 uma_histogram_max_value, 1);
Tarun Bansal1965b042017-09-07 04:59:191575
Maks Orlovichf0a2eed2020-05-02 20:08:211576 // Clients hints preferences for one origin should be persisted.
1577 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1578 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Illia Klimov48f643c2020-11-05 20:06:141579 &host_settings);
Maks Orlovichf0a2eed2020-05-02 20:08:211580 EXPECT_EQ(1u, host_settings.size());
1581 }
1582
1583 SetClientHintExpectationsOnMainFrame(!GetParam());
1584 SetClientHintExpectationsOnSubresources(!GetParam());
Tarun Bansal1965b042017-09-07 04:59:191585 ui_test_utils::NavigateToURL(browser(),
1586 without_accept_ch_without_lifetime_url());
Tarun Bansal6bf54302017-10-02 07:39:141587
Mike West2fddeeb72019-02-15 11:29:481588 // The user agent hint is attached to all three requests:
1589 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461590 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091591 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481592
Yoav Weissd33bacb2020-03-12 06:42:211593 // Expected number of hints attached to the image request, and the same number
1594 // to the main frame request.
Maks Orlovichf0a2eed2020-05-02 20:08:211595 EXPECT_EQ(GetParam() ? 0 : expected_client_hints_number * 2,
Yoav Weissd33bacb2020-03-12 06:42:211596 count_client_hints_headers_seen());
Tarun Bansal1965b042017-09-07 04:59:191597}
1598
Tarun Bansal293a7b6c2018-12-05 17:41:121599// The test first fetches a page that sets Accept-CH-Lifetime. Next, it fetches
1600// a URL from a different origin. However, that URL response redirects to the
1601// same origin from where the first page was fetched. The test verifies that
1602// on receiving redirect to an origin for which the browser has persisted client
1603// hints prefs, the browser attaches the client hints headers when fetching the
1604// redirected URL.
Maks Orlovichf0a2eed2020-05-02 20:08:211605IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal293a7b6c2018-12-05 17:41:121606 ClientHintsLifetimeFollowedByRedirectToNoClientHint) {
Maks Orlovichf0a2eed2020-05-02 20:08:211607 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal293a7b6c2018-12-05 17:41:121608
1609 base::HistogramTester histogram_tester;
1610 ContentSettingsForOneType host_settings;
1611
1612 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141613 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal293a7b6c2018-12-05 17:41:121614 &host_settings);
1615 EXPECT_EQ(0u, host_settings.size());
1616
1617 // Fetching |gurl| should persist the request for client hints.
1618 ui_test_utils::NavigateToURL(browser(), gurl);
1619
1620 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1621
1622 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281623 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal293a7b6c2018-12-05 17:41:121624
Yoav Weissd33bacb2020-03-12 06:42:211625 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1626 expected_client_hints_number, 1);
Tarun Bansal293a7b6c2018-12-05 17:41:121627 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:121628 // seconds, but a maximum value is registered instead.
Tarun Bansal293a7b6c2018-12-05 17:41:121629 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121630 uma_histogram_max_value, 1);
Tarun Bansal293a7b6c2018-12-05 17:41:121631 base::RunLoop().RunUntilIdle();
1632
1633 // Clients hints preferences for one origin should be persisted.
1634 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141635 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal293a7b6c2018-12-05 17:41:121636 &host_settings);
1637 EXPECT_EQ(1u, host_settings.size());
1638
1639 SetClientHintExpectationsOnMainFrame(true);
1640 SetClientHintExpectationsOnSubresources(true);
1641 ui_test_utils::NavigateToURL(browser(), redirect_url());
1642
Mike West2fddeeb72019-02-15 11:29:481643 // The user agent hint is attached to all three requests:
1644 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461645 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091646 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481647
Yoav Weissd33bacb2020-03-12 06:42:211648 // Expected number of hints attached to the image request, and the same number
1649 // to the main frame request.
1650 EXPECT_EQ(expected_client_hints_number * 2,
1651 count_client_hints_headers_seen());
Tarun Bansal293a7b6c2018-12-05 17:41:121652}
1653
Tarun Bansala0c1fc32018-10-03 16:14:521654// Ensure that even when cookies are blocked, client hint preferences are
Tarun Bansala61f0f62017-10-24 23:53:051655// persisted.
Maks Orlovichf0a2eed2020-05-02 20:08:211656IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521657 ClientHintsLifetimePersistedCookiesBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211658 const GURL gurl_with = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:051659
Tarun Bansala61f0f62017-10-24 23:53:051660 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
1661 CookieSettingsFactory::GetForProfile(browser()->profile());
1662 base::HistogramTester histogram_tester;
1663 ContentSettingsForOneType host_settings;
1664
1665 // Block cookies.
1666 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansala0c1fc32018-10-03 16:14:521667 ->SetContentSettingDefaultScope(gurl_with, GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451668 ContentSettingsType::COOKIES,
Illia Klimov48f643c2020-11-05 20:06:141669 CONTENT_SETTING_BLOCK);
Tarun Bansala61f0f62017-10-24 23:53:051670
Tarun Bansala0c1fc32018-10-03 16:14:521671 // Fetching |gurl_with| should persist the request for client hints.
Tarun Bansal9a7051f2018-07-10 18:30:051672 ui_test_utils::NavigateToURL(browser(), gurl_with);
Tarun Bansala0c1fc32018-10-03 16:14:521673 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 1);
Tarun Bansala61f0f62017-10-24 23:53:051674 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141675 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051676 &host_settings);
1677 EXPECT_EQ(1u, host_settings.size());
Tarun Bansala0c1fc32018-10-03 16:14:521678 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:051679}
1680
Maks Orlovichf0a2eed2020-05-02 20:08:211681IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521682 ClientHintsLifetimeAttachedCookiesBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211683 const GURL gurl_with = accept_ch_with_lifetime_url();
1684 const GURL gurl_without = accept_ch_without_lifetime_url();
Tarun Bansala61f0f62017-10-24 23:53:051685 base::HistogramTester histogram_tester;
1686 ContentSettingsForOneType host_settings;
1687
1688 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141689 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051690 &host_settings);
1691 EXPECT_EQ(0u, host_settings.size());
1692
Tarun Bansal9a7051f2018-07-10 18:30:051693 // Fetching |gurl_with| should persist the request for client hints.
1694 ui_test_utils::NavigateToURL(browser(), gurl_with);
Tarun Bansala61f0f62017-10-24 23:53:051695 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1696 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281697 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Maks Orlovichf0a2eed2020-05-02 20:08:211698 base::RunLoop().RunUntilIdle();
Tarun Bansala61f0f62017-10-24 23:53:051699
Yoav Weissd33bacb2020-03-12 06:42:211700 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1701 expected_client_hints_number, 1);
Yoav Weiss76e1afb762020-05-14 19:28:121702 // |gurl_with| tries to set client hints persist duration to 3600 seconds, but
1703 // a maximum value is registered instead.
Tarun Bansala61f0f62017-10-24 23:53:051704 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121705 uma_histogram_max_value, 1);
Tarun Bansala61f0f62017-10-24 23:53:051706
1707 // Clients hints preferences for one origin should be persisted.
1708 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141709 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051710 &host_settings);
1711 EXPECT_EQ(1u, host_settings.size());
1712
Tarun Bansala0c1fc32018-10-03 16:14:521713 // Block the cookies: Client hints should be attached.
Tarun Bansala61f0f62017-10-24 23:53:051714 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansal9a7051f2018-07-10 18:30:051715 ->SetContentSettingDefaultScope(gurl_without, GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451716 ContentSettingsType::COOKIES,
Illia Klimov48f643c2020-11-05 20:06:141717 CONTENT_SETTING_BLOCK);
Tarun Bansala61f0f62017-10-24 23:53:051718
Tarun Bansal229647bd002018-02-27 17:33:361719 SetClientHintExpectationsOnMainFrame(true);
1720 SetClientHintExpectationsOnSubresources(true);
Tarun Bansala61f0f62017-10-24 23:53:051721 ui_test_utils::NavigateToURL(browser(),
1722 without_accept_ch_without_lifetime_url());
Tarun Bansal79df868e2018-03-20 23:01:361723
Mike West2fddeeb72019-02-15 11:29:481724 // The user agent hint is attached to all three requests:
1725 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461726 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091727 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481728
Yoav Weissd33bacb2020-03-12 06:42:211729 // Expected number of hints attached to the image request, and the same number
1730 // to the main frame request.
1731 EXPECT_EQ(expected_client_hints_number * 2,
1732 count_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051733
1734 // Clear settings.
1735 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451736 ->ClearSettingsForOneType(ContentSettingsType::COOKIES);
Tarun Bansala61f0f62017-10-24 23:53:051737}
1738
1739// Ensure that when the JavaScript is blocked, client hint preferences are not
1740// persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051741IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala61f0f62017-10-24 23:53:051742 ClientHintsLifetimeNotPersistedJavaScriptBlocked) {
1743 ContentSettingsForOneType host_settings;
1744
1745 // Start a navigation. This navigation makes it possible to block JavaScript
1746 // later.
1747 ui_test_utils::NavigateToURL(browser(),
1748 without_accept_ch_without_lifetime_url());
1749
Tarun Bansal9a7051f2018-07-10 18:30:051750 const GURL gurl =
1751 GetParam() ? http_equiv_accept_ch_without_lifetime_with_iframe_url()
1752 : accept_ch_with_lifetime_url();
1753
Tarun Bansala61f0f62017-10-24 23:53:051754 // Block the JavaScript: Client hint preferences should not be persisted.
1755 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141756 ->SetContentSettingDefaultScope(
1757 gurl, GURL(), ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_BLOCK);
Tarun Bansala61f0f62017-10-24 23:53:051758 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
1759 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141760 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051761 &host_settings);
1762 EXPECT_EQ(0u, host_settings.size());
Tarun Bansalc211d8b2018-03-19 19:21:581763 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:051764
1765 // Allow the JavaScript: Client hint preferences should be persisted.
1766 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141767 ->SetContentSettingDefaultScope(
1768 gurl, GURL(), ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_ALLOW);
Tarun Bansala61f0f62017-10-24 23:53:051769 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
1770 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141771 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051772 &host_settings);
1773 EXPECT_EQ(1u, host_settings.size());
Tarun Bansal593790112018-03-20 04:53:341774
1775 // Clear settings.
1776 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451777 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansala61f0f62017-10-24 23:53:051778}
1779
1780// Ensure that when the JavaScript is blocked, persisted client hints are not
1781// attached to the request headers.
Maks Orlovichf0a2eed2020-05-02 20:08:211782IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala61f0f62017-10-24 23:53:051783 ClientHintsLifetimeNotAttachedJavaScriptBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211784 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:051785
Tarun Bansala61f0f62017-10-24 23:53:051786 base::HistogramTester histogram_tester;
1787 ContentSettingsForOneType host_settings;
1788
1789 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141790 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051791 &host_settings);
1792 EXPECT_EQ(0u, host_settings.size());
1793
1794 // Fetching accept_ch_with_lifetime_url() should persist the request for
1795 // client hints.
Tarun Bansal9a7051f2018-07-10 18:30:051796 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansala61f0f62017-10-24 23:53:051797 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1798 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281799 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Mike West2fddeeb72019-02-15 11:29:481800 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461801 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091802 EXPECT_EQ(1u, count_ua_platform_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051803
Yoav Weissd33bacb2020-03-12 06:42:211804 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1805 expected_client_hints_number, 1);
Tarun Bansala61f0f62017-10-24 23:53:051806 // accept_ch_with_lifetime_url() tries to set client hints persist duration to
Yoav Weiss76e1afb762020-05-14 19:28:121807 // 3600 seconds, but a maximum value is registered instead.
Tarun Bansala61f0f62017-10-24 23:53:051808 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121809 uma_histogram_max_value, 1);
Tarun Bansala61f0f62017-10-24 23:53:051810 base::RunLoop().RunUntilIdle();
1811
1812 // Clients hints preferences for one origin should be persisted.
1813 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141814 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051815 &host_settings);
1816 EXPECT_EQ(1u, host_settings.size());
1817
Changwan Ryu434c3a32019-07-30 23:42:581818 // Block JavaScript via WebPreferences: Client hints should not be attached.
1819 SetJsEnabledForActiveView(false);
1820
1821 SetClientHintExpectationsOnMainFrame(false);
1822 SetClientHintExpectationsOnSubresources(false);
1823 ui_test_utils::NavigateToURL(browser(),
1824 without_accept_ch_without_lifetime_url());
1825
1826 EXPECT_EQ(0u, count_client_hints_headers_seen());
1827 VerifyContentSettingsNotNotified();
1828 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461829 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091830 EXPECT_EQ(1u, count_ua_platform_client_hints_headers_seen());
Changwan Ryu434c3a32019-07-30 23:42:581831
1832 SetJsEnabledForActiveView(true);
1833
1834 // Block JavaScript via ContentSetting: Client hints should not be attached.
Tarun Bansala61f0f62017-10-24 23:53:051835 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1836 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
Darin Fisher42f5e7d2019-10-30 07:15:451837 GURL(), ContentSettingsType::JAVASCRIPT,
Illia Klimov48f643c2020-11-05 20:06:141838 CONTENT_SETTING_BLOCK);
Tarun Bansala61f0f62017-10-24 23:53:051839 ui_test_utils::NavigateToURL(browser(),
1840 without_accept_ch_without_lifetime_url());
1841 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansalc211d8b2018-03-19 19:21:581842 VerifyContentSettingsNotNotified();
Mike West2fddeeb72019-02-15 11:29:481843 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461844 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091845 EXPECT_EQ(1u, count_ua_platform_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051846
Changwan Ryu434c3a32019-07-30 23:42:581847 // Allow JavaScript: Client hints should now be attached.
Tarun Bansala61f0f62017-10-24 23:53:051848 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1849 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
Darin Fisher42f5e7d2019-10-30 07:15:451850 GURL(), ContentSettingsType::JAVASCRIPT,
Illia Klimov48f643c2020-11-05 20:06:141851 CONTENT_SETTING_ALLOW);
Tarun Bansala61f0f62017-10-24 23:53:051852
Tarun Bansal229647bd002018-02-27 17:33:361853 SetClientHintExpectationsOnMainFrame(true);
1854 SetClientHintExpectationsOnSubresources(true);
Tarun Bansala61f0f62017-10-24 23:53:051855 ui_test_utils::NavigateToURL(browser(),
1856 without_accept_ch_without_lifetime_url());
Tarun Bansal79df868e2018-03-20 23:01:361857
Mike West2fddeeb72019-02-15 11:29:481858 // The user agent hint is attached to all three requests:
1859 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461860 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091861 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481862
Yoav Weissd33bacb2020-03-12 06:42:211863 // Expected number of hints attached to the image request, and the same number
1864 // to the main frame request.
1865 EXPECT_EQ(expected_client_hints_number * 2,
1866 count_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051867
1868 // Clear settings.
1869 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451870 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansala61f0f62017-10-24 23:53:051871}
1872
Tarun Bansal73502f92019-04-16 21:21:191873// Test that if the content settings are malformed, then the browser does not
1874// crash.
1875IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
1876 ClientHintsMalformedContentSettings) {
1877 ContentSettingsForOneType client_hints_settings;
1878 HostContentSettingsMap* host_content_settings_map =
1879 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
1880
1881 // Add setting for the host.
1882 std::unique_ptr<base::ListValue> expiration_times_list =
1883 std::make_unique<base::ListValue>();
1884 expiration_times_list->AppendInteger(42 /* client hint value */);
1885 auto expiration_times_dictionary = std::make_unique<base::DictionaryValue>();
1886 expiration_times_dictionary->SetList("client_hints",
1887 std::move(expiration_times_list));
Aaron Tagliaboschi3c96a682019-10-29 18:10:281888 expiration_times_dictionary->SetDouble(
1889 "expiration_time",
1890 (base::Time::Now() + base::TimeDelta::FromDays(1)).ToDoubleT());
Tarun Bansal73502f92019-04-16 21:21:191891 host_content_settings_map->SetWebsiteSettingDefaultScope(
1892 without_accept_ch_without_lifetime_url(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141893 ContentSettingsType::CLIENT_HINTS,
Tarun Bansal73502f92019-04-16 21:21:191894 std::make_unique<base::Value>(expiration_times_dictionary->Clone()));
1895
1896 // Reading the settings should now return one setting.
1897 host_content_settings_map->GetSettingsForOneType(
Illia Klimov48f643c2020-11-05 20:06:141898 ContentSettingsType::CLIENT_HINTS, &client_hints_settings);
Tarun Bansal73502f92019-04-16 21:21:191899 EXPECT_EQ(1U, client_hints_settings.size());
1900
1901 SetClientHintExpectationsOnMainFrame(false);
1902 SetClientHintExpectationsOnSubresources(false);
1903 ui_test_utils::NavigateToURL(browser(),
1904 without_accept_ch_without_lifetime_url());
1905}
1906
Tarun Bansal229647bd002018-02-27 17:33:361907// Ensure that when the JavaScript is blocked, client hints requested using
Tarun Bansal3f343d7c2018-03-02 18:48:001908// Accept-CH are not attached to the request headers for subresources.
Tarun Bansal9a7051f2018-07-10 18:30:051909IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal229647bd002018-02-27 17:33:361910 ClientHintsNoLifetimeScriptNotAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:051911 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1912 : accept_ch_with_lifetime_url();
1913
Tarun Bansal1965b042017-09-07 04:59:191914 base::HistogramTester histogram_tester;
1915 ContentSettingsForOneType host_settings;
1916
1917 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141918 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal1965b042017-09-07 04:59:191919 &host_settings);
1920 EXPECT_EQ(0u, host_settings.size());
1921
Tarun Bansal3f343d7c2018-03-02 18:48:001922 // Block the Javascript: Client hints should not be attached.
1923 SetClientHintExpectationsOnSubresources(false);
Tarun Bansal229647bd002018-02-27 17:33:361924 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1925 ->SetContentSettingDefaultScope(
1926 accept_ch_without_lifetime_img_localhost(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141927 ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_BLOCK);
Tarun Bansal229647bd002018-02-27 17:33:361928 ui_test_utils::NavigateToURL(browser(),
1929 accept_ch_without_lifetime_img_localhost());
Mike West2fddeeb72019-02-15 11:29:481930 EXPECT_EQ(0u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461931 EXPECT_EQ(0u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091932 EXPECT_EQ(0u, count_ua_platform_client_hints_headers_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001933 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361934 EXPECT_EQ(1u, third_party_request_count_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001935 EXPECT_EQ(0u, third_party_client_hints_count_seen());
Tarun Bansal1965b042017-09-07 04:59:191936
Tarun Bansal3f343d7c2018-03-02 18:48:001937 // Allow the Javascript: Client hints should now be attached.
Tarun Bansal229647bd002018-02-27 17:33:361938 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1939 ->SetContentSettingDefaultScope(
1940 accept_ch_without_lifetime_img_localhost(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141941 ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_ALLOW);
Tarun Bansal1965b042017-09-07 04:59:191942
Tarun Bansal229647bd002018-02-27 17:33:361943 SetClientHintExpectationsOnSubresources(true);
1944 ui_test_utils::NavigateToURL(browser(),
1945 accept_ch_without_lifetime_img_localhost());
Tarun Bansal3f343d7c2018-03-02 18:48:001946
Mike West2fddeeb72019-02-15 11:29:481947 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461948 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091949 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Aaron Tagliaboschi150fb9042020-05-14 22:20:371950 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361951 EXPECT_EQ(2u, third_party_request_count_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091952 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansalc211d8b2018-03-19 19:21:581953 VerifyContentSettingsNotNotified();
Tarun Bansal1965b042017-09-07 04:59:191954
Tarun Bansal229647bd002018-02-27 17:33:361955 // Clear settings.
1956 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451957 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansal1965b042017-09-07 04:59:191958
Tarun Bansal229647bd002018-02-27 17:33:361959 // Block the Javascript again: Client hints should not be attached.
Tarun Bansal3f343d7c2018-03-02 18:48:001960 SetClientHintExpectationsOnSubresources(false);
Tarun Bansal229647bd002018-02-27 17:33:361961 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1962 ->SetContentSettingDefaultScope(
1963 accept_ch_without_lifetime_img_localhost(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141964 ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_BLOCK);
Tarun Bansal229647bd002018-02-27 17:33:361965 ui_test_utils::NavigateToURL(browser(),
1966 accept_ch_without_lifetime_img_localhost());
Mike West2fddeeb72019-02-15 11:29:481967 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461968 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091969 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Aaron Tagliaboschi150fb9042020-05-14 22:20:371970 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361971 EXPECT_EQ(3u, third_party_request_count_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091972 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansal593790112018-03-20 04:53:341973
1974 // Clear settings.
1975 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451976 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansal229647bd002018-02-27 17:33:361977}
1978
Tarun Bansala0c1fc32018-10-03 16:14:521979// Ensure that when the cookies is blocked, client hints are attached to the
Tarun Bansal3f343d7c2018-03-02 18:48:001980// request headers.
Tarun Bansal9a7051f2018-07-10 18:30:051981IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521982 ClientHintsLifetimeCookiesNotAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:051983 const GURL gurl = GetParam()
1984 ? http_equiv_accept_ch_without_lifetime_img_localhost()
1985 : accept_ch_without_lifetime_img_localhost();
1986
Tarun Bansal229647bd002018-02-27 17:33:361987 base::HistogramTester histogram_tester;
1988 ContentSettingsForOneType host_settings;
1989 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
1990 CookieSettingsFactory::GetForProfile(browser()->profile());
1991
Tarun Bansal1965b042017-09-07 04:59:191992 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141993 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal1965b042017-09-07 04:59:191994 &host_settings);
1995 EXPECT_EQ(0u, host_settings.size());
1996
Tarun Bansal229647bd002018-02-27 17:33:361997 // Block cookies.
1998 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141999 ->SetContentSettingDefaultScope(
2000 gurl, GURL(), ContentSettingsType::COOKIES, CONTENT_SETTING_BLOCK);
Tarun Bansal229647bd002018-02-27 17:33:362001 base::RunLoop().RunUntilIdle();
2002
Tarun Bansal229647bd002018-02-27 17:33:362003 SetClientHintExpectationsOnSubresources(true);
Tarun Bansal9a7051f2018-07-10 18:30:052004 ui_test_utils::NavigateToURL(browser(), gurl);
Mike West2fddeeb72019-02-15 11:29:482005 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462006 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092007 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:212008 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansala0c1fc32018-10-03 16:14:522009 EXPECT_EQ(1u, third_party_request_count_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092010 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansal593790112018-03-20 04:53:342011
2012 // Clear settings.
2013 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:452014 ->ClearSettingsForOneType(ContentSettingsType::COOKIES);
Tarun Bansal1965b042017-09-07 04:59:192015}
2016
Tarun Bansal3ce0ca42018-06-25 22:52:222017// Verify that client hints are sent in the incognito profiles, and server
2018// client hint opt-ins are honored within the incognito profile.
Maks Orlovichf0a2eed2020-05-02 20:08:212019IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal3ce0ca42018-06-25 22:52:222020 ClientHintsLifetimeFollowedByNoClientHintIncognito) {
Maks Orlovichf0a2eed2020-05-02 20:08:212021 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:052022
Tarun Bansal3ce0ca42018-06-25 22:52:222023 base::HistogramTester histogram_tester;
2024 Browser* incognito = CreateIncognitoBrowser();
2025 ContentSettingsForOneType host_settings;
2026
2027 HostContentSettingsMapFactory::GetForProfile(incognito->profile())
Illia Klimov48f643c2020-11-05 20:06:142028 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3ce0ca42018-06-25 22:52:222029 &host_settings);
2030 EXPECT_EQ(0u, host_settings.size());
2031
Tarun Bansal9a7051f2018-07-10 18:30:052032 // Fetching |gurl| should persist the request for client hints.
2033 ui_test_utils::NavigateToURL(incognito, gurl);
Tarun Bansal3ce0ca42018-06-25 22:52:222034
2035 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
2036
2037 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:282038 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal3ce0ca42018-06-25 22:52:222039
Yoav Weissd33bacb2020-03-12 06:42:212040 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
2041 expected_client_hints_number, 1);
Tarun Bansal3ce0ca42018-06-25 22:52:222042 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:122043 // seconds, but a maximum value is registered instead.
Tarun Bansal3ce0ca42018-06-25 22:52:222044 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:122045 uma_histogram_max_value, 1);
Tarun Bansal3ce0ca42018-06-25 22:52:222046 base::RunLoop().RunUntilIdle();
2047
2048 // Clients hints preferences for one origin should be persisted.
2049 HostContentSettingsMapFactory::GetForProfile(incognito->profile())
Illia Klimov48f643c2020-11-05 20:06:142050 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3ce0ca42018-06-25 22:52:222051 &host_settings);
2052 EXPECT_EQ(1u, host_settings.size());
2053
2054 SetClientHintExpectationsOnMainFrame(true);
2055 SetClientHintExpectationsOnSubresources(true);
2056 ui_test_utils::NavigateToURL(incognito,
2057 without_accept_ch_without_lifetime_url());
2058
Mike West2fddeeb72019-02-15 11:29:482059 // The user agent hint is attached to all three requests:
2060 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462061 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092062 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:482063
Yoav Weissd33bacb2020-03-12 06:42:212064 // Expected number of hints attached to the image request, and the same number
2065 // to the main frame request.
2066 EXPECT_EQ(expected_client_hints_number * 2,
2067 count_client_hints_headers_seen());
Tarun Bansal3ce0ca42018-06-25 22:52:222068
2069 // Navigate using regular profile. Client hints should not be send.
2070 SetClientHintExpectationsOnMainFrame(false);
2071 SetClientHintExpectationsOnSubresources(false);
2072 ui_test_utils::NavigateToURL(browser(),
2073 without_accept_ch_without_lifetime_url());
2074
Mike West2fddeeb72019-02-15 11:29:482075 // The user agent hint is attached to the two new requests.
2076 EXPECT_EQ(5u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462077 EXPECT_EQ(5u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092078 EXPECT_EQ(5u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:482079
2080 // No additional hints are sent.
Yoav Weissd33bacb2020-03-12 06:42:212081 EXPECT_EQ(expected_client_hints_number * 2,
2082 count_client_hints_headers_seen());
Tarun Bansal3ce0ca42018-06-25 22:52:222083}
Tarun Bansalbef6d652018-10-02 18:41:012084
Aaron Tagliaboschi8f3a28302020-06-24 03:08:262085class ClientHintsEnterprisePolicyTest : public ClientHintsBrowserTest {
2086 void SetUpInProcessBrowserTestFixture() override {
2087 policy::PolicyTest::SetUpInProcessBrowserTestFixture();
2088 policy::PolicyMap policies;
2089 SetPolicy(&policies, policy::key::kUserAgentClientHintsEnabled,
Aya ElAttare8811742020-07-20 08:24:372090 base::Value(false));
Aaron Tagliaboschi8f3a28302020-06-24 03:08:262091 provider_.UpdateChromePolicy(policies);
2092 }
2093};
2094
2095// Makes sure that no client hints are sent by default when the
2096// "UserAgentClientHintsEnabled" enterprise polickly is set to
2097// false
2098IN_PROC_BROWSER_TEST_F(ClientHintsEnterprisePolicyTest,
2099 ClientHintsEnterprisePolicy) {
2100 const GURL gurl = accept_ch_without_lifetime_url();
2101 ui_test_utils::NavigateToURL(browser(), gurl);
2102 // These would normally be one each
2103 EXPECT_EQ(0u, count_user_agent_hint_headers_seen());
2104 EXPECT_EQ(0u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092105 EXPECT_EQ(0u, count_ua_platform_client_hints_headers_seen());
Aaron Tagliaboschi8f3a28302020-06-24 03:08:262106}
2107
Tarun Bansalbef6d652018-10-02 18:41:012108class ClientHintsWebHoldbackBrowserTest : public ClientHintsBrowserTest {
2109 public:
2110 ClientHintsWebHoldbackBrowserTest() : ClientHintsBrowserTest() {
2111 ConfigureHoldbackExperiment();
2112 }
2113
2114 net::EffectiveConnectionType web_effective_connection_type_override() const {
2115 return web_effective_connection_type_override_;
2116 }
2117
Mike West2fddeeb72019-02-15 11:29:482118 std::unique_ptr<base::FeatureList> EnabledFeatures() override {
Tarun Bansalbef6d652018-10-02 18:41:012119 base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
2120 const std::string kTrialName = "TrialFoo";
2121 const std::string kGroupName = "GroupFoo"; // Value not used
2122
2123 scoped_refptr<base::FieldTrial> trial =
2124 base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
2125
2126 std::map<std::string, std::string> params;
2127
2128 params["web_effective_connection_type_override"] =
2129 net::GetNameForEffectiveConnectionType(
2130 web_effective_connection_type_override_);
Mike West2fddeeb72019-02-15 11:29:482131 EXPECT_TRUE(
Tarun Bansalbef6d652018-10-02 18:41:012132 base::FieldTrialParamAssociator::GetInstance()
2133 ->AssociateFieldTrialParams(kTrialName, kGroupName, params));
2134
2135 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
Maks Orlovichc66745a2020-06-30 17:40:022136 feature_list->InitializeFromCommandLine(
François Beaufort1b51d062021-05-18 11:11:232137 "UserAgentClientHint,LangClientHintHeader,"
2138 "PrefersColorSchemeClientHintHeader",
2139 "");
Tarun Bansalbef6d652018-10-02 18:41:012140 feature_list->RegisterFieldTrialOverride(
2141 features::kNetworkQualityEstimatorWebHoldback.name,
2142 base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
Mike West2fddeeb72019-02-15 11:29:482143 return feature_list;
Tarun Bansalbef6d652018-10-02 18:41:012144 }
2145
Mike West2fddeeb72019-02-15 11:29:482146 private:
2147 void ConfigureHoldbackExperiment() {}
2148
Tarun Bansalbef6d652018-10-02 18:41:012149 const net::EffectiveConnectionType web_effective_connection_type_override_ =
2150 net::EFFECTIVE_CONNECTION_TYPE_3G;
Tarun Bansalbef6d652018-10-02 18:41:012151};
2152
2153// Make sure that when NetInfo holdback experiment is enabled, the NetInfo APIs
2154// and client hints return the overridden values. Verify that the client hints
2155// are overridden on both main frame and subresource requests.
2156IN_PROC_BROWSER_TEST_F(ClientHintsWebHoldbackBrowserTest,
2157 EffectiveConnectionTypeChangeNotified) {
2158 SetExpectedEffectiveConnectionType(web_effective_connection_type_override());
2159
2160 SetClientHintExpectationsOnMainFrame(false);
2161 SetClientHintExpectationsOnSubresources(true);
2162
2163 base::RunLoop().RunUntilIdle();
2164
2165 EXPECT_TRUE(embedded_test_server()->Start());
2166 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
2167 EXPECT_EQ(0u, count_client_hints_headers_seen());
2168 EXPECT_EQ(0u, third_party_request_count_seen());
2169 EXPECT_EQ(0u, third_party_client_hints_count_seen());
2170
2171 SetClientHintExpectationsOnMainFrame(true);
2172 SetClientHintExpectationsOnSubresources(true);
2173 ui_test_utils::NavigateToURL(
2174 browser(), accept_ch_without_lifetime_with_subresource_url());
2175 base::RunLoop().RunUntilIdle();
2176 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:282177 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansalbef6d652018-10-02 18:41:012178
Mike West2fddeeb72019-02-15 11:29:482179 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462180 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092181 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:212182 EXPECT_EQ(expected_client_hints_number * 2,
2183 count_client_hints_headers_seen());
Tarun Bansalbef6d652018-10-02 18:41:012184 EXPECT_EQ(0u, third_party_request_count_seen());
2185 EXPECT_EQ(0u, third_party_client_hints_count_seen());
2186}
Aaron Tagliaboschi603540d22021-04-05 00:37:142187
2188class AcceptCHFrameObserverInterceptor {
2189 public:
2190 AcceptCHFrameObserverInterceptor()
2191 : interceptor_(base::BindRepeating(
2192 &AcceptCHFrameObserverInterceptor::InterceptURLRequest,
2193 base::Unretained(this))) {}
2194
2195 void set_accept_ch_frame(
2196 std::vector<network::mojom::WebClientHintsType> frame) {
2197 accept_ch_frame_ = frame;
2198 }
2199
2200 private:
2201 bool InterceptURLRequest(
2202 content::URLLoaderInterceptor::RequestParams* params) {
2203 if (!accept_ch_frame_ || !params->url_request.trusted_params ||
2204 !params->url_request.trusted_params->accept_ch_frame_observer) {
2205 return false;
2206 }
2207
2208 std::vector<network::mojom::WebClientHintsType> hints;
2209 for (auto hint : accept_ch_frame_.value()) {
2210 std::string header =
2211 network::kClientHintsNameMapping[static_cast<int>(hint)];
2212 if (!params->url_request.headers.HasHeader(header))
2213 hints.push_back(hint);
2214 }
2215
2216 if (hints.empty())
2217 return false;
2218
2219 mojo::Remote<network::mojom::AcceptCHFrameObserver> remote(std::move(
2220 params->url_request.trusted_params->accept_ch_frame_observer));
2221 remote->OnAcceptCHFrameReceived(params->url_request.url, hints,
2222 base::DoNothing::Once<int>());
2223 // At this point it's expected that either the remote's callback will be
2224 // called or the URLLoader will be destroyed to make way for a new one.
2225 // As this is essentially unobservable, RunUntilIdle must be used.
2226 base::RunLoop().RunUntilIdle();
2227 return false;
2228 }
2229
2230 content::URLLoaderInterceptor interceptor_;
Anton Bikineev46bbb972021-05-15 17:53:532231 absl::optional<std::vector<network::mojom::WebClientHintsType>>
Aaron Tagliaboschi603540d22021-04-05 00:37:142232 accept_ch_frame_;
2233};
2234
2235// Replace the request interceptor with an AcceptCHFrameObserverInterceptor.
2236class ClientHintsAcceptCHFrameObserverBrowserTest
2237 : public ClientHintsBrowserTest {
2238 public:
2239 void SetUpOnMainThread() override {
2240 host_resolver()->AddRule("*", "127.0.0.1");
2241 accept_ch_frame_observer_interceptor_ =
2242 std::make_unique<AcceptCHFrameObserverInterceptor>();
2243 }
2244
2245 void TearDownOnMainThread() override {
2246 accept_ch_frame_observer_interceptor_.reset();
2247 }
2248
2249 void set_accept_ch_frame(
2250 std::vector<network::mojom::WebClientHintsType> frame) {
2251 accept_ch_frame_observer_interceptor_->set_accept_ch_frame(frame);
2252 }
2253
2254 std::vector<network::mojom::WebClientHintsType> all_client_hints_types() {
2255 std::vector<network::mojom::WebClientHintsType> hints;
2256 for (size_t i = 0; i < blink::kClientHintsMappingsCount; i++) {
2257 hints.push_back(static_cast<network::mojom::WebClientHintsType>(i));
2258 }
2259
2260 return hints;
2261 }
2262
2263 private:
2264 std::unique_ptr<AcceptCHFrameObserverInterceptor>
2265 accept_ch_frame_observer_interceptor_;
2266};
2267
Elly Fong-Jonesdd9eb012021-04-05 22:45:272268#if defined(OS_CHROMEOS)
2269// Flaky: https://crbug.com/1195790
2270#define MAYBE_AcceptCHFrame DISABLED_AcceptCHFrame
2271#else
2272#define MAYBE_AcceptCHFrame AcceptCHFrame
2273#endif
2274
Aaron Tagliaboschi603540d22021-04-05 00:37:142275// Ensure that client hints are sent when the ACCEPT_CH frame observer is
2276// notified.
2277IN_PROC_BROWSER_TEST_F(ClientHintsAcceptCHFrameObserverBrowserTest,
Elly Fong-Jonesdd9eb012021-04-05 22:45:272278 MAYBE_AcceptCHFrame) {
Aaron Tagliaboschi603540d22021-04-05 00:37:142279 const GURL gurl = without_accept_ch_without_lifetime_url();
2280 set_accept_ch_frame(all_client_hints_types());
2281 SetClientHintExpectationsOnMainFrame(true);
2282 SetClientHintExpectationsOnSubresources(false);
2283 ui_test_utils::NavigateToURL(browser(), gurl);
2284}
2285
2286// Ensure that client hints are *not* sent when the observer is notified but
2287// client hints would normally not be sent (e.g. when JS is disabled for the
2288// frame).
2289IN_PROC_BROWSER_TEST_F(ClientHintsAcceptCHFrameObserverBrowserTest,
2290 AcceptCHFrameJSDisabled) {
2291 const GURL gurl = without_accept_ch_without_lifetime_url();
2292 set_accept_ch_frame(all_client_hints_types());
2293 SetJsEnabledForActiveView(false);
2294 SetClientHintExpectationsOnMainFrame(false);
2295 SetClientHintExpectationsOnSubresources(false);
2296 ui_test_utils::NavigateToURL(browser(), gurl);
2297}
Aaron Tagliaboschi25625c22021-05-11 18:13:592298
2299IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest, UseCounter) {
2300 auto web_feature_waiter =
2301 std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>(
2302 chrome_test_utils::GetActiveWebContents(this));
2303
2304 web_feature_waiter->AddWebFeatureExpectation(
Aaron Tagliaboschiec5bce62021-06-24 18:50:092305 blink::mojom::WebFeature::kClientHintsUAFullVersion);
Aaron Tagliaboschi25625c22021-05-11 18:13:592306 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
2307 : accept_ch_with_lifetime_url();
2308
2309 ui_test_utils::NavigateToURL(browser(), gurl);
2310
2311 web_feature_waiter->Wait();
2312}
François Beaufort34e299e2021-05-26 05:54:332313
2314class ClientHintsBrowserTestWithEmulatedMedia
2315 : public DevToolsProtocolTestBase {
2316 public:
2317 ClientHintsBrowserTestWithEmulatedMedia()
2318 : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
2319 scoped_feature_list_.InitFromCommandLine(
2320 "UserAgentClientHint,AcceptCHFrame,PrefersColorSchemeClientHintHeader",
2321 "");
2322
2323 https_server_.ServeFilesFromSourceDirectory(
2324 "chrome/test/data/client_hints");
2325 https_server_.RegisterRequestMonitor(base::BindRepeating(
2326 &ClientHintsBrowserTestWithEmulatedMedia::MonitorResourceRequest,
2327 base::Unretained(this)));
2328 EXPECT_TRUE(https_server_.Start());
2329
2330 test_url_ = https_server_.GetURL("/accept_ch_without_lifetime.html");
2331 }
2332
2333 ~ClientHintsBrowserTestWithEmulatedMedia() override = default;
2334
2335 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
2336 if (request.headers.find("sec-ch-prefers-color-scheme") !=
2337 request.headers.end()) {
2338 prefers_color_scheme_observed_ =
2339 request.headers.at("sec-ch-prefers-color-scheme");
2340 }
2341 }
2342
2343 const GURL& test_url() const { return test_url_; }
2344
2345 const std::string& prefers_color_scheme_observed() const {
2346 return prefers_color_scheme_observed_;
2347 }
2348
2349 void EmulatePrefersColorScheme(std::string value) {
2350 base::Value feature(base::Value::Type::DICTIONARY);
2351 feature.SetKey("name", base::Value("prefers-color-scheme"));
2352 feature.SetKey("value", base::Value(value));
2353 base::Value features(base::Value::Type::LIST);
2354 features.Append(std::move(feature));
2355 base::Value params(base::Value::Type::DICTIONARY);
2356 params.SetKey("features", std::move(features));
2357 SendCommandSync("Emulation.setEmulatedMedia", std::move(params));
2358 }
2359
2360 private:
2361 base::test::ScopedFeatureList scoped_feature_list_;
2362 net::EmbeddedTestServer https_server_;
2363 GURL test_url_;
2364 std::string prefers_color_scheme_observed_;
2365
2366 DISALLOW_COPY_AND_ASSIGN(ClientHintsBrowserTestWithEmulatedMedia);
2367};
2368
2369IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTestWithEmulatedMedia,
2370 PrefersColorScheme) {
2371 ui_test_utils::NavigateToURL(browser(), test_url());
2372 EXPECT_EQ(prefers_color_scheme_observed(), "");
2373 Attach();
2374
2375 EmulatePrefersColorScheme("light");
2376 ui_test_utils::NavigateToURL(browser(), test_url());
2377 EXPECT_EQ(prefers_color_scheme_observed(), "light");
2378
2379 EmulatePrefersColorScheme("dark");
2380 ui_test_utils::NavigateToURL(browser(), test_url());
2381 EXPECT_EQ(prefers_color_scheme_observed(), "dark");
2382}