blob: 7295b857a9b250804e63a4ffad719fbc6d8a0905 [file] [log] [blame]
Tarun Bansal0b8b7afd2017-08-25 03:52:161// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Tarun Bansal62efba12018-05-04 22:58:355#include <cctype>
6
Mike West2fddeeb72019-02-15 11:29:487#include "base/base_switches.h"
Tarun Bansal229647bd002018-02-27 17:33:368#include "base/bind.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:169#include "base/command_line.h"
Tarun Bansalbef6d652018-10-02 18:41:0110#include "base/metrics/field_trial_param_associator.h"
Gabriel Charetteb71eec892017-09-14 22:52:5611#include "base/run_loop.h"
Tarun Bansal6bf54302017-10-02 07:39:1412#include "base/stl_util.h"
Mike Weste555be862019-02-20 16:17:3013#include "base/strings/string_util.h"
Devlin Cronin626d80c2018-06-01 01:08:3614#include "base/test/metrics/histogram_tester.h"
Alexei Svitkine8724ea502019-06-14 21:51:4615#include "base/test/mock_entropy_provider.h"
Tarun Bansal5c28afb2018-03-17 02:55:2016#include "build/build_config.h"
Mike Weste555be862019-02-20 16:17:3017#include "chrome/browser/chrome_content_browser_client.h"
Tarun Bansala61f0f62017-10-24 23:53:0518#include "chrome/browser/content_settings/cookie_settings_factory.h"
Tarun Bansal1965b042017-09-07 04:59:1919#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
Tarun Bansalc211d8b2018-03-19 19:21:5820#include "chrome/browser/content_settings/tab_specific_content_settings.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1621#include "chrome/browser/metrics/subprocess_metrics_provider.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1622#include "chrome/browser/profiles/profile.h"
Tarun Bansal1965b042017-09-07 04:59:1923#include "chrome/browser/ui/browser.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1624#include "chrome/test/base/in_process_browser_test.h"
25#include "chrome/test/base/ui_test_utils.h"
Tarun Bansala61f0f62017-10-24 23:53:0526#include "components/content_settings/core/browser/cookie_settings.h"
Tarun Bansal1965b042017-09-07 04:59:1927#include "components/content_settings/core/browser/host_content_settings_map.h"
Tarun Bansala61f0f62017-10-24 23:53:0528#include "components/content_settings/core/common/pref_names.h"
29#include "components/prefs/pref_service.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1630#include "content/public/browser/browser_thread.h"
Changwan Ryu434c3a32019-07-30 23:42:5831#include "content/public/browser/render_view_host.h"
Tarun Bansalbef6d652018-10-02 18:41:0132#include "content/public/common/content_features.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1633#include "content/public/common/content_switches.h"
Changwan Ryu434c3a32019-07-30 23:42:5834#include "content/public/common/web_preferences.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1635#include "content/public/test/browser_test_utils.h"
36#include "content/public/test/test_utils.h"
Tarun Bansal229647bd002018-02-27 17:33:3637#include "content/public/test/url_loader_interceptor.h"
38#include "net/dns/mock_host_resolver.h"
39#include "net/http/http_request_headers.h"
Tarun Bansal7f3fe8c2018-04-06 22:37:4740#include "net/nqe/effective_connection_type.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1641#include "net/test/embedded_test_server/embedded_test_server.h"
Tarun Bansal1965b042017-09-07 04:59:1942#include "net/test/embedded_test_server/http_request.h"
Tarun Bansal229647bd002018-02-27 17:33:3643#include "net/test/embedded_test_server/http_response.h"
Tarun Bansal74e189d2018-05-07 19:07:3544#include "services/network/public/cpp/cors/cors.h"
Tarun Bansalceab9592018-05-01 18:57:3545#include "services/network/public/cpp/features.h"
Tarun Bansal7f3fe8c2018-04-06 22:37:4746#include "services/network/public/cpp/network_switches.h"
Blink Reformata30d4232018-04-07 15:31:0647#include "third_party/blink/public/common/client_hints/client_hints.h"
Tarun Bansal229647bd002018-02-27 17:33:3648
49namespace {
50
51// An interceptor that records count of fetches and client hint headers for
52// requests to https://foo.com/non-existing-image.jpg.
Jay Civelli1ff872d2018-03-09 21:52:1653class ThirdPartyURLLoaderInterceptor {
Tarun Bansal229647bd002018-02-27 17:33:3654 public:
Jay Civelli1ff872d2018-03-09 21:52:1655 explicit ThirdPartyURLLoaderInterceptor(const GURL intercepted_url)
56 : intercepted_url_(intercepted_url),
57 interceptor_(base::BindRepeating(
58 &ThirdPartyURLLoaderInterceptor::InterceptURLRequest,
59 base::Unretained(this))) {}
Tarun Bansal229647bd002018-02-27 17:33:3660
Jay Civelli1ff872d2018-03-09 21:52:1661 ~ThirdPartyURLLoaderInterceptor() = default;
Tarun Bansal229647bd002018-02-27 17:33:3662
63 size_t request_count_seen() const { return request_count_seen_; }
64
65 size_t client_hints_count_seen() const { return client_hints_count_seen_; }
66
67 private:
Jay Civelli1ff872d2018-03-09 21:52:1668 bool InterceptURLRequest(
69 content::URLLoaderInterceptor::RequestParams* params) {
70 if (params->url_request.url != intercepted_url_)
71 return false;
Tarun Bansal229647bd002018-02-27 17:33:3672
Jay Civelli1ff872d2018-03-09 21:52:1673 request_count_seen_++;
Mike West14c11102019-02-04 16:16:4774 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Tarun Bansalf9cf9892018-04-06 04:38:0175 if (params->url_request.headers.HasHeader(
76 blink::kClientHintsHeaderMapping[i])) {
77 client_hints_count_seen_++;
78 }
Tarun Bansal5c28afb2018-03-17 02:55:2079 }
Jay Civelli1ff872d2018-03-09 21:52:1680 return false;
81 }
Tarun Bansal229647bd002018-02-27 17:33:3682
Jay Civelli1ff872d2018-03-09 21:52:1683 GURL intercepted_url_;
84
85 size_t request_count_seen_ = 0u;
86
87 size_t client_hints_count_seen_ = 0u;
88
89 content::URLLoaderInterceptor interceptor_;
90
91 DISALLOW_COPY_AND_ASSIGN(ThirdPartyURLLoaderInterceptor);
Tarun Bansal229647bd002018-02-27 17:33:3692};
93
Tarun Bansal62efba12018-05-04 22:58:3594// Returns true only if |header_value| satisfies ABNF: 1*DIGIT [ "." 1*DIGIT ]
95bool IsSimilarToDoubleABNF(const std::string& header_value) {
96 if (header_value.empty())
97 return false;
98 char first_char = header_value.at(0);
99 if (!isdigit(first_char))
100 return false;
101
102 bool period_found = false;
103 bool digit_found_after_period = false;
104 for (char ch : header_value) {
105 if (isdigit(ch)) {
106 if (period_found) {
107 digit_found_after_period = true;
108 }
109 continue;
110 }
111 if (ch == '.') {
112 if (period_found)
113 return false;
114 period_found = true;
115 continue;
116 }
117 return false;
118 }
119 if (period_found)
120 return digit_found_after_period;
121 return true;
122}
123
124// Returns true only if |header_value| satisfies ABNF: 1*DIGIT
125bool IsSimilarToIntABNF(const std::string& header_value) {
126 if (header_value.empty())
127 return false;
128
129 for (char ch : header_value) {
130 if (!isdigit(ch))
131 return false;
132 }
133 return true;
134}
135
Tarun Bansal229647bd002018-02-27 17:33:36136} // namespace
Tarun Bansal0b8b7afd2017-08-25 03:52:16137
Tarun Bansal9a7051f2018-07-10 18:30:05138class ClientHintsBrowserTest : public InProcessBrowserTest,
139 public testing::WithParamInterface<bool> {
Tarun Bansal0b8b7afd2017-08-25 03:52:16140 public:
141 ClientHintsBrowserTest()
Alexei Svitkine8724ea502019-06-14 21:51:46142 : field_trial_list_(std::make_unique<base::MockEntropyProvider>()),
143 http_server_(net::EmbeddedTestServer::TYPE_HTTP),
Tarun Bansal3b330b02017-11-09 19:03:14144 https_server_(net::EmbeddedTestServer::TYPE_HTTPS),
Tarun Bansal345418632018-06-29 11:07:04145 https_cross_origin_server_(net::EmbeddedTestServer::TYPE_HTTPS),
Tarun Bansal229647bd002018-02-27 17:33:36146 expect_client_hints_on_main_frame_(false),
147 expect_client_hints_on_subresources_(false),
Mike West2fddeeb72019-02-15 11:29:48148 count_user_agent_hint_headers_seen_(0),
Tarun Bansal229647bd002018-02-27 17:33:36149 count_client_hints_headers_seen_(0),
150 request_interceptor_(nullptr) {
Tarun Bansal3b330b02017-11-09 19:03:14151 http_server_.ServeFilesFromSourceDirectory("chrome/test/data/client_hints");
Tarun Bansal0b8b7afd2017-08-25 03:52:16152 https_server_.ServeFilesFromSourceDirectory(
153 "chrome/test/data/client_hints");
Tarun Bansal345418632018-06-29 11:07:04154 https_cross_origin_server_.ServeFilesFromSourceDirectory(
155 "chrome/test/data/client_hints");
Tarun Bansal1965b042017-09-07 04:59:19156
Tarun Bansal3b330b02017-11-09 19:03:14157 http_server_.RegisterRequestMonitor(
Tarun Bansal345418632018-06-29 11:07:04158 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
159 base::Unretained(this)));
Tarun Bansal1965b042017-09-07 04:59:19160 https_server_.RegisterRequestMonitor(
Tarun Bansal345418632018-06-29 11:07:04161 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
162 base::Unretained(this)));
163 https_cross_origin_server_.RegisterRequestMonitor(
164 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
165 base::Unretained(this)));
Tarun Bansal293a7b6c2018-12-05 17:41:12166 https_cross_origin_server_.RegisterRequestHandler(
167 base::BindRepeating(&ClientHintsBrowserTest::RequestHandlerToRedirect,
168 base::Unretained(this)));
Tarun Bansal345418632018-06-29 11:07:04169 https_server_.RegisterRequestHandler(base::BindRepeating(
170 &ClientHintsBrowserTest::RequestHandlerToFetchCrossOriginIframe,
171 base::Unretained(this)));
Tarun Bansal1965b042017-09-07 04:59:19172
Tarun Bansal3b330b02017-11-09 19:03:14173 EXPECT_TRUE(http_server_.Start());
Tarun Bansal0b8b7afd2017-08-25 03:52:16174 EXPECT_TRUE(https_server_.Start());
Tarun Bansal345418632018-06-29 11:07:04175 EXPECT_TRUE(https_cross_origin_server_.Start());
176
177 EXPECT_NE(https_server_.base_url(), https_cross_origin_server_.base_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:16178
Tarun Bansal3b330b02017-11-09 19:03:14179 accept_ch_with_lifetime_http_local_url_ =
180 http_server_.GetURL("/accept_ch_with_lifetime.html");
Tarun Bansal9a7051f2018-07-10 18:30:05181 http_equiv_accept_ch_with_lifetime_http_local_url_ =
182 http_server_.GetURL("/http_equiv_accept_ch_with_lifetime.html");
Tarun Bansal3b330b02017-11-09 19:03:14183 EXPECT_TRUE(accept_ch_with_lifetime_http_local_url_.SchemeIsHTTPOrHTTPS());
184 EXPECT_FALSE(
185 accept_ch_with_lifetime_http_local_url_.SchemeIsCryptographic());
186
Tarun Bansal1965b042017-09-07 04:59:19187 accept_ch_with_lifetime_url_ =
188 https_server_.GetURL("/accept_ch_with_lifetime.html");
Tarun Bansal73502f92019-04-16 21:21:19189 accept_ch_with_short_lifetime_url_ =
190 https_server_.GetURL("/accept_ch_with_short_lifetime.html");
Tarun Bansal0b8b7afd2017-08-25 03:52:16191
Tarun Bansal1965b042017-09-07 04:59:19192 accept_ch_without_lifetime_url_ =
193 https_server_.GetURL("/accept_ch_without_lifetime.html");
194 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsHTTPOrHTTPS());
195 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal9a7051f2018-07-10 18:30:05196 http_equiv_accept_ch_without_lifetime_url_ =
197 https_server_.GetURL("/http_equiv_accept_ch_without_lifetime.html");
Tarun Bansal1965b042017-09-07 04:59:19198
199 without_accept_ch_without_lifetime_url_ =
200 https_server_.GetURL("/without_accept_ch_without_lifetime.html");
201 EXPECT_TRUE(without_accept_ch_without_lifetime_url_.SchemeIsHTTPOrHTTPS());
202 EXPECT_TRUE(
203 without_accept_ch_without_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal3b330b02017-11-09 19:03:14204
205 without_accept_ch_without_lifetime_local_url_ =
206 http_server_.GetURL("/without_accept_ch_without_lifetime.html");
207 EXPECT_TRUE(
208 without_accept_ch_without_lifetime_local_url_.SchemeIsHTTPOrHTTPS());
209 EXPECT_FALSE(
210 without_accept_ch_without_lifetime_local_url_.SchemeIsCryptographic());
Tarun Bansaladd5e1812018-02-09 19:07:58211
212 without_accept_ch_without_lifetime_img_localhost_ = https_server_.GetURL(
213 "/without_accept_ch_without_lifetime_img_localhost.html");
214 without_accept_ch_without_lifetime_img_foo_com_ = https_server_.GetURL(
215 "/without_accept_ch_without_lifetime_img_foo_com.html");
216 accept_ch_without_lifetime_with_iframe_url_ =
217 https_server_.GetURL("/accept_ch_without_lifetime_with_iframe.html");
Tarun Bansal9a7051f2018-07-10 18:30:05218 http_equiv_accept_ch_without_lifetime_with_iframe_url_ =
219 https_server_.GetURL(
220 "/http_equiv_accept_ch_without_lifetime_with_iframe.html");
Tarun Bansal62cc3542018-06-27 23:53:30221 accept_ch_without_lifetime_with_subresource_url_ = https_server_.GetURL(
222 "/accept_ch_without_lifetime_with_subresource.html");
Tarun Bansal9a7051f2018-07-10 18:30:05223 http_equiv_accept_ch_without_lifetime_with_subresource_url_ =
224 https_server_.GetURL(
225 "/http_equiv_accept_ch_without_lifetime_with_subresource.html");
Tarun Bansal62cc3542018-06-27 23:53:30226 accept_ch_without_lifetime_with_subresource_iframe_url_ =
227 https_server_.GetURL(
228 "/accept_ch_without_lifetime_with_subresource_iframe.html");
Tarun Bansal9a7051f2018-07-10 18:30:05229 http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_ =
230 https_server_.GetURL(
231 "/http_equiv_accept_ch_without_lifetime_with_subresource_iframe."
232 "html");
Tarun Bansal229647bd002018-02-27 17:33:36233 accept_ch_without_lifetime_img_localhost_ =
234 https_server_.GetURL("/accept_ch_without_lifetime_img_localhost.html");
Tarun Bansal9a7051f2018-07-10 18:30:05235 http_equiv_accept_ch_without_lifetime_img_localhost_ = https_server_.GetURL(
236 "/http_equiv_accept_ch_without_lifetime_img_localhost.html");
237 http_equiv_accept_ch_with_lifetime_ =
238 https_server_.GetURL("/http_equiv_accept_ch_with_lifetime.html");
Tarun Bansal293a7b6c2018-12-05 17:41:12239
240 redirect_url_ = https_cross_origin_server_.GetURL("/redirect.html");
Tarun Bansal0b8b7afd2017-08-25 03:52:16241 }
242
243 ~ClientHintsBrowserTest() override {}
244
Mike West2fddeeb72019-02-15 11:29:48245 virtual std::unique_ptr<base::FeatureList> EnabledFeatures() {
246 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
247 feature_list->InitializeFromCommandLine("UserAgentClientHint", "");
248 return feature_list;
249 }
250
251 void SetUp() override {
252 scoped_feature_list_.InitWithFeatureList(EnabledFeatures());
253 InProcessBrowserTest::SetUp();
254 }
255
Tarun Bansal0b8b7afd2017-08-25 03:52:16256 void SetUpOnMainThread() override {
Tarun Bansal229647bd002018-02-27 17:33:36257 host_resolver()->AddRule("*", "127.0.0.1");
Tarun Bansal229647bd002018-02-27 17:33:36258
Jay Civelli1ff872d2018-03-09 21:52:16259 request_interceptor_ = std::make_unique<ThirdPartyURLLoaderInterceptor>(
260 GURL("https://foo.com/non-existing-image.jpg"));
Tarun Bansal229647bd002018-02-27 17:33:36261 base::RunLoop().RunUntilIdle();
Tarun Bansal0b8b7afd2017-08-25 03:52:16262 }
263
Jay Civelli1ff872d2018-03-09 21:52:16264 void TearDownOnMainThread() override { request_interceptor_.reset(); }
265
Tarun Bansal0b8b7afd2017-08-25 03:52:16266 void SetUpCommandLine(base::CommandLine* cmd) override {
Tarun Bansal7f3fe8c2018-04-06 22:37:47267 cmd->AppendSwitchASCII(network::switches::kForceEffectiveConnectionType,
268 net::kEffectiveConnectionType2G);
Mike West14c11102019-02-04 16:16:47269 cmd->AppendSwitchASCII(switches::kEnableBlinkFeatures,
270 "LangClientHintHeader");
Tarun Bansal0b8b7afd2017-08-25 03:52:16271 }
272
Tarun Bansal229647bd002018-02-27 17:33:36273 void SetClientHintExpectationsOnMainFrame(bool expect_client_hints) {
274 expect_client_hints_on_main_frame_ = expect_client_hints;
Tarun Bansal1965b042017-09-07 04:59:19275 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16276
Tarun Bansal229647bd002018-02-27 17:33:36277 void SetClientHintExpectationsOnSubresources(bool expect_client_hints) {
278 expect_client_hints_on_subresources_ = expect_client_hints;
Tarun Bansala61f0f62017-10-24 23:53:05279 }
280
Tarun Bansalc211d8b2018-03-19 19:21:58281 // Verify that the user is not notified that cookies or JavaScript were
282 // blocked on the webpage due to the checks done by client hints.
283 void VerifyContentSettingsNotNotified() const {
284 content::WebContents* web_contents =
285 browser()->tab_strip_model()->GetActiveWebContents();
286 EXPECT_FALSE(TabSpecificContentSettings::FromWebContents(web_contents)
287 ->IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
288
289 EXPECT_FALSE(TabSpecificContentSettings::FromWebContents(web_contents)
290 ->IsContentBlocked(CONTENT_SETTINGS_TYPE_JAVASCRIPT));
291 }
292
Tarun Bansalbef6d652018-10-02 18:41:01293 void SetExpectedEffectiveConnectionType(
294 net::EffectiveConnectionType effective_connection_type) {
295 expected_ect = effective_connection_type;
296 }
297
Changwan Ryu434c3a32019-07-30 23:42:58298 void SetJsEnabledForActiveView(bool enabled) {
299 content::RenderViewHost* view = browser()
300 ->tab_strip_model()
301 ->GetActiveWebContents()
302 ->GetRenderViewHost();
303 content::WebPreferences prefs = view->GetWebkitPreferences();
304 prefs.javascript_enabled = enabled;
305 view->UpdateWebkitPreferences(prefs);
306 }
307
Tarun Bansal3b330b02017-11-09 19:03:14308 const GURL& accept_ch_with_lifetime_http_local_url() const {
309 return accept_ch_with_lifetime_http_local_url_;
310 }
Tarun Bansal9a7051f2018-07-10 18:30:05311 const GURL& http_equiv_accept_ch_with_lifetime_http_local_url() const {
312 return http_equiv_accept_ch_with_lifetime_http_local_url_;
313 }
Tarun Bansal3b330b02017-11-09 19:03:14314
Tarun Bansal1965b042017-09-07 04:59:19315 // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
316 // headers.
317 const GURL& accept_ch_with_lifetime_url() const {
318 return accept_ch_with_lifetime_url_;
319 }
Tarun Bansal9a7051f2018-07-10 18:30:05320 const GURL& http_equiv_accept_ch_with_lifetime() {
321 return http_equiv_accept_ch_with_lifetime_;
322 }
Tarun Bansal1965b042017-09-07 04:59:19323
Tarun Bansal73502f92019-04-16 21:21:19324 // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
325 // headers. The Accept-CH-Lifetime duration is set very short to 1 second.
326 const GURL& accept_ch_with_short_lifetime() const {
327 return accept_ch_with_short_lifetime_url_;
328 }
329
Tarun Bansal1965b042017-09-07 04:59:19330 // A URL whose response headers include only Accept-CH header.
331 const GURL& accept_ch_without_lifetime_url() const {
332 return accept_ch_without_lifetime_url_;
333 }
Tarun Bansal9a7051f2018-07-10 18:30:05334 const GURL& http_equiv_accept_ch_without_lifetime_url() const {
335 return http_equiv_accept_ch_without_lifetime_url_;
336 }
Tarun Bansal1965b042017-09-07 04:59:19337
338 // A URL whose response headers do not include either Accept-CH or
339 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
340 const GURL& without_accept_ch_without_lifetime_url() const {
341 return without_accept_ch_without_lifetime_url_;
342 }
343
Tarun Bansal3b330b02017-11-09 19:03:14344 // A URL whose response headers do not include either Accept-CH or
345 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
346 const GURL& without_accept_ch_without_lifetime_local_url() const {
347 return without_accept_ch_without_lifetime_local_url_;
348 }
349
Tarun Bansaladd5e1812018-02-09 19:07:58350 // A URL whose response headers do not include either Accept-CH or
351 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
352 // from localhost.
353 const GURL& without_accept_ch_without_lifetime_img_localhost() const {
354 return without_accept_ch_without_lifetime_img_localhost_;
355 }
356
357 // A URL whose response headers do not include either Accept-CH or
358 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
359 // from foo.com.
360 const GURL& without_accept_ch_without_lifetime_img_foo_com() const {
361 return without_accept_ch_without_lifetime_img_foo_com_;
362 }
363
364 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
365 // headers. The response loads accept_ch_with_lifetime_url() in an iframe.
366 const GURL& accept_ch_without_lifetime_with_iframe_url() const {
367 return accept_ch_without_lifetime_with_iframe_url_;
368 }
Tarun Bansal9a7051f2018-07-10 18:30:05369 const GURL& http_equiv_accept_ch_without_lifetime_with_iframe_url() const {
370 return http_equiv_accept_ch_without_lifetime_with_iframe_url_;
371 }
Tarun Bansaladd5e1812018-02-09 19:07:58372
Tarun Bansal62cc3542018-06-27 23:53:30373 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
374 // headers. The response loads accept_ch_with_lifetime_url() as a subresource
375 // in the main frame.
376 const GURL& accept_ch_without_lifetime_with_subresource_url() const {
377 return accept_ch_without_lifetime_with_subresource_url_;
378 }
Tarun Bansal9a7051f2018-07-10 18:30:05379 const GURL& http_equiv_accept_ch_without_lifetime_with_subresource_url()
380 const {
381 return http_equiv_accept_ch_without_lifetime_with_subresource_url_;
382 }
Tarun Bansal62cc3542018-06-27 23:53:30383
384 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
Tarun Bansal9a7051f2018-07-10 18:30:05385 // headers. The response loads accept_ch_with_lifetime_url() or
386 // http_equiv_accept_ch_with_lifetime_url() as a subresource in the iframe.
Tarun Bansal62cc3542018-06-27 23:53:30387 const GURL& accept_ch_without_lifetime_with_subresource_iframe_url() const {
388 return accept_ch_without_lifetime_with_subresource_iframe_url_;
389 }
Tarun Bansal9a7051f2018-07-10 18:30:05390 const GURL&
391 http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url() const {
392 return http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_;
393 }
Tarun Bansal62cc3542018-06-27 23:53:30394
Tarun Bansal9a7051f2018-07-10 18:30:05395 // A URL whose response includes only Accept-CH header. Navigating to
Tarun Bansal229647bd002018-02-27 17:33:36396 // this URL also fetches two images: One from the localhost, and one from
397 // foo.com.
398 const GURL& accept_ch_without_lifetime_img_localhost() const {
399 return accept_ch_without_lifetime_img_localhost_;
400 }
Tarun Bansal9a7051f2018-07-10 18:30:05401 const GURL& http_equiv_accept_ch_without_lifetime_img_localhost() const {
402 return http_equiv_accept_ch_without_lifetime_img_localhost_;
403 }
Tarun Bansal229647bd002018-02-27 17:33:36404
Tarun Bansal293a7b6c2018-12-05 17:41:12405 const GURL& redirect_url() const { return redirect_url_; }
406
Mike West2fddeeb72019-02-15 11:29:48407 size_t count_user_agent_hint_headers_seen() const {
408 return count_user_agent_hint_headers_seen_;
409 }
410
Tarun Bansal1965b042017-09-07 04:59:19411 size_t count_client_hints_headers_seen() const {
412 return count_client_hints_headers_seen_;
413 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16414
Tarun Bansal229647bd002018-02-27 17:33:36415 size_t third_party_request_count_seen() const {
416 return request_interceptor_->request_count_seen();
417 }
418
419 size_t third_party_client_hints_count_seen() const {
420 return request_interceptor_->client_hints_count_seen();
421 }
422
Mike Weste555be862019-02-20 16:17:30423 const std::string& main_frame_ua_observed() const {
424 return main_frame_ua_observed_;
425 }
426
Alexei Svitkine8724ea502019-06-14 21:51:46427 base::FieldTrialList field_trial_list_;
Tarun Bansalea0d8262018-05-21 16:11:50428 base::test::ScopedFeatureList scoped_feature_list_;
429
Tarun Bansal345418632018-06-29 11:07:04430 std::string intercept_iframe_resource_;
Tarun Bansal9a7051f2018-07-10 18:30:05431 bool intercept_to_http_equiv_iframe_ = false;
Tarun Bansal345418632018-06-29 11:07:04432
Tarun Bansal0b8b7afd2017-08-25 03:52:16433 private:
Tarun Bansal345418632018-06-29 11:07:04434 // Intercepts only the main frame requests that contain
Tarun Bansal293a7b6c2018-12-05 17:41:12435 // "redirect" in the resource path. The intercepted requests
436 // are served an HTML file that fetches an iframe from a cross-origin HTTPS
437 // server.
438 std::unique_ptr<net::test_server::HttpResponse> RequestHandlerToRedirect(
439 const net::test_server::HttpRequest& request) {
440 // Check if it's a main frame request.
441 if (request.relative_url.find(".html") == std::string::npos)
442 return nullptr;
443
444 if (request.GetURL().spec().find("redirect") == std::string::npos)
445 return nullptr;
446
447 std::unique_ptr<net::test_server::BasicHttpResponse> response;
448 response.reset(new net::test_server::BasicHttpResponse);
449 response->set_code(net::HTTP_FOUND);
450 response->AddCustomHeader("Location",
451 without_accept_ch_without_lifetime_url().spec());
452 return std::move(response);
453 }
454
455 // Intercepts only the main frame requests that contain
Tarun Bansal345418632018-06-29 11:07:04456 // |intercept_iframe_resource_| in the resource path. The intercepted requests
457 // are served an HTML file that fetches an iframe from a cross-origin HTTPS
458 // server.
459 std::unique_ptr<net::test_server::HttpResponse>
460 RequestHandlerToFetchCrossOriginIframe(
461 const net::test_server::HttpRequest& request) {
462 if (intercept_iframe_resource_.empty())
463 return nullptr;
464
465 // Check if it's a main frame request.
466 if (request.relative_url.find(".html") == std::string::npos)
467 return nullptr;
468
469 if (request.relative_url.find(intercept_iframe_resource_) ==
470 std::string::npos) {
471 return nullptr;
472 }
473
474 const std::string iframe_url =
Tarun Bansal9a7051f2018-07-10 18:30:05475 intercept_to_http_equiv_iframe_
476 ? https_cross_origin_server_
477 .GetURL("/http_equiv_accept_ch_with_lifetime.html")
478 .spec()
479 : https_cross_origin_server_.GetURL("/accept_ch_with_lifetime.html")
480 .spec();
Tarun Bansal345418632018-06-29 11:07:04481
482 std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
483 new net::test_server::BasicHttpResponse());
484 http_response->set_code(net::HTTP_OK);
485 http_response->set_content_type("text/html");
486 http_response->set_content(
487 "<html>"
488 "<link rel='icon' href='data:;base64,='><head></head>"
489 "Empty file which uses link-rel to disable favicon fetches. "
490 "<iframe src='" +
491 iframe_url + "'></iframe></html>");
492
493 return std::move(http_response);
494 }
495
Tarun Bansal1965b042017-09-07 04:59:19496 // Called by |https_server_|.
497 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
Tarun Bansal6bf54302017-10-02 07:39:14498 bool is_main_frame_navigation =
499 request.GetURL().spec().find(".html") != std::string::npos;
500
Tarun Bansal293a7b6c2018-12-05 17:41:12501 if (is_main_frame_navigation &&
502 request.GetURL().spec().find("redirect") != std::string::npos) {
503 return;
504 }
505
Tarun Bansal229647bd002018-02-27 17:33:36506 if (is_main_frame_navigation) {
Mike Weste555be862019-02-20 16:17:30507 if (request.headers.find("sec-ch-ua") != request.headers.end())
508 main_frame_ua_observed_ = request.headers.find("sec-ch-ua")->second;
509
Tarun Bansalf9cf9892018-04-06 04:38:01510 VerifyClientHintsReceived(expect_client_hints_on_main_frame_, request);
Tarun Bansal5c28afb2018-03-17 02:55:20511 if (expect_client_hints_on_main_frame_) {
512 double value = 0.0;
513 EXPECT_TRUE(base::StringToDouble(
514 request.headers.find("device-memory")->second, &value));
515 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35516 EXPECT_TRUE(IsSimilarToDoubleABNF(
517 request.headers.find("device-memory")->second));
Tarun Bansal44ad96882018-03-28 17:47:42518 main_frame_device_memory_observed_ = value;
Tarun Bansal5c28afb2018-03-17 02:55:20519
520 EXPECT_TRUE(
521 base::StringToDouble(request.headers.find("dpr")->second, &value));
522 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35523 EXPECT_TRUE(IsSimilarToDoubleABNF(request.headers.find("dpr")->second));
Tarun Bansal44ad96882018-03-28 17:47:42524 main_frame_dpr_observed_ = value;
525
Tarun Bansal5c28afb2018-03-17 02:55:20526 EXPECT_TRUE(base::StringToDouble(
527 request.headers.find("viewport-width")->second, &value));
Tarun Bansal62efba12018-05-04 22:58:35528 EXPECT_TRUE(
529 IsSimilarToIntABNF(request.headers.find("viewport-width")->second));
Tarun Bansal79df868e2018-03-20 23:01:36530#if !defined(OS_ANDROID)
Tarun Bansal5c28afb2018-03-17 02:55:20531 EXPECT_LT(0.0, value);
Tarun Bansal79df868e2018-03-20 23:01:36532#else
533 EXPECT_EQ(980, value);
Tarun Bansal5c28afb2018-03-17 02:55:20534#endif
Tarun Bansal44ad96882018-03-28 17:47:42535 main_frame_viewport_width_observed_ = value;
Mike Weste555be862019-02-20 16:17:30536
Tarun Bansal7f3fe8c2018-04-06 22:37:47537 VerifyNetworkQualityClientHints(request);
Tarun Bansal5c28afb2018-03-17 02:55:20538 }
Tarun Bansala61f0f62017-10-24 23:53:05539 }
Tarun Bansal6bf54302017-10-02 07:39:14540
Tarun Bansal229647bd002018-02-27 17:33:36541 if (!is_main_frame_navigation) {
Tarun Bansalf9cf9892018-04-06 04:38:01542 VerifyClientHintsReceived(expect_client_hints_on_subresources_, request);
Tarun Bansal5c28afb2018-03-17 02:55:20543
544 if (expect_client_hints_on_subresources_) {
545 double value = 0.0;
546 EXPECT_TRUE(base::StringToDouble(
547 request.headers.find("device-memory")->second, &value));
548 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35549 EXPECT_TRUE(IsSimilarToDoubleABNF(
550 request.headers.find("device-memory")->second));
Tarun Bansal44ad96882018-03-28 17:47:42551 if (main_frame_device_memory_observed_ > 0) {
552 EXPECT_EQ(main_frame_device_memory_observed_, value);
553 }
Tarun Bansal5c28afb2018-03-17 02:55:20554
555 EXPECT_TRUE(
556 base::StringToDouble(request.headers.find("dpr")->second, &value));
557 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35558 EXPECT_TRUE(IsSimilarToDoubleABNF(request.headers.find("dpr")->second));
Tarun Bansal44ad96882018-03-28 17:47:42559 if (main_frame_dpr_observed_ > 0) {
560 EXPECT_EQ(main_frame_dpr_observed_, value);
561 }
Tarun Bansal5c28afb2018-03-17 02:55:20562
563 EXPECT_TRUE(base::StringToDouble(
564 request.headers.find("viewport-width")->second, &value));
Tarun Bansal62efba12018-05-04 22:58:35565 EXPECT_TRUE(
566 IsSimilarToIntABNF(request.headers.find("viewport-width")->second));
Tarun Bansal79df868e2018-03-20 23:01:36567#if !defined(OS_ANDROID)
Tarun Bansal5c28afb2018-03-17 02:55:20568 EXPECT_LT(0.0, value);
Tarun Bansal79df868e2018-03-20 23:01:36569#else
570 EXPECT_EQ(980, value);
571#endif
Tarun Bansal44ad96882018-03-28 17:47:42572#if defined(OS_ANDROID)
573 // TODO(tbansal): https://crbug.com/825892: Viewport width on main
574 // frame requests may be incorrect when the Chrome window is not
575 // maximized.
576 if (main_frame_viewport_width_observed_ > 0) {
577 EXPECT_EQ(main_frame_viewport_width_observed_, value);
578 }
579#endif
Tarun Bansal7f3fe8c2018-04-06 22:37:47580 VerifyNetworkQualityClientHints(request);
Tarun Bansal5c28afb2018-03-17 02:55:20581 }
Tarun Bansala61f0f62017-10-24 23:53:05582 }
Tarun Bansal6bf54302017-10-02 07:39:14583
Mike West14c11102019-02-04 16:16:47584 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Jan Wilken Dörriea8cb56302019-06-06 18:59:36585 if (base::Contains(request.headers,
586 blink::kClientHintsHeaderMapping[i])) {
Mike West2fddeeb72019-02-15 11:29:48587 // The user agent hint is special:
588 if (std::string(blink::kClientHintsHeaderMapping[i]) == "sec-ch-ua") {
589 count_user_agent_hint_headers_seen_++;
590 } else {
591 count_client_hints_headers_seen_++;
592 }
Tarun Bansalf9cf9892018-04-06 04:38:01593 }
594 }
595 }
Tarun Bansal1965b042017-09-07 04:59:19596
Tarun Bansalf9cf9892018-04-06 04:38:01597 void VerifyClientHintsReceived(bool expect_client_hints,
598 const net::test_server::HttpRequest& request) {
Mike West14c11102019-02-04 16:16:47599 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
600 SCOPED_TRACE(testing::Message()
601 << std::string(blink::kClientHintsHeaderMapping[i]));
Tarun Bansalf9cf9892018-04-06 04:38:01602 // Resource width client hint is only attached on image subresources.
603 if (std::string(blink::kClientHintsHeaderMapping[i]) == "width") {
604 continue;
605 }
Mike West2fddeeb72019-02-15 11:29:48606
607 // `Sec-CH-UA` is attached on all requests.
608 if (std::string(blink::kClientHintsHeaderMapping[i]) == "sec-ch-ua") {
609 continue;
610 }
611
Jan Wilken Dörriea8cb56302019-06-06 18:59:36612 EXPECT_EQ(
613 expect_client_hints,
614 base::Contains(request.headers, blink::kClientHintsHeaderMapping[i]));
Tarun Bansalf9cf9892018-04-06 04:38:01615 }
Tarun Bansal1965b042017-09-07 04:59:19616 }
617
Tarun Bansal7f3fe8c2018-04-06 22:37:47618 void VerifyNetworkQualityClientHints(
619 const net::test_server::HttpRequest& request) const {
620 // Effective connection type is forced to 2G using command line in these
621 // tests.
Tarun Bansal509a8dd2018-04-10 17:19:16622 int rtt_value = 0.0;
Tarun Bansal7f3fe8c2018-04-06 22:37:47623 EXPECT_TRUE(
Tarun Bansal509a8dd2018-04-10 17:19:16624 base::StringToInt(request.headers.find("rtt")->second, &rtt_value));
625 EXPECT_LE(0, rtt_value);
Tarun Bansal62efba12018-05-04 22:58:35626 EXPECT_TRUE(IsSimilarToIntABNF(request.headers.find("rtt")->second));
Tarun Bansal509a8dd2018-04-10 17:19:16627 // Verify that RTT value is a multiple of 50 milliseconds.
628 EXPECT_EQ(0, rtt_value % 50);
Tarun Bansalbef6d652018-10-02 18:41:01629 EXPECT_GE(expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G ? 3000 : 500,
630 rtt_value);
Tarun Bansal7f3fe8c2018-04-06 22:37:47631
Tarun Bansal509a8dd2018-04-10 17:19:16632 double mbps_value = 0.0;
633 EXPECT_TRUE(base::StringToDouble(request.headers.find("downlink")->second,
634 &mbps_value));
635 EXPECT_LE(0, mbps_value);
Tarun Bansal62efba12018-05-04 22:58:35636 EXPECT_TRUE(
637 IsSimilarToDoubleABNF(request.headers.find("downlink")->second));
Tarun Bansal509a8dd2018-04-10 17:19:16638 // Verify that the mbps value is a multiple of 0.050 mbps.
639 // Allow for small amount of noise due to double to integer conversions.
640 EXPECT_NEAR(0, (static_cast<int>(mbps_value * 1000)) % 50, 1);
641 EXPECT_GE(10.0, mbps_value);
Tarun Bansal7f3fe8c2018-04-06 22:37:47642
643 EXPECT_FALSE(request.headers.find("ect")->second.empty());
Tarun Bansalceab9592018-05-01 18:57:35644
645 // TODO(tbansal): https://crbug.com/819244: When network servicification is
Tarun Bansal5ac533542018-08-10 19:45:52646 // enabled, the renderer processes do not receive notifications on
647 // change in the network quality. Hence, the network quality client hints
648 // are not set to the correct value on subresources.
649 bool is_main_frame_navigation =
650 request.GetURL().spec().find(".html") != std::string::npos;
John Abd-El-Malek67facbe82019-06-06 22:37:08651 if (is_main_frame_navigation) {
Tarun Bansalceab9592018-05-01 18:57:35652 // Effective connection type is forced to 2G using command line in these
653 // tests. RTT is expected to be 1800 msec but leave some gap to account
654 // for added noise and randomization.
Tarun Bansalbef6d652018-10-02 18:41:01655 if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G) {
656 EXPECT_NEAR(1800, rtt_value, 360);
657 } else if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_3G) {
658 EXPECT_NEAR(450, rtt_value, 90);
659 } else {
660 NOTREACHED();
661 }
Tarun Bansalceab9592018-05-01 18:57:35662
663 // Effective connection type is forced to 2G using command line in these
664 // tests. downlink is expected to be 0.075 Mbps but leave some gap to
665 // account for added noise and randomization.
Tarun Bansalbef6d652018-10-02 18:41:01666 if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G) {
667 EXPECT_NEAR(0.075, mbps_value, 0.05);
668 } else if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_3G) {
669 EXPECT_NEAR(0.4, mbps_value, 0.1);
670 } else {
671 NOTREACHED();
672 }
Tarun Bansalceab9592018-05-01 18:57:35673
Tarun Bansalbef6d652018-10-02 18:41:01674 EXPECT_EQ(expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G ? "2g" : "3g",
675 request.headers.find("ect")->second);
Tarun Bansalceab9592018-05-01 18:57:35676 }
Tarun Bansal7f3fe8c2018-04-06 22:37:47677 }
678
Tarun Bansal3b330b02017-11-09 19:03:14679 net::EmbeddedTestServer http_server_;
Tarun Bansal0b8b7afd2017-08-25 03:52:16680 net::EmbeddedTestServer https_server_;
Tarun Bansal345418632018-06-29 11:07:04681 net::EmbeddedTestServer https_cross_origin_server_;
Tarun Bansal3b330b02017-11-09 19:03:14682 GURL accept_ch_with_lifetime_http_local_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05683 GURL http_equiv_accept_ch_with_lifetime_http_local_url_;
Tarun Bansal1965b042017-09-07 04:59:19684 GURL accept_ch_with_lifetime_url_;
Tarun Bansal73502f92019-04-16 21:21:19685 GURL accept_ch_with_short_lifetime_url_;
Tarun Bansal1965b042017-09-07 04:59:19686 GURL accept_ch_without_lifetime_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05687 GURL http_equiv_accept_ch_without_lifetime_url_;
Tarun Bansal1965b042017-09-07 04:59:19688 GURL without_accept_ch_without_lifetime_url_;
Tarun Bansal3b330b02017-11-09 19:03:14689 GURL without_accept_ch_without_lifetime_local_url_;
Tarun Bansaladd5e1812018-02-09 19:07:58690 GURL accept_ch_without_lifetime_with_iframe_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05691 GURL http_equiv_accept_ch_without_lifetime_with_iframe_url_;
Tarun Bansal62cc3542018-06-27 23:53:30692 GURL accept_ch_without_lifetime_with_subresource_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05693 GURL http_equiv_accept_ch_without_lifetime_with_subresource_url_;
Tarun Bansal62cc3542018-06-27 23:53:30694 GURL accept_ch_without_lifetime_with_subresource_iframe_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05695 GURL http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_;
Tarun Bansaladd5e1812018-02-09 19:07:58696 GURL without_accept_ch_without_lifetime_img_foo_com_;
697 GURL without_accept_ch_without_lifetime_img_localhost_;
Tarun Bansal229647bd002018-02-27 17:33:36698 GURL accept_ch_without_lifetime_img_localhost_;
Tarun Bansal9a7051f2018-07-10 18:30:05699 GURL http_equiv_accept_ch_without_lifetime_img_localhost_;
700 GURL http_equiv_accept_ch_with_lifetime_;
Tarun Bansal293a7b6c2018-12-05 17:41:12701 GURL redirect_url_;
Tarun Bansal1965b042017-09-07 04:59:19702
Mike Weste555be862019-02-20 16:17:30703 std::string main_frame_ua_observed_;
704
Tarun Bansal44ad96882018-03-28 17:47:42705 double main_frame_dpr_observed_ = -1;
706 double main_frame_viewport_width_observed_ = -1;
707 double main_frame_device_memory_observed_ = -1;
708
Tarun Bansal229647bd002018-02-27 17:33:36709 // Expect client hints on all the main frame request.
710 bool expect_client_hints_on_main_frame_;
711 // Expect client hints on all the subresource requests.
712 bool expect_client_hints_on_subresources_;
713
Mike West2fddeeb72019-02-15 11:29:48714 size_t count_user_agent_hint_headers_seen_;
Tarun Bansal1965b042017-09-07 04:59:19715 size_t count_client_hints_headers_seen_;
Tarun Bansala61f0f62017-10-24 23:53:05716
Jay Civelli1ff872d2018-03-09 21:52:16717 std::unique_ptr<ThirdPartyURLLoaderInterceptor> request_interceptor_;
Tarun Bansal229647bd002018-02-27 17:33:36718
Tarun Bansalbef6d652018-10-02 18:41:01719 // Set to 2G in SetUpCommandLine().
720 net::EffectiveConnectionType expected_ect = net::EFFECTIVE_CONNECTION_TYPE_2G;
721
Tarun Bansala61f0f62017-10-24 23:53:05722 DISALLOW_COPY_AND_ASSIGN(ClientHintsBrowserTest);
Tarun Bansal0b8b7afd2017-08-25 03:52:16723};
724
Tarun Bansal9a7051f2018-07-10 18:30:05725// True if testing for http-equiv correctness. When set to true, the tests
726// use webpages that may contain http-equiv Accept-CH and Accept-CH-Lifetime
727// headers. When set to false, the tests use webpages that set the headers in
728// the HTTP response headers.
Victor Costane5e91512019-02-13 08:24:02729INSTANTIATE_TEST_SUITE_P(/* no prefix */,
730 ClientHintsBrowserTest,
731 testing::Bool());
Tarun Bansal9a7051f2018-07-10 18:30:05732
Tarun Bansalea0d8262018-05-21 16:11:50733class ClientHintsAllowThirdPartyBrowserTest : public ClientHintsBrowserTest {
Mike West2fddeeb72019-02-15 11:29:48734 std::unique_ptr<base::FeatureList> EnabledFeatures() override {
735 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
736 feature_list->InitializeFromCommandLine(
737 "AllowClientHintsToThirdParty,UserAgentClientHint", "");
738 return feature_list;
Tarun Bansalea0d8262018-05-21 16:11:50739 }
740};
741
Aaron Tagliaboschia09ec442019-09-18 15:29:03742INSTANTIATE_TEST_SUITE_P(/* no prefix */,
743 ClientHintsAllowThirdPartyBrowserTest,
744 testing::Bool());
745
Tarun Bansal74e189d2018-05-07 19:07:35746IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, CorsChecks) {
Mike West14c11102019-02-04 16:16:47747 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Tarun Bansal74e189d2018-05-07 19:07:35748 // Do not test for headers that have not been enabled on the blink "stable"
749 // yet.
750 if (std::string(blink::kClientHintsHeaderMapping[i]) == "rtt" ||
751 std::string(blink::kClientHintsHeaderMapping[i]) == "downlink" ||
752 std::string(blink::kClientHintsHeaderMapping[i]) == "ect") {
753 continue;
754 }
Takashi Toyoshima2e01e692018-11-16 03:23:27755 EXPECT_TRUE(network::cors::IsCorsSafelistedHeader(
Tarun Bansal74e189d2018-05-07 19:07:35756 blink::kClientHintsHeaderMapping[i], "42" /* value */));
757 }
Takashi Toyoshima2e01e692018-11-16 03:23:27758 EXPECT_FALSE(network::cors::IsCorsSafelistedHeader("not-a-client-hint-header",
Tarun Bansal74e189d2018-05-07 19:07:35759 "" /* value */));
760 EXPECT_TRUE(
Takashi Toyoshima2e01e692018-11-16 03:23:27761 network::cors::IsCorsSafelistedHeader("save-data", "on" /* value */));
Tarun Bansal74e189d2018-05-07 19:07:35762}
763
Tarun Bansal0b8b7afd2017-08-25 03:52:16764// Loads a webpage that requests persisting of client hints. Verifies that
765// the browser receives the mojo notification from the renderer and persists the
766// client hints to the disk.
Tarun Bansal9a7051f2018-07-10 18:30:05767IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest, ClientHintsHttps) {
Tarun Bansal0b8b7afd2017-08-25 03:52:16768 base::HistogramTester histogram_tester;
Tarun Bansal9a7051f2018-07-10 18:30:05769 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
770 : accept_ch_with_lifetime_url();
771 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal0b8b7afd2017-08-25 03:52:16772
773 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
774
775 content::FetchHistogramsFromChildProcesses();
776 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
777
Mike West2fddeeb72019-02-15 11:29:48778 // client_hints_url() sets eleven client hints.
779 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11, 1);
Tarun Bansal1965b042017-09-07 04:59:19780 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
781 // seconds.
Tarun Bansal0b8b7afd2017-08-25 03:52:16782 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
783 3600 * 1000, 1);
784}
785
Tarun Bansaladd5e1812018-02-09 19:07:58786// Test that client hints are attached to subresources only if they belong
787// to the same host as document host.
Tarun Bansal9a7051f2018-07-10 18:30:05788IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansaladd5e1812018-02-09 19:07:58789 ClientHintsHttpsSubresourceDifferentOrigin) {
Tarun Bansal9a7051f2018-07-10 18:30:05790 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
791 : accept_ch_with_lifetime_url();
792
Tarun Bansaladd5e1812018-02-09 19:07:58793 base::HistogramTester histogram_tester;
794
795 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:05796 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansaladd5e1812018-02-09 19:07:58797 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
798
799 // Verify that the client hints settings for localhost have been saved.
800 ContentSettingsForOneType client_hints_settings;
801 HostContentSettingsMap* host_content_settings_map =
802 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
803 host_content_settings_map->GetSettingsForOneType(
804 CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
805 &client_hints_settings);
806 ASSERT_EQ(1U, client_hints_settings.size());
807
808 // Copy the client hints setting for localhost to foo.com.
809 host_content_settings_map->SetWebsiteSettingDefaultScope(
810 GURL("https://foo.com/"), GURL(), CONTENT_SETTINGS_TYPE_CLIENT_HINTS,
811 std::string(),
Jeremy Romanec48d7a2018-03-01 17:35:09812 std::make_unique<base::Value>(
Oksana Zhuravlovab14dc882018-04-12 17:34:57813 client_hints_settings.at(0).setting_value.Clone()));
Tarun Bansaladd5e1812018-02-09 19:07:58814
815 // Verify that client hints for the two hosts has been saved.
816 host_content_settings_map =
817 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
818 host_content_settings_map->GetSettingsForOneType(
819 CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
820 &client_hints_settings);
821 ASSERT_EQ(2U, client_hints_settings.size());
822
823 // Navigating to without_accept_ch_without_lifetime_img_localhost() should
824 // attach client hints to the image subresouce contained in that page since
825 // the image is located on the same server as the document origin.
Tarun Bansal229647bd002018-02-27 17:33:36826 SetClientHintExpectationsOnMainFrame(true);
827 SetClientHintExpectationsOnSubresources(true);
Tarun Bansaladd5e1812018-02-09 19:07:58828 ui_test_utils::NavigateToURL(
829 browser(), without_accept_ch_without_lifetime_img_localhost());
830 base::RunLoop().RunUntilIdle();
831 content::FetchHistogramsFromChildProcesses();
832 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
833
Mike West2fddeeb72019-02-15 11:29:48834 // The user agent hint is attached to all three requests:
835 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
836
837 // Ten client hints are attached to the image request, and ten to the
838 // main frame request.
839 EXPECT_EQ(20u, count_client_hints_headers_seen());
Tarun Bansaladd5e1812018-02-09 19:07:58840
841 // Navigating to without_accept_ch_without_lifetime_img_foo_com() should not
842 // attach client hints to the image subresouce contained in that page since
843 // the image is located on a different server as the document origin.
Tarun Bansaladd5e1812018-02-09 19:07:58844 ui_test_utils::NavigateToURL(
845 browser(), without_accept_ch_without_lifetime_img_foo_com());
846 base::RunLoop().RunUntilIdle();
847 content::FetchHistogramsFromChildProcesses();
848 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
849
Tarun Bansalb30b7532018-03-14 21:50:38850 // The device-memory and dprheader is attached to the main frame request.
Tarun Bansal5c28afb2018-03-17 02:55:20851#if defined(OS_ANDROID)
Mike West2fddeeb72019-02-15 11:29:48852 EXPECT_EQ(10u, count_client_hints_headers_seen());
Tarun Bansal5c28afb2018-03-17 02:55:20853#else
Mike West2fddeeb72019-02-15 11:29:48854 EXPECT_EQ(30u, count_client_hints_headers_seen());
Tarun Bansal5c28afb2018-03-17 02:55:20855#endif
Mike West2fddeeb72019-02-15 11:29:48856
857 // Requests to third party servers should have only one client hint attached
858 // (`Sec-CH-UA`).
Tarun Bansal229647bd002018-02-27 17:33:36859 EXPECT_EQ(1u, third_party_request_count_seen());
Mike West2fddeeb72019-02-15 11:29:48860 EXPECT_EQ(1u, third_party_client_hints_count_seen());
Tarun Bansaladd5e1812018-02-09 19:07:58861}
862
Mike Weste555be862019-02-20 16:17:30863// Verify that we send only major version information in the `Sec-CH-UA` header
864// by default, and full version information after an opt-in.
865IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest, UserAgentVersion) {
866 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
867 : accept_ch_with_lifetime_url();
868
869 blink::UserAgentMetadata ua = ::GetUserAgentMetadata();
870
871 // Navigate to a page that opts-into the header: the value should end with
872 // the major version, and not contain the full version.
873 SetClientHintExpectationsOnMainFrame(false);
874 ui_test_utils::NavigateToURL(browser(), gurl);
875 EXPECT_TRUE(base::EndsWith(main_frame_ua_observed(), ua.major_version,
876 base::CompareCase::SENSITIVE));
877 EXPECT_EQ(std::string::npos, main_frame_ua_observed().find(ua.full_version));
878
879 // Navigate again, after the opt-in: the value should end with the full
880 // version.
881 SetClientHintExpectationsOnMainFrame(true);
882 ui_test_utils::NavigateToURL(browser(), gurl);
883 EXPECT_TRUE(base::EndsWith(main_frame_ua_observed(), ua.full_version,
884 base::CompareCase::SENSITIVE));
885}
886
Tarun Bansalea0d8262018-05-21 16:11:50887// Test that client hints are attached to third party subresources if
888// AllowClientHintsToThirdParty feature is enabled.
Tarun Bansal9a7051f2018-07-10 18:30:05889IN_PROC_BROWSER_TEST_P(ClientHintsAllowThirdPartyBrowserTest,
Tarun Bansalea0d8262018-05-21 16:11:50890 ClientHintsThirdPartyAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:05891 const GURL gurl = GetParam()
892 ? http_equiv_accept_ch_without_lifetime_img_localhost()
893 : accept_ch_without_lifetime_img_localhost();
894
Tarun Bansalea0d8262018-05-21 16:11:50895 base::HistogramTester histogram_tester;
896
897 SetClientHintExpectationsOnMainFrame(false);
898 SetClientHintExpectationsOnSubresources(true);
899
900 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:05901 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansalea0d8262018-05-21 16:11:50902 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
903
Aaron Tagliaboschia09ec442019-09-18 15:29:03904 EXPECT_EQ(10u, count_client_hints_headers_seen());
Tarun Bansalea0d8262018-05-21 16:11:50905
906 // Requests to third party servers should not have client hints attached.
907 EXPECT_EQ(1u, third_party_request_count_seen());
908
Aaron Tagliaboschia09ec442019-09-18 15:29:03909 // Device memory, viewport width, DRP, and UA client hints should be sent to
910 // the third-party when feature "AllowClientHintsToThirdParty" is enabled.
911 EXPECT_EQ(4u, third_party_client_hints_count_seen());
Tarun Bansalea0d8262018-05-21 16:11:50912}
913
914// Test that client hints are not attached to third party subresources if
915// AllowClientHintsToThirdParty feature is not enabled.
Tarun Bansal9a7051f2018-07-10 18:30:05916IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansalea0d8262018-05-21 16:11:50917 ClientHintsThirdPartyNotAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:05918 const GURL gurl = GetParam()
919 ? http_equiv_accept_ch_without_lifetime_img_localhost()
920 : accept_ch_without_lifetime_img_localhost();
921
Tarun Bansalea0d8262018-05-21 16:11:50922 base::HistogramTester histogram_tester;
923
924 SetClientHintExpectationsOnMainFrame(false);
925 SetClientHintExpectationsOnSubresources(true);
926
927 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:05928 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansalea0d8262018-05-21 16:11:50929 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
930
Mike West2fddeeb72019-02-15 11:29:48931 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
932 EXPECT_EQ(10u, count_client_hints_headers_seen());
Tarun Bansalea0d8262018-05-21 16:11:50933
934 // Requests to third party servers should not have client hints attached.
935 EXPECT_EQ(1u, third_party_request_count_seen());
936
937 // Client hints should not be sent to the third-party when feature
Mike West2fddeeb72019-02-15 11:29:48938 // "AllowClientHintsToThirdParty" is not enabled, with the exception of the
939 // `Sec-CH-UA` hint, which is sent with every request.
940 EXPECT_EQ(1u, third_party_client_hints_count_seen());
Tarun Bansalea0d8262018-05-21 16:11:50941}
942
Tarun Bansaladd5e1812018-02-09 19:07:58943// Loads a HTTPS webpage that does not request persisting of client hints.
Tarun Bansal345418632018-06-29 11:07:04944// A same-origin iframe loaded by the webpage requests persistence of client
945// hints. Verify that the request from the iframe is honored, and client hints
946// preference is persisted.
Tarun Bansal9a7051f2018-07-10 18:30:05947IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal345418632018-06-29 11:07:04948 PersistenceRequestIframe_SameOrigin) {
Tarun Bansal9a7051f2018-07-10 18:30:05949 const GURL gurl =
950 GetParam() ? accept_ch_without_lifetime_with_iframe_url()
951 : http_equiv_accept_ch_without_lifetime_with_iframe_url();
Tarun Bansal345418632018-06-29 11:07:04952 base::HistogramTester histogram_tester;
953 ContentSettingsForOneType host_settings;
954
955 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
956 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
957 &host_settings);
958 EXPECT_EQ(0u, host_settings.size());
959
Tarun Bansal9a7051f2018-07-10 18:30:05960 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal345418632018-06-29 11:07:04961
962 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 1);
963
964 content::FetchHistogramsFromChildProcesses();
965 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
966
967 // accept_ch_without_lifetime_with_iframe_url() loads
968 // accept_ch_with_lifetime() in an iframe. The request to persist client
969 // hints from accept_ch_with_lifetime() should be persisted.
970 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 1);
971 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
972 3600 * 1000, 1);
973}
974
975// Loads a HTTPS webpage that does not request persisting of client hints.
976// An iframe loaded by the webpage from an cross origin server requests
977// persistence of client hints.
978// Verify that the request from the cross origin iframe is not honored, and
979// client hints preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:05980IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal345418632018-06-29 11:07:04981 DisregardPersistenceRequestIframe_CrossOrigin) {
Tarun Bansal9a7051f2018-07-10 18:30:05982 const GURL gurl =
983 GetParam() ? http_equiv_accept_ch_without_lifetime_with_iframe_url()
984 : accept_ch_without_lifetime_with_iframe_url();
985
986 intercept_iframe_resource_ = gurl.path();
987 intercept_to_http_equiv_iframe_ = GetParam();
988
Tarun Bansaladd5e1812018-02-09 19:07:58989 base::HistogramTester histogram_tester;
990 ContentSettingsForOneType host_settings;
991
992 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
993 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
994 &host_settings);
995 EXPECT_EQ(0u, host_settings.size());
996
Tarun Bansal9a7051f2018-07-10 18:30:05997 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansaladd5e1812018-02-09 19:07:58998
999 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1000
1001 content::FetchHistogramsFromChildProcesses();
1002 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1003
1004 // accept_ch_without_lifetime_with_iframe_url() loads
Tarun Bansal345418632018-06-29 11:07:041005 // accept_ch_with_lifetime() in a cross origin iframe. The request to persist
1006 // client hints from accept_ch_with_lifetime() should be disregarded.
Tarun Bansaladd5e1812018-02-09 19:07:581007 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1008 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1009}
1010
Tarun Bansal62cc3542018-06-27 23:53:301011// Loads a HTTPS webpage that does not request persisting of client hints.
1012// A subresource loaded by the webpage requests persistence of client hints.
1013// Verify that the request from the subresource is not honored, and client hints
1014// preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051015IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal62cc3542018-06-27 23:53:301016 DisregardPersistenceRequestSubresource) {
Tarun Bansal9a7051f2018-07-10 18:30:051017 const GURL gurl =
1018 GetParam() ? http_equiv_accept_ch_without_lifetime_with_subresource_url()
1019 : accept_ch_without_lifetime_with_subresource_url();
1020
Tarun Bansal62cc3542018-06-27 23:53:301021 base::HistogramTester histogram_tester;
1022 ContentSettingsForOneType host_settings;
1023
1024 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1025 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1026 &host_settings);
1027 EXPECT_EQ(0u, host_settings.size());
1028
Tarun Bansal9a7051f2018-07-10 18:30:051029 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal62cc3542018-06-27 23:53:301030
1031 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1032
1033 content::FetchHistogramsFromChildProcesses();
1034 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1035
1036 // accept_ch_without_lifetime_with_subresource_url() loads
1037 // accept_ch_with_lifetime() as a subresource. The request to persist client
1038 // hints from accept_ch_with_lifetime() should be disregarded.
1039 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1040 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1041}
1042
1043// Loads a HTTPS webpage that does not request persisting of client hints.
1044// A subresource loaded by the webpage in an iframe requests persistence of
1045// client hints. Verify that the request from the subresource in the iframe
1046// is not honored, and client hints preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051047IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal62cc3542018-06-27 23:53:301048 DisregardPersistenceRequestSubresourceIframe) {
Tarun Bansal9a7051f2018-07-10 18:30:051049 const GURL gurl =
1050 GetParam()
1051 ? http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url()
1052 : accept_ch_without_lifetime_with_subresource_iframe_url();
1053
Tarun Bansal62cc3542018-06-27 23:53:301054 base::HistogramTester histogram_tester;
1055 ContentSettingsForOneType host_settings;
1056
1057 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1058 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1059 &host_settings);
1060 EXPECT_EQ(0u, host_settings.size());
1061
Tarun Bansal9a7051f2018-07-10 18:30:051062 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal62cc3542018-06-27 23:53:301063
1064 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1065
1066 content::FetchHistogramsFromChildProcesses();
1067 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1068
Tarun Bansal9a7051f2018-07-10 18:30:051069 // |gurl| loads accept_ch_with_lifetime() or
1070 // http_equiv_accept_ch_with_lifetime() as a subresource in an iframe. The
1071 // request to persist client hints from accept_ch_with_lifetime() or
1072 // http_equiv_accept_ch_with_lifetime() should be disregarded.
Tarun Bansal62cc3542018-06-27 23:53:301073 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1074 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1075}
1076
Tarun Bansal3b330b02017-11-09 19:03:141077// Loads a HTTP local webpage (which qualifies as a secure context) that
1078// requests persisting of client hints. Verifies that the browser receives the
1079// mojo notification from the renderer and persists the client hints to the
1080// disk.
Tarun Bansal9a7051f2018-07-10 18:30:051081IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal3b330b02017-11-09 19:03:141082 ClientHintsLifetimeFollowedByNoClientHintHttpLocal) {
Tarun Bansal9a7051f2018-07-10 18:30:051083 const GURL gurl = GetParam()
1084 ? http_equiv_accept_ch_with_lifetime_http_local_url()
1085 : accept_ch_with_lifetime_http_local_url();
1086
Tarun Bansal3b330b02017-11-09 19:03:141087 base::HistogramTester histogram_tester;
1088 ContentSettingsForOneType host_settings;
1089
1090 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1091 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1092 &host_settings);
1093 EXPECT_EQ(0u, host_settings.size());
1094
Tarun Bansal9a7051f2018-07-10 18:30:051095 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal3b330b02017-11-09 19:03:141096
1097 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1098
1099 content::FetchHistogramsFromChildProcesses();
1100 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1101
Mike West2fddeeb72019-02-15 11:29:481102 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11u, 1);
Tarun Bansal9a7051f2018-07-10 18:30:051103 // |gurl| sets client hints persist duration to 3600 seconds.
Tarun Bansal3b330b02017-11-09 19:03:141104 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
1105 3600 * 1000, 1);
1106
1107 base::RunLoop().RunUntilIdle();
1108
1109 // Clients hints preferences for one origin should be persisted.
1110 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1111 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1112 &host_settings);
1113 EXPECT_EQ(1u, host_settings.size());
1114
Tarun Bansal229647bd002018-02-27 17:33:361115 SetClientHintExpectationsOnMainFrame(true);
1116 SetClientHintExpectationsOnSubresources(true);
Tarun Bansal3b330b02017-11-09 19:03:141117 ui_test_utils::NavigateToURL(browser(),
1118 without_accept_ch_without_lifetime_local_url());
1119
Mike West2fddeeb72019-02-15 11:29:481120 // The user agent hint is attached to all three requests:
1121 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
1122
1123 // Ten client hints are attached to the image request, and ten to the
1124 // main frame request.
1125 EXPECT_EQ(20u, count_client_hints_headers_seen());
Tarun Bansal3b330b02017-11-09 19:03:141126}
1127
Tarun Bansal0b8b7afd2017-08-25 03:52:161128// Loads a webpage that does not request persisting of client hints.
1129IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, NoClientHintsHttps) {
1130 base::HistogramTester histogram_tester;
Tarun Bansal1965b042017-09-07 04:59:191131 ui_test_utils::NavigateToURL(browser(),
1132 without_accept_ch_without_lifetime_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:161133
1134 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1135
1136 content::FetchHistogramsFromChildProcesses();
1137 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1138
1139 // no_client_hints_url() does not sets the client hints.
1140 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1141 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1142}
1143
Tarun Bansal9a7051f2018-07-10 18:30:051144IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal1965b042017-09-07 04:59:191145 ClientHintsLifetimeFollowedByNoClientHint) {
Tarun Bansal9a7051f2018-07-10 18:30:051146 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1147 : accept_ch_with_lifetime_url();
1148
Tarun Bansal1965b042017-09-07 04:59:191149 base::HistogramTester histogram_tester;
1150 ContentSettingsForOneType host_settings;
1151
1152 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1153 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1154 &host_settings);
1155 EXPECT_EQ(0u, host_settings.size());
1156
Tarun Bansal9a7051f2018-07-10 18:30:051157 // Fetching |gurl| should persist the request for client hints.
1158 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal1965b042017-09-07 04:59:191159
1160 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1161
1162 content::FetchHistogramsFromChildProcesses();
1163 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1164
Mike West2fddeeb72019-02-15 11:29:481165 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11u, 1);
Tarun Bansal1965b042017-09-07 04:59:191166 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
1167 // seconds.
1168 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
1169 3600 * 1000, 1);
1170 base::RunLoop().RunUntilIdle();
1171
1172 // Clients hints preferences for one origin should be persisted.
1173 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1174 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1175 &host_settings);
1176 EXPECT_EQ(1u, host_settings.size());
1177
Tarun Bansal229647bd002018-02-27 17:33:361178 SetClientHintExpectationsOnMainFrame(true);
1179 SetClientHintExpectationsOnSubresources(true);
Tarun Bansal1965b042017-09-07 04:59:191180 ui_test_utils::NavigateToURL(browser(),
1181 without_accept_ch_without_lifetime_url());
Tarun Bansal6bf54302017-10-02 07:39:141182
Mike West2fddeeb72019-02-15 11:29:481183 // The user agent hint is attached to all three requests:
1184 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
1185
1186 // Ten client hints are attached to the image request, and ten to the
1187 // main frame request.
1188 EXPECT_EQ(20u, count_client_hints_headers_seen());
Tarun Bansal1965b042017-09-07 04:59:191189}
1190
Tarun Bansal73502f92019-04-16 21:21:191191// Verify that expired persistent client hint preferences are not used.
1192// Verifies this by setting Accept-CH-Lifetime value to 1 second,
1193// and loading a page after 1 second to verify that client hints are not
1194// attached.
1195IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
1196 ShortLifetimeFollowedByNoClientHint) {
1197 const GURL gurl = accept_ch_with_short_lifetime();
1198
1199 base::HistogramTester histogram_tester;
1200 ContentSettingsForOneType host_settings;
1201
1202 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1203 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1204 &host_settings);
1205 EXPECT_EQ(0u, host_settings.size());
1206
1207 // Fetching |gurl| should persist the request for client hints.
1208 ui_test_utils::NavigateToURL(browser(), gurl);
1209
1210 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1211
1212 content::FetchHistogramsFromChildProcesses();
1213 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1214
1215 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11u, 1);
1216 // |gurl| sets client hints persist duration to 1 second.
1217 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration", 1 * 1000,
1218 1);
1219 base::RunLoop().RunUntilIdle();
1220
1221 // Clients hints preferences for one origin should be persisted.
1222 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1223 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1224 &host_settings);
1225 EXPECT_EQ(1u, host_settings.size());
1226
1227 // Sleep for a duration longer than 1 second (duration of persisted client
1228 // hints).
1229 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1001));
1230
1231 SetClientHintExpectationsOnMainFrame(false);
1232 SetClientHintExpectationsOnSubresources(false);
1233 ui_test_utils::NavigateToURL(browser(),
1234 without_accept_ch_without_lifetime_url());
1235
1236 // The user agent hint is attached to all three requests:
1237 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
1238
1239 // No client hints are attached to the requests since the persisted hints must
1240 // be expired.
1241 EXPECT_EQ(0u, count_client_hints_headers_seen());
1242}
1243
Tarun Bansal293a7b6c2018-12-05 17:41:121244// The test first fetches a page that sets Accept-CH-Lifetime. Next, it fetches
1245// a URL from a different origin. However, that URL response redirects to the
1246// same origin from where the first page was fetched. The test verifies that
1247// on receiving redirect to an origin for which the browser has persisted client
1248// hints prefs, the browser attaches the client hints headers when fetching the
1249// redirected URL.
1250IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
1251 ClientHintsLifetimeFollowedByRedirectToNoClientHint) {
1252 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1253 : accept_ch_with_lifetime_url();
1254
1255 base::HistogramTester histogram_tester;
1256 ContentSettingsForOneType host_settings;
1257
1258 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1259 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1260 &host_settings);
1261 EXPECT_EQ(0u, host_settings.size());
1262
1263 // Fetching |gurl| should persist the request for client hints.
1264 ui_test_utils::NavigateToURL(browser(), gurl);
1265
1266 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1267
1268 content::FetchHistogramsFromChildProcesses();
1269 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1270
Mike West2fddeeb72019-02-15 11:29:481271 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11u, 1);
Tarun Bansal293a7b6c2018-12-05 17:41:121272 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
1273 // seconds.
1274 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
1275 3600 * 1000, 1);
1276 base::RunLoop().RunUntilIdle();
1277
1278 // Clients hints preferences for one origin should be persisted.
1279 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1280 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1281 &host_settings);
1282 EXPECT_EQ(1u, host_settings.size());
1283
1284 SetClientHintExpectationsOnMainFrame(true);
1285 SetClientHintExpectationsOnSubresources(true);
1286 ui_test_utils::NavigateToURL(browser(), redirect_url());
1287
Mike West2fddeeb72019-02-15 11:29:481288 // The user agent hint is attached to all three requests:
1289 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
1290
1291 // Ten client hints are attached to the image request, and ten to the
1292 // main frame request.
1293 EXPECT_EQ(20u, count_client_hints_headers_seen());
Tarun Bansal293a7b6c2018-12-05 17:41:121294}
1295
Tarun Bansala0c1fc32018-10-03 16:14:521296// Ensure that even when cookies are blocked, client hint preferences are
Tarun Bansala61f0f62017-10-24 23:53:051297// persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051298IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521299 ClientHintsLifetimePersistedCookiesBlocked) {
Tarun Bansal9a7051f2018-07-10 18:30:051300 const GURL gurl_with = GetParam() ? http_equiv_accept_ch_with_lifetime()
1301 : accept_ch_with_lifetime_url();
1302
Tarun Bansala61f0f62017-10-24 23:53:051303 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
1304 CookieSettingsFactory::GetForProfile(browser()->profile());
1305 base::HistogramTester histogram_tester;
1306 ContentSettingsForOneType host_settings;
1307
1308 // Block cookies.
1309 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansala0c1fc32018-10-03 16:14:521310 ->SetContentSettingDefaultScope(gurl_with, GURL(),
Tarun Bansala61f0f62017-10-24 23:53:051311 CONTENT_SETTINGS_TYPE_COOKIES,
1312 std::string(), CONTENT_SETTING_BLOCK);
1313
Tarun Bansala0c1fc32018-10-03 16:14:521314 // Fetching |gurl_with| should persist the request for client hints.
Tarun Bansal9a7051f2018-07-10 18:30:051315 ui_test_utils::NavigateToURL(browser(), gurl_with);
Tarun Bansala0c1fc32018-10-03 16:14:521316 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 1);
Tarun Bansala61f0f62017-10-24 23:53:051317 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1318 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1319 &host_settings);
1320 EXPECT_EQ(1u, host_settings.size());
Tarun Bansala0c1fc32018-10-03 16:14:521321 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:051322}
1323
Tarun Bansal9a7051f2018-07-10 18:30:051324IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521325 ClientHintsLifetimeAttachedCookiesBlocked) {
Tarun Bansal9a7051f2018-07-10 18:30:051326 const GURL gurl_with = GetParam() ? http_equiv_accept_ch_with_lifetime()
1327 : accept_ch_with_lifetime_url();
1328 const GURL gurl_without = GetParam()
1329 ? http_equiv_accept_ch_without_lifetime_url()
1330 : accept_ch_without_lifetime_url();
Tarun Bansala61f0f62017-10-24 23:53:051331 base::HistogramTester histogram_tester;
1332 ContentSettingsForOneType host_settings;
1333
1334 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1335 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1336 &host_settings);
1337 EXPECT_EQ(0u, host_settings.size());
1338
Tarun Bansal9a7051f2018-07-10 18:30:051339 // Fetching |gurl_with| should persist the request for client hints.
1340 ui_test_utils::NavigateToURL(browser(), gurl_with);
Tarun Bansala61f0f62017-10-24 23:53:051341 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1342 content::FetchHistogramsFromChildProcesses();
1343 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1344
Mike West2fddeeb72019-02-15 11:29:481345 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11u, 1);
Tarun Bansal9a7051f2018-07-10 18:30:051346 // |gurl_with| tries to set client hints persist duration to 3600 seconds.
Tarun Bansala61f0f62017-10-24 23:53:051347 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
1348 3600 * 1000, 1);
1349 base::RunLoop().RunUntilIdle();
1350
1351 // Clients hints preferences for one origin should be persisted.
1352 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1353 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1354 &host_settings);
1355 EXPECT_EQ(1u, host_settings.size());
1356
Tarun Bansala0c1fc32018-10-03 16:14:521357 // Block the cookies: Client hints should be attached.
Tarun Bansala61f0f62017-10-24 23:53:051358 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansal9a7051f2018-07-10 18:30:051359 ->SetContentSettingDefaultScope(gurl_without, GURL(),
Tarun Bansala61f0f62017-10-24 23:53:051360 CONTENT_SETTINGS_TYPE_COOKIES,
1361 std::string(), CONTENT_SETTING_BLOCK);
1362
Tarun Bansal229647bd002018-02-27 17:33:361363 SetClientHintExpectationsOnMainFrame(true);
1364 SetClientHintExpectationsOnSubresources(true);
Tarun Bansala61f0f62017-10-24 23:53:051365 ui_test_utils::NavigateToURL(browser(),
1366 without_accept_ch_without_lifetime_url());
Tarun Bansal79df868e2018-03-20 23:01:361367
Mike West2fddeeb72019-02-15 11:29:481368 // The user agent hint is attached to all three requests:
1369 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
1370
1371 // Ten client hints are attached to the image request, and ten to the
1372 // main frame request.
1373 EXPECT_EQ(20u, count_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051374
1375 // Clear settings.
1376 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1377 ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_COOKIES);
1378}
1379
1380// Ensure that when the JavaScript is blocked, client hint preferences are not
1381// persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051382IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala61f0f62017-10-24 23:53:051383 ClientHintsLifetimeNotPersistedJavaScriptBlocked) {
1384 ContentSettingsForOneType host_settings;
1385
1386 // Start a navigation. This navigation makes it possible to block JavaScript
1387 // later.
1388 ui_test_utils::NavigateToURL(browser(),
1389 without_accept_ch_without_lifetime_url());
1390
Tarun Bansal9a7051f2018-07-10 18:30:051391 const GURL gurl =
1392 GetParam() ? http_equiv_accept_ch_without_lifetime_with_iframe_url()
1393 : accept_ch_with_lifetime_url();
1394
Tarun Bansala61f0f62017-10-24 23:53:051395 // Block the JavaScript: Client hint preferences should not be persisted.
1396 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansal9a7051f2018-07-10 18:30:051397 ->SetContentSettingDefaultScope(gurl, GURL(),
Tarun Bansala61f0f62017-10-24 23:53:051398 CONTENT_SETTINGS_TYPE_JAVASCRIPT,
1399 std::string(), CONTENT_SETTING_BLOCK);
1400 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
1401 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1402 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1403 &host_settings);
1404 EXPECT_EQ(0u, host_settings.size());
Tarun Bansalc211d8b2018-03-19 19:21:581405 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:051406
1407 // Allow the JavaScript: Client hint preferences should be persisted.
1408 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansal9a7051f2018-07-10 18:30:051409 ->SetContentSettingDefaultScope(gurl, GURL(),
Tarun Bansala61f0f62017-10-24 23:53:051410 CONTENT_SETTINGS_TYPE_JAVASCRIPT,
1411 std::string(), CONTENT_SETTING_ALLOW);
1412 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
1413 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1414 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1415 &host_settings);
1416 EXPECT_EQ(1u, host_settings.size());
Tarun Bansal593790112018-03-20 04:53:341417
1418 // Clear settings.
1419 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1420 ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
Tarun Bansala61f0f62017-10-24 23:53:051421}
1422
1423// Ensure that when the JavaScript is blocked, persisted client hints are not
1424// attached to the request headers.
Tarun Bansal9a7051f2018-07-10 18:30:051425IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala61f0f62017-10-24 23:53:051426 ClientHintsLifetimeNotAttachedJavaScriptBlocked) {
Tarun Bansal9a7051f2018-07-10 18:30:051427 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1428 : accept_ch_with_lifetime_url();
1429
Tarun Bansala61f0f62017-10-24 23:53:051430 base::HistogramTester histogram_tester;
1431 ContentSettingsForOneType host_settings;
1432
1433 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1434 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1435 &host_settings);
1436 EXPECT_EQ(0u, host_settings.size());
1437
1438 // Fetching accept_ch_with_lifetime_url() should persist the request for
1439 // client hints.
Tarun Bansal9a7051f2018-07-10 18:30:051440 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansala61f0f62017-10-24 23:53:051441 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1442 content::FetchHistogramsFromChildProcesses();
1443 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Mike West2fddeeb72019-02-15 11:29:481444 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051445
Mike West2fddeeb72019-02-15 11:29:481446 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11u, 1);
Tarun Bansala61f0f62017-10-24 23:53:051447 // accept_ch_with_lifetime_url() tries to set client hints persist duration to
1448 // 3600 seconds.
1449 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
1450 3600 * 1000, 1);
1451 base::RunLoop().RunUntilIdle();
1452
1453 // Clients hints preferences for one origin should be persisted.
1454 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1455 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1456 &host_settings);
1457 EXPECT_EQ(1u, host_settings.size());
1458
Changwan Ryu434c3a32019-07-30 23:42:581459 // Block JavaScript via WebPreferences: Client hints should not be attached.
1460 SetJsEnabledForActiveView(false);
1461
1462 SetClientHintExpectationsOnMainFrame(false);
1463 SetClientHintExpectationsOnSubresources(false);
1464 ui_test_utils::NavigateToURL(browser(),
1465 without_accept_ch_without_lifetime_url());
1466
1467 EXPECT_EQ(0u, count_client_hints_headers_seen());
1468 VerifyContentSettingsNotNotified();
1469 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
1470
1471 SetJsEnabledForActiveView(true);
1472
1473 // Block JavaScript via ContentSetting: Client hints should not be attached.
Tarun Bansala61f0f62017-10-24 23:53:051474 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1475 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
1476 GURL(), CONTENT_SETTINGS_TYPE_JAVASCRIPT,
1477 std::string(), CONTENT_SETTING_BLOCK);
1478 ui_test_utils::NavigateToURL(browser(),
1479 without_accept_ch_without_lifetime_url());
1480 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansalc211d8b2018-03-19 19:21:581481 VerifyContentSettingsNotNotified();
Mike West2fddeeb72019-02-15 11:29:481482 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051483
Changwan Ryu434c3a32019-07-30 23:42:581484 // Allow JavaScript: Client hints should now be attached.
Tarun Bansala61f0f62017-10-24 23:53:051485 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1486 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
1487 GURL(), CONTENT_SETTINGS_TYPE_JAVASCRIPT,
1488 std::string(), CONTENT_SETTING_ALLOW);
1489
Tarun Bansal229647bd002018-02-27 17:33:361490 SetClientHintExpectationsOnMainFrame(true);
1491 SetClientHintExpectationsOnSubresources(true);
Tarun Bansala61f0f62017-10-24 23:53:051492 ui_test_utils::NavigateToURL(browser(),
1493 without_accept_ch_without_lifetime_url());
Tarun Bansal79df868e2018-03-20 23:01:361494
Mike West2fddeeb72019-02-15 11:29:481495 // The user agent hint is attached to all three requests:
1496 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
1497
1498 // Ten client hints are attached to the image request, and ten to the
1499 // main frame request.
1500 EXPECT_EQ(20u, count_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051501
1502 // Clear settings.
1503 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1504 ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
1505}
1506
Tarun Bansal73502f92019-04-16 21:21:191507// Test that if the content settings are malformed, then the browser does not
1508// crash.
1509IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
1510 ClientHintsMalformedContentSettings) {
1511 ContentSettingsForOneType client_hints_settings;
1512 HostContentSettingsMap* host_content_settings_map =
1513 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
1514
1515 // Add setting for the host.
1516 std::unique_ptr<base::ListValue> expiration_times_list =
1517 std::make_unique<base::ListValue>();
1518 expiration_times_list->AppendInteger(42 /* client hint value */);
1519 auto expiration_times_dictionary = std::make_unique<base::DictionaryValue>();
1520 expiration_times_dictionary->SetList("client_hints",
1521 std::move(expiration_times_list));
Aaron Tagliaboschi3c96a682019-10-29 18:10:281522 expiration_times_dictionary->SetDouble(
1523 "expiration_time",
1524 (base::Time::Now() + base::TimeDelta::FromDays(1)).ToDoubleT());
Tarun Bansal73502f92019-04-16 21:21:191525 host_content_settings_map->SetWebsiteSettingDefaultScope(
1526 without_accept_ch_without_lifetime_url(), GURL(),
1527 CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1528 std::make_unique<base::Value>(expiration_times_dictionary->Clone()));
1529
1530 // Reading the settings should now return one setting.
1531 host_content_settings_map->GetSettingsForOneType(
1532 CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1533 &client_hints_settings);
1534 EXPECT_EQ(1U, client_hints_settings.size());
1535
1536 SetClientHintExpectationsOnMainFrame(false);
1537 SetClientHintExpectationsOnSubresources(false);
1538 ui_test_utils::NavigateToURL(browser(),
1539 without_accept_ch_without_lifetime_url());
1540}
1541
Tarun Bansal229647bd002018-02-27 17:33:361542// Ensure that when the JavaScript is blocked, client hints requested using
Tarun Bansal3f343d7c2018-03-02 18:48:001543// Accept-CH are not attached to the request headers for subresources.
Tarun Bansal9a7051f2018-07-10 18:30:051544IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal229647bd002018-02-27 17:33:361545 ClientHintsNoLifetimeScriptNotAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:051546 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1547 : accept_ch_with_lifetime_url();
1548
Tarun Bansal1965b042017-09-07 04:59:191549 base::HistogramTester histogram_tester;
1550 ContentSettingsForOneType host_settings;
1551
1552 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1553 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1554 &host_settings);
1555 EXPECT_EQ(0u, host_settings.size());
1556
Tarun Bansal3f343d7c2018-03-02 18:48:001557 // Block the Javascript: Client hints should not be attached.
1558 SetClientHintExpectationsOnSubresources(false);
Tarun Bansal229647bd002018-02-27 17:33:361559 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1560 ->SetContentSettingDefaultScope(
1561 accept_ch_without_lifetime_img_localhost(), GURL(),
1562 CONTENT_SETTINGS_TYPE_JAVASCRIPT, std::string(),
1563 CONTENT_SETTING_BLOCK);
1564 ui_test_utils::NavigateToURL(browser(),
1565 accept_ch_without_lifetime_img_localhost());
Mike West2fddeeb72019-02-15 11:29:481566 EXPECT_EQ(0u, count_user_agent_hint_headers_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001567 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361568 EXPECT_EQ(1u, third_party_request_count_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001569 EXPECT_EQ(0u, third_party_client_hints_count_seen());
Tarun Bansal1965b042017-09-07 04:59:191570
Tarun Bansal3f343d7c2018-03-02 18:48:001571 // Allow the Javascript: Client hints should now be attached.
Tarun Bansal229647bd002018-02-27 17:33:361572 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1573 ->SetContentSettingDefaultScope(
1574 accept_ch_without_lifetime_img_localhost(), GURL(),
1575 CONTENT_SETTINGS_TYPE_JAVASCRIPT, std::string(),
1576 CONTENT_SETTING_ALLOW);
Tarun Bansal1965b042017-09-07 04:59:191577
Tarun Bansal229647bd002018-02-27 17:33:361578 SetClientHintExpectationsOnSubresources(true);
1579 ui_test_utils::NavigateToURL(browser(),
1580 accept_ch_without_lifetime_img_localhost());
Tarun Bansal3f343d7c2018-03-02 18:48:001581
Mike West2fddeeb72019-02-15 11:29:481582 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
1583 EXPECT_EQ(10u, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361584 EXPECT_EQ(2u, third_party_request_count_seen());
Mike West2fddeeb72019-02-15 11:29:481585 EXPECT_EQ(1u, third_party_client_hints_count_seen());
Tarun Bansalc211d8b2018-03-19 19:21:581586 VerifyContentSettingsNotNotified();
Tarun Bansal1965b042017-09-07 04:59:191587
Tarun Bansal229647bd002018-02-27 17:33:361588 // Clear settings.
1589 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1590 ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
Tarun Bansal1965b042017-09-07 04:59:191591
Tarun Bansal229647bd002018-02-27 17:33:361592 // Block the Javascript again: Client hints should not be attached.
Tarun Bansal3f343d7c2018-03-02 18:48:001593 SetClientHintExpectationsOnSubresources(false);
Tarun Bansal229647bd002018-02-27 17:33:361594 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1595 ->SetContentSettingDefaultScope(
1596 accept_ch_without_lifetime_img_localhost(), GURL(),
1597 CONTENT_SETTINGS_TYPE_JAVASCRIPT, std::string(),
1598 CONTENT_SETTING_BLOCK);
1599 ui_test_utils::NavigateToURL(browser(),
1600 accept_ch_without_lifetime_img_localhost());
Mike West2fddeeb72019-02-15 11:29:481601 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
1602 EXPECT_EQ(10u, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361603 EXPECT_EQ(3u, third_party_request_count_seen());
Mike West2fddeeb72019-02-15 11:29:481604 EXPECT_EQ(1u, third_party_client_hints_count_seen());
Tarun Bansal593790112018-03-20 04:53:341605
1606 // Clear settings.
1607 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1608 ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_JAVASCRIPT);
Tarun Bansal229647bd002018-02-27 17:33:361609}
1610
Tarun Bansala0c1fc32018-10-03 16:14:521611// Ensure that when the cookies is blocked, client hints are attached to the
Tarun Bansal3f343d7c2018-03-02 18:48:001612// request headers.
Tarun Bansal9a7051f2018-07-10 18:30:051613IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521614 ClientHintsLifetimeCookiesNotAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:051615 const GURL gurl = GetParam()
1616 ? http_equiv_accept_ch_without_lifetime_img_localhost()
1617 : accept_ch_without_lifetime_img_localhost();
1618
Tarun Bansal229647bd002018-02-27 17:33:361619 base::HistogramTester histogram_tester;
1620 ContentSettingsForOneType host_settings;
1621 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
1622 CookieSettingsFactory::GetForProfile(browser()->profile());
1623
Tarun Bansal1965b042017-09-07 04:59:191624 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1625 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1626 &host_settings);
1627 EXPECT_EQ(0u, host_settings.size());
1628
Tarun Bansal229647bd002018-02-27 17:33:361629 // Block cookies.
1630 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansal9a7051f2018-07-10 18:30:051631 ->SetContentSettingDefaultScope(gurl, GURL(),
1632 CONTENT_SETTINGS_TYPE_COOKIES,
1633 std::string(), CONTENT_SETTING_BLOCK);
Tarun Bansal229647bd002018-02-27 17:33:361634 base::RunLoop().RunUntilIdle();
1635
Tarun Bansal229647bd002018-02-27 17:33:361636 SetClientHintExpectationsOnSubresources(true);
Tarun Bansal9a7051f2018-07-10 18:30:051637 ui_test_utils::NavigateToURL(browser(), gurl);
Mike West2fddeeb72019-02-15 11:29:481638 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
1639 EXPECT_EQ(10u, count_client_hints_headers_seen());
Tarun Bansala0c1fc32018-10-03 16:14:521640 EXPECT_EQ(1u, third_party_request_count_seen());
Mike West2fddeeb72019-02-15 11:29:481641 EXPECT_EQ(1u, third_party_client_hints_count_seen());
Tarun Bansal593790112018-03-20 04:53:341642
1643 // Clear settings.
1644 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1645 ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_COOKIES);
Tarun Bansal1965b042017-09-07 04:59:191646}
1647
Tarun Bansal3ce0ca42018-06-25 22:52:221648// Verify that client hints are sent in the incognito profiles, and server
1649// client hint opt-ins are honored within the incognito profile.
Tarun Bansal9a7051f2018-07-10 18:30:051650IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal3ce0ca42018-06-25 22:52:221651 ClientHintsLifetimeFollowedByNoClientHintIncognito) {
Tarun Bansal9a7051f2018-07-10 18:30:051652 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1653 : accept_ch_with_lifetime_url();
1654
Tarun Bansal3ce0ca42018-06-25 22:52:221655 base::HistogramTester histogram_tester;
1656 Browser* incognito = CreateIncognitoBrowser();
1657 ContentSettingsForOneType host_settings;
1658
1659 HostContentSettingsMapFactory::GetForProfile(incognito->profile())
1660 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1661 &host_settings);
1662 EXPECT_EQ(0u, host_settings.size());
1663
Tarun Bansal9a7051f2018-07-10 18:30:051664 // Fetching |gurl| should persist the request for client hints.
1665 ui_test_utils::NavigateToURL(incognito, gurl);
Tarun Bansal3ce0ca42018-06-25 22:52:221666
1667 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1668
1669 content::FetchHistogramsFromChildProcesses();
1670 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1671
Mike West2fddeeb72019-02-15 11:29:481672 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize", 11u, 1);
Tarun Bansal3ce0ca42018-06-25 22:52:221673 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
1674 // seconds.
1675 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
1676 3600 * 1000, 1);
1677 base::RunLoop().RunUntilIdle();
1678
1679 // Clients hints preferences for one origin should be persisted.
1680 HostContentSettingsMapFactory::GetForProfile(incognito->profile())
1681 ->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS, std::string(),
1682 &host_settings);
1683 EXPECT_EQ(1u, host_settings.size());
1684
1685 SetClientHintExpectationsOnMainFrame(true);
1686 SetClientHintExpectationsOnSubresources(true);
1687 ui_test_utils::NavigateToURL(incognito,
1688 without_accept_ch_without_lifetime_url());
1689
Mike West2fddeeb72019-02-15 11:29:481690 // The user agent hint is attached to all three requests:
1691 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
1692
1693 // Ten client hints are attached to the image request, and ten to the
1694 // main frame request.
1695 EXPECT_EQ(20u, count_client_hints_headers_seen());
Tarun Bansal3ce0ca42018-06-25 22:52:221696
1697 // Navigate using regular profile. Client hints should not be send.
1698 SetClientHintExpectationsOnMainFrame(false);
1699 SetClientHintExpectationsOnSubresources(false);
1700 ui_test_utils::NavigateToURL(browser(),
1701 without_accept_ch_without_lifetime_url());
1702
Mike West2fddeeb72019-02-15 11:29:481703 // The user agent hint is attached to the two new requests.
1704 EXPECT_EQ(5u, count_user_agent_hint_headers_seen());
1705
1706 // No additional hints are sent.
1707 EXPECT_EQ(20u, count_client_hints_headers_seen());
Tarun Bansal3ce0ca42018-06-25 22:52:221708}
Tarun Bansalbef6d652018-10-02 18:41:011709
1710class ClientHintsWebHoldbackBrowserTest : public ClientHintsBrowserTest {
1711 public:
1712 ClientHintsWebHoldbackBrowserTest() : ClientHintsBrowserTest() {
1713 ConfigureHoldbackExperiment();
1714 }
1715
1716 net::EffectiveConnectionType web_effective_connection_type_override() const {
1717 return web_effective_connection_type_override_;
1718 }
1719
Mike West2fddeeb72019-02-15 11:29:481720 std::unique_ptr<base::FeatureList> EnabledFeatures() override {
Tarun Bansalbef6d652018-10-02 18:41:011721 base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
1722 const std::string kTrialName = "TrialFoo";
1723 const std::string kGroupName = "GroupFoo"; // Value not used
1724
1725 scoped_refptr<base::FieldTrial> trial =
1726 base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
1727
1728 std::map<std::string, std::string> params;
1729
1730 params["web_effective_connection_type_override"] =
1731 net::GetNameForEffectiveConnectionType(
1732 web_effective_connection_type_override_);
Mike West2fddeeb72019-02-15 11:29:481733 EXPECT_TRUE(
Tarun Bansalbef6d652018-10-02 18:41:011734 base::FieldTrialParamAssociator::GetInstance()
1735 ->AssociateFieldTrialParams(kTrialName, kGroupName, params));
1736
1737 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
Mike West2fddeeb72019-02-15 11:29:481738 feature_list->InitializeFromCommandLine("UserAgentClientHint", "");
Tarun Bansalbef6d652018-10-02 18:41:011739 feature_list->RegisterFieldTrialOverride(
1740 features::kNetworkQualityEstimatorWebHoldback.name,
1741 base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
Mike West2fddeeb72019-02-15 11:29:481742 return feature_list;
Tarun Bansalbef6d652018-10-02 18:41:011743 }
1744
Mike West2fddeeb72019-02-15 11:29:481745 private:
1746 void ConfigureHoldbackExperiment() {}
1747
Tarun Bansalbef6d652018-10-02 18:41:011748 const net::EffectiveConnectionType web_effective_connection_type_override_ =
1749 net::EFFECTIVE_CONNECTION_TYPE_3G;
Tarun Bansalbef6d652018-10-02 18:41:011750};
1751
1752// Make sure that when NetInfo holdback experiment is enabled, the NetInfo APIs
1753// and client hints return the overridden values. Verify that the client hints
1754// are overridden on both main frame and subresource requests.
1755IN_PROC_BROWSER_TEST_F(ClientHintsWebHoldbackBrowserTest,
1756 EffectiveConnectionTypeChangeNotified) {
1757 SetExpectedEffectiveConnectionType(web_effective_connection_type_override());
1758
1759 SetClientHintExpectationsOnMainFrame(false);
1760 SetClientHintExpectationsOnSubresources(true);
1761
1762 base::RunLoop().RunUntilIdle();
1763
1764 EXPECT_TRUE(embedded_test_server()->Start());
1765 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
1766 EXPECT_EQ(0u, count_client_hints_headers_seen());
1767 EXPECT_EQ(0u, third_party_request_count_seen());
1768 EXPECT_EQ(0u, third_party_client_hints_count_seen());
1769
1770 SetClientHintExpectationsOnMainFrame(true);
1771 SetClientHintExpectationsOnSubresources(true);
1772 ui_test_utils::NavigateToURL(
1773 browser(), accept_ch_without_lifetime_with_subresource_url());
1774 base::RunLoop().RunUntilIdle();
1775 content::FetchHistogramsFromChildProcesses();
1776 SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
1777
Mike West2fddeeb72019-02-15 11:29:481778 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
1779 EXPECT_EQ(20u, count_client_hints_headers_seen());
Tarun Bansalbef6d652018-10-02 18:41:011780 EXPECT_EQ(0u, third_party_request_count_seen());
1781 EXPECT_EQ(0u, third_party_client_hints_count_seen());
1782}