blob: b8902efa56e5ed05ffce900defaa8d3906346268 [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
5#include "base/command_line.h"
Gabriel Charetteb71eec892017-09-14 22:52:566#include "base/run_loop.h"
Tarun Bansal6bf54302017-10-02 07:39:147#include "base/stl_util.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:168#include "base/test/histogram_tester.h"
Tarun Bansala61f0f62017-10-24 23:53:059#include "chrome/browser/content_settings/cookie_settings_factory.h"
Tarun Bansal1965b042017-09-07 04:59:1910#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1611#include "chrome/browser/metrics/subprocess_metrics_provider.h"
12#include "chrome/browser/net/url_request_mock_util.h"
13#include "chrome/browser/profiles/profile.h"
Tarun Bansal1965b042017-09-07 04:59:1914#include "chrome/browser/ui/browser.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1615#include "chrome/test/base/in_process_browser_test.h"
16#include "chrome/test/base/ui_test_utils.h"
Tarun Bansala61f0f62017-10-24 23:53:0517#include "components/content_settings/core/browser/cookie_settings.h"
Tarun Bansal1965b042017-09-07 04:59:1918#include "components/content_settings/core/browser/host_content_settings_map.h"
Tarun Bansala61f0f62017-10-24 23:53:0519#include "components/content_settings/core/common/pref_names.h"
20#include "components/prefs/pref_service.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1621#include "content/public/browser/browser_thread.h"
Tarun Bansal1965b042017-09-07 04:59:1922#include "content/public/common/browser_side_navigation_policy.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1623#include "content/public/common/content_switches.h"
24#include "content/public/test/browser_test_utils.h"
25#include "content/public/test/test_utils.h"
26#include "net/test/embedded_test_server/embedded_test_server.h"
Tarun Bansal1965b042017-09-07 04:59:1927#include "net/test/embedded_test_server/http_request.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1628
29class ClientHintsBrowserTest : public InProcessBrowserTest {
30 public:
31 ClientHintsBrowserTest()
Tarun Bansal3b330b02017-11-09 19:03:1432 : http_server_(net::EmbeddedTestServer::TYPE_HTTP),
33 https_server_(net::EmbeddedTestServer::TYPE_HTTPS),
Tarun Bansal1965b042017-09-07 04:59:1934 expect_client_hints_(false),
Tarun Bansala61f0f62017-10-24 23:53:0535 expect_client_hints_on_main_frame_only_(false),
Tarun Bansal1965b042017-09-07 04:59:1936 count_client_hints_headers_seen_(0) {
Tarun Bansal3b330b02017-11-09 19:03:1437 http_server_.ServeFilesFromSourceDirectory("chrome/test/data/client_hints");
Tarun Bansal0b8b7afd2017-08-25 03:52:1638 https_server_.ServeFilesFromSourceDirectory(
39 "chrome/test/data/client_hints");
Tarun Bansal1965b042017-09-07 04:59:1940
Tarun Bansal3b330b02017-11-09 19:03:1441 http_server_.RegisterRequestMonitor(
42 base::Bind(&ClientHintsBrowserTest::MonitorResourceRequest,
43 base::Unretained(this)));
Tarun Bansal1965b042017-09-07 04:59:1944 https_server_.RegisterRequestMonitor(
45 base::Bind(&ClientHintsBrowserTest::MonitorResourceRequest,
46 base::Unretained(this)));
47
Tarun Bansal3b330b02017-11-09 19:03:1448 EXPECT_TRUE(http_server_.Start());
Tarun Bansal0b8b7afd2017-08-25 03:52:1649 EXPECT_TRUE(https_server_.Start());
50
Tarun Bansal3b330b02017-11-09 19:03:1451 accept_ch_with_lifetime_http_local_url_ =
52 http_server_.GetURL("/accept_ch_with_lifetime.html");
53 EXPECT_TRUE(accept_ch_with_lifetime_http_local_url_.SchemeIsHTTPOrHTTPS());
54 EXPECT_FALSE(
55 accept_ch_with_lifetime_http_local_url_.SchemeIsCryptographic());
56
Tarun Bansal1965b042017-09-07 04:59:1957 accept_ch_with_lifetime_url_ =
58 https_server_.GetURL("/accept_ch_with_lifetime.html");
59 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsHTTPOrHTTPS());
60 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal0b8b7afd2017-08-25 03:52:1661
Tarun Bansal1965b042017-09-07 04:59:1962 accept_ch_without_lifetime_url_ =
63 https_server_.GetURL("/accept_ch_without_lifetime.html");
64 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsHTTPOrHTTPS());
65 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsCryptographic());
66
67 without_accept_ch_without_lifetime_url_ =
68 https_server_.GetURL("/without_accept_ch_without_lifetime.html");
69 EXPECT_TRUE(without_accept_ch_without_lifetime_url_.SchemeIsHTTPOrHTTPS());
70 EXPECT_TRUE(
71 without_accept_ch_without_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal3b330b02017-11-09 19:03:1472
73 without_accept_ch_without_lifetime_local_url_ =
74 http_server_.GetURL("/without_accept_ch_without_lifetime.html");
75 EXPECT_TRUE(
76 without_accept_ch_without_lifetime_local_url_.SchemeIsHTTPOrHTTPS());
77 EXPECT_FALSE(
78 without_accept_ch_without_lifetime_local_url_.SchemeIsCryptographic());
Tarun Bansaladd5e1812018-02-09 19:07:5879
80 without_accept_ch_without_lifetime_img_localhost_ = https_server_.GetURL(
81 "/without_accept_ch_without_lifetime_img_localhost.html");
82 without_accept_ch_without_lifetime_img_foo_com_ = https_server_.GetURL(
83 "/without_accept_ch_without_lifetime_img_foo_com.html");
84 accept_ch_without_lifetime_with_iframe_url_ =
85 https_server_.GetURL("/accept_ch_without_lifetime_with_iframe.html");
Tarun Bansal0b8b7afd2017-08-25 03:52:1686 }
87
88 ~ClientHintsBrowserTest() override {}
89
90 void SetUpOnMainThread() override {
91 content::BrowserThread::PostTask(
92 content::BrowserThread::IO, FROM_HERE,
93 base::BindOnce(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
94 }
95
96 void SetUpCommandLine(base::CommandLine* cmd) override {
97 cmd->AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures);
98 }
99
Tarun Bansal1965b042017-09-07 04:59:19100 void SetClientHintExpectations(bool expect_client_hints) {
101 expect_client_hints_ = expect_client_hints;
102 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16103
Tarun Bansala61f0f62017-10-24 23:53:05104 void SetClientHintExpectationsOnMainFrameOnly(bool expect_client_hints) {
105 expect_client_hints_on_main_frame_only_ = expect_client_hints;
106 }
107
Tarun Bansal3b330b02017-11-09 19:03:14108 const GURL& accept_ch_with_lifetime_http_local_url() const {
109 return accept_ch_with_lifetime_http_local_url_;
110 }
111
Tarun Bansal1965b042017-09-07 04:59:19112 // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
113 // headers.
114 const GURL& accept_ch_with_lifetime_url() const {
115 return accept_ch_with_lifetime_url_;
116 }
117
118 // A URL whose response headers include only Accept-CH header.
119 const GURL& accept_ch_without_lifetime_url() const {
120 return accept_ch_without_lifetime_url_;
121 }
122
123 // A URL whose response headers do not include either Accept-CH or
124 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
125 const GURL& without_accept_ch_without_lifetime_url() const {
126 return without_accept_ch_without_lifetime_url_;
127 }
128
Tarun Bansal3b330b02017-11-09 19:03:14129 // A URL whose response headers do not include either Accept-CH or
130 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
131 const GURL& without_accept_ch_without_lifetime_local_url() const {
132 return without_accept_ch_without_lifetime_local_url_;
133 }
134
Tarun Bansaladd5e1812018-02-09 19:07:58135 // A URL whose response headers do not include either Accept-CH or
136 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
137 // from localhost.
138 const GURL& without_accept_ch_without_lifetime_img_localhost() const {
139 return without_accept_ch_without_lifetime_img_localhost_;
140 }
141
142 // A URL whose response headers do not include either Accept-CH or
143 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
144 // from foo.com.
145 const GURL& without_accept_ch_without_lifetime_img_foo_com() const {
146 return without_accept_ch_without_lifetime_img_foo_com_;
147 }
148
149 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
150 // headers. The response loads accept_ch_with_lifetime_url() in an iframe.
151 const GURL& accept_ch_without_lifetime_with_iframe_url() const {
152 return accept_ch_without_lifetime_with_iframe_url_;
153 }
154
Tarun Bansal1965b042017-09-07 04:59:19155 size_t count_client_hints_headers_seen() const {
156 return count_client_hints_headers_seen_;
157 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16158
159 private:
Tarun Bansal1965b042017-09-07 04:59:19160 // Called by |https_server_|.
161 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
Tarun Bansal6bf54302017-10-02 07:39:14162 bool is_main_frame_navigation =
163 request.GetURL().spec().find(".html") != std::string::npos;
164
165 // When browser side navigation is enabled, dpr headers is not attached to
166 // the main frame request.
Tarun Bansala61f0f62017-10-24 23:53:05167 if (!expect_client_hints_on_main_frame_only_) {
168 EXPECT_EQ(
169 expect_client_hints_ && (!content::IsBrowserSideNavigationEnabled() ||
170 !is_main_frame_navigation),
171 base::ContainsKey(request.headers, "dpr"));
172 } else {
173 EXPECT_EQ(expect_client_hints_on_main_frame_only_ &&
174 is_main_frame_navigation &&
175 (!content::IsBrowserSideNavigationEnabled() ||
176 !is_main_frame_navigation),
177 base::ContainsKey(request.headers, "dpr"));
178 }
Tarun Bansal6bf54302017-10-02 07:39:14179
180 // When browser side navigation is enabled, device-memory header is attached
181 // to the main frame request.
Tarun Bansala61f0f62017-10-24 23:53:05182 if (!expect_client_hints_on_main_frame_only_) {
183 EXPECT_EQ(expect_client_hints_,
184 base::ContainsKey(request.headers, "device-memory"));
185 } else {
186 EXPECT_EQ(expect_client_hints_ && is_main_frame_navigation,
187 base::ContainsKey(request.headers, "device-memory"));
188 }
Tarun Bansal6bf54302017-10-02 07:39:14189
190 if (base::ContainsKey(request.headers, "dpr"))
Tarun Bansal1965b042017-09-07 04:59:19191 count_client_hints_headers_seen_++;
192
Tarun Bansal6bf54302017-10-02 07:39:14193 if (base::ContainsKey(request.headers, "device-memory"))
Tarun Bansal1965b042017-09-07 04:59:19194 count_client_hints_headers_seen_++;
195 }
196
Tarun Bansal3b330b02017-11-09 19:03:14197 net::EmbeddedTestServer http_server_;
Tarun Bansal0b8b7afd2017-08-25 03:52:16198 net::EmbeddedTestServer https_server_;
Tarun Bansal3b330b02017-11-09 19:03:14199 GURL accept_ch_with_lifetime_http_local_url_;
Tarun Bansal1965b042017-09-07 04:59:19200 GURL accept_ch_with_lifetime_url_;
201 GURL accept_ch_without_lifetime_url_;
202 GURL without_accept_ch_without_lifetime_url_;
Tarun Bansal3b330b02017-11-09 19:03:14203 GURL without_accept_ch_without_lifetime_local_url_;
Tarun Bansaladd5e1812018-02-09 19:07:58204 GURL accept_ch_without_lifetime_with_iframe_url_;
205 GURL without_accept_ch_without_lifetime_img_foo_com_;
206 GURL without_accept_ch_without_lifetime_img_localhost_;
Tarun Bansal1965b042017-09-07 04:59:19207
208 bool expect_client_hints_;
Tarun Bansala61f0f62017-10-24 23:53:05209 // Expect client hints only on the main frame request, and not on
210 // subresources.
211 bool expect_client_hints_on_main_frame_only_;
Tarun Bansal1965b042017-09-07 04:59:19212 size_t count_client_hints_headers_seen_;
Tarun Bansala61f0f62017-10-24 23:53:05213
214 DISALLOW_COPY_AND_ASSIGN(ClientHintsBrowserTest);
Tarun Bansal0b8b7afd2017-08-25 03:52:16215};
216
217// Loads a webpage that requests persisting of client hints. Verifies that
218// the browser receives the mojo notification from the renderer and persists the
219// client hints to the disk.
220IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, ClientHintsHttps) {
221 base::HistogramTester histogram_tester;
Tarun Bansal1965b042017-09-07 04:59:19222 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:16223
224 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
225
226 content::FetchHistogramsFromChildProcesses();
227 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
228
229 // client_hints_url() sets two client hints.
230 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 2, 1);
Tarun Bansal1965b042017-09-07 04:59:19231 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
232 // seconds.
Tarun Bansal0b8b7afd2017-08-25 03:52:16233 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
234 3600 * 1000, 1);
235}
236
Tarun Bansaladd5e1812018-02-09 19:07:58237// Test that client hints are attached to subresources only if they belong
238// to the same host as document host.
239IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
240 ClientHintsHttpsSubresourceDifferentOrigin) {
241 base::HistogramTester histogram_tester;
242
243 // Add client hints for the embedded test server.
244 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
245 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
246
247 // Verify that the client hints settings for localhost have been saved.
248 ContentSettingsForOneType client_hints_settings;
249 HostContentSettingsMap* host_content_settings_map =
250 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
251 host_content_settings_map->GetSettingsForOneType(
252 CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
253 &client_hints_settings);
254 ASSERT_EQ(1U, client_hints_settings.size());
255
256 // Copy the client hints setting for localhost to foo.com.
257 host_content_settings_map->SetWebsiteSettingDefaultScope(
258 GURL("https://foo.com/"), GURL(), CONTENT_SETTINGS_TYPE_CLIENT_HINTS,
259 std::string(),
260 base::MakeUnique<base::Value>(
261 client_hints_settings.at(0).setting_value->Clone()));
262
263 // Verify that client hints for the two hosts has been saved.
264 host_content_settings_map =
265 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
266 host_content_settings_map->GetSettingsForOneType(
267 CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
268 &client_hints_settings);
269 ASSERT_EQ(2U, client_hints_settings.size());
270
271 // Navigating to without_accept_ch_without_lifetime_img_localhost() should
272 // attach client hints to the image subresouce contained in that page since
273 // the image is located on the same server as the document origin.
274 SetClientHintExpectations(true);
275 ui_test_utils::NavigateToURL(
276 browser(), without_accept_ch_without_lifetime_img_localhost());
277 base::RunLoop().RunUntilIdle();
278 content::FetchHistogramsFromChildProcesses();
279 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
280
281 if (content::IsBrowserSideNavigationEnabled()) {
282 // When browser side navigation is enabled, two client hints are attached to
283 // the image request, and the device-memory header is attached to the main
284 // frame request.
285 EXPECT_EQ(3u, count_client_hints_headers_seen());
286 } else {
287 // When browser side navigation is not enabled, two client hints are
288 // attached to each of the HTML and the image requests.
289 EXPECT_EQ(4u, count_client_hints_headers_seen());
290 }
291
292 // Navigating to without_accept_ch_without_lifetime_img_foo_com() should not
293 // attach client hints to the image subresouce contained in that page since
294 // the image is located on a different server as the document origin.
295 SetClientHintExpectations(true);
296 ui_test_utils::NavigateToURL(
297 browser(), without_accept_ch_without_lifetime_img_foo_com());
298 base::RunLoop().RunUntilIdle();
299 content::FetchHistogramsFromChildProcesses();
300 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
301
302 if (content::IsBrowserSideNavigationEnabled()) {
303 // When browser side navigation is enabled, the device-memory header is
304 // attached to the main frame request.
305 EXPECT_EQ(4u, count_client_hints_headers_seen());
306 } else {
307 // When browser side navigation is not enabled, two client hints are
308 // attached to the HTML request.
309 EXPECT_EQ(5u, count_client_hints_headers_seen());
310 }
311}
312
313// Loads a HTTPS webpage that does not request persisting of client hints.
314// An iframe loaded by the webpage requests persistence of client hints.
315// Verify that the request from the iframe is not honored, and client hints
316// preference is not persisted.
317IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
318 DisregardPersistenceRequestIframe) {
319 base::HistogramTester histogram_tester;
320 ContentSettingsForOneType host_settings;
321
322 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
323 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
324 &host_settings);
325 EXPECT_EQ(0u, host_settings.size());
326
327 ui_test_utils::NavigateToURL(browser(),
328 accept_ch_without_lifetime_with_iframe_url());
329
330 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
331
332 content::FetchHistogramsFromChildProcesses();
333 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
334
335 // accept_ch_without_lifetime_with_iframe_url() loads
336 // accept_ch_with_lifetime() in an iframe. The request to persist client
337 // hints from accept_ch_with_lifetime() should be disregarded.
338 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
339 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
340}
341
Tarun Bansal3b330b02017-11-09 19:03:14342// Loads a HTTP local webpage (which qualifies as a secure context) that
343// requests persisting of client hints. Verifies that the browser receives the
344// mojo notification from the renderer and persists the client hints to the
345// disk.
346IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
347 ClientHintsLifetimeFollowedByNoClientHintHttpLocal) {
348 base::HistogramTester histogram_tester;
349 ContentSettingsForOneType host_settings;
350
351 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
352 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
353 &host_settings);
354 EXPECT_EQ(0u, host_settings.size());
355
356 ui_test_utils::NavigateToURL(browser(),
357 accept_ch_with_lifetime_http_local_url());
358
359 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
360
361 content::FetchHistogramsFromChildProcesses();
362 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
363
364 // client_hints_url() sets two client hints.
365 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 2, 1);
366 // accept_ch_with_lifetime_http_local_url() sets client hints persist duration
367 // to 3600 seconds.
368 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
369 3600 * 1000, 1);
370
371 base::RunLoop().RunUntilIdle();
372
373 // Clients hints preferences for one origin should be persisted.
374 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
375 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
376 &host_settings);
377 EXPECT_EQ(1u, host_settings.size());
378
379 SetClientHintExpectations(true);
380 ui_test_utils::NavigateToURL(browser(),
381 without_accept_ch_without_lifetime_local_url());
382
383 if (content::IsBrowserSideNavigationEnabled()) {
384 // When browser side navigation is enabled, two client hints are attached to
385 // the image request, and the device-memory header is attached to the main
386 // frame request.
387 EXPECT_EQ(3u, count_client_hints_headers_seen());
388 } else {
389 // When browser side navigation is not enabled, two client hints are
390 // attached to each of the HTML and the image requests.
391 EXPECT_EQ(4u, count_client_hints_headers_seen());
392 }
393}
394
Tarun Bansal0b8b7afd2017-08-25 03:52:16395// Loads a webpage that does not request persisting of client hints.
396IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, NoClientHintsHttps) {
397 base::HistogramTester histogram_tester;
Tarun Bansal1965b042017-09-07 04:59:19398 ui_test_utils::NavigateToURL(browser(),
399 without_accept_ch_without_lifetime_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:16400
401 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
402
403 content::FetchHistogramsFromChildProcesses();
404 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
405
406 // no_client_hints_url() does not sets the client hints.
407 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
408 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
409}
410
Tarun Bansal1965b042017-09-07 04:59:19411IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
412 ClientHintsLifetimeFollowedByNoClientHint) {
413 base::HistogramTester histogram_tester;
414 ContentSettingsForOneType host_settings;
415
416 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
417 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
418 &host_settings);
419 EXPECT_EQ(0u, host_settings.size());
420
421 // Fetching accept_ch_with_lifetime_url() should persist the request for
422 // client hints.
423 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
424
425 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
426
427 content::FetchHistogramsFromChildProcesses();
428 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
429
430 // client_hints_url() sets two client hints.
431 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 2, 1);
432 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
433 // seconds.
434 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
435 3600 * 1000, 1);
436 base::RunLoop().RunUntilIdle();
437
438 // Clients hints preferences for one origin should be persisted.
439 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
440 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
441 &host_settings);
442 EXPECT_EQ(1u, host_settings.size());
443
444 SetClientHintExpectations(true);
445 ui_test_utils::NavigateToURL(browser(),
446 without_accept_ch_without_lifetime_url());
Tarun Bansal6bf54302017-10-02 07:39:14447
Tarun Bansal1965b042017-09-07 04:59:19448 if (content::IsBrowserSideNavigationEnabled()) {
449 // When browser side navigation is enabled, two client hints are attached to
Tarun Bansal6bf54302017-10-02 07:39:14450 // the image request, and the device-memory header is attached to the main
451 // frame request.
452 EXPECT_EQ(3u, count_client_hints_headers_seen());
Tarun Bansal1965b042017-09-07 04:59:19453 } else {
454 // When browser side navigation is not enabled, two client hints are
Tarun Bansal6bf54302017-10-02 07:39:14455 // attached to each of the HTML and the image requests.
Tarun Bansal1965b042017-09-07 04:59:19456 EXPECT_EQ(4u, count_client_hints_headers_seen());
457 }
458}
459
Tarun Bansala61f0f62017-10-24 23:53:05460// Ensure that when cookies are blocked, client hint preferences are not
461// persisted.
462IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
463 ClientHintsLifetimeNotPersistedCookiesBlocked) {
464 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
465 CookieSettingsFactory::GetForProfile(browser()->profile());
466 base::HistogramTester histogram_tester;
467 ContentSettingsForOneType host_settings;
468
469 // Block cookies.
470 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
471 ->SetContentSettingDefaultScope(accept_ch_without_lifetime_url(), GURL(),
472 CONTENT_SETTINGS_TYPE_COOKIES,
473 std::string(), CONTENT_SETTING_BLOCK);
474
475 // Fetching accept_ch_with_lifetime_url() should not persist the request for
476 // client hints since cookies are blocked.
477 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
478 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
479 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
480 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
481 &host_settings);
482 EXPECT_EQ(0u, host_settings.size());
483
484 // Allow cookies.
485 cookie_settings_->SetCookieSetting(accept_ch_without_lifetime_url(),
486 CONTENT_SETTING_ALLOW);
487 // Fetching accept_ch_with_lifetime_url() should persist the request for
488 // client hints since cookies are allowed.
489 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
490 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 1);
491 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
492 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
493 &host_settings);
494 EXPECT_EQ(1u, host_settings.size());
495}
496
497IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
498 ClientHintsLifetimeNotAttachedCookiesBlocked) {
499 base::HistogramTester histogram_tester;
500 ContentSettingsForOneType host_settings;
501
502 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
503 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
504 &host_settings);
505 EXPECT_EQ(0u, host_settings.size());
506
507 // Fetching accept_ch_with_lifetime_url() should persist the request for
508 // client hints.
509 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
510 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
511 content::FetchHistogramsFromChildProcesses();
512 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
513
514 // client_hints_url() sets two client hints.
515 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 2, 1);
516 // accept_ch_with_lifetime_url() tries to set client hints persist duration to
517 // 3600 seconds.
518 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
519 3600 * 1000, 1);
520 base::RunLoop().RunUntilIdle();
521
522 // Clients hints preferences for one origin should be persisted.
523 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
524 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
525 &host_settings);
526 EXPECT_EQ(1u, host_settings.size());
527
528 // Block the cookies: Client hints should not be attached.
529 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
530 ->SetContentSettingDefaultScope(accept_ch_without_lifetime_url(), GURL(),
531 CONTENT_SETTINGS_TYPE_COOKIES,
532 std::string(), CONTENT_SETTING_BLOCK);
533
534 ui_test_utils::NavigateToURL(browser(),
535 without_accept_ch_without_lifetime_url());
536 EXPECT_EQ(0u, count_client_hints_headers_seen());
537
538 // Allow the cookies: Client hints should now be attached.
539 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
540 ->SetContentSettingDefaultScope(accept_ch_without_lifetime_url(), GURL(),
541 CONTENT_SETTINGS_TYPE_COOKIES,
542 std::string(), CONTENT_SETTING_ALLOW);
543
544 SetClientHintExpectations(true);
545 ui_test_utils::NavigateToURL(browser(),
546 without_accept_ch_without_lifetime_url());
547 if (content::IsBrowserSideNavigationEnabled()) {
548 // When browser side navigation is enabled, two client hints are attached to
549 // the image request, and the device-memory header is attached to the main
550 // frame request.
551 EXPECT_EQ(3u, count_client_hints_headers_seen());
552 } else {
553 // When browser side navigation is not enabled, two client hints are
554 // attached to each of the HTML and the image requests.
555 EXPECT_EQ(4u, count_client_hints_headers_seen());
556 }
557
558 // Clear settings.
559 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
560 ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_COOKIES);
561}
562
563// Ensure that when the JavaScript is blocked, client hint preferences are not
564// persisted.
565IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
566 ClientHintsLifetimeNotPersistedJavaScriptBlocked) {
567 ContentSettingsForOneType host_settings;
568
569 // Start a navigation. This navigation makes it possible to block JavaScript
570 // later.
571 ui_test_utils::NavigateToURL(browser(),
572 without_accept_ch_without_lifetime_url());
573
574 // Block the JavaScript: Client hint preferences should not be persisted.
575 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
576 ->SetContentSettingDefaultScope(accept_ch_with_lifetime_url(), GURL(),
577 CONTENT_SETTINGS_TYPE_JAVASCRIPT,
578 std::string(), CONTENT_SETTING_BLOCK);
579 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
580 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
581 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
582 &host_settings);
583 EXPECT_EQ(0u, host_settings.size());
584
585 // Allow the JavaScript: Client hint preferences should be persisted.
586 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
587 ->SetContentSettingDefaultScope(accept_ch_with_lifetime_url(), GURL(),
588 CONTENT_SETTINGS_TYPE_JAVASCRIPT,
589 std::string(), CONTENT_SETTING_ALLOW);
590 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
591 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
592 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
593 &host_settings);
594 EXPECT_EQ(1u, host_settings.size());
595}
596
597// Ensure that when the JavaScript is blocked, persisted client hints are not
598// attached to the request headers.
599IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
600 ClientHintsLifetimeNotAttachedJavaScriptBlocked) {
601 base::HistogramTester histogram_tester;
602 ContentSettingsForOneType host_settings;
603
604 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
605 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
606 &host_settings);
607 EXPECT_EQ(0u, host_settings.size());
608
609 // Fetching accept_ch_with_lifetime_url() should persist the request for
610 // client hints.
611 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
612 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
613 content::FetchHistogramsFromChildProcesses();
614 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
615
616 // client_hints_url() sets two client hints.
617 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 2, 1);
618 // accept_ch_with_lifetime_url() tries to set client hints persist duration to
619 // 3600 seconds.
620 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
621 3600 * 1000, 1);
622 base::RunLoop().RunUntilIdle();
623
624 // Clients hints preferences for one origin should be persisted.
625 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
626 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
627 &host_settings);
628 EXPECT_EQ(1u, host_settings.size());
629
630 // Block the Javascript: Client hints should not be attached.
631 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
632 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
633 GURL(), CONTENT_SETTINGS_TYPE_JAVASCRIPT,
634 std::string(), CONTENT_SETTING_BLOCK);
635 ui_test_utils::NavigateToURL(browser(),
636 without_accept_ch_without_lifetime_url());
637 EXPECT_EQ(0u, count_client_hints_headers_seen());
638
639 // Allow the Javascript: Client hints should now be attached.
640 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
641 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
642 GURL(), CONTENT_SETTINGS_TYPE_JAVASCRIPT,
643 std::string(), CONTENT_SETTING_ALLOW);
644
645 SetClientHintExpectations(true);
646 ui_test_utils::NavigateToURL(browser(),
647 without_accept_ch_without_lifetime_url());
648 if (content::IsBrowserSideNavigationEnabled()) {
649 // When browser side navigation is enabled, two client hints are attached to
650 // the image request, and the device-memory header is attached to the main
651 // frame request.
652 EXPECT_EQ(3u, count_client_hints_headers_seen());
653 } else {
654 // When browser side navigation is not enabled, two client hints are
655 // attached to each of the HTML and the image requests.
656 EXPECT_EQ(4u, count_client_hints_headers_seen());
657 }
658
659 // Clear settings.
660 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
661 ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
662}
663
Tarun Bansal1965b042017-09-07 04:59:19664IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
665 ClientHintsNoLifetimeFollowedByNoClientHint) {
666 base::HistogramTester histogram_tester;
667 ContentSettingsForOneType host_settings;
668
669 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
670 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
671 &host_settings);
672 EXPECT_EQ(0u, host_settings.size());
673
674 // Fetching accept_ch_without_lifetime_url() should not persist the request
675 // for client hints.
676 ui_test_utils::NavigateToURL(browser(), accept_ch_without_lifetime_url());
677
678 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
679
680 content::FetchHistogramsFromChildProcesses();
681 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
682
683 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
684 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
685 base::RunLoop().RunUntilIdle();
686
687 // Clients hints preferences should not be persisted.
688 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
689 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
690 &host_settings);
691 EXPECT_EQ(0u, host_settings.size());
692
693 // Next request should not have client hint headers attached.
694 ui_test_utils::NavigateToURL(browser(),
695 without_accept_ch_without_lifetime_url());
696}
697
Tarun Bansal0b8b7afd2017-08-25 03:52:16698// Check the client hints for the given URL in an incognito window.
699// Start incognito browser twice to ensure that client hints prefs are
700// not carried over.
701IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, ClientHintsHttpsIncognito) {
702 for (size_t i = 0; i < 2; ++i) {
703 base::HistogramTester histogram_tester;
704
705 Browser* incognito = CreateIncognitoBrowser();
Tarun Bansal1965b042017-09-07 04:59:19706 ui_test_utils::NavigateToURL(incognito, accept_ch_with_lifetime_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:16707
708 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
709
710 content::FetchHistogramsFromChildProcesses();
711 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
712
Tarun Bansal1965b042017-09-07 04:59:19713 // accept_ch_with_lifetime_url() sets two client hints.
Tarun Bansal0b8b7afd2017-08-25 03:52:16714 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 2, 1);
715
716 // At least one renderer must have been created. All the renderers created
717 // must have read 0 client hints.
718 EXPECT_LE(1u,
719 histogram_tester.GetAllSamples("ClientHints.CountRulesReceived")
720 .size());
721 for (const auto& bucket :
722 histogram_tester.GetAllSamples("ClientHints.CountRulesReceived")) {
723 EXPECT_EQ(0, bucket.min);
724 }
725 // |url| sets client hints persist duration to 3600 seconds.
726 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
727 3600 * 1000, 1);
728
729 CloseBrowserSynchronously(incognito);
730 }
731}