blob: 4f960e343f1a95b696e3e6ebecaeeafae84c5db1 [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
Tarun Bansal229647bd002018-02-27 17:33:367#include "base/bind.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:168#include "base/command_line.h"
Gabriel Charetteb71eec892017-09-14 22:52:569#include "base/run_loop.h"
Tarun Bansal6bf54302017-10-02 07:39:1410#include "base/stl_util.h"
Devlin Cronin626d80c2018-06-01 01:08:3611#include "base/test/metrics/histogram_tester.h"
Tarun Bansal5c28afb2018-03-17 02:55:2012#include "build/build_config.h"
Tarun Bansala61f0f62017-10-24 23:53:0513#include "chrome/browser/content_settings/cookie_settings_factory.h"
Tarun Bansal1965b042017-09-07 04:59:1914#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
Tarun Bansalc211d8b2018-03-19 19:21:5815#include "chrome/browser/content_settings/tab_specific_content_settings.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1616#include "chrome/browser/metrics/subprocess_metrics_provider.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1617#include "chrome/browser/profiles/profile.h"
Tarun Bansal1965b042017-09-07 04:59:1918#include "chrome/browser/ui/browser.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1619#include "chrome/test/base/in_process_browser_test.h"
20#include "chrome/test/base/ui_test_utils.h"
Tarun Bansala61f0f62017-10-24 23:53:0521#include "components/content_settings/core/browser/cookie_settings.h"
Tarun Bansal1965b042017-09-07 04:59:1922#include "components/content_settings/core/browser/host_content_settings_map.h"
Tarun Bansala61f0f62017-10-24 23:53:0523#include "components/content_settings/core/common/pref_names.h"
24#include "components/prefs/pref_service.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1625#include "content/public/browser/browser_thread.h"
26#include "content/public/common/content_switches.h"
27#include "content/public/test/browser_test_utils.h"
28#include "content/public/test/test_utils.h"
Tarun Bansal229647bd002018-02-27 17:33:3629#include "content/public/test/url_loader_interceptor.h"
30#include "net/dns/mock_host_resolver.h"
31#include "net/http/http_request_headers.h"
Tarun Bansal7f3fe8c2018-04-06 22:37:4732#include "net/nqe/effective_connection_type.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1633#include "net/test/embedded_test_server/embedded_test_server.h"
Tarun Bansal1965b042017-09-07 04:59:1934#include "net/test/embedded_test_server/http_request.h"
Tarun Bansal229647bd002018-02-27 17:33:3635#include "net/test/embedded_test_server/http_response.h"
Tarun Bansal74e189d2018-05-07 19:07:3536#include "services/network/public/cpp/cors/cors.h"
Tarun Bansalceab9592018-05-01 18:57:3537#include "services/network/public/cpp/features.h"
Tarun Bansal7f3fe8c2018-04-06 22:37:4738#include "services/network/public/cpp/network_switches.h"
Blink Reformata30d4232018-04-07 15:31:0639#include "third_party/blink/public/common/client_hints/client_hints.h"
Tarun Bansal229647bd002018-02-27 17:33:3640
41namespace {
42
43// An interceptor that records count of fetches and client hint headers for
44// requests to https://foo.com/non-existing-image.jpg.
Jay Civelli1ff872d2018-03-09 21:52:1645class ThirdPartyURLLoaderInterceptor {
Tarun Bansal229647bd002018-02-27 17:33:3646 public:
Jay Civelli1ff872d2018-03-09 21:52:1647 explicit ThirdPartyURLLoaderInterceptor(const GURL intercepted_url)
48 : intercepted_url_(intercepted_url),
49 interceptor_(base::BindRepeating(
50 &ThirdPartyURLLoaderInterceptor::InterceptURLRequest,
51 base::Unretained(this))) {}
Tarun Bansal229647bd002018-02-27 17:33:3652
Jay Civelli1ff872d2018-03-09 21:52:1653 ~ThirdPartyURLLoaderInterceptor() = default;
Tarun Bansal229647bd002018-02-27 17:33:3654
55 size_t request_count_seen() const { return request_count_seen_; }
56
57 size_t client_hints_count_seen() const { return client_hints_count_seen_; }
58
59 private:
Jay Civelli1ff872d2018-03-09 21:52:1660 bool InterceptURLRequest(
61 content::URLLoaderInterceptor::RequestParams* params) {
62 if (params->url_request.url != intercepted_url_)
63 return false;
Tarun Bansal229647bd002018-02-27 17:33:3664
Jay Civelli1ff872d2018-03-09 21:52:1665 request_count_seen_++;
Tarun Bansalf9cf9892018-04-06 04:38:0166 for (size_t i = 0; i < blink::kClientHintsHeaderMappingCount; ++i) {
67 if (params->url_request.headers.HasHeader(
68 blink::kClientHintsHeaderMapping[i])) {
69 client_hints_count_seen_++;
70 }
Tarun Bansal5c28afb2018-03-17 02:55:2071 }
Jay Civelli1ff872d2018-03-09 21:52:1672 return false;
73 }
Tarun Bansal229647bd002018-02-27 17:33:3674
Jay Civelli1ff872d2018-03-09 21:52:1675 GURL intercepted_url_;
76
77 size_t request_count_seen_ = 0u;
78
79 size_t client_hints_count_seen_ = 0u;
80
81 content::URLLoaderInterceptor interceptor_;
82
83 DISALLOW_COPY_AND_ASSIGN(ThirdPartyURLLoaderInterceptor);
Tarun Bansal229647bd002018-02-27 17:33:3684};
85
Tarun Bansal62efba12018-05-04 22:58:3586// Returns true only if |header_value| satisfies ABNF: 1*DIGIT [ "." 1*DIGIT ]
87bool IsSimilarToDoubleABNF(const std::string& header_value) {
88 if (header_value.empty())
89 return false;
90 char first_char = header_value.at(0);
91 if (!isdigit(first_char))
92 return false;
93
94 bool period_found = false;
95 bool digit_found_after_period = false;
96 for (char ch : header_value) {
97 if (isdigit(ch)) {
98 if (period_found) {
99 digit_found_after_period = true;
100 }
101 continue;
102 }
103 if (ch == '.') {
104 if (period_found)
105 return false;
106 period_found = true;
107 continue;
108 }
109 return false;
110 }
111 if (period_found)
112 return digit_found_after_period;
113 return true;
114}
115
116// Returns true only if |header_value| satisfies ABNF: 1*DIGIT
117bool IsSimilarToIntABNF(const std::string& header_value) {
118 if (header_value.empty())
119 return false;
120
121 for (char ch : header_value) {
122 if (!isdigit(ch))
123 return false;
124 }
125 return true;
126}
127
Tarun Bansal229647bd002018-02-27 17:33:36128} // namespace
Tarun Bansal0b8b7afd2017-08-25 03:52:16129
130class ClientHintsBrowserTest : public InProcessBrowserTest {
131 public:
132 ClientHintsBrowserTest()
Tarun Bansal3b330b02017-11-09 19:03:14133 : http_server_(net::EmbeddedTestServer::TYPE_HTTP),
134 https_server_(net::EmbeddedTestServer::TYPE_HTTPS),
Tarun Bansal229647bd002018-02-27 17:33:36135 expect_client_hints_on_main_frame_(false),
136 expect_client_hints_on_subresources_(false),
137 count_client_hints_headers_seen_(0),
138 request_interceptor_(nullptr) {
Tarun Bansal3b330b02017-11-09 19:03:14139 http_server_.ServeFilesFromSourceDirectory("chrome/test/data/client_hints");
Tarun Bansal0b8b7afd2017-08-25 03:52:16140 https_server_.ServeFilesFromSourceDirectory(
141 "chrome/test/data/client_hints");
Tarun Bansal1965b042017-09-07 04:59:19142
Tarun Bansal3b330b02017-11-09 19:03:14143 http_server_.RegisterRequestMonitor(
144 base::Bind(&ClientHintsBrowserTest::MonitorResourceRequest,
145 base::Unretained(this)));
Tarun Bansal1965b042017-09-07 04:59:19146 https_server_.RegisterRequestMonitor(
147 base::Bind(&ClientHintsBrowserTest::MonitorResourceRequest,
148 base::Unretained(this)));
149
Tarun Bansal3b330b02017-11-09 19:03:14150 EXPECT_TRUE(http_server_.Start());
Tarun Bansal0b8b7afd2017-08-25 03:52:16151 EXPECT_TRUE(https_server_.Start());
152
Tarun Bansal3b330b02017-11-09 19:03:14153 accept_ch_with_lifetime_http_local_url_ =
154 http_server_.GetURL("/accept_ch_with_lifetime.html");
155 EXPECT_TRUE(accept_ch_with_lifetime_http_local_url_.SchemeIsHTTPOrHTTPS());
156 EXPECT_FALSE(
157 accept_ch_with_lifetime_http_local_url_.SchemeIsCryptographic());
158
Tarun Bansal1965b042017-09-07 04:59:19159 accept_ch_with_lifetime_url_ =
160 https_server_.GetURL("/accept_ch_with_lifetime.html");
161 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsHTTPOrHTTPS());
162 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal0b8b7afd2017-08-25 03:52:16163
Tarun Bansal1965b042017-09-07 04:59:19164 accept_ch_without_lifetime_url_ =
165 https_server_.GetURL("/accept_ch_without_lifetime.html");
166 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsHTTPOrHTTPS());
167 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsCryptographic());
168
169 without_accept_ch_without_lifetime_url_ =
170 https_server_.GetURL("/without_accept_ch_without_lifetime.html");
171 EXPECT_TRUE(without_accept_ch_without_lifetime_url_.SchemeIsHTTPOrHTTPS());
172 EXPECT_TRUE(
173 without_accept_ch_without_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal3b330b02017-11-09 19:03:14174
175 without_accept_ch_without_lifetime_local_url_ =
176 http_server_.GetURL("/without_accept_ch_without_lifetime.html");
177 EXPECT_TRUE(
178 without_accept_ch_without_lifetime_local_url_.SchemeIsHTTPOrHTTPS());
179 EXPECT_FALSE(
180 without_accept_ch_without_lifetime_local_url_.SchemeIsCryptographic());
Tarun Bansaladd5e1812018-02-09 19:07:58181
182 without_accept_ch_without_lifetime_img_localhost_ = https_server_.GetURL(
183 "/without_accept_ch_without_lifetime_img_localhost.html");
184 without_accept_ch_without_lifetime_img_foo_com_ = https_server_.GetURL(
185 "/without_accept_ch_without_lifetime_img_foo_com.html");
186 accept_ch_without_lifetime_with_iframe_url_ =
187 https_server_.GetURL("/accept_ch_without_lifetime_with_iframe.html");
Tarun Bansal229647bd002018-02-27 17:33:36188 accept_ch_without_lifetime_img_localhost_ =
189 https_server_.GetURL("/accept_ch_without_lifetime_img_localhost.html");
Tarun Bansal0b8b7afd2017-08-25 03:52:16190 }
191
192 ~ClientHintsBrowserTest() override {}
193
194 void SetUpOnMainThread() override {
Tarun Bansal229647bd002018-02-27 17:33:36195 host_resolver()->AddRule("*", "127.0.0.1");
Tarun Bansal229647bd002018-02-27 17:33:36196
Jay Civelli1ff872d2018-03-09 21:52:16197 request_interceptor_ = std::make_unique<ThirdPartyURLLoaderInterceptor>(
198 GURL("https://foo.com/non-existing-image.jpg"));
Tarun Bansal229647bd002018-02-27 17:33:36199 base::RunLoop().RunUntilIdle();
Tarun Bansal0b8b7afd2017-08-25 03:52:16200 }
201
Jay Civelli1ff872d2018-03-09 21:52:16202 void TearDownOnMainThread() override { request_interceptor_.reset(); }
203
Tarun Bansal0b8b7afd2017-08-25 03:52:16204 void SetUpCommandLine(base::CommandLine* cmd) override {
205 cmd->AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures);
Tarun Bansal7f3fe8c2018-04-06 22:37:47206 cmd->AppendSwitchASCII(network::switches::kForceEffectiveConnectionType,
207 net::kEffectiveConnectionType2G);
Tarun Bansal0b8b7afd2017-08-25 03:52:16208 }
209
Tarun Bansal229647bd002018-02-27 17:33:36210 void SetClientHintExpectationsOnMainFrame(bool expect_client_hints) {
211 expect_client_hints_on_main_frame_ = expect_client_hints;
Tarun Bansal1965b042017-09-07 04:59:19212 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16213
Tarun Bansal229647bd002018-02-27 17:33:36214 void SetClientHintExpectationsOnSubresources(bool expect_client_hints) {
215 expect_client_hints_on_subresources_ = expect_client_hints;
Tarun Bansala61f0f62017-10-24 23:53:05216 }
217
Tarun Bansalc211d8b2018-03-19 19:21:58218 // Verify that the user is not notified that cookies or JavaScript were
219 // blocked on the webpage due to the checks done by client hints.
220 void VerifyContentSettingsNotNotified() const {
221 content::WebContents* web_contents =
222 browser()->tab_strip_model()->GetActiveWebContents();
223 EXPECT_FALSE(TabSpecificContentSettings::FromWebContents(web_contents)
224 ->IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
225
226 EXPECT_FALSE(TabSpecificContentSettings::FromWebContents(web_contents)
227 ->IsContentBlocked(CONTENT_SETTINGS_TYPE_JAVASCRIPT));
228 }
229
Tarun Bansal3b330b02017-11-09 19:03:14230 const GURL& accept_ch_with_lifetime_http_local_url() const {
231 return accept_ch_with_lifetime_http_local_url_;
232 }
233
Tarun Bansal1965b042017-09-07 04:59:19234 // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
235 // headers.
236 const GURL& accept_ch_with_lifetime_url() const {
237 return accept_ch_with_lifetime_url_;
238 }
239
240 // A URL whose response headers include only Accept-CH header.
241 const GURL& accept_ch_without_lifetime_url() const {
242 return accept_ch_without_lifetime_url_;
243 }
244
245 // A URL whose response headers do not include either Accept-CH or
246 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
247 const GURL& without_accept_ch_without_lifetime_url() const {
248 return without_accept_ch_without_lifetime_url_;
249 }
250
Tarun Bansal3b330b02017-11-09 19:03:14251 // A URL whose response headers do not include either Accept-CH or
252 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
253 const GURL& without_accept_ch_without_lifetime_local_url() const {
254 return without_accept_ch_without_lifetime_local_url_;
255 }
256
Tarun Bansaladd5e1812018-02-09 19:07:58257 // A URL whose response headers do not include either Accept-CH or
258 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
259 // from localhost.
260 const GURL& without_accept_ch_without_lifetime_img_localhost() const {
261 return without_accept_ch_without_lifetime_img_localhost_;
262 }
263
264 // A URL whose response headers do not include either Accept-CH or
265 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
266 // from foo.com.
267 const GURL& without_accept_ch_without_lifetime_img_foo_com() const {
268 return without_accept_ch_without_lifetime_img_foo_com_;
269 }
270
271 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
272 // headers. The response loads accept_ch_with_lifetime_url() in an iframe.
273 const GURL& accept_ch_without_lifetime_with_iframe_url() const {
274 return accept_ch_without_lifetime_with_iframe_url_;
275 }
276
Tarun Bansal229647bd002018-02-27 17:33:36277 // A URL whose response headers includes only Accept-CH header. Navigating to
278 // this URL also fetches two images: One from the localhost, and one from
279 // foo.com.
280 const GURL& accept_ch_without_lifetime_img_localhost() const {
281 return accept_ch_without_lifetime_img_localhost_;
282 }
283
Tarun Bansal1965b042017-09-07 04:59:19284 size_t count_client_hints_headers_seen() const {
285 return count_client_hints_headers_seen_;
286 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16287
Tarun Bansal229647bd002018-02-27 17:33:36288 size_t third_party_request_count_seen() const {
289 return request_interceptor_->request_count_seen();
290 }
291
292 size_t third_party_client_hints_count_seen() const {
293 return request_interceptor_->client_hints_count_seen();
294 }
295
Tarun Bansalea0d8262018-05-21 16:11:50296 base::test::ScopedFeatureList scoped_feature_list_;
297
Tarun Bansal0b8b7afd2017-08-25 03:52:16298 private:
Tarun Bansal1965b042017-09-07 04:59:19299 // Called by |https_server_|.
300 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
Tarun Bansal6bf54302017-10-02 07:39:14301 bool is_main_frame_navigation =
302 request.GetURL().spec().find(".html") != std::string::npos;
303
Tarun Bansal229647bd002018-02-27 17:33:36304 if (is_main_frame_navigation) {
Tarun Bansalf9cf9892018-04-06 04:38:01305 VerifyClientHintsReceived(expect_client_hints_on_main_frame_, request);
Tarun Bansal5c28afb2018-03-17 02:55:20306 if (expect_client_hints_on_main_frame_) {
307 double value = 0.0;
308 EXPECT_TRUE(base::StringToDouble(
309 request.headers.find("device-memory")->second, &value));
310 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35311 EXPECT_TRUE(IsSimilarToDoubleABNF(
312 request.headers.find("device-memory")->second));
Tarun Bansal44ad96882018-03-28 17:47:42313 main_frame_device_memory_observed_ = value;
Tarun Bansal5c28afb2018-03-17 02:55:20314
315 EXPECT_TRUE(
316 base::StringToDouble(request.headers.find("dpr")->second, &value));
317 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35318 EXPECT_TRUE(IsSimilarToDoubleABNF(request.headers.find("dpr")->second));
Tarun Bansal44ad96882018-03-28 17:47:42319 main_frame_dpr_observed_ = value;
320
Tarun Bansal5c28afb2018-03-17 02:55:20321 EXPECT_TRUE(base::StringToDouble(
322 request.headers.find("viewport-width")->second, &value));
Tarun Bansal62efba12018-05-04 22:58:35323 EXPECT_TRUE(
324 IsSimilarToIntABNF(request.headers.find("viewport-width")->second));
Tarun Bansal79df868e2018-03-20 23:01:36325#if !defined(OS_ANDROID)
Tarun Bansal5c28afb2018-03-17 02:55:20326 EXPECT_LT(0.0, value);
Tarun Bansal79df868e2018-03-20 23:01:36327#else
328 EXPECT_EQ(980, value);
Tarun Bansal5c28afb2018-03-17 02:55:20329#endif
Tarun Bansal44ad96882018-03-28 17:47:42330 main_frame_viewport_width_observed_ = value;
Tarun Bansal7f3fe8c2018-04-06 22:37:47331 VerifyNetworkQualityClientHints(request);
Tarun Bansal5c28afb2018-03-17 02:55:20332 }
Tarun Bansala61f0f62017-10-24 23:53:05333 }
Tarun Bansal6bf54302017-10-02 07:39:14334
Tarun Bansal229647bd002018-02-27 17:33:36335 if (!is_main_frame_navigation) {
Tarun Bansalf9cf9892018-04-06 04:38:01336 VerifyClientHintsReceived(expect_client_hints_on_subresources_, request);
Tarun Bansal5c28afb2018-03-17 02:55:20337
338 if (expect_client_hints_on_subresources_) {
339 double value = 0.0;
340 EXPECT_TRUE(base::StringToDouble(
341 request.headers.find("device-memory")->second, &value));
342 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35343 EXPECT_TRUE(IsSimilarToDoubleABNF(
344 request.headers.find("device-memory")->second));
Tarun Bansal44ad96882018-03-28 17:47:42345 if (main_frame_device_memory_observed_ > 0) {
346 EXPECT_EQ(main_frame_device_memory_observed_, value);
347 }
Tarun Bansal5c28afb2018-03-17 02:55:20348
349 EXPECT_TRUE(
350 base::StringToDouble(request.headers.find("dpr")->second, &value));
351 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35352 EXPECT_TRUE(IsSimilarToDoubleABNF(request.headers.find("dpr")->second));
Tarun Bansal44ad96882018-03-28 17:47:42353 if (main_frame_dpr_observed_ > 0) {
354 EXPECT_EQ(main_frame_dpr_observed_, value);
355 }
Tarun Bansal5c28afb2018-03-17 02:55:20356
357 EXPECT_TRUE(base::StringToDouble(
358 request.headers.find("viewport-width")->second, &value));
Tarun Bansal62efba12018-05-04 22:58:35359 EXPECT_TRUE(
360 IsSimilarToIntABNF(request.headers.find("viewport-width")->second));
Tarun Bansal79df868e2018-03-20 23:01:36361#if !defined(OS_ANDROID)
Tarun Bansal5c28afb2018-03-17 02:55:20362 EXPECT_LT(0.0, value);
Tarun Bansal79df868e2018-03-20 23:01:36363#else
364 EXPECT_EQ(980, value);
365#endif
Tarun Bansal44ad96882018-03-28 17:47:42366#if defined(OS_ANDROID)
367 // TODO(tbansal): https://crbug.com/825892: Viewport width on main
368 // frame requests may be incorrect when the Chrome window is not
369 // maximized.
370 if (main_frame_viewport_width_observed_ > 0) {
371 EXPECT_EQ(main_frame_viewport_width_observed_, value);
372 }
373#endif
Tarun Bansal7f3fe8c2018-04-06 22:37:47374 VerifyNetworkQualityClientHints(request);
Tarun Bansal5c28afb2018-03-17 02:55:20375 }
Tarun Bansala61f0f62017-10-24 23:53:05376 }
Tarun Bansal6bf54302017-10-02 07:39:14377
Tarun Bansalf9cf9892018-04-06 04:38:01378 for (size_t i = 0; i < blink::kClientHintsHeaderMappingCount; ++i) {
379 if (base::ContainsKey(request.headers,
380 blink::kClientHintsHeaderMapping[i])) {
381 count_client_hints_headers_seen_++;
382 }
383 }
384 }
Tarun Bansal1965b042017-09-07 04:59:19385
Tarun Bansalf9cf9892018-04-06 04:38:01386 void VerifyClientHintsReceived(bool expect_client_hints,
387 const net::test_server::HttpRequest& request) {
388 for (size_t i = 0; i < blink::kClientHintsHeaderMappingCount; ++i) {
389 // Resource width client hint is only attached on image subresources.
390 if (std::string(blink::kClientHintsHeaderMapping[i]) == "width") {
391 continue;
392 }
393 EXPECT_EQ(expect_client_hints,
394 base::ContainsKey(request.headers,
395 blink::kClientHintsHeaderMapping[i]));
396 }
Tarun Bansal1965b042017-09-07 04:59:19397 }
398
Tarun Bansal7f3fe8c2018-04-06 22:37:47399 void VerifyNetworkQualityClientHints(
400 const net::test_server::HttpRequest& request) const {
401 // Effective connection type is forced to 2G using command line in these
402 // tests.
Tarun Bansal509a8dd2018-04-10 17:19:16403 int rtt_value = 0.0;
Tarun Bansal7f3fe8c2018-04-06 22:37:47404 EXPECT_TRUE(
Tarun Bansal509a8dd2018-04-10 17:19:16405 base::StringToInt(request.headers.find("rtt")->second, &rtt_value));
406 EXPECT_LE(0, rtt_value);
Tarun Bansal62efba12018-05-04 22:58:35407 EXPECT_TRUE(IsSimilarToIntABNF(request.headers.find("rtt")->second));
Tarun Bansal509a8dd2018-04-10 17:19:16408 // Verify that RTT value is a multiple of 50 milliseconds.
409 EXPECT_EQ(0, rtt_value % 50);
410 EXPECT_GE(3000, rtt_value);
Tarun Bansal7f3fe8c2018-04-06 22:37:47411
Tarun Bansal509a8dd2018-04-10 17:19:16412 double mbps_value = 0.0;
413 EXPECT_TRUE(base::StringToDouble(request.headers.find("downlink")->second,
414 &mbps_value));
415 EXPECT_LE(0, mbps_value);
Tarun Bansal62efba12018-05-04 22:58:35416 EXPECT_TRUE(
417 IsSimilarToDoubleABNF(request.headers.find("downlink")->second));
Tarun Bansal509a8dd2018-04-10 17:19:16418 // Verify that the mbps value is a multiple of 0.050 mbps.
419 // Allow for small amount of noise due to double to integer conversions.
420 EXPECT_NEAR(0, (static_cast<int>(mbps_value * 1000)) % 50, 1);
421 EXPECT_GE(10.0, mbps_value);
Tarun Bansal7f3fe8c2018-04-06 22:37:47422
423 EXPECT_FALSE(request.headers.find("ect")->second.empty());
Tarun Bansalceab9592018-05-01 18:57:35424
425 // TODO(tbansal): https://crbug.com/819244: When network servicification is
426 // enabled, the UI thread NQE observers do not receive notifications on
427 // change in the network quality.
428 if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
429 // Effective connection type is forced to 2G using command line in these
430 // tests. RTT is expected to be 1800 msec but leave some gap to account
431 // for added noise and randomization.
432 EXPECT_NEAR(1800, rtt_value, 360);
433
434 // Effective connection type is forced to 2G using command line in these
435 // tests. downlink is expected to be 0.075 Mbps but leave some gap to
436 // account for added noise and randomization.
437 EXPECT_NEAR(0.075, mbps_value, 0.05);
438
439 EXPECT_EQ("2g", request.headers.find("ect")->second);
440 }
Tarun Bansal7f3fe8c2018-04-06 22:37:47441 }
442
Tarun Bansal3b330b02017-11-09 19:03:14443 net::EmbeddedTestServer http_server_;
Tarun Bansal0b8b7afd2017-08-25 03:52:16444 net::EmbeddedTestServer https_server_;
Tarun Bansal3b330b02017-11-09 19:03:14445 GURL accept_ch_with_lifetime_http_local_url_;
Tarun Bansal1965b042017-09-07 04:59:19446 GURL accept_ch_with_lifetime_url_;
447 GURL accept_ch_without_lifetime_url_;
448 GURL without_accept_ch_without_lifetime_url_;
Tarun Bansal3b330b02017-11-09 19:03:14449 GURL without_accept_ch_without_lifetime_local_url_;
Tarun Bansaladd5e1812018-02-09 19:07:58450 GURL accept_ch_without_lifetime_with_iframe_url_;
451 GURL without_accept_ch_without_lifetime_img_foo_com_;
452 GURL without_accept_ch_without_lifetime_img_localhost_;
Tarun Bansal229647bd002018-02-27 17:33:36453 GURL accept_ch_without_lifetime_img_localhost_;
Tarun Bansal1965b042017-09-07 04:59:19454
Tarun Bansal44ad96882018-03-28 17:47:42455 double main_frame_dpr_observed_ = -1;
456 double main_frame_viewport_width_observed_ = -1;
457 double main_frame_device_memory_observed_ = -1;
458
Tarun Bansal229647bd002018-02-27 17:33:36459 // Expect client hints on all the main frame request.
460 bool expect_client_hints_on_main_frame_;
461 // Expect client hints on all the subresource requests.
462 bool expect_client_hints_on_subresources_;
463
Tarun Bansal1965b042017-09-07 04:59:19464 size_t count_client_hints_headers_seen_;
Tarun Bansala61f0f62017-10-24 23:53:05465
Jay Civelli1ff872d2018-03-09 21:52:16466 std::unique_ptr<ThirdPartyURLLoaderInterceptor> request_interceptor_;
Tarun Bansal229647bd002018-02-27 17:33:36467
Tarun Bansala61f0f62017-10-24 23:53:05468 DISALLOW_COPY_AND_ASSIGN(ClientHintsBrowserTest);
Tarun Bansal0b8b7afd2017-08-25 03:52:16469};
470
Tarun Bansalea0d8262018-05-21 16:11:50471class ClientHintsAllowThirdPartyBrowserTest : public ClientHintsBrowserTest {
472 void SetUpCommandLine(base::CommandLine* cmd) override {
473 scoped_feature_list_.InitFromCommandLine("AllowClientHintsToThirdParty",
474 "");
475 ClientHintsBrowserTest::SetUpCommandLine(cmd);
476 }
477};
478
Tarun Bansal74e189d2018-05-07 19:07:35479IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, CorsChecks) {
480 for (size_t i = 0; i < blink::kClientHintsHeaderMappingCount; ++i) {
481 // Do not test for headers that have not been enabled on the blink "stable"
482 // yet.
483 if (std::string(blink::kClientHintsHeaderMapping[i]) == "rtt" ||
484 std::string(blink::kClientHintsHeaderMapping[i]) == "downlink" ||
485 std::string(blink::kClientHintsHeaderMapping[i]) == "ect") {
486 continue;
487 }
488 EXPECT_TRUE(network::cors::IsCORSSafelistedHeader(
489 blink::kClientHintsHeaderMapping[i], "42" /* value */));
490 }
491 EXPECT_FALSE(network::cors::IsCORSSafelistedHeader("not-a-client-hint-header",
492 "" /* value */));
493 EXPECT_TRUE(
494 network::cors::IsCORSSafelistedHeader("save-data", "on" /* value */));
495}
496
Tarun Bansal0b8b7afd2017-08-25 03:52:16497// Loads a webpage that requests persisting of client hints. Verifies that
498// the browser receives the mojo notification from the renderer and persists the
499// client hints to the disk.
500IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, ClientHintsHttps) {
501 base::HistogramTester histogram_tester;
Tarun Bansal1965b042017-09-07 04:59:19502 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:16503
504 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
505
506 content::FetchHistogramsFromChildProcesses();
507 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
508
Tarun Bansal7f3fe8c2018-04-06 22:37:47509 // client_hints_url() sets six client hints.
510 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 6, 1);
Tarun Bansal1965b042017-09-07 04:59:19511 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
512 // seconds.
Tarun Bansal0b8b7afd2017-08-25 03:52:16513 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
514 3600 * 1000, 1);
515}
516
Tarun Bansaladd5e1812018-02-09 19:07:58517// Test that client hints are attached to subresources only if they belong
518// to the same host as document host.
519IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
520 ClientHintsHttpsSubresourceDifferentOrigin) {
521 base::HistogramTester histogram_tester;
522
523 // Add client hints for the embedded test server.
524 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
525 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
526
527 // Verify that the client hints settings for localhost have been saved.
528 ContentSettingsForOneType client_hints_settings;
529 HostContentSettingsMap* host_content_settings_map =
530 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
531 host_content_settings_map->GetSettingsForOneType(
532 CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
533 &client_hints_settings);
534 ASSERT_EQ(1U, client_hints_settings.size());
535
536 // Copy the client hints setting for localhost to foo.com.
537 host_content_settings_map->SetWebsiteSettingDefaultScope(
538 GURL("https://foo.com/"), GURL(), CONTENT_SETTINGS_TYPE_CLIENT_HINTS,
539 std::string(),
Jeremy Romanec48d7a2018-03-01 17:35:09540 std::make_unique<base::Value>(
Oksana Zhuravlovab14dc882018-04-12 17:34:57541 client_hints_settings.at(0).setting_value.Clone()));
Tarun Bansaladd5e1812018-02-09 19:07:58542
543 // Verify that client hints for the two hosts has been saved.
544 host_content_settings_map =
545 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
546 host_content_settings_map->GetSettingsForOneType(
547 CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
548 &client_hints_settings);
549 ASSERT_EQ(2U, client_hints_settings.size());
550
551 // Navigating to without_accept_ch_without_lifetime_img_localhost() should
552 // attach client hints to the image subresouce contained in that page since
553 // the image is located on the same server as the document origin.
Tarun Bansal229647bd002018-02-27 17:33:36554 SetClientHintExpectationsOnMainFrame(true);
555 SetClientHintExpectationsOnSubresources(true);
Tarun Bansaladd5e1812018-02-09 19:07:58556 ui_test_utils::NavigateToURL(
557 browser(), without_accept_ch_without_lifetime_img_localhost());
558 base::RunLoop().RunUntilIdle();
559 content::FetchHistogramsFromChildProcesses();
560 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
561
Tarun Bansal7f3fe8c2018-04-06 22:37:47562 // Six client hints are attached to the image request, and six to the main
Tarun Bansal79df868e2018-03-20 23:01:36563 // frame request.
Tarun Bansal7f3fe8c2018-04-06 22:37:47564 EXPECT_EQ(12u, count_client_hints_headers_seen());
Tarun Bansaladd5e1812018-02-09 19:07:58565
566 // Navigating to without_accept_ch_without_lifetime_img_foo_com() should not
567 // attach client hints to the image subresouce contained in that page since
568 // the image is located on a different server as the document origin.
Tarun Bansaladd5e1812018-02-09 19:07:58569 ui_test_utils::NavigateToURL(
570 browser(), without_accept_ch_without_lifetime_img_foo_com());
571 base::RunLoop().RunUntilIdle();
572 content::FetchHistogramsFromChildProcesses();
573 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
574
Tarun Bansalb30b7532018-03-14 21:50:38575 // The device-memory and dprheader is attached to the main frame request.
Tarun Bansal5c28afb2018-03-17 02:55:20576#if defined(OS_ANDROID)
Tarun Bansalb30b7532018-03-14 21:50:38577 EXPECT_EQ(6u, count_client_hints_headers_seen());
Tarun Bansal5c28afb2018-03-17 02:55:20578#else
Tarun Bansal7f3fe8c2018-04-06 22:37:47579 EXPECT_EQ(18u, count_client_hints_headers_seen());
Tarun Bansal5c28afb2018-03-17 02:55:20580#endif
Tarun Bansal229647bd002018-02-27 17:33:36581 // Requests to third party servers should not have client hints attached.
582 EXPECT_EQ(1u, third_party_request_count_seen());
583 EXPECT_EQ(0u, third_party_client_hints_count_seen());
Tarun Bansaladd5e1812018-02-09 19:07:58584}
585
Tarun Bansalea0d8262018-05-21 16:11:50586// Test that client hints are attached to third party subresources if
587// AllowClientHintsToThirdParty feature is enabled.
588IN_PROC_BROWSER_TEST_F(ClientHintsAllowThirdPartyBrowserTest,
589 ClientHintsThirdPartyAllowed) {
590 base::HistogramTester histogram_tester;
591
592 SetClientHintExpectationsOnMainFrame(false);
593 SetClientHintExpectationsOnSubresources(true);
594
595 // Add client hints for the embedded test server.
596 ui_test_utils::NavigateToURL(browser(),
597 accept_ch_without_lifetime_img_localhost());
598 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
599
600 EXPECT_EQ(6u, count_client_hints_headers_seen());
601
602 // Requests to third party servers should not have client hints attached.
603 EXPECT_EQ(1u, third_party_request_count_seen());
604
605 // Device memory, viewport width and DRP client hints should be sent to the
606 // third-party when feature "AllowClientHintsToThirdParty" is enabled.
607 EXPECT_EQ(3u, third_party_client_hints_count_seen());
608}
609
610// Test that client hints are not attached to third party subresources if
611// AllowClientHintsToThirdParty feature is not enabled.
612IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
613 ClientHintsThirdPartyNotAllowed) {
614 base::HistogramTester histogram_tester;
615
616 SetClientHintExpectationsOnMainFrame(false);
617 SetClientHintExpectationsOnSubresources(true);
618
619 // Add client hints for the embedded test server.
620 ui_test_utils::NavigateToURL(browser(),
621 accept_ch_without_lifetime_img_localhost());
622 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
623
624 EXPECT_EQ(6u, count_client_hints_headers_seen());
625
626 // Requests to third party servers should not have client hints attached.
627 EXPECT_EQ(1u, third_party_request_count_seen());
628
629 // Client hints should not be sent to the third-party when feature
630 // "AllowClientHintsToThirdParty" is not enabled.
631 EXPECT_EQ(0u, third_party_client_hints_count_seen());
632}
633
Tarun Bansaladd5e1812018-02-09 19:07:58634// Loads a HTTPS webpage that does not request persisting of client hints.
635// An iframe loaded by the webpage requests persistence of client hints.
636// Verify that the request from the iframe is not honored, and client hints
637// preference is not persisted.
638IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
639 DisregardPersistenceRequestIframe) {
640 base::HistogramTester histogram_tester;
641 ContentSettingsForOneType host_settings;
642
643 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
644 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
645 &host_settings);
646 EXPECT_EQ(0u, host_settings.size());
647
648 ui_test_utils::NavigateToURL(browser(),
649 accept_ch_without_lifetime_with_iframe_url());
650
651 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
652
653 content::FetchHistogramsFromChildProcesses();
654 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
655
656 // accept_ch_without_lifetime_with_iframe_url() loads
657 // accept_ch_with_lifetime() in an iframe. The request to persist client
658 // hints from accept_ch_with_lifetime() should be disregarded.
659 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
660 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
661}
662
Tarun Bansal3b330b02017-11-09 19:03:14663// Loads a HTTP local webpage (which qualifies as a secure context) that
664// requests persisting of client hints. Verifies that the browser receives the
665// mojo notification from the renderer and persists the client hints to the
666// disk.
667IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
668 ClientHintsLifetimeFollowedByNoClientHintHttpLocal) {
669 base::HistogramTester histogram_tester;
670 ContentSettingsForOneType host_settings;
671
672 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
673 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
674 &host_settings);
675 EXPECT_EQ(0u, host_settings.size());
676
677 ui_test_utils::NavigateToURL(browser(),
678 accept_ch_with_lifetime_http_local_url());
679
680 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
681
682 content::FetchHistogramsFromChildProcesses();
683 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
684
Tarun Bansal7f3fe8c2018-04-06 22:37:47685 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 6, 1);
Tarun Bansal3b330b02017-11-09 19:03:14686 // accept_ch_with_lifetime_http_local_url() sets client hints persist duration
687 // to 3600 seconds.
688 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
689 3600 * 1000, 1);
690
691 base::RunLoop().RunUntilIdle();
692
693 // Clients hints preferences for one origin should be persisted.
694 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
695 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
696 &host_settings);
697 EXPECT_EQ(1u, host_settings.size());
698
Tarun Bansal229647bd002018-02-27 17:33:36699 SetClientHintExpectationsOnMainFrame(true);
700 SetClientHintExpectationsOnSubresources(true);
Tarun Bansal3b330b02017-11-09 19:03:14701 ui_test_utils::NavigateToURL(browser(),
702 without_accept_ch_without_lifetime_local_url());
703
Tarun Bansal7f3fe8c2018-04-06 22:37:47704 // Six client hints are attached to the image request, and six to the main
Tarun Bansal79df868e2018-03-20 23:01:36705 // frame request.
Tarun Bansal7f3fe8c2018-04-06 22:37:47706 EXPECT_EQ(12u, count_client_hints_headers_seen());
Tarun Bansal3b330b02017-11-09 19:03:14707}
708
Tarun Bansal0b8b7afd2017-08-25 03:52:16709// Loads a webpage that does not request persisting of client hints.
710IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, NoClientHintsHttps) {
711 base::HistogramTester histogram_tester;
Tarun Bansal1965b042017-09-07 04:59:19712 ui_test_utils::NavigateToURL(browser(),
713 without_accept_ch_without_lifetime_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:16714
715 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
716
717 content::FetchHistogramsFromChildProcesses();
718 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
719
720 // no_client_hints_url() does not sets the client hints.
721 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
722 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
723}
724
Tarun Bansal1965b042017-09-07 04:59:19725IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
726 ClientHintsLifetimeFollowedByNoClientHint) {
727 base::HistogramTester histogram_tester;
728 ContentSettingsForOneType host_settings;
729
730 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
731 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
732 &host_settings);
733 EXPECT_EQ(0u, host_settings.size());
734
735 // Fetching accept_ch_with_lifetime_url() should persist the request for
736 // client hints.
737 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
738
739 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
740
741 content::FetchHistogramsFromChildProcesses();
742 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
743
Tarun Bansal7f3fe8c2018-04-06 22:37:47744 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 6, 1);
Tarun Bansal1965b042017-09-07 04:59:19745 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
746 // seconds.
747 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
748 3600 * 1000, 1);
749 base::RunLoop().RunUntilIdle();
750
751 // Clients hints preferences for one origin should be persisted.
752 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
753 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
754 &host_settings);
755 EXPECT_EQ(1u, host_settings.size());
756
Tarun Bansal229647bd002018-02-27 17:33:36757 SetClientHintExpectationsOnMainFrame(true);
758 SetClientHintExpectationsOnSubresources(true);
Tarun Bansal1965b042017-09-07 04:59:19759 ui_test_utils::NavigateToURL(browser(),
760 without_accept_ch_without_lifetime_url());
Tarun Bansal6bf54302017-10-02 07:39:14761
Tarun Bansal7f3fe8c2018-04-06 22:37:47762 // Six client hints are attached to the image request, and six to the main
Tarun Bansal79df868e2018-03-20 23:01:36763 // frame request.
Tarun Bansal7f3fe8c2018-04-06 22:37:47764 EXPECT_EQ(12u, count_client_hints_headers_seen());
Tarun Bansal1965b042017-09-07 04:59:19765}
766
Tarun Bansala61f0f62017-10-24 23:53:05767// Ensure that when cookies are blocked, client hint preferences are not
768// persisted.
769IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
770 ClientHintsLifetimeNotPersistedCookiesBlocked) {
771 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
772 CookieSettingsFactory::GetForProfile(browser()->profile());
773 base::HistogramTester histogram_tester;
774 ContentSettingsForOneType host_settings;
775
776 // Block cookies.
777 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
778 ->SetContentSettingDefaultScope(accept_ch_without_lifetime_url(), GURL(),
779 CONTENT_SETTINGS_TYPE_COOKIES,
780 std::string(), CONTENT_SETTING_BLOCK);
781
782 // Fetching accept_ch_with_lifetime_url() should not persist the request for
783 // client hints since cookies are blocked.
784 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
785 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
786 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
787 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
788 &host_settings);
789 EXPECT_EQ(0u, host_settings.size());
Tarun Bansalc211d8b2018-03-19 19:21:58790 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:05791
792 // Allow cookies.
793 cookie_settings_->SetCookieSetting(accept_ch_without_lifetime_url(),
794 CONTENT_SETTING_ALLOW);
795 // Fetching accept_ch_with_lifetime_url() should persist the request for
796 // client hints since cookies are allowed.
797 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
798 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 1);
799 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
800 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
801 &host_settings);
802 EXPECT_EQ(1u, host_settings.size());
803}
804
805IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
806 ClientHintsLifetimeNotAttachedCookiesBlocked) {
807 base::HistogramTester histogram_tester;
808 ContentSettingsForOneType host_settings;
809
810 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
811 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
812 &host_settings);
813 EXPECT_EQ(0u, host_settings.size());
814
815 // Fetching accept_ch_with_lifetime_url() should persist the request for
816 // client hints.
817 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
818 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
819 content::FetchHistogramsFromChildProcesses();
820 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
821
Tarun Bansal7f3fe8c2018-04-06 22:37:47822 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 6, 1);
Tarun Bansala61f0f62017-10-24 23:53:05823 // accept_ch_with_lifetime_url() tries to set client hints persist duration to
824 // 3600 seconds.
825 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
826 3600 * 1000, 1);
827 base::RunLoop().RunUntilIdle();
828
829 // Clients hints preferences for one origin should be persisted.
830 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
831 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
832 &host_settings);
833 EXPECT_EQ(1u, host_settings.size());
834
835 // Block the cookies: Client hints should not be attached.
836 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
837 ->SetContentSettingDefaultScope(accept_ch_without_lifetime_url(), GURL(),
838 CONTENT_SETTINGS_TYPE_COOKIES,
839 std::string(), CONTENT_SETTING_BLOCK);
840
841 ui_test_utils::NavigateToURL(browser(),
842 without_accept_ch_without_lifetime_url());
843 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansalc211d8b2018-03-19 19:21:58844 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:05845
846 // Allow the cookies: Client hints should now be attached.
847 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
848 ->SetContentSettingDefaultScope(accept_ch_without_lifetime_url(), GURL(),
849 CONTENT_SETTINGS_TYPE_COOKIES,
850 std::string(), CONTENT_SETTING_ALLOW);
851
Tarun Bansal229647bd002018-02-27 17:33:36852 SetClientHintExpectationsOnMainFrame(true);
853 SetClientHintExpectationsOnSubresources(true);
Tarun Bansala61f0f62017-10-24 23:53:05854 ui_test_utils::NavigateToURL(browser(),
855 without_accept_ch_without_lifetime_url());
Tarun Bansal79df868e2018-03-20 23:01:36856
Tarun Bansal7f3fe8c2018-04-06 22:37:47857 // Six client hints are attached to the image request, and six to the main
Tarun Bansal79df868e2018-03-20 23:01:36858 // frame request.
Tarun Bansal7f3fe8c2018-04-06 22:37:47859 EXPECT_EQ(12u, count_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:05860
861 // Clear settings.
862 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
863 ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_COOKIES);
864}
865
866// Ensure that when the JavaScript is blocked, client hint preferences are not
867// persisted.
868IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
869 ClientHintsLifetimeNotPersistedJavaScriptBlocked) {
870 ContentSettingsForOneType host_settings;
871
872 // Start a navigation. This navigation makes it possible to block JavaScript
873 // later.
874 ui_test_utils::NavigateToURL(browser(),
875 without_accept_ch_without_lifetime_url());
876
877 // Block the JavaScript: Client hint preferences should not be persisted.
878 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
879 ->SetContentSettingDefaultScope(accept_ch_with_lifetime_url(), GURL(),
880 CONTENT_SETTINGS_TYPE_JAVASCRIPT,
881 std::string(), CONTENT_SETTING_BLOCK);
882 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
883 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
884 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
885 &host_settings);
886 EXPECT_EQ(0u, host_settings.size());
Tarun Bansalc211d8b2018-03-19 19:21:58887 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:05888
889 // Allow the JavaScript: Client hint preferences should be persisted.
890 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
891 ->SetContentSettingDefaultScope(accept_ch_with_lifetime_url(), GURL(),
892 CONTENT_SETTINGS_TYPE_JAVASCRIPT,
893 std::string(), CONTENT_SETTING_ALLOW);
894 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
895 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
896 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
897 &host_settings);
898 EXPECT_EQ(1u, host_settings.size());
Tarun Bansal593790112018-03-20 04:53:34899
900 // Clear settings.
901 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
902 ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
Tarun Bansala61f0f62017-10-24 23:53:05903}
904
905// Ensure that when the JavaScript is blocked, persisted client hints are not
906// attached to the request headers.
907IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
908 ClientHintsLifetimeNotAttachedJavaScriptBlocked) {
909 base::HistogramTester histogram_tester;
910 ContentSettingsForOneType host_settings;
911
912 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
913 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
914 &host_settings);
915 EXPECT_EQ(0u, host_settings.size());
916
917 // Fetching accept_ch_with_lifetime_url() should persist the request for
918 // client hints.
919 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
920 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
921 content::FetchHistogramsFromChildProcesses();
922 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
923
Tarun Bansal7f3fe8c2018-04-06 22:37:47924 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 6, 1);
Tarun Bansala61f0f62017-10-24 23:53:05925 // accept_ch_with_lifetime_url() tries to set client hints persist duration to
926 // 3600 seconds.
927 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
928 3600 * 1000, 1);
929 base::RunLoop().RunUntilIdle();
930
931 // Clients hints preferences for one origin should be persisted.
932 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
933 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
934 &host_settings);
935 EXPECT_EQ(1u, host_settings.size());
936
937 // Block the Javascript: Client hints should not be attached.
938 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
939 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
940 GURL(), CONTENT_SETTINGS_TYPE_JAVASCRIPT,
941 std::string(), CONTENT_SETTING_BLOCK);
942 ui_test_utils::NavigateToURL(browser(),
943 without_accept_ch_without_lifetime_url());
944 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansalc211d8b2018-03-19 19:21:58945 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:05946
947 // Allow the Javascript: Client hints should now be attached.
948 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
949 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
950 GURL(), CONTENT_SETTINGS_TYPE_JAVASCRIPT,
951 std::string(), CONTENT_SETTING_ALLOW);
952
Tarun Bansal229647bd002018-02-27 17:33:36953 SetClientHintExpectationsOnMainFrame(true);
954 SetClientHintExpectationsOnSubresources(true);
Tarun Bansala61f0f62017-10-24 23:53:05955 ui_test_utils::NavigateToURL(browser(),
956 without_accept_ch_without_lifetime_url());
Tarun Bansal79df868e2018-03-20 23:01:36957
Tarun Bansal7f3fe8c2018-04-06 22:37:47958 // Six client hints are attached to the image request, and six to the main
Tarun Bansal79df868e2018-03-20 23:01:36959 // frame request.
Tarun Bansal7f3fe8c2018-04-06 22:37:47960 EXPECT_EQ(12u, count_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:05961
962 // Clear settings.
963 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
964 ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
965}
966
Tarun Bansal229647bd002018-02-27 17:33:36967// Ensure that when the JavaScript is blocked, client hints requested using
Tarun Bansal3f343d7c2018-03-02 18:48:00968// Accept-CH are not attached to the request headers for subresources.
Tarun Bansal1965b042017-09-07 04:59:19969IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal229647bd002018-02-27 17:33:36970 ClientHintsNoLifetimeScriptNotAllowed) {
Tarun Bansal1965b042017-09-07 04:59:19971 base::HistogramTester histogram_tester;
972 ContentSettingsForOneType host_settings;
973
974 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
975 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
976 &host_settings);
977 EXPECT_EQ(0u, host_settings.size());
978
Tarun Bansal3f343d7c2018-03-02 18:48:00979 // Block the Javascript: Client hints should not be attached.
980 SetClientHintExpectationsOnSubresources(false);
Tarun Bansal229647bd002018-02-27 17:33:36981 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
982 ->SetContentSettingDefaultScope(
983 accept_ch_without_lifetime_img_localhost(), GURL(),
984 CONTENT_SETTINGS_TYPE_JAVASCRIPT, std::string(),
985 CONTENT_SETTING_BLOCK);
986 ui_test_utils::NavigateToURL(browser(),
987 accept_ch_without_lifetime_img_localhost());
Tarun Bansal3f343d7c2018-03-02 18:48:00988 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:36989 EXPECT_EQ(1u, third_party_request_count_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:00990 EXPECT_EQ(0u, third_party_client_hints_count_seen());
Tarun Bansal1965b042017-09-07 04:59:19991
Tarun Bansal3f343d7c2018-03-02 18:48:00992 // Allow the Javascript: Client hints should now be attached.
Tarun Bansal229647bd002018-02-27 17:33:36993 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
994 ->SetContentSettingDefaultScope(
995 accept_ch_without_lifetime_img_localhost(), GURL(),
996 CONTENT_SETTINGS_TYPE_JAVASCRIPT, std::string(),
997 CONTENT_SETTING_ALLOW);
Tarun Bansal1965b042017-09-07 04:59:19998
Tarun Bansal229647bd002018-02-27 17:33:36999 SetClientHintExpectationsOnSubresources(true);
1000 ui_test_utils::NavigateToURL(browser(),
1001 accept_ch_without_lifetime_img_localhost());
Tarun Bansal3f343d7c2018-03-02 18:48:001002
Tarun Bansal7f3fe8c2018-04-06 22:37:471003 EXPECT_EQ(6u, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361004 EXPECT_EQ(2u, third_party_request_count_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001005 EXPECT_EQ(0u, third_party_client_hints_count_seen());
Tarun Bansalc211d8b2018-03-19 19:21:581006 VerifyContentSettingsNotNotified();
Tarun Bansal1965b042017-09-07 04:59:191007
Tarun Bansal229647bd002018-02-27 17:33:361008 // Clear settings.
1009 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1010 ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
Tarun Bansal1965b042017-09-07 04:59:191011
Tarun Bansal229647bd002018-02-27 17:33:361012 // Block the Javascript again: Client hints should not be attached.
Tarun Bansal3f343d7c2018-03-02 18:48:001013 SetClientHintExpectationsOnSubresources(false);
Tarun Bansal229647bd002018-02-27 17:33:361014 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1015 ->SetContentSettingDefaultScope(
1016 accept_ch_without_lifetime_img_localhost(), GURL(),
1017 CONTENT_SETTINGS_TYPE_JAVASCRIPT, std::string(),
1018 CONTENT_SETTING_BLOCK);
1019 ui_test_utils::NavigateToURL(browser(),
1020 accept_ch_without_lifetime_img_localhost());
Tarun Bansal7f3fe8c2018-04-06 22:37:471021 EXPECT_EQ(6u, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361022 EXPECT_EQ(3u, third_party_request_count_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001023 EXPECT_EQ(0u, third_party_client_hints_count_seen());
Tarun Bansal593790112018-03-20 04:53:341024
1025 // Clear settings.
1026 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1027 ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
Tarun Bansal229647bd002018-02-27 17:33:361028}
1029
Tarun Bansal3f343d7c2018-03-02 18:48:001030// Ensure that when the cookies is blocked, client hints are not attached to the
1031// request headers.
Tarun Bansal229647bd002018-02-27 17:33:361032IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
1033 ClientHintsNoLifetimeCookiesNotAllowed) {
1034 base::HistogramTester histogram_tester;
1035 ContentSettingsForOneType host_settings;
1036 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
1037 CookieSettingsFactory::GetForProfile(browser()->profile());
1038
Tarun Bansal1965b042017-09-07 04:59:191039 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1040 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1041 &host_settings);
1042 EXPECT_EQ(0u, host_settings.size());
1043
Tarun Bansal229647bd002018-02-27 17:33:361044 // Block cookies.
1045 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1046 ->SetContentSettingDefaultScope(
1047 accept_ch_without_lifetime_img_localhost(), GURL(),
1048 CONTENT_SETTINGS_TYPE_COOKIES, std::string(), CONTENT_SETTING_BLOCK);
1049 base::RunLoop().RunUntilIdle();
1050
Tarun Bansal1965b042017-09-07 04:59:191051 ui_test_utils::NavigateToURL(browser(),
Tarun Bansal229647bd002018-02-27 17:33:361052 accept_ch_without_lifetime_img_localhost());
1053 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001054 // Client hints are not attached to third party subresources even though
1055 // cookies are allowed only for the first party origin.
1056 EXPECT_EQ(0u, third_party_client_hints_count_seen());
Tarun Bansalc211d8b2018-03-19 19:21:581057 VerifyContentSettingsNotNotified();
Tarun Bansal229647bd002018-02-27 17:33:361058
1059 // Allow cookies.
1060 cookie_settings_->SetCookieSetting(accept_ch_without_lifetime_img_localhost(),
1061 CONTENT_SETTING_ALLOW);
1062 base::RunLoop().RunUntilIdle();
1063
1064 SetClientHintExpectationsOnSubresources(true);
1065 ui_test_utils::NavigateToURL(browser(),
1066 accept_ch_without_lifetime_img_localhost());
Tarun Bansal7f3fe8c2018-04-06 22:37:471067 EXPECT_EQ(6u, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361068 EXPECT_EQ(2u, third_party_request_count_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001069 EXPECT_EQ(0u, third_party_client_hints_count_seen());
Tarun Bansal229647bd002018-02-27 17:33:361070
1071 // Block cookies again.
1072 SetClientHintExpectationsOnSubresources(false);
1073 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1074 ->SetContentSettingDefaultScope(
1075 accept_ch_without_lifetime_img_localhost(), GURL(),
1076 CONTENT_SETTINGS_TYPE_COOKIES, std::string(), CONTENT_SETTING_BLOCK);
1077 base::RunLoop().RunUntilIdle();
1078
1079 ui_test_utils::NavigateToURL(browser(),
1080 accept_ch_without_lifetime_img_localhost());
Tarun Bansal7f3fe8c2018-04-06 22:37:471081 EXPECT_EQ(6u, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361082 EXPECT_EQ(3u, third_party_request_count_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001083 EXPECT_EQ(0u, third_party_client_hints_count_seen());
Tarun Bansal593790112018-03-20 04:53:341084
1085 // Clear settings.
1086 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1087 ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_COOKIES);
Tarun Bansal1965b042017-09-07 04:59:191088}
1089
Tarun Bansal0b8b7afd2017-08-25 03:52:161090// Check the client hints for the given URL in an incognito window.
1091// Start incognito browser twice to ensure that client hints prefs are
1092// not carried over.
1093IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, ClientHintsHttpsIncognito) {
1094 for (size_t i = 0; i < 2; ++i) {
1095 base::HistogramTester histogram_tester;
1096
1097 Browser* incognito = CreateIncognitoBrowser();
Tarun Bansal1965b042017-09-07 04:59:191098 ui_test_utils::NavigateToURL(incognito, accept_ch_with_lifetime_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:161099
1100 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1101
1102 content::FetchHistogramsFromChildProcesses();
1103 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1104
Tarun Bansal7f3fe8c2018-04-06 22:37:471105 // accept_ch_with_lifetime_url() sets six client hints.
1106 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 6, 1);
Tarun Bansal0b8b7afd2017-08-25 03:52:161107
1108 // At least one renderer must have been created. All the renderers created
1109 // must have read 0 client hints.
1110 EXPECT_LE(1u,
1111 histogram_tester.GetAllSamples("ClientHints.CountRulesReceived")
1112 .size());
1113 for (const auto& bucket :
1114 histogram_tester.GetAllSamples("ClientHints.CountRulesReceived")) {
1115 EXPECT_EQ(0, bucket.min);
1116 }
1117 // |url| sets client hints persist duration to 3600 seconds.
1118 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
1119 3600 * 1000, 1);
1120
1121 CloseBrowserSynchronously(incognito);
1122 }
1123}