blob: 1efa716e5560b278a0b97942fcdfd445e532f9a6 [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"
Aaron Tagliaboschi8f3a28302020-06-24 03:08:2620#include "chrome/browser/policy/policy_test_utils.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1621#include "chrome/browser/profiles/profile.h"
Tarun Bansal1965b042017-09-07 04:59:1922#include "chrome/browser/ui/browser.h"
Maks Orlovich73f374d2020-04-02 12:46:1323#include "chrome/browser/ui/browser_commands.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1624#include "chrome/test/base/in_process_browser_test.h"
25#include "chrome/test/base/ui_test_utils.h"
Carlos Caballerob4283202020-08-10 14:40:4626#include "components/content_settings/browser/page_specific_content_settings.h"
Tarun Bansala61f0f62017-10-24 23:53:0527#include "components/content_settings/core/browser/cookie_settings.h"
Tarun Bansal1965b042017-09-07 04:59:1928#include "components/content_settings/core/browser/host_content_settings_map.h"
Tarun Bansala61f0f62017-10-24 23:53:0529#include "components/content_settings/core/common/pref_names.h"
John Abd-El-Malekec1fc69e2021-01-28 19:14:4130#include "components/embedder_support/user_agent_utils.h"
John Abd-El-Malek161073c2020-06-12 20:40:2831#include "components/metrics/content/subprocess_metrics_provider.h"
Aaron Tagliaboschi8f3a28302020-06-24 03:08:2632#include "components/policy/core/common/policy_map.h"
33#include "components/policy/core/common/policy_pref_names.h"
34#include "components/policy/policy_constants.h"
Tarun Bansala61f0f62017-10-24 23:53:0535#include "components/prefs/pref_service.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1636#include "content/public/browser/browser_thread.h"
Maks Orlovich73f374d2020-04-02 12:46:1337#include "content/public/browser/navigation_entry.h"
Changwan Ryu434c3a32019-07-30 23:42:5838#include "content/public/browser/render_view_host.h"
Tarun Bansalbef6d652018-10-02 18:41:0139#include "content/public/common/content_features.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1640#include "content/public/common/content_switches.h"
Peter Kasting919ce652020-05-07 10:22:3641#include "content/public/test/browser_test.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1642#include "content/public/test/browser_test_utils.h"
43#include "content/public/test/test_utils.h"
Tarun Bansal229647bd002018-02-27 17:33:3644#include "content/public/test/url_loader_interceptor.h"
45#include "net/dns/mock_host_resolver.h"
46#include "net/http/http_request_headers.h"
Tarun Bansal7f3fe8c2018-04-06 22:37:4747#include "net/nqe/effective_connection_type.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1648#include "net/test/embedded_test_server/embedded_test_server.h"
Tarun Bansal1965b042017-09-07 04:59:1949#include "net/test/embedded_test_server/http_request.h"
Tarun Bansal229647bd002018-02-27 17:33:3650#include "net/test/embedded_test_server/http_response.h"
Aaron Tagliaboschi603540d22021-04-05 00:37:1451#include "services/network/public/cpp/client_hints.h"
Tarun Bansal74e189d2018-05-07 19:07:3552#include "services/network/public/cpp/cors/cors.h"
Tarun Bansalceab9592018-05-01 18:57:3553#include "services/network/public/cpp/features.h"
Tarun Bansal7f3fe8c2018-04-06 22:37:4754#include "services/network/public/cpp/network_switches.h"
Aaron Tagliaboschi603540d22021-04-05 00:37:1455#include "services/network/public/mojom/web_client_hints_types.mojom-shared.h"
Blink Reformata30d4232018-04-07 15:31:0656#include "third_party/blink/public/common/client_hints/client_hints.h"
Gyuyoung Kim1ac4ca782020-09-11 03:32:5157#include "third_party/blink/public/common/web_preferences/web_preferences.h"
Tarun Bansal229647bd002018-02-27 17:33:3658
59namespace {
60
Yoav Weissfd1d19f2020-05-05 09:23:0361const unsigned expected_client_hints_number = 12u;
Yoav Weiss76e1afb762020-05-14 19:28:1262const int32_t uma_histogram_max_value = 1471228928;
Yoav Weissd33bacb2020-03-12 06:42:2163
Tarun Bansal229647bd002018-02-27 17:33:3664// An interceptor that records count of fetches and client hint headers for
65// requests to https://foo.com/non-existing-image.jpg.
Jay Civelli1ff872d2018-03-09 21:52:1666class ThirdPartyURLLoaderInterceptor {
Tarun Bansal229647bd002018-02-27 17:33:3667 public:
Jay Civelli1ff872d2018-03-09 21:52:1668 explicit ThirdPartyURLLoaderInterceptor(const GURL intercepted_url)
69 : intercepted_url_(intercepted_url),
70 interceptor_(base::BindRepeating(
71 &ThirdPartyURLLoaderInterceptor::InterceptURLRequest,
72 base::Unretained(this))) {}
Tarun Bansal229647bd002018-02-27 17:33:3673
Jay Civelli1ff872d2018-03-09 21:52:1674 ~ThirdPartyURLLoaderInterceptor() = default;
Tarun Bansal229647bd002018-02-27 17:33:3675
76 size_t request_count_seen() const { return request_count_seen_; }
77
78 size_t client_hints_count_seen() const { return client_hints_count_seen_; }
79
80 private:
Jay Civelli1ff872d2018-03-09 21:52:1681 bool InterceptURLRequest(
82 content::URLLoaderInterceptor::RequestParams* params) {
83 if (params->url_request.url != intercepted_url_)
84 return false;
Tarun Bansal229647bd002018-02-27 17:33:3685
Jay Civelli1ff872d2018-03-09 21:52:1686 request_count_seen_++;
Mike West14c11102019-02-04 16:16:4787 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Tarun Bansalf9cf9892018-04-06 04:38:0188 if (params->url_request.headers.HasHeader(
89 blink::kClientHintsHeaderMapping[i])) {
90 client_hints_count_seen_++;
91 }
Tarun Bansal5c28afb2018-03-17 02:55:2092 }
Jay Civelli1ff872d2018-03-09 21:52:1693 return false;
94 }
Tarun Bansal229647bd002018-02-27 17:33:3695
Jay Civelli1ff872d2018-03-09 21:52:1696 GURL intercepted_url_;
97
98 size_t request_count_seen_ = 0u;
99
100 size_t client_hints_count_seen_ = 0u;
101
102 content::URLLoaderInterceptor interceptor_;
103
104 DISALLOW_COPY_AND_ASSIGN(ThirdPartyURLLoaderInterceptor);
Tarun Bansal229647bd002018-02-27 17:33:36105};
106
Tarun Bansal62efba12018-05-04 22:58:35107// Returns true only if |header_value| satisfies ABNF: 1*DIGIT [ "." 1*DIGIT ]
108bool IsSimilarToDoubleABNF(const std::string& header_value) {
109 if (header_value.empty())
110 return false;
111 char first_char = header_value.at(0);
112 if (!isdigit(first_char))
113 return false;
114
115 bool period_found = false;
116 bool digit_found_after_period = false;
117 for (char ch : header_value) {
118 if (isdigit(ch)) {
119 if (period_found) {
120 digit_found_after_period = true;
121 }
122 continue;
123 }
124 if (ch == '.') {
125 if (period_found)
126 return false;
127 period_found = true;
128 continue;
129 }
130 return false;
131 }
132 if (period_found)
133 return digit_found_after_period;
134 return true;
135}
136
137// Returns true only if |header_value| satisfies ABNF: 1*DIGIT
138bool IsSimilarToIntABNF(const std::string& header_value) {
139 if (header_value.empty())
140 return false;
141
142 for (char ch : header_value) {
143 if (!isdigit(ch))
144 return false;
145 }
146 return true;
147}
148
Tarun Bansal229647bd002018-02-27 17:33:36149} // namespace
Tarun Bansal0b8b7afd2017-08-25 03:52:16150
Aaron Tagliaboschi8f3a28302020-06-24 03:08:26151class ClientHintsBrowserTest : public policy::PolicyTest,
Tarun Bansal9a7051f2018-07-10 18:30:05152 public testing::WithParamInterface<bool> {
Tarun Bansal0b8b7afd2017-08-25 03:52:16153 public:
154 ClientHintsBrowserTest()
Mikel Astiz2de748d2019-11-16 10:39:36155 : http_server_(net::EmbeddedTestServer::TYPE_HTTP),
Tarun Bansal3b330b02017-11-09 19:03:14156 https_server_(net::EmbeddedTestServer::TYPE_HTTPS),
Tarun Bansal345418632018-06-29 11:07:04157 https_cross_origin_server_(net::EmbeddedTestServer::TYPE_HTTPS),
Tarun Bansal229647bd002018-02-27 17:33:36158 expect_client_hints_on_main_frame_(false),
159 expect_client_hints_on_subresources_(false),
Mike West2fddeeb72019-02-15 11:29:48160 count_user_agent_hint_headers_seen_(0),
Maks Orlovich5dcc99c2020-02-13 19:07:46161 count_ua_mobile_client_hints_headers_seen_(0),
Tarun Bansal229647bd002018-02-27 17:33:36162 count_client_hints_headers_seen_(0),
163 request_interceptor_(nullptr) {
Tarun Bansal3b330b02017-11-09 19:03:14164 http_server_.ServeFilesFromSourceDirectory("chrome/test/data/client_hints");
Tarun Bansal0b8b7afd2017-08-25 03:52:16165 https_server_.ServeFilesFromSourceDirectory(
166 "chrome/test/data/client_hints");
Tarun Bansal345418632018-06-29 11:07:04167 https_cross_origin_server_.ServeFilesFromSourceDirectory(
168 "chrome/test/data/client_hints");
Tarun Bansal1965b042017-09-07 04:59:19169
Tarun Bansal3b330b02017-11-09 19:03:14170 http_server_.RegisterRequestMonitor(
Tarun Bansal345418632018-06-29 11:07:04171 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
172 base::Unretained(this)));
Tarun Bansal1965b042017-09-07 04:59:19173 https_server_.RegisterRequestMonitor(
Tarun Bansal345418632018-06-29 11:07:04174 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
175 base::Unretained(this)));
176 https_cross_origin_server_.RegisterRequestMonitor(
177 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
178 base::Unretained(this)));
Tarun Bansal293a7b6c2018-12-05 17:41:12179 https_cross_origin_server_.RegisterRequestHandler(
180 base::BindRepeating(&ClientHintsBrowserTest::RequestHandlerToRedirect,
181 base::Unretained(this)));
Tarun Bansal345418632018-06-29 11:07:04182 https_server_.RegisterRequestHandler(base::BindRepeating(
183 &ClientHintsBrowserTest::RequestHandlerToFetchCrossOriginIframe,
184 base::Unretained(this)));
Tarun Bansal1965b042017-09-07 04:59:19185
Tarun Bansal3b330b02017-11-09 19:03:14186 EXPECT_TRUE(http_server_.Start());
Tarun Bansal0b8b7afd2017-08-25 03:52:16187 EXPECT_TRUE(https_server_.Start());
Tarun Bansal345418632018-06-29 11:07:04188 EXPECT_TRUE(https_cross_origin_server_.Start());
189
190 EXPECT_NE(https_server_.base_url(), https_cross_origin_server_.base_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:16191
Tarun Bansal3b330b02017-11-09 19:03:14192 accept_ch_with_lifetime_http_local_url_ =
193 http_server_.GetURL("/accept_ch_with_lifetime.html");
Tarun Bansal9a7051f2018-07-10 18:30:05194 http_equiv_accept_ch_with_lifetime_http_local_url_ =
195 http_server_.GetURL("/http_equiv_accept_ch_with_lifetime.html");
Tarun Bansal3b330b02017-11-09 19:03:14196 EXPECT_TRUE(accept_ch_with_lifetime_http_local_url_.SchemeIsHTTPOrHTTPS());
197 EXPECT_FALSE(
198 accept_ch_with_lifetime_http_local_url_.SchemeIsCryptographic());
199
Tarun Bansal1965b042017-09-07 04:59:19200 accept_ch_with_lifetime_url_ =
201 https_server_.GetURL("/accept_ch_with_lifetime.html");
Tarun Bansal73502f92019-04-16 21:21:19202 accept_ch_with_short_lifetime_url_ =
203 https_server_.GetURL("/accept_ch_with_short_lifetime.html");
Tarun Bansal0b8b7afd2017-08-25 03:52:16204
Tarun Bansal1965b042017-09-07 04:59:19205 accept_ch_without_lifetime_url_ =
206 https_server_.GetURL("/accept_ch_without_lifetime.html");
207 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsHTTPOrHTTPS());
208 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal9a7051f2018-07-10 18:30:05209 http_equiv_accept_ch_without_lifetime_url_ =
210 https_server_.GetURL("/http_equiv_accept_ch_without_lifetime.html");
Tarun Bansal1965b042017-09-07 04:59:19211
212 without_accept_ch_without_lifetime_url_ =
213 https_server_.GetURL("/without_accept_ch_without_lifetime.html");
214 EXPECT_TRUE(without_accept_ch_without_lifetime_url_.SchemeIsHTTPOrHTTPS());
215 EXPECT_TRUE(
216 without_accept_ch_without_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal3b330b02017-11-09 19:03:14217
218 without_accept_ch_without_lifetime_local_url_ =
219 http_server_.GetURL("/without_accept_ch_without_lifetime.html");
220 EXPECT_TRUE(
221 without_accept_ch_without_lifetime_local_url_.SchemeIsHTTPOrHTTPS());
222 EXPECT_FALSE(
223 without_accept_ch_without_lifetime_local_url_.SchemeIsCryptographic());
Tarun Bansaladd5e1812018-02-09 19:07:58224
225 without_accept_ch_without_lifetime_img_localhost_ = https_server_.GetURL(
226 "/without_accept_ch_without_lifetime_img_localhost.html");
227 without_accept_ch_without_lifetime_img_foo_com_ = https_server_.GetURL(
228 "/without_accept_ch_without_lifetime_img_foo_com.html");
229 accept_ch_without_lifetime_with_iframe_url_ =
230 https_server_.GetURL("/accept_ch_without_lifetime_with_iframe.html");
Tarun Bansal9a7051f2018-07-10 18:30:05231 http_equiv_accept_ch_without_lifetime_with_iframe_url_ =
232 https_server_.GetURL(
233 "/http_equiv_accept_ch_without_lifetime_with_iframe.html");
Tarun Bansal62cc3542018-06-27 23:53:30234 accept_ch_without_lifetime_with_subresource_url_ = https_server_.GetURL(
235 "/accept_ch_without_lifetime_with_subresource.html");
Tarun Bansal9a7051f2018-07-10 18:30:05236 http_equiv_accept_ch_without_lifetime_with_subresource_url_ =
237 https_server_.GetURL(
238 "/http_equiv_accept_ch_without_lifetime_with_subresource.html");
Tarun Bansal62cc3542018-06-27 23:53:30239 accept_ch_without_lifetime_with_subresource_iframe_url_ =
240 https_server_.GetURL(
241 "/accept_ch_without_lifetime_with_subresource_iframe.html");
Tarun Bansal9a7051f2018-07-10 18:30:05242 http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_ =
243 https_server_.GetURL(
244 "/http_equiv_accept_ch_without_lifetime_with_subresource_iframe."
245 "html");
Tarun Bansal229647bd002018-02-27 17:33:36246 accept_ch_without_lifetime_img_localhost_ =
247 https_server_.GetURL("/accept_ch_without_lifetime_img_localhost.html");
Tarun Bansal9a7051f2018-07-10 18:30:05248 http_equiv_accept_ch_without_lifetime_img_localhost_ = https_server_.GetURL(
249 "/http_equiv_accept_ch_without_lifetime_img_localhost.html");
250 http_equiv_accept_ch_with_lifetime_ =
251 https_server_.GetURL("/http_equiv_accept_ch_with_lifetime.html");
Tarun Bansal293a7b6c2018-12-05 17:41:12252
253 redirect_url_ = https_cross_origin_server_.GetURL("/redirect.html");
Maks Orlovich7a588d82020-05-06 15:17:24254
255 accept_ch_empty_ = https_server_.GetURL("/accept_ch_empty.html");
256 http_equiv_accept_ch_merge_ =
257 https_server_.GetURL("/http_equiv_accept_ch_merge.html");
Tarun Bansal0b8b7afd2017-08-25 03:52:16258 }
259
260 ~ClientHintsBrowserTest() override {}
261
Mike West2fddeeb72019-02-15 11:29:48262 virtual std::unique_ptr<base::FeatureList> EnabledFeatures() {
263 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
Maks Orlovichc66745a2020-06-30 17:40:02264 feature_list->InitializeFromCommandLine(
Aaron Tagliaboschi603540d22021-04-05 00:37:14265 "UserAgentClientHint,LangClientHintHeader,CriticalClientHint,"
266 "AcceptCHFrame",
267 "");
Mike West2fddeeb72019-02-15 11:29:48268 return feature_list;
269 }
270
271 void SetUp() override {
Maksim Sisov (GMT+3)830244f2020-08-10 12:52:24272 scoped_feature_list_.InitWithFeatureList(EnabledFeatures());
Mike West2fddeeb72019-02-15 11:29:48273 InProcessBrowserTest::SetUp();
274 }
275
Tarun Bansal0b8b7afd2017-08-25 03:52:16276 void SetUpOnMainThread() override {
Tarun Bansal229647bd002018-02-27 17:33:36277 host_resolver()->AddRule("*", "127.0.0.1");
Tarun Bansal229647bd002018-02-27 17:33:36278
Jay Civelli1ff872d2018-03-09 21:52:16279 request_interceptor_ = std::make_unique<ThirdPartyURLLoaderInterceptor>(
280 GURL("https://foo.com/non-existing-image.jpg"));
Tarun Bansal229647bd002018-02-27 17:33:36281 base::RunLoop().RunUntilIdle();
Tarun Bansal0b8b7afd2017-08-25 03:52:16282 }
283
Jay Civelli1ff872d2018-03-09 21:52:16284 void TearDownOnMainThread() override { request_interceptor_.reset(); }
285
Tarun Bansal0b8b7afd2017-08-25 03:52:16286 void SetUpCommandLine(base::CommandLine* cmd) override {
Tarun Bansal7f3fe8c2018-04-06 22:37:47287 cmd->AppendSwitchASCII(network::switches::kForceEffectiveConnectionType,
288 net::kEffectiveConnectionType2G);
Tarun Bansal0b8b7afd2017-08-25 03:52:16289 }
290
Tarun Bansal229647bd002018-02-27 17:33:36291 void SetClientHintExpectationsOnMainFrame(bool expect_client_hints) {
292 expect_client_hints_on_main_frame_ = expect_client_hints;
Tarun Bansal1965b042017-09-07 04:59:19293 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16294
Tarun Bansal229647bd002018-02-27 17:33:36295 void SetClientHintExpectationsOnSubresources(bool expect_client_hints) {
Callum May1d939742020-03-02 17:51:30296 base::AutoLock lock(expect_client_hints_on_subresources_lock_);
Tarun Bansal229647bd002018-02-27 17:33:36297 expect_client_hints_on_subresources_ = expect_client_hints;
Tarun Bansala61f0f62017-10-24 23:53:05298 }
299
Callum May1d939742020-03-02 17:51:30300 bool expect_client_hints_on_subresources() {
301 base::AutoLock lock(expect_client_hints_on_subresources_lock_);
302 return expect_client_hints_on_subresources_;
303 }
304
Tarun Bansalc211d8b2018-03-19 19:21:58305 // Verify that the user is not notified that cookies or JavaScript were
306 // blocked on the webpage due to the checks done by client hints.
307 void VerifyContentSettingsNotNotified() const {
Carlos Caballerob4283202020-08-10 14:40:46308 auto* pscs = content_settings::PageSpecificContentSettings::GetForFrame(
Carlos Caballerod7b759412020-07-31 18:00:08309 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
Carlos Caballerob4283202020-08-10 14:40:46310 EXPECT_FALSE(pscs->IsContentBlocked(ContentSettingsType::COOKIES));
311 EXPECT_FALSE(pscs->IsContentBlocked(ContentSettingsType::JAVASCRIPT));
Tarun Bansalc211d8b2018-03-19 19:21:58312 }
313
Tarun Bansalbef6d652018-10-02 18:41:01314 void SetExpectedEffectiveConnectionType(
315 net::EffectiveConnectionType effective_connection_type) {
316 expected_ect = effective_connection_type;
317 }
318
Changwan Ryu434c3a32019-07-30 23:42:58319 void SetJsEnabledForActiveView(bool enabled) {
Rakina Zata Amni347b70902020-07-22 10:49:04320 content::WebContents* web_contents =
321 browser()->tab_strip_model()->GetActiveWebContents();
Gyuyoung Kim1ac4ca782020-09-11 03:32:51322 blink::web_pref::WebPreferences prefs =
323 web_contents->GetOrCreateWebPreferences();
Changwan Ryu434c3a32019-07-30 23:42:58324 prefs.javascript_enabled = enabled;
Rakina Zata Amni347b70902020-07-22 10:49:04325 web_contents->SetWebPreferences(prefs);
Changwan Ryu434c3a32019-07-30 23:42:58326 }
327
Maks Orlovich7227ce0d2020-02-28 17:13:16328 void TestProfilesIndependent(Browser* browser_a, Browser* browser_b);
329
Tarun Bansal3b330b02017-11-09 19:03:14330 const GURL& accept_ch_with_lifetime_http_local_url() const {
331 return accept_ch_with_lifetime_http_local_url_;
332 }
Tarun Bansal9a7051f2018-07-10 18:30:05333 const GURL& http_equiv_accept_ch_with_lifetime_http_local_url() const {
334 return http_equiv_accept_ch_with_lifetime_http_local_url_;
335 }
Tarun Bansal3b330b02017-11-09 19:03:14336
Tarun Bansal1965b042017-09-07 04:59:19337 // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
338 // headers.
339 const GURL& accept_ch_with_lifetime_url() const {
340 return accept_ch_with_lifetime_url_;
341 }
Tarun Bansal9a7051f2018-07-10 18:30:05342 const GURL& http_equiv_accept_ch_with_lifetime() {
343 return http_equiv_accept_ch_with_lifetime_;
344 }
Tarun Bansal1965b042017-09-07 04:59:19345
Tarun Bansal73502f92019-04-16 21:21:19346 // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
347 // headers. The Accept-CH-Lifetime duration is set very short to 1 second.
348 const GURL& accept_ch_with_short_lifetime() const {
349 return accept_ch_with_short_lifetime_url_;
350 }
351
Tarun Bansal1965b042017-09-07 04:59:19352 // A URL whose response headers include only Accept-CH header.
353 const GURL& accept_ch_without_lifetime_url() const {
354 return accept_ch_without_lifetime_url_;
355 }
Tarun Bansal9a7051f2018-07-10 18:30:05356 const GURL& http_equiv_accept_ch_without_lifetime_url() const {
357 return http_equiv_accept_ch_without_lifetime_url_;
358 }
Tarun Bansal1965b042017-09-07 04:59:19359
360 // A URL whose response headers do not include either Accept-CH or
361 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
362 const GURL& without_accept_ch_without_lifetime_url() const {
363 return without_accept_ch_without_lifetime_url_;
364 }
365
Tarun Bansal3b330b02017-11-09 19:03:14366 // A URL whose response headers do not include either Accept-CH or
367 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
368 const GURL& without_accept_ch_without_lifetime_local_url() const {
369 return without_accept_ch_without_lifetime_local_url_;
370 }
371
Tarun Bansaladd5e1812018-02-09 19:07:58372 // A URL whose response headers do not include either Accept-CH or
373 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
374 // from localhost.
375 const GURL& without_accept_ch_without_lifetime_img_localhost() const {
376 return without_accept_ch_without_lifetime_img_localhost_;
377 }
378
379 // A URL whose response headers do not include either Accept-CH or
380 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
381 // from foo.com.
382 const GURL& without_accept_ch_without_lifetime_img_foo_com() const {
383 return without_accept_ch_without_lifetime_img_foo_com_;
384 }
385
386 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
387 // headers. The response loads accept_ch_with_lifetime_url() in an iframe.
388 const GURL& accept_ch_without_lifetime_with_iframe_url() const {
389 return accept_ch_without_lifetime_with_iframe_url_;
390 }
Tarun Bansal9a7051f2018-07-10 18:30:05391 const GURL& http_equiv_accept_ch_without_lifetime_with_iframe_url() const {
392 return http_equiv_accept_ch_without_lifetime_with_iframe_url_;
393 }
Tarun Bansaladd5e1812018-02-09 19:07:58394
Tarun Bansal62cc3542018-06-27 23:53:30395 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
396 // headers. The response loads accept_ch_with_lifetime_url() as a subresource
397 // in the main frame.
398 const GURL& accept_ch_without_lifetime_with_subresource_url() const {
399 return accept_ch_without_lifetime_with_subresource_url_;
400 }
Tarun Bansal9a7051f2018-07-10 18:30:05401 const GURL& http_equiv_accept_ch_without_lifetime_with_subresource_url()
402 const {
403 return http_equiv_accept_ch_without_lifetime_with_subresource_url_;
404 }
Tarun Bansal62cc3542018-06-27 23:53:30405
406 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
Tarun Bansal9a7051f2018-07-10 18:30:05407 // headers. The response loads accept_ch_with_lifetime_url() or
408 // http_equiv_accept_ch_with_lifetime_url() as a subresource in the iframe.
Tarun Bansal62cc3542018-06-27 23:53:30409 const GURL& accept_ch_without_lifetime_with_subresource_iframe_url() const {
410 return accept_ch_without_lifetime_with_subresource_iframe_url_;
411 }
Tarun Bansal9a7051f2018-07-10 18:30:05412 const GURL&
413 http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url() const {
414 return http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_;
415 }
Tarun Bansal62cc3542018-06-27 23:53:30416
Tarun Bansal9a7051f2018-07-10 18:30:05417 // A URL whose response includes only Accept-CH header. Navigating to
Tarun Bansal229647bd002018-02-27 17:33:36418 // this URL also fetches two images: One from the localhost, and one from
419 // foo.com.
420 const GURL& accept_ch_without_lifetime_img_localhost() const {
421 return accept_ch_without_lifetime_img_localhost_;
422 }
Tarun Bansal9a7051f2018-07-10 18:30:05423 const GURL& http_equiv_accept_ch_without_lifetime_img_localhost() const {
424 return http_equiv_accept_ch_without_lifetime_img_localhost_;
425 }
Tarun Bansal229647bd002018-02-27 17:33:36426
Tarun Bansal293a7b6c2018-12-05 17:41:12427 const GURL& redirect_url() const { return redirect_url_; }
428
Maks Orlovich7a588d82020-05-06 15:17:24429 // A URL to a page with a response containing an empty accept_ch header.
430 const GURL& accept_ch_empty() const { return accept_ch_empty_; }
431
432 // A page where some hints are in accept-ch header, some in http-equiv.
433 const GURL& http_equiv_accept_ch_merge() const {
434 return http_equiv_accept_ch_merge_;
435 }
436
Mike West2fddeeb72019-02-15 11:29:48437 size_t count_user_agent_hint_headers_seen() const {
Callum May7d88ff3e2019-11-12 18:21:46438 base::AutoLock lock(count_headers_lock_);
Mike West2fddeeb72019-02-15 11:29:48439 return count_user_agent_hint_headers_seen_;
440 }
441
Maks Orlovich5dcc99c2020-02-13 19:07:46442 size_t count_ua_mobile_client_hints_headers_seen() const {
443 base::AutoLock lock(count_headers_lock_);
444 return count_ua_mobile_client_hints_headers_seen_;
445 }
446
Tarun Bansal1965b042017-09-07 04:59:19447 size_t count_client_hints_headers_seen() const {
Callum May7d88ff3e2019-11-12 18:21:46448 base::AutoLock lock(count_headers_lock_);
Tarun Bansal1965b042017-09-07 04:59:19449 return count_client_hints_headers_seen_;
450 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16451
Tarun Bansal229647bd002018-02-27 17:33:36452 size_t third_party_request_count_seen() const {
453 return request_interceptor_->request_count_seen();
454 }
455
456 size_t third_party_client_hints_count_seen() const {
457 return request_interceptor_->client_hints_count_seen();
458 }
459
Mike Weste555be862019-02-20 16:17:30460 const std::string& main_frame_ua_observed() const {
461 return main_frame_ua_observed_;
462 }
463
Yoav Weissd33bacb2020-03-12 06:42:21464 const std::string& main_frame_ua_full_version_observed() const {
465 return main_frame_ua_full_version_observed_;
466 }
467
Maks Orlovich73f374d2020-04-02 12:46:13468 const std::string& main_frame_ua_mobile_observed() const {
469 return main_frame_ua_mobile_observed_;
470 }
471
472 const std::string& main_frame_ua_platform_observed() const {
473 return main_frame_ua_platform_observed_;
474 }
475
Tarun Bansalea0d8262018-05-21 16:11:50476 base::test::ScopedFeatureList scoped_feature_list_;
477
Tarun Bansal345418632018-06-29 11:07:04478 std::string intercept_iframe_resource_;
Tarun Bansal9a7051f2018-07-10 18:30:05479 bool intercept_to_http_equiv_iframe_ = false;
Callum May7d88ff3e2019-11-12 18:21:46480 mutable base::Lock count_headers_lock_;
Tarun Bansal345418632018-06-29 11:07:04481
Tarun Bansal0b8b7afd2017-08-25 03:52:16482 private:
Tarun Bansal345418632018-06-29 11:07:04483 // Intercepts only the main frame requests that contain
Tarun Bansal293a7b6c2018-12-05 17:41:12484 // "redirect" in the resource path. The intercepted requests
485 // are served an HTML file that fetches an iframe from a cross-origin HTTPS
486 // server.
487 std::unique_ptr<net::test_server::HttpResponse> RequestHandlerToRedirect(
488 const net::test_server::HttpRequest& request) {
489 // Check if it's a main frame request.
490 if (request.relative_url.find(".html") == std::string::npos)
491 return nullptr;
492
493 if (request.GetURL().spec().find("redirect") == std::string::npos)
494 return nullptr;
495
496 std::unique_ptr<net::test_server::BasicHttpResponse> response;
Peter Boström924f8032021-04-02 20:36:02497 response = std::make_unique<net::test_server::BasicHttpResponse>();
Tarun Bansal293a7b6c2018-12-05 17:41:12498 response->set_code(net::HTTP_FOUND);
499 response->AddCustomHeader("Location",
500 without_accept_ch_without_lifetime_url().spec());
501 return std::move(response);
502 }
503
504 // Intercepts only the main frame requests that contain
Tarun Bansal345418632018-06-29 11:07:04505 // |intercept_iframe_resource_| in the resource path. The intercepted requests
506 // are served an HTML file that fetches an iframe from a cross-origin HTTPS
507 // server.
508 std::unique_ptr<net::test_server::HttpResponse>
509 RequestHandlerToFetchCrossOriginIframe(
510 const net::test_server::HttpRequest& request) {
511 if (intercept_iframe_resource_.empty())
512 return nullptr;
513
514 // Check if it's a main frame request.
515 if (request.relative_url.find(".html") == std::string::npos)
516 return nullptr;
517
518 if (request.relative_url.find(intercept_iframe_resource_) ==
519 std::string::npos) {
520 return nullptr;
521 }
522
523 const std::string iframe_url =
Tarun Bansal9a7051f2018-07-10 18:30:05524 intercept_to_http_equiv_iframe_
525 ? https_cross_origin_server_
526 .GetURL("/http_equiv_accept_ch_with_lifetime.html")
527 .spec()
528 : https_cross_origin_server_.GetURL("/accept_ch_with_lifetime.html")
529 .spec();
Tarun Bansal345418632018-06-29 11:07:04530
531 std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
532 new net::test_server::BasicHttpResponse());
533 http_response->set_code(net::HTTP_OK);
534 http_response->set_content_type("text/html");
535 http_response->set_content(
536 "<html>"
537 "<link rel='icon' href='data:;base64,='><head></head>"
538 "Empty file which uses link-rel to disable favicon fetches. "
539 "<iframe src='" +
540 iframe_url + "'></iframe></html>");
541
542 return std::move(http_response);
543 }
544
Maks Orlovich73f374d2020-04-02 12:46:13545 static std::string UpdateHeaderObservation(
546 const net::test_server::HttpRequest& request,
547 const std::string& header) {
548 if (request.headers.find(header) != request.headers.end())
549 return request.headers.find(header)->second;
550 else
551 return "";
552 }
553
Tarun Bansal1965b042017-09-07 04:59:19554 // Called by |https_server_|.
555 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
Tarun Bansal6bf54302017-10-02 07:39:14556 bool is_main_frame_navigation =
557 request.GetURL().spec().find(".html") != std::string::npos;
558
Tarun Bansal293a7b6c2018-12-05 17:41:12559 if (is_main_frame_navigation &&
560 request.GetURL().spec().find("redirect") != std::string::npos) {
561 return;
562 }
563
Tarun Bansal229647bd002018-02-27 17:33:36564 if (is_main_frame_navigation) {
Maks Orlovich73f374d2020-04-02 12:46:13565 main_frame_ua_observed_ = UpdateHeaderObservation(request, "sec-ch-ua");
566 main_frame_ua_full_version_observed_ =
567 UpdateHeaderObservation(request, "sec-ch-ua-full-version");
568 main_frame_ua_mobile_observed_ =
569 UpdateHeaderObservation(request, "sec-ch-ua-mobile");
570 main_frame_ua_platform_observed_ =
571 UpdateHeaderObservation(request, "sec-ch-ua-platform");
Yoav Weissd33bacb2020-03-12 06:42:21572
Tarun Bansalf9cf9892018-04-06 04:38:01573 VerifyClientHintsReceived(expect_client_hints_on_main_frame_, request);
Tarun Bansal5c28afb2018-03-17 02:55:20574 if (expect_client_hints_on_main_frame_) {
575 double value = 0.0;
576 EXPECT_TRUE(base::StringToDouble(
577 request.headers.find("device-memory")->second, &value));
578 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35579 EXPECT_TRUE(IsSimilarToDoubleABNF(
580 request.headers.find("device-memory")->second));
Tarun Bansal44ad96882018-03-28 17:47:42581 main_frame_device_memory_observed_ = value;
Tarun Bansal5c28afb2018-03-17 02:55:20582
583 EXPECT_TRUE(
584 base::StringToDouble(request.headers.find("dpr")->second, &value));
585 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35586 EXPECT_TRUE(IsSimilarToDoubleABNF(request.headers.find("dpr")->second));
Tarun Bansal44ad96882018-03-28 17:47:42587 main_frame_dpr_observed_ = value;
588
Tarun Bansal5c28afb2018-03-17 02:55:20589 EXPECT_TRUE(base::StringToDouble(
590 request.headers.find("viewport-width")->second, &value));
Tarun Bansal62efba12018-05-04 22:58:35591 EXPECT_TRUE(
592 IsSimilarToIntABNF(request.headers.find("viewport-width")->second));
Tarun Bansal79df868e2018-03-20 23:01:36593#if !defined(OS_ANDROID)
Tarun Bansal5c28afb2018-03-17 02:55:20594 EXPECT_LT(0.0, value);
Tarun Bansal79df868e2018-03-20 23:01:36595#else
596 EXPECT_EQ(980, value);
Tarun Bansal5c28afb2018-03-17 02:55:20597#endif
Tarun Bansal44ad96882018-03-28 17:47:42598 main_frame_viewport_width_observed_ = value;
Mike Weste555be862019-02-20 16:17:30599
Tarun Bansal7f3fe8c2018-04-06 22:37:47600 VerifyNetworkQualityClientHints(request);
Tarun Bansal5c28afb2018-03-17 02:55:20601 }
Tarun Bansala61f0f62017-10-24 23:53:05602 }
Tarun Bansal6bf54302017-10-02 07:39:14603
Tarun Bansal229647bd002018-02-27 17:33:36604 if (!is_main_frame_navigation) {
Callum May1d939742020-03-02 17:51:30605 VerifyClientHintsReceived(expect_client_hints_on_subresources(), request);
Tarun Bansal5c28afb2018-03-17 02:55:20606
Callum May1d939742020-03-02 17:51:30607 if (expect_client_hints_on_subresources()) {
Tarun Bansal5c28afb2018-03-17 02:55:20608 double value = 0.0;
609 EXPECT_TRUE(base::StringToDouble(
610 request.headers.find("device-memory")->second, &value));
611 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35612 EXPECT_TRUE(IsSimilarToDoubleABNF(
613 request.headers.find("device-memory")->second));
Tarun Bansal44ad96882018-03-28 17:47:42614 if (main_frame_device_memory_observed_ > 0) {
615 EXPECT_EQ(main_frame_device_memory_observed_, value);
616 }
Tarun Bansal5c28afb2018-03-17 02:55:20617
618 EXPECT_TRUE(
619 base::StringToDouble(request.headers.find("dpr")->second, &value));
620 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35621 EXPECT_TRUE(IsSimilarToDoubleABNF(request.headers.find("dpr")->second));
Tarun Bansal44ad96882018-03-28 17:47:42622 if (main_frame_dpr_observed_ > 0) {
623 EXPECT_EQ(main_frame_dpr_observed_, value);
624 }
Tarun Bansal5c28afb2018-03-17 02:55:20625
626 EXPECT_TRUE(base::StringToDouble(
627 request.headers.find("viewport-width")->second, &value));
Tarun Bansal62efba12018-05-04 22:58:35628 EXPECT_TRUE(
629 IsSimilarToIntABNF(request.headers.find("viewport-width")->second));
Tarun Bansal79df868e2018-03-20 23:01:36630#if !defined(OS_ANDROID)
Tarun Bansal5c28afb2018-03-17 02:55:20631 EXPECT_LT(0.0, value);
Tarun Bansal79df868e2018-03-20 23:01:36632#else
633 EXPECT_EQ(980, value);
634#endif
Tarun Bansal44ad96882018-03-28 17:47:42635#if defined(OS_ANDROID)
636 // TODO(tbansal): https://crbug.com/825892: Viewport width on main
637 // frame requests may be incorrect when the Chrome window is not
638 // maximized.
639 if (main_frame_viewport_width_observed_ > 0) {
640 EXPECT_EQ(main_frame_viewport_width_observed_, value);
641 }
642#endif
Tarun Bansal7f3fe8c2018-04-06 22:37:47643 VerifyNetworkQualityClientHints(request);
Tarun Bansal5c28afb2018-03-17 02:55:20644 }
Tarun Bansala61f0f62017-10-24 23:53:05645 }
Tarun Bansal6bf54302017-10-02 07:39:14646
Mike West14c11102019-02-04 16:16:47647 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Jan Wilken Dörriea8cb56302019-06-06 18:59:36648 if (base::Contains(request.headers,
649 blink::kClientHintsHeaderMapping[i])) {
Callum May7d88ff3e2019-11-12 18:21:46650 base::AutoLock lock(count_headers_lock_);
Mike West2fddeeb72019-02-15 11:29:48651 // The user agent hint is special:
652 if (std::string(blink::kClientHintsHeaderMapping[i]) == "sec-ch-ua") {
653 count_user_agent_hint_headers_seen_++;
Maks Orlovich5dcc99c2020-02-13 19:07:46654 } else if (std::string(blink::kClientHintsHeaderMapping[i]) ==
655 "sec-ch-ua-mobile") {
656 count_ua_mobile_client_hints_headers_seen_++;
Mike West2fddeeb72019-02-15 11:29:48657 } else {
658 count_client_hints_headers_seen_++;
659 }
Tarun Bansalf9cf9892018-04-06 04:38:01660 }
661 }
662 }
Tarun Bansal1965b042017-09-07 04:59:19663
Tarun Bansalf9cf9892018-04-06 04:38:01664 void VerifyClientHintsReceived(bool expect_client_hints,
665 const net::test_server::HttpRequest& request) {
Mike West14c11102019-02-04 16:16:47666 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
667 SCOPED_TRACE(testing::Message()
668 << std::string(blink::kClientHintsHeaderMapping[i]));
Tarun Bansalf9cf9892018-04-06 04:38:01669 // Resource width client hint is only attached on image subresources.
670 if (std::string(blink::kClientHintsHeaderMapping[i]) == "width") {
671 continue;
672 }
Mike West2fddeeb72019-02-15 11:29:48673
Maks Orlovich5dcc99c2020-02-13 19:07:46674 // `Sec-CH-UA` and `Sec-CH-UA-Mobile` is attached on all requests.
675 if (std::string(blink::kClientHintsHeaderMapping[i]) == "sec-ch-ua" ||
676 std::string(blink::kClientHintsHeaderMapping[i]) ==
677 "sec-ch-ua-mobile") {
Mike West2fddeeb72019-02-15 11:29:48678 continue;
679 }
680
Jan Wilken Dörriea8cb56302019-06-06 18:59:36681 EXPECT_EQ(
682 expect_client_hints,
683 base::Contains(request.headers, blink::kClientHintsHeaderMapping[i]));
Tarun Bansalf9cf9892018-04-06 04:38:01684 }
Tarun Bansal1965b042017-09-07 04:59:19685 }
686
Tarun Bansal7f3fe8c2018-04-06 22:37:47687 void VerifyNetworkQualityClientHints(
688 const net::test_server::HttpRequest& request) const {
689 // Effective connection type is forced to 2G using command line in these
690 // tests.
Tarun Bansal509a8dd2018-04-10 17:19:16691 int rtt_value = 0.0;
Tarun Bansal7f3fe8c2018-04-06 22:37:47692 EXPECT_TRUE(
Tarun Bansal509a8dd2018-04-10 17:19:16693 base::StringToInt(request.headers.find("rtt")->second, &rtt_value));
694 EXPECT_LE(0, rtt_value);
Tarun Bansal62efba12018-05-04 22:58:35695 EXPECT_TRUE(IsSimilarToIntABNF(request.headers.find("rtt")->second));
Tarun Bansal509a8dd2018-04-10 17:19:16696 // Verify that RTT value is a multiple of 50 milliseconds.
697 EXPECT_EQ(0, rtt_value % 50);
Tarun Bansalbef6d652018-10-02 18:41:01698 EXPECT_GE(expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G ? 3000 : 500,
699 rtt_value);
Tarun Bansal7f3fe8c2018-04-06 22:37:47700
Tarun Bansal509a8dd2018-04-10 17:19:16701 double mbps_value = 0.0;
702 EXPECT_TRUE(base::StringToDouble(request.headers.find("downlink")->second,
703 &mbps_value));
704 EXPECT_LE(0, mbps_value);
Tarun Bansal62efba12018-05-04 22:58:35705 EXPECT_TRUE(
706 IsSimilarToDoubleABNF(request.headers.find("downlink")->second));
Tarun Bansal509a8dd2018-04-10 17:19:16707 // Verify that the mbps value is a multiple of 0.050 mbps.
708 // Allow for small amount of noise due to double to integer conversions.
709 EXPECT_NEAR(0, (static_cast<int>(mbps_value * 1000)) % 50, 1);
710 EXPECT_GE(10.0, mbps_value);
Tarun Bansal7f3fe8c2018-04-06 22:37:47711
712 EXPECT_FALSE(request.headers.find("ect")->second.empty());
Tarun Bansalceab9592018-05-01 18:57:35713
714 // TODO(tbansal): https://crbug.com/819244: When network servicification is
Tarun Bansal5ac533542018-08-10 19:45:52715 // enabled, the renderer processes do not receive notifications on
716 // change in the network quality. Hence, the network quality client hints
717 // are not set to the correct value on subresources.
718 bool is_main_frame_navigation =
719 request.GetURL().spec().find(".html") != std::string::npos;
John Abd-El-Malek67facbe82019-06-06 22:37:08720 if (is_main_frame_navigation) {
Tarun Bansalceab9592018-05-01 18:57:35721 // Effective connection type is forced to 2G using command line in these
722 // tests. RTT is expected to be 1800 msec but leave some gap to account
723 // for added noise and randomization.
Tarun Bansalbef6d652018-10-02 18:41:01724 if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G) {
725 EXPECT_NEAR(1800, rtt_value, 360);
726 } else if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_3G) {
727 EXPECT_NEAR(450, rtt_value, 90);
728 } else {
729 NOTREACHED();
730 }
Tarun Bansalceab9592018-05-01 18:57:35731
732 // Effective connection type is forced to 2G using command line in these
733 // tests. downlink is expected to be 0.075 Mbps but leave some gap to
734 // account for added noise and randomization.
Tarun Bansalbef6d652018-10-02 18:41:01735 if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G) {
736 EXPECT_NEAR(0.075, mbps_value, 0.05);
737 } else if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_3G) {
738 EXPECT_NEAR(0.4, mbps_value, 0.1);
739 } else {
740 NOTREACHED();
741 }
Tarun Bansalceab9592018-05-01 18:57:35742
Tarun Bansalbef6d652018-10-02 18:41:01743 EXPECT_EQ(expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G ? "2g" : "3g",
744 request.headers.find("ect")->second);
Tarun Bansalceab9592018-05-01 18:57:35745 }
Tarun Bansal7f3fe8c2018-04-06 22:37:47746 }
747
Tarun Bansal3b330b02017-11-09 19:03:14748 net::EmbeddedTestServer http_server_;
Tarun Bansal0b8b7afd2017-08-25 03:52:16749 net::EmbeddedTestServer https_server_;
Tarun Bansal345418632018-06-29 11:07:04750 net::EmbeddedTestServer https_cross_origin_server_;
Tarun Bansal3b330b02017-11-09 19:03:14751 GURL accept_ch_with_lifetime_http_local_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05752 GURL http_equiv_accept_ch_with_lifetime_http_local_url_;
Tarun Bansal1965b042017-09-07 04:59:19753 GURL accept_ch_with_lifetime_url_;
Tarun Bansal73502f92019-04-16 21:21:19754 GURL accept_ch_with_short_lifetime_url_;
Tarun Bansal1965b042017-09-07 04:59:19755 GURL accept_ch_without_lifetime_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05756 GURL http_equiv_accept_ch_without_lifetime_url_;
Tarun Bansal1965b042017-09-07 04:59:19757 GURL without_accept_ch_without_lifetime_url_;
Tarun Bansal3b330b02017-11-09 19:03:14758 GURL without_accept_ch_without_lifetime_local_url_;
Tarun Bansaladd5e1812018-02-09 19:07:58759 GURL accept_ch_without_lifetime_with_iframe_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05760 GURL http_equiv_accept_ch_without_lifetime_with_iframe_url_;
Tarun Bansal62cc3542018-06-27 23:53:30761 GURL accept_ch_without_lifetime_with_subresource_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05762 GURL http_equiv_accept_ch_without_lifetime_with_subresource_url_;
Tarun Bansal62cc3542018-06-27 23:53:30763 GURL accept_ch_without_lifetime_with_subresource_iframe_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05764 GURL http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_;
Tarun Bansaladd5e1812018-02-09 19:07:58765 GURL without_accept_ch_without_lifetime_img_foo_com_;
766 GURL without_accept_ch_without_lifetime_img_localhost_;
Tarun Bansal229647bd002018-02-27 17:33:36767 GURL accept_ch_without_lifetime_img_localhost_;
Tarun Bansal9a7051f2018-07-10 18:30:05768 GURL http_equiv_accept_ch_without_lifetime_img_localhost_;
769 GURL http_equiv_accept_ch_with_lifetime_;
Tarun Bansal293a7b6c2018-12-05 17:41:12770 GURL redirect_url_;
Maks Orlovich7a588d82020-05-06 15:17:24771 GURL accept_ch_empty_;
772 GURL http_equiv_accept_ch_merge_;
Tarun Bansal1965b042017-09-07 04:59:19773
Mike Weste555be862019-02-20 16:17:30774 std::string main_frame_ua_observed_;
Yoav Weissd33bacb2020-03-12 06:42:21775 std::string main_frame_ua_full_version_observed_;
Maks Orlovich73f374d2020-04-02 12:46:13776 std::string main_frame_ua_mobile_observed_;
777 std::string main_frame_ua_platform_observed_;
Mike Weste555be862019-02-20 16:17:30778
Tarun Bansal44ad96882018-03-28 17:47:42779 double main_frame_dpr_observed_ = -1;
780 double main_frame_viewport_width_observed_ = -1;
781 double main_frame_device_memory_observed_ = -1;
782
Tarun Bansal229647bd002018-02-27 17:33:36783 // Expect client hints on all the main frame request.
784 bool expect_client_hints_on_main_frame_;
785 // Expect client hints on all the subresource requests.
Callum May1d939742020-03-02 17:51:30786 bool expect_client_hints_on_subresources_
787 GUARDED_BY(expect_client_hints_on_subresources_lock_);
788
789 base::Lock expect_client_hints_on_subresources_lock_;
Tarun Bansal229647bd002018-02-27 17:33:36790
Mike West2fddeeb72019-02-15 11:29:48791 size_t count_user_agent_hint_headers_seen_;
Maks Orlovich5dcc99c2020-02-13 19:07:46792 size_t count_ua_mobile_client_hints_headers_seen_;
Tarun Bansal1965b042017-09-07 04:59:19793 size_t count_client_hints_headers_seen_;
Tarun Bansala61f0f62017-10-24 23:53:05794
Jay Civelli1ff872d2018-03-09 21:52:16795 std::unique_ptr<ThirdPartyURLLoaderInterceptor> request_interceptor_;
Tarun Bansal229647bd002018-02-27 17:33:36796
Tarun Bansalbef6d652018-10-02 18:41:01797 // Set to 2G in SetUpCommandLine().
798 net::EffectiveConnectionType expected_ect = net::EFFECTIVE_CONNECTION_TYPE_2G;
799
Tarun Bansala61f0f62017-10-24 23:53:05800 DISALLOW_COPY_AND_ASSIGN(ClientHintsBrowserTest);
Tarun Bansal0b8b7afd2017-08-25 03:52:16801};
802
Tarun Bansal9a7051f2018-07-10 18:30:05803// True if testing for http-equiv correctness. When set to true, the tests
804// use webpages that may contain http-equiv Accept-CH and Accept-CH-Lifetime
805// headers. When set to false, the tests use webpages that set the headers in
806// the HTTP response headers.
Ilia Samsonov282c38412019-12-09 08:15:10807INSTANTIATE_TEST_SUITE_P(All,
Victor Costane5e91512019-02-13 08:24:02808 ClientHintsBrowserTest,
809 testing::Bool());
Tarun Bansal9a7051f2018-07-10 18:30:05810
Tarun Bansalea0d8262018-05-21 16:11:50811class ClientHintsAllowThirdPartyBrowserTest : public ClientHintsBrowserTest {
Mike West2fddeeb72019-02-15 11:29:48812 std::unique_ptr<base::FeatureList> EnabledFeatures() override {
813 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
814 feature_list->InitializeFromCommandLine(
Maks Orlovichc66745a2020-06-30 17:40:02815 "AllowClientHintsToThirdParty,UserAgentClientHint,LangClientHintHeader",
816 "");
Mike West2fddeeb72019-02-15 11:29:48817 return feature_list;
Tarun Bansalea0d8262018-05-21 16:11:50818 }
819};
820
Ilia Samsonov282c38412019-12-09 08:15:10821INSTANTIATE_TEST_SUITE_P(All,
Aaron Tagliaboschia09ec442019-09-18 15:29:03822 ClientHintsAllowThirdPartyBrowserTest,
823 testing::Bool());
824
Tarun Bansal74e189d2018-05-07 19:07:35825IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, CorsChecks) {
Mike West14c11102019-02-04 16:16:47826 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Tarun Bansal74e189d2018-05-07 19:07:35827 // Do not test for headers that have not been enabled on the blink "stable"
828 // yet.
829 if (std::string(blink::kClientHintsHeaderMapping[i]) == "rtt" ||
830 std::string(blink::kClientHintsHeaderMapping[i]) == "downlink" ||
831 std::string(blink::kClientHintsHeaderMapping[i]) == "ect") {
832 continue;
833 }
Takashi Toyoshima2e01e692018-11-16 03:23:27834 EXPECT_TRUE(network::cors::IsCorsSafelistedHeader(
Tarun Bansal74e189d2018-05-07 19:07:35835 blink::kClientHintsHeaderMapping[i], "42" /* value */));
836 }
Takashi Toyoshima2e01e692018-11-16 03:23:27837 EXPECT_FALSE(network::cors::IsCorsSafelistedHeader("not-a-client-hint-header",
Tarun Bansal74e189d2018-05-07 19:07:35838 "" /* value */));
839 EXPECT_TRUE(
Takashi Toyoshima2e01e692018-11-16 03:23:27840 network::cors::IsCorsSafelistedHeader("save-data", "on" /* value */));
Tarun Bansal74e189d2018-05-07 19:07:35841}
842
Maks Orlovichf0a2eed2020-05-02 20:08:21843IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, HttpEquivWorks) {
844 const GURL gurl = http_equiv_accept_ch_without_lifetime_img_localhost();
845 base::HistogramTester histogram_tester;
846
847 SetClientHintExpectationsOnMainFrame(false);
848 SetClientHintExpectationsOnSubresources(true);
849
850 ui_test_utils::NavigateToURL(browser(), gurl);
851 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
852}
853
Tarun Bansal0b8b7afd2017-08-25 03:52:16854// Loads a webpage that requests persisting of client hints. Verifies that
855// the browser receives the mojo notification from the renderer and persists the
Maks Orlovichf0a2eed2020-05-02 20:08:21856// client hints to the disk --- unless it's using http-equiv which shouldn't
857// persist.
Tarun Bansal9a7051f2018-07-10 18:30:05858IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest, ClientHintsHttps) {
Tarun Bansal0b8b7afd2017-08-25 03:52:16859 base::HistogramTester histogram_tester;
Tarun Bansal9a7051f2018-07-10 18:30:05860 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
861 : accept_ch_with_lifetime_url();
862 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal0b8b7afd2017-08-25 03:52:16863
Maks Orlovichf0a2eed2020-05-02 20:08:21864 if (GetParam())
865 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
866 else
867 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
Tarun Bansal0b8b7afd2017-08-25 03:52:16868
869 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:28870 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal0b8b7afd2017-08-25 03:52:16871
Maks Orlovichf0a2eed2020-05-02 20:08:21872 if (GetParam()) {
873 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
874 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
875 } else {
876 // client_hints_url() sets the expected number of client hints.
877 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
878 expected_client_hints_number, 1);
879 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:12880 // seconds, but a maximum value is registered instead.
Maks Orlovichf0a2eed2020-05-02 20:08:21881 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:12882 uma_histogram_max_value, 1);
Maks Orlovichf0a2eed2020-05-02 20:08:21883 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16884}
885
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44886IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, PRE_ClientHintsClearSession) {
887 const GURL gurl = accept_ch_with_lifetime_url();
888
889 base::HistogramTester histogram_tester;
890 ContentSettingsForOneType host_settings;
891
892 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:14893 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44894 &host_settings);
895 EXPECT_EQ(0u, host_settings.size());
896
897 // Fetching |gurl| should persist the request for client hints iff using
898 // headers and not http-equiv.
899 ui_test_utils::NavigateToURL(browser(), gurl);
900
901 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
902
903 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:28904 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44905 base::RunLoop().RunUntilIdle();
906
907 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
908 expected_client_hints_number, 1);
909 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:12910 // seconds, but a maximum value is registered instead.
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44911 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:12912 uma_histogram_max_value, 1);
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44913
914 // Clients hints preferences for one origin should be persisted.
915 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:14916 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44917 &host_settings);
918 EXPECT_EQ(1u, host_settings.size());
919
920 SetClientHintExpectationsOnMainFrame(true);
921 SetClientHintExpectationsOnSubresources(true);
922 ui_test_utils::NavigateToURL(browser(),
923 without_accept_ch_without_lifetime_url());
924
925 // The user agent hint is attached to all three requests:
926 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
927 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
928
929 // Expected number of hints attached to the image request, and the same number
930 // to the main frame request.
931 EXPECT_EQ(expected_client_hints_number * 2,
932 count_client_hints_headers_seen());
933}
934
935IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, ClientHintsClearSession) {
936 const GURL gurl = accept_ch_with_lifetime_url();
937
938 base::HistogramTester histogram_tester;
939 ContentSettingsForOneType host_settings;
940
941 // Clients hints preferences for one origin should be persisted.
942 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:14943 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44944 &host_settings);
945 EXPECT_EQ(0u, host_settings.size());
946
947 SetClientHintExpectationsOnMainFrame(false);
948 SetClientHintExpectationsOnSubresources(false);
949 ui_test_utils::NavigateToURL(browser(),
950 without_accept_ch_without_lifetime_url());
951
952 // The user agent hint is attached to all three requests:
953 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
954 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
955
956 // Expected number of hints attached to the image request, and the same number
957 // to the main frame request.
958 EXPECT_EQ(0u, count_client_hints_headers_seen());
959}
960
Tarun Bansaladd5e1812018-02-09 19:07:58961// Test that client hints are attached to subresources only if they belong
962// to the same host as document host.
Maks Orlovichf0a2eed2020-05-02 20:08:21963IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansaladd5e1812018-02-09 19:07:58964 ClientHintsHttpsSubresourceDifferentOrigin) {
Maks Orlovichf0a2eed2020-05-02 20:08:21965 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:05966
Tarun Bansaladd5e1812018-02-09 19:07:58967 base::HistogramTester histogram_tester;
968
969 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:05970 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansaladd5e1812018-02-09 19:07:58971 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
972
973 // Verify that the client hints settings for localhost have been saved.
974 ContentSettingsForOneType client_hints_settings;
975 HostContentSettingsMap* host_content_settings_map =
976 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
977 host_content_settings_map->GetSettingsForOneType(
Illia Klimov48f643c2020-11-05 20:06:14978 ContentSettingsType::CLIENT_HINTS, &client_hints_settings);
Tarun Bansaladd5e1812018-02-09 19:07:58979 ASSERT_EQ(1U, client_hints_settings.size());
980
981 // Copy the client hints setting for localhost to foo.com.
982 host_content_settings_map->SetWebsiteSettingDefaultScope(
Darin Fisher42f5e7d2019-10-30 07:15:45983 GURL("https://foo.com/"), GURL(), ContentSettingsType::CLIENT_HINTS,
Illia Klimov48f643c2020-11-05 20:06:14984
Jeremy Romanec48d7a2018-03-01 17:35:09985 std::make_unique<base::Value>(
Oksana Zhuravlovab14dc882018-04-12 17:34:57986 client_hints_settings.at(0).setting_value.Clone()));
Tarun Bansaladd5e1812018-02-09 19:07:58987
988 // Verify that client hints for the two hosts has been saved.
989 host_content_settings_map =
990 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
991 host_content_settings_map->GetSettingsForOneType(
Illia Klimov48f643c2020-11-05 20:06:14992 ContentSettingsType::CLIENT_HINTS, &client_hints_settings);
Tarun Bansaladd5e1812018-02-09 19:07:58993 ASSERT_EQ(2U, client_hints_settings.size());
994
995 // Navigating to without_accept_ch_without_lifetime_img_localhost() should
996 // attach client hints to the image subresouce contained in that page since
997 // the image is located on the same server as the document origin.
Tarun Bansal229647bd002018-02-27 17:33:36998 SetClientHintExpectationsOnMainFrame(true);
999 SetClientHintExpectationsOnSubresources(true);
Tarun Bansaladd5e1812018-02-09 19:07:581000 ui_test_utils::NavigateToURL(
1001 browser(), without_accept_ch_without_lifetime_img_localhost());
1002 base::RunLoop().RunUntilIdle();
1003 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281004 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansaladd5e1812018-02-09 19:07:581005
Maks Orlovich5dcc99c2020-02-13 19:07:461006 // The user agent hint is attached to all three requests, as is UA-mobile:
Mike West2fddeeb72019-02-15 11:29:481007 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461008 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481009
Yoav Weissd33bacb2020-03-12 06:42:211010 // Expected number of hints attached to the image request, and the same number
1011 // to the main frame request.
1012 EXPECT_EQ(expected_client_hints_number * 2,
1013 count_client_hints_headers_seen());
Tarun Bansaladd5e1812018-02-09 19:07:581014
1015 // Navigating to without_accept_ch_without_lifetime_img_foo_com() should not
1016 // attach client hints to the image subresouce contained in that page since
1017 // the image is located on a different server as the document origin.
Tarun Bansaladd5e1812018-02-09 19:07:581018 ui_test_utils::NavigateToURL(
1019 browser(), without_accept_ch_without_lifetime_img_foo_com());
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
Tarun Bansalb30b7532018-03-14 21:50:381024 // The device-memory and dprheader is attached to the main frame request.
Tarun Bansal5c28afb2018-03-17 02:55:201025#if defined(OS_ANDROID)
Yoav Weissd33bacb2020-03-12 06:42:211026 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal5c28afb2018-03-17 02:55:201027#else
Yoav Weissd33bacb2020-03-12 06:42:211028 EXPECT_EQ(expected_client_hints_number * 3,
1029 count_client_hints_headers_seen());
Tarun Bansal5c28afb2018-03-17 02:55:201030#endif
Mike West2fddeeb72019-02-15 11:29:481031
1032 // Requests to third party servers should have only one client hint attached
1033 // (`Sec-CH-UA`).
Tarun Bansal229647bd002018-02-27 17:33:361034 EXPECT_EQ(1u, third_party_request_count_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461035 EXPECT_EQ(2u, third_party_client_hints_count_seen());
Tarun Bansaladd5e1812018-02-09 19:07:581036}
1037
Maks Orlovich7227ce0d2020-02-28 17:13:161038// Test that client hints are attached to subresources checks the right setting
1039// for OTR profile.
Maks Orlovichf0a2eed2020-05-02 20:08:211040IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Maks Orlovich7227ce0d2020-02-28 17:13:161041 ClientHintsHttpsSubresourceOffTheRecord) {
Maks Orlovichf0a2eed2020-05-02 20:08:211042 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich7227ce0d2020-02-28 17:13:161043
1044 base::HistogramTester histogram_tester;
1045
1046 // Add client hints for the embedded test server.
1047 ui_test_utils::NavigateToURL(browser(), gurl);
1048 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1049
1050 // Main profile should get hints for both page and subresources.
1051 SetClientHintExpectationsOnMainFrame(true);
1052 SetClientHintExpectationsOnSubresources(true);
1053 ui_test_utils::NavigateToURL(
1054 browser(), without_accept_ch_without_lifetime_img_localhost());
1055 base::RunLoop().RunUntilIdle();
1056 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281057 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Maks Orlovich7227ce0d2020-02-28 17:13:161058
1059 // The user agent hint is attached to all three requests:
1060 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
1061 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
1062
Yoav Weissd33bacb2020-03-12 06:42:211063 // Expected number of hints attached to the image request, and the same number
1064 // to the main frame request.
1065 EXPECT_EQ(expected_client_hints_number * 2,
1066 count_client_hints_headers_seen());
Maks Orlovich7227ce0d2020-02-28 17:13:161067
1068 // OTR profile should get neither.
1069 Browser* otr_browser = CreateIncognitoBrowser(browser()->profile());
1070 SetClientHintExpectationsOnMainFrame(false);
1071 SetClientHintExpectationsOnSubresources(false);
1072 ui_test_utils::NavigateToURL(
1073 otr_browser, without_accept_ch_without_lifetime_img_localhost());
1074}
1075
Mike Weste555be862019-02-20 16:17:301076// Verify that we send only major version information in the `Sec-CH-UA` header
Yoav Weissd33bacb2020-03-12 06:42:211077// by default, regardless of opt-in.
Maks Orlovichf0a2eed2020-05-02 20:08:211078IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UserAgentVersion) {
1079 const GURL gurl = accept_ch_with_lifetime_url();
Mike Weste555be862019-02-20 16:17:301080
John Abd-El-Malekec1fc69e2021-01-28 19:14:411081 blink::UserAgentMetadata ua = embedder_support::GetUserAgentMetadata();
Mike Weste555be862019-02-20 16:17:301082
1083 // Navigate to a page that opts-into the header: the value should end with
1084 // the major version, and not contain the full version.
1085 SetClientHintExpectationsOnMainFrame(false);
1086 ui_test_utils::NavigateToURL(browser(), gurl);
Aaron Tagliaboschi9f01b682020-05-05 21:03:171087 std::string expected_ua = ua.SerializeBrandVersionList();
Yoav Weissd33bacb2020-03-12 06:42:211088 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1089 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Mike Weste555be862019-02-20 16:17:301090
Yoav Weissd33bacb2020-03-12 06:42:211091 // Navigate again, after the opt-in: the value should stay the major
Mike Weste555be862019-02-20 16:17:301092 // version.
1093 SetClientHintExpectationsOnMainFrame(true);
1094 ui_test_utils::NavigateToURL(browser(), gurl);
Yoav Weissd33bacb2020-03-12 06:42:211095 std::string expected_full_version = "\"" + ua.full_version + "\"";
1096 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1097 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
Mike Weste555be862019-02-20 16:17:301098}
1099
Maks Orlovichf0a2eed2020-05-02 20:08:211100IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UAHintsTabletMode) {
1101 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich73f374d2020-04-02 12:46:131102
John Abd-El-Malekec1fc69e2021-01-28 19:14:411103 blink::UserAgentMetadata ua = embedder_support::GetUserAgentMetadata();
Maks Orlovich73f374d2020-04-02 12:46:131104
1105 // First request: only minimal hints, no tablet override.
1106 SetClientHintExpectationsOnMainFrame(false);
1107 ui_test_utils::NavigateToURL(browser(), gurl);
Aaron Tagliaboschi9f01b682020-05-05 21:03:171108 std::string expected_ua = ua.SerializeBrandVersionList();
Maks Orlovich73f374d2020-04-02 12:46:131109 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1110 EXPECT_EQ(main_frame_ua_full_version_observed(), "");
1111 EXPECT_EQ(main_frame_ua_mobile_observed(), "?0");
1112 EXPECT_EQ(main_frame_ua_platform_observed(), "");
1113
1114 // Second request: table override, all hints.
1115 chrome::ToggleRequestTabletSite(browser());
1116 SetClientHintExpectationsOnMainFrame(true);
1117 ui_test_utils::NavigateToURL(browser(), gurl);
1118 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1119 std::string expected_full_version = "\"" + ua.full_version + "\"";
1120 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
1121 EXPECT_EQ(main_frame_ua_mobile_observed(), "?1");
1122 EXPECT_EQ(main_frame_ua_platform_observed(), "\"Android\"");
1123}
1124
1125// TODO(morlovich): Move this into WebContentsImplBrowserTest once things are
1126// refactored enough that UA client hints actually work in content/
1127IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UserAgentOverrideClientHints) {
1128 content::WebContents* web_contents =
1129 browser()->tab_strip_model()->GetActiveWebContents();
1130
1131 ASSERT_TRUE(embedded_test_server()->Start());
1132 const std::string kHeaderPath = std::string("/echoheader?") +
1133 net::HttpRequestHeaders::kUserAgent +
1134 "&sec-ch-ua&sec-ch-ua-mobile";
1135 const GURL kUrl(embedded_test_server()->GetURL(kHeaderPath));
1136
1137 web_contents->SetUserAgentOverride(
1138 blink::UserAgentOverride::UserAgentOnly("foo"), false);
1139 // Not enabled first.
1140 ui_test_utils::NavigateToURL(browser(), kUrl);
1141 std::string header_value;
1142 EXPECT_TRUE(ExecuteScriptAndExtractString(
1143 web_contents,
1144 "window.domAutomationController.send(document.body.textContent);",
1145 &header_value));
1146 EXPECT_EQ(std::string::npos, header_value.find("foo")) << header_value;
1147
1148 // Actually turn it on.
1149 web_contents->GetController()
1150 .GetLastCommittedEntry()
1151 ->SetIsOverridingUserAgent(true);
1152
1153 ui_test_utils::NavigateToURL(browser(), kUrl);
1154 EXPECT_TRUE(ExecuteScriptAndExtractString(
1155 web_contents,
1156 "window.domAutomationController.send(document.body.textContent);",
1157 &header_value));
1158 // Since no value was provided for client hints, they are not sent.
1159 EXPECT_EQ("foo\nNone\nNone", header_value);
1160
1161 // Now actually provide values for the hints.
1162 blink::UserAgentOverride ua_override;
1163 ua_override.ua_string_override = "foobar";
1164 ua_override.ua_metadata_override.emplace();
1165 ua_override.ua_metadata_override->mobile = true;
Aaron Tagliaboschi9f01b682020-05-05 21:03:171166 ua_override.ua_metadata_override->brand_version_list.emplace_back(
1167 "Foobarnator", "3.14");
Maks Orlovich73f374d2020-04-02 12:46:131168 web_contents->SetUserAgentOverride(ua_override, false);
1169 ui_test_utils::NavigateToURL(browser(), kUrl);
1170 EXPECT_TRUE(ExecuteScriptAndExtractString(
1171 web_contents,
1172 "window.domAutomationController.send(document.body.textContent);",
1173 &header_value));
Aaron Tagliaboschi9f01b682020-05-05 21:03:171174 EXPECT_EQ("foobar\n\"Foobarnator\";v=\"3.14\"\n?1", header_value);
Maks Orlovich73f374d2020-04-02 12:46:131175}
1176
Maks Orlovich7a588d82020-05-06 15:17:241177IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, EmptyAcceptCH) {
1178 // First navigate to a page that enables hints. No CH for it yet, since
1179 // nothing opted in.
1180 GURL gurl = accept_ch_with_lifetime_url();
1181 SetClientHintExpectationsOnMainFrame(false);
1182 ui_test_utils::NavigateToURL(browser(), gurl);
1183
1184 // Now go to a page with blank Accept-CH. Should get hints from previous
1185 // visit.
1186 gurl = accept_ch_empty();
1187 SetClientHintExpectationsOnMainFrame(true);
1188 ui_test_utils::NavigateToURL(browser(), gurl);
1189
1190 // Visiting again should not expect them since we opted out again.
1191 SetClientHintExpectationsOnMainFrame(false);
1192 ui_test_utils::NavigateToURL(browser(), gurl);
1193}
1194
1195IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, MergeAcceptCH) {
1196 // Go to page where some hints are enabled by headers, some by
1197 // http-equiv. It shouldn't get hints itself (due to first visit),
1198 // but subresources should get all the client hints.
1199 GURL gurl = http_equiv_accept_ch_merge();
1200 SetClientHintExpectationsOnMainFrame(false);
1201 SetClientHintExpectationsOnSubresources(true);
1202 ui_test_utils::NavigateToURL(browser(), gurl);
1203 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
1204}
1205
Maks Orlovich7227ce0d2020-02-28 17:13:161206void ClientHintsBrowserTest::TestProfilesIndependent(Browser* browser_a,
1207 Browser* browser_b) {
Maks Orlovichf0a2eed2020-05-02 20:08:211208 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich7227ce0d2020-02-28 17:13:161209
John Abd-El-Malekec1fc69e2021-01-28 19:14:411210 blink::UserAgentMetadata ua = embedder_support::GetUserAgentMetadata();
Maks Orlovich7227ce0d2020-02-28 17:13:161211
1212 // Navigate |browser_a| to a page that opts-into the header: the value should
1213 // end with the major version, and not contain the full version.
1214 SetClientHintExpectationsOnMainFrame(false);
1215 ui_test_utils::NavigateToURL(browser_a, gurl);
Aaron Tagliaboschi9f01b682020-05-05 21:03:171216 std::string expected_ua = ua.SerializeBrandVersionList();
Yoav Weissd33bacb2020-03-12 06:42:211217 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1218 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Maks Orlovich7227ce0d2020-02-28 17:13:161219
1220 // Try again on |browser_a|, the header should have an effect there.
1221 SetClientHintExpectationsOnMainFrame(true);
1222 ui_test_utils::NavigateToURL(browser_a, gurl);
Yoav Weissd33bacb2020-03-12 06:42:211223 std::string expected_full_version = "\"" + ua.full_version + "\"";
1224 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1225 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
Maks Orlovich7227ce0d2020-02-28 17:13:161226
1227 // Navigate on |browser_b|. That should still only have the major
1228 // version.
1229 SetClientHintExpectationsOnMainFrame(false);
1230 ui_test_utils::NavigateToURL(browser_b, gurl);
Yoav Weissd33bacb2020-03-12 06:42:211231 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1232 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Maks Orlovich7227ce0d2020-02-28 17:13:161233}
1234
1235// Check that client hints attached to navigation inside OTR profiles
1236// use the right settings, regular -> OTR direction.
Maks Orlovichf0a2eed2020-05-02 20:08:211237IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, OffTheRecordIndependent) {
Maks Orlovich7227ce0d2020-02-28 17:13:161238 TestProfilesIndependent(browser(),
1239 CreateIncognitoBrowser(browser()->profile()));
1240}
1241
1242// Check that client hints attached to navigation inside OTR profiles
1243// use the right settings, OTR -> regular direction.
Maks Orlovichf0a2eed2020-05-02 20:08:211244IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, OffTheRecordIndependent2) {
Maks Orlovich7227ce0d2020-02-28 17:13:161245 TestProfilesIndependent(CreateIncognitoBrowser(browser()->profile()),
1246 browser());
1247}
1248
Tarun Bansalea0d8262018-05-21 16:11:501249// Test that client hints are attached to third party subresources if
1250// AllowClientHintsToThirdParty feature is enabled.
Tarun Bansal9a7051f2018-07-10 18:30:051251IN_PROC_BROWSER_TEST_P(ClientHintsAllowThirdPartyBrowserTest,
Tarun Bansalea0d8262018-05-21 16:11:501252 ClientHintsThirdPartyAllowed) {
Yoav Weiss76e1afb762020-05-14 19:28:121253 GURL gurl;
1254 unsigned update_event_count = 0;
1255 if (GetParam()) {
1256 gurl = http_equiv_accept_ch_without_lifetime_img_localhost();
1257 } else {
1258 gurl = accept_ch_without_lifetime_img_localhost();
1259 update_event_count = 1;
1260 }
Tarun Bansal9a7051f2018-07-10 18:30:051261
Tarun Bansalea0d8262018-05-21 16:11:501262 base::HistogramTester histogram_tester;
1263
1264 SetClientHintExpectationsOnMainFrame(false);
1265 SetClientHintExpectationsOnSubresources(true);
1266
1267 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:051268 ui_test_utils::NavigateToURL(browser(), gurl);
Yoav Weiss76e1afb762020-05-14 19:28:121269 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount",
1270 update_event_count);
Tarun Bansalea0d8262018-05-21 16:11:501271
Yoav Weissd33bacb2020-03-12 06:42:211272 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansalea0d8262018-05-21 16:11:501273
1274 // Requests to third party servers should not have client hints attached.
1275 EXPECT_EQ(1u, third_party_request_count_seen());
1276
Aaron Tagliaboschia09ec442019-09-18 15:29:031277 // Device memory, viewport width, DRP, and UA client hints should be sent to
1278 // the third-party when feature "AllowClientHintsToThirdParty" is enabled.
Maks Orlovich5dcc99c2020-02-13 19:07:461279 EXPECT_EQ(5u, third_party_client_hints_count_seen());
Tarun Bansalea0d8262018-05-21 16:11:501280}
1281
1282// Test that client hints are not attached to third party subresources if
1283// AllowClientHintsToThirdParty feature is not enabled.
Tarun Bansal9a7051f2018-07-10 18:30:051284IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansalea0d8262018-05-21 16:11:501285 ClientHintsThirdPartyNotAllowed) {
Yoav Weiss76e1afb762020-05-14 19:28:121286 GURL gurl;
1287 unsigned update_event_count = 0;
1288 if (GetParam()) {
1289 gurl = http_equiv_accept_ch_without_lifetime_img_localhost();
1290 } else {
1291 gurl = accept_ch_without_lifetime_img_localhost();
1292 update_event_count = 1;
1293 }
Tarun Bansal9a7051f2018-07-10 18:30:051294
Tarun Bansalea0d8262018-05-21 16:11:501295 base::HistogramTester histogram_tester;
1296
1297 SetClientHintExpectationsOnMainFrame(false);
1298 SetClientHintExpectationsOnSubresources(true);
1299
1300 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:051301 ui_test_utils::NavigateToURL(browser(), gurl);
Yoav Weiss76e1afb762020-05-14 19:28:121302 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount",
1303 update_event_count);
Tarun Bansalea0d8262018-05-21 16:11:501304
Mike West2fddeeb72019-02-15 11:29:481305 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461306 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:211307 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansalea0d8262018-05-21 16:11:501308
1309 // Requests to third party servers should not have client hints attached.
1310 EXPECT_EQ(1u, third_party_request_count_seen());
1311
1312 // Client hints should not be sent to the third-party when feature
Mike West2fddeeb72019-02-15 11:29:481313 // "AllowClientHintsToThirdParty" is not enabled, with the exception of the
1314 // `Sec-CH-UA` hint, which is sent with every request.
Maks Orlovich5dcc99c2020-02-13 19:07:461315 EXPECT_EQ(2u, third_party_client_hints_count_seen());
Tarun Bansalea0d8262018-05-21 16:11:501316}
1317
Tarun Bansaladd5e1812018-02-09 19:07:581318// Loads a HTTPS webpage that does not request persisting of client hints.
Tarun Bansal345418632018-06-29 11:07:041319// A same-origin iframe loaded by the webpage requests persistence of client
Maks Orlovich46619c732020-05-07 10:40:531320// hints. Since that's not a main frame, persistence should not happen.
Maks Orlovichf0a2eed2020-05-02 20:08:211321IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal345418632018-06-29 11:07:041322 PersistenceRequestIframe_SameOrigin) {
Maks Orlovichf0a2eed2020-05-02 20:08:211323 const GURL gurl = accept_ch_without_lifetime_with_iframe_url();
Tarun Bansal345418632018-06-29 11:07:041324 base::HistogramTester histogram_tester;
1325 ContentSettingsForOneType host_settings;
1326
1327 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141328 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal345418632018-06-29 11:07:041329 &host_settings);
1330 EXPECT_EQ(0u, host_settings.size());
1331
Tarun Bansal9a7051f2018-07-10 18:30:051332 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal345418632018-06-29 11:07:041333
Maks Orlovich46619c732020-05-07 10:40:531334 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
Tarun Bansal345418632018-06-29 11:07:041335
1336 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281337 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal345418632018-06-29 11:07:041338
1339 // accept_ch_without_lifetime_with_iframe_url() loads
1340 // accept_ch_with_lifetime() in an iframe. The request to persist client
Maks Orlovich46619c732020-05-07 10:40:531341 // hints from accept_ch_with_lifetime() should not be persisted.
1342 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1343 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
Tarun Bansal345418632018-06-29 11:07:041344}
1345
1346// Loads a HTTPS webpage that does not request persisting of client hints.
1347// An iframe loaded by the webpage from an cross origin server requests
1348// persistence of client hints.
1349// Verify that the request from the cross origin iframe is not honored, and
1350// client hints preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051351IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal345418632018-06-29 11:07:041352 DisregardPersistenceRequestIframe_CrossOrigin) {
Tarun Bansal9a7051f2018-07-10 18:30:051353 const GURL gurl =
1354 GetParam() ? http_equiv_accept_ch_without_lifetime_with_iframe_url()
1355 : accept_ch_without_lifetime_with_iframe_url();
1356
1357 intercept_iframe_resource_ = gurl.path();
1358 intercept_to_http_equiv_iframe_ = GetParam();
1359
Tarun Bansaladd5e1812018-02-09 19:07:581360 base::HistogramTester histogram_tester;
1361 ContentSettingsForOneType host_settings;
1362
1363 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141364 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansaladd5e1812018-02-09 19:07:581365 &host_settings);
1366 EXPECT_EQ(0u, host_settings.size());
1367
Tarun Bansal9a7051f2018-07-10 18:30:051368 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansaladd5e1812018-02-09 19:07:581369
1370 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1371
1372 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281373 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansaladd5e1812018-02-09 19:07:581374
1375 // accept_ch_without_lifetime_with_iframe_url() loads
Tarun Bansal345418632018-06-29 11:07:041376 // accept_ch_with_lifetime() in a cross origin iframe. The request to persist
1377 // client hints from accept_ch_with_lifetime() should be disregarded.
Tarun Bansaladd5e1812018-02-09 19:07:581378 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1379 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1380}
1381
Tarun Bansal62cc3542018-06-27 23:53:301382// Loads a HTTPS webpage that does not request persisting of client hints.
1383// A subresource loaded by the webpage requests persistence of client hints.
1384// Verify that the request from the subresource is not honored, and client hints
1385// preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051386IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal62cc3542018-06-27 23:53:301387 DisregardPersistenceRequestSubresource) {
Tarun Bansal9a7051f2018-07-10 18:30:051388 const GURL gurl =
1389 GetParam() ? http_equiv_accept_ch_without_lifetime_with_subresource_url()
1390 : accept_ch_without_lifetime_with_subresource_url();
1391
Tarun Bansal62cc3542018-06-27 23:53:301392 base::HistogramTester histogram_tester;
1393 ContentSettingsForOneType host_settings;
1394
1395 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141396 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal62cc3542018-06-27 23:53:301397 &host_settings);
1398 EXPECT_EQ(0u, host_settings.size());
1399
Tarun Bansal9a7051f2018-07-10 18:30:051400 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal62cc3542018-06-27 23:53:301401
1402 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1403
1404 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281405 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal62cc3542018-06-27 23:53:301406
1407 // accept_ch_without_lifetime_with_subresource_url() loads
1408 // accept_ch_with_lifetime() as a subresource. The request to persist client
1409 // hints from accept_ch_with_lifetime() should be disregarded.
1410 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1411 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1412}
1413
1414// Loads a HTTPS webpage that does not request persisting of client hints.
1415// A subresource loaded by the webpage in an iframe requests persistence of
1416// client hints. Verify that the request from the subresource in the iframe
1417// is not honored, and client hints preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051418IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal62cc3542018-06-27 23:53:301419 DisregardPersistenceRequestSubresourceIframe) {
Tarun Bansal9a7051f2018-07-10 18:30:051420 const GURL gurl =
1421 GetParam()
1422 ? http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url()
1423 : accept_ch_without_lifetime_with_subresource_iframe_url();
1424
Tarun Bansal62cc3542018-06-27 23:53:301425 base::HistogramTester histogram_tester;
1426 ContentSettingsForOneType host_settings;
1427
1428 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141429 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal62cc3542018-06-27 23:53:301430 &host_settings);
1431 EXPECT_EQ(0u, host_settings.size());
1432
Tarun Bansal9a7051f2018-07-10 18:30:051433 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal62cc3542018-06-27 23:53:301434
1435 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1436
1437 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281438 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal62cc3542018-06-27 23:53:301439
Tarun Bansal9a7051f2018-07-10 18:30:051440 // |gurl| loads accept_ch_with_lifetime() or
1441 // http_equiv_accept_ch_with_lifetime() as a subresource in an iframe. The
1442 // request to persist client hints from accept_ch_with_lifetime() or
1443 // http_equiv_accept_ch_with_lifetime() should be disregarded.
Tarun Bansal62cc3542018-06-27 23:53:301444 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1445 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1446}
1447
Tarun Bansal3b330b02017-11-09 19:03:141448// Loads a HTTP local webpage (which qualifies as a secure context) that
1449// requests persisting of client hints. Verifies that the browser receives the
1450// mojo notification from the renderer and persists the client hints to the
1451// disk.
Maks Orlovichf0a2eed2020-05-02 20:08:211452IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal3b330b02017-11-09 19:03:141453 ClientHintsLifetimeFollowedByNoClientHintHttpLocal) {
Maks Orlovichf0a2eed2020-05-02 20:08:211454 const GURL gurl = accept_ch_with_lifetime_http_local_url();
Tarun Bansal9a7051f2018-07-10 18:30:051455
Tarun Bansal3b330b02017-11-09 19:03:141456 base::HistogramTester histogram_tester;
1457 ContentSettingsForOneType host_settings;
1458
1459 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141460 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3b330b02017-11-09 19:03:141461 &host_settings);
1462 EXPECT_EQ(0u, host_settings.size());
1463
Tarun Bansal9a7051f2018-07-10 18:30:051464 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal3b330b02017-11-09 19:03:141465
1466 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1467
1468 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281469 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal3b330b02017-11-09 19:03:141470
Yoav Weissd33bacb2020-03-12 06:42:211471 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1472 expected_client_hints_number, 1);
Yoav Weiss76e1afb762020-05-14 19:28:121473 // |gurl| sets client hints persist duration to 3600 seconds, but a maximum
1474 // value is registered instead.
Tarun Bansal3b330b02017-11-09 19:03:141475 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121476 uma_histogram_max_value, 1);
Tarun Bansal3b330b02017-11-09 19:03:141477
1478 base::RunLoop().RunUntilIdle();
1479
1480 // Clients hints preferences for one origin should be persisted.
1481 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141482 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3b330b02017-11-09 19:03:141483 &host_settings);
1484 EXPECT_EQ(1u, host_settings.size());
1485
Tarun Bansal229647bd002018-02-27 17:33:361486 SetClientHintExpectationsOnMainFrame(true);
1487 SetClientHintExpectationsOnSubresources(true);
Tarun Bansal3b330b02017-11-09 19:03:141488 ui_test_utils::NavigateToURL(browser(),
1489 without_accept_ch_without_lifetime_local_url());
1490
Mike West2fddeeb72019-02-15 11:29:481491 // The user agent hint is attached to all three requests:
1492 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461493 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481494
Yoav Weissd33bacb2020-03-12 06:42:211495 // Expected number of hints attached to the image request, and the same number
1496 // to the main frame request.
1497 EXPECT_EQ(expected_client_hints_number * 2,
1498 count_client_hints_headers_seen());
Tarun Bansal3b330b02017-11-09 19:03:141499}
1500
Tarun Bansal0b8b7afd2017-08-25 03:52:161501// Loads a webpage that does not request persisting of client hints.
1502IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, NoClientHintsHttps) {
1503 base::HistogramTester histogram_tester;
Tarun Bansal1965b042017-09-07 04:59:191504 ui_test_utils::NavigateToURL(browser(),
1505 without_accept_ch_without_lifetime_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:161506
1507 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1508
1509 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281510 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal0b8b7afd2017-08-25 03:52:161511
1512 // no_client_hints_url() does not sets the client hints.
1513 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1514 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1515}
1516
Tarun Bansal9a7051f2018-07-10 18:30:051517IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal1965b042017-09-07 04:59:191518 ClientHintsLifetimeFollowedByNoClientHint) {
Tarun Bansal9a7051f2018-07-10 18:30:051519 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1520 : accept_ch_with_lifetime_url();
1521
Tarun Bansal1965b042017-09-07 04:59:191522 base::HistogramTester histogram_tester;
1523 ContentSettingsForOneType host_settings;
1524
1525 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141526 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal1965b042017-09-07 04:59:191527 &host_settings);
1528 EXPECT_EQ(0u, host_settings.size());
1529
Maks Orlovichf0a2eed2020-05-02 20:08:211530 // Fetching |gurl| should persist the request for client hints iff using
1531 // headers and not http-equiv.
Tarun Bansal9a7051f2018-07-10 18:30:051532 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal1965b042017-09-07 04:59:191533
Maks Orlovichf0a2eed2020-05-02 20:08:211534 if (GetParam())
1535 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1536 else
1537 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
Tarun Bansal1965b042017-09-07 04:59:191538
1539 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281540 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal1965b042017-09-07 04:59:191541 base::RunLoop().RunUntilIdle();
1542
Maks Orlovichf0a2eed2020-05-02 20:08:211543 if (GetParam()) {
1544 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1545 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1546 } else {
1547 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1548 expected_client_hints_number, 1);
1549 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:121550 // seconds, but a maximum value is registered instead.
Maks Orlovichf0a2eed2020-05-02 20:08:211551 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121552 uma_histogram_max_value, 1);
Tarun Bansal1965b042017-09-07 04:59:191553
Maks Orlovichf0a2eed2020-05-02 20:08:211554 // Clients hints preferences for one origin should be persisted.
1555 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1556 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Illia Klimov48f643c2020-11-05 20:06:141557 &host_settings);
Maks Orlovichf0a2eed2020-05-02 20:08:211558 EXPECT_EQ(1u, host_settings.size());
1559 }
1560
1561 SetClientHintExpectationsOnMainFrame(!GetParam());
1562 SetClientHintExpectationsOnSubresources(!GetParam());
Tarun Bansal1965b042017-09-07 04:59:191563 ui_test_utils::NavigateToURL(browser(),
1564 without_accept_ch_without_lifetime_url());
Tarun Bansal6bf54302017-10-02 07:39:141565
Mike West2fddeeb72019-02-15 11:29:481566 // The user agent hint is attached to all three requests:
1567 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461568 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481569
Yoav Weissd33bacb2020-03-12 06:42:211570 // Expected number of hints attached to the image request, and the same number
1571 // to the main frame request.
Maks Orlovichf0a2eed2020-05-02 20:08:211572 EXPECT_EQ(GetParam() ? 0 : expected_client_hints_number * 2,
Yoav Weissd33bacb2020-03-12 06:42:211573 count_client_hints_headers_seen());
Tarun Bansal1965b042017-09-07 04:59:191574}
1575
Tarun Bansal293a7b6c2018-12-05 17:41:121576// The test first fetches a page that sets Accept-CH-Lifetime. Next, it fetches
1577// a URL from a different origin. However, that URL response redirects to the
1578// same origin from where the first page was fetched. The test verifies that
1579// on receiving redirect to an origin for which the browser has persisted client
1580// hints prefs, the browser attaches the client hints headers when fetching the
1581// redirected URL.
Maks Orlovichf0a2eed2020-05-02 20:08:211582IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal293a7b6c2018-12-05 17:41:121583 ClientHintsLifetimeFollowedByRedirectToNoClientHint) {
Maks Orlovichf0a2eed2020-05-02 20:08:211584 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal293a7b6c2018-12-05 17:41:121585
1586 base::HistogramTester histogram_tester;
1587 ContentSettingsForOneType host_settings;
1588
1589 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141590 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal293a7b6c2018-12-05 17:41:121591 &host_settings);
1592 EXPECT_EQ(0u, host_settings.size());
1593
1594 // Fetching |gurl| should persist the request for client hints.
1595 ui_test_utils::NavigateToURL(browser(), gurl);
1596
1597 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1598
1599 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281600 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal293a7b6c2018-12-05 17:41:121601
Yoav Weissd33bacb2020-03-12 06:42:211602 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1603 expected_client_hints_number, 1);
Tarun Bansal293a7b6c2018-12-05 17:41:121604 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:121605 // seconds, but a maximum value is registered instead.
Tarun Bansal293a7b6c2018-12-05 17:41:121606 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121607 uma_histogram_max_value, 1);
Tarun Bansal293a7b6c2018-12-05 17:41:121608 base::RunLoop().RunUntilIdle();
1609
1610 // Clients hints preferences for one origin should be persisted.
1611 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141612 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal293a7b6c2018-12-05 17:41:121613 &host_settings);
1614 EXPECT_EQ(1u, host_settings.size());
1615
1616 SetClientHintExpectationsOnMainFrame(true);
1617 SetClientHintExpectationsOnSubresources(true);
1618 ui_test_utils::NavigateToURL(browser(), redirect_url());
1619
Mike West2fddeeb72019-02-15 11:29:481620 // The user agent hint is attached to all three requests:
1621 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461622 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481623
Yoav Weissd33bacb2020-03-12 06:42:211624 // Expected number of hints attached to the image request, and the same number
1625 // to the main frame request.
1626 EXPECT_EQ(expected_client_hints_number * 2,
1627 count_client_hints_headers_seen());
Tarun Bansal293a7b6c2018-12-05 17:41:121628}
1629
Tarun Bansala0c1fc32018-10-03 16:14:521630// Ensure that even when cookies are blocked, client hint preferences are
Tarun Bansala61f0f62017-10-24 23:53:051631// persisted.
Maks Orlovichf0a2eed2020-05-02 20:08:211632IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521633 ClientHintsLifetimePersistedCookiesBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211634 const GURL gurl_with = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:051635
Tarun Bansala61f0f62017-10-24 23:53:051636 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
1637 CookieSettingsFactory::GetForProfile(browser()->profile());
1638 base::HistogramTester histogram_tester;
1639 ContentSettingsForOneType host_settings;
1640
1641 // Block cookies.
1642 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansala0c1fc32018-10-03 16:14:521643 ->SetContentSettingDefaultScope(gurl_with, GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451644 ContentSettingsType::COOKIES,
Illia Klimov48f643c2020-11-05 20:06:141645 CONTENT_SETTING_BLOCK);
Tarun Bansala61f0f62017-10-24 23:53:051646
Tarun Bansala0c1fc32018-10-03 16:14:521647 // Fetching |gurl_with| should persist the request for client hints.
Tarun Bansal9a7051f2018-07-10 18:30:051648 ui_test_utils::NavigateToURL(browser(), gurl_with);
Tarun Bansala0c1fc32018-10-03 16:14:521649 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 1);
Tarun Bansala61f0f62017-10-24 23:53:051650 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141651 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051652 &host_settings);
1653 EXPECT_EQ(1u, host_settings.size());
Tarun Bansala0c1fc32018-10-03 16:14:521654 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:051655}
1656
Maks Orlovichf0a2eed2020-05-02 20:08:211657IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521658 ClientHintsLifetimeAttachedCookiesBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211659 const GURL gurl_with = accept_ch_with_lifetime_url();
1660 const GURL gurl_without = accept_ch_without_lifetime_url();
Tarun Bansala61f0f62017-10-24 23:53:051661 base::HistogramTester histogram_tester;
1662 ContentSettingsForOneType host_settings;
1663
1664 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141665 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051666 &host_settings);
1667 EXPECT_EQ(0u, host_settings.size());
1668
Tarun Bansal9a7051f2018-07-10 18:30:051669 // Fetching |gurl_with| should persist the request for client hints.
1670 ui_test_utils::NavigateToURL(browser(), gurl_with);
Tarun Bansala61f0f62017-10-24 23:53:051671 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1672 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281673 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Maks Orlovichf0a2eed2020-05-02 20:08:211674 base::RunLoop().RunUntilIdle();
Tarun Bansala61f0f62017-10-24 23:53:051675
Yoav Weissd33bacb2020-03-12 06:42:211676 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1677 expected_client_hints_number, 1);
Yoav Weiss76e1afb762020-05-14 19:28:121678 // |gurl_with| tries to set client hints persist duration to 3600 seconds, but
1679 // a maximum value is registered instead.
Tarun Bansala61f0f62017-10-24 23:53:051680 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121681 uma_histogram_max_value, 1);
Tarun Bansala61f0f62017-10-24 23:53:051682
1683 // Clients hints preferences for one origin should be persisted.
1684 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141685 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051686 &host_settings);
1687 EXPECT_EQ(1u, host_settings.size());
1688
Tarun Bansala0c1fc32018-10-03 16:14:521689 // Block the cookies: Client hints should be attached.
Tarun Bansala61f0f62017-10-24 23:53:051690 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansal9a7051f2018-07-10 18:30:051691 ->SetContentSettingDefaultScope(gurl_without, GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451692 ContentSettingsType::COOKIES,
Illia Klimov48f643c2020-11-05 20:06:141693 CONTENT_SETTING_BLOCK);
Tarun Bansala61f0f62017-10-24 23:53:051694
Tarun Bansal229647bd002018-02-27 17:33:361695 SetClientHintExpectationsOnMainFrame(true);
1696 SetClientHintExpectationsOnSubresources(true);
Tarun Bansala61f0f62017-10-24 23:53:051697 ui_test_utils::NavigateToURL(browser(),
1698 without_accept_ch_without_lifetime_url());
Tarun Bansal79df868e2018-03-20 23:01:361699
Mike West2fddeeb72019-02-15 11:29:481700 // The user agent hint is attached to all three requests:
1701 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461702 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481703
Yoav Weissd33bacb2020-03-12 06:42:211704 // Expected number of hints attached to the image request, and the same number
1705 // to the main frame request.
1706 EXPECT_EQ(expected_client_hints_number * 2,
1707 count_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051708
1709 // Clear settings.
1710 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451711 ->ClearSettingsForOneType(ContentSettingsType::COOKIES);
Tarun Bansala61f0f62017-10-24 23:53:051712}
1713
1714// Ensure that when the JavaScript is blocked, client hint preferences are not
1715// persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051716IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala61f0f62017-10-24 23:53:051717 ClientHintsLifetimeNotPersistedJavaScriptBlocked) {
1718 ContentSettingsForOneType host_settings;
1719
1720 // Start a navigation. This navigation makes it possible to block JavaScript
1721 // later.
1722 ui_test_utils::NavigateToURL(browser(),
1723 without_accept_ch_without_lifetime_url());
1724
Tarun Bansal9a7051f2018-07-10 18:30:051725 const GURL gurl =
1726 GetParam() ? http_equiv_accept_ch_without_lifetime_with_iframe_url()
1727 : accept_ch_with_lifetime_url();
1728
Tarun Bansala61f0f62017-10-24 23:53:051729 // Block the JavaScript: Client hint preferences should not be persisted.
1730 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141731 ->SetContentSettingDefaultScope(
1732 gurl, GURL(), ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_BLOCK);
Tarun Bansala61f0f62017-10-24 23:53:051733 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
1734 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141735 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051736 &host_settings);
1737 EXPECT_EQ(0u, host_settings.size());
Tarun Bansalc211d8b2018-03-19 19:21:581738 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:051739
1740 // Allow the JavaScript: Client hint preferences should be persisted.
1741 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141742 ->SetContentSettingDefaultScope(
1743 gurl, GURL(), ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_ALLOW);
Tarun Bansala61f0f62017-10-24 23:53:051744 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
1745 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141746 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051747 &host_settings);
1748 EXPECT_EQ(1u, host_settings.size());
Tarun Bansal593790112018-03-20 04:53:341749
1750 // Clear settings.
1751 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451752 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansala61f0f62017-10-24 23:53:051753}
1754
1755// Ensure that when the JavaScript is blocked, persisted client hints are not
1756// attached to the request headers.
Maks Orlovichf0a2eed2020-05-02 20:08:211757IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala61f0f62017-10-24 23:53:051758 ClientHintsLifetimeNotAttachedJavaScriptBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211759 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:051760
Tarun Bansala61f0f62017-10-24 23:53:051761 base::HistogramTester histogram_tester;
1762 ContentSettingsForOneType host_settings;
1763
1764 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141765 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051766 &host_settings);
1767 EXPECT_EQ(0u, host_settings.size());
1768
1769 // Fetching accept_ch_with_lifetime_url() should persist the request for
1770 // client hints.
Tarun Bansal9a7051f2018-07-10 18:30:051771 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansala61f0f62017-10-24 23:53:051772 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1773 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281774 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Mike West2fddeeb72019-02-15 11:29:481775 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461776 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051777
Yoav Weissd33bacb2020-03-12 06:42:211778 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1779 expected_client_hints_number, 1);
Tarun Bansala61f0f62017-10-24 23:53:051780 // accept_ch_with_lifetime_url() tries to set client hints persist duration to
Yoav Weiss76e1afb762020-05-14 19:28:121781 // 3600 seconds, but a maximum value is registered instead.
Tarun Bansala61f0f62017-10-24 23:53:051782 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121783 uma_histogram_max_value, 1);
Tarun Bansala61f0f62017-10-24 23:53:051784 base::RunLoop().RunUntilIdle();
1785
1786 // Clients hints preferences for one origin should be persisted.
1787 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141788 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051789 &host_settings);
1790 EXPECT_EQ(1u, host_settings.size());
1791
Changwan Ryu434c3a32019-07-30 23:42:581792 // Block JavaScript via WebPreferences: Client hints should not be attached.
1793 SetJsEnabledForActiveView(false);
1794
1795 SetClientHintExpectationsOnMainFrame(false);
1796 SetClientHintExpectationsOnSubresources(false);
1797 ui_test_utils::NavigateToURL(browser(),
1798 without_accept_ch_without_lifetime_url());
1799
1800 EXPECT_EQ(0u, count_client_hints_headers_seen());
1801 VerifyContentSettingsNotNotified();
1802 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461803 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Changwan Ryu434c3a32019-07-30 23:42:581804
1805 SetJsEnabledForActiveView(true);
1806
1807 // Block JavaScript via ContentSetting: Client hints should not be attached.
Tarun Bansala61f0f62017-10-24 23:53:051808 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1809 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
Darin Fisher42f5e7d2019-10-30 07:15:451810 GURL(), ContentSettingsType::JAVASCRIPT,
Illia Klimov48f643c2020-11-05 20:06:141811 CONTENT_SETTING_BLOCK);
Tarun Bansala61f0f62017-10-24 23:53:051812 ui_test_utils::NavigateToURL(browser(),
1813 without_accept_ch_without_lifetime_url());
1814 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansalc211d8b2018-03-19 19:21:581815 VerifyContentSettingsNotNotified();
Mike West2fddeeb72019-02-15 11:29:481816 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461817 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051818
Changwan Ryu434c3a32019-07-30 23:42:581819 // Allow JavaScript: Client hints should now be attached.
Tarun Bansala61f0f62017-10-24 23:53:051820 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1821 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
Darin Fisher42f5e7d2019-10-30 07:15:451822 GURL(), ContentSettingsType::JAVASCRIPT,
Illia Klimov48f643c2020-11-05 20:06:141823 CONTENT_SETTING_ALLOW);
Tarun Bansala61f0f62017-10-24 23:53:051824
Tarun Bansal229647bd002018-02-27 17:33:361825 SetClientHintExpectationsOnMainFrame(true);
1826 SetClientHintExpectationsOnSubresources(true);
Tarun Bansala61f0f62017-10-24 23:53:051827 ui_test_utils::NavigateToURL(browser(),
1828 without_accept_ch_without_lifetime_url());
Tarun Bansal79df868e2018-03-20 23:01:361829
Mike West2fddeeb72019-02-15 11:29:481830 // The user agent hint is attached to all three requests:
1831 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461832 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481833
Yoav Weissd33bacb2020-03-12 06:42:211834 // Expected number of hints attached to the image request, and the same number
1835 // to the main frame request.
1836 EXPECT_EQ(expected_client_hints_number * 2,
1837 count_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051838
1839 // Clear settings.
1840 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451841 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansala61f0f62017-10-24 23:53:051842}
1843
Tarun Bansal73502f92019-04-16 21:21:191844// Test that if the content settings are malformed, then the browser does not
1845// crash.
1846IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
1847 ClientHintsMalformedContentSettings) {
1848 ContentSettingsForOneType client_hints_settings;
1849 HostContentSettingsMap* host_content_settings_map =
1850 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
1851
1852 // Add setting for the host.
1853 std::unique_ptr<base::ListValue> expiration_times_list =
1854 std::make_unique<base::ListValue>();
1855 expiration_times_list->AppendInteger(42 /* client hint value */);
1856 auto expiration_times_dictionary = std::make_unique<base::DictionaryValue>();
1857 expiration_times_dictionary->SetList("client_hints",
1858 std::move(expiration_times_list));
Aaron Tagliaboschi3c96a682019-10-29 18:10:281859 expiration_times_dictionary->SetDouble(
1860 "expiration_time",
1861 (base::Time::Now() + base::TimeDelta::FromDays(1)).ToDoubleT());
Tarun Bansal73502f92019-04-16 21:21:191862 host_content_settings_map->SetWebsiteSettingDefaultScope(
1863 without_accept_ch_without_lifetime_url(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141864 ContentSettingsType::CLIENT_HINTS,
Tarun Bansal73502f92019-04-16 21:21:191865 std::make_unique<base::Value>(expiration_times_dictionary->Clone()));
1866
1867 // Reading the settings should now return one setting.
1868 host_content_settings_map->GetSettingsForOneType(
Illia Klimov48f643c2020-11-05 20:06:141869 ContentSettingsType::CLIENT_HINTS, &client_hints_settings);
Tarun Bansal73502f92019-04-16 21:21:191870 EXPECT_EQ(1U, client_hints_settings.size());
1871
1872 SetClientHintExpectationsOnMainFrame(false);
1873 SetClientHintExpectationsOnSubresources(false);
1874 ui_test_utils::NavigateToURL(browser(),
1875 without_accept_ch_without_lifetime_url());
1876}
1877
Tarun Bansal229647bd002018-02-27 17:33:361878// Ensure that when the JavaScript is blocked, client hints requested using
Tarun Bansal3f343d7c2018-03-02 18:48:001879// Accept-CH are not attached to the request headers for subresources.
Tarun Bansal9a7051f2018-07-10 18:30:051880IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal229647bd002018-02-27 17:33:361881 ClientHintsNoLifetimeScriptNotAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:051882 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1883 : accept_ch_with_lifetime_url();
1884
Tarun Bansal1965b042017-09-07 04:59:191885 base::HistogramTester histogram_tester;
1886 ContentSettingsForOneType host_settings;
1887
1888 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141889 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal1965b042017-09-07 04:59:191890 &host_settings);
1891 EXPECT_EQ(0u, host_settings.size());
1892
Tarun Bansal3f343d7c2018-03-02 18:48:001893 // Block the Javascript: Client hints should not be attached.
1894 SetClientHintExpectationsOnSubresources(false);
Tarun Bansal229647bd002018-02-27 17:33:361895 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1896 ->SetContentSettingDefaultScope(
1897 accept_ch_without_lifetime_img_localhost(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141898 ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_BLOCK);
Tarun Bansal229647bd002018-02-27 17:33:361899 ui_test_utils::NavigateToURL(browser(),
1900 accept_ch_without_lifetime_img_localhost());
Mike West2fddeeb72019-02-15 11:29:481901 EXPECT_EQ(0u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461902 EXPECT_EQ(0u, count_ua_mobile_client_hints_headers_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001903 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361904 EXPECT_EQ(1u, third_party_request_count_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001905 EXPECT_EQ(0u, third_party_client_hints_count_seen());
Tarun Bansal1965b042017-09-07 04:59:191906
Tarun Bansal3f343d7c2018-03-02 18:48:001907 // Allow the Javascript: Client hints should now be attached.
Tarun Bansal229647bd002018-02-27 17:33:361908 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1909 ->SetContentSettingDefaultScope(
1910 accept_ch_without_lifetime_img_localhost(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141911 ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_ALLOW);
Tarun Bansal1965b042017-09-07 04:59:191912
Tarun Bansal229647bd002018-02-27 17:33:361913 SetClientHintExpectationsOnSubresources(true);
1914 ui_test_utils::NavigateToURL(browser(),
1915 accept_ch_without_lifetime_img_localhost());
Tarun Bansal3f343d7c2018-03-02 18:48:001916
Mike West2fddeeb72019-02-15 11:29:481917 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461918 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschi150fb9042020-05-14 22:20:371919 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361920 EXPECT_EQ(2u, third_party_request_count_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461921 EXPECT_EQ(2u, third_party_client_hints_count_seen());
Tarun Bansalc211d8b2018-03-19 19:21:581922 VerifyContentSettingsNotNotified();
Tarun Bansal1965b042017-09-07 04:59:191923
Tarun Bansal229647bd002018-02-27 17:33:361924 // Clear settings.
1925 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451926 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansal1965b042017-09-07 04:59:191927
Tarun Bansal229647bd002018-02-27 17:33:361928 // Block the Javascript again: Client hints should not be attached.
Tarun Bansal3f343d7c2018-03-02 18:48:001929 SetClientHintExpectationsOnSubresources(false);
Tarun Bansal229647bd002018-02-27 17:33:361930 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1931 ->SetContentSettingDefaultScope(
1932 accept_ch_without_lifetime_img_localhost(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141933 ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_BLOCK);
Tarun Bansal229647bd002018-02-27 17:33:361934 ui_test_utils::NavigateToURL(browser(),
1935 accept_ch_without_lifetime_img_localhost());
Mike West2fddeeb72019-02-15 11:29:481936 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461937 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschi150fb9042020-05-14 22:20:371938 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361939 EXPECT_EQ(3u, third_party_request_count_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461940 EXPECT_EQ(2u, third_party_client_hints_count_seen());
Tarun Bansal593790112018-03-20 04:53:341941
1942 // Clear settings.
1943 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451944 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansal229647bd002018-02-27 17:33:361945}
1946
Tarun Bansala0c1fc32018-10-03 16:14:521947// Ensure that when the cookies is blocked, client hints are attached to the
Tarun Bansal3f343d7c2018-03-02 18:48:001948// request headers.
Tarun Bansal9a7051f2018-07-10 18:30:051949IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521950 ClientHintsLifetimeCookiesNotAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:051951 const GURL gurl = GetParam()
1952 ? http_equiv_accept_ch_without_lifetime_img_localhost()
1953 : accept_ch_without_lifetime_img_localhost();
1954
Tarun Bansal229647bd002018-02-27 17:33:361955 base::HistogramTester histogram_tester;
1956 ContentSettingsForOneType host_settings;
1957 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
1958 CookieSettingsFactory::GetForProfile(browser()->profile());
1959
Tarun Bansal1965b042017-09-07 04:59:191960 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141961 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal1965b042017-09-07 04:59:191962 &host_settings);
1963 EXPECT_EQ(0u, host_settings.size());
1964
Tarun Bansal229647bd002018-02-27 17:33:361965 // Block cookies.
1966 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141967 ->SetContentSettingDefaultScope(
1968 gurl, GURL(), ContentSettingsType::COOKIES, CONTENT_SETTING_BLOCK);
Tarun Bansal229647bd002018-02-27 17:33:361969 base::RunLoop().RunUntilIdle();
1970
Tarun Bansal229647bd002018-02-27 17:33:361971 SetClientHintExpectationsOnSubresources(true);
Tarun Bansal9a7051f2018-07-10 18:30:051972 ui_test_utils::NavigateToURL(browser(), gurl);
Mike West2fddeeb72019-02-15 11:29:481973 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461974 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:211975 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansala0c1fc32018-10-03 16:14:521976 EXPECT_EQ(1u, third_party_request_count_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461977 EXPECT_EQ(2u, third_party_client_hints_count_seen());
Tarun Bansal593790112018-03-20 04:53:341978
1979 // Clear settings.
1980 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451981 ->ClearSettingsForOneType(ContentSettingsType::COOKIES);
Tarun Bansal1965b042017-09-07 04:59:191982}
1983
Tarun Bansal3ce0ca42018-06-25 22:52:221984// Verify that client hints are sent in the incognito profiles, and server
1985// client hint opt-ins are honored within the incognito profile.
Maks Orlovichf0a2eed2020-05-02 20:08:211986IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal3ce0ca42018-06-25 22:52:221987 ClientHintsLifetimeFollowedByNoClientHintIncognito) {
Maks Orlovichf0a2eed2020-05-02 20:08:211988 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:051989
Tarun Bansal3ce0ca42018-06-25 22:52:221990 base::HistogramTester histogram_tester;
1991 Browser* incognito = CreateIncognitoBrowser();
1992 ContentSettingsForOneType host_settings;
1993
1994 HostContentSettingsMapFactory::GetForProfile(incognito->profile())
Illia Klimov48f643c2020-11-05 20:06:141995 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3ce0ca42018-06-25 22:52:221996 &host_settings);
1997 EXPECT_EQ(0u, host_settings.size());
1998
Tarun Bansal9a7051f2018-07-10 18:30:051999 // Fetching |gurl| should persist the request for client hints.
2000 ui_test_utils::NavigateToURL(incognito, gurl);
Tarun Bansal3ce0ca42018-06-25 22:52:222001
2002 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
2003
2004 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:282005 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal3ce0ca42018-06-25 22:52:222006
Yoav Weissd33bacb2020-03-12 06:42:212007 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
2008 expected_client_hints_number, 1);
Tarun Bansal3ce0ca42018-06-25 22:52:222009 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:122010 // seconds, but a maximum value is registered instead.
Tarun Bansal3ce0ca42018-06-25 22:52:222011 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:122012 uma_histogram_max_value, 1);
Tarun Bansal3ce0ca42018-06-25 22:52:222013 base::RunLoop().RunUntilIdle();
2014
2015 // Clients hints preferences for one origin should be persisted.
2016 HostContentSettingsMapFactory::GetForProfile(incognito->profile())
Illia Klimov48f643c2020-11-05 20:06:142017 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3ce0ca42018-06-25 22:52:222018 &host_settings);
2019 EXPECT_EQ(1u, host_settings.size());
2020
2021 SetClientHintExpectationsOnMainFrame(true);
2022 SetClientHintExpectationsOnSubresources(true);
2023 ui_test_utils::NavigateToURL(incognito,
2024 without_accept_ch_without_lifetime_url());
2025
Mike West2fddeeb72019-02-15 11:29:482026 // The user agent hint is attached to all three requests:
2027 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462028 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:482029
Yoav Weissd33bacb2020-03-12 06:42:212030 // Expected number of hints attached to the image request, and the same number
2031 // to the main frame request.
2032 EXPECT_EQ(expected_client_hints_number * 2,
2033 count_client_hints_headers_seen());
Tarun Bansal3ce0ca42018-06-25 22:52:222034
2035 // Navigate using regular profile. Client hints should not be send.
2036 SetClientHintExpectationsOnMainFrame(false);
2037 SetClientHintExpectationsOnSubresources(false);
2038 ui_test_utils::NavigateToURL(browser(),
2039 without_accept_ch_without_lifetime_url());
2040
Mike West2fddeeb72019-02-15 11:29:482041 // The user agent hint is attached to the two new requests.
2042 EXPECT_EQ(5u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462043 EXPECT_EQ(5u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:482044
2045 // No additional hints are sent.
Yoav Weissd33bacb2020-03-12 06:42:212046 EXPECT_EQ(expected_client_hints_number * 2,
2047 count_client_hints_headers_seen());
Tarun Bansal3ce0ca42018-06-25 22:52:222048}
Tarun Bansalbef6d652018-10-02 18:41:012049
Aaron Tagliaboschi8f3a28302020-06-24 03:08:262050class ClientHintsEnterprisePolicyTest : public ClientHintsBrowserTest {
2051 void SetUpInProcessBrowserTestFixture() override {
2052 policy::PolicyTest::SetUpInProcessBrowserTestFixture();
2053 policy::PolicyMap policies;
2054 SetPolicy(&policies, policy::key::kUserAgentClientHintsEnabled,
Aya ElAttare8811742020-07-20 08:24:372055 base::Value(false));
Aaron Tagliaboschi8f3a28302020-06-24 03:08:262056 provider_.UpdateChromePolicy(policies);
2057 }
2058};
2059
2060// Makes sure that no client hints are sent by default when the
2061// "UserAgentClientHintsEnabled" enterprise polickly is set to
2062// false
2063IN_PROC_BROWSER_TEST_F(ClientHintsEnterprisePolicyTest,
2064 ClientHintsEnterprisePolicy) {
2065 const GURL gurl = accept_ch_without_lifetime_url();
2066 ui_test_utils::NavigateToURL(browser(), gurl);
2067 // These would normally be one each
2068 EXPECT_EQ(0u, count_user_agent_hint_headers_seen());
2069 EXPECT_EQ(0u, count_ua_mobile_client_hints_headers_seen());
2070}
2071
Tarun Bansalbef6d652018-10-02 18:41:012072class ClientHintsWebHoldbackBrowserTest : public ClientHintsBrowserTest {
2073 public:
2074 ClientHintsWebHoldbackBrowserTest() : ClientHintsBrowserTest() {
2075 ConfigureHoldbackExperiment();
2076 }
2077
2078 net::EffectiveConnectionType web_effective_connection_type_override() const {
2079 return web_effective_connection_type_override_;
2080 }
2081
Mike West2fddeeb72019-02-15 11:29:482082 std::unique_ptr<base::FeatureList> EnabledFeatures() override {
Tarun Bansalbef6d652018-10-02 18:41:012083 base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
2084 const std::string kTrialName = "TrialFoo";
2085 const std::string kGroupName = "GroupFoo"; // Value not used
2086
2087 scoped_refptr<base::FieldTrial> trial =
2088 base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
2089
2090 std::map<std::string, std::string> params;
2091
2092 params["web_effective_connection_type_override"] =
2093 net::GetNameForEffectiveConnectionType(
2094 web_effective_connection_type_override_);
Mike West2fddeeb72019-02-15 11:29:482095 EXPECT_TRUE(
Tarun Bansalbef6d652018-10-02 18:41:012096 base::FieldTrialParamAssociator::GetInstance()
2097 ->AssociateFieldTrialParams(kTrialName, kGroupName, params));
2098
2099 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
Maks Orlovichc66745a2020-06-30 17:40:022100 feature_list->InitializeFromCommandLine(
2101 "UserAgentClientHint,LangClientHintHeader", "");
Tarun Bansalbef6d652018-10-02 18:41:012102 feature_list->RegisterFieldTrialOverride(
2103 features::kNetworkQualityEstimatorWebHoldback.name,
2104 base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
Mike West2fddeeb72019-02-15 11:29:482105 return feature_list;
Tarun Bansalbef6d652018-10-02 18:41:012106 }
2107
Mike West2fddeeb72019-02-15 11:29:482108 private:
2109 void ConfigureHoldbackExperiment() {}
2110
Tarun Bansalbef6d652018-10-02 18:41:012111 const net::EffectiveConnectionType web_effective_connection_type_override_ =
2112 net::EFFECTIVE_CONNECTION_TYPE_3G;
Tarun Bansalbef6d652018-10-02 18:41:012113};
2114
2115// Make sure that when NetInfo holdback experiment is enabled, the NetInfo APIs
2116// and client hints return the overridden values. Verify that the client hints
2117// are overridden on both main frame and subresource requests.
2118IN_PROC_BROWSER_TEST_F(ClientHintsWebHoldbackBrowserTest,
2119 EffectiveConnectionTypeChangeNotified) {
2120 SetExpectedEffectiveConnectionType(web_effective_connection_type_override());
2121
2122 SetClientHintExpectationsOnMainFrame(false);
2123 SetClientHintExpectationsOnSubresources(true);
2124
2125 base::RunLoop().RunUntilIdle();
2126
2127 EXPECT_TRUE(embedded_test_server()->Start());
2128 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
2129 EXPECT_EQ(0u, count_client_hints_headers_seen());
2130 EXPECT_EQ(0u, third_party_request_count_seen());
2131 EXPECT_EQ(0u, third_party_client_hints_count_seen());
2132
2133 SetClientHintExpectationsOnMainFrame(true);
2134 SetClientHintExpectationsOnSubresources(true);
2135 ui_test_utils::NavigateToURL(
2136 browser(), accept_ch_without_lifetime_with_subresource_url());
2137 base::RunLoop().RunUntilIdle();
2138 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:282139 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansalbef6d652018-10-02 18:41:012140
Mike West2fddeeb72019-02-15 11:29:482141 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462142 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:212143 EXPECT_EQ(expected_client_hints_number * 2,
2144 count_client_hints_headers_seen());
Tarun Bansalbef6d652018-10-02 18:41:012145 EXPECT_EQ(0u, third_party_request_count_seen());
2146 EXPECT_EQ(0u, third_party_client_hints_count_seen());
2147}
Aaron Tagliaboschi603540d22021-04-05 00:37:142148
2149class AcceptCHFrameObserverInterceptor {
2150 public:
2151 AcceptCHFrameObserverInterceptor()
2152 : interceptor_(base::BindRepeating(
2153 &AcceptCHFrameObserverInterceptor::InterceptURLRequest,
2154 base::Unretained(this))) {}
2155
2156 void set_accept_ch_frame(
2157 std::vector<network::mojom::WebClientHintsType> frame) {
2158 accept_ch_frame_ = frame;
2159 }
2160
2161 private:
2162 bool InterceptURLRequest(
2163 content::URLLoaderInterceptor::RequestParams* params) {
2164 if (!accept_ch_frame_ || !params->url_request.trusted_params ||
2165 !params->url_request.trusted_params->accept_ch_frame_observer) {
2166 return false;
2167 }
2168
2169 std::vector<network::mojom::WebClientHintsType> hints;
2170 for (auto hint : accept_ch_frame_.value()) {
2171 std::string header =
2172 network::kClientHintsNameMapping[static_cast<int>(hint)];
2173 if (!params->url_request.headers.HasHeader(header))
2174 hints.push_back(hint);
2175 }
2176
2177 if (hints.empty())
2178 return false;
2179
2180 mojo::Remote<network::mojom::AcceptCHFrameObserver> remote(std::move(
2181 params->url_request.trusted_params->accept_ch_frame_observer));
2182 remote->OnAcceptCHFrameReceived(params->url_request.url, hints,
2183 base::DoNothing::Once<int>());
2184 // At this point it's expected that either the remote's callback will be
2185 // called or the URLLoader will be destroyed to make way for a new one.
2186 // As this is essentially unobservable, RunUntilIdle must be used.
2187 base::RunLoop().RunUntilIdle();
2188 return false;
2189 }
2190
2191 content::URLLoaderInterceptor interceptor_;
2192 base::Optional<std::vector<network::mojom::WebClientHintsType>>
2193 accept_ch_frame_;
2194};
2195
2196// Replace the request interceptor with an AcceptCHFrameObserverInterceptor.
2197class ClientHintsAcceptCHFrameObserverBrowserTest
2198 : public ClientHintsBrowserTest {
2199 public:
2200 void SetUpOnMainThread() override {
2201 host_resolver()->AddRule("*", "127.0.0.1");
2202 accept_ch_frame_observer_interceptor_ =
2203 std::make_unique<AcceptCHFrameObserverInterceptor>();
2204 }
2205
2206 void TearDownOnMainThread() override {
2207 accept_ch_frame_observer_interceptor_.reset();
2208 }
2209
2210 void set_accept_ch_frame(
2211 std::vector<network::mojom::WebClientHintsType> frame) {
2212 accept_ch_frame_observer_interceptor_->set_accept_ch_frame(frame);
2213 }
2214
2215 std::vector<network::mojom::WebClientHintsType> all_client_hints_types() {
2216 std::vector<network::mojom::WebClientHintsType> hints;
2217 for (size_t i = 0; i < blink::kClientHintsMappingsCount; i++) {
2218 hints.push_back(static_cast<network::mojom::WebClientHintsType>(i));
2219 }
2220
2221 return hints;
2222 }
2223
2224 private:
2225 std::unique_ptr<AcceptCHFrameObserverInterceptor>
2226 accept_ch_frame_observer_interceptor_;
2227};
2228
Elly Fong-Jonesdd9eb012021-04-05 22:45:272229#if defined(OS_CHROMEOS)
2230// Flaky: https://crbug.com/1195790
2231#define MAYBE_AcceptCHFrame DISABLED_AcceptCHFrame
2232#else
2233#define MAYBE_AcceptCHFrame AcceptCHFrame
2234#endif
2235
Aaron Tagliaboschi603540d22021-04-05 00:37:142236// Ensure that client hints are sent when the ACCEPT_CH frame observer is
2237// notified.
2238IN_PROC_BROWSER_TEST_F(ClientHintsAcceptCHFrameObserverBrowserTest,
Elly Fong-Jonesdd9eb012021-04-05 22:45:272239 MAYBE_AcceptCHFrame) {
Aaron Tagliaboschi603540d22021-04-05 00:37:142240 const GURL gurl = without_accept_ch_without_lifetime_url();
2241 set_accept_ch_frame(all_client_hints_types());
2242 SetClientHintExpectationsOnMainFrame(true);
2243 SetClientHintExpectationsOnSubresources(false);
2244 ui_test_utils::NavigateToURL(browser(), gurl);
2245}
2246
2247// Ensure that client hints are *not* sent when the observer is notified but
2248// client hints would normally not be sent (e.g. when JS is disabled for the
2249// frame).
2250IN_PROC_BROWSER_TEST_F(ClientHintsAcceptCHFrameObserverBrowserTest,
2251 AcceptCHFrameJSDisabled) {
2252 const GURL gurl = without_accept_ch_without_lifetime_url();
2253 set_accept_ch_frame(all_client_hints_types());
2254 SetJsEnabledForActiveView(false);
2255 SetClientHintExpectationsOnMainFrame(false);
2256 SetClientHintExpectationsOnSubresources(false);
2257 ui_test_utils::NavigateToURL(browser(), gurl);
2258}