blob: b80be8a23d2fe932d50680fefee7696f41bef3a0 [file] [log] [blame]
Tarun Bansal0b8b7afd2017-08-25 03:52:161// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Tarun Bansal62efba12018-05-04 22:58:355#include <cctype>
Peter Boström924f8032021-04-02 20:36:026#include <memory>
Tarun Bansal62efba12018-05-04 22:58:357
Mike West2fddeeb72019-02-15 11:29:488#include "base/base_switches.h"
Tarun Bansal229647bd002018-02-27 17:33:369#include "base/bind.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1610#include "base/command_line.h"
Jan Wilken Dörrieb5a41c32020-12-09 18:55:4711#include "base/containers/contains.h"
Tarun Bansalbef6d652018-10-02 18:41:0112#include "base/metrics/field_trial_param_associator.h"
Gabriel Charetteb71eec892017-09-14 22:52:5613#include "base/run_loop.h"
Ali Beyad7417fc22021-08-06 03:09:5814#include "base/strings/strcat.h"
Mike Weste555be862019-02-20 16:17:3015#include "base/strings/string_util.h"
Callum May7d88ff3e2019-11-12 18:21:4616#include "base/synchronization/lock.h"
Ali Beyad7417fc22021-08-06 03:09:5817#include "base/test/bind.h"
Devlin Cronin626d80c2018-06-01 01:08:3618#include "base/test/metrics/histogram_tester.h"
Tarun Bansal5c28afb2018-03-17 02:55:2019#include "build/build_config.h"
Tarun Bansala61f0f62017-10-24 23:53:0520#include "chrome/browser/content_settings/cookie_settings_factory.h"
Tarun Bansal1965b042017-09-07 04:59:1921#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
François Beaufort34e299e2021-05-26 05:54:3322#include "chrome/browser/devtools/protocol/devtools_protocol_test_support.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1623#include "chrome/browser/profiles/profile.h"
Tarun Bansal1965b042017-09-07 04:59:1924#include "chrome/browser/ui/browser.h"
Maks Orlovich73f374d2020-04-02 12:46:1325#include "chrome/browser/ui/browser_commands.h"
Aaron Tagliaboschi25625c22021-05-11 18:13:5926#include "chrome/test/base/chrome_test_utils.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1627#include "chrome/test/base/in_process_browser_test.h"
28#include "chrome/test/base/ui_test_utils.h"
Carlos Caballerob4283202020-08-10 14:40:4629#include "components/content_settings/browser/page_specific_content_settings.h"
Tarun Bansala61f0f62017-10-24 23:53:0530#include "components/content_settings/core/browser/cookie_settings.h"
Tarun Bansal1965b042017-09-07 04:59:1931#include "components/content_settings/core/browser/host_content_settings_map.h"
Tarun Bansala61f0f62017-10-24 23:53:0532#include "components/content_settings/core/common/pref_names.h"
Ali Beyad7417fc22021-08-06 03:09:5833#include "components/embedder_support/switches.h"
John Abd-El-Malekec1fc69e2021-01-28 19:14:4134#include "components/embedder_support/user_agent_utils.h"
John Abd-El-Malek161073c2020-06-12 20:40:2835#include "components/metrics/content/subprocess_metrics_provider.h"
Aaron Tagliaboschi25625c22021-05-11 18:13:5936#include "components/page_load_metrics/browser/page_load_metrics_test_waiter.h"
Tarun Bansala61f0f62017-10-24 23:53:0537#include "components/prefs/pref_service.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1638#include "content/public/browser/browser_thread.h"
Maks Orlovich73f374d2020-04-02 12:46:1339#include "content/public/browser/navigation_entry.h"
Ali Beyad7417fc22021-08-06 03:09:5840#include "content/public/browser/navigation_handle.h"
Changwan Ryu434c3a32019-07-30 23:42:5841#include "content/public/browser/render_view_host.h"
Ali Beyad7417fc22021-08-06 03:09:5842#include "content/public/browser/web_contents_observer.h"
Tarun Bansalbef6d652018-10-02 18:41:0143#include "content/public/common/content_features.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1644#include "content/public/common/content_switches.h"
Peter Kasting919ce652020-05-07 10:22:3645#include "content/public/test/browser_test.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1646#include "content/public/test/browser_test_utils.h"
Ali Beyad7417fc22021-08-06 03:09:5847#include "content/public/test/content_browser_test.h"
48#include "content/public/test/content_browser_test_utils.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1649#include "content/public/test/test_utils.h"
Tarun Bansal229647bd002018-02-27 17:33:3650#include "content/public/test/url_loader_interceptor.h"
51#include "net/dns/mock_host_resolver.h"
52#include "net/http/http_request_headers.h"
Tarun Bansal7f3fe8c2018-04-06 22:37:4753#include "net/nqe/effective_connection_type.h"
Tarun Bansal0b8b7afd2017-08-25 03:52:1654#include "net/test/embedded_test_server/embedded_test_server.h"
Tarun Bansal1965b042017-09-07 04:59:1955#include "net/test/embedded_test_server/http_request.h"
Tarun Bansal229647bd002018-02-27 17:33:3656#include "net/test/embedded_test_server/http_response.h"
Aaron Tagliaboschi603540d22021-04-05 00:37:1457#include "services/network/public/cpp/client_hints.h"
Tarun Bansal74e189d2018-05-07 19:07:3558#include "services/network/public/cpp/cors/cors.h"
Tarun Bansalceab9592018-05-01 18:57:3559#include "services/network/public/cpp/features.h"
Tarun Bansal7f3fe8c2018-04-06 22:37:4760#include "services/network/public/cpp/network_switches.h"
Ali Beyad7417fc22021-08-06 03:09:5861#include "services/network/public/cpp/resource_request.h"
Aaron Tagliaboschi603540d22021-04-05 00:37:1462#include "services/network/public/mojom/web_client_hints_types.mojom-shared.h"
Ali Beyad7417fc22021-08-06 03:09:5863#include "testing/gmock/include/gmock/gmock-matchers.h"
Ali Beyada6b0fb6f2021-07-28 00:13:2464#include "testing/gmock/include/gmock/gmock.h"
Ali Beyad7417fc22021-08-06 03:09:5865#include "third_party/abseil-cpp/absl/types/optional.h"
Blink Reformata30d4232018-04-07 15:31:0666#include "third_party/blink/public/common/client_hints/client_hints.h"
Gyuyoung Kim1ac4ca782020-09-11 03:32:5167#include "third_party/blink/public/common/web_preferences/web_preferences.h"
Ali Beyad4074a9c52021-08-17 16:15:5168#include "third_party/re2/src/re2/re2.h"
Tarun Bansal229647bd002018-02-27 17:33:3669
70namespace {
71
Ali Beyadf05102d2021-08-23 16:53:4072using ::content::URLLoaderInterceptor;
Ali Beyada6b0fb6f2021-07-28 00:13:2473using ::testing::Eq;
74using ::testing::Optional;
75
Max Curran99cbec1492021-08-16 19:54:2676constexpr unsigned expected_client_hints_number = 14u;
Ali Beyada6b0fb6f2021-07-28 00:13:2477constexpr int32_t uma_histogram_max_value = 1471228928;
Yoav Weissd33bacb2020-03-12 06:42:2178
Tarun Bansal229647bd002018-02-27 17:33:3679// An interceptor that records count of fetches and client hint headers for
80// requests to https://foo.com/non-existing-image.jpg.
Jay Civelli1ff872d2018-03-09 21:52:1681class ThirdPartyURLLoaderInterceptor {
Tarun Bansal229647bd002018-02-27 17:33:3682 public:
Jay Civelli1ff872d2018-03-09 21:52:1683 explicit ThirdPartyURLLoaderInterceptor(const GURL intercepted_url)
84 : intercepted_url_(intercepted_url),
85 interceptor_(base::BindRepeating(
86 &ThirdPartyURLLoaderInterceptor::InterceptURLRequest,
87 base::Unretained(this))) {}
Tarun Bansal229647bd002018-02-27 17:33:3688
Jay Civelli1ff872d2018-03-09 21:52:1689 ~ThirdPartyURLLoaderInterceptor() = default;
Tarun Bansal229647bd002018-02-27 17:33:3690
91 size_t request_count_seen() const { return request_count_seen_; }
92
93 size_t client_hints_count_seen() const { return client_hints_count_seen_; }
94
95 private:
Ali Beyadf05102d2021-08-23 16:53:4096 bool InterceptURLRequest(URLLoaderInterceptor::RequestParams* params) {
Jay Civelli1ff872d2018-03-09 21:52:1697 if (params->url_request.url != intercepted_url_)
98 return false;
Tarun Bansal229647bd002018-02-27 17:33:3699
Jay Civelli1ff872d2018-03-09 21:52:16100 request_count_seen_++;
Mike West14c11102019-02-04 16:16:47101 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Tarun Bansalf9cf9892018-04-06 04:38:01102 if (params->url_request.headers.HasHeader(
103 blink::kClientHintsHeaderMapping[i])) {
104 client_hints_count_seen_++;
105 }
Tarun Bansal5c28afb2018-03-17 02:55:20106 }
Jay Civelli1ff872d2018-03-09 21:52:16107 return false;
108 }
Tarun Bansal229647bd002018-02-27 17:33:36109
Jay Civelli1ff872d2018-03-09 21:52:16110 GURL intercepted_url_;
111
112 size_t request_count_seen_ = 0u;
113
114 size_t client_hints_count_seen_ = 0u;
115
Ali Beyadf05102d2021-08-23 16:53:40116 URLLoaderInterceptor interceptor_;
Jay Civelli1ff872d2018-03-09 21:52:16117
118 DISALLOW_COPY_AND_ASSIGN(ThirdPartyURLLoaderInterceptor);
Tarun Bansal229647bd002018-02-27 17:33:36119};
120
Tarun Bansal62efba12018-05-04 22:58:35121// Returns true only if |header_value| satisfies ABNF: 1*DIGIT [ "." 1*DIGIT ]
122bool IsSimilarToDoubleABNF(const std::string& header_value) {
123 if (header_value.empty())
124 return false;
125 char first_char = header_value.at(0);
126 if (!isdigit(first_char))
127 return false;
128
129 bool period_found = false;
130 bool digit_found_after_period = false;
131 for (char ch : header_value) {
132 if (isdigit(ch)) {
133 if (period_found) {
134 digit_found_after_period = true;
135 }
136 continue;
137 }
138 if (ch == '.') {
139 if (period_found)
140 return false;
141 period_found = true;
142 continue;
143 }
144 return false;
145 }
146 if (period_found)
147 return digit_found_after_period;
148 return true;
149}
150
151// Returns true only if |header_value| satisfies ABNF: 1*DIGIT
152bool IsSimilarToIntABNF(const std::string& header_value) {
153 if (header_value.empty())
154 return false;
155
156 for (char ch : header_value) {
157 if (!isdigit(ch))
158 return false;
159 }
160 return true;
161}
162
Tarun Bansal229647bd002018-02-27 17:33:36163} // namespace
Tarun Bansal0b8b7afd2017-08-25 03:52:16164
Ali Beyad0a4a3d712021-07-19 17:07:40165class ClientHintsBrowserTest : public InProcessBrowserTest,
Tarun Bansal9a7051f2018-07-10 18:30:05166 public testing::WithParamInterface<bool> {
Tarun Bansal0b8b7afd2017-08-25 03:52:16167 public:
168 ClientHintsBrowserTest()
Mikel Astiz2de748d2019-11-16 10:39:36169 : http_server_(net::EmbeddedTestServer::TYPE_HTTP),
Tarun Bansal3b330b02017-11-09 19:03:14170 https_server_(net::EmbeddedTestServer::TYPE_HTTPS),
Tarun Bansal345418632018-06-29 11:07:04171 https_cross_origin_server_(net::EmbeddedTestServer::TYPE_HTTPS),
Tarun Bansal229647bd002018-02-27 17:33:36172 expect_client_hints_on_main_frame_(false),
173 expect_client_hints_on_subresources_(false),
Mike West2fddeeb72019-02-15 11:29:48174 count_user_agent_hint_headers_seen_(0),
Maks Orlovich5dcc99c2020-02-13 19:07:46175 count_ua_mobile_client_hints_headers_seen_(0),
Aaron Tagliaboschiec5bce62021-06-24 18:50:09176 count_ua_platform_client_hints_headers_seen_(0),
Tarun Bansal229647bd002018-02-27 17:33:36177 count_client_hints_headers_seen_(0),
178 request_interceptor_(nullptr) {
Tarun Bansal3b330b02017-11-09 19:03:14179 http_server_.ServeFilesFromSourceDirectory("chrome/test/data/client_hints");
Tarun Bansal0b8b7afd2017-08-25 03:52:16180 https_server_.ServeFilesFromSourceDirectory(
181 "chrome/test/data/client_hints");
Tarun Bansal345418632018-06-29 11:07:04182 https_cross_origin_server_.ServeFilesFromSourceDirectory(
183 "chrome/test/data/client_hints");
Tarun Bansal1965b042017-09-07 04:59:19184
Tarun Bansal3b330b02017-11-09 19:03:14185 http_server_.RegisterRequestMonitor(
Tarun Bansal345418632018-06-29 11:07:04186 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
187 base::Unretained(this)));
Tarun Bansal1965b042017-09-07 04:59:19188 https_server_.RegisterRequestMonitor(
Tarun Bansal345418632018-06-29 11:07:04189 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
190 base::Unretained(this)));
191 https_cross_origin_server_.RegisterRequestMonitor(
192 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
193 base::Unretained(this)));
Tarun Bansal293a7b6c2018-12-05 17:41:12194 https_cross_origin_server_.RegisterRequestHandler(
195 base::BindRepeating(&ClientHintsBrowserTest::RequestHandlerToRedirect,
196 base::Unretained(this)));
Tarun Bansal345418632018-06-29 11:07:04197 https_server_.RegisterRequestHandler(base::BindRepeating(
198 &ClientHintsBrowserTest::RequestHandlerToFetchCrossOriginIframe,
199 base::Unretained(this)));
Tarun Bansal1965b042017-09-07 04:59:19200
Tarun Bansal3b330b02017-11-09 19:03:14201 EXPECT_TRUE(http_server_.Start());
Tarun Bansal0b8b7afd2017-08-25 03:52:16202 EXPECT_TRUE(https_server_.Start());
Tarun Bansal345418632018-06-29 11:07:04203 EXPECT_TRUE(https_cross_origin_server_.Start());
204
205 EXPECT_NE(https_server_.base_url(), https_cross_origin_server_.base_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:16206
Tarun Bansal3b330b02017-11-09 19:03:14207 accept_ch_with_lifetime_http_local_url_ =
208 http_server_.GetURL("/accept_ch_with_lifetime.html");
Tarun Bansal9a7051f2018-07-10 18:30:05209 http_equiv_accept_ch_with_lifetime_http_local_url_ =
210 http_server_.GetURL("/http_equiv_accept_ch_with_lifetime.html");
Tarun Bansal3b330b02017-11-09 19:03:14211 EXPECT_TRUE(accept_ch_with_lifetime_http_local_url_.SchemeIsHTTPOrHTTPS());
212 EXPECT_FALSE(
213 accept_ch_with_lifetime_http_local_url_.SchemeIsCryptographic());
214
Tarun Bansal1965b042017-09-07 04:59:19215 accept_ch_with_lifetime_url_ =
216 https_server_.GetURL("/accept_ch_with_lifetime.html");
Tarun Bansal73502f92019-04-16 21:21:19217 accept_ch_with_short_lifetime_url_ =
218 https_server_.GetURL("/accept_ch_with_short_lifetime.html");
Tarun Bansal0b8b7afd2017-08-25 03:52:16219
Tarun Bansal1965b042017-09-07 04:59:19220 accept_ch_without_lifetime_url_ =
221 https_server_.GetURL("/accept_ch_without_lifetime.html");
222 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsHTTPOrHTTPS());
223 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal9a7051f2018-07-10 18:30:05224 http_equiv_accept_ch_without_lifetime_url_ =
225 https_server_.GetURL("/http_equiv_accept_ch_without_lifetime.html");
Tarun Bansal1965b042017-09-07 04:59:19226
227 without_accept_ch_without_lifetime_url_ =
228 https_server_.GetURL("/without_accept_ch_without_lifetime.html");
229 EXPECT_TRUE(without_accept_ch_without_lifetime_url_.SchemeIsHTTPOrHTTPS());
230 EXPECT_TRUE(
231 without_accept_ch_without_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal3b330b02017-11-09 19:03:14232
233 without_accept_ch_without_lifetime_local_url_ =
234 http_server_.GetURL("/without_accept_ch_without_lifetime.html");
235 EXPECT_TRUE(
236 without_accept_ch_without_lifetime_local_url_.SchemeIsHTTPOrHTTPS());
237 EXPECT_FALSE(
238 without_accept_ch_without_lifetime_local_url_.SchemeIsCryptographic());
Tarun Bansaladd5e1812018-02-09 19:07:58239
240 without_accept_ch_without_lifetime_img_localhost_ = https_server_.GetURL(
241 "/without_accept_ch_without_lifetime_img_localhost.html");
242 without_accept_ch_without_lifetime_img_foo_com_ = https_server_.GetURL(
243 "/without_accept_ch_without_lifetime_img_foo_com.html");
244 accept_ch_without_lifetime_with_iframe_url_ =
245 https_server_.GetURL("/accept_ch_without_lifetime_with_iframe.html");
Tarun Bansal9a7051f2018-07-10 18:30:05246 http_equiv_accept_ch_without_lifetime_with_iframe_url_ =
247 https_server_.GetURL(
248 "/http_equiv_accept_ch_without_lifetime_with_iframe.html");
Tarun Bansal62cc3542018-06-27 23:53:30249 accept_ch_without_lifetime_with_subresource_url_ = https_server_.GetURL(
250 "/accept_ch_without_lifetime_with_subresource.html");
Tarun Bansal9a7051f2018-07-10 18:30:05251 http_equiv_accept_ch_without_lifetime_with_subresource_url_ =
252 https_server_.GetURL(
253 "/http_equiv_accept_ch_without_lifetime_with_subresource.html");
Tarun Bansal62cc3542018-06-27 23:53:30254 accept_ch_without_lifetime_with_subresource_iframe_url_ =
255 https_server_.GetURL(
256 "/accept_ch_without_lifetime_with_subresource_iframe.html");
Tarun Bansal9a7051f2018-07-10 18:30:05257 http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_ =
258 https_server_.GetURL(
259 "/http_equiv_accept_ch_without_lifetime_with_subresource_iframe."
260 "html");
Tarun Bansal229647bd002018-02-27 17:33:36261 accept_ch_without_lifetime_img_localhost_ =
262 https_server_.GetURL("/accept_ch_without_lifetime_img_localhost.html");
Tarun Bansal9a7051f2018-07-10 18:30:05263 http_equiv_accept_ch_without_lifetime_img_localhost_ = https_server_.GetURL(
264 "/http_equiv_accept_ch_without_lifetime_img_localhost.html");
265 http_equiv_accept_ch_with_lifetime_ =
266 https_server_.GetURL("/http_equiv_accept_ch_with_lifetime.html");
Tarun Bansal293a7b6c2018-12-05 17:41:12267
268 redirect_url_ = https_cross_origin_server_.GetURL("/redirect.html");
Maks Orlovich7a588d82020-05-06 15:17:24269
270 accept_ch_empty_ = https_server_.GetURL("/accept_ch_empty.html");
271 http_equiv_accept_ch_merge_ =
272 https_server_.GetURL("/http_equiv_accept_ch_merge.html");
Tarun Bansal0b8b7afd2017-08-25 03:52:16273 }
274
275 ~ClientHintsBrowserTest() override {}
276
Mike West2fddeeb72019-02-15 11:29:48277 virtual std::unique_ptr<base::FeatureList> EnabledFeatures() {
278 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
Maks Orlovichc66745a2020-06-30 17:40:02279 feature_list->InitializeFromCommandLine(
Aaron Tagliaboschi603540d22021-04-05 00:37:14280 "UserAgentClientHint,LangClientHintHeader,CriticalClientHint,"
Max Curran99cbec1492021-08-16 19:54:26281 "AcceptCHFrame,PrefersColorSchemeClientHintHeader,"
282 "ViewportHeightClientHintHeader",
Aaron Tagliaboschi603540d22021-04-05 00:37:14283 "");
Mike West2fddeeb72019-02-15 11:29:48284 return feature_list;
285 }
286
287 void SetUp() override {
Maksim Sisov (GMT+3)830244f2020-08-10 12:52:24288 scoped_feature_list_.InitWithFeatureList(EnabledFeatures());
Mike West2fddeeb72019-02-15 11:29:48289 InProcessBrowserTest::SetUp();
290 }
291
Tarun Bansal0b8b7afd2017-08-25 03:52:16292 void SetUpOnMainThread() override {
Tarun Bansal229647bd002018-02-27 17:33:36293 host_resolver()->AddRule("*", "127.0.0.1");
Tarun Bansal229647bd002018-02-27 17:33:36294
Jay Civelli1ff872d2018-03-09 21:52:16295 request_interceptor_ = std::make_unique<ThirdPartyURLLoaderInterceptor>(
296 GURL("https://foo.com/non-existing-image.jpg"));
Tarun Bansal229647bd002018-02-27 17:33:36297 base::RunLoop().RunUntilIdle();
Tarun Bansal0b8b7afd2017-08-25 03:52:16298 }
299
Jay Civelli1ff872d2018-03-09 21:52:16300 void TearDownOnMainThread() override { request_interceptor_.reset(); }
301
Tarun Bansal0b8b7afd2017-08-25 03:52:16302 void SetUpCommandLine(base::CommandLine* cmd) override {
Tarun Bansal7f3fe8c2018-04-06 22:37:47303 cmd->AppendSwitchASCII(network::switches::kForceEffectiveConnectionType,
304 net::kEffectiveConnectionType2G);
Tarun Bansal0b8b7afd2017-08-25 03:52:16305 }
306
Tarun Bansal229647bd002018-02-27 17:33:36307 void SetClientHintExpectationsOnMainFrame(bool expect_client_hints) {
308 expect_client_hints_on_main_frame_ = expect_client_hints;
Tarun Bansal1965b042017-09-07 04:59:19309 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16310
Tarun Bansal229647bd002018-02-27 17:33:36311 void SetClientHintExpectationsOnSubresources(bool expect_client_hints) {
Callum May1d939742020-03-02 17:51:30312 base::AutoLock lock(expect_client_hints_on_subresources_lock_);
Tarun Bansal229647bd002018-02-27 17:33:36313 expect_client_hints_on_subresources_ = expect_client_hints;
Tarun Bansala61f0f62017-10-24 23:53:05314 }
315
Callum May1d939742020-03-02 17:51:30316 bool expect_client_hints_on_subresources() {
317 base::AutoLock lock(expect_client_hints_on_subresources_lock_);
318 return expect_client_hints_on_subresources_;
319 }
320
Tarun Bansalc211d8b2018-03-19 19:21:58321 // Verify that the user is not notified that cookies or JavaScript were
322 // blocked on the webpage due to the checks done by client hints.
323 void VerifyContentSettingsNotNotified() const {
Carlos Caballerob4283202020-08-10 14:40:46324 auto* pscs = content_settings::PageSpecificContentSettings::GetForFrame(
Carlos Caballerod7b759412020-07-31 18:00:08325 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
Carlos Caballerob4283202020-08-10 14:40:46326 EXPECT_FALSE(pscs->IsContentBlocked(ContentSettingsType::COOKIES));
327 EXPECT_FALSE(pscs->IsContentBlocked(ContentSettingsType::JAVASCRIPT));
Tarun Bansalc211d8b2018-03-19 19:21:58328 }
329
Tarun Bansalbef6d652018-10-02 18:41:01330 void SetExpectedEffectiveConnectionType(
331 net::EffectiveConnectionType effective_connection_type) {
332 expected_ect = effective_connection_type;
333 }
334
Changwan Ryu434c3a32019-07-30 23:42:58335 void SetJsEnabledForActiveView(bool enabled) {
Rakina Zata Amni347b70902020-07-22 10:49:04336 content::WebContents* web_contents =
337 browser()->tab_strip_model()->GetActiveWebContents();
Gyuyoung Kim1ac4ca782020-09-11 03:32:51338 blink::web_pref::WebPreferences prefs =
339 web_contents->GetOrCreateWebPreferences();
Changwan Ryu434c3a32019-07-30 23:42:58340 prefs.javascript_enabled = enabled;
Rakina Zata Amni347b70902020-07-22 10:49:04341 web_contents->SetWebPreferences(prefs);
Changwan Ryu434c3a32019-07-30 23:42:58342 }
343
Maks Orlovich7227ce0d2020-02-28 17:13:16344 void TestProfilesIndependent(Browser* browser_a, Browser* browser_b);
345
Tarun Bansal3b330b02017-11-09 19:03:14346 const GURL& accept_ch_with_lifetime_http_local_url() const {
347 return accept_ch_with_lifetime_http_local_url_;
348 }
Tarun Bansal9a7051f2018-07-10 18:30:05349 const GURL& http_equiv_accept_ch_with_lifetime_http_local_url() const {
350 return http_equiv_accept_ch_with_lifetime_http_local_url_;
351 }
Tarun Bansal3b330b02017-11-09 19:03:14352
Tarun Bansal1965b042017-09-07 04:59:19353 // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
354 // headers.
355 const GURL& accept_ch_with_lifetime_url() const {
356 return accept_ch_with_lifetime_url_;
357 }
Tarun Bansal9a7051f2018-07-10 18:30:05358 const GURL& http_equiv_accept_ch_with_lifetime() {
359 return http_equiv_accept_ch_with_lifetime_;
360 }
Tarun Bansal1965b042017-09-07 04:59:19361
Tarun Bansal73502f92019-04-16 21:21:19362 // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
363 // headers. The Accept-CH-Lifetime duration is set very short to 1 second.
364 const GURL& accept_ch_with_short_lifetime() const {
365 return accept_ch_with_short_lifetime_url_;
366 }
367
Tarun Bansal1965b042017-09-07 04:59:19368 // A URL whose response headers include only Accept-CH header.
369 const GURL& accept_ch_without_lifetime_url() const {
370 return accept_ch_without_lifetime_url_;
371 }
Tarun Bansal9a7051f2018-07-10 18:30:05372 const GURL& http_equiv_accept_ch_without_lifetime_url() const {
373 return http_equiv_accept_ch_without_lifetime_url_;
374 }
Tarun Bansal1965b042017-09-07 04:59:19375
376 // A URL whose response headers do not include either Accept-CH or
377 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
378 const GURL& without_accept_ch_without_lifetime_url() const {
379 return without_accept_ch_without_lifetime_url_;
380 }
381
Tarun Bansal3b330b02017-11-09 19:03:14382 // A URL whose response headers do not include either Accept-CH or
383 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
384 const GURL& without_accept_ch_without_lifetime_local_url() const {
385 return without_accept_ch_without_lifetime_local_url_;
386 }
387
Tarun Bansaladd5e1812018-02-09 19:07:58388 // A URL whose response headers do not include either Accept-CH or
389 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
390 // from localhost.
391 const GURL& without_accept_ch_without_lifetime_img_localhost() const {
392 return without_accept_ch_without_lifetime_img_localhost_;
393 }
394
395 // A URL whose response headers do not include either Accept-CH or
396 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
397 // from foo.com.
398 const GURL& without_accept_ch_without_lifetime_img_foo_com() const {
399 return without_accept_ch_without_lifetime_img_foo_com_;
400 }
401
402 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
403 // headers. The response loads accept_ch_with_lifetime_url() in an iframe.
404 const GURL& accept_ch_without_lifetime_with_iframe_url() const {
405 return accept_ch_without_lifetime_with_iframe_url_;
406 }
Tarun Bansal9a7051f2018-07-10 18:30:05407 const GURL& http_equiv_accept_ch_without_lifetime_with_iframe_url() const {
408 return http_equiv_accept_ch_without_lifetime_with_iframe_url_;
409 }
Tarun Bansaladd5e1812018-02-09 19:07:58410
Tarun Bansal62cc3542018-06-27 23:53:30411 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
412 // headers. The response loads accept_ch_with_lifetime_url() as a subresource
413 // in the main frame.
414 const GURL& accept_ch_without_lifetime_with_subresource_url() const {
415 return accept_ch_without_lifetime_with_subresource_url_;
416 }
Tarun Bansal9a7051f2018-07-10 18:30:05417 const GURL& http_equiv_accept_ch_without_lifetime_with_subresource_url()
418 const {
419 return http_equiv_accept_ch_without_lifetime_with_subresource_url_;
420 }
Tarun Bansal62cc3542018-06-27 23:53:30421
422 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
Tarun Bansal9a7051f2018-07-10 18:30:05423 // headers. The response loads accept_ch_with_lifetime_url() or
424 // http_equiv_accept_ch_with_lifetime_url() as a subresource in the iframe.
Tarun Bansal62cc3542018-06-27 23:53:30425 const GURL& accept_ch_without_lifetime_with_subresource_iframe_url() const {
426 return accept_ch_without_lifetime_with_subresource_iframe_url_;
427 }
Tarun Bansal9a7051f2018-07-10 18:30:05428 const GURL&
429 http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url() const {
430 return http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_;
431 }
Tarun Bansal62cc3542018-06-27 23:53:30432
Tarun Bansal9a7051f2018-07-10 18:30:05433 // A URL whose response includes only Accept-CH header. Navigating to
Tarun Bansal229647bd002018-02-27 17:33:36434 // this URL also fetches two images: One from the localhost, and one from
435 // foo.com.
436 const GURL& accept_ch_without_lifetime_img_localhost() const {
437 return accept_ch_without_lifetime_img_localhost_;
438 }
Tarun Bansal9a7051f2018-07-10 18:30:05439 const GURL& http_equiv_accept_ch_without_lifetime_img_localhost() const {
440 return http_equiv_accept_ch_without_lifetime_img_localhost_;
441 }
Tarun Bansal229647bd002018-02-27 17:33:36442
Tarun Bansal293a7b6c2018-12-05 17:41:12443 const GURL& redirect_url() const { return redirect_url_; }
444
Maks Orlovich7a588d82020-05-06 15:17:24445 // A URL to a page with a response containing an empty accept_ch header.
446 const GURL& accept_ch_empty() const { return accept_ch_empty_; }
447
448 // A page where some hints are in accept-ch header, some in http-equiv.
449 const GURL& http_equiv_accept_ch_merge() const {
450 return http_equiv_accept_ch_merge_;
451 }
452
Mike West2fddeeb72019-02-15 11:29:48453 size_t count_user_agent_hint_headers_seen() const {
Callum May7d88ff3e2019-11-12 18:21:46454 base::AutoLock lock(count_headers_lock_);
Mike West2fddeeb72019-02-15 11:29:48455 return count_user_agent_hint_headers_seen_;
456 }
457
Maks Orlovich5dcc99c2020-02-13 19:07:46458 size_t count_ua_mobile_client_hints_headers_seen() const {
459 base::AutoLock lock(count_headers_lock_);
460 return count_ua_mobile_client_hints_headers_seen_;
461 }
462
Aaron Tagliaboschiec5bce62021-06-24 18:50:09463 size_t count_ua_platform_client_hints_headers_seen() const {
464 base::AutoLock lock(count_headers_lock_);
465 return count_ua_platform_client_hints_headers_seen_;
466 }
467
Tarun Bansal1965b042017-09-07 04:59:19468 size_t count_client_hints_headers_seen() const {
Callum May7d88ff3e2019-11-12 18:21:46469 base::AutoLock lock(count_headers_lock_);
Tarun Bansal1965b042017-09-07 04:59:19470 return count_client_hints_headers_seen_;
471 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16472
Tarun Bansal229647bd002018-02-27 17:33:36473 size_t third_party_request_count_seen() const {
474 return request_interceptor_->request_count_seen();
475 }
476
477 size_t third_party_client_hints_count_seen() const {
478 return request_interceptor_->client_hints_count_seen();
479 }
480
Mike Weste555be862019-02-20 16:17:30481 const std::string& main_frame_ua_observed() const {
482 return main_frame_ua_observed_;
483 }
484
Yoav Weissd33bacb2020-03-12 06:42:21485 const std::string& main_frame_ua_full_version_observed() const {
486 return main_frame_ua_full_version_observed_;
487 }
488
Maks Orlovich73f374d2020-04-02 12:46:13489 const std::string& main_frame_ua_mobile_observed() const {
490 return main_frame_ua_mobile_observed_;
491 }
492
493 const std::string& main_frame_ua_platform_observed() const {
494 return main_frame_ua_platform_observed_;
495 }
496
Tarun Bansalea0d8262018-05-21 16:11:50497 base::test::ScopedFeatureList scoped_feature_list_;
498
Tarun Bansal345418632018-06-29 11:07:04499 std::string intercept_iframe_resource_;
Tarun Bansal9a7051f2018-07-10 18:30:05500 bool intercept_to_http_equiv_iframe_ = false;
Callum May7d88ff3e2019-11-12 18:21:46501 mutable base::Lock count_headers_lock_;
Tarun Bansal345418632018-06-29 11:07:04502
Tarun Bansal0b8b7afd2017-08-25 03:52:16503 private:
Tarun Bansal345418632018-06-29 11:07:04504 // Intercepts only the main frame requests that contain
Tarun Bansal293a7b6c2018-12-05 17:41:12505 // "redirect" in the resource path. The intercepted requests
506 // are served an HTML file that fetches an iframe from a cross-origin HTTPS
507 // server.
508 std::unique_ptr<net::test_server::HttpResponse> RequestHandlerToRedirect(
509 const net::test_server::HttpRequest& request) {
510 // Check if it's a main frame request.
511 if (request.relative_url.find(".html") == std::string::npos)
512 return nullptr;
513
514 if (request.GetURL().spec().find("redirect") == std::string::npos)
515 return nullptr;
516
Lei Zhange00db752021-04-17 00:48:46517 auto response = std::make_unique<net::test_server::BasicHttpResponse>();
Tarun Bansal293a7b6c2018-12-05 17:41:12518 response->set_code(net::HTTP_FOUND);
519 response->AddCustomHeader("Location",
520 without_accept_ch_without_lifetime_url().spec());
521 return std::move(response);
522 }
523
524 // Intercepts only the main frame requests that contain
Tarun Bansal345418632018-06-29 11:07:04525 // |intercept_iframe_resource_| in the resource path. The intercepted requests
526 // are served an HTML file that fetches an iframe from a cross-origin HTTPS
527 // server.
528 std::unique_ptr<net::test_server::HttpResponse>
529 RequestHandlerToFetchCrossOriginIframe(
530 const net::test_server::HttpRequest& request) {
531 if (intercept_iframe_resource_.empty())
532 return nullptr;
533
534 // Check if it's a main frame request.
535 if (request.relative_url.find(".html") == std::string::npos)
536 return nullptr;
537
538 if (request.relative_url.find(intercept_iframe_resource_) ==
539 std::string::npos) {
540 return nullptr;
541 }
542
543 const std::string iframe_url =
Tarun Bansal9a7051f2018-07-10 18:30:05544 intercept_to_http_equiv_iframe_
545 ? https_cross_origin_server_
546 .GetURL("/http_equiv_accept_ch_with_lifetime.html")
547 .spec()
548 : https_cross_origin_server_.GetURL("/accept_ch_with_lifetime.html")
549 .spec();
Tarun Bansal345418632018-06-29 11:07:04550
551 std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
552 new net::test_server::BasicHttpResponse());
553 http_response->set_code(net::HTTP_OK);
554 http_response->set_content_type("text/html");
555 http_response->set_content(
556 "<html>"
557 "<link rel='icon' href='data:;base64,='><head></head>"
558 "Empty file which uses link-rel to disable favicon fetches. "
559 "<iframe src='" +
560 iframe_url + "'></iframe></html>");
561
562 return std::move(http_response);
563 }
564
Maks Orlovich73f374d2020-04-02 12:46:13565 static std::string UpdateHeaderObservation(
566 const net::test_server::HttpRequest& request,
567 const std::string& header) {
568 if (request.headers.find(header) != request.headers.end())
569 return request.headers.find(header)->second;
570 else
571 return "";
572 }
573
Tarun Bansal1965b042017-09-07 04:59:19574 // Called by |https_server_|.
575 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
Tarun Bansal6bf54302017-10-02 07:39:14576 bool is_main_frame_navigation =
577 request.GetURL().spec().find(".html") != std::string::npos;
578
Tarun Bansal293a7b6c2018-12-05 17:41:12579 if (is_main_frame_navigation &&
580 request.GetURL().spec().find("redirect") != std::string::npos) {
581 return;
582 }
583
Tarun Bansal229647bd002018-02-27 17:33:36584 if (is_main_frame_navigation) {
Maks Orlovich73f374d2020-04-02 12:46:13585 main_frame_ua_observed_ = UpdateHeaderObservation(request, "sec-ch-ua");
586 main_frame_ua_full_version_observed_ =
587 UpdateHeaderObservation(request, "sec-ch-ua-full-version");
588 main_frame_ua_mobile_observed_ =
589 UpdateHeaderObservation(request, "sec-ch-ua-mobile");
590 main_frame_ua_platform_observed_ =
591 UpdateHeaderObservation(request, "sec-ch-ua-platform");
Yoav Weissd33bacb2020-03-12 06:42:21592
Tarun Bansalf9cf9892018-04-06 04:38:01593 VerifyClientHintsReceived(expect_client_hints_on_main_frame_, request);
Tarun Bansal5c28afb2018-03-17 02:55:20594 if (expect_client_hints_on_main_frame_) {
595 double value = 0.0;
596 EXPECT_TRUE(base::StringToDouble(
597 request.headers.find("device-memory")->second, &value));
598 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35599 EXPECT_TRUE(IsSimilarToDoubleABNF(
600 request.headers.find("device-memory")->second));
Tarun Bansal44ad96882018-03-28 17:47:42601 main_frame_device_memory_observed_ = value;
Tarun Bansal5c28afb2018-03-17 02:55:20602
603 EXPECT_TRUE(
604 base::StringToDouble(request.headers.find("dpr")->second, &value));
605 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35606 EXPECT_TRUE(IsSimilarToDoubleABNF(request.headers.find("dpr")->second));
Tarun Bansal44ad96882018-03-28 17:47:42607 main_frame_dpr_observed_ = value;
608
Tarun Bansal5c28afb2018-03-17 02:55:20609 EXPECT_TRUE(base::StringToDouble(
610 request.headers.find("viewport-width")->second, &value));
Tarun Bansal62efba12018-05-04 22:58:35611 EXPECT_TRUE(
612 IsSimilarToIntABNF(request.headers.find("viewport-width")->second));
Tarun Bansal79df868e2018-03-20 23:01:36613#if !defined(OS_ANDROID)
Tarun Bansal5c28afb2018-03-17 02:55:20614 EXPECT_LT(0.0, value);
Tarun Bansal79df868e2018-03-20 23:01:36615#else
616 EXPECT_EQ(980, value);
Tarun Bansal5c28afb2018-03-17 02:55:20617#endif
Tarun Bansal44ad96882018-03-28 17:47:42618 main_frame_viewport_width_observed_ = value;
Mike Weste555be862019-02-20 16:17:30619
Max Curran99cbec1492021-08-16 19:54:26620 EXPECT_TRUE(base::StringToDouble(
621 request.headers.find("sec-ch-viewport-height")->second, &value));
622 EXPECT_TRUE(IsSimilarToIntABNF(
623 request.headers.find("sec-ch-viewport-height")->second));
624 EXPECT_LT(0.0, value);
625
Tarun Bansal7f3fe8c2018-04-06 22:37:47626 VerifyNetworkQualityClientHints(request);
Tarun Bansal5c28afb2018-03-17 02:55:20627 }
Tarun Bansala61f0f62017-10-24 23:53:05628 }
Tarun Bansal6bf54302017-10-02 07:39:14629
Tarun Bansal229647bd002018-02-27 17:33:36630 if (!is_main_frame_navigation) {
Callum May1d939742020-03-02 17:51:30631 VerifyClientHintsReceived(expect_client_hints_on_subresources(), request);
Tarun Bansal5c28afb2018-03-17 02:55:20632
Callum May1d939742020-03-02 17:51:30633 if (expect_client_hints_on_subresources()) {
Tarun Bansal5c28afb2018-03-17 02:55:20634 double value = 0.0;
635 EXPECT_TRUE(base::StringToDouble(
636 request.headers.find("device-memory")->second, &value));
637 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35638 EXPECT_TRUE(IsSimilarToDoubleABNF(
639 request.headers.find("device-memory")->second));
Tarun Bansal44ad96882018-03-28 17:47:42640 if (main_frame_device_memory_observed_ > 0) {
641 EXPECT_EQ(main_frame_device_memory_observed_, value);
642 }
Tarun Bansal5c28afb2018-03-17 02:55:20643
644 EXPECT_TRUE(
645 base::StringToDouble(request.headers.find("dpr")->second, &value));
646 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35647 EXPECT_TRUE(IsSimilarToDoubleABNF(request.headers.find("dpr")->second));
Tarun Bansal44ad96882018-03-28 17:47:42648 if (main_frame_dpr_observed_ > 0) {
649 EXPECT_EQ(main_frame_dpr_observed_, value);
650 }
Tarun Bansal5c28afb2018-03-17 02:55:20651
652 EXPECT_TRUE(base::StringToDouble(
653 request.headers.find("viewport-width")->second, &value));
Tarun Bansal62efba12018-05-04 22:58:35654 EXPECT_TRUE(
655 IsSimilarToIntABNF(request.headers.find("viewport-width")->second));
Tarun Bansal79df868e2018-03-20 23:01:36656#if !defined(OS_ANDROID)
Tarun Bansal5c28afb2018-03-17 02:55:20657 EXPECT_LT(0.0, value);
Tarun Bansal79df868e2018-03-20 23:01:36658#else
659 EXPECT_EQ(980, value);
660#endif
Tarun Bansal44ad96882018-03-28 17:47:42661#if defined(OS_ANDROID)
662 // TODO(tbansal): https://crbug.com/825892: Viewport width on main
663 // frame requests may be incorrect when the Chrome window is not
664 // maximized.
665 if (main_frame_viewport_width_observed_ > 0) {
666 EXPECT_EQ(main_frame_viewport_width_observed_, value);
667 }
668#endif
Max Curran99cbec1492021-08-16 19:54:26669 EXPECT_TRUE(base::StringToDouble(
670 request.headers.find("sec-ch-viewport-height")->second, &value));
671 EXPECT_TRUE(IsSimilarToIntABNF(
672 request.headers.find("sec-ch-viewport-height")->second));
673 EXPECT_LT(0.0, value);
674
Tarun Bansal7f3fe8c2018-04-06 22:37:47675 VerifyNetworkQualityClientHints(request);
Tarun Bansal5c28afb2018-03-17 02:55:20676 }
Tarun Bansala61f0f62017-10-24 23:53:05677 }
Tarun Bansal6bf54302017-10-02 07:39:14678
Mike West14c11102019-02-04 16:16:47679 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Jan Wilken Dörriea8cb56302019-06-06 18:59:36680 if (base::Contains(request.headers,
681 blink::kClientHintsHeaderMapping[i])) {
Callum May7d88ff3e2019-11-12 18:21:46682 base::AutoLock lock(count_headers_lock_);
Mike West2fddeeb72019-02-15 11:29:48683 // The user agent hint is special:
684 if (std::string(blink::kClientHintsHeaderMapping[i]) == "sec-ch-ua") {
685 count_user_agent_hint_headers_seen_++;
Maks Orlovich5dcc99c2020-02-13 19:07:46686 } else if (std::string(blink::kClientHintsHeaderMapping[i]) ==
687 "sec-ch-ua-mobile") {
688 count_ua_mobile_client_hints_headers_seen_++;
Aaron Tagliaboschiec5bce62021-06-24 18:50:09689 } else if (std::string(blink::kClientHintsHeaderMapping[i]) ==
690 "sec-ch-ua-platform") {
691 count_ua_platform_client_hints_headers_seen_++;
Mike West2fddeeb72019-02-15 11:29:48692 } else {
693 count_client_hints_headers_seen_++;
694 }
Tarun Bansalf9cf9892018-04-06 04:38:01695 }
696 }
697 }
Tarun Bansal1965b042017-09-07 04:59:19698
Tarun Bansalf9cf9892018-04-06 04:38:01699 void VerifyClientHintsReceived(bool expect_client_hints,
700 const net::test_server::HttpRequest& request) {
Mike West14c11102019-02-04 16:16:47701 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
702 SCOPED_TRACE(testing::Message()
703 << std::string(blink::kClientHintsHeaderMapping[i]));
Tarun Bansalf9cf9892018-04-06 04:38:01704 // Resource width client hint is only attached on image subresources.
705 if (std::string(blink::kClientHintsHeaderMapping[i]) == "width") {
706 continue;
707 }
Mike West2fddeeb72019-02-15 11:29:48708
Aaron Tagliaboschiec5bce62021-06-24 18:50:09709 // `Sec-CH-UA`, `Sec-CH-UA-Mobile`, and `Sec-CH-UA-Platform` is attached
710 // on all requests.
Maks Orlovich5dcc99c2020-02-13 19:07:46711 if (std::string(blink::kClientHintsHeaderMapping[i]) == "sec-ch-ua" ||
712 std::string(blink::kClientHintsHeaderMapping[i]) ==
Aaron Tagliaboschiec5bce62021-06-24 18:50:09713 "sec-ch-ua-mobile" ||
714 std::string(blink::kClientHintsHeaderMapping[i]) ==
715 "sec-ch-ua-platform") {
Mike West2fddeeb72019-02-15 11:29:48716 continue;
717 }
718
Ali Beyad7417fc22021-08-06 03:09:58719 // Skip over the `Sec-CH-UA-Reduced` client hint because it is only added
720 // in the presence of a valid "UserAgentReduction" Origin Trial token.
721 // `Sec-CH-UA-Reduced` is tested via UaReducedOriginTrialBrowserTest
722 // below.
Ali Beyad67abdaf22021-07-29 01:00:24723 if (std::string(blink::kClientHintsHeaderMapping[i]) ==
724 "sec-ch-ua-reduced") {
725 continue;
726 }
727
Jan Wilken Dörriea8cb56302019-06-06 18:59:36728 EXPECT_EQ(
729 expect_client_hints,
730 base::Contains(request.headers, blink::kClientHintsHeaderMapping[i]));
Tarun Bansalf9cf9892018-04-06 04:38:01731 }
Tarun Bansal1965b042017-09-07 04:59:19732 }
733
Tarun Bansal7f3fe8c2018-04-06 22:37:47734 void VerifyNetworkQualityClientHints(
735 const net::test_server::HttpRequest& request) const {
736 // Effective connection type is forced to 2G using command line in these
737 // tests.
Tarun Bansal509a8dd2018-04-10 17:19:16738 int rtt_value = 0.0;
Tarun Bansal7f3fe8c2018-04-06 22:37:47739 EXPECT_TRUE(
Tarun Bansal509a8dd2018-04-10 17:19:16740 base::StringToInt(request.headers.find("rtt")->second, &rtt_value));
741 EXPECT_LE(0, rtt_value);
Tarun Bansal62efba12018-05-04 22:58:35742 EXPECT_TRUE(IsSimilarToIntABNF(request.headers.find("rtt")->second));
Tarun Bansal509a8dd2018-04-10 17:19:16743 // Verify that RTT value is a multiple of 50 milliseconds.
744 EXPECT_EQ(0, rtt_value % 50);
Tarun Bansalbef6d652018-10-02 18:41:01745 EXPECT_GE(expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G ? 3000 : 500,
746 rtt_value);
Tarun Bansal7f3fe8c2018-04-06 22:37:47747
Tarun Bansal509a8dd2018-04-10 17:19:16748 double mbps_value = 0.0;
749 EXPECT_TRUE(base::StringToDouble(request.headers.find("downlink")->second,
750 &mbps_value));
751 EXPECT_LE(0, mbps_value);
Tarun Bansal62efba12018-05-04 22:58:35752 EXPECT_TRUE(
753 IsSimilarToDoubleABNF(request.headers.find("downlink")->second));
Tarun Bansal509a8dd2018-04-10 17:19:16754 // Verify that the mbps value is a multiple of 0.050 mbps.
755 // Allow for small amount of noise due to double to integer conversions.
756 EXPECT_NEAR(0, (static_cast<int>(mbps_value * 1000)) % 50, 1);
757 EXPECT_GE(10.0, mbps_value);
Tarun Bansal7f3fe8c2018-04-06 22:37:47758
759 EXPECT_FALSE(request.headers.find("ect")->second.empty());
Tarun Bansalceab9592018-05-01 18:57:35760
761 // TODO(tbansal): https://crbug.com/819244: When network servicification is
Tarun Bansal5ac533542018-08-10 19:45:52762 // enabled, the renderer processes do not receive notifications on
763 // change in the network quality. Hence, the network quality client hints
764 // are not set to the correct value on subresources.
765 bool is_main_frame_navigation =
766 request.GetURL().spec().find(".html") != std::string::npos;
John Abd-El-Malek67facbe82019-06-06 22:37:08767 if (is_main_frame_navigation) {
Tarun Bansalceab9592018-05-01 18:57:35768 // Effective connection type is forced to 2G using command line in these
769 // tests. RTT is expected to be 1800 msec but leave some gap to account
770 // for added noise and randomization.
Tarun Bansalbef6d652018-10-02 18:41:01771 if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G) {
772 EXPECT_NEAR(1800, rtt_value, 360);
773 } else if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_3G) {
774 EXPECT_NEAR(450, rtt_value, 90);
775 } else {
776 NOTREACHED();
777 }
Tarun Bansalceab9592018-05-01 18:57:35778
779 // Effective connection type is forced to 2G using command line in these
780 // tests. downlink is expected to be 0.075 Mbps but leave some gap to
781 // account for added noise and randomization.
Tarun Bansalbef6d652018-10-02 18:41:01782 if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G) {
783 EXPECT_NEAR(0.075, mbps_value, 0.05);
784 } else if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_3G) {
785 EXPECT_NEAR(0.4, mbps_value, 0.1);
786 } else {
787 NOTREACHED();
788 }
Tarun Bansalceab9592018-05-01 18:57:35789
Tarun Bansalbef6d652018-10-02 18:41:01790 EXPECT_EQ(expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G ? "2g" : "3g",
791 request.headers.find("ect")->second);
Tarun Bansalceab9592018-05-01 18:57:35792 }
Tarun Bansal7f3fe8c2018-04-06 22:37:47793 }
794
Tarun Bansal3b330b02017-11-09 19:03:14795 net::EmbeddedTestServer http_server_;
Tarun Bansal0b8b7afd2017-08-25 03:52:16796 net::EmbeddedTestServer https_server_;
Tarun Bansal345418632018-06-29 11:07:04797 net::EmbeddedTestServer https_cross_origin_server_;
Tarun Bansal3b330b02017-11-09 19:03:14798 GURL accept_ch_with_lifetime_http_local_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05799 GURL http_equiv_accept_ch_with_lifetime_http_local_url_;
Tarun Bansal1965b042017-09-07 04:59:19800 GURL accept_ch_with_lifetime_url_;
Tarun Bansal73502f92019-04-16 21:21:19801 GURL accept_ch_with_short_lifetime_url_;
Tarun Bansal1965b042017-09-07 04:59:19802 GURL accept_ch_without_lifetime_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05803 GURL http_equiv_accept_ch_without_lifetime_url_;
Tarun Bansal1965b042017-09-07 04:59:19804 GURL without_accept_ch_without_lifetime_url_;
Tarun Bansal3b330b02017-11-09 19:03:14805 GURL without_accept_ch_without_lifetime_local_url_;
Tarun Bansaladd5e1812018-02-09 19:07:58806 GURL accept_ch_without_lifetime_with_iframe_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05807 GURL http_equiv_accept_ch_without_lifetime_with_iframe_url_;
Tarun Bansal62cc3542018-06-27 23:53:30808 GURL accept_ch_without_lifetime_with_subresource_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05809 GURL http_equiv_accept_ch_without_lifetime_with_subresource_url_;
Tarun Bansal62cc3542018-06-27 23:53:30810 GURL accept_ch_without_lifetime_with_subresource_iframe_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05811 GURL http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_;
Tarun Bansaladd5e1812018-02-09 19:07:58812 GURL without_accept_ch_without_lifetime_img_foo_com_;
813 GURL without_accept_ch_without_lifetime_img_localhost_;
Tarun Bansal229647bd002018-02-27 17:33:36814 GURL accept_ch_without_lifetime_img_localhost_;
Tarun Bansal9a7051f2018-07-10 18:30:05815 GURL http_equiv_accept_ch_without_lifetime_img_localhost_;
816 GURL http_equiv_accept_ch_with_lifetime_;
Tarun Bansal293a7b6c2018-12-05 17:41:12817 GURL redirect_url_;
Maks Orlovich7a588d82020-05-06 15:17:24818 GURL accept_ch_empty_;
819 GURL http_equiv_accept_ch_merge_;
Tarun Bansal1965b042017-09-07 04:59:19820
Mike Weste555be862019-02-20 16:17:30821 std::string main_frame_ua_observed_;
Yoav Weissd33bacb2020-03-12 06:42:21822 std::string main_frame_ua_full_version_observed_;
Maks Orlovich73f374d2020-04-02 12:46:13823 std::string main_frame_ua_mobile_observed_;
824 std::string main_frame_ua_platform_observed_;
Mike Weste555be862019-02-20 16:17:30825
Tarun Bansal44ad96882018-03-28 17:47:42826 double main_frame_dpr_observed_ = -1;
827 double main_frame_viewport_width_observed_ = -1;
828 double main_frame_device_memory_observed_ = -1;
829
Tarun Bansal229647bd002018-02-27 17:33:36830 // Expect client hints on all the main frame request.
831 bool expect_client_hints_on_main_frame_;
832 // Expect client hints on all the subresource requests.
Callum May1d939742020-03-02 17:51:30833 bool expect_client_hints_on_subresources_
834 GUARDED_BY(expect_client_hints_on_subresources_lock_);
835
836 base::Lock expect_client_hints_on_subresources_lock_;
Tarun Bansal229647bd002018-02-27 17:33:36837
Mike West2fddeeb72019-02-15 11:29:48838 size_t count_user_agent_hint_headers_seen_;
Maks Orlovich5dcc99c2020-02-13 19:07:46839 size_t count_ua_mobile_client_hints_headers_seen_;
Aaron Tagliaboschiec5bce62021-06-24 18:50:09840 size_t count_ua_platform_client_hints_headers_seen_;
Tarun Bansal1965b042017-09-07 04:59:19841 size_t count_client_hints_headers_seen_;
Tarun Bansala61f0f62017-10-24 23:53:05842
Jay Civelli1ff872d2018-03-09 21:52:16843 std::unique_ptr<ThirdPartyURLLoaderInterceptor> request_interceptor_;
Tarun Bansal229647bd002018-02-27 17:33:36844
Tarun Bansalbef6d652018-10-02 18:41:01845 // Set to 2G in SetUpCommandLine().
846 net::EffectiveConnectionType expected_ect = net::EFFECTIVE_CONNECTION_TYPE_2G;
847
Tarun Bansala61f0f62017-10-24 23:53:05848 DISALLOW_COPY_AND_ASSIGN(ClientHintsBrowserTest);
Tarun Bansal0b8b7afd2017-08-25 03:52:16849};
850
Tarun Bansal9a7051f2018-07-10 18:30:05851// True if testing for http-equiv correctness. When set to true, the tests
852// use webpages that may contain http-equiv Accept-CH and Accept-CH-Lifetime
853// headers. When set to false, the tests use webpages that set the headers in
854// the HTTP response headers.
Ilia Samsonov282c38412019-12-09 08:15:10855INSTANTIATE_TEST_SUITE_P(All,
Victor Costane5e91512019-02-13 08:24:02856 ClientHintsBrowserTest,
857 testing::Bool());
Tarun Bansal9a7051f2018-07-10 18:30:05858
Tarun Bansalea0d8262018-05-21 16:11:50859class ClientHintsAllowThirdPartyBrowserTest : public ClientHintsBrowserTest {
Mike West2fddeeb72019-02-15 11:29:48860 std::unique_ptr<base::FeatureList> EnabledFeatures() override {
861 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
862 feature_list->InitializeFromCommandLine(
François Beaufort1b51d062021-05-18 11:11:23863 "AllowClientHintsToThirdParty,UserAgentClientHint,"
Max Curran99cbec1492021-08-16 19:54:26864 "LangClientHintHeader,PrefersColorSchemeClientHintHeader,"
865 "ViewportHeightClientHintHeader",
Maks Orlovichc66745a2020-06-30 17:40:02866 "");
Mike West2fddeeb72019-02-15 11:29:48867 return feature_list;
Tarun Bansalea0d8262018-05-21 16:11:50868 }
869};
870
Ilia Samsonov282c38412019-12-09 08:15:10871INSTANTIATE_TEST_SUITE_P(All,
Aaron Tagliaboschia09ec442019-09-18 15:29:03872 ClientHintsAllowThirdPartyBrowserTest,
873 testing::Bool());
874
Tarun Bansal74e189d2018-05-07 19:07:35875IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, CorsChecks) {
Mike West14c11102019-02-04 16:16:47876 for (size_t i = 0; i < blink::kClientHintsMappingsCount; ++i) {
Tarun Bansal74e189d2018-05-07 19:07:35877 // Do not test for headers that have not been enabled on the blink "stable"
878 // yet.
879 if (std::string(blink::kClientHintsHeaderMapping[i]) == "rtt" ||
880 std::string(blink::kClientHintsHeaderMapping[i]) == "downlink" ||
881 std::string(blink::kClientHintsHeaderMapping[i]) == "ect") {
882 continue;
883 }
Takashi Toyoshima2e01e692018-11-16 03:23:27884 EXPECT_TRUE(network::cors::IsCorsSafelistedHeader(
Tarun Bansal74e189d2018-05-07 19:07:35885 blink::kClientHintsHeaderMapping[i], "42" /* value */));
886 }
Takashi Toyoshima2e01e692018-11-16 03:23:27887 EXPECT_FALSE(network::cors::IsCorsSafelistedHeader("not-a-client-hint-header",
Tarun Bansal74e189d2018-05-07 19:07:35888 "" /* value */));
889 EXPECT_TRUE(
Takashi Toyoshima2e01e692018-11-16 03:23:27890 network::cors::IsCorsSafelistedHeader("save-data", "on" /* value */));
Tarun Bansal74e189d2018-05-07 19:07:35891}
892
Maks Orlovichf0a2eed2020-05-02 20:08:21893IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, HttpEquivWorks) {
894 const GURL gurl = http_equiv_accept_ch_without_lifetime_img_localhost();
895 base::HistogramTester histogram_tester;
896
897 SetClientHintExpectationsOnMainFrame(false);
898 SetClientHintExpectationsOnSubresources(true);
899
900 ui_test_utils::NavigateToURL(browser(), gurl);
901 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
902}
903
Tarun Bansal0b8b7afd2017-08-25 03:52:16904// Loads a webpage that requests persisting of client hints. Verifies that
905// the browser receives the mojo notification from the renderer and persists the
Maks Orlovichf0a2eed2020-05-02 20:08:21906// client hints to the disk --- unless it's using http-equiv which shouldn't
907// persist.
Tarun Bansal9a7051f2018-07-10 18:30:05908IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest, ClientHintsHttps) {
Tarun Bansal0b8b7afd2017-08-25 03:52:16909 base::HistogramTester histogram_tester;
Tarun Bansal9a7051f2018-07-10 18:30:05910 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
911 : accept_ch_with_lifetime_url();
912 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal0b8b7afd2017-08-25 03:52:16913
Maks Orlovichf0a2eed2020-05-02 20:08:21914 if (GetParam())
915 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
916 else
917 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
Tarun Bansal0b8b7afd2017-08-25 03:52:16918
919 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:28920 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal0b8b7afd2017-08-25 03:52:16921
Maks Orlovichf0a2eed2020-05-02 20:08:21922 if (GetParam()) {
923 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
924 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
925 } else {
926 // client_hints_url() sets the expected number of client hints.
927 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
928 expected_client_hints_number, 1);
929 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:12930 // seconds, but a maximum value is registered instead.
Maks Orlovichf0a2eed2020-05-02 20:08:21931 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:12932 uma_histogram_max_value, 1);
Maks Orlovichf0a2eed2020-05-02 20:08:21933 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16934}
935
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44936IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, PRE_ClientHintsClearSession) {
937 const GURL gurl = accept_ch_with_lifetime_url();
938
939 base::HistogramTester histogram_tester;
940 ContentSettingsForOneType host_settings;
941
942 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:14943 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44944 &host_settings);
945 EXPECT_EQ(0u, host_settings.size());
946
947 // Fetching |gurl| should persist the request for client hints iff using
948 // headers and not http-equiv.
949 ui_test_utils::NavigateToURL(browser(), gurl);
950
951 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
952
953 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:28954 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44955 base::RunLoop().RunUntilIdle();
956
957 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
958 expected_client_hints_number, 1);
959 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:12960 // seconds, but a maximum value is registered instead.
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44961 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:12962 uma_histogram_max_value, 1);
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44963
964 // Clients hints preferences for one origin should be persisted.
965 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:14966 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44967 &host_settings);
968 EXPECT_EQ(1u, host_settings.size());
969
970 SetClientHintExpectationsOnMainFrame(true);
971 SetClientHintExpectationsOnSubresources(true);
972 ui_test_utils::NavigateToURL(browser(),
973 without_accept_ch_without_lifetime_url());
974
975 // The user agent hint is attached to all three requests:
976 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
977 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:09978 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44979
980 // Expected number of hints attached to the image request, and the same number
981 // to the main frame request.
982 EXPECT_EQ(expected_client_hints_number * 2,
983 count_client_hints_headers_seen());
984}
985
986IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, ClientHintsClearSession) {
987 const GURL gurl = accept_ch_with_lifetime_url();
988
989 base::HistogramTester histogram_tester;
990 ContentSettingsForOneType host_settings;
991
992 // Clients hints preferences for one origin should be persisted.
993 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:14994 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44995 &host_settings);
996 EXPECT_EQ(0u, host_settings.size());
997
998 SetClientHintExpectationsOnMainFrame(false);
999 SetClientHintExpectationsOnSubresources(false);
1000 ui_test_utils::NavigateToURL(browser(),
1001 without_accept_ch_without_lifetime_url());
1002
1003 // The user agent hint is attached to all three requests:
1004 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
1005 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091006 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:441007
1008 // Expected number of hints attached to the image request, and the same number
1009 // to the main frame request.
1010 EXPECT_EQ(0u, count_client_hints_headers_seen());
1011}
1012
Tarun Bansaladd5e1812018-02-09 19:07:581013// Test that client hints are attached to subresources only if they belong
1014// to the same host as document host.
Maks Orlovichf0a2eed2020-05-02 20:08:211015IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansaladd5e1812018-02-09 19:07:581016 ClientHintsHttpsSubresourceDifferentOrigin) {
Maks Orlovichf0a2eed2020-05-02 20:08:211017 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:051018
Tarun Bansaladd5e1812018-02-09 19:07:581019 base::HistogramTester histogram_tester;
1020
1021 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:051022 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansaladd5e1812018-02-09 19:07:581023 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1024
1025 // Verify that the client hints settings for localhost have been saved.
1026 ContentSettingsForOneType client_hints_settings;
1027 HostContentSettingsMap* host_content_settings_map =
1028 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
1029 host_content_settings_map->GetSettingsForOneType(
Illia Klimov48f643c2020-11-05 20:06:141030 ContentSettingsType::CLIENT_HINTS, &client_hints_settings);
Tarun Bansaladd5e1812018-02-09 19:07:581031 ASSERT_EQ(1U, client_hints_settings.size());
1032
1033 // Copy the client hints setting for localhost to foo.com.
1034 host_content_settings_map->SetWebsiteSettingDefaultScope(
Darin Fisher42f5e7d2019-10-30 07:15:451035 GURL("https://foo.com/"), GURL(), ContentSettingsType::CLIENT_HINTS,
Illia Klimov48f643c2020-11-05 20:06:141036
Jeremy Romanec48d7a2018-03-01 17:35:091037 std::make_unique<base::Value>(
Oksana Zhuravlovab14dc882018-04-12 17:34:571038 client_hints_settings.at(0).setting_value.Clone()));
Tarun Bansaladd5e1812018-02-09 19:07:581039
1040 // Verify that client hints for the two hosts has been saved.
1041 host_content_settings_map =
1042 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
1043 host_content_settings_map->GetSettingsForOneType(
Illia Klimov48f643c2020-11-05 20:06:141044 ContentSettingsType::CLIENT_HINTS, &client_hints_settings);
Tarun Bansaladd5e1812018-02-09 19:07:581045 ASSERT_EQ(2U, client_hints_settings.size());
1046
1047 // Navigating to without_accept_ch_without_lifetime_img_localhost() should
1048 // attach client hints to the image subresouce contained in that page since
1049 // the image is located on the same server as the document origin.
Tarun Bansal229647bd002018-02-27 17:33:361050 SetClientHintExpectationsOnMainFrame(true);
1051 SetClientHintExpectationsOnSubresources(true);
Tarun Bansaladd5e1812018-02-09 19:07:581052 ui_test_utils::NavigateToURL(
1053 browser(), without_accept_ch_without_lifetime_img_localhost());
1054 base::RunLoop().RunUntilIdle();
1055 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281056 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansaladd5e1812018-02-09 19:07:581057
Maks Orlovich5dcc99c2020-02-13 19:07:461058 // The user agent hint is attached to all three requests, as is UA-mobile:
Mike West2fddeeb72019-02-15 11:29:481059 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461060 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091061 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481062
Yoav Weissd33bacb2020-03-12 06:42:211063 // Expected number of hints attached to the image request, and the same number
1064 // to the main frame request.
1065 EXPECT_EQ(expected_client_hints_number * 2,
1066 count_client_hints_headers_seen());
Tarun Bansaladd5e1812018-02-09 19:07:581067
1068 // Navigating to without_accept_ch_without_lifetime_img_foo_com() should not
1069 // attach client hints to the image subresouce contained in that page since
1070 // the image is located on a different server as the document origin.
Tarun Bansaladd5e1812018-02-09 19:07:581071 ui_test_utils::NavigateToURL(
1072 browser(), without_accept_ch_without_lifetime_img_foo_com());
1073 base::RunLoop().RunUntilIdle();
1074 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281075 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansaladd5e1812018-02-09 19:07:581076
Tarun Bansalb30b7532018-03-14 21:50:381077 // The device-memory and dprheader is attached to the main frame request.
Tarun Bansal5c28afb2018-03-17 02:55:201078#if defined(OS_ANDROID)
Yoav Weissd33bacb2020-03-12 06:42:211079 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal5c28afb2018-03-17 02:55:201080#else
Yoav Weissd33bacb2020-03-12 06:42:211081 EXPECT_EQ(expected_client_hints_number * 3,
1082 count_client_hints_headers_seen());
Tarun Bansal5c28afb2018-03-17 02:55:201083#endif
Mike West2fddeeb72019-02-15 11:29:481084
Aaron Tagliaboschiec5bce62021-06-24 18:50:091085 // Requests to third party servers should have three (3) client hints attached
1086 // (`Sec-CH-UA`, `Sec-CH-UA-Mobile`, `Sec-CH-UA-Platform`).
Tarun Bansal229647bd002018-02-27 17:33:361087 EXPECT_EQ(1u, third_party_request_count_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091088 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansaladd5e1812018-02-09 19:07:581089}
1090
Maks Orlovich7227ce0d2020-02-28 17:13:161091// Test that client hints are attached to subresources checks the right setting
1092// for OTR profile.
Maks Orlovichf0a2eed2020-05-02 20:08:211093IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Maks Orlovich7227ce0d2020-02-28 17:13:161094 ClientHintsHttpsSubresourceOffTheRecord) {
Maks Orlovichf0a2eed2020-05-02 20:08:211095 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich7227ce0d2020-02-28 17:13:161096
1097 base::HistogramTester histogram_tester;
1098
1099 // Add client hints for the embedded test server.
1100 ui_test_utils::NavigateToURL(browser(), gurl);
1101 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1102
1103 // Main profile should get hints for both page and subresources.
1104 SetClientHintExpectationsOnMainFrame(true);
1105 SetClientHintExpectationsOnSubresources(true);
1106 ui_test_utils::NavigateToURL(
1107 browser(), without_accept_ch_without_lifetime_img_localhost());
1108 base::RunLoop().RunUntilIdle();
1109 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281110 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Maks Orlovich7227ce0d2020-02-28 17:13:161111
1112 // The user agent hint is attached to all three requests:
1113 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
1114 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091115 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Maks Orlovich7227ce0d2020-02-28 17:13:161116
Yoav Weissd33bacb2020-03-12 06:42:211117 // Expected number of hints attached to the image request, and the same number
1118 // to the main frame request.
1119 EXPECT_EQ(expected_client_hints_number * 2,
1120 count_client_hints_headers_seen());
Maks Orlovich7227ce0d2020-02-28 17:13:161121
1122 // OTR profile should get neither.
1123 Browser* otr_browser = CreateIncognitoBrowser(browser()->profile());
1124 SetClientHintExpectationsOnMainFrame(false);
1125 SetClientHintExpectationsOnSubresources(false);
1126 ui_test_utils::NavigateToURL(
1127 otr_browser, without_accept_ch_without_lifetime_img_localhost());
1128}
1129
Mike Weste555be862019-02-20 16:17:301130// Verify that we send only major version information in the `Sec-CH-UA` header
Yoav Weissd33bacb2020-03-12 06:42:211131// by default, regardless of opt-in.
Maks Orlovichf0a2eed2020-05-02 20:08:211132IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UserAgentVersion) {
1133 const GURL gurl = accept_ch_with_lifetime_url();
Mike Weste555be862019-02-20 16:17:301134
John Abd-El-Malekec1fc69e2021-01-28 19:14:411135 blink::UserAgentMetadata ua = embedder_support::GetUserAgentMetadata();
Mike Weste555be862019-02-20 16:17:301136
1137 // Navigate to a page that opts-into the header: the value should end with
1138 // the major version, and not contain the full version.
1139 SetClientHintExpectationsOnMainFrame(false);
1140 ui_test_utils::NavigateToURL(browser(), gurl);
Aaron Tagliaboschi9f01b682020-05-05 21:03:171141 std::string expected_ua = ua.SerializeBrandVersionList();
Yoav Weissd33bacb2020-03-12 06:42:211142 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1143 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Mike Weste555be862019-02-20 16:17:301144
Yoav Weissd33bacb2020-03-12 06:42:211145 // Navigate again, after the opt-in: the value should stay the major
Mike Weste555be862019-02-20 16:17:301146 // version.
1147 SetClientHintExpectationsOnMainFrame(true);
1148 ui_test_utils::NavigateToURL(browser(), gurl);
Yoav Weissd33bacb2020-03-12 06:42:211149 std::string expected_full_version = "\"" + ua.full_version + "\"";
1150 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1151 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
Mike Weste555be862019-02-20 16:17:301152}
1153
Maks Orlovichf0a2eed2020-05-02 20:08:211154IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UAHintsTabletMode) {
1155 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich73f374d2020-04-02 12:46:131156
John Abd-El-Malekec1fc69e2021-01-28 19:14:411157 blink::UserAgentMetadata ua = embedder_support::GetUserAgentMetadata();
Maks Orlovich73f374d2020-04-02 12:46:131158
1159 // First request: only minimal hints, no tablet override.
1160 SetClientHintExpectationsOnMainFrame(false);
1161 ui_test_utils::NavigateToURL(browser(), gurl);
Aaron Tagliaboschi9f01b682020-05-05 21:03:171162 std::string expected_ua = ua.SerializeBrandVersionList();
Maks Orlovich73f374d2020-04-02 12:46:131163 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1164 EXPECT_EQ(main_frame_ua_full_version_observed(), "");
1165 EXPECT_EQ(main_frame_ua_mobile_observed(), "?0");
Aaron Tagliaboschiec5bce62021-06-24 18:50:091166 EXPECT_EQ(main_frame_ua_platform_observed(), "\"" + ua.platform + "\"");
Maks Orlovich73f374d2020-04-02 12:46:131167
1168 // Second request: table override, all hints.
1169 chrome::ToggleRequestTabletSite(browser());
1170 SetClientHintExpectationsOnMainFrame(true);
1171 ui_test_utils::NavigateToURL(browser(), gurl);
1172 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1173 std::string expected_full_version = "\"" + ua.full_version + "\"";
1174 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
1175 EXPECT_EQ(main_frame_ua_mobile_observed(), "?1");
1176 EXPECT_EQ(main_frame_ua_platform_observed(), "\"Android\"");
1177}
1178
1179// TODO(morlovich): Move this into WebContentsImplBrowserTest once things are
1180// refactored enough that UA client hints actually work in content/
1181IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UserAgentOverrideClientHints) {
1182 content::WebContents* web_contents =
1183 browser()->tab_strip_model()->GetActiveWebContents();
1184
1185 ASSERT_TRUE(embedded_test_server()->Start());
1186 const std::string kHeaderPath = std::string("/echoheader?") +
1187 net::HttpRequestHeaders::kUserAgent +
1188 "&sec-ch-ua&sec-ch-ua-mobile";
1189 const GURL kUrl(embedded_test_server()->GetURL(kHeaderPath));
1190
1191 web_contents->SetUserAgentOverride(
1192 blink::UserAgentOverride::UserAgentOnly("foo"), false);
1193 // Not enabled first.
1194 ui_test_utils::NavigateToURL(browser(), kUrl);
1195 std::string header_value;
1196 EXPECT_TRUE(ExecuteScriptAndExtractString(
1197 web_contents,
1198 "window.domAutomationController.send(document.body.textContent);",
1199 &header_value));
1200 EXPECT_EQ(std::string::npos, header_value.find("foo")) << header_value;
1201
1202 // Actually turn it on.
1203 web_contents->GetController()
1204 .GetLastCommittedEntry()
1205 ->SetIsOverridingUserAgent(true);
1206
1207 ui_test_utils::NavigateToURL(browser(), kUrl);
1208 EXPECT_TRUE(ExecuteScriptAndExtractString(
1209 web_contents,
1210 "window.domAutomationController.send(document.body.textContent);",
1211 &header_value));
1212 // Since no value was provided for client hints, they are not sent.
1213 EXPECT_EQ("foo\nNone\nNone", header_value);
1214
1215 // Now actually provide values for the hints.
1216 blink::UserAgentOverride ua_override;
1217 ua_override.ua_string_override = "foobar";
1218 ua_override.ua_metadata_override.emplace();
1219 ua_override.ua_metadata_override->mobile = true;
Aaron Tagliaboschi9f01b682020-05-05 21:03:171220 ua_override.ua_metadata_override->brand_version_list.emplace_back(
1221 "Foobarnator", "3.14");
Maks Orlovich73f374d2020-04-02 12:46:131222 web_contents->SetUserAgentOverride(ua_override, false);
1223 ui_test_utils::NavigateToURL(browser(), kUrl);
1224 EXPECT_TRUE(ExecuteScriptAndExtractString(
1225 web_contents,
1226 "window.domAutomationController.send(document.body.textContent);",
1227 &header_value));
Aaron Tagliaboschi9f01b682020-05-05 21:03:171228 EXPECT_EQ("foobar\n\"Foobarnator\";v=\"3.14\"\n?1", header_value);
Maks Orlovich73f374d2020-04-02 12:46:131229}
1230
Maks Orlovich7a588d82020-05-06 15:17:241231IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, EmptyAcceptCH) {
1232 // First navigate to a page that enables hints. No CH for it yet, since
1233 // nothing opted in.
1234 GURL gurl = accept_ch_with_lifetime_url();
1235 SetClientHintExpectationsOnMainFrame(false);
1236 ui_test_utils::NavigateToURL(browser(), gurl);
1237
1238 // Now go to a page with blank Accept-CH. Should get hints from previous
1239 // visit.
1240 gurl = accept_ch_empty();
1241 SetClientHintExpectationsOnMainFrame(true);
1242 ui_test_utils::NavigateToURL(browser(), gurl);
1243
1244 // Visiting again should not expect them since we opted out again.
1245 SetClientHintExpectationsOnMainFrame(false);
1246 ui_test_utils::NavigateToURL(browser(), gurl);
1247}
1248
1249IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, MergeAcceptCH) {
1250 // Go to page where some hints are enabled by headers, some by
1251 // http-equiv. It shouldn't get hints itself (due to first visit),
1252 // but subresources should get all the client hints.
1253 GURL gurl = http_equiv_accept_ch_merge();
1254 SetClientHintExpectationsOnMainFrame(false);
1255 SetClientHintExpectationsOnSubresources(true);
1256 ui_test_utils::NavigateToURL(browser(), gurl);
1257 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
1258}
1259
Maks Orlovich7227ce0d2020-02-28 17:13:161260void ClientHintsBrowserTest::TestProfilesIndependent(Browser* browser_a,
1261 Browser* browser_b) {
Maks Orlovichf0a2eed2020-05-02 20:08:211262 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich7227ce0d2020-02-28 17:13:161263
John Abd-El-Malekec1fc69e2021-01-28 19:14:411264 blink::UserAgentMetadata ua = embedder_support::GetUserAgentMetadata();
Maks Orlovich7227ce0d2020-02-28 17:13:161265
1266 // Navigate |browser_a| to a page that opts-into the header: the value should
1267 // end with the major version, and not contain the full version.
1268 SetClientHintExpectationsOnMainFrame(false);
1269 ui_test_utils::NavigateToURL(browser_a, gurl);
Aaron Tagliaboschi9f01b682020-05-05 21:03:171270 std::string expected_ua = ua.SerializeBrandVersionList();
Yoav Weissd33bacb2020-03-12 06:42:211271 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1272 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Maks Orlovich7227ce0d2020-02-28 17:13:161273
1274 // Try again on |browser_a|, the header should have an effect there.
1275 SetClientHintExpectationsOnMainFrame(true);
1276 ui_test_utils::NavigateToURL(browser_a, gurl);
Yoav Weissd33bacb2020-03-12 06:42:211277 std::string expected_full_version = "\"" + ua.full_version + "\"";
1278 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1279 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
Maks Orlovich7227ce0d2020-02-28 17:13:161280
1281 // Navigate on |browser_b|. That should still only have the major
1282 // version.
1283 SetClientHintExpectationsOnMainFrame(false);
1284 ui_test_utils::NavigateToURL(browser_b, gurl);
Yoav Weissd33bacb2020-03-12 06:42:211285 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1286 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Maks Orlovich7227ce0d2020-02-28 17:13:161287}
1288
1289// Check that client hints attached to navigation inside OTR profiles
1290// use the right settings, regular -> OTR direction.
Maks Orlovichf0a2eed2020-05-02 20:08:211291IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, OffTheRecordIndependent) {
Maks Orlovich7227ce0d2020-02-28 17:13:161292 TestProfilesIndependent(browser(),
1293 CreateIncognitoBrowser(browser()->profile()));
1294}
1295
1296// Check that client hints attached to navigation inside OTR profiles
1297// use the right settings, OTR -> regular direction.
Maks Orlovichf0a2eed2020-05-02 20:08:211298IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, OffTheRecordIndependent2) {
Maks Orlovich7227ce0d2020-02-28 17:13:161299 TestProfilesIndependent(CreateIncognitoBrowser(browser()->profile()),
1300 browser());
1301}
1302
Tarun Bansalea0d8262018-05-21 16:11:501303// Test that client hints are attached to third party subresources if
1304// AllowClientHintsToThirdParty feature is enabled.
Tarun Bansal9a7051f2018-07-10 18:30:051305IN_PROC_BROWSER_TEST_P(ClientHintsAllowThirdPartyBrowserTest,
Tarun Bansalea0d8262018-05-21 16:11:501306 ClientHintsThirdPartyAllowed) {
Yoav Weiss76e1afb762020-05-14 19:28:121307 GURL gurl;
1308 unsigned update_event_count = 0;
1309 if (GetParam()) {
1310 gurl = http_equiv_accept_ch_without_lifetime_img_localhost();
1311 } else {
1312 gurl = accept_ch_without_lifetime_img_localhost();
1313 update_event_count = 1;
1314 }
Tarun Bansal9a7051f2018-07-10 18:30:051315
Tarun Bansalea0d8262018-05-21 16:11:501316 base::HistogramTester histogram_tester;
1317
1318 SetClientHintExpectationsOnMainFrame(false);
1319 SetClientHintExpectationsOnSubresources(true);
1320
1321 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:051322 ui_test_utils::NavigateToURL(browser(), gurl);
Yoav Weiss76e1afb762020-05-14 19:28:121323 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount",
1324 update_event_count);
Tarun Bansalea0d8262018-05-21 16:11:501325
Yoav Weissd33bacb2020-03-12 06:42:211326 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansalea0d8262018-05-21 16:11:501327
1328 // Requests to third party servers should not have client hints attached.
1329 EXPECT_EQ(1u, third_party_request_count_seen());
1330
Aaron Tagliaboschia09ec442019-09-18 15:29:031331 // Device memory, viewport width, DRP, and UA client hints should be sent to
1332 // the third-party when feature "AllowClientHintsToThirdParty" is enabled.
Aaron Tagliaboschiec5bce62021-06-24 18:50:091333 EXPECT_EQ(6u, third_party_client_hints_count_seen());
Tarun Bansalea0d8262018-05-21 16:11:501334}
1335
1336// Test that client hints are not attached to third party subresources if
1337// AllowClientHintsToThirdParty feature is not enabled.
Tarun Bansal9a7051f2018-07-10 18:30:051338IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansalea0d8262018-05-21 16:11:501339 ClientHintsThirdPartyNotAllowed) {
Yoav Weiss76e1afb762020-05-14 19:28:121340 GURL gurl;
1341 unsigned update_event_count = 0;
1342 if (GetParam()) {
1343 gurl = http_equiv_accept_ch_without_lifetime_img_localhost();
1344 } else {
1345 gurl = accept_ch_without_lifetime_img_localhost();
1346 update_event_count = 1;
1347 }
Tarun Bansal9a7051f2018-07-10 18:30:051348
Tarun Bansalea0d8262018-05-21 16:11:501349 base::HistogramTester histogram_tester;
1350
1351 SetClientHintExpectationsOnMainFrame(false);
1352 SetClientHintExpectationsOnSubresources(true);
1353
1354 // Add client hints for the embedded test server.
Tarun Bansal9a7051f2018-07-10 18:30:051355 ui_test_utils::NavigateToURL(browser(), gurl);
Yoav Weiss76e1afb762020-05-14 19:28:121356 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount",
1357 update_event_count);
Tarun Bansalea0d8262018-05-21 16:11:501358
Mike West2fddeeb72019-02-15 11:29:481359 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461360 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091361 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:211362 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansalea0d8262018-05-21 16:11:501363
1364 // Requests to third party servers should not have client hints attached.
1365 EXPECT_EQ(1u, third_party_request_count_seen());
1366
1367 // Client hints should not be sent to the third-party when feature
Mike West2fddeeb72019-02-15 11:29:481368 // "AllowClientHintsToThirdParty" is not enabled, with the exception of the
1369 // `Sec-CH-UA` hint, which is sent with every request.
Aaron Tagliaboschiec5bce62021-06-24 18:50:091370 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansalea0d8262018-05-21 16:11:501371}
1372
Tarun Bansaladd5e1812018-02-09 19:07:581373// Loads a HTTPS webpage that does not request persisting of client hints.
Tarun Bansal345418632018-06-29 11:07:041374// A same-origin iframe loaded by the webpage requests persistence of client
Maks Orlovich46619c732020-05-07 10:40:531375// hints. Since that's not a main frame, persistence should not happen.
Maks Orlovichf0a2eed2020-05-02 20:08:211376IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal345418632018-06-29 11:07:041377 PersistenceRequestIframe_SameOrigin) {
Maks Orlovichf0a2eed2020-05-02 20:08:211378 const GURL gurl = accept_ch_without_lifetime_with_iframe_url();
Tarun Bansal345418632018-06-29 11:07:041379 base::HistogramTester histogram_tester;
1380 ContentSettingsForOneType host_settings;
1381
1382 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141383 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal345418632018-06-29 11:07:041384 &host_settings);
1385 EXPECT_EQ(0u, host_settings.size());
1386
Tarun Bansal9a7051f2018-07-10 18:30:051387 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal345418632018-06-29 11:07:041388
Maks Orlovich46619c732020-05-07 10:40:531389 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
Tarun Bansal345418632018-06-29 11:07:041390
1391 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281392 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal345418632018-06-29 11:07:041393
1394 // accept_ch_without_lifetime_with_iframe_url() loads
1395 // accept_ch_with_lifetime() in an iframe. The request to persist client
Maks Orlovich46619c732020-05-07 10:40:531396 // hints from accept_ch_with_lifetime() should not be persisted.
1397 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1398 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
Tarun Bansal345418632018-06-29 11:07:041399}
1400
1401// Loads a HTTPS webpage that does not request persisting of client hints.
1402// An iframe loaded by the webpage from an cross origin server requests
1403// persistence of client hints.
1404// Verify that the request from the cross origin iframe is not honored, and
1405// client hints preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051406IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal345418632018-06-29 11:07:041407 DisregardPersistenceRequestIframe_CrossOrigin) {
Tarun Bansal9a7051f2018-07-10 18:30:051408 const GURL gurl =
1409 GetParam() ? http_equiv_accept_ch_without_lifetime_with_iframe_url()
1410 : accept_ch_without_lifetime_with_iframe_url();
1411
1412 intercept_iframe_resource_ = gurl.path();
1413 intercept_to_http_equiv_iframe_ = GetParam();
1414
Tarun Bansaladd5e1812018-02-09 19:07:581415 base::HistogramTester histogram_tester;
1416 ContentSettingsForOneType host_settings;
1417
1418 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141419 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansaladd5e1812018-02-09 19:07:581420 &host_settings);
1421 EXPECT_EQ(0u, host_settings.size());
1422
Tarun Bansal9a7051f2018-07-10 18:30:051423 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansaladd5e1812018-02-09 19:07:581424
1425 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1426
1427 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281428 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansaladd5e1812018-02-09 19:07:581429
1430 // accept_ch_without_lifetime_with_iframe_url() loads
Tarun Bansal345418632018-06-29 11:07:041431 // accept_ch_with_lifetime() in a cross origin iframe. The request to persist
1432 // client hints from accept_ch_with_lifetime() should be disregarded.
Tarun Bansaladd5e1812018-02-09 19:07:581433 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1434 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1435}
1436
Tarun Bansal62cc3542018-06-27 23:53:301437// Loads a HTTPS webpage that does not request persisting of client hints.
1438// A subresource loaded by the webpage requests persistence of client hints.
1439// Verify that the request from the subresource is not honored, and client hints
1440// preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051441IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal62cc3542018-06-27 23:53:301442 DisregardPersistenceRequestSubresource) {
Tarun Bansal9a7051f2018-07-10 18:30:051443 const GURL gurl =
1444 GetParam() ? http_equiv_accept_ch_without_lifetime_with_subresource_url()
1445 : accept_ch_without_lifetime_with_subresource_url();
1446
Tarun Bansal62cc3542018-06-27 23:53:301447 base::HistogramTester histogram_tester;
1448 ContentSettingsForOneType host_settings;
1449
1450 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141451 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal62cc3542018-06-27 23:53:301452 &host_settings);
1453 EXPECT_EQ(0u, host_settings.size());
1454
Tarun Bansal9a7051f2018-07-10 18:30:051455 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal62cc3542018-06-27 23:53:301456
1457 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1458
1459 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281460 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal62cc3542018-06-27 23:53:301461
1462 // accept_ch_without_lifetime_with_subresource_url() loads
1463 // accept_ch_with_lifetime() as a subresource. The request to persist client
1464 // hints from accept_ch_with_lifetime() should be disregarded.
1465 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1466 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1467}
1468
1469// Loads a HTTPS webpage that does not request persisting of client hints.
1470// A subresource loaded by the webpage in an iframe requests persistence of
1471// client hints. Verify that the request from the subresource in the iframe
1472// is not honored, and client hints preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051473IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal62cc3542018-06-27 23:53:301474 DisregardPersistenceRequestSubresourceIframe) {
Tarun Bansal9a7051f2018-07-10 18:30:051475 const GURL gurl =
1476 GetParam()
1477 ? http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url()
1478 : accept_ch_without_lifetime_with_subresource_iframe_url();
1479
Tarun Bansal62cc3542018-06-27 23:53:301480 base::HistogramTester histogram_tester;
1481 ContentSettingsForOneType host_settings;
1482
1483 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141484 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal62cc3542018-06-27 23:53:301485 &host_settings);
1486 EXPECT_EQ(0u, host_settings.size());
1487
Tarun Bansal9a7051f2018-07-10 18:30:051488 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal62cc3542018-06-27 23:53:301489
1490 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1491
1492 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281493 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal62cc3542018-06-27 23:53:301494
Tarun Bansal9a7051f2018-07-10 18:30:051495 // |gurl| loads accept_ch_with_lifetime() or
1496 // http_equiv_accept_ch_with_lifetime() as a subresource in an iframe. The
1497 // request to persist client hints from accept_ch_with_lifetime() or
1498 // http_equiv_accept_ch_with_lifetime() should be disregarded.
Tarun Bansal62cc3542018-06-27 23:53:301499 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1500 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1501}
1502
Tarun Bansal3b330b02017-11-09 19:03:141503// Loads a HTTP local webpage (which qualifies as a secure context) that
1504// requests persisting of client hints. Verifies that the browser receives the
1505// mojo notification from the renderer and persists the client hints to the
1506// disk.
Maks Orlovichf0a2eed2020-05-02 20:08:211507IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal3b330b02017-11-09 19:03:141508 ClientHintsLifetimeFollowedByNoClientHintHttpLocal) {
Maks Orlovichf0a2eed2020-05-02 20:08:211509 const GURL gurl = accept_ch_with_lifetime_http_local_url();
Tarun Bansal9a7051f2018-07-10 18:30:051510
Tarun Bansal3b330b02017-11-09 19:03:141511 base::HistogramTester histogram_tester;
1512 ContentSettingsForOneType host_settings;
1513
1514 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141515 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3b330b02017-11-09 19:03:141516 &host_settings);
1517 EXPECT_EQ(0u, host_settings.size());
1518
Tarun Bansal9a7051f2018-07-10 18:30:051519 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal3b330b02017-11-09 19:03:141520
1521 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1522
1523 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281524 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal3b330b02017-11-09 19:03:141525
Yoav Weissd33bacb2020-03-12 06:42:211526 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1527 expected_client_hints_number, 1);
Yoav Weiss76e1afb762020-05-14 19:28:121528 // |gurl| sets client hints persist duration to 3600 seconds, but a maximum
1529 // value is registered instead.
Tarun Bansal3b330b02017-11-09 19:03:141530 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121531 uma_histogram_max_value, 1);
Tarun Bansal3b330b02017-11-09 19:03:141532
1533 base::RunLoop().RunUntilIdle();
1534
1535 // Clients hints preferences for one origin should be persisted.
1536 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141537 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3b330b02017-11-09 19:03:141538 &host_settings);
1539 EXPECT_EQ(1u, host_settings.size());
1540
Tarun Bansal229647bd002018-02-27 17:33:361541 SetClientHintExpectationsOnMainFrame(true);
1542 SetClientHintExpectationsOnSubresources(true);
Tarun Bansal3b330b02017-11-09 19:03:141543 ui_test_utils::NavigateToURL(browser(),
1544 without_accept_ch_without_lifetime_local_url());
1545
Mike West2fddeeb72019-02-15 11:29:481546 // The user agent hint is attached to all three requests:
1547 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461548 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091549 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481550
Yoav Weissd33bacb2020-03-12 06:42:211551 // Expected number of hints attached to the image request, and the same number
1552 // to the main frame request.
1553 EXPECT_EQ(expected_client_hints_number * 2,
1554 count_client_hints_headers_seen());
Tarun Bansal3b330b02017-11-09 19:03:141555}
1556
Tarun Bansal0b8b7afd2017-08-25 03:52:161557// Loads a webpage that does not request persisting of client hints.
1558IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, NoClientHintsHttps) {
1559 base::HistogramTester histogram_tester;
Tarun Bansal1965b042017-09-07 04:59:191560 ui_test_utils::NavigateToURL(browser(),
1561 without_accept_ch_without_lifetime_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:161562
1563 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1564
1565 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281566 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal0b8b7afd2017-08-25 03:52:161567
1568 // no_client_hints_url() does not sets the client hints.
1569 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1570 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1571}
1572
Tarun Bansal9a7051f2018-07-10 18:30:051573IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal1965b042017-09-07 04:59:191574 ClientHintsLifetimeFollowedByNoClientHint) {
Tarun Bansal9a7051f2018-07-10 18:30:051575 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1576 : accept_ch_with_lifetime_url();
1577
Tarun Bansal1965b042017-09-07 04:59:191578 base::HistogramTester histogram_tester;
1579 ContentSettingsForOneType host_settings;
1580
1581 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141582 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal1965b042017-09-07 04:59:191583 &host_settings);
1584 EXPECT_EQ(0u, host_settings.size());
1585
Maks Orlovichf0a2eed2020-05-02 20:08:211586 // Fetching |gurl| should persist the request for client hints iff using
1587 // headers and not http-equiv.
Tarun Bansal9a7051f2018-07-10 18:30:051588 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansal1965b042017-09-07 04:59:191589
Maks Orlovichf0a2eed2020-05-02 20:08:211590 if (GetParam())
1591 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1592 else
1593 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
Tarun Bansal1965b042017-09-07 04:59:191594
1595 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281596 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal1965b042017-09-07 04:59:191597 base::RunLoop().RunUntilIdle();
1598
Maks Orlovichf0a2eed2020-05-02 20:08:211599 if (GetParam()) {
1600 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1601 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1602 } else {
1603 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1604 expected_client_hints_number, 1);
1605 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:121606 // seconds, but a maximum value is registered instead.
Maks Orlovichf0a2eed2020-05-02 20:08:211607 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121608 uma_histogram_max_value, 1);
Tarun Bansal1965b042017-09-07 04:59:191609
Maks Orlovichf0a2eed2020-05-02 20:08:211610 // Clients hints preferences for one origin should be persisted.
1611 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1612 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Illia Klimov48f643c2020-11-05 20:06:141613 &host_settings);
Maks Orlovichf0a2eed2020-05-02 20:08:211614 EXPECT_EQ(1u, host_settings.size());
1615 }
1616
1617 SetClientHintExpectationsOnMainFrame(!GetParam());
1618 SetClientHintExpectationsOnSubresources(!GetParam());
Tarun Bansal1965b042017-09-07 04:59:191619 ui_test_utils::NavigateToURL(browser(),
1620 without_accept_ch_without_lifetime_url());
Tarun Bansal6bf54302017-10-02 07:39:141621
Mike West2fddeeb72019-02-15 11:29:481622 // The user agent hint is attached to all three requests:
1623 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461624 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091625 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481626
Yoav Weissd33bacb2020-03-12 06:42:211627 // Expected number of hints attached to the image request, and the same number
1628 // to the main frame request.
Maks Orlovichf0a2eed2020-05-02 20:08:211629 EXPECT_EQ(GetParam() ? 0 : expected_client_hints_number * 2,
Yoav Weissd33bacb2020-03-12 06:42:211630 count_client_hints_headers_seen());
Tarun Bansal1965b042017-09-07 04:59:191631}
1632
Tarun Bansal293a7b6c2018-12-05 17:41:121633// The test first fetches a page that sets Accept-CH-Lifetime. Next, it fetches
1634// a URL from a different origin. However, that URL response redirects to the
1635// same origin from where the first page was fetched. The test verifies that
1636// on receiving redirect to an origin for which the browser has persisted client
1637// hints prefs, the browser attaches the client hints headers when fetching the
1638// redirected URL.
Maks Orlovichf0a2eed2020-05-02 20:08:211639IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal293a7b6c2018-12-05 17:41:121640 ClientHintsLifetimeFollowedByRedirectToNoClientHint) {
Maks Orlovichf0a2eed2020-05-02 20:08:211641 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal293a7b6c2018-12-05 17:41:121642
1643 base::HistogramTester histogram_tester;
1644 ContentSettingsForOneType host_settings;
1645
1646 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141647 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal293a7b6c2018-12-05 17:41:121648 &host_settings);
1649 EXPECT_EQ(0u, host_settings.size());
1650
1651 // Fetching |gurl| should persist the request for client hints.
1652 ui_test_utils::NavigateToURL(browser(), gurl);
1653
1654 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1655
1656 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281657 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal293a7b6c2018-12-05 17:41:121658
Yoav Weissd33bacb2020-03-12 06:42:211659 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1660 expected_client_hints_number, 1);
Tarun Bansal293a7b6c2018-12-05 17:41:121661 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:121662 // seconds, but a maximum value is registered instead.
Tarun Bansal293a7b6c2018-12-05 17:41:121663 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121664 uma_histogram_max_value, 1);
Tarun Bansal293a7b6c2018-12-05 17:41:121665 base::RunLoop().RunUntilIdle();
1666
1667 // Clients hints preferences for one origin should be persisted.
1668 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141669 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal293a7b6c2018-12-05 17:41:121670 &host_settings);
1671 EXPECT_EQ(1u, host_settings.size());
1672
1673 SetClientHintExpectationsOnMainFrame(true);
1674 SetClientHintExpectationsOnSubresources(true);
1675 ui_test_utils::NavigateToURL(browser(), redirect_url());
1676
Mike West2fddeeb72019-02-15 11:29:481677 // The user agent hint is attached to all three requests:
1678 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461679 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091680 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481681
Yoav Weissd33bacb2020-03-12 06:42:211682 // Expected number of hints attached to the image request, and the same number
1683 // to the main frame request.
1684 EXPECT_EQ(expected_client_hints_number * 2,
1685 count_client_hints_headers_seen());
Tarun Bansal293a7b6c2018-12-05 17:41:121686}
1687
Tarun Bansala0c1fc32018-10-03 16:14:521688// Ensure that even when cookies are blocked, client hint preferences are
Tarun Bansala61f0f62017-10-24 23:53:051689// persisted.
Maks Orlovichf0a2eed2020-05-02 20:08:211690IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521691 ClientHintsLifetimePersistedCookiesBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211692 const GURL gurl_with = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:051693
Tarun Bansala61f0f62017-10-24 23:53:051694 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
1695 CookieSettingsFactory::GetForProfile(browser()->profile());
1696 base::HistogramTester histogram_tester;
1697 ContentSettingsForOneType host_settings;
1698
1699 // Block cookies.
1700 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansala0c1fc32018-10-03 16:14:521701 ->SetContentSettingDefaultScope(gurl_with, GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451702 ContentSettingsType::COOKIES,
Illia Klimov48f643c2020-11-05 20:06:141703 CONTENT_SETTING_BLOCK);
Tarun Bansala61f0f62017-10-24 23:53:051704
Tarun Bansala0c1fc32018-10-03 16:14:521705 // Fetching |gurl_with| should persist the request for client hints.
Tarun Bansal9a7051f2018-07-10 18:30:051706 ui_test_utils::NavigateToURL(browser(), gurl_with);
Tarun Bansala0c1fc32018-10-03 16:14:521707 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 1);
Tarun Bansala61f0f62017-10-24 23:53:051708 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141709 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051710 &host_settings);
1711 EXPECT_EQ(1u, host_settings.size());
Tarun Bansala0c1fc32018-10-03 16:14:521712 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:051713}
1714
Maks Orlovichf0a2eed2020-05-02 20:08:211715IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521716 ClientHintsLifetimeAttachedCookiesBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211717 const GURL gurl_with = accept_ch_with_lifetime_url();
1718 const GURL gurl_without = accept_ch_without_lifetime_url();
Tarun Bansala61f0f62017-10-24 23:53:051719 base::HistogramTester histogram_tester;
1720 ContentSettingsForOneType host_settings;
1721
1722 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141723 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051724 &host_settings);
1725 EXPECT_EQ(0u, host_settings.size());
1726
Tarun Bansal9a7051f2018-07-10 18:30:051727 // Fetching |gurl_with| should persist the request for client hints.
1728 ui_test_utils::NavigateToURL(browser(), gurl_with);
Tarun Bansala61f0f62017-10-24 23:53:051729 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1730 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281731 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Maks Orlovichf0a2eed2020-05-02 20:08:211732 base::RunLoop().RunUntilIdle();
Tarun Bansala61f0f62017-10-24 23:53:051733
Yoav Weissd33bacb2020-03-12 06:42:211734 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1735 expected_client_hints_number, 1);
Yoav Weiss76e1afb762020-05-14 19:28:121736 // |gurl_with| tries to set client hints persist duration to 3600 seconds, but
1737 // a maximum value is registered instead.
Tarun Bansala61f0f62017-10-24 23:53:051738 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121739 uma_histogram_max_value, 1);
Tarun Bansala61f0f62017-10-24 23:53:051740
1741 // Clients hints preferences for one origin should be persisted.
1742 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141743 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051744 &host_settings);
1745 EXPECT_EQ(1u, host_settings.size());
1746
Tarun Bansala0c1fc32018-10-03 16:14:521747 // Block the cookies: Client hints should be attached.
Tarun Bansala61f0f62017-10-24 23:53:051748 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansal9a7051f2018-07-10 18:30:051749 ->SetContentSettingDefaultScope(gurl_without, GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451750 ContentSettingsType::COOKIES,
Illia Klimov48f643c2020-11-05 20:06:141751 CONTENT_SETTING_BLOCK);
Tarun Bansala61f0f62017-10-24 23:53:051752
Tarun Bansal229647bd002018-02-27 17:33:361753 SetClientHintExpectationsOnMainFrame(true);
1754 SetClientHintExpectationsOnSubresources(true);
Tarun Bansala61f0f62017-10-24 23:53:051755 ui_test_utils::NavigateToURL(browser(),
1756 without_accept_ch_without_lifetime_url());
Tarun Bansal79df868e2018-03-20 23:01:361757
Mike West2fddeeb72019-02-15 11:29:481758 // The user agent hint is attached to all three requests:
1759 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461760 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091761 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481762
Yoav Weissd33bacb2020-03-12 06:42:211763 // Expected number of hints attached to the image request, and the same number
1764 // to the main frame request.
1765 EXPECT_EQ(expected_client_hints_number * 2,
1766 count_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051767
1768 // Clear settings.
1769 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451770 ->ClearSettingsForOneType(ContentSettingsType::COOKIES);
Tarun Bansala61f0f62017-10-24 23:53:051771}
1772
1773// Ensure that when the JavaScript is blocked, client hint preferences are not
1774// persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051775IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala61f0f62017-10-24 23:53:051776 ClientHintsLifetimeNotPersistedJavaScriptBlocked) {
1777 ContentSettingsForOneType host_settings;
1778
1779 // Start a navigation. This navigation makes it possible to block JavaScript
1780 // later.
1781 ui_test_utils::NavigateToURL(browser(),
1782 without_accept_ch_without_lifetime_url());
1783
Tarun Bansal9a7051f2018-07-10 18:30:051784 const GURL gurl =
1785 GetParam() ? http_equiv_accept_ch_without_lifetime_with_iframe_url()
1786 : accept_ch_with_lifetime_url();
1787
Tarun Bansala61f0f62017-10-24 23:53:051788 // Block the JavaScript: Client hint preferences should not be persisted.
1789 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141790 ->SetContentSettingDefaultScope(
1791 gurl, GURL(), ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_BLOCK);
Tarun Bansala61f0f62017-10-24 23:53:051792 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
1793 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141794 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051795 &host_settings);
1796 EXPECT_EQ(0u, host_settings.size());
Tarun Bansalc211d8b2018-03-19 19:21:581797 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:051798
1799 // Allow the JavaScript: Client hint preferences should be persisted.
1800 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141801 ->SetContentSettingDefaultScope(
1802 gurl, GURL(), ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_ALLOW);
Tarun Bansala61f0f62017-10-24 23:53:051803 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
1804 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141805 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051806 &host_settings);
1807 EXPECT_EQ(1u, host_settings.size());
Tarun Bansal593790112018-03-20 04:53:341808
1809 // Clear settings.
1810 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451811 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansala61f0f62017-10-24 23:53:051812}
1813
1814// Ensure that when the JavaScript is blocked, persisted client hints are not
1815// attached to the request headers.
Maks Orlovichf0a2eed2020-05-02 20:08:211816IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala61f0f62017-10-24 23:53:051817 ClientHintsLifetimeNotAttachedJavaScriptBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211818 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:051819
Tarun Bansala61f0f62017-10-24 23:53:051820 base::HistogramTester histogram_tester;
1821 ContentSettingsForOneType host_settings;
1822
1823 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141824 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051825 &host_settings);
1826 EXPECT_EQ(0u, host_settings.size());
1827
1828 // Fetching accept_ch_with_lifetime_url() should persist the request for
1829 // client hints.
Tarun Bansal9a7051f2018-07-10 18:30:051830 ui_test_utils::NavigateToURL(browser(), gurl);
Tarun Bansala61f0f62017-10-24 23:53:051831 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1832 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281833 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Mike West2fddeeb72019-02-15 11:29:481834 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461835 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091836 EXPECT_EQ(1u, count_ua_platform_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051837
Yoav Weissd33bacb2020-03-12 06:42:211838 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1839 expected_client_hints_number, 1);
Tarun Bansala61f0f62017-10-24 23:53:051840 // accept_ch_with_lifetime_url() tries to set client hints persist duration to
Yoav Weiss76e1afb762020-05-14 19:28:121841 // 3600 seconds, but a maximum value is registered instead.
Tarun Bansala61f0f62017-10-24 23:53:051842 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121843 uma_histogram_max_value, 1);
Tarun Bansala61f0f62017-10-24 23:53:051844 base::RunLoop().RunUntilIdle();
1845
1846 // Clients hints preferences for one origin should be persisted.
1847 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141848 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051849 &host_settings);
1850 EXPECT_EQ(1u, host_settings.size());
1851
Changwan Ryu434c3a32019-07-30 23:42:581852 // Block JavaScript via WebPreferences: Client hints should not be attached.
1853 SetJsEnabledForActiveView(false);
1854
1855 SetClientHintExpectationsOnMainFrame(false);
1856 SetClientHintExpectationsOnSubresources(false);
1857 ui_test_utils::NavigateToURL(browser(),
1858 without_accept_ch_without_lifetime_url());
1859
1860 EXPECT_EQ(0u, count_client_hints_headers_seen());
1861 VerifyContentSettingsNotNotified();
1862 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461863 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091864 EXPECT_EQ(1u, count_ua_platform_client_hints_headers_seen());
Changwan Ryu434c3a32019-07-30 23:42:581865
1866 SetJsEnabledForActiveView(true);
1867
1868 // Block JavaScript via ContentSetting: Client hints should not be attached.
Tarun Bansala61f0f62017-10-24 23:53:051869 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1870 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
Darin Fisher42f5e7d2019-10-30 07:15:451871 GURL(), ContentSettingsType::JAVASCRIPT,
Illia Klimov48f643c2020-11-05 20:06:141872 CONTENT_SETTING_BLOCK);
Tarun Bansala61f0f62017-10-24 23:53:051873 ui_test_utils::NavigateToURL(browser(),
1874 without_accept_ch_without_lifetime_url());
1875 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansalc211d8b2018-03-19 19:21:581876 VerifyContentSettingsNotNotified();
Mike West2fddeeb72019-02-15 11:29:481877 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461878 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091879 EXPECT_EQ(1u, count_ua_platform_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051880
Changwan Ryu434c3a32019-07-30 23:42:581881 // Allow JavaScript: Client hints should now be attached.
Tarun Bansala61f0f62017-10-24 23:53:051882 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1883 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
Darin Fisher42f5e7d2019-10-30 07:15:451884 GURL(), ContentSettingsType::JAVASCRIPT,
Illia Klimov48f643c2020-11-05 20:06:141885 CONTENT_SETTING_ALLOW);
Tarun Bansala61f0f62017-10-24 23:53:051886
Tarun Bansal229647bd002018-02-27 17:33:361887 SetClientHintExpectationsOnMainFrame(true);
1888 SetClientHintExpectationsOnSubresources(true);
Tarun Bansala61f0f62017-10-24 23:53:051889 ui_test_utils::NavigateToURL(browser(),
1890 without_accept_ch_without_lifetime_url());
Tarun Bansal79df868e2018-03-20 23:01:361891
Mike West2fddeeb72019-02-15 11:29:481892 // The user agent hint is attached to all three requests:
1893 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461894 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091895 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481896
Yoav Weissd33bacb2020-03-12 06:42:211897 // Expected number of hints attached to the image request, and the same number
1898 // to the main frame request.
1899 EXPECT_EQ(expected_client_hints_number * 2,
1900 count_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051901
1902 // Clear settings.
1903 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451904 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansala61f0f62017-10-24 23:53:051905}
1906
Tarun Bansal73502f92019-04-16 21:21:191907// Test that if the content settings are malformed, then the browser does not
1908// crash.
1909IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
1910 ClientHintsMalformedContentSettings) {
1911 ContentSettingsForOneType client_hints_settings;
1912 HostContentSettingsMap* host_content_settings_map =
1913 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
1914
1915 // Add setting for the host.
1916 std::unique_ptr<base::ListValue> expiration_times_list =
1917 std::make_unique<base::ListValue>();
Clark DuVallf138b4d2021-09-01 18:07:051918 expiration_times_list->Append(42 /* client hint value */);
Tarun Bansal73502f92019-04-16 21:21:191919 auto expiration_times_dictionary = std::make_unique<base::DictionaryValue>();
1920 expiration_times_dictionary->SetList("client_hints",
1921 std::move(expiration_times_list));
Reilly Grant655445f2021-07-14 02:52:231922 expiration_times_dictionary->SetDoubleKey(
Aaron Tagliaboschi3c96a682019-10-29 18:10:281923 "expiration_time",
1924 (base::Time::Now() + base::TimeDelta::FromDays(1)).ToDoubleT());
Tarun Bansal73502f92019-04-16 21:21:191925 host_content_settings_map->SetWebsiteSettingDefaultScope(
1926 without_accept_ch_without_lifetime_url(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141927 ContentSettingsType::CLIENT_HINTS,
Tarun Bansal73502f92019-04-16 21:21:191928 std::make_unique<base::Value>(expiration_times_dictionary->Clone()));
1929
1930 // Reading the settings should now return one setting.
1931 host_content_settings_map->GetSettingsForOneType(
Illia Klimov48f643c2020-11-05 20:06:141932 ContentSettingsType::CLIENT_HINTS, &client_hints_settings);
Tarun Bansal73502f92019-04-16 21:21:191933 EXPECT_EQ(1U, client_hints_settings.size());
1934
1935 SetClientHintExpectationsOnMainFrame(false);
1936 SetClientHintExpectationsOnSubresources(false);
1937 ui_test_utils::NavigateToURL(browser(),
1938 without_accept_ch_without_lifetime_url());
1939}
1940
Tarun Bansal229647bd002018-02-27 17:33:361941// Ensure that when the JavaScript is blocked, client hints requested using
Tarun Bansal3f343d7c2018-03-02 18:48:001942// Accept-CH are not attached to the request headers for subresources.
Tarun Bansal9a7051f2018-07-10 18:30:051943IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal229647bd002018-02-27 17:33:361944 ClientHintsNoLifetimeScriptNotAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:051945 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1946 : accept_ch_with_lifetime_url();
1947
Tarun Bansal1965b042017-09-07 04:59:191948 base::HistogramTester histogram_tester;
1949 ContentSettingsForOneType host_settings;
1950
1951 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141952 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal1965b042017-09-07 04:59:191953 &host_settings);
1954 EXPECT_EQ(0u, host_settings.size());
1955
Tarun Bansal3f343d7c2018-03-02 18:48:001956 // Block the Javascript: Client hints should not be attached.
1957 SetClientHintExpectationsOnSubresources(false);
Tarun Bansal229647bd002018-02-27 17:33:361958 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1959 ->SetContentSettingDefaultScope(
1960 accept_ch_without_lifetime_img_localhost(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141961 ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_BLOCK);
Tarun Bansal229647bd002018-02-27 17:33:361962 ui_test_utils::NavigateToURL(browser(),
1963 accept_ch_without_lifetime_img_localhost());
Mike West2fddeeb72019-02-15 11:29:481964 EXPECT_EQ(0u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461965 EXPECT_EQ(0u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091966 EXPECT_EQ(0u, count_ua_platform_client_hints_headers_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001967 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361968 EXPECT_EQ(1u, third_party_request_count_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001969 EXPECT_EQ(0u, third_party_client_hints_count_seen());
Tarun Bansal1965b042017-09-07 04:59:191970
Tarun Bansal3f343d7c2018-03-02 18:48:001971 // Allow the Javascript: Client hints should now be attached.
Tarun Bansal229647bd002018-02-27 17:33:361972 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1973 ->SetContentSettingDefaultScope(
1974 accept_ch_without_lifetime_img_localhost(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141975 ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_ALLOW);
Tarun Bansal1965b042017-09-07 04:59:191976
Tarun Bansal229647bd002018-02-27 17:33:361977 SetClientHintExpectationsOnSubresources(true);
1978 ui_test_utils::NavigateToURL(browser(),
1979 accept_ch_without_lifetime_img_localhost());
Tarun Bansal3f343d7c2018-03-02 18:48:001980
Mike West2fddeeb72019-02-15 11:29:481981 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461982 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091983 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Aaron Tagliaboschi150fb9042020-05-14 22:20:371984 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361985 EXPECT_EQ(2u, third_party_request_count_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091986 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansalc211d8b2018-03-19 19:21:581987 VerifyContentSettingsNotNotified();
Tarun Bansal1965b042017-09-07 04:59:191988
Tarun Bansal229647bd002018-02-27 17:33:361989 // Clear settings.
1990 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451991 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansal1965b042017-09-07 04:59:191992
Tarun Bansal229647bd002018-02-27 17:33:361993 // Block the Javascript again: Client hints should not be attached.
Tarun Bansal3f343d7c2018-03-02 18:48:001994 SetClientHintExpectationsOnSubresources(false);
Tarun Bansal229647bd002018-02-27 17:33:361995 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1996 ->SetContentSettingDefaultScope(
1997 accept_ch_without_lifetime_img_localhost(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141998 ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_BLOCK);
Tarun Bansal229647bd002018-02-27 17:33:361999 ui_test_utils::NavigateToURL(browser(),
2000 accept_ch_without_lifetime_img_localhost());
Mike West2fddeeb72019-02-15 11:29:482001 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462002 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092003 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Aaron Tagliaboschi150fb9042020-05-14 22:20:372004 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:362005 EXPECT_EQ(3u, third_party_request_count_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092006 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansal593790112018-03-20 04:53:342007
2008 // Clear settings.
2009 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:452010 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansal229647bd002018-02-27 17:33:362011}
2012
Tarun Bansala0c1fc32018-10-03 16:14:522013// Ensure that when the cookies is blocked, client hints are attached to the
Tarun Bansal3f343d7c2018-03-02 18:48:002014// request headers.
Tarun Bansal9a7051f2018-07-10 18:30:052015IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:522016 ClientHintsLifetimeCookiesNotAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:052017 const GURL gurl = GetParam()
2018 ? http_equiv_accept_ch_without_lifetime_img_localhost()
2019 : accept_ch_without_lifetime_img_localhost();
2020
Tarun Bansal229647bd002018-02-27 17:33:362021 base::HistogramTester histogram_tester;
2022 ContentSettingsForOneType host_settings;
2023 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
2024 CookieSettingsFactory::GetForProfile(browser()->profile());
2025
Tarun Bansal1965b042017-09-07 04:59:192026 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:142027 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal1965b042017-09-07 04:59:192028 &host_settings);
2029 EXPECT_EQ(0u, host_settings.size());
2030
Tarun Bansal229647bd002018-02-27 17:33:362031 // Block cookies.
2032 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:142033 ->SetContentSettingDefaultScope(
2034 gurl, GURL(), ContentSettingsType::COOKIES, CONTENT_SETTING_BLOCK);
Tarun Bansal229647bd002018-02-27 17:33:362035 base::RunLoop().RunUntilIdle();
2036
Tarun Bansal229647bd002018-02-27 17:33:362037 SetClientHintExpectationsOnSubresources(true);
Tarun Bansal9a7051f2018-07-10 18:30:052038 ui_test_utils::NavigateToURL(browser(), gurl);
Mike West2fddeeb72019-02-15 11:29:482039 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462040 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092041 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:212042 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansala0c1fc32018-10-03 16:14:522043 EXPECT_EQ(1u, third_party_request_count_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092044 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansal593790112018-03-20 04:53:342045
2046 // Clear settings.
2047 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:452048 ->ClearSettingsForOneType(ContentSettingsType::COOKIES);
Tarun Bansal1965b042017-09-07 04:59:192049}
2050
Tarun Bansal3ce0ca42018-06-25 22:52:222051// Verify that client hints are sent in the incognito profiles, and server
2052// client hint opt-ins are honored within the incognito profile.
Maks Orlovichf0a2eed2020-05-02 20:08:212053IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal3ce0ca42018-06-25 22:52:222054 ClientHintsLifetimeFollowedByNoClientHintIncognito) {
Maks Orlovichf0a2eed2020-05-02 20:08:212055 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:052056
Tarun Bansal3ce0ca42018-06-25 22:52:222057 base::HistogramTester histogram_tester;
2058 Browser* incognito = CreateIncognitoBrowser();
2059 ContentSettingsForOneType host_settings;
2060
2061 HostContentSettingsMapFactory::GetForProfile(incognito->profile())
Illia Klimov48f643c2020-11-05 20:06:142062 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3ce0ca42018-06-25 22:52:222063 &host_settings);
2064 EXPECT_EQ(0u, host_settings.size());
2065
Tarun Bansal9a7051f2018-07-10 18:30:052066 // Fetching |gurl| should persist the request for client hints.
2067 ui_test_utils::NavigateToURL(incognito, gurl);
Tarun Bansal3ce0ca42018-06-25 22:52:222068
2069 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
2070
2071 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:282072 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal3ce0ca42018-06-25 22:52:222073
Yoav Weissd33bacb2020-03-12 06:42:212074 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
2075 expected_client_hints_number, 1);
Tarun Bansal3ce0ca42018-06-25 22:52:222076 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:122077 // seconds, but a maximum value is registered instead.
Tarun Bansal3ce0ca42018-06-25 22:52:222078 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:122079 uma_histogram_max_value, 1);
Tarun Bansal3ce0ca42018-06-25 22:52:222080 base::RunLoop().RunUntilIdle();
2081
2082 // Clients hints preferences for one origin should be persisted.
2083 HostContentSettingsMapFactory::GetForProfile(incognito->profile())
Illia Klimov48f643c2020-11-05 20:06:142084 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3ce0ca42018-06-25 22:52:222085 &host_settings);
2086 EXPECT_EQ(1u, host_settings.size());
2087
2088 SetClientHintExpectationsOnMainFrame(true);
2089 SetClientHintExpectationsOnSubresources(true);
2090 ui_test_utils::NavigateToURL(incognito,
2091 without_accept_ch_without_lifetime_url());
2092
Mike West2fddeeb72019-02-15 11:29:482093 // The user agent hint is attached to all three requests:
2094 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462095 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092096 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:482097
Yoav Weissd33bacb2020-03-12 06:42:212098 // Expected number of hints attached to the image request, and the same number
2099 // to the main frame request.
2100 EXPECT_EQ(expected_client_hints_number * 2,
2101 count_client_hints_headers_seen());
Tarun Bansal3ce0ca42018-06-25 22:52:222102
2103 // Navigate using regular profile. Client hints should not be send.
2104 SetClientHintExpectationsOnMainFrame(false);
2105 SetClientHintExpectationsOnSubresources(false);
2106 ui_test_utils::NavigateToURL(browser(),
2107 without_accept_ch_without_lifetime_url());
2108
Mike West2fddeeb72019-02-15 11:29:482109 // The user agent hint is attached to the two new requests.
2110 EXPECT_EQ(5u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462111 EXPECT_EQ(5u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092112 EXPECT_EQ(5u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:482113
2114 // No additional hints are sent.
Yoav Weissd33bacb2020-03-12 06:42:212115 EXPECT_EQ(expected_client_hints_number * 2,
2116 count_client_hints_headers_seen());
Tarun Bansal3ce0ca42018-06-25 22:52:222117}
Tarun Bansalbef6d652018-10-02 18:41:012118
Tarun Bansalbef6d652018-10-02 18:41:012119class ClientHintsWebHoldbackBrowserTest : public ClientHintsBrowserTest {
2120 public:
2121 ClientHintsWebHoldbackBrowserTest() : ClientHintsBrowserTest() {
2122 ConfigureHoldbackExperiment();
2123 }
2124
2125 net::EffectiveConnectionType web_effective_connection_type_override() const {
2126 return web_effective_connection_type_override_;
2127 }
2128
Mike West2fddeeb72019-02-15 11:29:482129 std::unique_ptr<base::FeatureList> EnabledFeatures() override {
Tarun Bansalbef6d652018-10-02 18:41:012130 base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
2131 const std::string kTrialName = "TrialFoo";
2132 const std::string kGroupName = "GroupFoo"; // Value not used
2133
2134 scoped_refptr<base::FieldTrial> trial =
2135 base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
2136
2137 std::map<std::string, std::string> params;
2138
2139 params["web_effective_connection_type_override"] =
2140 net::GetNameForEffectiveConnectionType(
2141 web_effective_connection_type_override_);
Mike West2fddeeb72019-02-15 11:29:482142 EXPECT_TRUE(
Tarun Bansalbef6d652018-10-02 18:41:012143 base::FieldTrialParamAssociator::GetInstance()
2144 ->AssociateFieldTrialParams(kTrialName, kGroupName, params));
2145
2146 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
Maks Orlovichc66745a2020-06-30 17:40:022147 feature_list->InitializeFromCommandLine(
François Beaufort1b51d062021-05-18 11:11:232148 "UserAgentClientHint,LangClientHintHeader,"
Max Curran99cbec1492021-08-16 19:54:262149 "PrefersColorSchemeClientHintHeader,ViewportHeightClientHintHeader",
François Beaufort1b51d062021-05-18 11:11:232150 "");
Tarun Bansalbef6d652018-10-02 18:41:012151 feature_list->RegisterFieldTrialOverride(
2152 features::kNetworkQualityEstimatorWebHoldback.name,
2153 base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
Mike West2fddeeb72019-02-15 11:29:482154 return feature_list;
Tarun Bansalbef6d652018-10-02 18:41:012155 }
2156
Mike West2fddeeb72019-02-15 11:29:482157 private:
2158 void ConfigureHoldbackExperiment() {}
2159
Tarun Bansalbef6d652018-10-02 18:41:012160 const net::EffectiveConnectionType web_effective_connection_type_override_ =
2161 net::EFFECTIVE_CONNECTION_TYPE_3G;
Tarun Bansalbef6d652018-10-02 18:41:012162};
2163
2164// Make sure that when NetInfo holdback experiment is enabled, the NetInfo APIs
2165// and client hints return the overridden values. Verify that the client hints
2166// are overridden on both main frame and subresource requests.
2167IN_PROC_BROWSER_TEST_F(ClientHintsWebHoldbackBrowserTest,
2168 EffectiveConnectionTypeChangeNotified) {
2169 SetExpectedEffectiveConnectionType(web_effective_connection_type_override());
2170
2171 SetClientHintExpectationsOnMainFrame(false);
2172 SetClientHintExpectationsOnSubresources(true);
2173
2174 base::RunLoop().RunUntilIdle();
2175
2176 EXPECT_TRUE(embedded_test_server()->Start());
2177 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url());
2178 EXPECT_EQ(0u, count_client_hints_headers_seen());
2179 EXPECT_EQ(0u, third_party_request_count_seen());
2180 EXPECT_EQ(0u, third_party_client_hints_count_seen());
2181
2182 SetClientHintExpectationsOnMainFrame(true);
2183 SetClientHintExpectationsOnSubresources(true);
2184 ui_test_utils::NavigateToURL(
2185 browser(), accept_ch_without_lifetime_with_subresource_url());
2186 base::RunLoop().RunUntilIdle();
2187 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:282188 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansalbef6d652018-10-02 18:41:012189
Mike West2fddeeb72019-02-15 11:29:482190 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462191 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092192 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:212193 EXPECT_EQ(expected_client_hints_number * 2,
2194 count_client_hints_headers_seen());
Tarun Bansalbef6d652018-10-02 18:41:012195 EXPECT_EQ(0u, third_party_request_count_seen());
2196 EXPECT_EQ(0u, third_party_client_hints_count_seen());
2197}
Aaron Tagliaboschi603540d22021-04-05 00:37:142198
2199class AcceptCHFrameObserverInterceptor {
2200 public:
2201 AcceptCHFrameObserverInterceptor()
2202 : interceptor_(base::BindRepeating(
2203 &AcceptCHFrameObserverInterceptor::InterceptURLRequest,
2204 base::Unretained(this))) {}
2205
2206 void set_accept_ch_frame(
2207 std::vector<network::mojom::WebClientHintsType> frame) {
2208 accept_ch_frame_ = frame;
2209 }
2210
2211 private:
Ali Beyadf05102d2021-08-23 16:53:402212 bool InterceptURLRequest(URLLoaderInterceptor::RequestParams* params) {
Aaron Tagliaboschi603540d22021-04-05 00:37:142213 if (!accept_ch_frame_ || !params->url_request.trusted_params ||
2214 !params->url_request.trusted_params->accept_ch_frame_observer) {
2215 return false;
2216 }
2217
2218 std::vector<network::mojom::WebClientHintsType> hints;
2219 for (auto hint : accept_ch_frame_.value()) {
2220 std::string header =
2221 network::kClientHintsNameMapping[static_cast<int>(hint)];
2222 if (!params->url_request.headers.HasHeader(header))
2223 hints.push_back(hint);
2224 }
2225
2226 if (hints.empty())
2227 return false;
2228
2229 mojo::Remote<network::mojom::AcceptCHFrameObserver> remote(std::move(
2230 params->url_request.trusted_params->accept_ch_frame_observer));
2231 remote->OnAcceptCHFrameReceived(params->url_request.url, hints,
2232 base::DoNothing::Once<int>());
2233 // At this point it's expected that either the remote's callback will be
2234 // called or the URLLoader will be destroyed to make way for a new one.
2235 // As this is essentially unobservable, RunUntilIdle must be used.
2236 base::RunLoop().RunUntilIdle();
2237 return false;
2238 }
2239
Ali Beyadf05102d2021-08-23 16:53:402240 URLLoaderInterceptor interceptor_;
Anton Bikineev46bbb972021-05-15 17:53:532241 absl::optional<std::vector<network::mojom::WebClientHintsType>>
Aaron Tagliaboschi603540d22021-04-05 00:37:142242 accept_ch_frame_;
2243};
2244
2245// Replace the request interceptor with an AcceptCHFrameObserverInterceptor.
2246class ClientHintsAcceptCHFrameObserverBrowserTest
2247 : public ClientHintsBrowserTest {
2248 public:
2249 void SetUpOnMainThread() override {
2250 host_resolver()->AddRule("*", "127.0.0.1");
2251 accept_ch_frame_observer_interceptor_ =
2252 std::make_unique<AcceptCHFrameObserverInterceptor>();
2253 }
2254
2255 void TearDownOnMainThread() override {
2256 accept_ch_frame_observer_interceptor_.reset();
2257 }
2258
2259 void set_accept_ch_frame(
2260 std::vector<network::mojom::WebClientHintsType> frame) {
2261 accept_ch_frame_observer_interceptor_->set_accept_ch_frame(frame);
2262 }
2263
2264 std::vector<network::mojom::WebClientHintsType> all_client_hints_types() {
2265 std::vector<network::mojom::WebClientHintsType> hints;
2266 for (size_t i = 0; i < blink::kClientHintsMappingsCount; i++) {
2267 hints.push_back(static_cast<network::mojom::WebClientHintsType>(i));
2268 }
2269
2270 return hints;
2271 }
2272
2273 private:
2274 std::unique_ptr<AcceptCHFrameObserverInterceptor>
2275 accept_ch_frame_observer_interceptor_;
2276};
2277
Elly Fong-Jonesdd9eb012021-04-05 22:45:272278#if defined(OS_CHROMEOS)
2279// Flaky: https://crbug.com/1195790
2280#define MAYBE_AcceptCHFrame DISABLED_AcceptCHFrame
2281#else
2282#define MAYBE_AcceptCHFrame AcceptCHFrame
2283#endif
2284
Aaron Tagliaboschi603540d22021-04-05 00:37:142285// Ensure that client hints are sent when the ACCEPT_CH frame observer is
2286// notified.
2287IN_PROC_BROWSER_TEST_F(ClientHintsAcceptCHFrameObserverBrowserTest,
Elly Fong-Jonesdd9eb012021-04-05 22:45:272288 MAYBE_AcceptCHFrame) {
Aaron Tagliaboschi603540d22021-04-05 00:37:142289 const GURL gurl = without_accept_ch_without_lifetime_url();
2290 set_accept_ch_frame(all_client_hints_types());
2291 SetClientHintExpectationsOnMainFrame(true);
2292 SetClientHintExpectationsOnSubresources(false);
2293 ui_test_utils::NavigateToURL(browser(), gurl);
2294}
2295
2296// Ensure that client hints are *not* sent when the observer is notified but
2297// client hints would normally not be sent (e.g. when JS is disabled for the
2298// frame).
2299IN_PROC_BROWSER_TEST_F(ClientHintsAcceptCHFrameObserverBrowserTest,
2300 AcceptCHFrameJSDisabled) {
2301 const GURL gurl = without_accept_ch_without_lifetime_url();
2302 set_accept_ch_frame(all_client_hints_types());
2303 SetJsEnabledForActiveView(false);
2304 SetClientHintExpectationsOnMainFrame(false);
2305 SetClientHintExpectationsOnSubresources(false);
2306 ui_test_utils::NavigateToURL(browser(), gurl);
2307}
Aaron Tagliaboschi25625c22021-05-11 18:13:592308
2309IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest, UseCounter) {
2310 auto web_feature_waiter =
2311 std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>(
2312 chrome_test_utils::GetActiveWebContents(this));
2313
2314 web_feature_waiter->AddWebFeatureExpectation(
Aaron Tagliaboschiec5bce62021-06-24 18:50:092315 blink::mojom::WebFeature::kClientHintsUAFullVersion);
Aaron Tagliaboschi25625c22021-05-11 18:13:592316 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
2317 : accept_ch_with_lifetime_url();
2318
2319 ui_test_utils::NavigateToURL(browser(), gurl);
2320
2321 web_feature_waiter->Wait();
2322}
François Beaufort34e299e2021-05-26 05:54:332323
Ali Beyada6b0fb6f2021-07-28 00:13:242324class CriticalClientHintsBrowserTest : public InProcessBrowserTest {
2325 public:
2326 CriticalClientHintsBrowserTest()
2327 : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
2328 https_server_.ServeFilesFromSourceDirectory(
2329 "chrome/test/data/client_hints");
2330 https_server_.RegisterRequestMonitor(base::BindRepeating(
2331 &CriticalClientHintsBrowserTest::MonitorResourceRequest,
2332 base::Unretained(this)));
2333 EXPECT_TRUE(https_server_.Start());
2334 }
2335
2336 void SetUp() override {
2337 std::unique_ptr<base::FeatureList> feature_list =
2338 std::make_unique<base::FeatureList>();
2339 // Don't include LangClientHintHeader in the enabled features; we will
2340 // verify that the Sec-CH-Lang header is not included.
2341 feature_list->InitializeFromCommandLine(
2342 "UserAgentClientHint,CriticalClientHint,AcceptCHFrame,"
2343 "PrefersColorSchemeClientHintHeader",
2344 "");
2345 scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
Ali Beyad821f4192021-08-20 16:21:282346
2347 InProcessBrowserTest::SetUp();
Ali Beyada6b0fb6f2021-07-28 00:13:242348 }
2349
2350 void SetUpOnMainThread() override {
2351 host_resolver()->AddRule("*", "127.0.0.1");
Ali Beyad821f4192021-08-20 16:21:282352
2353 InProcessBrowserTest::SetUpOnMainThread();
Ali Beyada6b0fb6f2021-07-28 00:13:242354 }
2355
2356 GURL critical_ch_ua_full_version_url() const {
2357 return https_server_.GetURL("/critical_ch_ua_full_version.html");
2358 }
2359
2360 GURL critical_ch_lang_url() const {
2361 return https_server_.GetURL("/critical_ch_lang.html");
2362 }
2363
2364 const absl::optional<std::string>& observed_ch_ua_full_version() {
2365 base::AutoLock lock(ch_ua_full_version_lock_);
2366 return ch_ua_full_version_;
2367 }
2368
2369 const absl::optional<std::string>& observed_ch_lang() {
2370 base::AutoLock lock(ch_lang_lock_);
2371 return ch_lang_;
2372 }
2373
2374 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
2375 if (request.headers.find("sec-ch-ua-full-version") !=
2376 request.headers.end()) {
2377 SetChUaFullVersion(request.headers.at("sec-ch-ua-full-version"));
2378 }
2379 if (request.headers.find("sec-ch-lang") != request.headers.end()) {
2380 SetChLang(request.headers.at("sec-ch-lang"));
2381 }
2382 }
2383
2384 private:
2385 void SetChUaFullVersion(const std::string& ch_ua_full_version) {
2386 base::AutoLock lock(ch_ua_full_version_lock_);
2387 ch_ua_full_version_ = ch_ua_full_version;
2388 }
2389
2390 void SetChLang(const std::string& ch_lang) {
2391 base::AutoLock lock(ch_lang_lock_);
2392 ch_lang_ = ch_lang;
2393 }
2394
2395 base::test::ScopedFeatureList scoped_feature_list_;
2396 net::EmbeddedTestServer https_server_;
2397 base::Lock ch_ua_full_version_lock_;
2398 absl::optional<std::string> ch_ua_full_version_
2399 GUARDED_BY(ch_ua_full_version_lock_);
2400 base::Lock ch_lang_lock_;
2401 absl::optional<std::string> ch_lang_ GUARDED_BY(ch_lang_lock_);
2402};
2403
2404// Verify that setting Critical-CH in the response header causes the request to
2405// be resent with the client hint included.
2406IN_PROC_BROWSER_TEST_F(CriticalClientHintsBrowserTest,
Ali Beyad821f4192021-08-20 16:21:282407 CriticalClientHintInRequestHeader) {
Ali Beyada6b0fb6f2021-07-28 00:13:242408 blink::UserAgentMetadata ua = embedder_support::GetUserAgentMetadata();
2409 // On the first navigation request, the client hints in the Critical-CH
2410 // should be set on the request header.
2411 ui_test_utils::NavigateToURL(browser(), critical_ch_ua_full_version_url());
2412 const std::string expected_ch_ua_full_version = "\"" + ua.full_version + "\"";
2413 EXPECT_THAT(observed_ch_ua_full_version(),
2414 Optional(Eq(expected_ch_ua_full_version)));
2415 EXPECT_EQ(observed_ch_lang(), absl::nullopt);
2416}
2417
2418// Verify that setting Critical-CH in the response header with a client hint
2419// that is filtered out of Accept-CH causes the request to *not* be resent and
2420// the critical client hint is not included.
2421//
2422// NB: When the LangClientHintHeader feature is removed, this test needs to be
2423// updated.
2424IN_PROC_BROWSER_TEST_F(
2425 CriticalClientHintsBrowserTest,
2426 CriticalClientHintFilteredOutOfAcceptChNotInRequestHeader) {
2427 // On the first navigation request, the client hints in the Critical-CH
2428 // should be set on the request header, but in this case, the
2429 // LangClientHintHeader is not enabled, so the critical client hint won't be
2430 // set in the request header.
2431 ui_test_utils::NavigateToURL(browser(), critical_ch_lang_url());
2432 EXPECT_EQ(observed_ch_lang(), absl::nullopt);
2433 // The request should not have been resent, so ch-ua-full-version should also
2434 // not be present.
2435 EXPECT_EQ(observed_ch_ua_full_version(), absl::nullopt);
2436}
2437
François Beaufort34e299e2021-05-26 05:54:332438class ClientHintsBrowserTestWithEmulatedMedia
2439 : public DevToolsProtocolTestBase {
2440 public:
2441 ClientHintsBrowserTestWithEmulatedMedia()
2442 : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
2443 scoped_feature_list_.InitFromCommandLine(
2444 "UserAgentClientHint,AcceptCHFrame,PrefersColorSchemeClientHintHeader",
2445 "");
2446
2447 https_server_.ServeFilesFromSourceDirectory(
2448 "chrome/test/data/client_hints");
2449 https_server_.RegisterRequestMonitor(base::BindRepeating(
2450 &ClientHintsBrowserTestWithEmulatedMedia::MonitorResourceRequest,
2451 base::Unretained(this)));
2452 EXPECT_TRUE(https_server_.Start());
2453
2454 test_url_ = https_server_.GetURL("/accept_ch_without_lifetime.html");
2455 }
2456
2457 ~ClientHintsBrowserTestWithEmulatedMedia() override = default;
2458
2459 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
2460 if (request.headers.find("sec-ch-prefers-color-scheme") !=
2461 request.headers.end()) {
2462 prefers_color_scheme_observed_ =
2463 request.headers.at("sec-ch-prefers-color-scheme");
2464 }
2465 }
2466
2467 const GURL& test_url() const { return test_url_; }
2468
2469 const std::string& prefers_color_scheme_observed() const {
2470 return prefers_color_scheme_observed_;
2471 }
2472
2473 void EmulatePrefersColorScheme(std::string value) {
2474 base::Value feature(base::Value::Type::DICTIONARY);
2475 feature.SetKey("name", base::Value("prefers-color-scheme"));
2476 feature.SetKey("value", base::Value(value));
2477 base::Value features(base::Value::Type::LIST);
2478 features.Append(std::move(feature));
2479 base::Value params(base::Value::Type::DICTIONARY);
2480 params.SetKey("features", std::move(features));
2481 SendCommandSync("Emulation.setEmulatedMedia", std::move(params));
2482 }
2483
2484 private:
2485 base::test::ScopedFeatureList scoped_feature_list_;
2486 net::EmbeddedTestServer https_server_;
2487 GURL test_url_;
2488 std::string prefers_color_scheme_observed_;
2489
2490 DISALLOW_COPY_AND_ASSIGN(ClientHintsBrowserTestWithEmulatedMedia);
2491};
2492
2493IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTestWithEmulatedMedia,
2494 PrefersColorScheme) {
2495 ui_test_utils::NavigateToURL(browser(), test_url());
2496 EXPECT_EQ(prefers_color_scheme_observed(), "");
2497 Attach();
2498
2499 EmulatePrefersColorScheme("light");
2500 ui_test_utils::NavigateToURL(browser(), test_url());
2501 EXPECT_EQ(prefers_color_scheme_observed(), "light");
2502
2503 EmulatePrefersColorScheme("dark");
2504 ui_test_utils::NavigateToURL(browser(), test_url());
2505 EXPECT_EQ(prefers_color_scheme_observed(), "dark");
2506}
Ali Beyad7417fc22021-08-06 03:09:582507
Ali Beyadf05102d2021-08-23 16:53:402508// Base class for the User-Agent reduction Origin Trial browser tests. Common
2509// functionality shared between the various UA reduction browser tests should
2510// go in this class.
Ali Beyad7417fc22021-08-06 03:09:582511class UaReducedOriginTrialBrowserTest : public InProcessBrowserTest {
2512 public:
Ali Beyad7417fc22021-08-06 03:09:582513 void SetUpCommandLine(base::CommandLine* command_line) override {
2514 // The public key for the default privatey key used by the
2515 // tools/origin_trials/generate_token.py tool.
2516 static constexpr char kOriginTrialTestPublicKey[] =
2517 "dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BNA=";
2518 command_line->AppendSwitchASCII(embedder_support::kOriginTrialPublicKey,
2519 kOriginTrialTestPublicKey);
2520 }
2521
2522 void SetUp() override {
2523 std::unique_ptr<base::FeatureList> feature_list =
2524 std::make_unique<base::FeatureList>();
2525 feature_list->InitializeFromCommandLine("CriticalClientHint", "");
2526 scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
Ali Beyad821f4192021-08-20 16:21:282527
2528 InProcessBrowserTest::SetUp();
Ali Beyad7417fc22021-08-06 03:09:582529 }
2530
Ali Beyadf05102d2021-08-23 16:53:402531 void SetUserAgentOverride(const std::string& ua_override) {
2532 content::WebContents* web_contents =
2533 browser()->tab_strip_model()->GetActiveWebContents();
2534 web_contents->SetUserAgentOverride(
2535 blink::UserAgentOverride::UserAgentOnly(ua_override), false);
2536 web_contents->GetController()
2537 .GetLastCommittedEntry()
2538 ->SetIsOverridingUserAgent(true);
2539 }
2540
2541 void CheckUaReducedClientHint(const bool ch_ua_reduced_expected) {
2542 const absl::optional<std::string>& ua_reduced_client_hint =
2543 GetLastUaReducedClientHintValue();
2544
2545 if (ch_ua_reduced_expected) {
2546 EXPECT_THAT(ua_reduced_client_hint, Optional(Eq("?1")));
2547 } else {
2548 EXPECT_THAT(ua_reduced_client_hint, Eq(absl::nullopt));
2549 }
2550 }
2551
2552 void CheckUserAgentString(const std::string& expected_ua_header_value) {
2553 EXPECT_THAT(GetLastUserAgentHeaderValue(),
2554 Optional(expected_ua_header_value));
2555 }
2556
Ali Beyad703d3c42021-09-03 19:43:002557 void CheckUserAgentReduced(const std::string& user_agent_value,
2558 const bool expected_user_agent_reduced) {
Ali Beyadf05102d2021-08-23 16:53:402559 // A regular expression that matches Chrome/{major_version}.{minor_version}
2560 // in the User-Agent string, where the {minor_version} is captured.
2561 static constexpr char kChromeVersionRegex[] =
2562 "Chrome/[0-9]+\\.([0-9]+\\.[0-9]+\\.[0-9]+)";
2563 // The minor version in the reduced UA string is always "0.0.0".
2564 static constexpr char kReducedMinorVersion[] = "0.0.0";
2565
Ali Beyadf05102d2021-08-23 16:53:402566 std::string minor_version;
Ali Beyad703d3c42021-09-03 19:43:002567 EXPECT_TRUE(re2::RE2::PartialMatch(user_agent_value, kChromeVersionRegex,
2568 &minor_version));
Ali Beyadf05102d2021-08-23 16:53:402569 if (expected_user_agent_reduced) {
2570 EXPECT_EQ(minor_version, kReducedMinorVersion);
2571 } else {
2572 EXPECT_NE(minor_version, kReducedMinorVersion);
2573 }
2574 }
2575
Ali Beyad703d3c42021-09-03 19:43:002576 void CheckUserAgentReduced(const bool expected_user_agent_reduced) {
2577 const absl::optional<std::string>& user_agent_header_value =
2578 GetLastUserAgentHeaderValue();
2579 EXPECT_TRUE(user_agent_header_value.has_value());
2580 CheckUserAgentReduced(*user_agent_header_value,
2581 expected_user_agent_reduced);
2582 }
2583
Ali Beyadf05102d2021-08-23 16:53:402584 void NavigateAndCheckHeaders(const GURL& url,
2585 const bool ch_ua_reduced_expected) {
2586 ui_test_utils::NavigateToURL(browser(), url);
2587
2588 CheckUaReducedClientHint(ch_ua_reduced_expected);
2589 CheckUserAgentReduced(ch_ua_reduced_expected);
2590 }
2591
2592 protected:
2593 // Returns the value of the User-Agent request header from the last sent
2594 // request, or nullopt if the header could not be read.
2595 virtual const absl::optional<std::string>& GetLastUserAgentHeaderValue() = 0;
2596 // Returns the value of the Sec-CH-UA-Reduced request header from the last
2597 // sent request, or nullopt if the header could not be read.
2598 virtual const absl::optional<std::string>&
2599 GetLastUaReducedClientHintValue() = 0;
2600
2601 private:
2602 base::test::ScopedFeatureList scoped_feature_list_;
2603};
2604
2605// Tests that the Sec-CH-UA-Reduced client hint is sent if and only if the
2606// UserAgentReduction Origin Trial token is present and valid in the response
2607// headers.
2608//
2609// The test Origin Trial token found in the test files was generated by running
2610// (in tools/origin_trials):
2611// generate_token.py https://127.0.0.1:44444 UserAgentReduction
2612// --expire-timestamp=2000000000
2613//
2614// The Origin Trial token expires in 2033. Generate a new token by then, or
2615// find a better way to re-generate a test trial token.
2616class SameOriginUaReducedOriginTrialBrowserTest
2617 : public UaReducedOriginTrialBrowserTest {
2618 public:
2619 SameOriginUaReducedOriginTrialBrowserTest() = default;
2620
2621 // The URL that was used to register the Origin Trial token.
2622 static constexpr const char kOriginUrl[] = "https://127.0.0.1:44444";
2623
Ali Beyad7417fc22021-08-06 03:09:582624 void SetUpOnMainThread() override {
Ali Beyad7417fc22021-08-06 03:09:582625 // We use a URLLoaderInterceptor, rather than the EmbeddedTestServer, since
2626 // the origin trial token in the response is associated with a fixed
2627 // origin, whereas EmbeddedTestServer serves content on a random port.
2628 url_loader_interceptor_ =
Ali Beyadf05102d2021-08-23 16:53:402629 URLLoaderInterceptor::ServeFilesFromDirectoryAtOrigin(
Ali Beyad7417fc22021-08-06 03:09:582630 "chrome/test/data/client_hints", GURL(kOriginUrl));
Ali Beyad821f4192021-08-20 16:21:282631
2632 InProcessBrowserTest::SetUpOnMainThread();
Ali Beyad7417fc22021-08-06 03:09:582633 }
2634
2635 void TearDownOnMainThread() override {
2636 url_loader_interceptor_.reset();
2637 InProcessBrowserTest::TearDownOnMainThread();
2638 }
2639
Ali Beyadf05102d2021-08-23 16:53:402640 const absl::optional<std::string>& GetLastUserAgentHeaderValue() override {
2641 std::string user_agent;
2642 CHECK(url_loader_interceptor_->GetLastRequestHeaders().GetHeader(
2643 "user-agent", &user_agent));
2644 last_user_agent_ = user_agent;
2645 return last_user_agent_;
2646 }
2647
2648 const absl::optional<std::string>& GetLastUaReducedClientHintValue()
2649 override {
2650 std::string ch_ua_reduced_header_value;
2651 if (url_loader_interceptor_->GetLastRequestHeaders().GetHeader(
2652 "sec-ch-ua-reduced", &ch_ua_reduced_header_value)) {
2653 last_ua_reduced_ch_ = ch_ua_reduced_header_value;
2654 } else {
2655 last_ua_reduced_ch_ = absl::nullopt;
2656 }
2657 return last_ua_reduced_ch_;
2658 }
2659
Ali Beyad7417fc22021-08-06 03:09:582660 GURL ua_reduced_with_valid_origin_trial_token_url() const {
2661 return GURL(base::StrCat(
2662 {kOriginUrl, "/accept_ch_ua_reduced_with_valid_origin_trial.html"}));
2663 }
2664
2665 GURL ua_reduced_with_invalid_origin_trial_token_url() const {
2666 return GURL(base::StrCat(
2667 {kOriginUrl, "/accept_ch_ua_reduced_with_invalid_origin_trial.html"}));
2668 }
2669
2670 GURL ua_reduced_with_no_origin_trial_token_url() const {
2671 return GURL(base::StrCat(
2672 {kOriginUrl, "/accept_ch_ua_reduced_with_no_origin_trial.html"}));
2673 }
2674
2675 GURL ua_reduced_missing_with_valid_origin_trial_token_url() const {
2676 return GURL(base::StrCat(
2677 {kOriginUrl, "/accept_ch_ua_reduced_missing_valid_origin_trial.html"}));
2678 }
2679
2680 GURL critical_ch_ua_reduced_with_valid_origin_trial_token_url() const {
2681 return GURL(base::StrCat(
2682 {kOriginUrl, "/critical_ch_ua_reduced_with_valid_origin_trial.html"}));
2683 }
2684
2685 GURL critical_ch_ua_reduced_with_invalid_origin_trial_token_url() const {
2686 return GURL(base::StrCat(
2687 {kOriginUrl,
2688 "/critical_ch_ua_reduced_with_invalid_origin_trial.html"}));
2689 }
2690
Ali Beyad4074a9c52021-08-17 16:15:512691 GURL accept_ch_ua_reduced_subresource_request_url() const {
2692 return GURL(base::StrCat(
2693 {kOriginUrl, "/accept_ch_ua_reduced_subresource_request.html"}));
2694 }
Ali Beyad7417fc22021-08-06 03:09:582695
Ali Beyad4074a9c52021-08-17 16:15:512696 GURL accept_ch_ua_reduced_iframe_request_url() const {
2697 return GURL(base::StrCat(
2698 {kOriginUrl, "/accept_ch_ua_reduced_iframe_request.html"}));
2699 }
2700
2701 GURL critical_ch_ua_reduced_subresource_request_url() const {
2702 return GURL(base::StrCat(
2703 {kOriginUrl, "/critical_ch_ua_reduced_subresource_request.html"}));
2704 }
2705
2706 GURL critical_ch_ua_reduced_iframe_request_url() const {
2707 return GURL(base::StrCat(
2708 {kOriginUrl, "/critical_ch_ua_reduced_iframe_request.html"}));
2709 }
2710
Ali Beyad77dba952021-08-25 20:52:582711 GURL simple_request_url() const {
2712 return GURL(base::StrCat({kOriginUrl, "/simple.html"}));
2713 }
2714
Ali Beyad4074a9c52021-08-17 16:15:512715 GURL last_request_url() const {
2716 return url_loader_interceptor_->GetLastRequestURL();
2717 }
2718
Ali Beyad7417fc22021-08-06 03:09:582719 void NavigateTwiceAndCheckHeader(const GURL& url,
2720 const bool ch_ua_reduced_expected,
2721 const bool critical_ch_ua_reduced_expected) {
Ali Beyad2618b472021-08-31 15:31:042722 base::HistogramTester histograms;
2723 int reduced_count = 0;
2724 int full_count = 0;
2725
Ali Beyad7417fc22021-08-06 03:09:582726 // If Critical-CH is set, we expect Sec-CH-UA-Reduced in the first
2727 // navigation request header. If Critical-CH is not set, we don't expect
2728 // Sec-CH-UA-Reduced in the first navigation request.
Ali Beyad2618b472021-08-31 15:31:042729 const bool first_navigation_reduced_ua =
2730 critical_ch_ua_reduced_expected && ch_ua_reduced_expected;
2731 NavigateAndCheckHeaders(url, first_navigation_reduced_ua);
2732 if (first_navigation_reduced_ua) {
2733 ++reduced_count;
2734 if (critical_ch_ua_reduced_expected) {
2735 // If Critical-CH was set, there will also be the initial navigation
2736 // that does not send the reduced UA string.
2737 ++full_count;
2738 }
2739 } else {
2740 ++full_count;
2741 }
2742 // The UserAgentStringType enum is not accessible in //chrome/browser, so
2743 // we just use the enum's integer value.
2744 histograms.ExpectBucketCount("Navigation.UserAgentStringType",
2745 /*NavigationRequest::kFullVersion*/ 0,
2746 full_count);
2747 histograms.ExpectBucketCount("Navigation.UserAgentStringType",
2748 /*NavigationRequest::kReducedVersion*/ 1,
2749 reduced_count);
Ali Beyad7417fc22021-08-06 03:09:582750
2751 // Regardless of the Critical-CH setting, we expect the Sec-CH-UA-Reduced
2752 // client hint sent on the second request, if Sec-CH-UA-Reduced is set and
2753 // the Origin Trial token is valid.
Ali Beyad4074a9c52021-08-17 16:15:512754 NavigateAndCheckHeaders(url, ch_ua_reduced_expected);
Ali Beyad2618b472021-08-31 15:31:042755 if (ch_ua_reduced_expected) {
2756 ++reduced_count;
2757 } else {
2758 ++full_count;
2759 }
2760 histograms.ExpectBucketCount("Navigation.UserAgentStringType",
2761 /*NavigationRequest::kFullVersion*/ 0,
2762 full_count);
2763 histograms.ExpectBucketCount("Navigation.UserAgentStringType",
2764 /*NavigationRequest::kReducedVersion*/ 1,
2765 reduced_count);
Ali Beyad7417fc22021-08-06 03:09:582766 }
2767
2768 private:
Ali Beyadf05102d2021-08-23 16:53:402769 std::unique_ptr<URLLoaderInterceptor> url_loader_interceptor_;
2770 absl::optional<std::string> last_user_agent_;
2771 absl::optional<std::string> last_ua_reduced_ch_;
Ali Beyad7417fc22021-08-06 03:09:582772};
2773
Ali Beyadf05102d2021-08-23 16:53:402774constexpr const char SameOriginUaReducedOriginTrialBrowserTest::kOriginUrl[];
Ali Beyad7417fc22021-08-06 03:09:582775
Ali Beyadf05102d2021-08-23 16:53:402776IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad7417fc22021-08-06 03:09:582777 AcceptChUaReducedWithValidOriginTrialToken) {
2778 NavigateTwiceAndCheckHeader(ua_reduced_with_valid_origin_trial_token_url(),
2779 /*ch_ua_reduced_expected=*/true,
2780 /*critical_ch_ua_reduced_expected=*/false);
Ali Beyad703d3c42021-09-03 19:43:002781
2782 // The Origin Trial token is valid, so we expect the reduced UA values in the
2783 // Javascript getters as well.
2784 content::WebContents* web_contents =
2785 browser()->tab_strip_model()->GetActiveWebContents();
2786 CheckUserAgentReduced(
2787 content::EvalJs(web_contents, "navigator.userAgent").ExtractString(),
2788 /*expected_user_agent_reduced=*/true);
2789 CheckUserAgentReduced(
2790 content::EvalJs(web_contents, "navigator.appVersion").ExtractString(),
2791 /*expected_user_agent_reduced=*/true);
2792 // Instead of checking all platform types, just check one that has a
2793 // difference between the full and reduced versions.
2794#if defined(OS_ANDROID)
2795 EXPECT_EQ("Linux x86_64",
2796 content::EvalJs(web_contents, "navigator.platform"));
2797#endif
Ali Beyad7417fc22021-08-06 03:09:582798}
2799
Ali Beyadf05102d2021-08-23 16:53:402800IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad7417fc22021-08-06 03:09:582801 AcceptChUaReducedWithInvalidOriginTrialToken) {
2802 // The response contained Sec-CH-UA-Reduced in the Accept-CH header, but the
2803 // origin trial token is invalid.
2804 NavigateTwiceAndCheckHeader(ua_reduced_with_invalid_origin_trial_token_url(),
2805 /*ch_ua_reduced_expected=*/false,
2806 /*critical_ch_ua_reduced_expected=*/false);
Ali Beyad703d3c42021-09-03 19:43:002807
2808 // The Origin Trial token is invalid, so we expect the full UA values in the
2809 // Javascript getters.
2810 content::WebContents* web_contents =
2811 browser()->tab_strip_model()->GetActiveWebContents();
2812 CheckUserAgentReduced(
2813 content::EvalJs(web_contents, "navigator.userAgent").ExtractString(),
2814 /*expected_user_agent_reduced=*/false);
2815 CheckUserAgentReduced(
2816 content::EvalJs(web_contents, "navigator.appVersion").ExtractString(),
2817 /*expected_user_agent_reduced=*/false);
2818 // Instead of checking all platform types, just check one that has a
2819 // difference between the full and reduced versions.
2820#if defined(OS_ANDROID)
2821 EXPECT_NE("Linux x86_64",
2822 content::EvalJs(web_contents, "navigator.platform"));
2823#endif
Ali Beyad7417fc22021-08-06 03:09:582824}
2825
Ali Beyadf05102d2021-08-23 16:53:402826IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad7417fc22021-08-06 03:09:582827 AcceptChUaReducedWithNoOriginTrialToken) {
2828 // The response contained Sec-CH-UA-Reduced in the Accept-CH header, but the
2829 // origin trial token is not present.
2830 NavigateTwiceAndCheckHeader(ua_reduced_with_no_origin_trial_token_url(),
2831 /*ch_ua_reduced_expected=*/false,
2832 /*critical_ch_ua_reduced_expected=*/false);
2833}
2834
Ali Beyadf05102d2021-08-23 16:53:402835IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad7417fc22021-08-06 03:09:582836 NoAcceptChUaReducedWithValidOriginTrialToken) {
2837 // The response contained a valid Origin Trial token, but no Sec-CH-UA-Reduced
2838 // in the Accept-CH header.
2839 NavigateTwiceAndCheckHeader(
2840 ua_reduced_missing_with_valid_origin_trial_token_url(),
2841 /*ch_ua_reduced_expected=*/false,
2842 /*critical_ch_ua_reduced_expected=*/false);
2843}
2844
Ali Beyadf05102d2021-08-23 16:53:402845IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad821f4192021-08-20 16:21:282846 CriticalChUaReducedWithValidOriginTrialToken) {
Ali Beyad7417fc22021-08-06 03:09:582847 // The initial navigation also contains the Critical-CH header, so the
2848 // Sec-CH-UA-Reduced header should be set after the first navigation.
2849 NavigateTwiceAndCheckHeader(
2850 critical_ch_ua_reduced_with_valid_origin_trial_token_url(),
2851 /*ch_ua_reduced_expected=*/true,
2852 /*critical_ch_ua_reduced_expected=*/true);
2853}
2854
Ali Beyadf05102d2021-08-23 16:53:402855IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad7417fc22021-08-06 03:09:582856 CriticalChUaReducedWithInvalidOriginTrialToken) {
2857 // The Origin Trial token is invalid, so the Critical-CH should not have
2858 // resulted in the Sec-CH-UA-Reduced header being sent.
2859 NavigateTwiceAndCheckHeader(
2860 critical_ch_ua_reduced_with_invalid_origin_trial_token_url(),
2861 /*ch_ua_reduced_expected=*/false,
2862 /*critical_ch_ua_reduced_expected=*/false);
2863}
2864
Ali Beyadf05102d2021-08-23 16:53:402865IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad4074a9c52021-08-17 16:15:512866 IframeRequestUaReducedWithValidOriginTrialToken) {
2867 // The last resource request processed for this navigation will be an embedded
2868 // iframe request. Since Accept-CH has Sec-CH-UA-Reduced set on the top-level
2869 // level frame's response header, along with a valid origin trial token, the
2870 // iframe request should send Sec-CH-UA-Reduced and the reduced UA string in
2871 // the request header.
2872 NavigateAndCheckHeaders(accept_ch_ua_reduced_iframe_request_url(),
2873 /*ch_ua_reduced_expected=*/true);
2874 // Make sure the last intercepted URL was the request for the embedded iframe.
2875 EXPECT_EQ(last_request_url().path(), "/simple.html");
2876}
2877
2878IN_PROC_BROWSER_TEST_F(
Ali Beyadf05102d2021-08-23 16:53:402879 SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad4074a9c52021-08-17 16:15:512880 IframeRequestUaReducedWithValidOriginTrialTokenAndCriticalCH) {
2881 // The last resource request processed for this navigation will be an embedded
2882 // iframe request. Since Accept-CH has Sec-CH-UA-Reduced set on the top-level
2883 // level frame's response header, along with a valid origin trial token, the
2884 // iframe request should send Sec-CH-UA-Reduced and the reduced UA string in
2885 // the request header.
2886 NavigateAndCheckHeaders(critical_ch_ua_reduced_iframe_request_url(),
2887 /*ch_ua_reduced_expected=*/true);
2888 // Make sure the last intercepted URL was the request for the embedded iframe.
2889 EXPECT_EQ(last_request_url().path(), "/simple.html");
2890}
2891
Ali Beyadf05102d2021-08-23 16:53:402892IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad4074a9c52021-08-17 16:15:512893 SubresourceRequestUaReducedWithValidOriginTrialToken) {
2894 // The last resource request processed for this navigation will be a
2895 // subresource request for the stylesheet. Since Accept-CH has
2896 // Sec-CH-UA-Reduced set on the top-level level frame's response header, along
2897 // with a valid origin trial token, the subresource request should send
2898 // Sec-CH-UA-Reduced and the reduced UA string in the request header.
2899 NavigateAndCheckHeaders(accept_ch_ua_reduced_subresource_request_url(),
2900 /*ch_ua_reduced_expected=*/true);
2901 // Make sure the last intercepted URL was the subresource request for the
2902 // embedded stylesheet.
2903 EXPECT_EQ(last_request_url().path(), "/style.css");
2904}
2905
2906IN_PROC_BROWSER_TEST_F(
Ali Beyadf05102d2021-08-23 16:53:402907 SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad4074a9c52021-08-17 16:15:512908 SubresourceRequestUaReducedWithValidOriginTrialTokenAndCriticalCH) {
2909 // The last resource request processed for this navigation will be a
2910 // subresource request for the stylesheet. Since Accept-CH has
2911 // Sec-CH-UA-Reduced set on the top-level level frame's response header, along
2912 // with a valid origin trial token, the subresource request should send
2913 // Sec-CH-UA-Reduced and the reduced UA string in the request header.
2914 NavigateAndCheckHeaders(critical_ch_ua_reduced_subresource_request_url(),
2915 /*ch_ua_reduced_expected=*/true);
2916 // Make sure the last intercepted URL was the subresource request for the
2917 // embedded stylesheet.
2918 EXPECT_EQ(last_request_url().path(), "/style.css");
2919}
2920
Ali Beyadf05102d2021-08-23 16:53:402921IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad4074a9c52021-08-17 16:15:512922 UserAgentOverrideAcceptChUaReduced) {
Ali Beyad2618b472021-08-31 15:31:042923 base::HistogramTester histograms;
Ali Beyad4074a9c52021-08-17 16:15:512924 const std::string user_agent_override = "foo";
2925 SetUserAgentOverride(user_agent_override);
2926
2927 const GURL url = ua_reduced_with_valid_origin_trial_token_url();
2928 // First navigation to set the client hints in the response.
2929 ui_test_utils::NavigateToURL(browser(), url);
2930 // Second navigation has the Sec-CH-UA-Reduced client hint stored from the
2931 // first navigation's response.
2932 ui_test_utils::NavigateToURL(browser(), url);
2933
2934 // Since the UA override was set, the UA client hints are *not* added to the
2935 // request.
2936 CheckUaReducedClientHint(/*ch_ua_reduced_expected=*/false);
2937 // Make sure the overridden UA string is the one sent.
2938 CheckUserAgentString(user_agent_override);
Ali Beyad2618b472021-08-31 15:31:042939
2940 // The UserAgentStringType enum is not accessible in //chrome/browser, so
2941 // we just use the enum's integer value.
2942 histograms.ExpectBucketCount("Navigation.UserAgentStringType",
2943 /*NavigationRequest::kOverridden*/ 2, 2);
Ali Beyad4074a9c52021-08-17 16:15:512944}
2945
Ali Beyadf05102d2021-08-23 16:53:402946IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad4074a9c52021-08-17 16:15:512947 UserAgentOverrideSubresourceRequest) {
2948 const std::string user_agent_override = "foo";
2949 SetUserAgentOverride(user_agent_override);
2950
2951 const GURL url = accept_ch_ua_reduced_subresource_request_url();
2952 // First navigation to set the client hints in the response.
2953 ui_test_utils::NavigateToURL(browser(), url);
2954 // Second navigation has the Sec-CH-UA-Reduced client hint stored from the
2955 // first navigation's response.
2956 ui_test_utils::NavigateToURL(browser(), url);
2957
2958 // Since the UA override was set, the UA client hints are *not* added to the
2959 // request.
2960 CheckUaReducedClientHint(/*ch_ua_reduced_expected=*/false);
2961 // Make sure the overridden UA string is the one sent.
2962 CheckUserAgentString(user_agent_override);
2963}
2964
Ali Beyadf05102d2021-08-23 16:53:402965IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad4074a9c52021-08-17 16:15:512966 UserAgentOverrideIframeRequest) {
2967 const std::string user_agent_override = "foo";
2968 SetUserAgentOverride(user_agent_override);
2969
2970 const GURL url = accept_ch_ua_reduced_iframe_request_url();
2971 // First navigation to set the client hints in the response.
2972 ui_test_utils::NavigateToURL(browser(), url);
2973 // Second navigation has the Sec-CH-UA-Reduced client hint stored from the
2974 // first navigation's response.
2975 ui_test_utils::NavigateToURL(browser(), url);
2976
2977 // Since the UA override was set, the UA client hints are *not* added to the
2978 // request.
2979 CheckUaReducedClientHint(/*ch_ua_reduced_expected=*/false);
2980 // Make sure the overridden UA string is the one sent.
2981 CheckUserAgentString(user_agent_override);
2982}
2983
Ali Beyad77dba952021-08-25 20:52:582984IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
2985 NoAcceptCHRemovesSecChUaReducedFromStorage) {
2986 // The first navigation sets Sec-CH-UA-Reduced in the client hints storage for
2987 // the origin.
2988 NavigateAndCheckHeaders(ua_reduced_with_valid_origin_trial_token_url(),
2989 /*ch_ua_reduced_expected=*/false);
2990 // The second navigation doesn't contain an Accept-CH header in the response,
2991 // so Sec-CH-UA-Reduced is removed from the storage.
2992 NavigateAndCheckHeaders(simple_request_url(),
2993 /*ch_ua_reduced_expected=*/true);
2994 // The third navigation doesn't contain a Sec-CH-UA-Reduced in the request
2995 // header because the second navigation caused it to get removed.
2996 NavigateAndCheckHeaders(ua_reduced_with_valid_origin_trial_token_url(),
2997 /*ch_ua_reduced_expected=*/false);
2998}
2999
Ali Beyadf05102d2021-08-23 16:53:403000// Tests that the Sec-CH-UA-Reduced client hint and the reduced User-Agent
3001// string are sent on request headers for third-party embedded resources if the
3002// Origin Trial token from the top-level frame is valid and the permissions
3003// policy allows it.
3004class ThirdPartyUaReducedOriginTrialBrowserTest
3005 : public UaReducedOriginTrialBrowserTest {
3006 public:
3007 ThirdPartyUaReducedOriginTrialBrowserTest()
3008 : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
3009 https_server_.ServeFilesFromSourceDirectory(
3010 "chrome/test/data/client_hints");
3011 https_server_.RegisterRequestMonitor(base::BindRepeating(
3012 &ThirdPartyUaReducedOriginTrialBrowserTest::MonitorResourceRequest,
3013 base::Unretained(this)));
3014 EXPECT_TRUE(https_server_.Start());
3015 }
3016
3017 // The URL that was used to register the Origin Trial token.
3018 static constexpr char kFirstPartyOriginUrl[] = "https://my-site.com:44444";
3019
3020 void SetUpOnMainThread() override {
3021 InProcessBrowserTest::SetUpOnMainThread();
3022
3023 // We use a URLLoaderInterceptor, rather than the EmbeddedTestServer, since
3024 // the origin trial token in the response is associated with a fixed
3025 // origin, whereas EmbeddedTestServer serves content on a random port.
3026 url_loader_interceptor_ =
3027 std::make_unique<URLLoaderInterceptor>(base::BindRepeating(
3028 &ThirdPartyUaReducedOriginTrialBrowserTest::InterceptRequest,
3029 base::Unretained(this)));
3030 }
3031
3032 void TearDownOnMainThread() override {
3033 url_loader_interceptor_.reset();
3034 InProcessBrowserTest::TearDownOnMainThread();
3035 }
3036
3037 GURL accept_ch_ua_reduced_cross_origin_iframe_request_url() const {
3038 return GURL(base::StrCat(
3039 {kFirstPartyOriginUrl,
3040 "/accept_ch_ua_reuced_cross_origin_iframe_request.html"}));
3041 }
3042
3043 GURL accept_ch_ua_reduced_cross_origin_subresource_request_url() const {
3044 return GURL(base::StrCat(
3045 {kFirstPartyOriginUrl,
3046 "/accept_ch_ua_reuced_cross_origin_subresource_request.html"}));
3047 }
3048
3049 protected:
3050 const absl::optional<std::string>& GetLastUserAgentHeaderValue() override {
3051 base::AutoLock lock(last_request_lock_);
3052 return last_user_agent_;
3053 }
3054
3055 const absl::optional<std::string>& GetLastUaReducedClientHintValue()
3056 override {
3057 base::AutoLock lock(last_request_lock_);
3058 return last_sec_ch_ua_reduced_;
3059 }
3060
3061 const absl::optional<GURL>& GetLastRequestedURL() {
3062 base::AutoLock lock(last_request_lock_);
3063 return last_requested_url_;
3064 }
3065
3066 void SetUaReducedPermissionsPolicy(const std::string& value) {
3067 ua_reduced_permissions_policy_header_value_ = value;
3068 }
3069
3070 void SetValidOTToken(const bool valid_ot_token) {
3071 valid_ot_token_ = valid_ot_token;
3072 }
3073
3074 GURL GetServerOrigin() const { return https_server_.GetOrigin().GetURL(); }
3075
3076 private:
3077 // URLLoaderInterceptor callback
3078 bool InterceptRequest(URLLoaderInterceptor::RequestParams* params) {
3079 if (params->url_request.url.GetOrigin() != GURL(kFirstPartyOriginUrl)) {
3080 return false;
3081 }
3082 if (params->url_request.url.path() !=
3083 "/accept_ch_ua_reuced_cross_origin_iframe_request.html" &&
3084 params->url_request.url.path() !=
3085 "/accept_ch_ua_reuced_cross_origin_subresource_request.html") {
3086 return false;
3087 }
3088
3089 // Generated by running (in tools/origin_trials):
3090 // generate_token.py https://my-site.com:44444 UserAgentReduction
3091 // --expire-timestamp=2000000000
3092 //
3093 // The Origin Trial token expires in 2033. Generate a new token by then, or
3094 // find a better way to re-generate a test trial token.
3095 static constexpr const char kOriginTrialToken[] =
3096 "AziP2Iyo74PHkJAVVXJ1NBAyZd+"
3097 "GZFmTqpFtug4Wazsj5rQPFeCFjjZpiEYb086vZzi48lF1ydynMj/"
3098 "oLqqLXgEAAABeeyJvcmlnaW4iOiAiaHR0cHM6Ly9teS1zaXRlLmNvbTo0NDQ0NCIsICJmZ"
3099 "WF0dXJlIjogIlVzZXJBZ2VudFJlZHVjdGlvbiIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ="
3100 "=";
3101
3102 // Construct and send the response.
3103 std::string headers =
3104 "HTTP/1.1 200 OK\nContent-Type: text/html; charset=utf-8\n";
3105 base::StrAppend(&headers, {"Accept-CH: Sec-CH-UA-Reduced\n"});
3106 base::StrAppend(&headers,
3107 {"Permissions-Policy: ch-ua-reduced=",
3108 ua_reduced_permissions_policy_header_value_, "\n"});
3109 base::StrAppend(&headers, {"Origin-Trial: ",
3110 valid_ot_token_ ? kOriginTrialToken
3111 : "invalid-origin-trial-token",
3112 "\n\n"});
3113 std::string body = "<html><head>";
3114 if (params->url_request.url.path() ==
3115 "/accept_ch_ua_reuced_cross_origin_subresource_request.html") {
3116 base::StrAppend(&body, {BuildSubresourceHTML()});
3117 }
3118 base::StrAppend(&body, {"</head><body>"});
3119 if (params->url_request.url.path() ==
3120 "/accept_ch_ua_reuced_cross_origin_iframe_request.html") {
3121 base::StrAppend(&body, {BuildIframeHTML()});
3122 }
3123 base::StrAppend(&body, {"</body></html>"});
3124 URLLoaderInterceptor::WriteResponse(headers, body, params->client.get());
3125 return true;
3126 }
3127
3128 void SetLastUserAgent(const std::string* value) {
3129 base::AutoLock lock(last_request_lock_);
3130 if (value != nullptr) {
3131 last_user_agent_ = *value;
3132 } else {
3133 NOTREACHED();
3134 }
3135 }
3136
3137 void SetLastSecChUaReduced(const std::string* value) {
3138 base::AutoLock lock(last_request_lock_);
3139 if (value != nullptr) {
3140 last_sec_ch_ua_reduced_ = *value;
3141 } else {
3142 last_sec_ch_ua_reduced_ = absl::nullopt;
3143 }
3144 }
3145
3146 void SetLastRequestedURL(const GURL& url) {
3147 base::AutoLock lock(last_request_lock_);
3148 last_requested_url_ = url;
3149 }
3150
3151 // Called by |https_server_|.
3152 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
3153 SetLastRequestedURL(request.GetURL());
3154 auto it = request.headers.find("user-agent");
3155 SetLastUserAgent(it != request.headers.end() ? &it->second : nullptr);
3156 it = request.headers.find("sec-ch-ua-reduced");
3157 SetLastSecChUaReduced(it != request.headers.end() ? &it->second : nullptr);
3158 }
3159
3160 std::string BuildIframeHTML() {
3161 std::string html = "<iframe src=\"";
3162 base::StrAppend(
3163 &html, {https_server_.GetURL("/simple.html").spec(), "\"></iframe>"});
3164 return html;
3165 }
3166
3167 std::string BuildSubresourceHTML() {
3168 std::string html = "<link rel=\"stylesheet\" href=\"";
3169 base::StrAppend(&html,
3170 {https_server_.GetURL("/style.css").spec(), "\"></link>"});
3171 return html;
3172 }
3173
3174 std::unique_ptr<URLLoaderInterceptor> url_loader_interceptor_;
3175 net::EmbeddedTestServer https_server_;
3176 std::string ua_reduced_permissions_policy_header_value_;
3177 bool valid_ot_token_ = true;
3178 base::Lock last_request_lock_;
3179 absl::optional<std::string> last_user_agent_ GUARDED_BY(last_request_lock_);
3180 absl::optional<std::string> last_sec_ch_ua_reduced_
3181 GUARDED_BY(last_request_lock_);
3182 absl::optional<GURL> last_requested_url_ GUARDED_BY(last_request_lock_);
3183};
3184
3185constexpr const char
3186 ThirdPartyUaReducedOriginTrialBrowserTest::kFirstPartyOriginUrl[];
3187
3188IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3189 ThirdPartyIframeUaReducedWildcardPolicy) {
3190 SetUaReducedPermissionsPolicy("*"); // Allow all third-party sites.
3191
3192 NavigateAndCheckHeaders(
3193 accept_ch_ua_reduced_cross_origin_iframe_request_url(),
3194 /*ch_ua_reduced_expected=*/true);
3195
3196 // Make sure the last intercepted URL was the request for the embedded iframe.
3197 EXPECT_EQ(GetLastRequestedURL()->path(), "/simple.html");
3198}
3199
3200IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3201 ThirdPartySubresourceUaReducedWithWildcardPolicy) {
3202 SetUaReducedPermissionsPolicy("*"); // Allow all third-party sites.
3203
3204 NavigateAndCheckHeaders(
3205 accept_ch_ua_reduced_cross_origin_subresource_request_url(),
3206 /*ch_ua_reduced_expected=*/true);
3207
3208 // Make sure the last intercepted URL was the request for the embedded iframe.
3209 EXPECT_EQ(GetLastRequestedURL()->path(), "/style.css");
3210}
3211
3212IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3213 ThirdPartyIframeUaReducedSpecificPolicy) {
3214 std::string policy = "(self \"";
3215 base::StrAppend(&policy, {GetServerOrigin().spec(), "\")"});
3216 SetUaReducedPermissionsPolicy(policy); // Allow our third-party site only.
3217
3218 NavigateAndCheckHeaders(
3219 accept_ch_ua_reduced_cross_origin_iframe_request_url(),
3220 /*ch_ua_reduced_expected=*/true);
3221
3222 // Make sure the last intercepted URL was the request for the embedded iframe.
3223 EXPECT_EQ(GetLastRequestedURL()->path(), "/simple.html");
3224}
3225
3226IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3227 ThirdPartySubresourceUaReducedSpecificPolicy) {
3228 std::string policy = "(self \"";
3229 base::StrAppend(&policy, {GetServerOrigin().spec(), "\")"});
3230 SetUaReducedPermissionsPolicy(policy); // Allow our third-party site only.
3231
3232 NavigateAndCheckHeaders(
3233 accept_ch_ua_reduced_cross_origin_subresource_request_url(),
3234 /*ch_ua_reduced_expected=*/true);
3235
3236 // Make sure the last intercepted URL was the request for the embedded iframe.
3237 EXPECT_EQ(GetLastRequestedURL()->path(), "/style.css");
3238}
3239
3240IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3241 ThirdPartyIframeUaReducedPolicyNotAllowed) {
3242 SetUaReducedPermissionsPolicy(
3243 "(self)"); // Only allow self, no third-party sites.
3244
3245 NavigateAndCheckHeaders(
3246 accept_ch_ua_reduced_cross_origin_iframe_request_url(),
3247 /*ch_ua_reduced_expected=*/false);
3248
3249 // Make sure the last intercepted URL was the request for the embedded iframe.
3250 EXPECT_EQ(GetLastRequestedURL()->path(), "/simple.html");
3251}
3252
3253IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3254 ThirdPartySubresourceUaReducedPolicyNotAllowed) {
3255 SetUaReducedPermissionsPolicy(
3256 "(self)"); // Only allow self, no third-party sites.
3257
3258 NavigateAndCheckHeaders(
3259 accept_ch_ua_reduced_cross_origin_subresource_request_url(),
3260 /*ch_ua_reduced_expected=*/false);
3261
3262 // Make sure the last intercepted URL was the request for the embedded iframe.
3263 EXPECT_EQ(GetLastRequestedURL()->path(), "/style.css");
3264}
3265
3266IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3267 ThirdPartyIframeUaReducedInvalidOriginTrialToken) {
3268 SetUaReducedPermissionsPolicy("*"); // Allow all third-party sites.
3269 SetValidOTToken(false); // Origin Trial Token is invalid.
3270
3271 NavigateAndCheckHeaders(
3272 accept_ch_ua_reduced_cross_origin_iframe_request_url(),
3273 /*ch_ua_reduced_expected=*/false);
3274
3275 // Make sure the last intercepted URL was the request for the embedded iframe.
3276 EXPECT_EQ(GetLastRequestedURL()->path(), "/simple.html");
3277}
3278
3279IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3280 ThirdPartySubresourceUaReducedInvalidOriginTrialToken) {
3281 SetUaReducedPermissionsPolicy("*"); // Allow all third-party sites.
3282 SetValidOTToken(false); // Origin Trial Token is invalid.
3283
3284 NavigateAndCheckHeaders(
3285 accept_ch_ua_reduced_cross_origin_subresource_request_url(),
3286 /*ch_ua_reduced_expected=*/false);
3287
3288 // Make sure the last intercepted URL was the request for the embedded iframe.
3289 EXPECT_EQ(GetLastRequestedURL()->path(), "/style.css");
Ali Beyad7417fc22021-08-06 03:09:583290}