blob: 63fa949bf58289d0f674c72fed858095aa32edc3 [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>
6
Mike West2fddeeb72019-02-15 11:29:487#include "base/base_switches.h"
Tarun Bansal229647bd002018-02-27 17:33:368#include "base/bind.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:169#include "base/command_line.h"
Tarun Bansalbef6d652018-10-02 18:41:0110#include "base/metrics/field_trial_param_associator.h"
Gabriel Charetteb71eec892017-09-14 22:52:5611#include "base/run_loop.h"
Tarun Bansal6bf54302017-10-02 07:39:1412#include "base/stl_util.h"
Mike Weste555be862019-02-20 16:17:3013#include "base/strings/string_util.h"
Callum May7d88ff3e2019-11-12 18:21:4614#include "base/synchronization/lock.h"
Devlin Cronin626d80c2018-06-01 01:08:3615#include "base/test/metrics/histogram_tester.h"
Tarun Bansal5c28afb2018-03-17 02:55:2016#include "build/build_config.h"
Mike Weste555be862019-02-20 16:17:3017#include "chrome/browser/chrome_content_browser_client.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"
Tarun Bansal0b8b7afd2017-08-25 03:52:1620#include "chrome/browser/metrics/subprocess_metrics_provider.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"
Clark DuVall84a33d612020-04-17 16:01:0026#include "components/content_settings/browser/tab_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"
30#include "components/prefs/pref_service.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1631#include "content/public/browser/browser_thread.h"
Maks Orlovich73f374d2020-04-02 12:46:1332#include "content/public/browser/navigation_entry.h"
Changwan Ryu434c3a32019-07-30 23:42:5833#include "content/public/browser/render_view_host.h"
Tarun Bansalbef6d652018-10-02 18:41:0134#include "content/public/common/content_features.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1635#include "content/public/common/content_switches.h"
Changwan Ryu434c3a32019-07-30 23:42:5836#include "content/public/common/web_preferences.h"
Peter Kasting919ce652020-05-07 10:22:3637#include "content/public/test/browser_test.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1638#include "content/public/test/browser_test_utils.h"
39#include "content/public/test/test_utils.h"
Tarun Bansal229647bd002018-02-27 17:33:3640#include "content/public/test/url_loader_interceptor.h"
41#include "net/dns/mock_host_resolver.h"
42#include "net/http/http_request_headers.h"
Tarun Bansal7f3fe8c2018-04-06 22:37:4743#include "net/nqe/effective_connection_type.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1644#include "net/test/embedded_test_server/embedded_test_server.h"
Tarun Bansal1965b042017-09-07 04:59:1945#include "net/test/embedded_test_server/http_request.h"
Tarun Bansal229647bd002018-02-27 17:33:3646#include "net/test/embedded_test_server/http_response.h"
Tarun Bansal74e189d2018-05-07 19:07:3547#include "services/network/public/cpp/cors/cors.h"
Tarun Bansalceab9592018-05-01 18:57:3548#include "services/network/public/cpp/features.h"
Tarun Bansal7f3fe8c2018-04-06 22:37:4749#include "services/network/public/cpp/network_switches.h"
Blink Reformata30d4232018-04-07 15:31:0650#include "third_party/blink/public/common/client_hints/client_hints.h"
Tarun Bansal229647bd002018-02-27 17:33:3651
52namespace {
53
Yoav Weissfd1d19f2020-05-05 09:23:0354const unsigned expected_client_hints_number = 12u;
Yoav Weissd33bacb2020-03-12 06:42:2155
Tarun Bansal229647bd002018-02-27 17:33:3656// An interceptor that records count of fetches and client hint headers for
57// requests to https://foo.com/non-existing-image.jpg.
Jay Civelli1ff872d2018-03-09 21:52:1658class ThirdPartyURLLoaderInterceptor {
Tarun Bansal229647bd002018-02-27 17:33:3659 public:
Jay Civelli1ff872d2018-03-09 21:52:1660 explicit ThirdPartyURLLoaderInterceptor(const GURL intercepted_url)
61 : intercepted_url_(intercepted_url),
62 interceptor_(base::BindRepeating(
63 &ThirdPartyURLLoaderInterceptor::InterceptURLRequest,
64 base::Unretained(this))) {}
Tarun Bansal229647bd002018-02-27 17:33:3665
Jay Civelli1ff872d2018-03-09 21:52:1666 ~ThirdPartyURLLoaderInterceptor() = default;
Tarun Bansal229647bd002018-02-27 17:33:3667
68 size_t request_count_seen() const { return request_count_seen_; }
69
70 size_t client_hints_count_seen() const { return client_hints_count_seen_; }
71
72 private:
Jay Civelli1ff872d2018-03-09 21:52:1673 bool InterceptURLRequest(
74 content::URLLoaderInterceptor::RequestParams* params) {
75 if (params->url_request.url != intercepted_url_)
76 return false;
Tarun Bansal229647bd002018-02-27 17:33:3677
Jay Civelli1ff872d2018-03-09 21:52:1678 request_count_seen_++;
Mike West14c11102019-02-04 16:16:4779 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Tarun Bansalf9cf9892018-04-06 04:38:0180 if (params->url_request.headers.HasHeader(
81 blink::kClientHintsHeaderMapping[i])) {
82 client_hints_count_seen_++;
83 }
Tarun Bansal5c28afb2018-03-17 02:55:2084 }
Jay Civelli1ff872d2018-03-09 21:52:1685 return false;
86 }
Tarun Bansal229647bd002018-02-27 17:33:3687
Jay Civelli1ff872d2018-03-09 21:52:1688 GURL intercepted_url_;
89
90 size_t request_count_seen_ = 0u;
91
92 size_t client_hints_count_seen_ = 0u;
93
94 content::URLLoaderInterceptor interceptor_;
95
96 DISALLOW_COPY_AND_ASSIGN(ThirdPartyURLLoaderInterceptor);
Tarun Bansal229647bd002018-02-27 17:33:3697};
98
Tarun Bansal62efba12018-05-04 22:58:3599// Returns true only if |header_value| satisfies ABNF: 1*DIGIT [ "." 1*DIGIT ]
100bool IsSimilarToDoubleABNF(const std::string& header_value) {
101 if (header_value.empty())
102 return false;
103 char first_char = header_value.at(0);
104 if (!isdigit(first_char))
105 return false;
106
107 bool period_found = false;
108 bool digit_found_after_period = false;
109 for (char ch : header_value) {
110 if (isdigit(ch)) {
111 if (period_found) {
112 digit_found_after_period = true;
113 }
114 continue;
115 }
116 if (ch == '.') {
117 if (period_found)
118 return false;
119 period_found = true;
120 continue;
121 }
122 return false;
123 }
124 if (period_found)
125 return digit_found_after_period;
126 return true;
127}
128
129// Returns true only if |header_value| satisfies ABNF: 1*DIGIT
130bool IsSimilarToIntABNF(const std::string& header_value) {
131 if (header_value.empty())
132 return false;
133
134 for (char ch : header_value) {
135 if (!isdigit(ch))
136 return false;
137 }
138 return true;
139}
140
Tarun Bansal229647bd002018-02-27 17:33:36141} // namespace
Tarun Bansal0b8b7afd2017-08-25 03:52:16142
Tarun Bansal9a7051f2018-07-10 18:30:05143class ClientHintsBrowserTest : public InProcessBrowserTest,
144 public testing::WithParamInterface<bool> {
Tarun Bansal0b8b7afd2017-08-25 03:52:16145 public:
146 ClientHintsBrowserTest()
Mikel Astiz2de748d2019-11-16 10:39:36147 : http_server_(net::EmbeddedTestServer::TYPE_HTTP),
Tarun Bansal3b330b02017-11-09 19:03:14148 https_server_(net::EmbeddedTestServer::TYPE_HTTPS),
Tarun Bansal345418632018-06-29 11:07:04149 https_cross_origin_server_(net::EmbeddedTestServer::TYPE_HTTPS),
Tarun Bansal229647bd002018-02-27 17:33:36150 expect_client_hints_on_main_frame_(false),
151 expect_client_hints_on_subresources_(false),
Mike West2fddeeb72019-02-15 11:29:48152 count_user_agent_hint_headers_seen_(0),
Maks Orlovich5dcc99c2020-02-13 19:07:46153 count_ua_mobile_client_hints_headers_seen_(0),
Tarun Bansal229647bd002018-02-27 17:33:36154 count_client_hints_headers_seen_(0),
155 request_interceptor_(nullptr) {
Tarun Bansal3b330b02017-11-09 19:03:14156 http_server_.ServeFilesFromSourceDirectory("chrome/test/data/client_hints");
Tarun Bansal0b8b7afd2017-08-25 03:52:16157 https_server_.ServeFilesFromSourceDirectory(
158 "chrome/test/data/client_hints");
Tarun Bansal345418632018-06-29 11:07:04159 https_cross_origin_server_.ServeFilesFromSourceDirectory(
160 "chrome/test/data/client_hints");
Tarun Bansal1965b042017-09-07 04:59:19161
Tarun Bansal3b330b02017-11-09 19:03:14162 http_server_.RegisterRequestMonitor(
Tarun Bansal345418632018-06-29 11:07:04163 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
164 base::Unretained(this)));
Tarun Bansal1965b042017-09-07 04:59:19165 https_server_.RegisterRequestMonitor(
Tarun Bansal345418632018-06-29 11:07:04166 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
167 base::Unretained(this)));
168 https_cross_origin_server_.RegisterRequestMonitor(
169 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
170 base::Unretained(this)));
Tarun Bansal293a7b6c2018-12-05 17:41:12171 https_cross_origin_server_.RegisterRequestHandler(
172 base::BindRepeating(&ClientHintsBrowserTest::RequestHandlerToRedirect,
173 base::Unretained(this)));
Tarun Bansal345418632018-06-29 11:07:04174 https_server_.RegisterRequestHandler(base::BindRepeating(
175 &ClientHintsBrowserTest::RequestHandlerToFetchCrossOriginIframe,
176 base::Unretained(this)));
Tarun Bansal1965b042017-09-07 04:59:19177
Tarun Bansal3b330b02017-11-09 19:03:14178 EXPECT_TRUE(http_server_.Start());
Tarun Bansal0b8b7afd2017-08-25 03:52:16179 EXPECT_TRUE(https_server_.Start());
Tarun Bansal345418632018-06-29 11:07:04180 EXPECT_TRUE(https_cross_origin_server_.Start());
181
182 EXPECT_NE(https_server_.base_url(), https_cross_origin_server_.base_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:16183
Tarun Bansal3b330b02017-11-09 19:03:14184 accept_ch_with_lifetime_http_local_url_ =
185 http_server_.GetURL("/accept_ch_with_lifetime.html");
Tarun Bansal9a7051f2018-07-10 18:30:05186 http_equiv_accept_ch_with_lifetime_http_local_url_ =
187 http_server_.GetURL("/http_equiv_accept_ch_with_lifetime.html");
Tarun Bansal3b330b02017-11-09 19:03:14188 EXPECT_TRUE(accept_ch_with_lifetime_http_local_url_.SchemeIsHTTPOrHTTPS());
189 EXPECT_FALSE(
190 accept_ch_with_lifetime_http_local_url_.SchemeIsCryptographic());
191
Tarun Bansal1965b042017-09-07 04:59:19192 accept_ch_with_lifetime_url_ =
193 https_server_.GetURL("/accept_ch_with_lifetime.html");
Tarun Bansal73502f92019-04-16 21:21:19194 accept_ch_with_short_lifetime_url_ =
195 https_server_.GetURL("/accept_ch_with_short_lifetime.html");
Tarun Bansal0b8b7afd2017-08-25 03:52:16196
Tarun Bansal1965b042017-09-07 04:59:19197 accept_ch_without_lifetime_url_ =
198 https_server_.GetURL("/accept_ch_without_lifetime.html");
199 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsHTTPOrHTTPS());
200 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal9a7051f2018-07-10 18:30:05201 http_equiv_accept_ch_without_lifetime_url_ =
202 https_server_.GetURL("/http_equiv_accept_ch_without_lifetime.html");
Tarun Bansal1965b042017-09-07 04:59:19203
204 without_accept_ch_without_lifetime_url_ =
205 https_server_.GetURL("/without_accept_ch_without_lifetime.html");
206 EXPECT_TRUE(without_accept_ch_without_lifetime_url_.SchemeIsHTTPOrHTTPS());
207 EXPECT_TRUE(
208 without_accept_ch_without_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal3b330b02017-11-09 19:03:14209
210 without_accept_ch_without_lifetime_local_url_ =
211 http_server_.GetURL("/without_accept_ch_without_lifetime.html");
212 EXPECT_TRUE(
213 without_accept_ch_without_lifetime_local_url_.SchemeIsHTTPOrHTTPS());
214 EXPECT_FALSE(
215 without_accept_ch_without_lifetime_local_url_.SchemeIsCryptographic());
Tarun Bansaladd5e1812018-02-09 19:07:58216
217 without_accept_ch_without_lifetime_img_localhost_ = https_server_.GetURL(
218 "/without_accept_ch_without_lifetime_img_localhost.html");
219 without_accept_ch_without_lifetime_img_foo_com_ = https_server_.GetURL(
220 "/without_accept_ch_without_lifetime_img_foo_com.html");
221 accept_ch_without_lifetime_with_iframe_url_ =
222 https_server_.GetURL("/accept_ch_without_lifetime_with_iframe.html");
Tarun Bansal9a7051f2018-07-10 18:30:05223 http_equiv_accept_ch_without_lifetime_with_iframe_url_ =
224 https_server_.GetURL(
225 "/http_equiv_accept_ch_without_lifetime_with_iframe.html");
Tarun Bansal62cc3542018-06-27 23:53:30226 accept_ch_without_lifetime_with_subresource_url_ = https_server_.GetURL(
227 "/accept_ch_without_lifetime_with_subresource.html");
Tarun Bansal9a7051f2018-07-10 18:30:05228 http_equiv_accept_ch_without_lifetime_with_subresource_url_ =
229 https_server_.GetURL(
230 "/http_equiv_accept_ch_without_lifetime_with_subresource.html");
Tarun Bansal62cc3542018-06-27 23:53:30231 accept_ch_without_lifetime_with_subresource_iframe_url_ =
232 https_server_.GetURL(
233 "/accept_ch_without_lifetime_with_subresource_iframe.html");
Tarun Bansal9a7051f2018-07-10 18:30:05234 http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_ =
235 https_server_.GetURL(
236 "/http_equiv_accept_ch_without_lifetime_with_subresource_iframe."
237 "html");
Tarun Bansal229647bd002018-02-27 17:33:36238 accept_ch_without_lifetime_img_localhost_ =
239 https_server_.GetURL("/accept_ch_without_lifetime_img_localhost.html");
Tarun Bansal9a7051f2018-07-10 18:30:05240 http_equiv_accept_ch_without_lifetime_img_localhost_ = https_server_.GetURL(
241 "/http_equiv_accept_ch_without_lifetime_img_localhost.html");
242 http_equiv_accept_ch_with_lifetime_ =
243 https_server_.GetURL("/http_equiv_accept_ch_with_lifetime.html");
Tarun Bansal293a7b6c2018-12-05 17:41:12244
245 redirect_url_ = https_cross_origin_server_.GetURL("/redirect.html");
Maks Orlovich7a588d82020-05-06 15:17:24246
247 accept_ch_empty_ = https_server_.GetURL("/accept_ch_empty.html");
248 http_equiv_accept_ch_merge_ =
249 https_server_.GetURL("/http_equiv_accept_ch_merge.html");
Tarun Bansal0b8b7afd2017-08-25 03:52:16250 }
251
252 ~ClientHintsBrowserTest() override {}
253
Mike West2fddeeb72019-02-15 11:29:48254 virtual std::unique_ptr<base::FeatureList> EnabledFeatures() {
255 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
256 feature_list->InitializeFromCommandLine("UserAgentClientHint", "");
257 return feature_list;
258 }
259
260 void SetUp() override {
261 scoped_feature_list_.InitWithFeatureList(EnabledFeatures());
262 InProcessBrowserTest::SetUp();
263 }
264
Tarun Bansal0b8b7afd2017-08-25 03:52:16265 void SetUpOnMainThread() override {
Tarun Bansal229647bd002018-02-27 17:33:36266 host_resolver()->AddRule("*", "127.0.0.1");
Tarun Bansal229647bd002018-02-27 17:33:36267
Jay Civelli1ff872d2018-03-09 21:52:16268 request_interceptor_ = std::make_unique<ThirdPartyURLLoaderInterceptor>(
269 GURL("https://foo.com/non-existing-image.jpg"));
Tarun Bansal229647bd002018-02-27 17:33:36270 base::RunLoop().RunUntilIdle();
Tarun Bansal0b8b7afd2017-08-25 03:52:16271 }
272
Jay Civelli1ff872d2018-03-09 21:52:16273 void TearDownOnMainThread() override { request_interceptor_.reset(); }
274
Tarun Bansal0b8b7afd2017-08-25 03:52:16275 void SetUpCommandLine(base::CommandLine* cmd) override {
Tarun Bansal7f3fe8c2018-04-06 22:37:47276 cmd->AppendSwitchASCII(network::switches::kForceEffectiveConnectionType,
277 net::kEffectiveConnectionType2G);
Mike West14c11102019-02-04 16:16:47278 cmd->AppendSwitchASCII(switches::kEnableBlinkFeatures,
279 "LangClientHintHeader");
Tarun Bansal0b8b7afd2017-08-25 03:52:16280 }
281
Tarun Bansal229647bd002018-02-27 17:33:36282 void SetClientHintExpectationsOnMainFrame(bool expect_client_hints) {
283 expect_client_hints_on_main_frame_ = expect_client_hints;
Tarun Bansal1965b042017-09-07 04:59:19284 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16285
Tarun Bansal229647bd002018-02-27 17:33:36286 void SetClientHintExpectationsOnSubresources(bool expect_client_hints) {
Callum May1d939742020-03-02 17:51:30287 base::AutoLock lock(expect_client_hints_on_subresources_lock_);
Tarun Bansal229647bd002018-02-27 17:33:36288 expect_client_hints_on_subresources_ = expect_client_hints;
Tarun Bansala61f0f62017-10-24 23:53:05289 }
290
Callum May1d939742020-03-02 17:51:30291 bool expect_client_hints_on_subresources() {
292 base::AutoLock lock(expect_client_hints_on_subresources_lock_);
293 return expect_client_hints_on_subresources_;
294 }
295
Tarun Bansalc211d8b2018-03-19 19:21:58296 // Verify that the user is not notified that cookies or JavaScript were
297 // blocked on the webpage due to the checks done by client hints.
298 void VerifyContentSettingsNotNotified() const {
299 content::WebContents* web_contents =
300 browser()->tab_strip_model()->GetActiveWebContents();
Clark DuVall84a33d612020-04-17 16:01:00301 EXPECT_FALSE(content_settings::TabSpecificContentSettings::FromWebContents(
302 web_contents)
Darin Fisher42f5e7d2019-10-30 07:15:45303 ->IsContentBlocked(ContentSettingsType::COOKIES));
Tarun Bansalc211d8b2018-03-19 19:21:58304
Clark DuVall84a33d612020-04-17 16:01:00305 EXPECT_FALSE(content_settings::TabSpecificContentSettings::FromWebContents(
306 web_contents)
Darin Fisher42f5e7d2019-10-30 07:15:45307 ->IsContentBlocked(ContentSettingsType::JAVASCRIPT));
Tarun Bansalc211d8b2018-03-19 19:21:58308 }
309
Tarun Bansalbef6d652018-10-02 18:41:01310 void SetExpectedEffectiveConnectionType(
311 net::EffectiveConnectionType effective_connection_type) {
312 expected_ect = effective_connection_type;
313 }
314
Changwan Ryu434c3a32019-07-30 23:42:58315 void SetJsEnabledForActiveView(bool enabled) {
316 content::RenderViewHost* view = browser()
317 ->tab_strip_model()
318 ->GetActiveWebContents()
319 ->GetRenderViewHost();
320 content::WebPreferences prefs = view->GetWebkitPreferences();
321 prefs.javascript_enabled = enabled;
322 view->UpdateWebkitPreferences(prefs);
323 }
324
Maks Orlovich7227ce0d2020-02-28 17:13:16325 void TestProfilesIndependent(Browser* browser_a, Browser* browser_b);
326
Tarun Bansal3b330b02017-11-09 19:03:14327 const GURL& accept_ch_with_lifetime_http_local_url() const {
328 return accept_ch_with_lifetime_http_local_url_;
329 }
Tarun Bansal9a7051f2018-07-10 18:30:05330 const GURL& http_equiv_accept_ch_with_lifetime_http_local_url() const {
331 return http_equiv_accept_ch_with_lifetime_http_local_url_;
332 }
Tarun Bansal3b330b02017-11-09 19:03:14333
Tarun Bansal1965b042017-09-07 04:59:19334 // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
335 // headers.
336 const GURL& accept_ch_with_lifetime_url() const {
337 return accept_ch_with_lifetime_url_;
338 }
Tarun Bansal9a7051f2018-07-10 18:30:05339 const GURL& http_equiv_accept_ch_with_lifetime() {
340 return http_equiv_accept_ch_with_lifetime_;
341 }
Tarun Bansal1965b042017-09-07 04:59:19342
Tarun Bansal73502f92019-04-16 21:21:19343 // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
344 // headers. The Accept-CH-Lifetime duration is set very short to 1 second.
345 const GURL& accept_ch_with_short_lifetime() const {
346 return accept_ch_with_short_lifetime_url_;
347 }
348
Tarun Bansal1965b042017-09-07 04:59:19349 // A URL whose response headers include only Accept-CH header.
350 const GURL& accept_ch_without_lifetime_url() const {
351 return accept_ch_without_lifetime_url_;
352 }
Tarun Bansal9a7051f2018-07-10 18:30:05353 const GURL& http_equiv_accept_ch_without_lifetime_url() const {
354 return http_equiv_accept_ch_without_lifetime_url_;
355 }
Tarun Bansal1965b042017-09-07 04:59:19356
357 // A URL whose response headers do not include either Accept-CH or
358 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
359 const GURL& without_accept_ch_without_lifetime_url() const {
360 return without_accept_ch_without_lifetime_url_;
361 }
362
Tarun Bansal3b330b02017-11-09 19:03:14363 // A URL whose response headers do not include either Accept-CH or
364 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
365 const GURL& without_accept_ch_without_lifetime_local_url() const {
366 return without_accept_ch_without_lifetime_local_url_;
367 }
368
Tarun Bansaladd5e1812018-02-09 19:07:58369 // A URL whose response headers do not include either Accept-CH or
370 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
371 // from localhost.
372 const GURL& without_accept_ch_without_lifetime_img_localhost() const {
373 return without_accept_ch_without_lifetime_img_localhost_;
374 }
375
376 // A URL whose response headers do not include either Accept-CH or
377 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
378 // from foo.com.
379 const GURL& without_accept_ch_without_lifetime_img_foo_com() const {
380 return without_accept_ch_without_lifetime_img_foo_com_;
381 }
382
383 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
384 // headers. The response loads accept_ch_with_lifetime_url() in an iframe.
385 const GURL& accept_ch_without_lifetime_with_iframe_url() const {
386 return accept_ch_without_lifetime_with_iframe_url_;
387 }
Tarun Bansal9a7051f2018-07-10 18:30:05388 const GURL& http_equiv_accept_ch_without_lifetime_with_iframe_url() const {
389 return http_equiv_accept_ch_without_lifetime_with_iframe_url_;
390 }
Tarun Bansaladd5e1812018-02-09 19:07:58391
Tarun Bansal62cc3542018-06-27 23:53:30392 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
393 // headers. The response loads accept_ch_with_lifetime_url() as a subresource
394 // in the main frame.
395 const GURL& accept_ch_without_lifetime_with_subresource_url() const {
396 return accept_ch_without_lifetime_with_subresource_url_;
397 }
Tarun Bansal9a7051f2018-07-10 18:30:05398 const GURL& http_equiv_accept_ch_without_lifetime_with_subresource_url()
399 const {
400 return http_equiv_accept_ch_without_lifetime_with_subresource_url_;
401 }
Tarun Bansal62cc3542018-06-27 23:53:30402
403 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
Tarun Bansal9a7051f2018-07-10 18:30:05404 // headers. The response loads accept_ch_with_lifetime_url() or
405 // http_equiv_accept_ch_with_lifetime_url() as a subresource in the iframe.
Tarun Bansal62cc3542018-06-27 23:53:30406 const GURL& accept_ch_without_lifetime_with_subresource_iframe_url() const {
407 return accept_ch_without_lifetime_with_subresource_iframe_url_;
408 }
Tarun Bansal9a7051f2018-07-10 18:30:05409 const GURL&
410 http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url() const {
411 return http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_;
412 }
Tarun Bansal62cc3542018-06-27 23:53:30413
Tarun Bansal9a7051f2018-07-10 18:30:05414 // A URL whose response includes only Accept-CH header. Navigating to
Tarun Bansal229647bd002018-02-27 17:33:36415 // this URL also fetches two images: One from the localhost, and one from
416 // foo.com.
417 const GURL& accept_ch_without_lifetime_img_localhost() const {
418 return accept_ch_without_lifetime_img_localhost_;
419 }
Tarun Bansal9a7051f2018-07-10 18:30:05420 const GURL& http_equiv_accept_ch_without_lifetime_img_localhost() const {
421 return http_equiv_accept_ch_without_lifetime_img_localhost_;
422 }
Tarun Bansal229647bd002018-02-27 17:33:36423
Tarun Bansal293a7b6c2018-12-05 17:41:12424 const GURL& redirect_url() const { return redirect_url_; }
425
Maks Orlovich7a588d82020-05-06 15:17:24426 // A URL to a page with a response containing an empty accept_ch header.
427 const GURL& accept_ch_empty() const { return accept_ch_empty_; }
428
429 // A page where some hints are in accept-ch header, some in http-equiv.
430 const GURL& http_equiv_accept_ch_merge() const {
431 return http_equiv_accept_ch_merge_;
432 }
433
Mike West2fddeeb72019-02-15 11:29:48434 size_t count_user_agent_hint_headers_seen() const {
Callum May7d88ff3e2019-11-12 18:21:46435 base::AutoLock lock(count_headers_lock_);
Mike West2fddeeb72019-02-15 11:29:48436 return count_user_agent_hint_headers_seen_;
437 }
438
Maks Orlovich5dcc99c2020-02-13 19:07:46439 size_t count_ua_mobile_client_hints_headers_seen() const {
440 base::AutoLock lock(count_headers_lock_);
441 return count_ua_mobile_client_hints_headers_seen_;
442 }
443
Tarun Bansal1965b042017-09-07 04:59:19444 size_t count_client_hints_headers_seen() const {
Callum May7d88ff3e2019-11-12 18:21:46445 base::AutoLock lock(count_headers_lock_);
Tarun Bansal1965b042017-09-07 04:59:19446 return count_client_hints_headers_seen_;
447 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16448
Tarun Bansal229647bd002018-02-27 17:33:36449 size_t third_party_request_count_seen() const {
450 return request_interceptor_->request_count_seen();
451 }
452
453 size_t third_party_client_hints_count_seen() const {
454 return request_interceptor_->client_hints_count_seen();
455 }
456
Mike Weste555be862019-02-20 16:17:30457 const std::string& main_frame_ua_observed() const {
458 return main_frame_ua_observed_;
459 }
460
Yoav Weissd33bacb2020-03-12 06:42:21461 const std::string& main_frame_ua_full_version_observed() const {
462 return main_frame_ua_full_version_observed_;
463 }
464
Maks Orlovich73f374d2020-04-02 12:46:13465 const std::string& main_frame_ua_mobile_observed() const {
466 return main_frame_ua_mobile_observed_;
467 }
468
469 const std::string& main_frame_ua_platform_observed() const {
470 return main_frame_ua_platform_observed_;
471 }
472
Tarun Bansalea0d8262018-05-21 16:11:50473 base::test::ScopedFeatureList scoped_feature_list_;
474
Tarun Bansal345418632018-06-29 11:07:04475 std::string intercept_iframe_resource_;
Tarun Bansal9a7051f2018-07-10 18:30:05476 bool intercept_to_http_equiv_iframe_ = false;
Callum May7d88ff3e2019-11-12 18:21:46477 mutable base::Lock count_headers_lock_;
Tarun Bansal345418632018-06-29 11:07:04478
Tarun Bansal0b8b7afd2017-08-25 03:52:16479 private:
Tarun Bansal345418632018-06-29 11:07:04480 // Intercepts only the main frame requests that contain
Tarun Bansal293a7b6c2018-12-05 17:41:12481 // "redirect" in the resource path. The intercepted requests
482 // are served an HTML file that fetches an iframe from a cross-origin HTTPS
483 // server.
484 std::unique_ptr<net::test_server::HttpResponse> RequestHandlerToRedirect(
485 const net::test_server::HttpRequest& request) {
486 // Check if it's a main frame request.
487 if (request.relative_url.find(".html") == std::string::npos)
488 return nullptr;
489
490 if (request.GetURL().spec().find("redirect") == std::string::npos)
491 return nullptr;
492
493 std::unique_ptr<net::test_server::BasicHttpResponse> response;
494 response.reset(new net::test_server::BasicHttpResponse);
495 response->set_code(net::HTTP_FOUND);
496 response->AddCustomHeader("Location",
497 without_accept_ch_without_lifetime_url().spec());
498 return std::move(response);
499 }
500
501 // Intercepts only the main frame requests that contain
Tarun Bansal345418632018-06-29 11:07:04502 // |intercept_iframe_resource_| in the resource path. The intercepted requests
503 // are served an HTML file that fetches an iframe from a cross-origin HTTPS
504 // server.
505 std::unique_ptr<net::test_server::HttpResponse>
506 RequestHandlerToFetchCrossOriginIframe(
507 const net::test_server::HttpRequest& request) {
508 if (intercept_iframe_resource_.empty())
509 return nullptr;
510
511 // Check if it's a main frame request.
512 if (request.relative_url.find(".html") == std::string::npos)
513 return nullptr;
514
515 if (request.relative_url.find(intercept_iframe_resource_) ==
516 std::string::npos) {
517 return nullptr;
518 }
519
520 const std::string iframe_url =
Tarun Bansal9a7051f2018-07-10 18:30:05521 intercept_to_http_equiv_iframe_
522 ? https_cross_origin_server_
523 .GetURL("/http_equiv_accept_ch_with_lifetime.html")
524 .spec()
525 : https_cross_origin_server_.GetURL("/accept_ch_with_lifetime.html")
526 .spec();
Tarun Bansal345418632018-06-29 11:07:04527
528 std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
529 new net::test_server::BasicHttpResponse());
530 http_response->set_code(net::HTTP_OK);
531 http_response->set_content_type("text/html");
532 http_response->set_content(
533 "<html>"
534 "<link rel='icon' href='data:;base64,='><head></head>"
535 "Empty file which uses link-rel to disable favicon fetches. "
536 "<iframe src='" +
537 iframe_url + "'></iframe></html>");
538
539 return std::move(http_response);
540 }
541
Maks Orlovich73f374d2020-04-02 12:46:13542 static std::string UpdateHeaderObservation(
543 const net::test_server::HttpRequest& request,
544 const std::string& header) {
545 if (request.headers.find(header) != request.headers.end())
546 return request.headers.find(header)->second;
547 else
548 return "";
549 }
550
Tarun Bansal1965b042017-09-07 04:59:19551 // Called by |https_server_|.
552 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
Tarun Bansal6bf54302017-10-02 07:39:14553 bool is_main_frame_navigation =
554 request.GetURL().spec().find(".html") != std::string::npos;
555
Tarun Bansal293a7b6c2018-12-05 17:41:12556 if (is_main_frame_navigation &&
557 request.GetURL().spec().find("redirect") != std::string::npos) {
558 return;
559 }
560
Tarun Bansal229647bd002018-02-27 17:33:36561 if (is_main_frame_navigation) {
Maks Orlovich73f374d2020-04-02 12:46:13562 main_frame_ua_observed_ = UpdateHeaderObservation(request, "sec-ch-ua");
563 main_frame_ua_full_version_observed_ =
564 UpdateHeaderObservation(request, "sec-ch-ua-full-version");
565 main_frame_ua_mobile_observed_ =
566 UpdateHeaderObservation(request, "sec-ch-ua-mobile");
567 main_frame_ua_platform_observed_ =
568 UpdateHeaderObservation(request, "sec-ch-ua-platform");
Yoav Weissd33bacb2020-03-12 06:42:21569
Tarun Bansalf9cf9892018-04-06 04:38:01570 VerifyClientHintsReceived(expect_client_hints_on_main_frame_, request);
Tarun Bansal5c28afb2018-03-17 02:55:20571 if (expect_client_hints_on_main_frame_) {
572 double value = 0.0;
573 EXPECT_TRUE(base::StringToDouble(
574 request.headers.find("device-memory")->second, &value));
575 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35576 EXPECT_TRUE(IsSimilarToDoubleABNF(
577 request.headers.find("device-memory")->second));
Tarun Bansal44ad96882018-03-28 17:47:42578 main_frame_device_memory_observed_ = value;
Tarun Bansal5c28afb2018-03-17 02:55:20579
580 EXPECT_TRUE(
581 base::StringToDouble(request.headers.find("dpr")->second, &value));
582 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35583 EXPECT_TRUE(IsSimilarToDoubleABNF(request.headers.find("dpr")->second));
Tarun Bansal44ad96882018-03-28 17:47:42584 main_frame_dpr_observed_ = value;
585
Tarun Bansal5c28afb2018-03-17 02:55:20586 EXPECT_TRUE(base::StringToDouble(
587 request.headers.find("viewport-width")->second, &value));
Tarun Bansal62efba12018-05-04 22:58:35588 EXPECT_TRUE(
589 IsSimilarToIntABNF(request.headers.find("viewport-width")->second));
Tarun Bansal79df868e2018-03-20 23:01:36590#if !defined(OS_ANDROID)
Tarun Bansal5c28afb2018-03-17 02:55:20591 EXPECT_LT(0.0, value);
Tarun Bansal79df868e2018-03-20 23:01:36592#else
593 EXPECT_EQ(980, value);
Tarun Bansal5c28afb2018-03-17 02:55:20594#endif
Tarun Bansal44ad96882018-03-28 17:47:42595 main_frame_viewport_width_observed_ = value;
Mike Weste555be862019-02-20 16:17:30596
Tarun Bansal7f3fe8c2018-04-06 22:37:47597 VerifyNetworkQualityClientHints(request);
Tarun Bansal5c28afb2018-03-17 02:55:20598 }
Tarun Bansala61f0f62017-10-24 23:53:05599 }
Tarun Bansal6bf54302017-10-02 07:39:14600
Tarun Bansal229647bd002018-02-27 17:33:36601 if (!is_main_frame_navigation) {
Callum May1d939742020-03-02 17:51:30602 VerifyClientHintsReceived(expect_client_hints_on_subresources(), request);
Tarun Bansal5c28afb2018-03-17 02:55:20603
Callum May1d939742020-03-02 17:51:30604 if (expect_client_hints_on_subresources()) {
Tarun Bansal5c28afb2018-03-17 02:55:20605 double value = 0.0;
606 EXPECT_TRUE(base::StringToDouble(
607 request.headers.find("device-memory")->second, &value));
608 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35609 EXPECT_TRUE(IsSimilarToDoubleABNF(
610 request.headers.find("device-memory")->second));
Tarun Bansal44ad96882018-03-28 17:47:42611 if (main_frame_device_memory_observed_ > 0) {
612 EXPECT_EQ(main_frame_device_memory_observed_, value);
613 }
Tarun Bansal5c28afb2018-03-17 02:55:20614
615 EXPECT_TRUE(
616 base::StringToDouble(request.headers.find("dpr")->second, &value));
617 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35618 EXPECT_TRUE(IsSimilarToDoubleABNF(request.headers.find("dpr")->second));
Tarun Bansal44ad96882018-03-28 17:47:42619 if (main_frame_dpr_observed_ > 0) {
620 EXPECT_EQ(main_frame_dpr_observed_, value);
621 }
Tarun Bansal5c28afb2018-03-17 02:55:20622
623 EXPECT_TRUE(base::StringToDouble(
624 request.headers.find("viewport-width")->second, &value));
Tarun Bansal62efba12018-05-04 22:58:35625 EXPECT_TRUE(
626 IsSimilarToIntABNF(request.headers.find("viewport-width")->second));
Tarun Bansal79df868e2018-03-20 23:01:36627#if !defined(OS_ANDROID)
Tarun Bansal5c28afb2018-03-17 02:55:20628 EXPECT_LT(0.0, value);
Tarun Bansal79df868e2018-03-20 23:01:36629#else
630 EXPECT_EQ(980, value);
631#endif
Tarun Bansal44ad96882018-03-28 17:47:42632#if defined(OS_ANDROID)
633 // TODO(tbansal): https://crbug.com/825892: Viewport width on main
634 // frame requests may be incorrect when the Chrome window is not
635 // maximized.
636 if (main_frame_viewport_width_observed_ > 0) {
637 EXPECT_EQ(main_frame_viewport_width_observed_, value);
638 }
639#endif
Tarun Bansal7f3fe8c2018-04-06 22:37:47640 VerifyNetworkQualityClientHints(request);
Tarun Bansal5c28afb2018-03-17 02:55:20641 }
Tarun Bansala61f0f62017-10-24 23:53:05642 }
Tarun Bansal6bf54302017-10-02 07:39:14643
Mike West14c11102019-02-04 16:16:47644 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Jan Wilken Dörriea8cb56302019-06-06 18:59:36645 if (base::Contains(request.headers,
646 blink::kClientHintsHeaderMapping[i])) {
Callum May7d88ff3e2019-11-12 18:21:46647 base::AutoLock lock(count_headers_lock_);
Mike West2fddeeb72019-02-15 11:29:48648 // The user agent hint is special:
649 if (std::string(blink::kClientHintsHeaderMapping[i]) == "sec-ch-ua") {
650 count_user_agent_hint_headers_seen_++;
Maks Orlovich5dcc99c2020-02-13 19:07:46651 } else if (std::string(blink::kClientHintsHeaderMapping[i]) ==
652 "sec-ch-ua-mobile") {
653 count_ua_mobile_client_hints_headers_seen_++;
Mike West2fddeeb72019-02-15 11:29:48654 } else {
655 count_client_hints_headers_seen_++;
656 }
Tarun Bansalf9cf9892018-04-06 04:38:01657 }
658 }
659 }
Tarun Bansal1965b042017-09-07 04:59:19660
Tarun Bansalf9cf9892018-04-06 04:38:01661 void VerifyClientHintsReceived(bool expect_client_hints,
662 const net::test_server::HttpRequest& request) {
Mike West14c11102019-02-04 16:16:47663 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
664 SCOPED_TRACE(testing::Message()
665 << std::string(blink::kClientHintsHeaderMapping[i]));
Tarun Bansalf9cf9892018-04-06 04:38:01666 // Resource width client hint is only attached on image subresources.
667 if (std::string(blink::kClientHintsHeaderMapping[i]) == "width") {
668 continue;
669 }
Mike West2fddeeb72019-02-15 11:29:48670
Maks Orlovich5dcc99c2020-02-13 19:07:46671 // `Sec-CH-UA` and `Sec-CH-UA-Mobile` is attached on all requests.
672 if (std::string(blink::kClientHintsHeaderMapping[i]) == "sec-ch-ua" ||
673 std::string(blink::kClientHintsHeaderMapping[i]) ==
674 "sec-ch-ua-mobile") {
Mike West2fddeeb72019-02-15 11:29:48675 continue;
676 }
677
Jan Wilken Dörriea8cb56302019-06-06 18:59:36678 EXPECT_EQ(
679 expect_client_hints,
680 base::Contains(request.headers, blink::kClientHintsHeaderMapping[i]));
Tarun Bansalf9cf9892018-04-06 04:38:01681 }
Tarun Bansal1965b042017-09-07 04:59:19682 }
683
Tarun Bansal7f3fe8c2018-04-06 22:37:47684 void VerifyNetworkQualityClientHints(
685 const net::test_server::HttpRequest& request) const {
686 // Effective connection type is forced to 2G using command line in these
687 // tests.
Tarun Bansal509a8dd2018-04-10 17:19:16688 int rtt_value = 0.0;
Tarun Bansal7f3fe8c2018-04-06 22:37:47689 EXPECT_TRUE(
Tarun Bansal509a8dd2018-04-10 17:19:16690 base::StringToInt(request.headers.find("rtt")->second, &rtt_value));
691 EXPECT_LE(0, rtt_value);
Tarun Bansal62efba12018-05-04 22:58:35692 EXPECT_TRUE(IsSimilarToIntABNF(request.headers.find("rtt")->second));
Tarun Bansal509a8dd2018-04-10 17:19:16693 // Verify that RTT value is a multiple of 50 milliseconds.
694 EXPECT_EQ(0, rtt_value % 50);
Tarun Bansalbef6d652018-10-02 18:41:01695 EXPECT_GE(expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G ? 3000 : 500,
696 rtt_value);
Tarun Bansal7f3fe8c2018-04-06 22:37:47697
Tarun Bansal509a8dd2018-04-10 17:19:16698 double mbps_value = 0.0;
699 EXPECT_TRUE(base::StringToDouble(request.headers.find("downlink")->second,
700 &mbps_value));
701 EXPECT_LE(0, mbps_value);
Tarun Bansal62efba12018-05-04 22:58:35702 EXPECT_TRUE(
703 IsSimilarToDoubleABNF(request.headers.find("downlink")->second));
Tarun Bansal509a8dd2018-04-10 17:19:16704 // Verify that the mbps value is a multiple of 0.050 mbps.
705 // Allow for small amount of noise due to double to integer conversions.
706 EXPECT_NEAR(0, (static_cast<int>(mbps_value * 1000)) % 50, 1);
707 EXPECT_GE(10.0, mbps_value);
Tarun Bansal7f3fe8c2018-04-06 22:37:47708
709 EXPECT_FALSE(request.headers.find("ect")->second.empty());
Tarun Bansalceab9592018-05-01 18:57:35710
711 // TODO(tbansal): https://crbug.com/819244: When network servicification is
Tarun Bansal5ac533542018-08-10 19:45:52712 // enabled, the renderer processes do not receive notifications on
713 // change in the network quality. Hence, the network quality client hints
714 // are not set to the correct value on subresources.
715 bool is_main_frame_navigation =
716 request.GetURL().spec().find(".html") != std::string::npos;
John Abd-El-Malek67facbe82019-06-06 22:37:08717 if (is_main_frame_navigation) {
Tarun Bansalceab9592018-05-01 18:57:35718 // Effective connection type is forced to 2G using command line in these
719 // tests. RTT is expected to be 1800 msec but leave some gap to account
720 // for added noise and randomization.
Tarun Bansalbef6d652018-10-02 18:41:01721 if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G) {
722 EXPECT_NEAR(1800, rtt_value, 360);
723 } else if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_3G) {
724 EXPECT_NEAR(450, rtt_value, 90);
725 } else {
726 NOTREACHED();
727 }
Tarun Bansalceab9592018-05-01 18:57:35728
729 // Effective connection type is forced to 2G using command line in these
730 // tests. downlink is expected to be 0.075 Mbps but leave some gap to
731 // account for added noise and randomization.
Tarun Bansalbef6d652018-10-02 18:41:01732 if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G) {
733 EXPECT_NEAR(0.075, mbps_value, 0.05);
734 } else if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_3G) {
735 EXPECT_NEAR(0.4, mbps_value, 0.1);
736 } else {
737 NOTREACHED();
738 }
Tarun Bansalceab9592018-05-01 18:57:35739
Tarun Bansalbef6d652018-10-02 18:41:01740 EXPECT_EQ(expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G ? "2g" : "3g",
741 request.headers.find("ect")->second);
Tarun Bansalceab9592018-05-01 18:57:35742 }
Tarun Bansal7f3fe8c2018-04-06 22:37:47743 }
744
Tarun Bansal3b330b02017-11-09 19:03:14745 net::EmbeddedTestServer http_server_;
Tarun Bansal0b8b7afd2017-08-25 03:52:16746 net::EmbeddedTestServer https_server_;
Tarun Bansal345418632018-06-29 11:07:04747 net::EmbeddedTestServer https_cross_origin_server_;
Tarun Bansal3b330b02017-11-09 19:03:14748 GURL accept_ch_with_lifetime_http_local_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05749 GURL http_equiv_accept_ch_with_lifetime_http_local_url_;
Tarun Bansal1965b042017-09-07 04:59:19750 GURL accept_ch_with_lifetime_url_;
Tarun Bansal73502f92019-04-16 21:21:19751 GURL accept_ch_with_short_lifetime_url_;
Tarun Bansal1965b042017-09-07 04:59:19752 GURL accept_ch_without_lifetime_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05753 GURL http_equiv_accept_ch_without_lifetime_url_;
Tarun Bansal1965b042017-09-07 04:59:19754 GURL without_accept_ch_without_lifetime_url_;
Tarun Bansal3b330b02017-11-09 19:03:14755 GURL without_accept_ch_without_lifetime_local_url_;
Tarun Bansaladd5e1812018-02-09 19:07:58756 GURL accept_ch_without_lifetime_with_iframe_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05757 GURL http_equiv_accept_ch_without_lifetime_with_iframe_url_;
Tarun Bansal62cc3542018-06-27 23:53:30758 GURL accept_ch_without_lifetime_with_subresource_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05759 GURL http_equiv_accept_ch_without_lifetime_with_subresource_url_;
Tarun Bansal62cc3542018-06-27 23:53:30760 GURL accept_ch_without_lifetime_with_subresource_iframe_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05761 GURL http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_;
Tarun Bansaladd5e1812018-02-09 19:07:58762 GURL without_accept_ch_without_lifetime_img_foo_com_;
763 GURL without_accept_ch_without_lifetime_img_localhost_;
Tarun Bansal229647bd002018-02-27 17:33:36764 GURL accept_ch_without_lifetime_img_localhost_;
Tarun Bansal9a7051f2018-07-10 18:30:05765 GURL http_equiv_accept_ch_without_lifetime_img_localhost_;
766 GURL http_equiv_accept_ch_with_lifetime_;
Tarun Bansal293a7b6c2018-12-05 17:41:12767 GURL redirect_url_;
Maks Orlovich7a588d82020-05-06 15:17:24768 GURL accept_ch_empty_;
769 GURL http_equiv_accept_ch_merge_;
Tarun Bansal1965b042017-09-07 04:59:19770
Mike Weste555be862019-02-20 16:17:30771 std::string main_frame_ua_observed_;
Yoav Weissd33bacb2020-03-12 06:42:21772 std::string main_frame_ua_full_version_observed_;
Maks Orlovich73f374d2020-04-02 12:46:13773 std::string main_frame_ua_mobile_observed_;
774 std::string main_frame_ua_platform_observed_;
Mike Weste555be862019-02-20 16:17:30775
Tarun Bansal44ad96882018-03-28 17:47:42776 double main_frame_dpr_observed_ = -1;
777 double main_frame_viewport_width_observed_ = -1;
778 double main_frame_device_memory_observed_ = -1;
779
Tarun Bansal229647bd002018-02-27 17:33:36780 // Expect client hints on all the main frame request.
781 bool expect_client_hints_on_main_frame_;
782 // Expect client hints on all the subresource requests.
Callum May1d939742020-03-02 17:51:30783 bool expect_client_hints_on_subresources_
784 GUARDED_BY(expect_client_hints_on_subresources_lock_);
785
786 base::Lock expect_client_hints_on_subresources_lock_;
Tarun Bansal229647bd002018-02-27 17:33:36787
Mike West2fddeeb72019-02-15 11:29:48788 size_t count_user_agent_hint_headers_seen_;
Maks Orlovich5dcc99c2020-02-13 19:07:46789 size_t count_ua_mobile_client_hints_headers_seen_;
Tarun Bansal1965b042017-09-07 04:59:19790 size_t count_client_hints_headers_seen_;
Tarun Bansala61f0f62017-10-24 23:53:05791
Jay Civelli1ff872d2018-03-09 21:52:16792 std::unique_ptr<ThirdPartyURLLoaderInterceptor> request_interceptor_;
Tarun Bansal229647bd002018-02-27 17:33:36793
Tarun Bansalbef6d652018-10-02 18:41:01794 // Set to 2G in SetUpCommandLine().
795 net::EffectiveConnectionType expected_ect = net::EFFECTIVE_CONNECTION_TYPE_2G;
796
Tarun Bansala61f0f62017-10-24 23:53:05797 DISALLOW_COPY_AND_ASSIGN(ClientHintsBrowserTest);
Tarun Bansal0b8b7afd2017-08-25 03:52:16798};
799
Tarun Bansal9a7051f2018-07-10 18:30:05800// True if testing for http-equiv correctness. When set to true, the tests
801// use webpages that may contain http-equiv Accept-CH and Accept-CH-Lifetime
802// headers. When set to false, the tests use webpages that set the headers in
803// the HTTP response headers.
Ilia Samsonov282c38412019-12-09 08:15:10804INSTANTIATE_TEST_SUITE_P(All,
Victor Costane5e91512019-02-13 08:24:02805 ClientHintsBrowserTest,
806 testing::Bool());
Tarun Bansal9a7051f2018-07-10 18:30:05807
Tarun Bansalea0d8262018-05-21 16:11:50808class ClientHintsAllowThirdPartyBrowserTest : public ClientHintsBrowserTest {
Mike West2fddeeb72019-02-15 11:29:48809 std::unique_ptr<base::FeatureList> EnabledFeatures() override {
810 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
811 feature_list->InitializeFromCommandLine(
812 "AllowClientHintsToThirdParty,UserAgentClientHint", "");
813 return feature_list;
Tarun Bansalea0d8262018-05-21 16:11:50814 }
815};
816
Ilia Samsonov282c38412019-12-09 08:15:10817INSTANTIATE_TEST_SUITE_P(All,
Aaron Tagliaboschia09ec442019-09-18 15:29:03818 ClientHintsAllowThirdPartyBrowserTest,
819 testing::Bool());
820
Tarun Bansal74e189d2018-05-07 19:07:35821IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, CorsChecks) {
Mike West14c11102019-02-04 16:16:47822 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Tarun Bansal74e189d2018-05-07 19:07:35823 // Do not test for headers that have not been enabled on the blink "stable"
824 // yet.
825 if (std::string(blink::kClientHintsHeaderMapping[i]) == "rtt" ||
826 std::string(blink::kClientHintsHeaderMapping[i]) == "downlink" ||
827 std::string(blink::kClientHintsHeaderMapping[i]) == "ect") {
828 continue;
829 }
Takashi Toyoshima2e01e692018-11-16 03:23:27830 EXPECT_TRUE(network::cors::IsCorsSafelistedHeader(
Tarun Bansal74e189d2018-05-07 19:07:35831 blink::kClientHintsHeaderMapping[i], "42" /* value */));
832 }
Takashi Toyoshima2e01e692018-11-16 03:23:27833 EXPECT_FALSE(network::cors::IsCorsSafelistedHeader("not-a-client-hint-header",
Tarun Bansal74e189d2018-05-07 19:07:35834 "" /* value */));
835 EXPECT_TRUE(
Takashi Toyoshima2e01e692018-11-16 03:23:27836 network::cors::IsCorsSafelistedHeader("save-data", "on" /* value */));
Tarun Bansal74e189d2018-05-07 19:07:35837}
838
Maks Orlovichf0a2eed2020-05-02 20:08:21839IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, HttpEquivWorks) {
840 const GURL gurl = http_equiv_accept_ch_without_lifetime_img_localhost();
841 base::HistogramTester histogram_tester;
842
843 SetClientHintExpectationsOnMainFrame(false);
844 SetClientHintExpectationsOnSubresources(true);
845
846 ui_test_utils::NavigateToURL(browser(), gurl);
847 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
848}
849
Tarun Bansal0b8b7afd2017-08-25 03:52:16850// Loads a webpage that requests persisting of client hints. Verifies that
851// the browser receives the mojo notification from the renderer and persists the
Maks Orlovichf0a2eed2020-05-02 20:08:21852// client hints to the disk --- unless it's using http-equiv which shouldn't
853// persist.
Tarun Bansal9a7051f2018-07-10 18:30:05854IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest, ClientHintsHttps) {
Tarun Bansal0b8b7afd2017-08-25 03:52:16855 base::HistogramTester histogram_tester;
Tarun Bansal9a7051f2018-07-10 18:30:05856 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
857 : accept_ch_with_lifetime_url();
858 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal0b8b7afd2017-08-25 03:52:16859
Maks Orlovichf0a2eed2020-05-02 20:08:21860 if (GetParam())
861 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
862 else
863 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
Tarun Bansal0b8b7afd2017-08-25 03:52:16864
865 content::FetchHistogramsFromChildProcesses();
866 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
867
Maks Orlovichf0a2eed2020-05-02 20:08:21868 if (GetParam()) {
869 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
870 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
871 } else {
872 // client_hints_url() sets the expected number of client hints.
873 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
874 expected_client_hints_number, 1);
875 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
876 // seconds.
877 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
878 3600 * 1000, 1);
879 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16880}
881
Tarun Bansaladd5e1812018-02-09 19:07:58882// Test that client hints are attached to subresources only if they belong
883// to the same host as document host.
Maks Orlovichf0a2eed2020-05-02 20:08:21884IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansaladd5e1812018-02-09 19:07:58885 ClientHintsHttpsSubresourceDifferentOrigin) {
Maks Orlovichf0a2eed2020-05-02 20:08:21886 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:05887
Tarun Bansaladd5e1812018-02-09 19:07:58888 base::HistogramTester histogram_tester;
889
890 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:05891 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansaladd5e1812018-02-09 19:07:58892 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
893
894 // Verify that the client hints settings for localhost have been saved.
895 ContentSettingsForOneType client_hints_settings;
896 HostContentSettingsMap* host_content_settings_map =
897 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
898 host_content_settings_map->GetSettingsForOneType(
Darin Fisher42f5e7d2019-10-30 07:15:45899 ContentSettingsType::CLIENT_HINTS, std::string(), &client_hints_settings);
Tarun Bansaladd5e1812018-02-09 19:07:58900 ASSERT_EQ(1U, client_hints_settings.size());
901
902 // Copy the client hints setting for localhost to foo.com.
903 host_content_settings_map->SetWebsiteSettingDefaultScope(
Darin Fisher42f5e7d2019-10-30 07:15:45904 GURL("https://foo.com/"), GURL(), ContentSettingsType::CLIENT_HINTS,
Tarun Bansaladd5e1812018-02-09 19:07:58905 std::string(),
Jeremy Romanec48d7a2018-03-01 17:35:09906 std::make_unique<base::Value>(
Oksana Zhuravlovab14dc882018-04-12 17:34:57907 client_hints_settings.at(0).setting_value.Clone()));
Tarun Bansaladd5e1812018-02-09 19:07:58908
909 // Verify that client hints for the two hosts has been saved.
910 host_content_settings_map =
911 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
912 host_content_settings_map->GetSettingsForOneType(
Darin Fisher42f5e7d2019-10-30 07:15:45913 ContentSettingsType::CLIENT_HINTS, std::string(), &client_hints_settings);
Tarun Bansaladd5e1812018-02-09 19:07:58914 ASSERT_EQ(2U, client_hints_settings.size());
915
916 // Navigating to without_accept_ch_without_lifetime_img_localhost() should
917 // attach client hints to the image subresouce contained in that page since
918 // the image is located on the same server as the document origin.
Tarun Bansal229647bd002018-02-27 17:33:36919 SetClientHintExpectationsOnMainFrame(true);
920 SetClientHintExpectationsOnSubresources(true);
Tarun Bansaladd5e1812018-02-09 19:07:58921 ui_test_utils::NavigateToURL(
922 browser(), without_accept_ch_without_lifetime_img_localhost());
923 base::RunLoop().RunUntilIdle();
924 content::FetchHistogramsFromChildProcesses();
925 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
926
Maks Orlovich5dcc99c2020-02-13 19:07:46927 // The user agent hint is attached to all three requests, as is UA-mobile:
Mike West2fddeeb72019-02-15 11:29:48928 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:46929 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:48930
Yoav Weissd33bacb2020-03-12 06:42:21931 // Expected number of hints attached to the image request, and the same number
932 // to the main frame request.
933 EXPECT_EQ(expected_client_hints_number * 2,
934 count_client_hints_headers_seen());
Tarun Bansaladd5e1812018-02-09 19:07:58935
936 // Navigating to without_accept_ch_without_lifetime_img_foo_com() should not
937 // attach client hints to the image subresouce contained in that page since
938 // the image is located on a different server as the document origin.
Tarun Bansaladd5e1812018-02-09 19:07:58939 ui_test_utils::NavigateToURL(
940 browser(), without_accept_ch_without_lifetime_img_foo_com());
941 base::RunLoop().RunUntilIdle();
942 content::FetchHistogramsFromChildProcesses();
943 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
944
Tarun Bansalb30b7532018-03-14 21:50:38945 // The device-memory and dprheader is attached to the main frame request.
Tarun Bansal5c28afb2018-03-17 02:55:20946#if defined(OS_ANDROID)
Yoav Weissd33bacb2020-03-12 06:42:21947 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal5c28afb2018-03-17 02:55:20948#else
Yoav Weissd33bacb2020-03-12 06:42:21949 EXPECT_EQ(expected_client_hints_number * 3,
950 count_client_hints_headers_seen());
Tarun Bansal5c28afb2018-03-17 02:55:20951#endif
Mike West2fddeeb72019-02-15 11:29:48952
953 // Requests to third party servers should have only one client hint attached
954 // (`Sec-CH-UA`).
Tarun Bansal229647bd002018-02-27 17:33:36955 EXPECT_EQ(1u, third_party_request_count_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:46956 EXPECT_EQ(2u, third_party_client_hints_count_seen());
Tarun Bansaladd5e1812018-02-09 19:07:58957}
958
Maks Orlovich7227ce0d2020-02-28 17:13:16959// Test that client hints are attached to subresources checks the right setting
960// for OTR profile.
Maks Orlovichf0a2eed2020-05-02 20:08:21961IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Maks Orlovich7227ce0d2020-02-28 17:13:16962 ClientHintsHttpsSubresourceOffTheRecord) {
Maks Orlovichf0a2eed2020-05-02 20:08:21963 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich7227ce0d2020-02-28 17:13:16964
965 base::HistogramTester histogram_tester;
966
967 // Add client hints for the embedded test server.
968 ui_test_utils::NavigateToURL(browser(), gurl);
969 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
970
971 // Main profile should get hints for both page and subresources.
972 SetClientHintExpectationsOnMainFrame(true);
973 SetClientHintExpectationsOnSubresources(true);
974 ui_test_utils::NavigateToURL(
975 browser(), without_accept_ch_without_lifetime_img_localhost());
976 base::RunLoop().RunUntilIdle();
977 content::FetchHistogramsFromChildProcesses();
978 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
979
980 // The user agent hint is attached to all three requests:
981 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
982 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
983
Yoav Weissd33bacb2020-03-12 06:42:21984 // Expected number of hints attached to the image request, and the same number
985 // to the main frame request.
986 EXPECT_EQ(expected_client_hints_number * 2,
987 count_client_hints_headers_seen());
Maks Orlovich7227ce0d2020-02-28 17:13:16988
989 // OTR profile should get neither.
990 Browser* otr_browser = CreateIncognitoBrowser(browser()->profile());
991 SetClientHintExpectationsOnMainFrame(false);
992 SetClientHintExpectationsOnSubresources(false);
993 ui_test_utils::NavigateToURL(
994 otr_browser, without_accept_ch_without_lifetime_img_localhost());
995}
996
Mike Weste555be862019-02-20 16:17:30997// Verify that we send only major version information in the `Sec-CH-UA` header
Yoav Weissd33bacb2020-03-12 06:42:21998// by default, regardless of opt-in.
Maks Orlovichf0a2eed2020-05-02 20:08:21999IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UserAgentVersion) {
1000 const GURL gurl = accept_ch_with_lifetime_url();
Mike Weste555be862019-02-20 16:17:301001
1002 blink::UserAgentMetadata ua = ::GetUserAgentMetadata();
1003
1004 // Navigate to a page that opts-into the header: the value should end with
1005 // the major version, and not contain the full version.
1006 SetClientHintExpectationsOnMainFrame(false);
1007 ui_test_utils::NavigateToURL(browser(), gurl);
Aaron Tagliaboschi9f01b682020-05-05 21:03:171008 std::string expected_ua = ua.SerializeBrandVersionList();
Yoav Weissd33bacb2020-03-12 06:42:211009 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1010 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Mike Weste555be862019-02-20 16:17:301011
Yoav Weissd33bacb2020-03-12 06:42:211012 // Navigate again, after the opt-in: the value should stay the major
Mike Weste555be862019-02-20 16:17:301013 // version.
1014 SetClientHintExpectationsOnMainFrame(true);
1015 ui_test_utils::NavigateToURL(browser(), gurl);
Yoav Weissd33bacb2020-03-12 06:42:211016 std::string expected_full_version = "\"" + ua.full_version + "\"";
1017 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1018 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
Mike Weste555be862019-02-20 16:17:301019}
1020
Maks Orlovichf0a2eed2020-05-02 20:08:211021IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UAHintsTabletMode) {
1022 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich73f374d2020-04-02 12:46:131023
1024 blink::UserAgentMetadata ua = ::GetUserAgentMetadata();
1025
1026 // First request: only minimal hints, no tablet override.
1027 SetClientHintExpectationsOnMainFrame(false);
1028 ui_test_utils::NavigateToURL(browser(), gurl);
Aaron Tagliaboschi9f01b682020-05-05 21:03:171029 std::string expected_ua = ua.SerializeBrandVersionList();
Maks Orlovich73f374d2020-04-02 12:46:131030 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1031 EXPECT_EQ(main_frame_ua_full_version_observed(), "");
1032 EXPECT_EQ(main_frame_ua_mobile_observed(), "?0");
1033 EXPECT_EQ(main_frame_ua_platform_observed(), "");
1034
1035 // Second request: table override, all hints.
1036 chrome::ToggleRequestTabletSite(browser());
1037 SetClientHintExpectationsOnMainFrame(true);
1038 ui_test_utils::NavigateToURL(browser(), gurl);
1039 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1040 std::string expected_full_version = "\"" + ua.full_version + "\"";
1041 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
1042 EXPECT_EQ(main_frame_ua_mobile_observed(), "?1");
1043 EXPECT_EQ(main_frame_ua_platform_observed(), "\"Android\"");
1044}
1045
1046// TODO(morlovich): Move this into WebContentsImplBrowserTest once things are
1047// refactored enough that UA client hints actually work in content/
1048IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UserAgentOverrideClientHints) {
1049 content::WebContents* web_contents =
1050 browser()->tab_strip_model()->GetActiveWebContents();
1051
1052 ASSERT_TRUE(embedded_test_server()->Start());
1053 const std::string kHeaderPath = std::string("/echoheader?") +
1054 net::HttpRequestHeaders::kUserAgent +
1055 "&sec-ch-ua&sec-ch-ua-mobile";
1056 const GURL kUrl(embedded_test_server()->GetURL(kHeaderPath));
1057
1058 web_contents->SetUserAgentOverride(
1059 blink::UserAgentOverride::UserAgentOnly("foo"), false);
1060 // Not enabled first.
1061 ui_test_utils::NavigateToURL(browser(), kUrl);
1062 std::string header_value;
1063 EXPECT_TRUE(ExecuteScriptAndExtractString(
1064 web_contents,
1065 "window.domAutomationController.send(document.body.textContent);",
1066 &header_value));
1067 EXPECT_EQ(std::string::npos, header_value.find("foo")) << header_value;
1068
1069 // Actually turn it on.
1070 web_contents->GetController()
1071 .GetLastCommittedEntry()
1072 ->SetIsOverridingUserAgent(true);
1073
1074 ui_test_utils::NavigateToURL(browser(), kUrl);
1075 EXPECT_TRUE(ExecuteScriptAndExtractString(
1076 web_contents,
1077 "window.domAutomationController.send(document.body.textContent);",
1078 &header_value));
1079 // Since no value was provided for client hints, they are not sent.
1080 EXPECT_EQ("foo\nNone\nNone", header_value);
1081
1082 // Now actually provide values for the hints.
1083 blink::UserAgentOverride ua_override;
1084 ua_override.ua_string_override = "foobar";
1085 ua_override.ua_metadata_override.emplace();
1086 ua_override.ua_metadata_override->mobile = true;
Aaron Tagliaboschi9f01b682020-05-05 21:03:171087 ua_override.ua_metadata_override->brand_version_list.emplace_back(
1088 "Foobarnator", "3.14");
Maks Orlovich73f374d2020-04-02 12:46:131089 web_contents->SetUserAgentOverride(ua_override, false);
1090 ui_test_utils::NavigateToURL(browser(), kUrl);
1091 EXPECT_TRUE(ExecuteScriptAndExtractString(
1092 web_contents,
1093 "window.domAutomationController.send(document.body.textContent);",
1094 &header_value));
Aaron Tagliaboschi9f01b682020-05-05 21:03:171095 EXPECT_EQ("foobar\n\"Foobarnator\";v=\"3.14\"\n?1", header_value);
Maks Orlovich73f374d2020-04-02 12:46:131096}
1097
Maks Orlovich7a588d82020-05-06 15:17:241098IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, EmptyAcceptCH) {
1099 // First navigate to a page that enables hints. No CH for it yet, since
1100 // nothing opted in.
1101 GURL gurl = accept_ch_with_lifetime_url();
1102 SetClientHintExpectationsOnMainFrame(false);
1103 ui_test_utils::NavigateToURL(browser(), gurl);
1104
1105 // Now go to a page with blank Accept-CH. Should get hints from previous
1106 // visit.
1107 gurl = accept_ch_empty();
1108 SetClientHintExpectationsOnMainFrame(true);
1109 ui_test_utils::NavigateToURL(browser(), gurl);
1110
1111 // Visiting again should not expect them since we opted out again.
1112 SetClientHintExpectationsOnMainFrame(false);
1113 ui_test_utils::NavigateToURL(browser(), gurl);
1114}
1115
1116IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, MergeAcceptCH) {
1117 // Go to page where some hints are enabled by headers, some by
1118 // http-equiv. It shouldn't get hints itself (due to first visit),
1119 // but subresources should get all the client hints.
1120 GURL gurl = http_equiv_accept_ch_merge();
1121 SetClientHintExpectationsOnMainFrame(false);
1122 SetClientHintExpectationsOnSubresources(true);
1123 ui_test_utils::NavigateToURL(browser(), gurl);
1124 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
1125}
1126
Maks Orlovich7227ce0d2020-02-28 17:13:161127void ClientHintsBrowserTest::TestProfilesIndependent(Browser* browser_a,
1128 Browser* browser_b) {
Maks Orlovichf0a2eed2020-05-02 20:08:211129 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich7227ce0d2020-02-28 17:13:161130
1131 blink::UserAgentMetadata ua = ::GetUserAgentMetadata();
1132
1133 // Navigate |browser_a| to a page that opts-into the header: the value should
1134 // end with the major version, and not contain the full version.
1135 SetClientHintExpectationsOnMainFrame(false);
1136 ui_test_utils::NavigateToURL(browser_a, gurl);
Aaron Tagliaboschi9f01b682020-05-05 21:03:171137 std::string expected_ua = ua.SerializeBrandVersionList();
Yoav Weissd33bacb2020-03-12 06:42:211138 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1139 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Maks Orlovich7227ce0d2020-02-28 17:13:161140
1141 // Try again on |browser_a|, the header should have an effect there.
1142 SetClientHintExpectationsOnMainFrame(true);
1143 ui_test_utils::NavigateToURL(browser_a, gurl);
Yoav Weissd33bacb2020-03-12 06:42:211144 std::string expected_full_version = "\"" + ua.full_version + "\"";
1145 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1146 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
Maks Orlovich7227ce0d2020-02-28 17:13:161147
1148 // Navigate on |browser_b|. That should still only have the major
1149 // version.
1150 SetClientHintExpectationsOnMainFrame(false);
1151 ui_test_utils::NavigateToURL(browser_b, gurl);
Yoav Weissd33bacb2020-03-12 06:42:211152 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1153 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Maks Orlovich7227ce0d2020-02-28 17:13:161154}
1155
1156// Check that client hints attached to navigation inside OTR profiles
1157// use the right settings, regular -> OTR direction.
Maks Orlovichf0a2eed2020-05-02 20:08:211158IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, OffTheRecordIndependent) {
Maks Orlovich7227ce0d2020-02-28 17:13:161159 TestProfilesIndependent(browser(),
1160 CreateIncognitoBrowser(browser()->profile()));
1161}
1162
1163// Check that client hints attached to navigation inside OTR profiles
1164// use the right settings, OTR -> regular direction.
Maks Orlovichf0a2eed2020-05-02 20:08:211165IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, OffTheRecordIndependent2) {
Maks Orlovich7227ce0d2020-02-28 17:13:161166 TestProfilesIndependent(CreateIncognitoBrowser(browser()->profile()),
1167 browser());
1168}
1169
Tarun Bansalea0d8262018-05-21 16:11:501170// Test that client hints are attached to third party subresources if
1171// AllowClientHintsToThirdParty feature is enabled.
Tarun Bansal9a7051f2018-07-10 18:30:051172IN_PROC_BROWSER_TEST_P(ClientHintsAllowThirdPartyBrowserTest,
Tarun Bansalea0d8262018-05-21 16:11:501173 ClientHintsThirdPartyAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:051174 const GURL gurl = GetParam()
1175 ? http_equiv_accept_ch_without_lifetime_img_localhost()
1176 : accept_ch_without_lifetime_img_localhost();
1177
Tarun Bansalea0d8262018-05-21 16:11:501178 base::HistogramTester histogram_tester;
1179
1180 SetClientHintExpectationsOnMainFrame(false);
1181 SetClientHintExpectationsOnSubresources(true);
1182
1183 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:051184 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansalea0d8262018-05-21 16:11:501185 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1186
Yoav Weissd33bacb2020-03-12 06:42:211187 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansalea0d8262018-05-21 16:11:501188
1189 // Requests to third party servers should not have client hints attached.
1190 EXPECT_EQ(1u, third_party_request_count_seen());
1191
Aaron Tagliaboschia09ec442019-09-18 15:29:031192 // Device memory, viewport width, DRP, and UA client hints should be sent to
1193 // the third-party when feature "AllowClientHintsToThirdParty" is enabled.
Maks Orlovich5dcc99c2020-02-13 19:07:461194 EXPECT_EQ(5u, third_party_client_hints_count_seen());
Tarun Bansalea0d8262018-05-21 16:11:501195}
1196
1197// Test that client hints are not attached to third party subresources if
1198// AllowClientHintsToThirdParty feature is not enabled.
Tarun Bansal9a7051f2018-07-10 18:30:051199IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansalea0d8262018-05-21 16:11:501200 ClientHintsThirdPartyNotAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:051201 const GURL gurl = GetParam()
1202 ? http_equiv_accept_ch_without_lifetime_img_localhost()
1203 : accept_ch_without_lifetime_img_localhost();
1204
Tarun Bansalea0d8262018-05-21 16:11:501205 base::HistogramTester histogram_tester;
1206
1207 SetClientHintExpectationsOnMainFrame(false);
1208 SetClientHintExpectationsOnSubresources(true);
1209
1210 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:051211 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansalea0d8262018-05-21 16:11:501212 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1213
Mike West2fddeeb72019-02-15 11:29:481214 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461215 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:211216 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansalea0d8262018-05-21 16:11:501217
1218 // Requests to third party servers should not have client hints attached.
1219 EXPECT_EQ(1u, third_party_request_count_seen());
1220
1221 // Client hints should not be sent to the third-party when feature
Mike West2fddeeb72019-02-15 11:29:481222 // "AllowClientHintsToThirdParty" is not enabled, with the exception of the
1223 // `Sec-CH-UA` hint, which is sent with every request.
Maks Orlovich5dcc99c2020-02-13 19:07:461224 EXPECT_EQ(2u, third_party_client_hints_count_seen());
Tarun Bansalea0d8262018-05-21 16:11:501225}
1226
Tarun Bansaladd5e1812018-02-09 19:07:581227// Loads a HTTPS webpage that does not request persisting of client hints.
Tarun Bansal345418632018-06-29 11:07:041228// A same-origin iframe loaded by the webpage requests persistence of client
1229// hints. Verify that the request from the iframe is honored, and client hints
1230// preference is persisted.
Maks Orlovichf0a2eed2020-05-02 20:08:211231IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal345418632018-06-29 11:07:041232 PersistenceRequestIframe_SameOrigin) {
Maks Orlovichf0a2eed2020-05-02 20:08:211233 const GURL gurl = accept_ch_without_lifetime_with_iframe_url();
Tarun Bansal345418632018-06-29 11:07:041234 base::HistogramTester histogram_tester;
1235 ContentSettingsForOneType host_settings;
1236
1237 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451238 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal345418632018-06-29 11:07:041239 &host_settings);
1240 EXPECT_EQ(0u, host_settings.size());
1241
Tarun Bansal9a7051f2018-07-10 18:30:051242 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal345418632018-06-29 11:07:041243
1244 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 1);
1245
1246 content::FetchHistogramsFromChildProcesses();
1247 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1248
1249 // accept_ch_without_lifetime_with_iframe_url() loads
1250 // accept_ch_with_lifetime() in an iframe. The request to persist client
1251 // hints from accept_ch_with_lifetime() should be persisted.
1252 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 1);
1253 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
1254 3600 * 1000, 1);
1255}
1256
1257// Loads a HTTPS webpage that does not request persisting of client hints.
1258// An iframe loaded by the webpage from an cross origin server requests
1259// persistence of client hints.
1260// Verify that the request from the cross origin iframe is not honored, and
1261// client hints preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051262IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal345418632018-06-29 11:07:041263 DisregardPersistenceRequestIframe_CrossOrigin) {
Tarun Bansal9a7051f2018-07-10 18:30:051264 const GURL gurl =
1265 GetParam() ? http_equiv_accept_ch_without_lifetime_with_iframe_url()
1266 : accept_ch_without_lifetime_with_iframe_url();
1267
1268 intercept_iframe_resource_ = gurl.path();
1269 intercept_to_http_equiv_iframe_ = GetParam();
1270
Tarun Bansaladd5e1812018-02-09 19:07:581271 base::HistogramTester histogram_tester;
1272 ContentSettingsForOneType host_settings;
1273
1274 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451275 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansaladd5e1812018-02-09 19:07:581276 &host_settings);
1277 EXPECT_EQ(0u, host_settings.size());
1278
Tarun Bansal9a7051f2018-07-10 18:30:051279 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansaladd5e1812018-02-09 19:07:581280
1281 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1282
1283 content::FetchHistogramsFromChildProcesses();
1284 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1285
1286 // accept_ch_without_lifetime_with_iframe_url() loads
Tarun Bansal345418632018-06-29 11:07:041287 // accept_ch_with_lifetime() in a cross origin iframe. The request to persist
1288 // client hints from accept_ch_with_lifetime() should be disregarded.
Tarun Bansaladd5e1812018-02-09 19:07:581289 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1290 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1291}
1292
Tarun Bansal62cc3542018-06-27 23:53:301293// Loads a HTTPS webpage that does not request persisting of client hints.
1294// A subresource loaded by the webpage requests persistence of client hints.
1295// Verify that the request from the subresource is not honored, and client hints
1296// preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051297IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal62cc3542018-06-27 23:53:301298 DisregardPersistenceRequestSubresource) {
Tarun Bansal9a7051f2018-07-10 18:30:051299 const GURL gurl =
1300 GetParam() ? http_equiv_accept_ch_without_lifetime_with_subresource_url()
1301 : accept_ch_without_lifetime_with_subresource_url();
1302
Tarun Bansal62cc3542018-06-27 23:53:301303 base::HistogramTester histogram_tester;
1304 ContentSettingsForOneType host_settings;
1305
1306 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451307 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal62cc3542018-06-27 23:53:301308 &host_settings);
1309 EXPECT_EQ(0u, host_settings.size());
1310
Tarun Bansal9a7051f2018-07-10 18:30:051311 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal62cc3542018-06-27 23:53:301312
1313 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1314
1315 content::FetchHistogramsFromChildProcesses();
1316 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1317
1318 // accept_ch_without_lifetime_with_subresource_url() loads
1319 // accept_ch_with_lifetime() as a subresource. The request to persist client
1320 // hints from accept_ch_with_lifetime() should be disregarded.
1321 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1322 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1323}
1324
1325// Loads a HTTPS webpage that does not request persisting of client hints.
1326// A subresource loaded by the webpage in an iframe requests persistence of
1327// client hints. Verify that the request from the subresource in the iframe
1328// is not honored, and client hints preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051329IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal62cc3542018-06-27 23:53:301330 DisregardPersistenceRequestSubresourceIframe) {
Tarun Bansal9a7051f2018-07-10 18:30:051331 const GURL gurl =
1332 GetParam()
1333 ? http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url()
1334 : accept_ch_without_lifetime_with_subresource_iframe_url();
1335
Tarun Bansal62cc3542018-06-27 23:53:301336 base::HistogramTester histogram_tester;
1337 ContentSettingsForOneType host_settings;
1338
1339 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451340 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal62cc3542018-06-27 23:53:301341 &host_settings);
1342 EXPECT_EQ(0u, host_settings.size());
1343
Tarun Bansal9a7051f2018-07-10 18:30:051344 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal62cc3542018-06-27 23:53:301345
1346 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1347
1348 content::FetchHistogramsFromChildProcesses();
1349 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1350
Tarun Bansal9a7051f2018-07-10 18:30:051351 // |gurl| loads accept_ch_with_lifetime() or
1352 // http_equiv_accept_ch_with_lifetime() as a subresource in an iframe. The
1353 // request to persist client hints from accept_ch_with_lifetime() or
1354 // http_equiv_accept_ch_with_lifetime() should be disregarded.
Tarun Bansal62cc3542018-06-27 23:53:301355 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1356 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1357}
1358
Tarun Bansal3b330b02017-11-09 19:03:141359// Loads a HTTP local webpage (which qualifies as a secure context) that
1360// requests persisting of client hints. Verifies that the browser receives the
1361// mojo notification from the renderer and persists the client hints to the
1362// disk.
Maks Orlovichf0a2eed2020-05-02 20:08:211363IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal3b330b02017-11-09 19:03:141364 ClientHintsLifetimeFollowedByNoClientHintHttpLocal) {
Maks Orlovichf0a2eed2020-05-02 20:08:211365 const GURL gurl = accept_ch_with_lifetime_http_local_url();
Tarun Bansal9a7051f2018-07-10 18:30:051366
Tarun Bansal3b330b02017-11-09 19:03:141367 base::HistogramTester histogram_tester;
1368 ContentSettingsForOneType host_settings;
1369
1370 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451371 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal3b330b02017-11-09 19:03:141372 &host_settings);
1373 EXPECT_EQ(0u, host_settings.size());
1374
Tarun Bansal9a7051f2018-07-10 18:30:051375 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal3b330b02017-11-09 19:03:141376
1377 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1378
1379 content::FetchHistogramsFromChildProcesses();
1380 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1381
Yoav Weissd33bacb2020-03-12 06:42:211382 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1383 expected_client_hints_number, 1);
Tarun Bansal9a7051f2018-07-10 18:30:051384 // |gurl| sets client hints persist duration to 3600 seconds.
Tarun Bansal3b330b02017-11-09 19:03:141385 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
1386 3600 * 1000, 1);
1387
1388 base::RunLoop().RunUntilIdle();
1389
1390 // Clients hints preferences for one origin should be persisted.
1391 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451392 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal3b330b02017-11-09 19:03:141393 &host_settings);
1394 EXPECT_EQ(1u, host_settings.size());
1395
Tarun Bansal229647bd002018-02-27 17:33:361396 SetClientHintExpectationsOnMainFrame(true);
1397 SetClientHintExpectationsOnSubresources(true);
Tarun Bansal3b330b02017-11-09 19:03:141398 ui_test_utils::NavigateToURL(browser(),
1399 without_accept_ch_without_lifetime_local_url());
1400
Mike West2fddeeb72019-02-15 11:29:481401 // The user agent hint is attached to all three requests:
1402 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461403 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481404
Yoav Weissd33bacb2020-03-12 06:42:211405 // Expected number of hints attached to the image request, and the same number
1406 // to the main frame request.
1407 EXPECT_EQ(expected_client_hints_number * 2,
1408 count_client_hints_headers_seen());
Tarun Bansal3b330b02017-11-09 19:03:141409}
1410
Tarun Bansal0b8b7afd2017-08-25 03:52:161411// Loads a webpage that does not request persisting of client hints.
1412IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, NoClientHintsHttps) {
1413 base::HistogramTester histogram_tester;
Tarun Bansal1965b042017-09-07 04:59:191414 ui_test_utils::NavigateToURL(browser(),
1415 without_accept_ch_without_lifetime_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:161416
1417 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1418
1419 content::FetchHistogramsFromChildProcesses();
1420 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1421
1422 // no_client_hints_url() does not sets the client hints.
1423 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1424 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1425}
1426
Tarun Bansal9a7051f2018-07-10 18:30:051427IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal1965b042017-09-07 04:59:191428 ClientHintsLifetimeFollowedByNoClientHint) {
Tarun Bansal9a7051f2018-07-10 18:30:051429 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1430 : accept_ch_with_lifetime_url();
1431
Tarun Bansal1965b042017-09-07 04:59:191432 base::HistogramTester histogram_tester;
1433 ContentSettingsForOneType host_settings;
1434
1435 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451436 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal1965b042017-09-07 04:59:191437 &host_settings);
1438 EXPECT_EQ(0u, host_settings.size());
1439
Maks Orlovichf0a2eed2020-05-02 20:08:211440 // Fetching |gurl| should persist the request for client hints iff using
1441 // headers and not http-equiv.
Tarun Bansal9a7051f2018-07-10 18:30:051442 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal1965b042017-09-07 04:59:191443
Maks Orlovichf0a2eed2020-05-02 20:08:211444 if (GetParam())
1445 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1446 else
1447 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
Tarun Bansal1965b042017-09-07 04:59:191448
1449 content::FetchHistogramsFromChildProcesses();
1450 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal1965b042017-09-07 04:59:191451 base::RunLoop().RunUntilIdle();
1452
Maks Orlovichf0a2eed2020-05-02 20:08:211453 if (GetParam()) {
1454 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1455 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1456 } else {
1457 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1458 expected_client_hints_number, 1);
1459 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
1460 // seconds.
1461 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
1462 3600 * 1000, 1);
Tarun Bansal1965b042017-09-07 04:59:191463
Maks Orlovichf0a2eed2020-05-02 20:08:211464 // Clients hints preferences for one origin should be persisted.
1465 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1466 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
1467 std::string(), &host_settings);
1468 EXPECT_EQ(1u, host_settings.size());
1469 }
1470
1471 SetClientHintExpectationsOnMainFrame(!GetParam());
1472 SetClientHintExpectationsOnSubresources(!GetParam());
Tarun Bansal1965b042017-09-07 04:59:191473 ui_test_utils::NavigateToURL(browser(),
1474 without_accept_ch_without_lifetime_url());
Tarun Bansal6bf54302017-10-02 07:39:141475
Mike West2fddeeb72019-02-15 11:29:481476 // The user agent hint is attached to all three requests:
1477 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461478 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481479
Yoav Weissd33bacb2020-03-12 06:42:211480 // Expected number of hints attached to the image request, and the same number
1481 // to the main frame request.
Maks Orlovichf0a2eed2020-05-02 20:08:211482 EXPECT_EQ(GetParam() ? 0 : expected_client_hints_number * 2,
Yoav Weissd33bacb2020-03-12 06:42:211483 count_client_hints_headers_seen());
Tarun Bansal1965b042017-09-07 04:59:191484}
1485
Tarun Bansal73502f92019-04-16 21:21:191486// Verify that expired persistent client hint preferences are not used.
1487// Verifies this by setting Accept-CH-Lifetime value to 1 second,
1488// and loading a page after 1 second to verify that client hints are not
1489// attached.
1490IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
1491 ShortLifetimeFollowedByNoClientHint) {
1492 const GURL gurl = accept_ch_with_short_lifetime();
1493
1494 base::HistogramTester histogram_tester;
1495 ContentSettingsForOneType host_settings;
1496
1497 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451498 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal73502f92019-04-16 21:21:191499 &host_settings);
1500 EXPECT_EQ(0u, host_settings.size());
1501
1502 // Fetching |gurl| should persist the request for client hints.
1503 ui_test_utils::NavigateToURL(browser(), gurl);
1504
1505 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1506
1507 content::FetchHistogramsFromChildProcesses();
1508 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1509
Yoav Weissd33bacb2020-03-12 06:42:211510 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1511 expected_client_hints_number, 1);
Tarun Bansal73502f92019-04-16 21:21:191512 // |gurl| sets client hints persist duration to 1 second.
1513 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration", 1 * 1000,
1514 1);
1515 base::RunLoop().RunUntilIdle();
1516
1517 // Clients hints preferences for one origin should be persisted.
1518 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451519 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal73502f92019-04-16 21:21:191520 &host_settings);
1521 EXPECT_EQ(1u, host_settings.size());
1522
1523 // Sleep for a duration longer than 1 second (duration of persisted client
1524 // hints).
1525 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1001));
1526
1527 SetClientHintExpectationsOnMainFrame(false);
1528 SetClientHintExpectationsOnSubresources(false);
1529 ui_test_utils::NavigateToURL(browser(),
1530 without_accept_ch_without_lifetime_url());
1531
1532 // The user agent hint is attached to all three requests:
1533 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461534 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Tarun Bansal73502f92019-04-16 21:21:191535
1536 // No client hints are attached to the requests since the persisted hints must
1537 // be expired.
1538 EXPECT_EQ(0u, count_client_hints_headers_seen());
1539}
1540
Tarun Bansal293a7b6c2018-12-05 17:41:121541// The test first fetches a page that sets Accept-CH-Lifetime. Next, it fetches
1542// a URL from a different origin. However, that URL response redirects to the
1543// same origin from where the first page was fetched. The test verifies that
1544// on receiving redirect to an origin for which the browser has persisted client
1545// hints prefs, the browser attaches the client hints headers when fetching the
1546// redirected URL.
Maks Orlovichf0a2eed2020-05-02 20:08:211547IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal293a7b6c2018-12-05 17:41:121548 ClientHintsLifetimeFollowedByRedirectToNoClientHint) {
Maks Orlovichf0a2eed2020-05-02 20:08:211549 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal293a7b6c2018-12-05 17:41:121550
1551 base::HistogramTester histogram_tester;
1552 ContentSettingsForOneType host_settings;
1553
1554 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451555 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal293a7b6c2018-12-05 17:41:121556 &host_settings);
1557 EXPECT_EQ(0u, host_settings.size());
1558
1559 // Fetching |gurl| should persist the request for client hints.
1560 ui_test_utils::NavigateToURL(browser(), gurl);
1561
1562 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1563
1564 content::FetchHistogramsFromChildProcesses();
1565 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1566
Yoav Weissd33bacb2020-03-12 06:42:211567 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1568 expected_client_hints_number, 1);
Tarun Bansal293a7b6c2018-12-05 17:41:121569 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
1570 // seconds.
1571 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
1572 3600 * 1000, 1);
1573 base::RunLoop().RunUntilIdle();
1574
1575 // Clients hints preferences for one origin should be persisted.
1576 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451577 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal293a7b6c2018-12-05 17:41:121578 &host_settings);
1579 EXPECT_EQ(1u, host_settings.size());
1580
1581 SetClientHintExpectationsOnMainFrame(true);
1582 SetClientHintExpectationsOnSubresources(true);
1583 ui_test_utils::NavigateToURL(browser(), redirect_url());
1584
Mike West2fddeeb72019-02-15 11:29:481585 // The user agent hint is attached to all three requests:
1586 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461587 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481588
Yoav Weissd33bacb2020-03-12 06:42:211589 // Expected number of hints attached to the image request, and the same number
1590 // to the main frame request.
1591 EXPECT_EQ(expected_client_hints_number * 2,
1592 count_client_hints_headers_seen());
Tarun Bansal293a7b6c2018-12-05 17:41:121593}
1594
Tarun Bansala0c1fc32018-10-03 16:14:521595// Ensure that even when cookies are blocked, client hint preferences are
Tarun Bansala61f0f62017-10-24 23:53:051596// persisted.
Maks Orlovichf0a2eed2020-05-02 20:08:211597IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521598 ClientHintsLifetimePersistedCookiesBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211599 const GURL gurl_with = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:051600
Tarun Bansala61f0f62017-10-24 23:53:051601 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
1602 CookieSettingsFactory::GetForProfile(browser()->profile());
1603 base::HistogramTester histogram_tester;
1604 ContentSettingsForOneType host_settings;
1605
1606 // Block cookies.
1607 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansala0c1fc32018-10-03 16:14:521608 ->SetContentSettingDefaultScope(gurl_with, GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451609 ContentSettingsType::COOKIES,
Tarun Bansala61f0f62017-10-24 23:53:051610 std::string(), CONTENT_SETTING_BLOCK);
1611
Tarun Bansala0c1fc32018-10-03 16:14:521612 // Fetching |gurl_with| should persist the request for client hints.
Tarun Bansal9a7051f2018-07-10 18:30:051613 ui_test_utils::NavigateToURL(browser(), gurl_with);
Tarun Bansala0c1fc32018-10-03 16:14:521614 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 1);
Tarun Bansala61f0f62017-10-24 23:53:051615 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451616 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansala61f0f62017-10-24 23:53:051617 &host_settings);
1618 EXPECT_EQ(1u, host_settings.size());
Tarun Bansala0c1fc32018-10-03 16:14:521619 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:051620}
1621
Maks Orlovichf0a2eed2020-05-02 20:08:211622IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521623 ClientHintsLifetimeAttachedCookiesBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211624 const GURL gurl_with = accept_ch_with_lifetime_url();
1625 const GURL gurl_without = accept_ch_without_lifetime_url();
Tarun Bansala61f0f62017-10-24 23:53:051626 base::HistogramTester histogram_tester;
1627 ContentSettingsForOneType host_settings;
1628
1629 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451630 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansala61f0f62017-10-24 23:53:051631 &host_settings);
1632 EXPECT_EQ(0u, host_settings.size());
1633
Tarun Bansal9a7051f2018-07-10 18:30:051634 // Fetching |gurl_with| should persist the request for client hints.
1635 ui_test_utils::NavigateToURL(browser(), gurl_with);
Tarun Bansala61f0f62017-10-24 23:53:051636 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1637 content::FetchHistogramsFromChildProcesses();
1638 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Maks Orlovichf0a2eed2020-05-02 20:08:211639 base::RunLoop().RunUntilIdle();
Tarun Bansala61f0f62017-10-24 23:53:051640
Yoav Weissd33bacb2020-03-12 06:42:211641 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1642 expected_client_hints_number, 1);
Tarun Bansal9a7051f2018-07-10 18:30:051643 // |gurl_with| tries to set client hints persist duration to 3600 seconds.
Tarun Bansala61f0f62017-10-24 23:53:051644 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
1645 3600 * 1000, 1);
Tarun Bansala61f0f62017-10-24 23:53:051646
1647 // Clients hints preferences for one origin should be persisted.
1648 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451649 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansala61f0f62017-10-24 23:53:051650 &host_settings);
1651 EXPECT_EQ(1u, host_settings.size());
1652
Tarun Bansala0c1fc32018-10-03 16:14:521653 // Block the cookies: Client hints should be attached.
Tarun Bansala61f0f62017-10-24 23:53:051654 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansal9a7051f2018-07-10 18:30:051655 ->SetContentSettingDefaultScope(gurl_without, GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451656 ContentSettingsType::COOKIES,
Tarun Bansala61f0f62017-10-24 23:53:051657 std::string(), CONTENT_SETTING_BLOCK);
1658
Tarun Bansal229647bd002018-02-27 17:33:361659 SetClientHintExpectationsOnMainFrame(true);
1660 SetClientHintExpectationsOnSubresources(true);
Tarun Bansala61f0f62017-10-24 23:53:051661 ui_test_utils::NavigateToURL(browser(),
1662 without_accept_ch_without_lifetime_url());
Tarun Bansal79df868e2018-03-20 23:01:361663
Mike West2fddeeb72019-02-15 11:29:481664 // The user agent hint is attached to all three requests:
1665 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461666 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481667
Yoav Weissd33bacb2020-03-12 06:42:211668 // Expected number of hints attached to the image request, and the same number
1669 // to the main frame request.
1670 EXPECT_EQ(expected_client_hints_number * 2,
1671 count_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051672
1673 // Clear settings.
1674 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451675 ->ClearSettingsForOneType(ContentSettingsType::COOKIES);
Tarun Bansala61f0f62017-10-24 23:53:051676}
1677
1678// Ensure that when the JavaScript is blocked, client hint preferences are not
1679// persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051680IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala61f0f62017-10-24 23:53:051681 ClientHintsLifetimeNotPersistedJavaScriptBlocked) {
1682 ContentSettingsForOneType host_settings;
1683
1684 // Start a navigation. This navigation makes it possible to block JavaScript
1685 // later.
1686 ui_test_utils::NavigateToURL(browser(),
1687 without_accept_ch_without_lifetime_url());
1688
Tarun Bansal9a7051f2018-07-10 18:30:051689 const GURL gurl =
1690 GetParam() ? http_equiv_accept_ch_without_lifetime_with_iframe_url()
1691 : accept_ch_with_lifetime_url();
1692
Tarun Bansala61f0f62017-10-24 23:53:051693 // Block the JavaScript: Client hint preferences should not be persisted.
1694 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansal9a7051f2018-07-10 18:30:051695 ->SetContentSettingDefaultScope(gurl, GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451696 ContentSettingsType::JAVASCRIPT,
Tarun Bansala61f0f62017-10-24 23:53:051697 std::string(), CONTENT_SETTING_BLOCK);
1698 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
1699 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451700 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansala61f0f62017-10-24 23:53:051701 &host_settings);
1702 EXPECT_EQ(0u, host_settings.size());
Tarun Bansalc211d8b2018-03-19 19:21:581703 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:051704
1705 // Allow the JavaScript: Client hint preferences should be persisted.
1706 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansal9a7051f2018-07-10 18:30:051707 ->SetContentSettingDefaultScope(gurl, GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451708 ContentSettingsType::JAVASCRIPT,
Tarun Bansala61f0f62017-10-24 23:53:051709 std::string(), CONTENT_SETTING_ALLOW);
1710 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
1711 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451712 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansala61f0f62017-10-24 23:53:051713 &host_settings);
1714 EXPECT_EQ(1u, host_settings.size());
Tarun Bansal593790112018-03-20 04:53:341715
1716 // Clear settings.
1717 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451718 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansala61f0f62017-10-24 23:53:051719}
1720
1721// Ensure that when the JavaScript is blocked, persisted client hints are not
1722// attached to the request headers.
Maks Orlovichf0a2eed2020-05-02 20:08:211723IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala61f0f62017-10-24 23:53:051724 ClientHintsLifetimeNotAttachedJavaScriptBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211725 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:051726
Tarun Bansala61f0f62017-10-24 23:53:051727 base::HistogramTester histogram_tester;
1728 ContentSettingsForOneType host_settings;
1729
1730 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451731 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansala61f0f62017-10-24 23:53:051732 &host_settings);
1733 EXPECT_EQ(0u, host_settings.size());
1734
1735 // Fetching accept_ch_with_lifetime_url() should persist the request for
1736 // client hints.
Tarun Bansal9a7051f2018-07-10 18:30:051737 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansala61f0f62017-10-24 23:53:051738 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1739 content::FetchHistogramsFromChildProcesses();
1740 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Mike West2fddeeb72019-02-15 11:29:481741 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461742 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051743
Yoav Weissd33bacb2020-03-12 06:42:211744 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1745 expected_client_hints_number, 1);
Tarun Bansala61f0f62017-10-24 23:53:051746 // accept_ch_with_lifetime_url() tries to set client hints persist duration to
1747 // 3600 seconds.
1748 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
1749 3600 * 1000, 1);
1750 base::RunLoop().RunUntilIdle();
1751
1752 // Clients hints preferences for one origin should be persisted.
1753 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451754 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansala61f0f62017-10-24 23:53:051755 &host_settings);
1756 EXPECT_EQ(1u, host_settings.size());
1757
Changwan Ryu434c3a32019-07-30 23:42:581758 // Block JavaScript via WebPreferences: Client hints should not be attached.
1759 SetJsEnabledForActiveView(false);
1760
1761 SetClientHintExpectationsOnMainFrame(false);
1762 SetClientHintExpectationsOnSubresources(false);
1763 ui_test_utils::NavigateToURL(browser(),
1764 without_accept_ch_without_lifetime_url());
1765
1766 EXPECT_EQ(0u, count_client_hints_headers_seen());
1767 VerifyContentSettingsNotNotified();
1768 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461769 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Changwan Ryu434c3a32019-07-30 23:42:581770
1771 SetJsEnabledForActiveView(true);
1772
1773 // Block JavaScript via ContentSetting: Client hints should not be attached.
Tarun Bansala61f0f62017-10-24 23:53:051774 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1775 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
Darin Fisher42f5e7d2019-10-30 07:15:451776 GURL(), ContentSettingsType::JAVASCRIPT,
Tarun Bansala61f0f62017-10-24 23:53:051777 std::string(), CONTENT_SETTING_BLOCK);
1778 ui_test_utils::NavigateToURL(browser(),
1779 without_accept_ch_without_lifetime_url());
1780 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansalc211d8b2018-03-19 19:21:581781 VerifyContentSettingsNotNotified();
Mike West2fddeeb72019-02-15 11:29:481782 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461783 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051784
Changwan Ryu434c3a32019-07-30 23:42:581785 // Allow JavaScript: Client hints should now be attached.
Tarun Bansala61f0f62017-10-24 23:53:051786 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1787 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
Darin Fisher42f5e7d2019-10-30 07:15:451788 GURL(), ContentSettingsType::JAVASCRIPT,
Tarun Bansala61f0f62017-10-24 23:53:051789 std::string(), CONTENT_SETTING_ALLOW);
1790
Tarun Bansal229647bd002018-02-27 17:33:361791 SetClientHintExpectationsOnMainFrame(true);
1792 SetClientHintExpectationsOnSubresources(true);
Tarun Bansala61f0f62017-10-24 23:53:051793 ui_test_utils::NavigateToURL(browser(),
1794 without_accept_ch_without_lifetime_url());
Tarun Bansal79df868e2018-03-20 23:01:361795
Mike West2fddeeb72019-02-15 11:29:481796 // The user agent hint is attached to all three requests:
1797 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461798 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481799
Yoav Weissd33bacb2020-03-12 06:42:211800 // Expected number of hints attached to the image request, and the same number
1801 // to the main frame request.
1802 EXPECT_EQ(expected_client_hints_number * 2,
1803 count_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051804
1805 // Clear settings.
1806 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451807 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansala61f0f62017-10-24 23:53:051808}
1809
Tarun Bansal73502f92019-04-16 21:21:191810// Test that if the content settings are malformed, then the browser does not
1811// crash.
1812IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
1813 ClientHintsMalformedContentSettings) {
1814 ContentSettingsForOneType client_hints_settings;
1815 HostContentSettingsMap* host_content_settings_map =
1816 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
1817
1818 // Add setting for the host.
1819 std::unique_ptr<base::ListValue> expiration_times_list =
1820 std::make_unique<base::ListValue>();
1821 expiration_times_list->AppendInteger(42 /* client hint value */);
1822 auto expiration_times_dictionary = std::make_unique<base::DictionaryValue>();
1823 expiration_times_dictionary->SetList("client_hints",
1824 std::move(expiration_times_list));
Aaron Tagliaboschi3c96a682019-10-29 18:10:281825 expiration_times_dictionary->SetDouble(
1826 "expiration_time",
1827 (base::Time::Now() + base::TimeDelta::FromDays(1)).ToDoubleT());
Tarun Bansal73502f92019-04-16 21:21:191828 host_content_settings_map->SetWebsiteSettingDefaultScope(
1829 without_accept_ch_without_lifetime_url(), GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451830 ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal73502f92019-04-16 21:21:191831 std::make_unique<base::Value>(expiration_times_dictionary->Clone()));
1832
1833 // Reading the settings should now return one setting.
1834 host_content_settings_map->GetSettingsForOneType(
Darin Fisher42f5e7d2019-10-30 07:15:451835 ContentSettingsType::CLIENT_HINTS, std::string(), &client_hints_settings);
Tarun Bansal73502f92019-04-16 21:21:191836 EXPECT_EQ(1U, client_hints_settings.size());
1837
1838 SetClientHintExpectationsOnMainFrame(false);
1839 SetClientHintExpectationsOnSubresources(false);
1840 ui_test_utils::NavigateToURL(browser(),
1841 without_accept_ch_without_lifetime_url());
1842}
1843
Tarun Bansal229647bd002018-02-27 17:33:361844// Ensure that when the JavaScript is blocked, client hints requested using
Tarun Bansal3f343d7c2018-03-02 18:48:001845// Accept-CH are not attached to the request headers for subresources.
Tarun Bansal9a7051f2018-07-10 18:30:051846IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal229647bd002018-02-27 17:33:361847 ClientHintsNoLifetimeScriptNotAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:051848 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1849 : accept_ch_with_lifetime_url();
1850
Tarun Bansal1965b042017-09-07 04:59:191851 base::HistogramTester histogram_tester;
1852 ContentSettingsForOneType host_settings;
1853
1854 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451855 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal1965b042017-09-07 04:59:191856 &host_settings);
1857 EXPECT_EQ(0u, host_settings.size());
1858
Tarun Bansal3f343d7c2018-03-02 18:48:001859 // Block the Javascript: Client hints should not be attached.
1860 SetClientHintExpectationsOnSubresources(false);
Tarun Bansal229647bd002018-02-27 17:33:361861 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1862 ->SetContentSettingDefaultScope(
1863 accept_ch_without_lifetime_img_localhost(), GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451864 ContentSettingsType::JAVASCRIPT, std::string(),
Tarun Bansal229647bd002018-02-27 17:33:361865 CONTENT_SETTING_BLOCK);
1866 ui_test_utils::NavigateToURL(browser(),
1867 accept_ch_without_lifetime_img_localhost());
Mike West2fddeeb72019-02-15 11:29:481868 EXPECT_EQ(0u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461869 EXPECT_EQ(0u, count_ua_mobile_client_hints_headers_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001870 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361871 EXPECT_EQ(1u, third_party_request_count_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001872 EXPECT_EQ(0u, third_party_client_hints_count_seen());
Tarun Bansal1965b042017-09-07 04:59:191873
Tarun Bansal3f343d7c2018-03-02 18:48:001874 // Allow the Javascript: Client hints should now be attached.
Tarun Bansal229647bd002018-02-27 17:33:361875 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1876 ->SetContentSettingDefaultScope(
1877 accept_ch_without_lifetime_img_localhost(), GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451878 ContentSettingsType::JAVASCRIPT, std::string(),
Tarun Bansal229647bd002018-02-27 17:33:361879 CONTENT_SETTING_ALLOW);
Tarun Bansal1965b042017-09-07 04:59:191880
Tarun Bansal229647bd002018-02-27 17:33:361881 SetClientHintExpectationsOnSubresources(true);
1882 ui_test_utils::NavigateToURL(browser(),
1883 accept_ch_without_lifetime_img_localhost());
Tarun Bansal3f343d7c2018-03-02 18:48:001884
Mike West2fddeeb72019-02-15 11:29:481885 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461886 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:211887 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361888 EXPECT_EQ(2u, third_party_request_count_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461889 EXPECT_EQ(2u, third_party_client_hints_count_seen());
Tarun Bansalc211d8b2018-03-19 19:21:581890 VerifyContentSettingsNotNotified();
Tarun Bansal1965b042017-09-07 04:59:191891
Tarun Bansal229647bd002018-02-27 17:33:361892 // Clear settings.
1893 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451894 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansal1965b042017-09-07 04:59:191895
Tarun Bansal229647bd002018-02-27 17:33:361896 // Block the Javascript again: Client hints should not be attached.
Tarun Bansal3f343d7c2018-03-02 18:48:001897 SetClientHintExpectationsOnSubresources(false);
Tarun Bansal229647bd002018-02-27 17:33:361898 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1899 ->SetContentSettingDefaultScope(
1900 accept_ch_without_lifetime_img_localhost(), GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451901 ContentSettingsType::JAVASCRIPT, std::string(),
Tarun Bansal229647bd002018-02-27 17:33:361902 CONTENT_SETTING_BLOCK);
1903 ui_test_utils::NavigateToURL(browser(),
1904 accept_ch_without_lifetime_img_localhost());
Mike West2fddeeb72019-02-15 11:29:481905 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461906 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:211907 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361908 EXPECT_EQ(3u, third_party_request_count_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461909 EXPECT_EQ(2u, third_party_client_hints_count_seen());
Tarun Bansal593790112018-03-20 04:53:341910
1911 // Clear settings.
1912 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451913 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansal229647bd002018-02-27 17:33:361914}
1915
Tarun Bansala0c1fc32018-10-03 16:14:521916// Ensure that when the cookies is blocked, client hints are attached to the
Tarun Bansal3f343d7c2018-03-02 18:48:001917// request headers.
Tarun Bansal9a7051f2018-07-10 18:30:051918IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521919 ClientHintsLifetimeCookiesNotAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:051920 const GURL gurl = GetParam()
1921 ? http_equiv_accept_ch_without_lifetime_img_localhost()
1922 : accept_ch_without_lifetime_img_localhost();
1923
Tarun Bansal229647bd002018-02-27 17:33:361924 base::HistogramTester histogram_tester;
1925 ContentSettingsForOneType host_settings;
1926 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
1927 CookieSettingsFactory::GetForProfile(browser()->profile());
1928
Tarun Bansal1965b042017-09-07 04:59:191929 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451930 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal1965b042017-09-07 04:59:191931 &host_settings);
1932 EXPECT_EQ(0u, host_settings.size());
1933
Tarun Bansal229647bd002018-02-27 17:33:361934 // Block cookies.
1935 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansal9a7051f2018-07-10 18:30:051936 ->SetContentSettingDefaultScope(gurl, GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451937 ContentSettingsType::COOKIES,
Tarun Bansal9a7051f2018-07-10 18:30:051938 std::string(), CONTENT_SETTING_BLOCK);
Tarun Bansal229647bd002018-02-27 17:33:361939 base::RunLoop().RunUntilIdle();
1940
Tarun Bansal229647bd002018-02-27 17:33:361941 SetClientHintExpectationsOnSubresources(true);
Tarun Bansal9a7051f2018-07-10 18:30:051942 ui_test_utils::NavigateToURL(browser(), gurl);
Mike West2fddeeb72019-02-15 11:29:481943 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461944 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:211945 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansala0c1fc32018-10-03 16:14:521946 EXPECT_EQ(1u, third_party_request_count_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461947 EXPECT_EQ(2u, third_party_client_hints_count_seen());
Tarun Bansal593790112018-03-20 04:53:341948
1949 // Clear settings.
1950 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451951 ->ClearSettingsForOneType(ContentSettingsType::COOKIES);
Tarun Bansal1965b042017-09-07 04:59:191952}
1953
Tarun Bansal3ce0ca42018-06-25 22:52:221954// Verify that client hints are sent in the incognito profiles, and server
1955// client hint opt-ins are honored within the incognito profile.
Maks Orlovichf0a2eed2020-05-02 20:08:211956IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal3ce0ca42018-06-25 22:52:221957 ClientHintsLifetimeFollowedByNoClientHintIncognito) {
Maks Orlovichf0a2eed2020-05-02 20:08:211958 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:051959
Tarun Bansal3ce0ca42018-06-25 22:52:221960 base::HistogramTester histogram_tester;
1961 Browser* incognito = CreateIncognitoBrowser();
1962 ContentSettingsForOneType host_settings;
1963
1964 HostContentSettingsMapFactory::GetForProfile(incognito->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451965 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal3ce0ca42018-06-25 22:52:221966 &host_settings);
1967 EXPECT_EQ(0u, host_settings.size());
1968
Tarun Bansal9a7051f2018-07-10 18:30:051969 // Fetching |gurl| should persist the request for client hints.
1970 ui_test_utils::NavigateToURL(incognito, gurl);
Tarun Bansal3ce0ca42018-06-25 22:52:221971
1972 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1973
1974 content::FetchHistogramsFromChildProcesses();
1975 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1976
Yoav Weissd33bacb2020-03-12 06:42:211977 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1978 expected_client_hints_number, 1);
Tarun Bansal3ce0ca42018-06-25 22:52:221979 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
1980 // seconds.
1981 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
1982 3600 * 1000, 1);
1983 base::RunLoop().RunUntilIdle();
1984
1985 // Clients hints preferences for one origin should be persisted.
1986 HostContentSettingsMapFactory::GetForProfile(incognito->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451987 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS, std::string(),
Tarun Bansal3ce0ca42018-06-25 22:52:221988 &host_settings);
1989 EXPECT_EQ(1u, host_settings.size());
1990
1991 SetClientHintExpectationsOnMainFrame(true);
1992 SetClientHintExpectationsOnSubresources(true);
1993 ui_test_utils::NavigateToURL(incognito,
1994 without_accept_ch_without_lifetime_url());
1995
Mike West2fddeeb72019-02-15 11:29:481996 // The user agent hint is attached to all three requests:
1997 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461998 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481999
Yoav Weissd33bacb2020-03-12 06:42:212000 // Expected number of hints attached to the image request, and the same number
2001 // to the main frame request.
2002 EXPECT_EQ(expected_client_hints_number * 2,
2003 count_client_hints_headers_seen());
Tarun Bansal3ce0ca42018-06-25 22:52:222004
2005 // Navigate using regular profile. Client hints should not be send.
2006 SetClientHintExpectationsOnMainFrame(false);
2007 SetClientHintExpectationsOnSubresources(false);
2008 ui_test_utils::NavigateToURL(browser(),
2009 without_accept_ch_without_lifetime_url());
2010
Mike West2fddeeb72019-02-15 11:29:482011 // The user agent hint is attached to the two new requests.
2012 EXPECT_EQ(5u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462013 EXPECT_EQ(5u, count_ua_mobile_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:482014
2015 // No additional hints are sent.
Yoav Weissd33bacb2020-03-12 06:42:212016 EXPECT_EQ(expected_client_hints_number * 2,
2017 count_client_hints_headers_seen());
Tarun Bansal3ce0ca42018-06-25 22:52:222018}
Tarun Bansalbef6d652018-10-02 18:41:012019
2020class ClientHintsWebHoldbackBrowserTest : public ClientHintsBrowserTest {
2021 public:
2022 ClientHintsWebHoldbackBrowserTest() : ClientHintsBrowserTest() {
2023 ConfigureHoldbackExperiment();
2024 }
2025
2026 net::EffectiveConnectionType web_effective_connection_type_override() const {
2027 return web_effective_connection_type_override_;
2028 }
2029
Mike West2fddeeb72019-02-15 11:29:482030 std::unique_ptr<base::FeatureList> EnabledFeatures() override {
Tarun Bansalbef6d652018-10-02 18:41:012031 base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
2032 const std::string kTrialName = "TrialFoo";
2033 const std::string kGroupName = "GroupFoo"; // Value not used
2034
2035 scoped_refptr<base::FieldTrial> trial =
2036 base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
2037
2038 std::map<std::string, std::string> params;
2039
2040 params["web_effective_connection_type_override"] =
2041 net::GetNameForEffectiveConnectionType(
2042 web_effective_connection_type_override_);
Mike West2fddeeb72019-02-15 11:29:482043 EXPECT_TRUE(
Tarun Bansalbef6d652018-10-02 18:41:012044 base::FieldTrialParamAssociator::GetInstance()
2045 ->AssociateFieldTrialParams(kTrialName, kGroupName, params));
2046
2047 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
Mike West2fddeeb72019-02-15 11:29:482048 feature_list->InitializeFromCommandLine("UserAgentClientHint", "");
Tarun Bansalbef6d652018-10-02 18:41:012049 feature_list->RegisterFieldTrialOverride(
2050 features::kNetworkQualityEstimatorWebHoldback.name,
2051 base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
Mike West2fddeeb72019-02-15 11:29:482052 return feature_list;
Tarun Bansalbef6d652018-10-02 18:41:012053 }
2054
Mike West2fddeeb72019-02-15 11:29:482055 private:
2056 void ConfigureHoldbackExperiment() {}
2057
Tarun Bansalbef6d652018-10-02 18:41:012058 const net::EffectiveConnectionType web_effective_connection_type_override_ =
2059 net::EFFECTIVE_CONNECTION_TYPE_3G;
Tarun Bansalbef6d652018-10-02 18:41:012060};
2061
2062// Make sure that when NetInfo holdback experiment is enabled, the NetInfo APIs
2063// and client hints return the overridden values. Verify that the client hints
2064// are overridden on both main frame and subresource requests.
2065IN_PROC_BROWSER_TEST_F(ClientHintsWebHoldbackBrowserTest,
2066 EffectiveConnectionTypeChangeNotified) {
2067 SetExpectedEffectiveConnectionType(web_effective_connection_type_override());
2068
2069 SetClientHintExpectationsOnMainFrame(false);
2070 SetClientHintExpectationsOnSubresources(true);
2071
2072 base::RunLoop().RunUntilIdle();
2073
2074 EXPECT_TRUE(embedded_test_server()->Start());
2075 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
2076 EXPECT_EQ(0u, count_client_hints_headers_seen());
2077 EXPECT_EQ(0u, third_party_request_count_seen());
2078 EXPECT_EQ(0u, third_party_client_hints_count_seen());
2079
2080 SetClientHintExpectationsOnMainFrame(true);
2081 SetClientHintExpectationsOnSubresources(true);
2082 ui_test_utils::NavigateToURL(
2083 browser(), accept_ch_without_lifetime_with_subresource_url());
2084 base::RunLoop().RunUntilIdle();
2085 content::FetchHistogramsFromChildProcesses();
2086 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
2087
Mike West2fddeeb72019-02-15 11:29:482088 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462089 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:212090 EXPECT_EQ(expected_client_hints_number * 2,
2091 count_client_hints_headers_seen());
Tarun Bansalbef6d652018-10-02 18:41:012092 EXPECT_EQ(0u, third_party_request_count_seen());
2093 EXPECT_EQ(0u, third_party_client_hints_count_seen());
2094}