blob: de8c7a74999ee567bf9aab2f258f793e0a3cb30e [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
Ari Chivukulae399ab42021-09-15 22:20:2876constexpr unsigned expected_client_hints_number = 13u;
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_++;
Ari Chivukula51baf9b2021-09-13 20:01:49101 for (const auto& elem : network::GetClientHintToNameMap()) {
102 const auto& header = elem.second;
103 if (params->url_request.headers.HasHeader(header))
Tarun Bansalf9cf9892018-04-06 04:38:01104 client_hints_count_seen_++;
Tarun Bansal5c28afb2018-03-17 02:55:20105 }
Jay Civelli1ff872d2018-03-09 21:52:16106 return false;
107 }
Tarun Bansal229647bd002018-02-27 17:33:36108
Jay Civelli1ff872d2018-03-09 21:52:16109 GURL intercepted_url_;
110
111 size_t request_count_seen_ = 0u;
112
113 size_t client_hints_count_seen_ = 0u;
114
Ali Beyadf05102d2021-08-23 16:53:40115 URLLoaderInterceptor interceptor_;
Jay Civelli1ff872d2018-03-09 21:52:16116
117 DISALLOW_COPY_AND_ASSIGN(ThirdPartyURLLoaderInterceptor);
Tarun Bansal229647bd002018-02-27 17:33:36118};
119
Tarun Bansal62efba12018-05-04 22:58:35120// Returns true only if |header_value| satisfies ABNF: 1*DIGIT [ "." 1*DIGIT ]
121bool IsSimilarToDoubleABNF(const std::string& header_value) {
122 if (header_value.empty())
123 return false;
124 char first_char = header_value.at(0);
125 if (!isdigit(first_char))
126 return false;
127
128 bool period_found = false;
129 bool digit_found_after_period = false;
130 for (char ch : header_value) {
131 if (isdigit(ch)) {
132 if (period_found) {
133 digit_found_after_period = true;
134 }
135 continue;
136 }
137 if (ch == '.') {
138 if (period_found)
139 return false;
140 period_found = true;
141 continue;
142 }
143 return false;
144 }
145 if (period_found)
146 return digit_found_after_period;
147 return true;
148}
149
150// Returns true only if |header_value| satisfies ABNF: 1*DIGIT
151bool IsSimilarToIntABNF(const std::string& header_value) {
152 if (header_value.empty())
153 return false;
154
155 for (char ch : header_value) {
156 if (!isdigit(ch))
157 return false;
158 }
159 return true;
160}
161
Tarun Bansal229647bd002018-02-27 17:33:36162} // namespace
Tarun Bansal0b8b7afd2017-08-25 03:52:16163
Ali Beyad0a4a3d712021-07-19 17:07:40164class ClientHintsBrowserTest : public InProcessBrowserTest,
Tarun Bansal9a7051f2018-07-10 18:30:05165 public testing::WithParamInterface<bool> {
Tarun Bansal0b8b7afd2017-08-25 03:52:16166 public:
167 ClientHintsBrowserTest()
Mikel Astiz2de748d2019-11-16 10:39:36168 : http_server_(net::EmbeddedTestServer::TYPE_HTTP),
Tarun Bansal3b330b02017-11-09 19:03:14169 https_server_(net::EmbeddedTestServer::TYPE_HTTPS),
Tarun Bansal345418632018-06-29 11:07:04170 https_cross_origin_server_(net::EmbeddedTestServer::TYPE_HTTPS),
Tarun Bansal229647bd002018-02-27 17:33:36171 expect_client_hints_on_main_frame_(false),
172 expect_client_hints_on_subresources_(false),
Mike West2fddeeb72019-02-15 11:29:48173 count_user_agent_hint_headers_seen_(0),
Maks Orlovich5dcc99c2020-02-13 19:07:46174 count_ua_mobile_client_hints_headers_seen_(0),
Aaron Tagliaboschiec5bce62021-06-24 18:50:09175 count_ua_platform_client_hints_headers_seen_(0),
Tarun Bansal229647bd002018-02-27 17:33:36176 count_client_hints_headers_seen_(0),
177 request_interceptor_(nullptr) {
Tarun Bansal3b330b02017-11-09 19:03:14178 http_server_.ServeFilesFromSourceDirectory("chrome/test/data/client_hints");
Tarun Bansal0b8b7afd2017-08-25 03:52:16179 https_server_.ServeFilesFromSourceDirectory(
180 "chrome/test/data/client_hints");
Tarun Bansal345418632018-06-29 11:07:04181 https_cross_origin_server_.ServeFilesFromSourceDirectory(
182 "chrome/test/data/client_hints");
Tarun Bansal1965b042017-09-07 04:59:19183
Tarun Bansal3b330b02017-11-09 19:03:14184 http_server_.RegisterRequestMonitor(
Tarun Bansal345418632018-06-29 11:07:04185 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
186 base::Unretained(this)));
Tarun Bansal1965b042017-09-07 04:59:19187 https_server_.RegisterRequestMonitor(
Tarun Bansal345418632018-06-29 11:07:04188 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
189 base::Unretained(this)));
190 https_cross_origin_server_.RegisterRequestMonitor(
191 base::BindRepeating(&ClientHintsBrowserTest::MonitorResourceRequest,
192 base::Unretained(this)));
Tarun Bansal293a7b6c2018-12-05 17:41:12193 https_cross_origin_server_.RegisterRequestHandler(
194 base::BindRepeating(&ClientHintsBrowserTest::RequestHandlerToRedirect,
195 base::Unretained(this)));
Tarun Bansal345418632018-06-29 11:07:04196 https_server_.RegisterRequestHandler(base::BindRepeating(
197 &ClientHintsBrowserTest::RequestHandlerToFetchCrossOriginIframe,
198 base::Unretained(this)));
Tarun Bansal1965b042017-09-07 04:59:19199
Tarun Bansal3b330b02017-11-09 19:03:14200 EXPECT_TRUE(http_server_.Start());
Tarun Bansal0b8b7afd2017-08-25 03:52:16201 EXPECT_TRUE(https_server_.Start());
Tarun Bansal345418632018-06-29 11:07:04202 EXPECT_TRUE(https_cross_origin_server_.Start());
203
204 EXPECT_NE(https_server_.base_url(), https_cross_origin_server_.base_url());
Tarun Bansal0b8b7afd2017-08-25 03:52:16205
Tarun Bansal3b330b02017-11-09 19:03:14206 accept_ch_with_lifetime_http_local_url_ =
207 http_server_.GetURL("/accept_ch_with_lifetime.html");
Tarun Bansal9a7051f2018-07-10 18:30:05208 http_equiv_accept_ch_with_lifetime_http_local_url_ =
209 http_server_.GetURL("/http_equiv_accept_ch_with_lifetime.html");
Tarun Bansal3b330b02017-11-09 19:03:14210 EXPECT_TRUE(accept_ch_with_lifetime_http_local_url_.SchemeIsHTTPOrHTTPS());
211 EXPECT_FALSE(
212 accept_ch_with_lifetime_http_local_url_.SchemeIsCryptographic());
213
Tarun Bansal1965b042017-09-07 04:59:19214 accept_ch_with_lifetime_url_ =
215 https_server_.GetURL("/accept_ch_with_lifetime.html");
Tarun Bansal73502f92019-04-16 21:21:19216 accept_ch_with_short_lifetime_url_ =
217 https_server_.GetURL("/accept_ch_with_short_lifetime.html");
Tarun Bansal0b8b7afd2017-08-25 03:52:16218
Tarun Bansal1965b042017-09-07 04:59:19219 accept_ch_without_lifetime_url_ =
220 https_server_.GetURL("/accept_ch_without_lifetime.html");
221 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsHTTPOrHTTPS());
222 EXPECT_TRUE(accept_ch_with_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal9a7051f2018-07-10 18:30:05223 http_equiv_accept_ch_without_lifetime_url_ =
224 https_server_.GetURL("/http_equiv_accept_ch_without_lifetime.html");
Tarun Bansal1965b042017-09-07 04:59:19225
226 without_accept_ch_without_lifetime_url_ =
227 https_server_.GetURL("/without_accept_ch_without_lifetime.html");
228 EXPECT_TRUE(without_accept_ch_without_lifetime_url_.SchemeIsHTTPOrHTTPS());
229 EXPECT_TRUE(
230 without_accept_ch_without_lifetime_url_.SchemeIsCryptographic());
Tarun Bansal3b330b02017-11-09 19:03:14231
232 without_accept_ch_without_lifetime_local_url_ =
233 http_server_.GetURL("/without_accept_ch_without_lifetime.html");
234 EXPECT_TRUE(
235 without_accept_ch_without_lifetime_local_url_.SchemeIsHTTPOrHTTPS());
236 EXPECT_FALSE(
237 without_accept_ch_without_lifetime_local_url_.SchemeIsCryptographic());
Tarun Bansaladd5e1812018-02-09 19:07:58238
239 without_accept_ch_without_lifetime_img_localhost_ = https_server_.GetURL(
240 "/without_accept_ch_without_lifetime_img_localhost.html");
241 without_accept_ch_without_lifetime_img_foo_com_ = https_server_.GetURL(
242 "/without_accept_ch_without_lifetime_img_foo_com.html");
243 accept_ch_without_lifetime_with_iframe_url_ =
244 https_server_.GetURL("/accept_ch_without_lifetime_with_iframe.html");
Tarun Bansal9a7051f2018-07-10 18:30:05245 http_equiv_accept_ch_without_lifetime_with_iframe_url_ =
246 https_server_.GetURL(
247 "/http_equiv_accept_ch_without_lifetime_with_iframe.html");
Tarun Bansal62cc3542018-06-27 23:53:30248 accept_ch_without_lifetime_with_subresource_url_ = https_server_.GetURL(
249 "/accept_ch_without_lifetime_with_subresource.html");
Tarun Bansal9a7051f2018-07-10 18:30:05250 http_equiv_accept_ch_without_lifetime_with_subresource_url_ =
251 https_server_.GetURL(
252 "/http_equiv_accept_ch_without_lifetime_with_subresource.html");
Tarun Bansal62cc3542018-06-27 23:53:30253 accept_ch_without_lifetime_with_subresource_iframe_url_ =
254 https_server_.GetURL(
255 "/accept_ch_without_lifetime_with_subresource_iframe.html");
Tarun Bansal9a7051f2018-07-10 18:30:05256 http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_ =
257 https_server_.GetURL(
258 "/http_equiv_accept_ch_without_lifetime_with_subresource_iframe."
259 "html");
Tarun Bansal229647bd002018-02-27 17:33:36260 accept_ch_without_lifetime_img_localhost_ =
261 https_server_.GetURL("/accept_ch_without_lifetime_img_localhost.html");
Tarun Bansal9a7051f2018-07-10 18:30:05262 http_equiv_accept_ch_without_lifetime_img_localhost_ = https_server_.GetURL(
263 "/http_equiv_accept_ch_without_lifetime_img_localhost.html");
264 http_equiv_accept_ch_with_lifetime_ =
265 https_server_.GetURL("/http_equiv_accept_ch_with_lifetime.html");
Tarun Bansal293a7b6c2018-12-05 17:41:12266
267 redirect_url_ = https_cross_origin_server_.GetURL("/redirect.html");
Maks Orlovich7a588d82020-05-06 15:17:24268
269 accept_ch_empty_ = https_server_.GetURL("/accept_ch_empty.html");
270 http_equiv_accept_ch_merge_ =
271 https_server_.GetURL("/http_equiv_accept_ch_merge.html");
Tarun Bansal0b8b7afd2017-08-25 03:52:16272 }
273
274 ~ClientHintsBrowserTest() override {}
275
Mike West2fddeeb72019-02-15 11:29:48276 virtual std::unique_ptr<base::FeatureList> EnabledFeatures() {
277 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
Maks Orlovichc66745a2020-06-30 17:40:02278 feature_list->InitializeFromCommandLine(
Ari Chivukulae399ab42021-09-15 22:20:28279 "UserAgentClientHint,CriticalClientHint,"
Max Curran99cbec1492021-08-16 19:54:26280 "AcceptCHFrame,PrefersColorSchemeClientHintHeader,"
281 "ViewportHeightClientHintHeader",
Aaron Tagliaboschi603540d22021-04-05 00:37:14282 "");
Mike West2fddeeb72019-02-15 11:29:48283 return feature_list;
284 }
285
286 void SetUp() override {
Maksim Sisov (GMT+3)830244f2020-08-10 12:52:24287 scoped_feature_list_.InitWithFeatureList(EnabledFeatures());
Mike West2fddeeb72019-02-15 11:29:48288 InProcessBrowserTest::SetUp();
289 }
290
Tarun Bansal0b8b7afd2017-08-25 03:52:16291 void SetUpOnMainThread() override {
Tarun Bansal229647bd002018-02-27 17:33:36292 host_resolver()->AddRule("*", "127.0.0.1");
Tarun Bansal229647bd002018-02-27 17:33:36293
Jay Civelli1ff872d2018-03-09 21:52:16294 request_interceptor_ = std::make_unique<ThirdPartyURLLoaderInterceptor>(
295 GURL("https://foo.com/non-existing-image.jpg"));
Tarun Bansal229647bd002018-02-27 17:33:36296 base::RunLoop().RunUntilIdle();
Tarun Bansal0b8b7afd2017-08-25 03:52:16297 }
298
Jay Civelli1ff872d2018-03-09 21:52:16299 void TearDownOnMainThread() override { request_interceptor_.reset(); }
300
Tarun Bansal0b8b7afd2017-08-25 03:52:16301 void SetUpCommandLine(base::CommandLine* cmd) override {
Tarun Bansal7f3fe8c2018-04-06 22:37:47302 cmd->AppendSwitchASCII(network::switches::kForceEffectiveConnectionType,
303 net::kEffectiveConnectionType2G);
Tarun Bansal0b8b7afd2017-08-25 03:52:16304 }
305
Tarun Bansal229647bd002018-02-27 17:33:36306 void SetClientHintExpectationsOnMainFrame(bool expect_client_hints) {
307 expect_client_hints_on_main_frame_ = expect_client_hints;
Tarun Bansal1965b042017-09-07 04:59:19308 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16309
Tarun Bansal229647bd002018-02-27 17:33:36310 void SetClientHintExpectationsOnSubresources(bool expect_client_hints) {
Callum May1d939742020-03-02 17:51:30311 base::AutoLock lock(expect_client_hints_on_subresources_lock_);
Tarun Bansal229647bd002018-02-27 17:33:36312 expect_client_hints_on_subresources_ = expect_client_hints;
Tarun Bansala61f0f62017-10-24 23:53:05313 }
314
Callum May1d939742020-03-02 17:51:30315 bool expect_client_hints_on_subresources() {
316 base::AutoLock lock(expect_client_hints_on_subresources_lock_);
317 return expect_client_hints_on_subresources_;
318 }
319
Tarun Bansalc211d8b2018-03-19 19:21:58320 // Verify that the user is not notified that cookies or JavaScript were
321 // blocked on the webpage due to the checks done by client hints.
322 void VerifyContentSettingsNotNotified() const {
Carlos Caballerob4283202020-08-10 14:40:46323 auto* pscs = content_settings::PageSpecificContentSettings::GetForFrame(
Carlos Caballerod7b759412020-07-31 18:00:08324 browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame());
Carlos Caballerob4283202020-08-10 14:40:46325 EXPECT_FALSE(pscs->IsContentBlocked(ContentSettingsType::COOKIES));
326 EXPECT_FALSE(pscs->IsContentBlocked(ContentSettingsType::JAVASCRIPT));
Tarun Bansalc211d8b2018-03-19 19:21:58327 }
328
Tarun Bansalbef6d652018-10-02 18:41:01329 void SetExpectedEffectiveConnectionType(
330 net::EffectiveConnectionType effective_connection_type) {
331 expected_ect = effective_connection_type;
332 }
333
Changwan Ryu434c3a32019-07-30 23:42:58334 void SetJsEnabledForActiveView(bool enabled) {
Rakina Zata Amni347b70902020-07-22 10:49:04335 content::WebContents* web_contents =
336 browser()->tab_strip_model()->GetActiveWebContents();
Gyuyoung Kim1ac4ca782020-09-11 03:32:51337 blink::web_pref::WebPreferences prefs =
338 web_contents->GetOrCreateWebPreferences();
Changwan Ryu434c3a32019-07-30 23:42:58339 prefs.javascript_enabled = enabled;
Rakina Zata Amni347b70902020-07-22 10:49:04340 web_contents->SetWebPreferences(prefs);
Changwan Ryu434c3a32019-07-30 23:42:58341 }
342
Maks Orlovich7227ce0d2020-02-28 17:13:16343 void TestProfilesIndependent(Browser* browser_a, Browser* browser_b);
344
Tarun Bansal3b330b02017-11-09 19:03:14345 const GURL& accept_ch_with_lifetime_http_local_url() const {
346 return accept_ch_with_lifetime_http_local_url_;
347 }
Tarun Bansal9a7051f2018-07-10 18:30:05348 const GURL& http_equiv_accept_ch_with_lifetime_http_local_url() const {
349 return http_equiv_accept_ch_with_lifetime_http_local_url_;
350 }
Tarun Bansal3b330b02017-11-09 19:03:14351
Tarun Bansal1965b042017-09-07 04:59:19352 // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
353 // headers.
354 const GURL& accept_ch_with_lifetime_url() const {
355 return accept_ch_with_lifetime_url_;
356 }
Tarun Bansal9a7051f2018-07-10 18:30:05357 const GURL& http_equiv_accept_ch_with_lifetime() {
358 return http_equiv_accept_ch_with_lifetime_;
359 }
Tarun Bansal1965b042017-09-07 04:59:19360
Tarun Bansal73502f92019-04-16 21:21:19361 // A URL whose response headers include Accept-CH and Accept-CH-Lifetime
362 // headers. The Accept-CH-Lifetime duration is set very short to 1 second.
363 const GURL& accept_ch_with_short_lifetime() const {
364 return accept_ch_with_short_lifetime_url_;
365 }
366
Tarun Bansal1965b042017-09-07 04:59:19367 // A URL whose response headers include only Accept-CH header.
368 const GURL& accept_ch_without_lifetime_url() const {
369 return accept_ch_without_lifetime_url_;
370 }
Tarun Bansal9a7051f2018-07-10 18:30:05371 const GURL& http_equiv_accept_ch_without_lifetime_url() const {
372 return http_equiv_accept_ch_without_lifetime_url_;
373 }
Tarun Bansal1965b042017-09-07 04:59:19374
375 // A URL whose response headers do not include either Accept-CH or
376 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
377 const GURL& without_accept_ch_without_lifetime_url() const {
378 return without_accept_ch_without_lifetime_url_;
379 }
380
Tarun Bansal3b330b02017-11-09 19:03:14381 // A URL whose response headers do not include either Accept-CH or
382 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image.
383 const GURL& without_accept_ch_without_lifetime_local_url() const {
384 return without_accept_ch_without_lifetime_local_url_;
385 }
386
Tarun Bansaladd5e1812018-02-09 19:07:58387 // A URL whose response headers do not include either Accept-CH or
388 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
389 // from localhost.
390 const GURL& without_accept_ch_without_lifetime_img_localhost() const {
391 return without_accept_ch_without_lifetime_img_localhost_;
392 }
393
394 // A URL whose response headers do not include either Accept-CH or
395 // Accept-CH-Lifetime headers. Navigating to this URL also fetches an image
396 // from foo.com.
397 const GURL& without_accept_ch_without_lifetime_img_foo_com() const {
398 return without_accept_ch_without_lifetime_img_foo_com_;
399 }
400
401 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
402 // headers. The response loads accept_ch_with_lifetime_url() in an iframe.
403 const GURL& accept_ch_without_lifetime_with_iframe_url() const {
404 return accept_ch_without_lifetime_with_iframe_url_;
405 }
Tarun Bansal9a7051f2018-07-10 18:30:05406 const GURL& http_equiv_accept_ch_without_lifetime_with_iframe_url() const {
407 return http_equiv_accept_ch_without_lifetime_with_iframe_url_;
408 }
Tarun Bansaladd5e1812018-02-09 19:07:58409
Tarun Bansal62cc3542018-06-27 23:53:30410 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
411 // headers. The response loads accept_ch_with_lifetime_url() as a subresource
412 // in the main frame.
413 const GURL& accept_ch_without_lifetime_with_subresource_url() const {
414 return accept_ch_without_lifetime_with_subresource_url_;
415 }
Tarun Bansal9a7051f2018-07-10 18:30:05416 const GURL& http_equiv_accept_ch_without_lifetime_with_subresource_url()
417 const {
418 return http_equiv_accept_ch_without_lifetime_with_subresource_url_;
419 }
Tarun Bansal62cc3542018-06-27 23:53:30420
421 // A URL whose response does not include Accept-CH or Accept-CH-Lifetime
Tarun Bansal9a7051f2018-07-10 18:30:05422 // headers. The response loads accept_ch_with_lifetime_url() or
423 // http_equiv_accept_ch_with_lifetime_url() as a subresource in the iframe.
Tarun Bansal62cc3542018-06-27 23:53:30424 const GURL& accept_ch_without_lifetime_with_subresource_iframe_url() const {
425 return accept_ch_without_lifetime_with_subresource_iframe_url_;
426 }
Tarun Bansal9a7051f2018-07-10 18:30:05427 const GURL&
428 http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url() const {
429 return http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_;
430 }
Tarun Bansal62cc3542018-06-27 23:53:30431
Tarun Bansal9a7051f2018-07-10 18:30:05432 // A URL whose response includes only Accept-CH header. Navigating to
Tarun Bansal229647bd002018-02-27 17:33:36433 // this URL also fetches two images: One from the localhost, and one from
434 // foo.com.
435 const GURL& accept_ch_without_lifetime_img_localhost() const {
436 return accept_ch_without_lifetime_img_localhost_;
437 }
Tarun Bansal9a7051f2018-07-10 18:30:05438 const GURL& http_equiv_accept_ch_without_lifetime_img_localhost() const {
439 return http_equiv_accept_ch_without_lifetime_img_localhost_;
440 }
Tarun Bansal229647bd002018-02-27 17:33:36441
Tarun Bansal293a7b6c2018-12-05 17:41:12442 const GURL& redirect_url() const { return redirect_url_; }
443
Maks Orlovich7a588d82020-05-06 15:17:24444 // A URL to a page with a response containing an empty accept_ch header.
445 const GURL& accept_ch_empty() const { return accept_ch_empty_; }
446
447 // A page where some hints are in accept-ch header, some in http-equiv.
448 const GURL& http_equiv_accept_ch_merge() const {
449 return http_equiv_accept_ch_merge_;
450 }
451
Mike West2fddeeb72019-02-15 11:29:48452 size_t count_user_agent_hint_headers_seen() const {
Callum May7d88ff3e2019-11-12 18:21:46453 base::AutoLock lock(count_headers_lock_);
Mike West2fddeeb72019-02-15 11:29:48454 return count_user_agent_hint_headers_seen_;
455 }
456
Maks Orlovich5dcc99c2020-02-13 19:07:46457 size_t count_ua_mobile_client_hints_headers_seen() const {
458 base::AutoLock lock(count_headers_lock_);
459 return count_ua_mobile_client_hints_headers_seen_;
460 }
461
Aaron Tagliaboschiec5bce62021-06-24 18:50:09462 size_t count_ua_platform_client_hints_headers_seen() const {
463 base::AutoLock lock(count_headers_lock_);
464 return count_ua_platform_client_hints_headers_seen_;
465 }
466
Tarun Bansal1965b042017-09-07 04:59:19467 size_t count_client_hints_headers_seen() const {
Callum May7d88ff3e2019-11-12 18:21:46468 base::AutoLock lock(count_headers_lock_);
Tarun Bansal1965b042017-09-07 04:59:19469 return count_client_hints_headers_seen_;
470 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16471
Tarun Bansal229647bd002018-02-27 17:33:36472 size_t third_party_request_count_seen() const {
473 return request_interceptor_->request_count_seen();
474 }
475
476 size_t third_party_client_hints_count_seen() const {
477 return request_interceptor_->client_hints_count_seen();
478 }
479
Mike Weste555be862019-02-20 16:17:30480 const std::string& main_frame_ua_observed() const {
481 return main_frame_ua_observed_;
482 }
483
Yoav Weissd33bacb2020-03-12 06:42:21484 const std::string& main_frame_ua_full_version_observed() const {
485 return main_frame_ua_full_version_observed_;
486 }
487
Maks Orlovich73f374d2020-04-02 12:46:13488 const std::string& main_frame_ua_mobile_observed() const {
489 return main_frame_ua_mobile_observed_;
490 }
491
492 const std::string& main_frame_ua_platform_observed() const {
493 return main_frame_ua_platform_observed_;
494 }
495
Tarun Bansalea0d8262018-05-21 16:11:50496 base::test::ScopedFeatureList scoped_feature_list_;
497
Tarun Bansal345418632018-06-29 11:07:04498 std::string intercept_iframe_resource_;
Tarun Bansal9a7051f2018-07-10 18:30:05499 bool intercept_to_http_equiv_iframe_ = false;
Callum May7d88ff3e2019-11-12 18:21:46500 mutable base::Lock count_headers_lock_;
Tarun Bansal345418632018-06-29 11:07:04501
Tarun Bansal0b8b7afd2017-08-25 03:52:16502 private:
Tarun Bansal345418632018-06-29 11:07:04503 // Intercepts only the main frame requests that contain
Tarun Bansal293a7b6c2018-12-05 17:41:12504 // "redirect" in the resource path. The intercepted requests
505 // are served an HTML file that fetches an iframe from a cross-origin HTTPS
506 // server.
507 std::unique_ptr<net::test_server::HttpResponse> RequestHandlerToRedirect(
508 const net::test_server::HttpRequest& request) {
509 // Check if it's a main frame request.
510 if (request.relative_url.find(".html") == std::string::npos)
511 return nullptr;
512
513 if (request.GetURL().spec().find("redirect") == std::string::npos)
514 return nullptr;
515
Lei Zhange00db752021-04-17 00:48:46516 auto response = std::make_unique<net::test_server::BasicHttpResponse>();
Tarun Bansal293a7b6c2018-12-05 17:41:12517 response->set_code(net::HTTP_FOUND);
518 response->AddCustomHeader("Location",
519 without_accept_ch_without_lifetime_url().spec());
520 return std::move(response);
521 }
522
523 // Intercepts only the main frame requests that contain
Tarun Bansal345418632018-06-29 11:07:04524 // |intercept_iframe_resource_| in the resource path. The intercepted requests
525 // are served an HTML file that fetches an iframe from a cross-origin HTTPS
526 // server.
527 std::unique_ptr<net::test_server::HttpResponse>
528 RequestHandlerToFetchCrossOriginIframe(
529 const net::test_server::HttpRequest& request) {
530 if (intercept_iframe_resource_.empty())
531 return nullptr;
532
533 // Check if it's a main frame request.
534 if (request.relative_url.find(".html") == std::string::npos)
535 return nullptr;
536
537 if (request.relative_url.find(intercept_iframe_resource_) ==
538 std::string::npos) {
539 return nullptr;
540 }
541
542 const std::string iframe_url =
Tarun Bansal9a7051f2018-07-10 18:30:05543 intercept_to_http_equiv_iframe_
544 ? https_cross_origin_server_
545 .GetURL("/http_equiv_accept_ch_with_lifetime.html")
546 .spec()
547 : https_cross_origin_server_.GetURL("/accept_ch_with_lifetime.html")
548 .spec();
Tarun Bansal345418632018-06-29 11:07:04549
550 std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
551 new net::test_server::BasicHttpResponse());
552 http_response->set_code(net::HTTP_OK);
553 http_response->set_content_type("text/html");
554 http_response->set_content(
555 "<html>"
556 "<link rel='icon' href='data:;base64,='><head></head>"
557 "Empty file which uses link-rel to disable favicon fetches. "
558 "<iframe src='" +
559 iframe_url + "'></iframe></html>");
560
561 return std::move(http_response);
562 }
563
Maks Orlovich73f374d2020-04-02 12:46:13564 static std::string UpdateHeaderObservation(
565 const net::test_server::HttpRequest& request,
566 const std::string& header) {
567 if (request.headers.find(header) != request.headers.end())
568 return request.headers.find(header)->second;
569 else
570 return "";
571 }
572
Tarun Bansal1965b042017-09-07 04:59:19573 // Called by |https_server_|.
574 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
Tarun Bansal6bf54302017-10-02 07:39:14575 bool is_main_frame_navigation =
576 request.GetURL().spec().find(".html") != std::string::npos;
577
Tarun Bansal293a7b6c2018-12-05 17:41:12578 if (is_main_frame_navigation &&
579 request.GetURL().spec().find("redirect") != std::string::npos) {
580 return;
581 }
582
Tarun Bansal229647bd002018-02-27 17:33:36583 if (is_main_frame_navigation) {
Maks Orlovich73f374d2020-04-02 12:46:13584 main_frame_ua_observed_ = UpdateHeaderObservation(request, "sec-ch-ua");
585 main_frame_ua_full_version_observed_ =
586 UpdateHeaderObservation(request, "sec-ch-ua-full-version");
587 main_frame_ua_mobile_observed_ =
588 UpdateHeaderObservation(request, "sec-ch-ua-mobile");
589 main_frame_ua_platform_observed_ =
590 UpdateHeaderObservation(request, "sec-ch-ua-platform");
Yoav Weissd33bacb2020-03-12 06:42:21591
Tarun Bansalf9cf9892018-04-06 04:38:01592 VerifyClientHintsReceived(expect_client_hints_on_main_frame_, request);
Tarun Bansal5c28afb2018-03-17 02:55:20593 if (expect_client_hints_on_main_frame_) {
594 double value = 0.0;
595 EXPECT_TRUE(base::StringToDouble(
596 request.headers.find("device-memory")->second, &value));
597 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35598 EXPECT_TRUE(IsSimilarToDoubleABNF(
599 request.headers.find("device-memory")->second));
Tarun Bansal44ad96882018-03-28 17:47:42600 main_frame_device_memory_observed_ = value;
Tarun Bansal5c28afb2018-03-17 02:55:20601
602 EXPECT_TRUE(
603 base::StringToDouble(request.headers.find("dpr")->second, &value));
604 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35605 EXPECT_TRUE(IsSimilarToDoubleABNF(request.headers.find("dpr")->second));
Tarun Bansal44ad96882018-03-28 17:47:42606 main_frame_dpr_observed_ = value;
607
Tarun Bansal5c28afb2018-03-17 02:55:20608 EXPECT_TRUE(base::StringToDouble(
609 request.headers.find("viewport-width")->second, &value));
Tarun Bansal62efba12018-05-04 22:58:35610 EXPECT_TRUE(
611 IsSimilarToIntABNF(request.headers.find("viewport-width")->second));
Tarun Bansal79df868e2018-03-20 23:01:36612#if !defined(OS_ANDROID)
Tarun Bansal5c28afb2018-03-17 02:55:20613 EXPECT_LT(0.0, value);
Tarun Bansal79df868e2018-03-20 23:01:36614#else
615 EXPECT_EQ(980, value);
Tarun Bansal5c28afb2018-03-17 02:55:20616#endif
Tarun Bansal44ad96882018-03-28 17:47:42617 main_frame_viewport_width_observed_ = value;
Mike Weste555be862019-02-20 16:17:30618
Max Curran99cbec1492021-08-16 19:54:26619 EXPECT_TRUE(base::StringToDouble(
620 request.headers.find("sec-ch-viewport-height")->second, &value));
621 EXPECT_TRUE(IsSimilarToIntABNF(
622 request.headers.find("sec-ch-viewport-height")->second));
623 EXPECT_LT(0.0, value);
624
Tarun Bansal7f3fe8c2018-04-06 22:37:47625 VerifyNetworkQualityClientHints(request);
Tarun Bansal5c28afb2018-03-17 02:55:20626 }
Tarun Bansala61f0f62017-10-24 23:53:05627 }
Tarun Bansal6bf54302017-10-02 07:39:14628
Tarun Bansal229647bd002018-02-27 17:33:36629 if (!is_main_frame_navigation) {
Callum May1d939742020-03-02 17:51:30630 VerifyClientHintsReceived(expect_client_hints_on_subresources(), request);
Tarun Bansal5c28afb2018-03-17 02:55:20631
Callum May1d939742020-03-02 17:51:30632 if (expect_client_hints_on_subresources()) {
Tarun Bansal5c28afb2018-03-17 02:55:20633 double value = 0.0;
634 EXPECT_TRUE(base::StringToDouble(
635 request.headers.find("device-memory")->second, &value));
636 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35637 EXPECT_TRUE(IsSimilarToDoubleABNF(
638 request.headers.find("device-memory")->second));
Tarun Bansal44ad96882018-03-28 17:47:42639 if (main_frame_device_memory_observed_ > 0) {
640 EXPECT_EQ(main_frame_device_memory_observed_, value);
641 }
Tarun Bansal5c28afb2018-03-17 02:55:20642
643 EXPECT_TRUE(
644 base::StringToDouble(request.headers.find("dpr")->second, &value));
645 EXPECT_LT(0.0, value);
Tarun Bansal62efba12018-05-04 22:58:35646 EXPECT_TRUE(IsSimilarToDoubleABNF(request.headers.find("dpr")->second));
Tarun Bansal44ad96882018-03-28 17:47:42647 if (main_frame_dpr_observed_ > 0) {
648 EXPECT_EQ(main_frame_dpr_observed_, value);
649 }
Tarun Bansal5c28afb2018-03-17 02:55:20650
651 EXPECT_TRUE(base::StringToDouble(
652 request.headers.find("viewport-width")->second, &value));
Tarun Bansal62efba12018-05-04 22:58:35653 EXPECT_TRUE(
654 IsSimilarToIntABNF(request.headers.find("viewport-width")->second));
Tarun Bansal79df868e2018-03-20 23:01:36655#if !defined(OS_ANDROID)
Tarun Bansal5c28afb2018-03-17 02:55:20656 EXPECT_LT(0.0, value);
Tarun Bansal79df868e2018-03-20 23:01:36657#else
658 EXPECT_EQ(980, value);
659#endif
Tarun Bansal44ad96882018-03-28 17:47:42660#if defined(OS_ANDROID)
661 // TODO(tbansal): https://crbug.com/825892: Viewport width on main
662 // frame requests may be incorrect when the Chrome window is not
663 // maximized.
664 if (main_frame_viewport_width_observed_ > 0) {
665 EXPECT_EQ(main_frame_viewport_width_observed_, value);
666 }
667#endif
Max Curran99cbec1492021-08-16 19:54:26668 EXPECT_TRUE(base::StringToDouble(
669 request.headers.find("sec-ch-viewport-height")->second, &value));
670 EXPECT_TRUE(IsSimilarToIntABNF(
671 request.headers.find("sec-ch-viewport-height")->second));
672 EXPECT_LT(0.0, value);
673
Tarun Bansal7f3fe8c2018-04-06 22:37:47674 VerifyNetworkQualityClientHints(request);
Tarun Bansal5c28afb2018-03-17 02:55:20675 }
Tarun Bansala61f0f62017-10-24 23:53:05676 }
Tarun Bansal6bf54302017-10-02 07:39:14677
Ari Chivukula51baf9b2021-09-13 20:01:49678 for (const auto& elem : network::GetClientHintToNameMap()) {
679 const auto& header = elem.second;
680 if (base::Contains(request.headers, header)) {
Callum May7d88ff3e2019-11-12 18:21:46681 base::AutoLock lock(count_headers_lock_);
Mike West2fddeeb72019-02-15 11:29:48682 // The user agent hint is special:
Ari Chivukula51baf9b2021-09-13 20:01:49683 if (header == "sec-ch-ua") {
Mike West2fddeeb72019-02-15 11:29:48684 count_user_agent_hint_headers_seen_++;
Ari Chivukula51baf9b2021-09-13 20:01:49685 } else if (header == "sec-ch-ua-mobile") {
Maks Orlovich5dcc99c2020-02-13 19:07:46686 count_ua_mobile_client_hints_headers_seen_++;
Ari Chivukula51baf9b2021-09-13 20:01:49687 } else if (header == "sec-ch-ua-platform") {
Aaron Tagliaboschiec5bce62021-06-24 18:50:09688 count_ua_platform_client_hints_headers_seen_++;
Mike West2fddeeb72019-02-15 11:29:48689 } else {
690 count_client_hints_headers_seen_++;
691 }
Tarun Bansalf9cf9892018-04-06 04:38:01692 }
693 }
694 }
Tarun Bansal1965b042017-09-07 04:59:19695
Tarun Bansalf9cf9892018-04-06 04:38:01696 void VerifyClientHintsReceived(bool expect_client_hints,
697 const net::test_server::HttpRequest& request) {
Ari Chivukula51baf9b2021-09-13 20:01:49698 for (const auto& elem : network::GetClientHintToNameMap()) {
699 const auto& header = elem.second;
700 SCOPED_TRACE(testing::Message() << header);
Tarun Bansalf9cf9892018-04-06 04:38:01701 // Resource width client hint is only attached on image subresources.
Ari Chivukula51baf9b2021-09-13 20:01:49702 if (header == "width") {
Tarun Bansalf9cf9892018-04-06 04:38:01703 continue;
704 }
Mike West2fddeeb72019-02-15 11:29:48705
Aaron Tagliaboschiec5bce62021-06-24 18:50:09706 // `Sec-CH-UA`, `Sec-CH-UA-Mobile`, and `Sec-CH-UA-Platform` is attached
707 // on all requests.
Ari Chivukula51baf9b2021-09-13 20:01:49708 if (header == "sec-ch-ua" || header == "sec-ch-ua-mobile" ||
709 header == "sec-ch-ua-platform") {
Mike West2fddeeb72019-02-15 11:29:48710 continue;
711 }
712
Ali Beyad7417fc22021-08-06 03:09:58713 // Skip over the `Sec-CH-UA-Reduced` client hint because it is only added
714 // in the presence of a valid "UserAgentReduction" Origin Trial token.
715 // `Sec-CH-UA-Reduced` is tested via UaReducedOriginTrialBrowserTest
716 // below.
Ari Chivukula51baf9b2021-09-13 20:01:49717 if (header == "sec-ch-ua-reduced") {
Ali Beyad67abdaf22021-07-29 01:00:24718 continue;
719 }
720
Ari Chivukula51baf9b2021-09-13 20:01:49721 EXPECT_EQ(expect_client_hints, base::Contains(request.headers, header));
Tarun Bansalf9cf9892018-04-06 04:38:01722 }
Tarun Bansal1965b042017-09-07 04:59:19723 }
724
Tarun Bansal7f3fe8c2018-04-06 22:37:47725 void VerifyNetworkQualityClientHints(
726 const net::test_server::HttpRequest& request) const {
727 // Effective connection type is forced to 2G using command line in these
728 // tests.
Tarun Bansal509a8dd2018-04-10 17:19:16729 int rtt_value = 0.0;
Tarun Bansal7f3fe8c2018-04-06 22:37:47730 EXPECT_TRUE(
Tarun Bansal509a8dd2018-04-10 17:19:16731 base::StringToInt(request.headers.find("rtt")->second, &rtt_value));
732 EXPECT_LE(0, rtt_value);
Tarun Bansal62efba12018-05-04 22:58:35733 EXPECT_TRUE(IsSimilarToIntABNF(request.headers.find("rtt")->second));
Tarun Bansal509a8dd2018-04-10 17:19:16734 // Verify that RTT value is a multiple of 50 milliseconds.
735 EXPECT_EQ(0, rtt_value % 50);
Tarun Bansalbef6d652018-10-02 18:41:01736 EXPECT_GE(expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G ? 3000 : 500,
737 rtt_value);
Tarun Bansal7f3fe8c2018-04-06 22:37:47738
Tarun Bansal509a8dd2018-04-10 17:19:16739 double mbps_value = 0.0;
740 EXPECT_TRUE(base::StringToDouble(request.headers.find("downlink")->second,
741 &mbps_value));
742 EXPECT_LE(0, mbps_value);
Tarun Bansal62efba12018-05-04 22:58:35743 EXPECT_TRUE(
744 IsSimilarToDoubleABNF(request.headers.find("downlink")->second));
Tarun Bansal509a8dd2018-04-10 17:19:16745 // Verify that the mbps value is a multiple of 0.050 mbps.
746 // Allow for small amount of noise due to double to integer conversions.
747 EXPECT_NEAR(0, (static_cast<int>(mbps_value * 1000)) % 50, 1);
748 EXPECT_GE(10.0, mbps_value);
Tarun Bansal7f3fe8c2018-04-06 22:37:47749
750 EXPECT_FALSE(request.headers.find("ect")->second.empty());
Tarun Bansalceab9592018-05-01 18:57:35751
752 // TODO(tbansal): https://crbug.com/819244: When network servicification is
Tarun Bansal5ac533542018-08-10 19:45:52753 // enabled, the renderer processes do not receive notifications on
754 // change in the network quality. Hence, the network quality client hints
755 // are not set to the correct value on subresources.
756 bool is_main_frame_navigation =
757 request.GetURL().spec().find(".html") != std::string::npos;
John Abd-El-Malek67facbe82019-06-06 22:37:08758 if (is_main_frame_navigation) {
Tarun Bansalceab9592018-05-01 18:57:35759 // Effective connection type is forced to 2G using command line in these
760 // tests. RTT is expected to be 1800 msec but leave some gap to account
761 // for added noise and randomization.
Tarun Bansalbef6d652018-10-02 18:41:01762 if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G) {
763 EXPECT_NEAR(1800, rtt_value, 360);
764 } else if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_3G) {
765 EXPECT_NEAR(450, rtt_value, 90);
766 } else {
767 NOTREACHED();
768 }
Tarun Bansalceab9592018-05-01 18:57:35769
770 // Effective connection type is forced to 2G using command line in these
771 // tests. downlink is expected to be 0.075 Mbps but leave some gap to
772 // account for added noise and randomization.
Tarun Bansalbef6d652018-10-02 18:41:01773 if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G) {
774 EXPECT_NEAR(0.075, mbps_value, 0.05);
775 } else if (expected_ect == net::EFFECTIVE_CONNECTION_TYPE_3G) {
776 EXPECT_NEAR(0.4, mbps_value, 0.1);
777 } else {
778 NOTREACHED();
779 }
Tarun Bansalceab9592018-05-01 18:57:35780
Tarun Bansalbef6d652018-10-02 18:41:01781 EXPECT_EQ(expected_ect == net::EFFECTIVE_CONNECTION_TYPE_2G ? "2g" : "3g",
782 request.headers.find("ect")->second);
Tarun Bansalceab9592018-05-01 18:57:35783 }
Tarun Bansal7f3fe8c2018-04-06 22:37:47784 }
785
Tarun Bansal3b330b02017-11-09 19:03:14786 net::EmbeddedTestServer http_server_;
Tarun Bansal0b8b7afd2017-08-25 03:52:16787 net::EmbeddedTestServer https_server_;
Tarun Bansal345418632018-06-29 11:07:04788 net::EmbeddedTestServer https_cross_origin_server_;
Tarun Bansal3b330b02017-11-09 19:03:14789 GURL accept_ch_with_lifetime_http_local_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05790 GURL http_equiv_accept_ch_with_lifetime_http_local_url_;
Tarun Bansal1965b042017-09-07 04:59:19791 GURL accept_ch_with_lifetime_url_;
Tarun Bansal73502f92019-04-16 21:21:19792 GURL accept_ch_with_short_lifetime_url_;
Tarun Bansal1965b042017-09-07 04:59:19793 GURL accept_ch_without_lifetime_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05794 GURL http_equiv_accept_ch_without_lifetime_url_;
Tarun Bansal1965b042017-09-07 04:59:19795 GURL without_accept_ch_without_lifetime_url_;
Tarun Bansal3b330b02017-11-09 19:03:14796 GURL without_accept_ch_without_lifetime_local_url_;
Tarun Bansaladd5e1812018-02-09 19:07:58797 GURL accept_ch_without_lifetime_with_iframe_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05798 GURL http_equiv_accept_ch_without_lifetime_with_iframe_url_;
Tarun Bansal62cc3542018-06-27 23:53:30799 GURL accept_ch_without_lifetime_with_subresource_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05800 GURL http_equiv_accept_ch_without_lifetime_with_subresource_url_;
Tarun Bansal62cc3542018-06-27 23:53:30801 GURL accept_ch_without_lifetime_with_subresource_iframe_url_;
Tarun Bansal9a7051f2018-07-10 18:30:05802 GURL http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url_;
Tarun Bansaladd5e1812018-02-09 19:07:58803 GURL without_accept_ch_without_lifetime_img_foo_com_;
804 GURL without_accept_ch_without_lifetime_img_localhost_;
Tarun Bansal229647bd002018-02-27 17:33:36805 GURL accept_ch_without_lifetime_img_localhost_;
Tarun Bansal9a7051f2018-07-10 18:30:05806 GURL http_equiv_accept_ch_without_lifetime_img_localhost_;
807 GURL http_equiv_accept_ch_with_lifetime_;
Tarun Bansal293a7b6c2018-12-05 17:41:12808 GURL redirect_url_;
Maks Orlovich7a588d82020-05-06 15:17:24809 GURL accept_ch_empty_;
810 GURL http_equiv_accept_ch_merge_;
Tarun Bansal1965b042017-09-07 04:59:19811
Mike Weste555be862019-02-20 16:17:30812 std::string main_frame_ua_observed_;
Yoav Weissd33bacb2020-03-12 06:42:21813 std::string main_frame_ua_full_version_observed_;
Maks Orlovich73f374d2020-04-02 12:46:13814 std::string main_frame_ua_mobile_observed_;
815 std::string main_frame_ua_platform_observed_;
Mike Weste555be862019-02-20 16:17:30816
Tarun Bansal44ad96882018-03-28 17:47:42817 double main_frame_dpr_observed_ = -1;
818 double main_frame_viewport_width_observed_ = -1;
819 double main_frame_device_memory_observed_ = -1;
820
Tarun Bansal229647bd002018-02-27 17:33:36821 // Expect client hints on all the main frame request.
822 bool expect_client_hints_on_main_frame_;
823 // Expect client hints on all the subresource requests.
Callum May1d939742020-03-02 17:51:30824 bool expect_client_hints_on_subresources_
825 GUARDED_BY(expect_client_hints_on_subresources_lock_);
826
827 base::Lock expect_client_hints_on_subresources_lock_;
Tarun Bansal229647bd002018-02-27 17:33:36828
Mike West2fddeeb72019-02-15 11:29:48829 size_t count_user_agent_hint_headers_seen_;
Maks Orlovich5dcc99c2020-02-13 19:07:46830 size_t count_ua_mobile_client_hints_headers_seen_;
Aaron Tagliaboschiec5bce62021-06-24 18:50:09831 size_t count_ua_platform_client_hints_headers_seen_;
Tarun Bansal1965b042017-09-07 04:59:19832 size_t count_client_hints_headers_seen_;
Tarun Bansala61f0f62017-10-24 23:53:05833
Jay Civelli1ff872d2018-03-09 21:52:16834 std::unique_ptr<ThirdPartyURLLoaderInterceptor> request_interceptor_;
Tarun Bansal229647bd002018-02-27 17:33:36835
Tarun Bansalbef6d652018-10-02 18:41:01836 // Set to 2G in SetUpCommandLine().
837 net::EffectiveConnectionType expected_ect = net::EFFECTIVE_CONNECTION_TYPE_2G;
838
Tarun Bansala61f0f62017-10-24 23:53:05839 DISALLOW_COPY_AND_ASSIGN(ClientHintsBrowserTest);
Tarun Bansal0b8b7afd2017-08-25 03:52:16840};
841
Tarun Bansal9a7051f2018-07-10 18:30:05842// True if testing for http-equiv correctness. When set to true, the tests
843// use webpages that may contain http-equiv Accept-CH and Accept-CH-Lifetime
844// headers. When set to false, the tests use webpages that set the headers in
845// the HTTP response headers.
Ilia Samsonov282c38412019-12-09 08:15:10846INSTANTIATE_TEST_SUITE_P(All,
Victor Costane5e91512019-02-13 08:24:02847 ClientHintsBrowserTest,
848 testing::Bool());
Tarun Bansal9a7051f2018-07-10 18:30:05849
Tarun Bansalea0d8262018-05-21 16:11:50850class ClientHintsAllowThirdPartyBrowserTest : public ClientHintsBrowserTest {
Mike West2fddeeb72019-02-15 11:29:48851 std::unique_ptr<base::FeatureList> EnabledFeatures() override {
852 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
853 feature_list->InitializeFromCommandLine(
François Beaufort1b51d062021-05-18 11:11:23854 "AllowClientHintsToThirdParty,UserAgentClientHint,"
Ari Chivukulae399ab42021-09-15 22:20:28855 "PrefersColorSchemeClientHintHeader,ViewportHeightClientHintHeader",
Maks Orlovichc66745a2020-06-30 17:40:02856 "");
Mike West2fddeeb72019-02-15 11:29:48857 return feature_list;
Tarun Bansalea0d8262018-05-21 16:11:50858 }
859};
860
Ilia Samsonov282c38412019-12-09 08:15:10861INSTANTIATE_TEST_SUITE_P(All,
Aaron Tagliaboschia09ec442019-09-18 15:29:03862 ClientHintsAllowThirdPartyBrowserTest,
863 testing::Bool());
864
Tarun Bansal74e189d2018-05-07 19:07:35865IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, CorsChecks) {
Ari Chivukula51baf9b2021-09-13 20:01:49866 for (const auto& elem : network::GetClientHintToNameMap()) {
867 const auto& header = elem.second;
Tarun Bansal74e189d2018-05-07 19:07:35868 // Do not test for headers that have not been enabled on the blink "stable"
869 // yet.
Ari Chivukula51baf9b2021-09-13 20:01:49870 if (header == "rtt" || header == "downlink" || header == "ect") {
Tarun Bansal74e189d2018-05-07 19:07:35871 continue;
872 }
Ari Chivukula51baf9b2021-09-13 20:01:49873 EXPECT_TRUE(
874 network::cors::IsCorsSafelistedHeader(header, "42" /* value */));
Tarun Bansal74e189d2018-05-07 19:07:35875 }
Takashi Toyoshima2e01e692018-11-16 03:23:27876 EXPECT_FALSE(network::cors::IsCorsSafelistedHeader("not-a-client-hint-header",
Tarun Bansal74e189d2018-05-07 19:07:35877 "" /* value */));
878 EXPECT_TRUE(
Takashi Toyoshima2e01e692018-11-16 03:23:27879 network::cors::IsCorsSafelistedHeader("save-data", "on" /* value */));
Tarun Bansal74e189d2018-05-07 19:07:35880}
881
Maks Orlovichf0a2eed2020-05-02 20:08:21882IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, HttpEquivWorks) {
883 const GURL gurl = http_equiv_accept_ch_without_lifetime_img_localhost();
884 base::HistogramTester histogram_tester;
885
886 SetClientHintExpectationsOnMainFrame(false);
887 SetClientHintExpectationsOnSubresources(true);
888
Lukasz Anforowiczb78290c2021-09-08 04:31:38889 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Maks Orlovichf0a2eed2020-05-02 20:08:21890 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
891}
892
Tarun Bansal0b8b7afd2017-08-25 03:52:16893// Loads a webpage that requests persisting of client hints. Verifies that
894// the browser receives the mojo notification from the renderer and persists the
Maks Orlovichf0a2eed2020-05-02 20:08:21895// client hints to the disk --- unless it's using http-equiv which shouldn't
896// persist.
Tarun Bansal9a7051f2018-07-10 18:30:05897IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest, ClientHintsHttps) {
Tarun Bansal0b8b7afd2017-08-25 03:52:16898 base::HistogramTester histogram_tester;
Tarun Bansal9a7051f2018-07-10 18:30:05899 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
900 : accept_ch_with_lifetime_url();
Lukasz Anforowiczb78290c2021-09-08 04:31:38901 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Tarun Bansal0b8b7afd2017-08-25 03:52:16902
Maks Orlovichf0a2eed2020-05-02 20:08:21903 if (GetParam())
904 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
905 else
906 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
Tarun Bansal0b8b7afd2017-08-25 03:52:16907
908 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:28909 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal0b8b7afd2017-08-25 03:52:16910
Maks Orlovichf0a2eed2020-05-02 20:08:21911 if (GetParam()) {
912 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
913 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
914 } else {
915 // client_hints_url() sets the expected number of client hints.
916 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
917 expected_client_hints_number, 1);
918 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:12919 // seconds, but a maximum value is registered instead.
Maks Orlovichf0a2eed2020-05-02 20:08:21920 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:12921 uma_histogram_max_value, 1);
Maks Orlovichf0a2eed2020-05-02 20:08:21922 }
Tarun Bansal0b8b7afd2017-08-25 03:52:16923}
924
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44925IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, PRE_ClientHintsClearSession) {
926 const GURL gurl = accept_ch_with_lifetime_url();
927
928 base::HistogramTester histogram_tester;
929 ContentSettingsForOneType host_settings;
930
931 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:14932 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44933 &host_settings);
934 EXPECT_EQ(0u, host_settings.size());
935
936 // Fetching |gurl| should persist the request for client hints iff using
937 // headers and not http-equiv.
Lukasz Anforowiczb78290c2021-09-08 04:31:38938 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44939
940 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
941
942 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:28943 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44944 base::RunLoop().RunUntilIdle();
945
946 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
947 expected_client_hints_number, 1);
948 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:12949 // seconds, but a maximum value is registered instead.
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44950 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:12951 uma_histogram_max_value, 1);
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44952
953 // Clients hints preferences for one origin should be persisted.
954 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:14955 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44956 &host_settings);
957 EXPECT_EQ(1u, host_settings.size());
958
959 SetClientHintExpectationsOnMainFrame(true);
960 SetClientHintExpectationsOnSubresources(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:38961 ASSERT_TRUE(ui_test_utils::NavigateToURL(
962 browser(), without_accept_ch_without_lifetime_url()));
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44963
964 // The user agent hint is attached to all three requests:
965 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
966 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:09967 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44968
969 // Expected number of hints attached to the image request, and the same number
970 // to the main frame request.
971 EXPECT_EQ(expected_client_hints_number * 2,
972 count_client_hints_headers_seen());
973}
974
975IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, ClientHintsClearSession) {
976 const GURL gurl = accept_ch_with_lifetime_url();
977
978 base::HistogramTester histogram_tester;
979 ContentSettingsForOneType host_settings;
980
981 // Clients hints preferences for one origin should be persisted.
982 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:14983 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44984 &host_settings);
985 EXPECT_EQ(0u, host_settings.size());
986
987 SetClientHintExpectationsOnMainFrame(false);
988 SetClientHintExpectationsOnSubresources(false);
Lukasz Anforowiczb78290c2021-09-08 04:31:38989 ASSERT_TRUE(ui_test_utils::NavigateToURL(
990 browser(), without_accept_ch_without_lifetime_url()));
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44991
992 // The user agent hint is attached to all three requests:
993 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
994 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:09995 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Aaron Tagliaboschi8ef04eca2020-05-12 23:16:44996
997 // Expected number of hints attached to the image request, and the same number
998 // to the main frame request.
999 EXPECT_EQ(0u, count_client_hints_headers_seen());
1000}
1001
Tarun Bansaladd5e1812018-02-09 19:07:581002// Test that client hints are attached to subresources only if they belong
1003// to the same host as document host.
Maks Orlovichf0a2eed2020-05-02 20:08:211004IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansaladd5e1812018-02-09 19:07:581005 ClientHintsHttpsSubresourceDifferentOrigin) {
Maks Orlovichf0a2eed2020-05-02 20:08:211006 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:051007
Tarun Bansaladd5e1812018-02-09 19:07:581008 base::HistogramTester histogram_tester;
1009
1010 // Add client hints for the embedded test server.
Lukasz Anforowiczb78290c2021-09-08 04:31:381011 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Tarun Bansaladd5e1812018-02-09 19:07:581012 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1013
1014 // Verify that the client hints settings for localhost have been saved.
1015 ContentSettingsForOneType client_hints_settings;
1016 HostContentSettingsMap* host_content_settings_map =
1017 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
1018 host_content_settings_map->GetSettingsForOneType(
Illia Klimov48f643c2020-11-05 20:06:141019 ContentSettingsType::CLIENT_HINTS, &client_hints_settings);
Tarun Bansaladd5e1812018-02-09 19:07:581020 ASSERT_EQ(1U, client_hints_settings.size());
1021
1022 // Copy the client hints setting for localhost to foo.com.
1023 host_content_settings_map->SetWebsiteSettingDefaultScope(
Darin Fisher42f5e7d2019-10-30 07:15:451024 GURL("https://foo.com/"), GURL(), ContentSettingsType::CLIENT_HINTS,
Illia Klimov48f643c2020-11-05 20:06:141025
Jeremy Romanec48d7a2018-03-01 17:35:091026 std::make_unique<base::Value>(
Oksana Zhuravlovab14dc882018-04-12 17:34:571027 client_hints_settings.at(0).setting_value.Clone()));
Tarun Bansaladd5e1812018-02-09 19:07:581028
1029 // Verify that client hints for the two hosts has been saved.
1030 host_content_settings_map =
1031 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
1032 host_content_settings_map->GetSettingsForOneType(
Illia Klimov48f643c2020-11-05 20:06:141033 ContentSettingsType::CLIENT_HINTS, &client_hints_settings);
Tarun Bansaladd5e1812018-02-09 19:07:581034 ASSERT_EQ(2U, client_hints_settings.size());
1035
1036 // Navigating to without_accept_ch_without_lifetime_img_localhost() should
1037 // attach client hints to the image subresouce contained in that page since
1038 // the image is located on the same server as the document origin.
Tarun Bansal229647bd002018-02-27 17:33:361039 SetClientHintExpectationsOnMainFrame(true);
1040 SetClientHintExpectationsOnSubresources(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:381041 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1042 browser(), without_accept_ch_without_lifetime_img_localhost()));
Tarun Bansaladd5e1812018-02-09 19:07:581043 base::RunLoop().RunUntilIdle();
1044 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281045 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansaladd5e1812018-02-09 19:07:581046
Maks Orlovich5dcc99c2020-02-13 19:07:461047 // The user agent hint is attached to all three requests, as is UA-mobile:
Mike West2fddeeb72019-02-15 11:29:481048 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461049 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091050 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481051
Yoav Weissd33bacb2020-03-12 06:42:211052 // Expected number of hints attached to the image request, and the same number
1053 // to the main frame request.
1054 EXPECT_EQ(expected_client_hints_number * 2,
1055 count_client_hints_headers_seen());
Tarun Bansaladd5e1812018-02-09 19:07:581056
1057 // Navigating to without_accept_ch_without_lifetime_img_foo_com() should not
1058 // attach client hints to the image subresouce contained in that page since
1059 // the image is located on a different server as the document origin.
Lukasz Anforowiczb78290c2021-09-08 04:31:381060 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1061 browser(), without_accept_ch_without_lifetime_img_foo_com()));
Tarun Bansaladd5e1812018-02-09 19:07:581062 base::RunLoop().RunUntilIdle();
1063 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281064 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansaladd5e1812018-02-09 19:07:581065
Tarun Bansalb30b7532018-03-14 21:50:381066 // The device-memory and dprheader is attached to the main frame request.
Tarun Bansal5c28afb2018-03-17 02:55:201067#if defined(OS_ANDROID)
Yoav Weissd33bacb2020-03-12 06:42:211068 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal5c28afb2018-03-17 02:55:201069#else
Yoav Weissd33bacb2020-03-12 06:42:211070 EXPECT_EQ(expected_client_hints_number * 3,
1071 count_client_hints_headers_seen());
Tarun Bansal5c28afb2018-03-17 02:55:201072#endif
Mike West2fddeeb72019-02-15 11:29:481073
Aaron Tagliaboschiec5bce62021-06-24 18:50:091074 // Requests to third party servers should have three (3) client hints attached
1075 // (`Sec-CH-UA`, `Sec-CH-UA-Mobile`, `Sec-CH-UA-Platform`).
Tarun Bansal229647bd002018-02-27 17:33:361076 EXPECT_EQ(1u, third_party_request_count_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091077 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansaladd5e1812018-02-09 19:07:581078}
1079
Maks Orlovich7227ce0d2020-02-28 17:13:161080// Test that client hints are attached to subresources checks the right setting
1081// for OTR profile.
Maks Orlovichf0a2eed2020-05-02 20:08:211082IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Maks Orlovich7227ce0d2020-02-28 17:13:161083 ClientHintsHttpsSubresourceOffTheRecord) {
Maks Orlovichf0a2eed2020-05-02 20:08:211084 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich7227ce0d2020-02-28 17:13:161085
1086 base::HistogramTester histogram_tester;
1087
1088 // Add client hints for the embedded test server.
Lukasz Anforowiczb78290c2021-09-08 04:31:381089 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Maks Orlovich7227ce0d2020-02-28 17:13:161090 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1091
1092 // Main profile should get hints for both page and subresources.
1093 SetClientHintExpectationsOnMainFrame(true);
1094 SetClientHintExpectationsOnSubresources(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:381095 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1096 browser(), without_accept_ch_without_lifetime_img_localhost()));
Maks Orlovich7227ce0d2020-02-28 17:13:161097 base::RunLoop().RunUntilIdle();
1098 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281099 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Maks Orlovich7227ce0d2020-02-28 17:13:161100
1101 // The user agent hint is attached to all three requests:
1102 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
1103 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091104 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Maks Orlovich7227ce0d2020-02-28 17:13:161105
Yoav Weissd33bacb2020-03-12 06:42:211106 // Expected number of hints attached to the image request, and the same number
1107 // to the main frame request.
1108 EXPECT_EQ(expected_client_hints_number * 2,
1109 count_client_hints_headers_seen());
Maks Orlovich7227ce0d2020-02-28 17:13:161110
1111 // OTR profile should get neither.
1112 Browser* otr_browser = CreateIncognitoBrowser(browser()->profile());
1113 SetClientHintExpectationsOnMainFrame(false);
1114 SetClientHintExpectationsOnSubresources(false);
Lukasz Anforowiczb78290c2021-09-08 04:31:381115 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1116 otr_browser, without_accept_ch_without_lifetime_img_localhost()));
Maks Orlovich7227ce0d2020-02-28 17:13:161117}
1118
Mike Weste555be862019-02-20 16:17:301119// Verify that we send only major version information in the `Sec-CH-UA` header
Yoav Weissd33bacb2020-03-12 06:42:211120// by default, regardless of opt-in.
Maks Orlovichf0a2eed2020-05-02 20:08:211121IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UserAgentVersion) {
1122 const GURL gurl = accept_ch_with_lifetime_url();
Mike Weste555be862019-02-20 16:17:301123
John Abd-El-Malekec1fc69e2021-01-28 19:14:411124 blink::UserAgentMetadata ua = embedder_support::GetUserAgentMetadata();
Mike Weste555be862019-02-20 16:17:301125
1126 // Navigate to a page that opts-into the header: the value should end with
1127 // the major version, and not contain the full version.
1128 SetClientHintExpectationsOnMainFrame(false);
Lukasz Anforowiczb78290c2021-09-08 04:31:381129 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Aaron Tagliaboschi9f01b682020-05-05 21:03:171130 std::string expected_ua = ua.SerializeBrandVersionList();
Yoav Weissd33bacb2020-03-12 06:42:211131 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1132 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Mike Weste555be862019-02-20 16:17:301133
Yoav Weissd33bacb2020-03-12 06:42:211134 // Navigate again, after the opt-in: the value should stay the major
Mike Weste555be862019-02-20 16:17:301135 // version.
1136 SetClientHintExpectationsOnMainFrame(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:381137 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Yoav Weissd33bacb2020-03-12 06:42:211138 std::string expected_full_version = "\"" + ua.full_version + "\"";
1139 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1140 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
Mike Weste555be862019-02-20 16:17:301141}
1142
Maks Orlovichf0a2eed2020-05-02 20:08:211143IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UAHintsTabletMode) {
1144 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich73f374d2020-04-02 12:46:131145
John Abd-El-Malekec1fc69e2021-01-28 19:14:411146 blink::UserAgentMetadata ua = embedder_support::GetUserAgentMetadata();
Maks Orlovich73f374d2020-04-02 12:46:131147
1148 // First request: only minimal hints, no tablet override.
1149 SetClientHintExpectationsOnMainFrame(false);
Lukasz Anforowiczb78290c2021-09-08 04:31:381150 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Aaron Tagliaboschi9f01b682020-05-05 21:03:171151 std::string expected_ua = ua.SerializeBrandVersionList();
Maks Orlovich73f374d2020-04-02 12:46:131152 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1153 EXPECT_EQ(main_frame_ua_full_version_observed(), "");
1154 EXPECT_EQ(main_frame_ua_mobile_observed(), "?0");
Aaron Tagliaboschiec5bce62021-06-24 18:50:091155 EXPECT_EQ(main_frame_ua_platform_observed(), "\"" + ua.platform + "\"");
Maks Orlovich73f374d2020-04-02 12:46:131156
1157 // Second request: table override, all hints.
1158 chrome::ToggleRequestTabletSite(browser());
1159 SetClientHintExpectationsOnMainFrame(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:381160 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Maks Orlovich73f374d2020-04-02 12:46:131161 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1162 std::string expected_full_version = "\"" + ua.full_version + "\"";
1163 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
1164 EXPECT_EQ(main_frame_ua_mobile_observed(), "?1");
1165 EXPECT_EQ(main_frame_ua_platform_observed(), "\"Android\"");
1166}
1167
1168// TODO(morlovich): Move this into WebContentsImplBrowserTest once things are
1169// refactored enough that UA client hints actually work in content/
1170IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, UserAgentOverrideClientHints) {
1171 content::WebContents* web_contents =
1172 browser()->tab_strip_model()->GetActiveWebContents();
1173
1174 ASSERT_TRUE(embedded_test_server()->Start());
1175 const std::string kHeaderPath = std::string("/echoheader?") +
1176 net::HttpRequestHeaders::kUserAgent +
1177 "&sec-ch-ua&sec-ch-ua-mobile";
1178 const GURL kUrl(embedded_test_server()->GetURL(kHeaderPath));
1179
1180 web_contents->SetUserAgentOverride(
1181 blink::UserAgentOverride::UserAgentOnly("foo"), false);
1182 // Not enabled first.
Lukasz Anforowiczb78290c2021-09-08 04:31:381183 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), kUrl));
Maks Orlovich73f374d2020-04-02 12:46:131184 std::string header_value;
1185 EXPECT_TRUE(ExecuteScriptAndExtractString(
1186 web_contents,
1187 "window.domAutomationController.send(document.body.textContent);",
1188 &header_value));
1189 EXPECT_EQ(std::string::npos, header_value.find("foo")) << header_value;
1190
1191 // Actually turn it on.
1192 web_contents->GetController()
1193 .GetLastCommittedEntry()
1194 ->SetIsOverridingUserAgent(true);
1195
Lukasz Anforowiczb78290c2021-09-08 04:31:381196 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), kUrl));
Maks Orlovich73f374d2020-04-02 12:46:131197 EXPECT_TRUE(ExecuteScriptAndExtractString(
1198 web_contents,
1199 "window.domAutomationController.send(document.body.textContent);",
1200 &header_value));
1201 // Since no value was provided for client hints, they are not sent.
1202 EXPECT_EQ("foo\nNone\nNone", header_value);
1203
1204 // Now actually provide values for the hints.
1205 blink::UserAgentOverride ua_override;
1206 ua_override.ua_string_override = "foobar";
1207 ua_override.ua_metadata_override.emplace();
1208 ua_override.ua_metadata_override->mobile = true;
Aaron Tagliaboschi9f01b682020-05-05 21:03:171209 ua_override.ua_metadata_override->brand_version_list.emplace_back(
1210 "Foobarnator", "3.14");
Maks Orlovich73f374d2020-04-02 12:46:131211 web_contents->SetUserAgentOverride(ua_override, false);
Lukasz Anforowiczb78290c2021-09-08 04:31:381212 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), kUrl));
Maks Orlovich73f374d2020-04-02 12:46:131213 EXPECT_TRUE(ExecuteScriptAndExtractString(
1214 web_contents,
1215 "window.domAutomationController.send(document.body.textContent);",
1216 &header_value));
Aaron Tagliaboschi9f01b682020-05-05 21:03:171217 EXPECT_EQ("foobar\n\"Foobarnator\";v=\"3.14\"\n?1", header_value);
Maks Orlovich73f374d2020-04-02 12:46:131218}
1219
Maks Orlovich7a588d82020-05-06 15:17:241220IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, EmptyAcceptCH) {
1221 // First navigate to a page that enables hints. No CH for it yet, since
1222 // nothing opted in.
1223 GURL gurl = accept_ch_with_lifetime_url();
1224 SetClientHintExpectationsOnMainFrame(false);
Lukasz Anforowiczb78290c2021-09-08 04:31:381225 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Maks Orlovich7a588d82020-05-06 15:17:241226
1227 // Now go to a page with blank Accept-CH. Should get hints from previous
1228 // visit.
1229 gurl = accept_ch_empty();
1230 SetClientHintExpectationsOnMainFrame(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:381231 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Maks Orlovich7a588d82020-05-06 15:17:241232
1233 // Visiting again should not expect them since we opted out again.
1234 SetClientHintExpectationsOnMainFrame(false);
Lukasz Anforowiczb78290c2021-09-08 04:31:381235 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Maks Orlovich7a588d82020-05-06 15:17:241236}
1237
1238IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, MergeAcceptCH) {
1239 // Go to page where some hints are enabled by headers, some by
1240 // http-equiv. It shouldn't get hints itself (due to first visit),
1241 // but subresources should get all the client hints.
1242 GURL gurl = http_equiv_accept_ch_merge();
1243 SetClientHintExpectationsOnMainFrame(false);
1244 SetClientHintExpectationsOnSubresources(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:381245 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Maks Orlovich7a588d82020-05-06 15:17:241246 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
1247}
1248
Maks Orlovich7227ce0d2020-02-28 17:13:161249void ClientHintsBrowserTest::TestProfilesIndependent(Browser* browser_a,
1250 Browser* browser_b) {
Maks Orlovichf0a2eed2020-05-02 20:08:211251 const GURL gurl = accept_ch_with_lifetime_url();
Maks Orlovich7227ce0d2020-02-28 17:13:161252
John Abd-El-Malekec1fc69e2021-01-28 19:14:411253 blink::UserAgentMetadata ua = embedder_support::GetUserAgentMetadata();
Maks Orlovich7227ce0d2020-02-28 17:13:161254
1255 // Navigate |browser_a| to a page that opts-into the header: the value should
1256 // end with the major version, and not contain the full version.
1257 SetClientHintExpectationsOnMainFrame(false);
Lukasz Anforowiczb78290c2021-09-08 04:31:381258 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser_a, gurl));
Aaron Tagliaboschi9f01b682020-05-05 21:03:171259 std::string expected_ua = ua.SerializeBrandVersionList();
Yoav Weissd33bacb2020-03-12 06:42:211260 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1261 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Maks Orlovich7227ce0d2020-02-28 17:13:161262
1263 // Try again on |browser_a|, the header should have an effect there.
1264 SetClientHintExpectationsOnMainFrame(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:381265 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser_a, gurl));
Yoav Weissd33bacb2020-03-12 06:42:211266 std::string expected_full_version = "\"" + ua.full_version + "\"";
1267 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1268 EXPECT_EQ(main_frame_ua_full_version_observed(), expected_full_version);
Maks Orlovich7227ce0d2020-02-28 17:13:161269
1270 // Navigate on |browser_b|. That should still only have the major
1271 // version.
1272 SetClientHintExpectationsOnMainFrame(false);
Lukasz Anforowiczb78290c2021-09-08 04:31:381273 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser_b, gurl));
Yoav Weissd33bacb2020-03-12 06:42:211274 EXPECT_EQ(main_frame_ua_observed(), expected_ua);
1275 EXPECT_TRUE(main_frame_ua_full_version_observed().empty());
Maks Orlovich7227ce0d2020-02-28 17:13:161276}
1277
1278// Check that client hints attached to navigation inside OTR profiles
1279// use the right settings, regular -> OTR direction.
Maks Orlovichf0a2eed2020-05-02 20:08:211280IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, OffTheRecordIndependent) {
Maks Orlovich7227ce0d2020-02-28 17:13:161281 TestProfilesIndependent(browser(),
1282 CreateIncognitoBrowser(browser()->profile()));
1283}
1284
1285// Check that client hints attached to navigation inside OTR profiles
1286// use the right settings, OTR -> regular direction.
Maks Orlovichf0a2eed2020-05-02 20:08:211287IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, OffTheRecordIndependent2) {
Maks Orlovich7227ce0d2020-02-28 17:13:161288 TestProfilesIndependent(CreateIncognitoBrowser(browser()->profile()),
1289 browser());
1290}
1291
Tarun Bansalea0d8262018-05-21 16:11:501292// Test that client hints are attached to third party subresources if
1293// AllowClientHintsToThirdParty feature is enabled.
Tarun Bansal9a7051f2018-07-10 18:30:051294IN_PROC_BROWSER_TEST_P(ClientHintsAllowThirdPartyBrowserTest,
Tarun Bansalea0d8262018-05-21 16:11:501295 ClientHintsThirdPartyAllowed) {
Yoav Weiss76e1afb762020-05-14 19:28:121296 GURL gurl;
1297 unsigned update_event_count = 0;
1298 if (GetParam()) {
1299 gurl = http_equiv_accept_ch_without_lifetime_img_localhost();
1300 } else {
1301 gurl = accept_ch_without_lifetime_img_localhost();
1302 update_event_count = 1;
1303 }
Tarun Bansal9a7051f2018-07-10 18:30:051304
Tarun Bansalea0d8262018-05-21 16:11:501305 base::HistogramTester histogram_tester;
1306
1307 SetClientHintExpectationsOnMainFrame(false);
1308 SetClientHintExpectationsOnSubresources(true);
1309
1310 // Add client hints for the embedded test server.
Lukasz Anforowiczb78290c2021-09-08 04:31:381311 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Yoav Weiss76e1afb762020-05-14 19:28:121312 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount",
1313 update_event_count);
Tarun Bansalea0d8262018-05-21 16:11:501314
Yoav Weissd33bacb2020-03-12 06:42:211315 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansalea0d8262018-05-21 16:11:501316
1317 // Requests to third party servers should not have client hints attached.
1318 EXPECT_EQ(1u, third_party_request_count_seen());
1319
Aaron Tagliaboschia09ec442019-09-18 15:29:031320 // Device memory, viewport width, DRP, and UA client hints should be sent to
1321 // the third-party when feature "AllowClientHintsToThirdParty" is enabled.
Aaron Tagliaboschiec5bce62021-06-24 18:50:091322 EXPECT_EQ(6u, third_party_client_hints_count_seen());
Tarun Bansalea0d8262018-05-21 16:11:501323}
1324
1325// Test that client hints are not attached to third party subresources if
1326// AllowClientHintsToThirdParty feature is not enabled.
Tarun Bansal9a7051f2018-07-10 18:30:051327IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansalea0d8262018-05-21 16:11:501328 ClientHintsThirdPartyNotAllowed) {
Yoav Weiss76e1afb762020-05-14 19:28:121329 GURL gurl;
1330 unsigned update_event_count = 0;
1331 if (GetParam()) {
1332 gurl = http_equiv_accept_ch_without_lifetime_img_localhost();
1333 } else {
1334 gurl = accept_ch_without_lifetime_img_localhost();
1335 update_event_count = 1;
1336 }
Tarun Bansal9a7051f2018-07-10 18:30:051337
Tarun Bansalea0d8262018-05-21 16:11:501338 base::HistogramTester histogram_tester;
1339
1340 SetClientHintExpectationsOnMainFrame(false);
1341 SetClientHintExpectationsOnSubresources(true);
1342
1343 // Add client hints for the embedded test server.
Lukasz Anforowiczb78290c2021-09-08 04:31:381344 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Yoav Weiss76e1afb762020-05-14 19:28:121345 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount",
1346 update_event_count);
Tarun Bansalea0d8262018-05-21 16:11:501347
Mike West2fddeeb72019-02-15 11:29:481348 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461349 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091350 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:211351 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansalea0d8262018-05-21 16:11:501352
1353 // Requests to third party servers should not have client hints attached.
1354 EXPECT_EQ(1u, third_party_request_count_seen());
1355
1356 // Client hints should not be sent to the third-party when feature
Mike West2fddeeb72019-02-15 11:29:481357 // "AllowClientHintsToThirdParty" is not enabled, with the exception of the
1358 // `Sec-CH-UA` hint, which is sent with every request.
Aaron Tagliaboschiec5bce62021-06-24 18:50:091359 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansalea0d8262018-05-21 16:11:501360}
1361
Tarun Bansaladd5e1812018-02-09 19:07:581362// Loads a HTTPS webpage that does not request persisting of client hints.
Tarun Bansal345418632018-06-29 11:07:041363// A same-origin iframe loaded by the webpage requests persistence of client
Maks Orlovich46619c732020-05-07 10:40:531364// hints. Since that's not a main frame, persistence should not happen.
Maks Orlovichf0a2eed2020-05-02 20:08:211365IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal345418632018-06-29 11:07:041366 PersistenceRequestIframe_SameOrigin) {
Maks Orlovichf0a2eed2020-05-02 20:08:211367 const GURL gurl = accept_ch_without_lifetime_with_iframe_url();
Tarun Bansal345418632018-06-29 11:07:041368 base::HistogramTester histogram_tester;
1369 ContentSettingsForOneType host_settings;
1370
1371 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141372 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal345418632018-06-29 11:07:041373 &host_settings);
1374 EXPECT_EQ(0u, host_settings.size());
1375
Lukasz Anforowiczb78290c2021-09-08 04:31:381376 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Tarun Bansal345418632018-06-29 11:07:041377
Maks Orlovich46619c732020-05-07 10:40:531378 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
Tarun Bansal345418632018-06-29 11:07:041379
1380 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281381 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal345418632018-06-29 11:07:041382
1383 // accept_ch_without_lifetime_with_iframe_url() loads
1384 // accept_ch_with_lifetime() in an iframe. The request to persist client
Maks Orlovich46619c732020-05-07 10:40:531385 // hints from accept_ch_with_lifetime() should not be persisted.
1386 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1387 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
Tarun Bansal345418632018-06-29 11:07:041388}
1389
1390// Loads a HTTPS webpage that does not request persisting of client hints.
1391// An iframe loaded by the webpage from an cross origin server requests
1392// persistence of client hints.
1393// Verify that the request from the cross origin iframe is not honored, and
1394// client hints preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051395IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal345418632018-06-29 11:07:041396 DisregardPersistenceRequestIframe_CrossOrigin) {
Tarun Bansal9a7051f2018-07-10 18:30:051397 const GURL gurl =
1398 GetParam() ? http_equiv_accept_ch_without_lifetime_with_iframe_url()
1399 : accept_ch_without_lifetime_with_iframe_url();
1400
1401 intercept_iframe_resource_ = gurl.path();
1402 intercept_to_http_equiv_iframe_ = GetParam();
1403
Tarun Bansaladd5e1812018-02-09 19:07:581404 base::HistogramTester histogram_tester;
1405 ContentSettingsForOneType host_settings;
1406
1407 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141408 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansaladd5e1812018-02-09 19:07:581409 &host_settings);
1410 EXPECT_EQ(0u, host_settings.size());
1411
Lukasz Anforowiczb78290c2021-09-08 04:31:381412 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Tarun Bansaladd5e1812018-02-09 19:07:581413
1414 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1415
1416 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281417 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansaladd5e1812018-02-09 19:07:581418
1419 // accept_ch_without_lifetime_with_iframe_url() loads
Tarun Bansal345418632018-06-29 11:07:041420 // accept_ch_with_lifetime() in a cross origin iframe. The request to persist
1421 // client hints from accept_ch_with_lifetime() should be disregarded.
Tarun Bansaladd5e1812018-02-09 19:07:581422 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1423 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1424}
1425
Tarun Bansal62cc3542018-06-27 23:53:301426// Loads a HTTPS webpage that does not request persisting of client hints.
1427// A subresource loaded by the webpage requests persistence of client hints.
1428// Verify that the request from the subresource is not honored, and client hints
1429// preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051430IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal62cc3542018-06-27 23:53:301431 DisregardPersistenceRequestSubresource) {
Tarun Bansal9a7051f2018-07-10 18:30:051432 const GURL gurl =
1433 GetParam() ? http_equiv_accept_ch_without_lifetime_with_subresource_url()
1434 : accept_ch_without_lifetime_with_subresource_url();
1435
Tarun Bansal62cc3542018-06-27 23:53:301436 base::HistogramTester histogram_tester;
1437 ContentSettingsForOneType host_settings;
1438
1439 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141440 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal62cc3542018-06-27 23:53:301441 &host_settings);
1442 EXPECT_EQ(0u, host_settings.size());
1443
Lukasz Anforowiczb78290c2021-09-08 04:31:381444 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Tarun Bansal62cc3542018-06-27 23:53:301445
1446 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1447
1448 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281449 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal62cc3542018-06-27 23:53:301450
1451 // accept_ch_without_lifetime_with_subresource_url() loads
1452 // accept_ch_with_lifetime() as a subresource. The request to persist client
1453 // hints from accept_ch_with_lifetime() should be disregarded.
1454 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1455 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1456}
1457
1458// Loads a HTTPS webpage that does not request persisting of client hints.
1459// A subresource loaded by the webpage in an iframe requests persistence of
1460// client hints. Verify that the request from the subresource in the iframe
1461// is not honored, and client hints preference is not persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051462IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal62cc3542018-06-27 23:53:301463 DisregardPersistenceRequestSubresourceIframe) {
Tarun Bansal9a7051f2018-07-10 18:30:051464 const GURL gurl =
1465 GetParam()
1466 ? http_equiv_accept_ch_without_lifetime_with_subresource_iframe_url()
1467 : accept_ch_without_lifetime_with_subresource_iframe_url();
1468
Tarun Bansal62cc3542018-06-27 23:53:301469 base::HistogramTester histogram_tester;
1470 ContentSettingsForOneType host_settings;
1471
1472 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141473 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal62cc3542018-06-27 23:53:301474 &host_settings);
1475 EXPECT_EQ(0u, host_settings.size());
1476
Lukasz Anforowiczb78290c2021-09-08 04:31:381477 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Tarun Bansal62cc3542018-06-27 23:53:301478
1479 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1480
1481 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281482 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal62cc3542018-06-27 23:53:301483
Tarun Bansal9a7051f2018-07-10 18:30:051484 // |gurl| loads accept_ch_with_lifetime() or
1485 // http_equiv_accept_ch_with_lifetime() as a subresource in an iframe. The
1486 // request to persist client hints from accept_ch_with_lifetime() or
1487 // http_equiv_accept_ch_with_lifetime() should be disregarded.
Tarun Bansal62cc3542018-06-27 23:53:301488 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1489 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1490}
1491
Tarun Bansal3b330b02017-11-09 19:03:141492// Loads a HTTP local webpage (which qualifies as a secure context) that
1493// requests persisting of client hints. Verifies that the browser receives the
1494// mojo notification from the renderer and persists the client hints to the
1495// disk.
Maks Orlovichf0a2eed2020-05-02 20:08:211496IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal3b330b02017-11-09 19:03:141497 ClientHintsLifetimeFollowedByNoClientHintHttpLocal) {
Maks Orlovichf0a2eed2020-05-02 20:08:211498 const GURL gurl = accept_ch_with_lifetime_http_local_url();
Tarun Bansal9a7051f2018-07-10 18:30:051499
Tarun Bansal3b330b02017-11-09 19:03:141500 base::HistogramTester histogram_tester;
1501 ContentSettingsForOneType host_settings;
1502
1503 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141504 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3b330b02017-11-09 19:03:141505 &host_settings);
1506 EXPECT_EQ(0u, host_settings.size());
1507
Lukasz Anforowiczb78290c2021-09-08 04:31:381508 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Tarun Bansal3b330b02017-11-09 19:03:141509
1510 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1511
1512 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281513 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal3b330b02017-11-09 19:03:141514
Yoav Weissd33bacb2020-03-12 06:42:211515 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1516 expected_client_hints_number, 1);
Yoav Weiss76e1afb762020-05-14 19:28:121517 // |gurl| sets client hints persist duration to 3600 seconds, but a maximum
1518 // value is registered instead.
Tarun Bansal3b330b02017-11-09 19:03:141519 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121520 uma_histogram_max_value, 1);
Tarun Bansal3b330b02017-11-09 19:03:141521
1522 base::RunLoop().RunUntilIdle();
1523
1524 // Clients hints preferences for one origin should be persisted.
1525 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141526 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3b330b02017-11-09 19:03:141527 &host_settings);
1528 EXPECT_EQ(1u, host_settings.size());
1529
Tarun Bansal229647bd002018-02-27 17:33:361530 SetClientHintExpectationsOnMainFrame(true);
1531 SetClientHintExpectationsOnSubresources(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:381532 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1533 browser(), without_accept_ch_without_lifetime_local_url()));
Tarun Bansal3b330b02017-11-09 19:03:141534
Mike West2fddeeb72019-02-15 11:29:481535 // The user agent hint is attached to all three requests:
1536 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461537 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091538 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481539
Yoav Weissd33bacb2020-03-12 06:42:211540 // Expected number of hints attached to the image request, and the same number
1541 // to the main frame request.
1542 EXPECT_EQ(expected_client_hints_number * 2,
1543 count_client_hints_headers_seen());
Tarun Bansal3b330b02017-11-09 19:03:141544}
1545
Tarun Bansal0b8b7afd2017-08-25 03:52:161546// Loads a webpage that does not request persisting of client hints.
1547IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest, NoClientHintsHttps) {
1548 base::HistogramTester histogram_tester;
Lukasz Anforowiczb78290c2021-09-08 04:31:381549 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1550 browser(), without_accept_ch_without_lifetime_url()));
Tarun Bansal0b8b7afd2017-08-25 03:52:161551
1552 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1553
1554 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281555 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal0b8b7afd2017-08-25 03:52:161556
1557 // no_client_hints_url() does not sets the client hints.
1558 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1559 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1560}
1561
Tarun Bansal9a7051f2018-07-10 18:30:051562IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal1965b042017-09-07 04:59:191563 ClientHintsLifetimeFollowedByNoClientHint) {
Tarun Bansal9a7051f2018-07-10 18:30:051564 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1565 : accept_ch_with_lifetime_url();
1566
Tarun Bansal1965b042017-09-07 04:59:191567 base::HistogramTester histogram_tester;
1568 ContentSettingsForOneType host_settings;
1569
1570 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141571 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal1965b042017-09-07 04:59:191572 &host_settings);
1573 EXPECT_EQ(0u, host_settings.size());
1574
Maks Orlovichf0a2eed2020-05-02 20:08:211575 // Fetching |gurl| should persist the request for client hints iff using
1576 // headers and not http-equiv.
Lukasz Anforowiczb78290c2021-09-08 04:31:381577 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Tarun Bansal1965b042017-09-07 04:59:191578
Maks Orlovichf0a2eed2020-05-02 20:08:211579 if (GetParam())
1580 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 0);
1581 else
1582 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
Tarun Bansal1965b042017-09-07 04:59:191583
1584 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281585 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal1965b042017-09-07 04:59:191586 base::RunLoop().RunUntilIdle();
1587
Maks Orlovichf0a2eed2020-05-02 20:08:211588 if (GetParam()) {
1589 histogram_tester.ExpectTotalCount("ClientHints.UpdateSize", 0);
1590 histogram_tester.ExpectTotalCount("ClientHints.PersistDuration", 0);
1591 } else {
1592 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1593 expected_client_hints_number, 1);
1594 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:121595 // seconds, but a maximum value is registered instead.
Maks Orlovichf0a2eed2020-05-02 20:08:211596 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121597 uma_histogram_max_value, 1);
Tarun Bansal1965b042017-09-07 04:59:191598
Maks Orlovichf0a2eed2020-05-02 20:08:211599 // Clients hints preferences for one origin should be persisted.
1600 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1601 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Illia Klimov48f643c2020-11-05 20:06:141602 &host_settings);
Maks Orlovichf0a2eed2020-05-02 20:08:211603 EXPECT_EQ(1u, host_settings.size());
1604 }
1605
1606 SetClientHintExpectationsOnMainFrame(!GetParam());
1607 SetClientHintExpectationsOnSubresources(!GetParam());
Lukasz Anforowiczb78290c2021-09-08 04:31:381608 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1609 browser(), without_accept_ch_without_lifetime_url()));
Tarun Bansal6bf54302017-10-02 07:39:141610
Mike West2fddeeb72019-02-15 11:29:481611 // The user agent hint is attached to all three requests:
1612 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461613 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091614 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481615
Yoav Weissd33bacb2020-03-12 06:42:211616 // Expected number of hints attached to the image request, and the same number
1617 // to the main frame request.
Maks Orlovichf0a2eed2020-05-02 20:08:211618 EXPECT_EQ(GetParam() ? 0 : expected_client_hints_number * 2,
Yoav Weissd33bacb2020-03-12 06:42:211619 count_client_hints_headers_seen());
Tarun Bansal1965b042017-09-07 04:59:191620}
1621
Tarun Bansal293a7b6c2018-12-05 17:41:121622// The test first fetches a page that sets Accept-CH-Lifetime. Next, it fetches
1623// a URL from a different origin. However, that URL response redirects to the
1624// same origin from where the first page was fetched. The test verifies that
1625// on receiving redirect to an origin for which the browser has persisted client
1626// hints prefs, the browser attaches the client hints headers when fetching the
1627// redirected URL.
Maks Orlovichf0a2eed2020-05-02 20:08:211628IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal293a7b6c2018-12-05 17:41:121629 ClientHintsLifetimeFollowedByRedirectToNoClientHint) {
Maks Orlovichf0a2eed2020-05-02 20:08:211630 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal293a7b6c2018-12-05 17:41:121631
1632 base::HistogramTester histogram_tester;
1633 ContentSettingsForOneType host_settings;
1634
1635 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141636 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal293a7b6c2018-12-05 17:41:121637 &host_settings);
1638 EXPECT_EQ(0u, host_settings.size());
1639
1640 // Fetching |gurl| should persist the request for client hints.
Lukasz Anforowiczb78290c2021-09-08 04:31:381641 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Tarun Bansal293a7b6c2018-12-05 17:41:121642
1643 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1644
1645 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281646 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal293a7b6c2018-12-05 17:41:121647
Yoav Weissd33bacb2020-03-12 06:42:211648 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1649 expected_client_hints_number, 1);
Tarun Bansal293a7b6c2018-12-05 17:41:121650 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:121651 // seconds, but a maximum value is registered instead.
Tarun Bansal293a7b6c2018-12-05 17:41:121652 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121653 uma_histogram_max_value, 1);
Tarun Bansal293a7b6c2018-12-05 17:41:121654 base::RunLoop().RunUntilIdle();
1655
1656 // Clients hints preferences for one origin should be persisted.
1657 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141658 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal293a7b6c2018-12-05 17:41:121659 &host_settings);
1660 EXPECT_EQ(1u, host_settings.size());
1661
1662 SetClientHintExpectationsOnMainFrame(true);
1663 SetClientHintExpectationsOnSubresources(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:381664 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), redirect_url()));
Tarun Bansal293a7b6c2018-12-05 17:41:121665
Mike West2fddeeb72019-02-15 11:29:481666 // The user agent hint is attached to all three requests:
1667 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461668 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091669 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481670
Yoav Weissd33bacb2020-03-12 06:42:211671 // Expected number of hints attached to the image request, and the same number
1672 // to the main frame request.
1673 EXPECT_EQ(expected_client_hints_number * 2,
1674 count_client_hints_headers_seen());
Tarun Bansal293a7b6c2018-12-05 17:41:121675}
1676
Tarun Bansala0c1fc32018-10-03 16:14:521677// Ensure that even when cookies are blocked, client hint preferences are
Tarun Bansala61f0f62017-10-24 23:53:051678// persisted.
Maks Orlovichf0a2eed2020-05-02 20:08:211679IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521680 ClientHintsLifetimePersistedCookiesBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211681 const GURL gurl_with = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:051682
Tarun Bansala61f0f62017-10-24 23:53:051683 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
1684 CookieSettingsFactory::GetForProfile(browser()->profile());
1685 base::HistogramTester histogram_tester;
1686 ContentSettingsForOneType host_settings;
1687
1688 // Block cookies.
1689 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansala0c1fc32018-10-03 16:14:521690 ->SetContentSettingDefaultScope(gurl_with, GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451691 ContentSettingsType::COOKIES,
Illia Klimov48f643c2020-11-05 20:06:141692 CONTENT_SETTING_BLOCK);
Tarun Bansala61f0f62017-10-24 23:53:051693
Tarun Bansala0c1fc32018-10-03 16:14:521694 // Fetching |gurl_with| should persist the request for client hints.
Lukasz Anforowiczb78290c2021-09-08 04:31:381695 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl_with));
Tarun Bansala0c1fc32018-10-03 16:14:521696 histogram_tester.ExpectTotalCount("ClientHints.UpdateEventCount", 1);
Tarun Bansala61f0f62017-10-24 23:53:051697 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141698 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051699 &host_settings);
1700 EXPECT_EQ(1u, host_settings.size());
Tarun Bansala0c1fc32018-10-03 16:14:521701 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:051702}
1703
Maks Orlovichf0a2eed2020-05-02 20:08:211704IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:521705 ClientHintsLifetimeAttachedCookiesBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211706 const GURL gurl_with = accept_ch_with_lifetime_url();
1707 const GURL gurl_without = accept_ch_without_lifetime_url();
Tarun Bansala61f0f62017-10-24 23:53:051708 base::HistogramTester histogram_tester;
1709 ContentSettingsForOneType host_settings;
1710
1711 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141712 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051713 &host_settings);
1714 EXPECT_EQ(0u, host_settings.size());
1715
Tarun Bansal9a7051f2018-07-10 18:30:051716 // Fetching |gurl_with| should persist the request for client hints.
Lukasz Anforowiczb78290c2021-09-08 04:31:381717 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl_with));
Tarun Bansala61f0f62017-10-24 23:53:051718 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1719 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281720 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Maks Orlovichf0a2eed2020-05-02 20:08:211721 base::RunLoop().RunUntilIdle();
Tarun Bansala61f0f62017-10-24 23:53:051722
Yoav Weissd33bacb2020-03-12 06:42:211723 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1724 expected_client_hints_number, 1);
Yoav Weiss76e1afb762020-05-14 19:28:121725 // |gurl_with| tries to set client hints persist duration to 3600 seconds, but
1726 // a maximum value is registered instead.
Tarun Bansala61f0f62017-10-24 23:53:051727 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121728 uma_histogram_max_value, 1);
Tarun Bansala61f0f62017-10-24 23:53:051729
1730 // Clients hints preferences for one origin should be persisted.
1731 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141732 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051733 &host_settings);
1734 EXPECT_EQ(1u, host_settings.size());
1735
Tarun Bansala0c1fc32018-10-03 16:14:521736 // Block the cookies: Client hints should be attached.
Tarun Bansala61f0f62017-10-24 23:53:051737 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Tarun Bansal9a7051f2018-07-10 18:30:051738 ->SetContentSettingDefaultScope(gurl_without, GURL(),
Darin Fisher42f5e7d2019-10-30 07:15:451739 ContentSettingsType::COOKIES,
Illia Klimov48f643c2020-11-05 20:06:141740 CONTENT_SETTING_BLOCK);
Tarun Bansala61f0f62017-10-24 23:53:051741
Tarun Bansal229647bd002018-02-27 17:33:361742 SetClientHintExpectationsOnMainFrame(true);
1743 SetClientHintExpectationsOnSubresources(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:381744 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1745 browser(), without_accept_ch_without_lifetime_url()));
Tarun Bansal79df868e2018-03-20 23:01:361746
Mike West2fddeeb72019-02-15 11:29:481747 // The user agent hint is attached to all three requests:
1748 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461749 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091750 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481751
Yoav Weissd33bacb2020-03-12 06:42:211752 // Expected number of hints attached to the image request, and the same number
1753 // to the main frame request.
1754 EXPECT_EQ(expected_client_hints_number * 2,
1755 count_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051756
1757 // Clear settings.
1758 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451759 ->ClearSettingsForOneType(ContentSettingsType::COOKIES);
Tarun Bansala61f0f62017-10-24 23:53:051760}
1761
1762// Ensure that when the JavaScript is blocked, client hint preferences are not
1763// persisted.
Tarun Bansal9a7051f2018-07-10 18:30:051764IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala61f0f62017-10-24 23:53:051765 ClientHintsLifetimeNotPersistedJavaScriptBlocked) {
1766 ContentSettingsForOneType host_settings;
1767
1768 // Start a navigation. This navigation makes it possible to block JavaScript
1769 // later.
Lukasz Anforowiczb78290c2021-09-08 04:31:381770 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1771 browser(), without_accept_ch_without_lifetime_url()));
Tarun Bansala61f0f62017-10-24 23:53:051772
Tarun Bansal9a7051f2018-07-10 18:30:051773 const GURL gurl =
1774 GetParam() ? http_equiv_accept_ch_without_lifetime_with_iframe_url()
1775 : accept_ch_with_lifetime_url();
1776
Tarun Bansala61f0f62017-10-24 23:53:051777 // Block the JavaScript: Client hint preferences should not be persisted.
1778 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141779 ->SetContentSettingDefaultScope(
1780 gurl, GURL(), ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_BLOCK);
Lukasz Anforowiczb78290c2021-09-08 04:31:381781 ASSERT_TRUE(
1782 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url()));
Tarun Bansala61f0f62017-10-24 23:53:051783 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141784 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051785 &host_settings);
1786 EXPECT_EQ(0u, host_settings.size());
Tarun Bansalc211d8b2018-03-19 19:21:581787 VerifyContentSettingsNotNotified();
Tarun Bansala61f0f62017-10-24 23:53:051788
1789 // Allow the JavaScript: Client hint preferences should be persisted.
1790 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141791 ->SetContentSettingDefaultScope(
1792 gurl, GURL(), ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_ALLOW);
Lukasz Anforowiczb78290c2021-09-08 04:31:381793 ASSERT_TRUE(
1794 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url()));
Tarun Bansala61f0f62017-10-24 23:53:051795 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141796 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051797 &host_settings);
1798 EXPECT_EQ(1u, host_settings.size());
Tarun Bansal593790112018-03-20 04:53:341799
1800 // Clear settings.
1801 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451802 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansala61f0f62017-10-24 23:53:051803}
1804
1805// Ensure that when the JavaScript is blocked, persisted client hints are not
1806// attached to the request headers.
Maks Orlovichf0a2eed2020-05-02 20:08:211807IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansala61f0f62017-10-24 23:53:051808 ClientHintsLifetimeNotAttachedJavaScriptBlocked) {
Maks Orlovichf0a2eed2020-05-02 20:08:211809 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:051810
Tarun Bansala61f0f62017-10-24 23:53:051811 base::HistogramTester histogram_tester;
1812 ContentSettingsForOneType host_settings;
1813
1814 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141815 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051816 &host_settings);
1817 EXPECT_EQ(0u, host_settings.size());
1818
1819 // Fetching accept_ch_with_lifetime_url() should persist the request for
1820 // client hints.
Lukasz Anforowiczb78290c2021-09-08 04:31:381821 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Tarun Bansala61f0f62017-10-24 23:53:051822 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
1823 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:281824 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Mike West2fddeeb72019-02-15 11:29:481825 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461826 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091827 EXPECT_EQ(1u, count_ua_platform_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051828
Yoav Weissd33bacb2020-03-12 06:42:211829 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
1830 expected_client_hints_number, 1);
Tarun Bansala61f0f62017-10-24 23:53:051831 // accept_ch_with_lifetime_url() tries to set client hints persist duration to
Yoav Weiss76e1afb762020-05-14 19:28:121832 // 3600 seconds, but a maximum value is registered instead.
Tarun Bansala61f0f62017-10-24 23:53:051833 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:121834 uma_histogram_max_value, 1);
Tarun Bansala61f0f62017-10-24 23:53:051835 base::RunLoop().RunUntilIdle();
1836
1837 // Clients hints preferences for one origin should be persisted.
1838 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141839 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansala61f0f62017-10-24 23:53:051840 &host_settings);
1841 EXPECT_EQ(1u, host_settings.size());
1842
Changwan Ryu434c3a32019-07-30 23:42:581843 // Block JavaScript via WebPreferences: Client hints should not be attached.
1844 SetJsEnabledForActiveView(false);
1845
1846 SetClientHintExpectationsOnMainFrame(false);
1847 SetClientHintExpectationsOnSubresources(false);
Lukasz Anforowiczb78290c2021-09-08 04:31:381848 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1849 browser(), without_accept_ch_without_lifetime_url()));
Changwan Ryu434c3a32019-07-30 23:42:581850
1851 EXPECT_EQ(0u, count_client_hints_headers_seen());
1852 VerifyContentSettingsNotNotified();
1853 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461854 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091855 EXPECT_EQ(1u, count_ua_platform_client_hints_headers_seen());
Changwan Ryu434c3a32019-07-30 23:42:581856
1857 SetJsEnabledForActiveView(true);
1858
1859 // Block JavaScript via ContentSetting: Client hints should not be attached.
Tarun Bansala61f0f62017-10-24 23:53:051860 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1861 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
Darin Fisher42f5e7d2019-10-30 07:15:451862 GURL(), ContentSettingsType::JAVASCRIPT,
Illia Klimov48f643c2020-11-05 20:06:141863 CONTENT_SETTING_BLOCK);
Lukasz Anforowiczb78290c2021-09-08 04:31:381864 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1865 browser(), without_accept_ch_without_lifetime_url()));
Tarun Bansala61f0f62017-10-24 23:53:051866 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansalc211d8b2018-03-19 19:21:581867 VerifyContentSettingsNotNotified();
Mike West2fddeeb72019-02-15 11:29:481868 EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461869 EXPECT_EQ(1u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091870 EXPECT_EQ(1u, count_ua_platform_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051871
Changwan Ryu434c3a32019-07-30 23:42:581872 // Allow JavaScript: Client hints should now be attached.
Tarun Bansala61f0f62017-10-24 23:53:051873 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1874 ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
Darin Fisher42f5e7d2019-10-30 07:15:451875 GURL(), ContentSettingsType::JAVASCRIPT,
Illia Klimov48f643c2020-11-05 20:06:141876 CONTENT_SETTING_ALLOW);
Tarun Bansala61f0f62017-10-24 23:53:051877
Tarun Bansal229647bd002018-02-27 17:33:361878 SetClientHintExpectationsOnMainFrame(true);
1879 SetClientHintExpectationsOnSubresources(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:381880 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1881 browser(), without_accept_ch_without_lifetime_url()));
Tarun Bansal79df868e2018-03-20 23:01:361882
Mike West2fddeeb72019-02-15 11:29:481883 // The user agent hint is attached to all three requests:
1884 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461885 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091886 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:481887
Yoav Weissd33bacb2020-03-12 06:42:211888 // Expected number of hints attached to the image request, and the same number
1889 // to the main frame request.
1890 EXPECT_EQ(expected_client_hints_number * 2,
1891 count_client_hints_headers_seen());
Tarun Bansala61f0f62017-10-24 23:53:051892
1893 // Clear settings.
1894 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451895 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansala61f0f62017-10-24 23:53:051896}
1897
Tarun Bansal73502f92019-04-16 21:21:191898// Test that if the content settings are malformed, then the browser does not
1899// crash.
1900IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
1901 ClientHintsMalformedContentSettings) {
1902 ContentSettingsForOneType client_hints_settings;
1903 HostContentSettingsMap* host_content_settings_map =
1904 HostContentSettingsMapFactory::GetForProfile(browser()->profile());
1905
1906 // Add setting for the host.
1907 std::unique_ptr<base::ListValue> expiration_times_list =
1908 std::make_unique<base::ListValue>();
Clark DuVallf138b4d2021-09-01 18:07:051909 expiration_times_list->Append(42 /* client hint value */);
Tarun Bansal73502f92019-04-16 21:21:191910 auto expiration_times_dictionary = std::make_unique<base::DictionaryValue>();
1911 expiration_times_dictionary->SetList("client_hints",
1912 std::move(expiration_times_list));
Reilly Grant655445f2021-07-14 02:52:231913 expiration_times_dictionary->SetDoubleKey(
Aaron Tagliaboschi3c96a682019-10-29 18:10:281914 "expiration_time",
1915 (base::Time::Now() + base::TimeDelta::FromDays(1)).ToDoubleT());
Tarun Bansal73502f92019-04-16 21:21:191916 host_content_settings_map->SetWebsiteSettingDefaultScope(
1917 without_accept_ch_without_lifetime_url(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141918 ContentSettingsType::CLIENT_HINTS,
Tarun Bansal73502f92019-04-16 21:21:191919 std::make_unique<base::Value>(expiration_times_dictionary->Clone()));
1920
1921 // Reading the settings should now return one setting.
1922 host_content_settings_map->GetSettingsForOneType(
Illia Klimov48f643c2020-11-05 20:06:141923 ContentSettingsType::CLIENT_HINTS, &client_hints_settings);
Tarun Bansal73502f92019-04-16 21:21:191924 EXPECT_EQ(1U, client_hints_settings.size());
1925
1926 SetClientHintExpectationsOnMainFrame(false);
1927 SetClientHintExpectationsOnSubresources(false);
Lukasz Anforowiczb78290c2021-09-08 04:31:381928 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1929 browser(), without_accept_ch_without_lifetime_url()));
Tarun Bansal73502f92019-04-16 21:21:191930}
1931
Tarun Bansal229647bd002018-02-27 17:33:361932// Ensure that when the JavaScript is blocked, client hints requested using
Tarun Bansal3f343d7c2018-03-02 18:48:001933// Accept-CH are not attached to the request headers for subresources.
Tarun Bansal9a7051f2018-07-10 18:30:051934IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansal229647bd002018-02-27 17:33:361935 ClientHintsNoLifetimeScriptNotAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:051936 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
1937 : accept_ch_with_lifetime_url();
1938
Tarun Bansal1965b042017-09-07 04:59:191939 base::HistogramTester histogram_tester;
1940 ContentSettingsForOneType host_settings;
1941
1942 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:141943 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal1965b042017-09-07 04:59:191944 &host_settings);
1945 EXPECT_EQ(0u, host_settings.size());
1946
Tarun Bansal3f343d7c2018-03-02 18:48:001947 // Block the Javascript: Client hints should not be attached.
1948 SetClientHintExpectationsOnSubresources(false);
Tarun Bansal229647bd002018-02-27 17:33:361949 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1950 ->SetContentSettingDefaultScope(
1951 accept_ch_without_lifetime_img_localhost(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141952 ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_BLOCK);
Lukasz Anforowiczb78290c2021-09-08 04:31:381953 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1954 browser(), accept_ch_without_lifetime_img_localhost()));
Mike West2fddeeb72019-02-15 11:29:481955 EXPECT_EQ(0u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461956 EXPECT_EQ(0u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091957 EXPECT_EQ(0u, count_ua_platform_client_hints_headers_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001958 EXPECT_EQ(0u, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361959 EXPECT_EQ(1u, third_party_request_count_seen());
Tarun Bansal3f343d7c2018-03-02 18:48:001960 EXPECT_EQ(0u, third_party_client_hints_count_seen());
Tarun Bansal1965b042017-09-07 04:59:191961
Tarun Bansal3f343d7c2018-03-02 18:48:001962 // Allow the Javascript: Client hints should now be attached.
Tarun Bansal229647bd002018-02-27 17:33:361963 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1964 ->SetContentSettingDefaultScope(
1965 accept_ch_without_lifetime_img_localhost(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141966 ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_ALLOW);
Tarun Bansal1965b042017-09-07 04:59:191967
Tarun Bansal229647bd002018-02-27 17:33:361968 SetClientHintExpectationsOnSubresources(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:381969 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1970 browser(), accept_ch_without_lifetime_img_localhost()));
Tarun Bansal3f343d7c2018-03-02 18:48:001971
Mike West2fddeeb72019-02-15 11:29:481972 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461973 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091974 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Aaron Tagliaboschi150fb9042020-05-14 22:20:371975 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361976 EXPECT_EQ(2u, third_party_request_count_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091977 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansalc211d8b2018-03-19 19:21:581978 VerifyContentSettingsNotNotified();
Tarun Bansal1965b042017-09-07 04:59:191979
Tarun Bansal229647bd002018-02-27 17:33:361980 // Clear settings.
1981 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:451982 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansal1965b042017-09-07 04:59:191983
Tarun Bansal229647bd002018-02-27 17:33:361984 // Block the Javascript again: Client hints should not be attached.
Tarun Bansal3f343d7c2018-03-02 18:48:001985 SetClientHintExpectationsOnSubresources(false);
Tarun Bansal229647bd002018-02-27 17:33:361986 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
1987 ->SetContentSettingDefaultScope(
1988 accept_ch_without_lifetime_img_localhost(), GURL(),
Illia Klimov48f643c2020-11-05 20:06:141989 ContentSettingsType::JAVASCRIPT, CONTENT_SETTING_BLOCK);
Lukasz Anforowiczb78290c2021-09-08 04:31:381990 ASSERT_TRUE(ui_test_utils::NavigateToURL(
1991 browser(), accept_ch_without_lifetime_img_localhost()));
Mike West2fddeeb72019-02-15 11:29:481992 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:461993 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091994 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Aaron Tagliaboschi150fb9042020-05-14 22:20:371995 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansal229647bd002018-02-27 17:33:361996 EXPECT_EQ(3u, third_party_request_count_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:091997 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansal593790112018-03-20 04:53:341998
1999 // Clear settings.
2000 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:452001 ->ClearSettingsForOneType(ContentSettingsType::JAVASCRIPT);
Tarun Bansal229647bd002018-02-27 17:33:362002}
2003
Tarun Bansala0c1fc32018-10-03 16:14:522004// Ensure that when the cookies is blocked, client hints are attached to the
Tarun Bansal3f343d7c2018-03-02 18:48:002005// request headers.
Tarun Bansal9a7051f2018-07-10 18:30:052006IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest,
Tarun Bansala0c1fc32018-10-03 16:14:522007 ClientHintsLifetimeCookiesNotAllowed) {
Tarun Bansal9a7051f2018-07-10 18:30:052008 const GURL gurl = GetParam()
2009 ? http_equiv_accept_ch_without_lifetime_img_localhost()
2010 : accept_ch_without_lifetime_img_localhost();
2011
Tarun Bansal229647bd002018-02-27 17:33:362012 base::HistogramTester histogram_tester;
2013 ContentSettingsForOneType host_settings;
2014 scoped_refptr<content_settings::CookieSettings> cookie_settings_ =
2015 CookieSettingsFactory::GetForProfile(browser()->profile());
2016
Tarun Bansal1965b042017-09-07 04:59:192017 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:142018 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal1965b042017-09-07 04:59:192019 &host_settings);
2020 EXPECT_EQ(0u, host_settings.size());
2021
Tarun Bansal229647bd002018-02-27 17:33:362022 // Block cookies.
2023 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Illia Klimov48f643c2020-11-05 20:06:142024 ->SetContentSettingDefaultScope(
2025 gurl, GURL(), ContentSettingsType::COOKIES, CONTENT_SETTING_BLOCK);
Tarun Bansal229647bd002018-02-27 17:33:362026 base::RunLoop().RunUntilIdle();
2027
Tarun Bansal229647bd002018-02-27 17:33:362028 SetClientHintExpectationsOnSubresources(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:382029 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Mike West2fddeeb72019-02-15 11:29:482030 EXPECT_EQ(2u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462031 EXPECT_EQ(2u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092032 EXPECT_EQ(2u, count_ua_platform_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:212033 EXPECT_EQ(expected_client_hints_number, count_client_hints_headers_seen());
Tarun Bansala0c1fc32018-10-03 16:14:522034 EXPECT_EQ(1u, third_party_request_count_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092035 EXPECT_EQ(3u, third_party_client_hints_count_seen());
Tarun Bansal593790112018-03-20 04:53:342036
2037 // Clear settings.
2038 HostContentSettingsMapFactory::GetForProfile(browser()->profile())
Darin Fisher42f5e7d2019-10-30 07:15:452039 ->ClearSettingsForOneType(ContentSettingsType::COOKIES);
Tarun Bansal1965b042017-09-07 04:59:192040}
2041
Tarun Bansal3ce0ca42018-06-25 22:52:222042// Verify that client hints are sent in the incognito profiles, and server
2043// client hint opt-ins are honored within the incognito profile.
Maks Orlovichf0a2eed2020-05-02 20:08:212044IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTest,
Tarun Bansal3ce0ca42018-06-25 22:52:222045 ClientHintsLifetimeFollowedByNoClientHintIncognito) {
Maks Orlovichf0a2eed2020-05-02 20:08:212046 const GURL gurl = accept_ch_with_lifetime_url();
Tarun Bansal9a7051f2018-07-10 18:30:052047
Tarun Bansal3ce0ca42018-06-25 22:52:222048 base::HistogramTester histogram_tester;
2049 Browser* incognito = CreateIncognitoBrowser();
2050 ContentSettingsForOneType host_settings;
2051
2052 HostContentSettingsMapFactory::GetForProfile(incognito->profile())
Illia Klimov48f643c2020-11-05 20:06:142053 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3ce0ca42018-06-25 22:52:222054 &host_settings);
2055 EXPECT_EQ(0u, host_settings.size());
2056
Tarun Bansal9a7051f2018-07-10 18:30:052057 // Fetching |gurl| should persist the request for client hints.
Lukasz Anforowiczb78290c2021-09-08 04:31:382058 ASSERT_TRUE(ui_test_utils::NavigateToURL(incognito, gurl));
Tarun Bansal3ce0ca42018-06-25 22:52:222059
2060 histogram_tester.ExpectUniqueSample("ClientHints.UpdateEventCount", 1, 1);
2061
2062 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:282063 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansal3ce0ca42018-06-25 22:52:222064
Yoav Weissd33bacb2020-03-12 06:42:212065 histogram_tester.ExpectUniqueSample("ClientHints.UpdateSize",
2066 expected_client_hints_number, 1);
Tarun Bansal3ce0ca42018-06-25 22:52:222067 // accept_ch_with_lifetime_url() sets client hints persist duration to 3600
Yoav Weiss76e1afb762020-05-14 19:28:122068 // seconds, but a maximum value is registered instead.
Tarun Bansal3ce0ca42018-06-25 22:52:222069 histogram_tester.ExpectUniqueSample("ClientHints.PersistDuration",
Yoav Weiss76e1afb762020-05-14 19:28:122070 uma_histogram_max_value, 1);
Tarun Bansal3ce0ca42018-06-25 22:52:222071 base::RunLoop().RunUntilIdle();
2072
2073 // Clients hints preferences for one origin should be persisted.
2074 HostContentSettingsMapFactory::GetForProfile(incognito->profile())
Illia Klimov48f643c2020-11-05 20:06:142075 ->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
Tarun Bansal3ce0ca42018-06-25 22:52:222076 &host_settings);
2077 EXPECT_EQ(1u, host_settings.size());
2078
2079 SetClientHintExpectationsOnMainFrame(true);
2080 SetClientHintExpectationsOnSubresources(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:382081 ASSERT_TRUE(ui_test_utils::NavigateToURL(
2082 incognito, without_accept_ch_without_lifetime_url()));
Tarun Bansal3ce0ca42018-06-25 22:52:222083
Mike West2fddeeb72019-02-15 11:29:482084 // The user agent hint is attached to all three requests:
2085 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462086 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092087 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:482088
Yoav Weissd33bacb2020-03-12 06:42:212089 // Expected number of hints attached to the image request, and the same number
2090 // to the main frame request.
2091 EXPECT_EQ(expected_client_hints_number * 2,
2092 count_client_hints_headers_seen());
Tarun Bansal3ce0ca42018-06-25 22:52:222093
2094 // Navigate using regular profile. Client hints should not be send.
2095 SetClientHintExpectationsOnMainFrame(false);
2096 SetClientHintExpectationsOnSubresources(false);
Lukasz Anforowiczb78290c2021-09-08 04:31:382097 ASSERT_TRUE(ui_test_utils::NavigateToURL(
2098 browser(), without_accept_ch_without_lifetime_url()));
Tarun Bansal3ce0ca42018-06-25 22:52:222099
Mike West2fddeeb72019-02-15 11:29:482100 // The user agent hint is attached to the two new requests.
2101 EXPECT_EQ(5u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462102 EXPECT_EQ(5u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092103 EXPECT_EQ(5u, count_ua_platform_client_hints_headers_seen());
Mike West2fddeeb72019-02-15 11:29:482104
2105 // No additional hints are sent.
Yoav Weissd33bacb2020-03-12 06:42:212106 EXPECT_EQ(expected_client_hints_number * 2,
2107 count_client_hints_headers_seen());
Tarun Bansal3ce0ca42018-06-25 22:52:222108}
Tarun Bansalbef6d652018-10-02 18:41:012109
Tarun Bansalbef6d652018-10-02 18:41:012110class ClientHintsWebHoldbackBrowserTest : public ClientHintsBrowserTest {
2111 public:
2112 ClientHintsWebHoldbackBrowserTest() : ClientHintsBrowserTest() {
2113 ConfigureHoldbackExperiment();
2114 }
2115
2116 net::EffectiveConnectionType web_effective_connection_type_override() const {
2117 return web_effective_connection_type_override_;
2118 }
2119
Mike West2fddeeb72019-02-15 11:29:482120 std::unique_ptr<base::FeatureList> EnabledFeatures() override {
Tarun Bansalbef6d652018-10-02 18:41:012121 base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
2122 const std::string kTrialName = "TrialFoo";
2123 const std::string kGroupName = "GroupFoo"; // Value not used
2124
2125 scoped_refptr<base::FieldTrial> trial =
2126 base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
2127
2128 std::map<std::string, std::string> params;
2129
2130 params["web_effective_connection_type_override"] =
2131 net::GetNameForEffectiveConnectionType(
2132 web_effective_connection_type_override_);
Mike West2fddeeb72019-02-15 11:29:482133 EXPECT_TRUE(
Tarun Bansalbef6d652018-10-02 18:41:012134 base::FieldTrialParamAssociator::GetInstance()
2135 ->AssociateFieldTrialParams(kTrialName, kGroupName, params));
2136
2137 std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
Maks Orlovichc66745a2020-06-30 17:40:022138 feature_list->InitializeFromCommandLine(
Ari Chivukulae399ab42021-09-15 22:20:282139 "UserAgentClientHint,PrefersColorSchemeClientHintHeader,"
2140 "ViewportHeightClientHintHeader",
François Beaufort1b51d062021-05-18 11:11:232141 "");
Tarun Bansalbef6d652018-10-02 18:41:012142 feature_list->RegisterFieldTrialOverride(
2143 features::kNetworkQualityEstimatorWebHoldback.name,
2144 base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
Mike West2fddeeb72019-02-15 11:29:482145 return feature_list;
Tarun Bansalbef6d652018-10-02 18:41:012146 }
2147
Mike West2fddeeb72019-02-15 11:29:482148 private:
2149 void ConfigureHoldbackExperiment() {}
2150
Tarun Bansalbef6d652018-10-02 18:41:012151 const net::EffectiveConnectionType web_effective_connection_type_override_ =
2152 net::EFFECTIVE_CONNECTION_TYPE_3G;
Tarun Bansalbef6d652018-10-02 18:41:012153};
2154
2155// Make sure that when NetInfo holdback experiment is enabled, the NetInfo APIs
2156// and client hints return the overridden values. Verify that the client hints
2157// are overridden on both main frame and subresource requests.
2158IN_PROC_BROWSER_TEST_F(ClientHintsWebHoldbackBrowserTest,
2159 EffectiveConnectionTypeChangeNotified) {
2160 SetExpectedEffectiveConnectionType(web_effective_connection_type_override());
2161
2162 SetClientHintExpectationsOnMainFrame(false);
2163 SetClientHintExpectationsOnSubresources(true);
2164
2165 base::RunLoop().RunUntilIdle();
2166
2167 EXPECT_TRUE(embedded_test_server()->Start());
Lukasz Anforowiczb78290c2021-09-08 04:31:382168 ASSERT_TRUE(
2169 ui_test_utils::NavigateToURL(browser(), accept_ch_with_lifetime_url()));
Tarun Bansalbef6d652018-10-02 18:41:012170 EXPECT_EQ(0u, count_client_hints_headers_seen());
2171 EXPECT_EQ(0u, third_party_request_count_seen());
2172 EXPECT_EQ(0u, third_party_client_hints_count_seen());
2173
2174 SetClientHintExpectationsOnMainFrame(true);
2175 SetClientHintExpectationsOnSubresources(true);
Lukasz Anforowiczb78290c2021-09-08 04:31:382176 ASSERT_TRUE(ui_test_utils::NavigateToURL(
2177 browser(), accept_ch_without_lifetime_with_subresource_url()));
Tarun Bansalbef6d652018-10-02 18:41:012178 base::RunLoop().RunUntilIdle();
2179 content::FetchHistogramsFromChildProcesses();
John Abd-El-Malek161073c2020-06-12 20:40:282180 metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
Tarun Bansalbef6d652018-10-02 18:41:012181
Mike West2fddeeb72019-02-15 11:29:482182 EXPECT_EQ(3u, count_user_agent_hint_headers_seen());
Maks Orlovich5dcc99c2020-02-13 19:07:462183 EXPECT_EQ(3u, count_ua_mobile_client_hints_headers_seen());
Aaron Tagliaboschiec5bce62021-06-24 18:50:092184 EXPECT_EQ(3u, count_ua_platform_client_hints_headers_seen());
Yoav Weissd33bacb2020-03-12 06:42:212185 EXPECT_EQ(expected_client_hints_number * 2,
2186 count_client_hints_headers_seen());
Tarun Bansalbef6d652018-10-02 18:41:012187 EXPECT_EQ(0u, third_party_request_count_seen());
2188 EXPECT_EQ(0u, third_party_client_hints_count_seen());
2189}
Aaron Tagliaboschi603540d22021-04-05 00:37:142190
2191class AcceptCHFrameObserverInterceptor {
2192 public:
2193 AcceptCHFrameObserverInterceptor()
2194 : interceptor_(base::BindRepeating(
2195 &AcceptCHFrameObserverInterceptor::InterceptURLRequest,
2196 base::Unretained(this))) {}
2197
2198 void set_accept_ch_frame(
2199 std::vector<network::mojom::WebClientHintsType> frame) {
2200 accept_ch_frame_ = frame;
2201 }
2202
2203 private:
Ali Beyadf05102d2021-08-23 16:53:402204 bool InterceptURLRequest(URLLoaderInterceptor::RequestParams* params) {
Aaron Tagliaboschi603540d22021-04-05 00:37:142205 if (!accept_ch_frame_ || !params->url_request.trusted_params ||
2206 !params->url_request.trusted_params->accept_ch_frame_observer) {
2207 return false;
2208 }
2209
2210 std::vector<network::mojom::WebClientHintsType> hints;
2211 for (auto hint : accept_ch_frame_.value()) {
Ari Chivukula51baf9b2021-09-13 20:01:492212 std::string header = network::GetClientHintToNameMap().at(hint);
Aaron Tagliaboschi603540d22021-04-05 00:37:142213 if (!params->url_request.headers.HasHeader(header))
2214 hints.push_back(hint);
2215 }
2216
2217 if (hints.empty())
2218 return false;
2219
2220 mojo::Remote<network::mojom::AcceptCHFrameObserver> remote(std::move(
2221 params->url_request.trusted_params->accept_ch_frame_observer));
2222 remote->OnAcceptCHFrameReceived(params->url_request.url, hints,
2223 base::DoNothing::Once<int>());
2224 // At this point it's expected that either the remote's callback will be
2225 // called or the URLLoader will be destroyed to make way for a new one.
2226 // As this is essentially unobservable, RunUntilIdle must be used.
2227 base::RunLoop().RunUntilIdle();
2228 return false;
2229 }
2230
Ali Beyadf05102d2021-08-23 16:53:402231 URLLoaderInterceptor interceptor_;
Anton Bikineev46bbb972021-05-15 17:53:532232 absl::optional<std::vector<network::mojom::WebClientHintsType>>
Aaron Tagliaboschi603540d22021-04-05 00:37:142233 accept_ch_frame_;
2234};
2235
2236// Replace the request interceptor with an AcceptCHFrameObserverInterceptor.
2237class ClientHintsAcceptCHFrameObserverBrowserTest
2238 : public ClientHintsBrowserTest {
2239 public:
2240 void SetUpOnMainThread() override {
2241 host_resolver()->AddRule("*", "127.0.0.1");
2242 accept_ch_frame_observer_interceptor_ =
2243 std::make_unique<AcceptCHFrameObserverInterceptor>();
2244 }
2245
2246 void TearDownOnMainThread() override {
2247 accept_ch_frame_observer_interceptor_.reset();
2248 }
2249
2250 void set_accept_ch_frame(
2251 std::vector<network::mojom::WebClientHintsType> frame) {
2252 accept_ch_frame_observer_interceptor_->set_accept_ch_frame(frame);
2253 }
2254
2255 std::vector<network::mojom::WebClientHintsType> all_client_hints_types() {
2256 std::vector<network::mojom::WebClientHintsType> hints;
Ari Chivukula51baf9b2021-09-13 20:01:492257 for (const auto& elem : network::GetClientHintToNameMap()) {
2258 const auto& type = elem.first;
2259 hints.push_back(type);
Aaron Tagliaboschi603540d22021-04-05 00:37:142260 }
Aaron Tagliaboschi603540d22021-04-05 00:37:142261 return hints;
2262 }
2263
2264 private:
2265 std::unique_ptr<AcceptCHFrameObserverInterceptor>
2266 accept_ch_frame_observer_interceptor_;
2267};
2268
Elly Fong-Jonesdd9eb012021-04-05 22:45:272269#if defined(OS_CHROMEOS)
2270// Flaky: https://crbug.com/1195790
2271#define MAYBE_AcceptCHFrame DISABLED_AcceptCHFrame
2272#else
2273#define MAYBE_AcceptCHFrame AcceptCHFrame
2274#endif
2275
Aaron Tagliaboschi603540d22021-04-05 00:37:142276// Ensure that client hints are sent when the ACCEPT_CH frame observer is
2277// notified.
2278IN_PROC_BROWSER_TEST_F(ClientHintsAcceptCHFrameObserverBrowserTest,
Elly Fong-Jonesdd9eb012021-04-05 22:45:272279 MAYBE_AcceptCHFrame) {
Aaron Tagliaboschi603540d22021-04-05 00:37:142280 const GURL gurl = without_accept_ch_without_lifetime_url();
2281 set_accept_ch_frame(all_client_hints_types());
2282 SetClientHintExpectationsOnMainFrame(true);
2283 SetClientHintExpectationsOnSubresources(false);
Lukasz Anforowiczb78290c2021-09-08 04:31:382284 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Aaron Tagliaboschi603540d22021-04-05 00:37:142285}
2286
2287// Ensure that client hints are *not* sent when the observer is notified but
2288// client hints would normally not be sent (e.g. when JS is disabled for the
2289// frame).
2290IN_PROC_BROWSER_TEST_F(ClientHintsAcceptCHFrameObserverBrowserTest,
2291 AcceptCHFrameJSDisabled) {
2292 const GURL gurl = without_accept_ch_without_lifetime_url();
2293 set_accept_ch_frame(all_client_hints_types());
2294 SetJsEnabledForActiveView(false);
2295 SetClientHintExpectationsOnMainFrame(false);
2296 SetClientHintExpectationsOnSubresources(false);
Lukasz Anforowiczb78290c2021-09-08 04:31:382297 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Aaron Tagliaboschi603540d22021-04-05 00:37:142298}
Aaron Tagliaboschi25625c22021-05-11 18:13:592299
2300IN_PROC_BROWSER_TEST_P(ClientHintsBrowserTest, UseCounter) {
2301 auto web_feature_waiter =
2302 std::make_unique<page_load_metrics::PageLoadMetricsTestWaiter>(
2303 chrome_test_utils::GetActiveWebContents(this));
2304
2305 web_feature_waiter->AddWebFeatureExpectation(
Aaron Tagliaboschiec5bce62021-06-24 18:50:092306 blink::mojom::WebFeature::kClientHintsUAFullVersion);
Aaron Tagliaboschi25625c22021-05-11 18:13:592307 const GURL gurl = GetParam() ? http_equiv_accept_ch_with_lifetime()
2308 : accept_ch_with_lifetime_url();
2309
Lukasz Anforowiczb78290c2021-09-08 04:31:382310 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
Aaron Tagliaboschi25625c22021-05-11 18:13:592311
2312 web_feature_waiter->Wait();
2313}
François Beaufort34e299e2021-05-26 05:54:332314
Ali Beyada6b0fb6f2021-07-28 00:13:242315class CriticalClientHintsBrowserTest : public InProcessBrowserTest {
2316 public:
2317 CriticalClientHintsBrowserTest()
2318 : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
2319 https_server_.ServeFilesFromSourceDirectory(
2320 "chrome/test/data/client_hints");
2321 https_server_.RegisterRequestMonitor(base::BindRepeating(
2322 &CriticalClientHintsBrowserTest::MonitorResourceRequest,
2323 base::Unretained(this)));
2324 EXPECT_TRUE(https_server_.Start());
2325 }
2326
2327 void SetUp() override {
2328 std::unique_ptr<base::FeatureList> feature_list =
2329 std::make_unique<base::FeatureList>();
Ari Chivukulae399ab42021-09-15 22:20:282330 // Don't include PrefersColorSchemeClientHintHeader in the enabled
2331 // features; we will verify that PrefersColorScheme is not included.
Ali Beyada6b0fb6f2021-07-28 00:13:242332 feature_list->InitializeFromCommandLine(
Ari Chivukulae399ab42021-09-15 22:20:282333 "UserAgentClientHint,CriticalClientHint,AcceptCHFrame", "");
Ali Beyada6b0fb6f2021-07-28 00:13:242334 scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
Ali Beyad821f4192021-08-20 16:21:282335
2336 InProcessBrowserTest::SetUp();
Ali Beyada6b0fb6f2021-07-28 00:13:242337 }
2338
2339 void SetUpOnMainThread() override {
2340 host_resolver()->AddRule("*", "127.0.0.1");
Ali Beyad821f4192021-08-20 16:21:282341
2342 InProcessBrowserTest::SetUpOnMainThread();
Ali Beyada6b0fb6f2021-07-28 00:13:242343 }
2344
2345 GURL critical_ch_ua_full_version_url() const {
2346 return https_server_.GetURL("/critical_ch_ua_full_version.html");
2347 }
2348
Ari Chivukulae399ab42021-09-15 22:20:282349 GURL critical_ch_prefers_color_scheme_url() const {
2350 return https_server_.GetURL("/critical_ch_prefers-color-scheme.html");
Ali Beyada6b0fb6f2021-07-28 00:13:242351 }
2352
2353 const absl::optional<std::string>& observed_ch_ua_full_version() {
2354 base::AutoLock lock(ch_ua_full_version_lock_);
2355 return ch_ua_full_version_;
2356 }
2357
Ari Chivukulae399ab42021-09-15 22:20:282358 const absl::optional<std::string>& observed_ch_prefers_color_scheme() {
2359 base::AutoLock lock(ch_prefers_color_scheme_lock_);
2360 return ch_prefers_color_scheme_;
Ali Beyada6b0fb6f2021-07-28 00:13:242361 }
2362
2363 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
2364 if (request.headers.find("sec-ch-ua-full-version") !=
2365 request.headers.end()) {
2366 SetChUaFullVersion(request.headers.at("sec-ch-ua-full-version"));
2367 }
Ari Chivukulae399ab42021-09-15 22:20:282368 if (request.headers.find("prefers-color-scheme") != request.headers.end()) {
2369 SetChPrefersColorScheme(request.headers.at("prefers-color-scheme"));
Ali Beyada6b0fb6f2021-07-28 00:13:242370 }
2371 }
2372
2373 private:
2374 void SetChUaFullVersion(const std::string& ch_ua_full_version) {
2375 base::AutoLock lock(ch_ua_full_version_lock_);
2376 ch_ua_full_version_ = ch_ua_full_version;
2377 }
2378
Ari Chivukulae399ab42021-09-15 22:20:282379 void SetChPrefersColorScheme(const std::string& ch_prefers_color_scheme) {
2380 base::AutoLock lock(ch_prefers_color_scheme_lock_);
2381 ch_prefers_color_scheme_ = ch_prefers_color_scheme;
Ali Beyada6b0fb6f2021-07-28 00:13:242382 }
2383
2384 base::test::ScopedFeatureList scoped_feature_list_;
2385 net::EmbeddedTestServer https_server_;
2386 base::Lock ch_ua_full_version_lock_;
2387 absl::optional<std::string> ch_ua_full_version_
2388 GUARDED_BY(ch_ua_full_version_lock_);
Ari Chivukulae399ab42021-09-15 22:20:282389 base::Lock ch_prefers_color_scheme_lock_;
2390 absl::optional<std::string> ch_prefers_color_scheme_
2391 GUARDED_BY(ch_prefers_color_scheme_lock_);
Ali Beyada6b0fb6f2021-07-28 00:13:242392};
2393
2394// Verify that setting Critical-CH in the response header causes the request to
2395// be resent with the client hint included.
2396IN_PROC_BROWSER_TEST_F(CriticalClientHintsBrowserTest,
Ali Beyad821f4192021-08-20 16:21:282397 CriticalClientHintInRequestHeader) {
Ali Beyada6b0fb6f2021-07-28 00:13:242398 blink::UserAgentMetadata ua = embedder_support::GetUserAgentMetadata();
2399 // On the first navigation request, the client hints in the Critical-CH
2400 // should be set on the request header.
Lukasz Anforowiczb78290c2021-09-08 04:31:382401 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(),
2402 critical_ch_ua_full_version_url()));
Ali Beyada6b0fb6f2021-07-28 00:13:242403 const std::string expected_ch_ua_full_version = "\"" + ua.full_version + "\"";
2404 EXPECT_THAT(observed_ch_ua_full_version(),
2405 Optional(Eq(expected_ch_ua_full_version)));
Ari Chivukulae399ab42021-09-15 22:20:282406 EXPECT_EQ(observed_ch_prefers_color_scheme(), absl::nullopt);
Ali Beyada6b0fb6f2021-07-28 00:13:242407}
2408
2409// Verify that setting Critical-CH in the response header with a client hint
2410// that is filtered out of Accept-CH causes the request to *not* be resent and
2411// the critical client hint is not included.
Ali Beyada6b0fb6f2021-07-28 00:13:242412IN_PROC_BROWSER_TEST_F(
2413 CriticalClientHintsBrowserTest,
2414 CriticalClientHintFilteredOutOfAcceptChNotInRequestHeader) {
2415 // On the first navigation request, the client hints in the Critical-CH
2416 // should be set on the request header, but in this case, the
Ari Chivukulae399ab42021-09-15 22:20:282417 // kPrefersColorSchemeClientHintHeader is not enabled, so the critical client
2418 // hint won't be set in the request header.
2419 ASSERT_TRUE(ui_test_utils::NavigateToURL(
2420 browser(), critical_ch_prefers_color_scheme_url()));
2421 EXPECT_EQ(observed_ch_prefers_color_scheme(), absl::nullopt);
Ali Beyada6b0fb6f2021-07-28 00:13:242422 // The request should not have been resent, so ch-ua-full-version should also
2423 // not be present.
2424 EXPECT_EQ(observed_ch_ua_full_version(), absl::nullopt);
2425}
2426
François Beaufort34e299e2021-05-26 05:54:332427class ClientHintsBrowserTestWithEmulatedMedia
2428 : public DevToolsProtocolTestBase {
2429 public:
2430 ClientHintsBrowserTestWithEmulatedMedia()
2431 : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
2432 scoped_feature_list_.InitFromCommandLine(
2433 "UserAgentClientHint,AcceptCHFrame,PrefersColorSchemeClientHintHeader",
2434 "");
2435
2436 https_server_.ServeFilesFromSourceDirectory(
2437 "chrome/test/data/client_hints");
2438 https_server_.RegisterRequestMonitor(base::BindRepeating(
2439 &ClientHintsBrowserTestWithEmulatedMedia::MonitorResourceRequest,
2440 base::Unretained(this)));
2441 EXPECT_TRUE(https_server_.Start());
2442
2443 test_url_ = https_server_.GetURL("/accept_ch_without_lifetime.html");
2444 }
2445
2446 ~ClientHintsBrowserTestWithEmulatedMedia() override = default;
2447
2448 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
2449 if (request.headers.find("sec-ch-prefers-color-scheme") !=
2450 request.headers.end()) {
2451 prefers_color_scheme_observed_ =
2452 request.headers.at("sec-ch-prefers-color-scheme");
2453 }
2454 }
2455
2456 const GURL& test_url() const { return test_url_; }
2457
2458 const std::string& prefers_color_scheme_observed() const {
2459 return prefers_color_scheme_observed_;
2460 }
2461
2462 void EmulatePrefersColorScheme(std::string value) {
2463 base::Value feature(base::Value::Type::DICTIONARY);
2464 feature.SetKey("name", base::Value("prefers-color-scheme"));
2465 feature.SetKey("value", base::Value(value));
2466 base::Value features(base::Value::Type::LIST);
2467 features.Append(std::move(feature));
2468 base::Value params(base::Value::Type::DICTIONARY);
2469 params.SetKey("features", std::move(features));
2470 SendCommandSync("Emulation.setEmulatedMedia", std::move(params));
2471 }
2472
2473 private:
2474 base::test::ScopedFeatureList scoped_feature_list_;
2475 net::EmbeddedTestServer https_server_;
2476 GURL test_url_;
2477 std::string prefers_color_scheme_observed_;
2478
2479 DISALLOW_COPY_AND_ASSIGN(ClientHintsBrowserTestWithEmulatedMedia);
2480};
2481
2482IN_PROC_BROWSER_TEST_F(ClientHintsBrowserTestWithEmulatedMedia,
2483 PrefersColorScheme) {
Lukasz Anforowiczb78290c2021-09-08 04:31:382484 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url()));
François Beaufort34e299e2021-05-26 05:54:332485 EXPECT_EQ(prefers_color_scheme_observed(), "");
2486 Attach();
2487
2488 EmulatePrefersColorScheme("light");
Lukasz Anforowiczb78290c2021-09-08 04:31:382489 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url()));
François Beaufort34e299e2021-05-26 05:54:332490 EXPECT_EQ(prefers_color_scheme_observed(), "light");
2491
2492 EmulatePrefersColorScheme("dark");
Lukasz Anforowiczb78290c2021-09-08 04:31:382493 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url()));
François Beaufort34e299e2021-05-26 05:54:332494 EXPECT_EQ(prefers_color_scheme_observed(), "dark");
2495}
Ali Beyad7417fc22021-08-06 03:09:582496
Ali Beyadf05102d2021-08-23 16:53:402497// Base class for the User-Agent reduction Origin Trial browser tests. Common
2498// functionality shared between the various UA reduction browser tests should
2499// go in this class.
Ali Beyad7417fc22021-08-06 03:09:582500class UaReducedOriginTrialBrowserTest : public InProcessBrowserTest {
2501 public:
Ali Beyad7417fc22021-08-06 03:09:582502 void SetUpCommandLine(base::CommandLine* command_line) override {
2503 // The public key for the default privatey key used by the
2504 // tools/origin_trials/generate_token.py tool.
2505 static constexpr char kOriginTrialTestPublicKey[] =
2506 "dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BNA=";
2507 command_line->AppendSwitchASCII(embedder_support::kOriginTrialPublicKey,
2508 kOriginTrialTestPublicKey);
2509 }
2510
2511 void SetUp() override {
2512 std::unique_ptr<base::FeatureList> feature_list =
2513 std::make_unique<base::FeatureList>();
2514 feature_list->InitializeFromCommandLine("CriticalClientHint", "");
2515 scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
Ali Beyad821f4192021-08-20 16:21:282516
2517 InProcessBrowserTest::SetUp();
Ali Beyad7417fc22021-08-06 03:09:582518 }
2519
Ali Beyadf05102d2021-08-23 16:53:402520 void SetUserAgentOverride(const std::string& ua_override) {
2521 content::WebContents* web_contents =
2522 browser()->tab_strip_model()->GetActiveWebContents();
2523 web_contents->SetUserAgentOverride(
2524 blink::UserAgentOverride::UserAgentOnly(ua_override), false);
2525 web_contents->GetController()
2526 .GetLastCommittedEntry()
2527 ->SetIsOverridingUserAgent(true);
2528 }
2529
2530 void CheckUaReducedClientHint(const bool ch_ua_reduced_expected) {
2531 const absl::optional<std::string>& ua_reduced_client_hint =
2532 GetLastUaReducedClientHintValue();
2533
2534 if (ch_ua_reduced_expected) {
2535 EXPECT_THAT(ua_reduced_client_hint, Optional(Eq("?1")));
2536 } else {
2537 EXPECT_THAT(ua_reduced_client_hint, Eq(absl::nullopt));
2538 }
2539 }
2540
2541 void CheckUserAgentString(const std::string& expected_ua_header_value) {
2542 EXPECT_THAT(GetLastUserAgentHeaderValue(),
2543 Optional(expected_ua_header_value));
2544 }
2545
Ali Beyad703d3c42021-09-03 19:43:002546 void CheckUserAgentReduced(const std::string& user_agent_value,
2547 const bool expected_user_agent_reduced) {
Ali Beyadf05102d2021-08-23 16:53:402548 // A regular expression that matches Chrome/{major_version}.{minor_version}
2549 // in the User-Agent string, where the {minor_version} is captured.
2550 static constexpr char kChromeVersionRegex[] =
2551 "Chrome/[0-9]+\\.([0-9]+\\.[0-9]+\\.[0-9]+)";
2552 // The minor version in the reduced UA string is always "0.0.0".
2553 static constexpr char kReducedMinorVersion[] = "0.0.0";
2554
Ali Beyadf05102d2021-08-23 16:53:402555 std::string minor_version;
Ali Beyad703d3c42021-09-03 19:43:002556 EXPECT_TRUE(re2::RE2::PartialMatch(user_agent_value, kChromeVersionRegex,
2557 &minor_version));
Ali Beyadf05102d2021-08-23 16:53:402558 if (expected_user_agent_reduced) {
2559 EXPECT_EQ(minor_version, kReducedMinorVersion);
2560 } else {
2561 EXPECT_NE(minor_version, kReducedMinorVersion);
2562 }
2563 }
2564
Ali Beyad703d3c42021-09-03 19:43:002565 void CheckUserAgentReduced(const bool expected_user_agent_reduced) {
2566 const absl::optional<std::string>& user_agent_header_value =
2567 GetLastUserAgentHeaderValue();
2568 EXPECT_TRUE(user_agent_header_value.has_value());
2569 CheckUserAgentReduced(*user_agent_header_value,
2570 expected_user_agent_reduced);
2571 }
2572
Ali Beyadf05102d2021-08-23 16:53:402573 void NavigateAndCheckHeaders(const GURL& url,
2574 const bool ch_ua_reduced_expected) {
Lukasz Anforowiczb78290c2021-09-08 04:31:382575 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
Ali Beyadf05102d2021-08-23 16:53:402576
2577 CheckUaReducedClientHint(ch_ua_reduced_expected);
2578 CheckUserAgentReduced(ch_ua_reduced_expected);
2579 }
2580
2581 protected:
2582 // Returns the value of the User-Agent request header from the last sent
2583 // request, or nullopt if the header could not be read.
2584 virtual const absl::optional<std::string>& GetLastUserAgentHeaderValue() = 0;
2585 // Returns the value of the Sec-CH-UA-Reduced request header from the last
2586 // sent request, or nullopt if the header could not be read.
2587 virtual const absl::optional<std::string>&
2588 GetLastUaReducedClientHintValue() = 0;
2589
2590 private:
2591 base::test::ScopedFeatureList scoped_feature_list_;
2592};
2593
2594// Tests that the Sec-CH-UA-Reduced client hint is sent if and only if the
2595// UserAgentReduction Origin Trial token is present and valid in the response
2596// headers.
2597//
2598// The test Origin Trial token found in the test files was generated by running
2599// (in tools/origin_trials):
2600// generate_token.py https://127.0.0.1:44444 UserAgentReduction
2601// --expire-timestamp=2000000000
2602//
2603// The Origin Trial token expires in 2033. Generate a new token by then, or
2604// find a better way to re-generate a test trial token.
2605class SameOriginUaReducedOriginTrialBrowserTest
2606 : public UaReducedOriginTrialBrowserTest {
2607 public:
2608 SameOriginUaReducedOriginTrialBrowserTest() = default;
2609
2610 // The URL that was used to register the Origin Trial token.
2611 static constexpr const char kOriginUrl[] = "https://127.0.0.1:44444";
2612
Ali Beyad7417fc22021-08-06 03:09:582613 void SetUpOnMainThread() override {
Ali Beyad7417fc22021-08-06 03:09:582614 // We use a URLLoaderInterceptor, rather than the EmbeddedTestServer, since
2615 // the origin trial token in the response is associated with a fixed
2616 // origin, whereas EmbeddedTestServer serves content on a random port.
2617 url_loader_interceptor_ =
Ali Beyadf05102d2021-08-23 16:53:402618 URLLoaderInterceptor::ServeFilesFromDirectoryAtOrigin(
Ali Beyad7417fc22021-08-06 03:09:582619 "chrome/test/data/client_hints", GURL(kOriginUrl));
Ali Beyad821f4192021-08-20 16:21:282620
2621 InProcessBrowserTest::SetUpOnMainThread();
Ali Beyad7417fc22021-08-06 03:09:582622 }
2623
2624 void TearDownOnMainThread() override {
2625 url_loader_interceptor_.reset();
2626 InProcessBrowserTest::TearDownOnMainThread();
2627 }
2628
Ali Beyadf05102d2021-08-23 16:53:402629 const absl::optional<std::string>& GetLastUserAgentHeaderValue() override {
2630 std::string user_agent;
2631 CHECK(url_loader_interceptor_->GetLastRequestHeaders().GetHeader(
2632 "user-agent", &user_agent));
2633 last_user_agent_ = user_agent;
2634 return last_user_agent_;
2635 }
2636
2637 const absl::optional<std::string>& GetLastUaReducedClientHintValue()
2638 override {
2639 std::string ch_ua_reduced_header_value;
2640 if (url_loader_interceptor_->GetLastRequestHeaders().GetHeader(
2641 "sec-ch-ua-reduced", &ch_ua_reduced_header_value)) {
2642 last_ua_reduced_ch_ = ch_ua_reduced_header_value;
2643 } else {
2644 last_ua_reduced_ch_ = absl::nullopt;
2645 }
2646 return last_ua_reduced_ch_;
2647 }
2648
Ali Beyad7417fc22021-08-06 03:09:582649 GURL ua_reduced_with_valid_origin_trial_token_url() const {
2650 return GURL(base::StrCat(
2651 {kOriginUrl, "/accept_ch_ua_reduced_with_valid_origin_trial.html"}));
2652 }
2653
2654 GURL ua_reduced_with_invalid_origin_trial_token_url() const {
2655 return GURL(base::StrCat(
2656 {kOriginUrl, "/accept_ch_ua_reduced_with_invalid_origin_trial.html"}));
2657 }
2658
2659 GURL ua_reduced_with_no_origin_trial_token_url() const {
2660 return GURL(base::StrCat(
2661 {kOriginUrl, "/accept_ch_ua_reduced_with_no_origin_trial.html"}));
2662 }
2663
2664 GURL ua_reduced_missing_with_valid_origin_trial_token_url() const {
2665 return GURL(base::StrCat(
2666 {kOriginUrl, "/accept_ch_ua_reduced_missing_valid_origin_trial.html"}));
2667 }
2668
2669 GURL critical_ch_ua_reduced_with_valid_origin_trial_token_url() const {
2670 return GURL(base::StrCat(
2671 {kOriginUrl, "/critical_ch_ua_reduced_with_valid_origin_trial.html"}));
2672 }
2673
2674 GURL critical_ch_ua_reduced_with_invalid_origin_trial_token_url() const {
2675 return GURL(base::StrCat(
2676 {kOriginUrl,
2677 "/critical_ch_ua_reduced_with_invalid_origin_trial.html"}));
2678 }
2679
Ali Beyad4074a9c52021-08-17 16:15:512680 GURL accept_ch_ua_reduced_subresource_request_url() const {
2681 return GURL(base::StrCat(
2682 {kOriginUrl, "/accept_ch_ua_reduced_subresource_request.html"}));
2683 }
Ali Beyad7417fc22021-08-06 03:09:582684
Ali Beyad4074a9c52021-08-17 16:15:512685 GURL accept_ch_ua_reduced_iframe_request_url() const {
2686 return GURL(base::StrCat(
2687 {kOriginUrl, "/accept_ch_ua_reduced_iframe_request.html"}));
2688 }
2689
2690 GURL critical_ch_ua_reduced_subresource_request_url() const {
2691 return GURL(base::StrCat(
2692 {kOriginUrl, "/critical_ch_ua_reduced_subresource_request.html"}));
2693 }
2694
2695 GURL critical_ch_ua_reduced_iframe_request_url() const {
2696 return GURL(base::StrCat(
2697 {kOriginUrl, "/critical_ch_ua_reduced_iframe_request.html"}));
2698 }
2699
Ali Beyad77dba952021-08-25 20:52:582700 GURL simple_request_url() const {
2701 return GURL(base::StrCat({kOriginUrl, "/simple.html"}));
2702 }
2703
Ali Beyad4074a9c52021-08-17 16:15:512704 GURL last_request_url() const {
2705 return url_loader_interceptor_->GetLastRequestURL();
2706 }
2707
Ali Beyad7417fc22021-08-06 03:09:582708 void NavigateTwiceAndCheckHeader(const GURL& url,
2709 const bool ch_ua_reduced_expected,
2710 const bool critical_ch_ua_reduced_expected) {
Ali Beyad2618b472021-08-31 15:31:042711 base::HistogramTester histograms;
2712 int reduced_count = 0;
2713 int full_count = 0;
2714
Ali Beyad7417fc22021-08-06 03:09:582715 // If Critical-CH is set, we expect Sec-CH-UA-Reduced in the first
2716 // navigation request header. If Critical-CH is not set, we don't expect
2717 // Sec-CH-UA-Reduced in the first navigation request.
Ali Beyad2618b472021-08-31 15:31:042718 const bool first_navigation_reduced_ua =
2719 critical_ch_ua_reduced_expected && ch_ua_reduced_expected;
2720 NavigateAndCheckHeaders(url, first_navigation_reduced_ua);
2721 if (first_navigation_reduced_ua) {
2722 ++reduced_count;
2723 if (critical_ch_ua_reduced_expected) {
2724 // If Critical-CH was set, there will also be the initial navigation
2725 // that does not send the reduced UA string.
2726 ++full_count;
2727 }
2728 } else {
2729 ++full_count;
2730 }
2731 // The UserAgentStringType enum is not accessible in //chrome/browser, so
2732 // we just use the enum's integer value.
2733 histograms.ExpectBucketCount("Navigation.UserAgentStringType",
2734 /*NavigationRequest::kFullVersion*/ 0,
2735 full_count);
2736 histograms.ExpectBucketCount("Navigation.UserAgentStringType",
2737 /*NavigationRequest::kReducedVersion*/ 1,
2738 reduced_count);
Ali Beyad7417fc22021-08-06 03:09:582739
2740 // Regardless of the Critical-CH setting, we expect the Sec-CH-UA-Reduced
2741 // client hint sent on the second request, if Sec-CH-UA-Reduced is set and
2742 // the Origin Trial token is valid.
Ali Beyad4074a9c52021-08-17 16:15:512743 NavigateAndCheckHeaders(url, ch_ua_reduced_expected);
Ali Beyad2618b472021-08-31 15:31:042744 if (ch_ua_reduced_expected) {
2745 ++reduced_count;
2746 } else {
2747 ++full_count;
2748 }
2749 histograms.ExpectBucketCount("Navigation.UserAgentStringType",
2750 /*NavigationRequest::kFullVersion*/ 0,
2751 full_count);
2752 histograms.ExpectBucketCount("Navigation.UserAgentStringType",
2753 /*NavigationRequest::kReducedVersion*/ 1,
2754 reduced_count);
Ali Beyad7417fc22021-08-06 03:09:582755 }
2756
2757 private:
Ali Beyadf05102d2021-08-23 16:53:402758 std::unique_ptr<URLLoaderInterceptor> url_loader_interceptor_;
2759 absl::optional<std::string> last_user_agent_;
2760 absl::optional<std::string> last_ua_reduced_ch_;
Ali Beyad7417fc22021-08-06 03:09:582761};
2762
Ali Beyadf05102d2021-08-23 16:53:402763constexpr const char SameOriginUaReducedOriginTrialBrowserTest::kOriginUrl[];
Ali Beyad7417fc22021-08-06 03:09:582764
Ali Beyadf05102d2021-08-23 16:53:402765IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad7417fc22021-08-06 03:09:582766 AcceptChUaReducedWithValidOriginTrialToken) {
2767 NavigateTwiceAndCheckHeader(ua_reduced_with_valid_origin_trial_token_url(),
2768 /*ch_ua_reduced_expected=*/true,
2769 /*critical_ch_ua_reduced_expected=*/false);
Ali Beyad703d3c42021-09-03 19:43:002770
2771 // The Origin Trial token is valid, so we expect the reduced UA values in the
2772 // Javascript getters as well.
2773 content::WebContents* web_contents =
2774 browser()->tab_strip_model()->GetActiveWebContents();
2775 CheckUserAgentReduced(
2776 content::EvalJs(web_contents, "navigator.userAgent").ExtractString(),
2777 /*expected_user_agent_reduced=*/true);
2778 CheckUserAgentReduced(
2779 content::EvalJs(web_contents, "navigator.appVersion").ExtractString(),
2780 /*expected_user_agent_reduced=*/true);
2781 // Instead of checking all platform types, just check one that has a
2782 // difference between the full and reduced versions.
2783#if defined(OS_ANDROID)
2784 EXPECT_EQ("Linux x86_64",
2785 content::EvalJs(web_contents, "navigator.platform"));
2786#endif
Ali Beyad7417fc22021-08-06 03:09:582787}
2788
Ali Beyadf05102d2021-08-23 16:53:402789IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad7417fc22021-08-06 03:09:582790 AcceptChUaReducedWithInvalidOriginTrialToken) {
2791 // The response contained Sec-CH-UA-Reduced in the Accept-CH header, but the
2792 // origin trial token is invalid.
2793 NavigateTwiceAndCheckHeader(ua_reduced_with_invalid_origin_trial_token_url(),
2794 /*ch_ua_reduced_expected=*/false,
2795 /*critical_ch_ua_reduced_expected=*/false);
Ali Beyad703d3c42021-09-03 19:43:002796
2797 // The Origin Trial token is invalid, so we expect the full UA values in the
2798 // Javascript getters.
2799 content::WebContents* web_contents =
2800 browser()->tab_strip_model()->GetActiveWebContents();
2801 CheckUserAgentReduced(
2802 content::EvalJs(web_contents, "navigator.userAgent").ExtractString(),
2803 /*expected_user_agent_reduced=*/false);
2804 CheckUserAgentReduced(
2805 content::EvalJs(web_contents, "navigator.appVersion").ExtractString(),
2806 /*expected_user_agent_reduced=*/false);
2807 // Instead of checking all platform types, just check one that has a
2808 // difference between the full and reduced versions.
2809#if defined(OS_ANDROID)
2810 EXPECT_NE("Linux x86_64",
2811 content::EvalJs(web_contents, "navigator.platform"));
2812#endif
Ali Beyad7417fc22021-08-06 03:09:582813}
2814
Ali Beyadf05102d2021-08-23 16:53:402815IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad7417fc22021-08-06 03:09:582816 AcceptChUaReducedWithNoOriginTrialToken) {
2817 // The response contained Sec-CH-UA-Reduced in the Accept-CH header, but the
2818 // origin trial token is not present.
2819 NavigateTwiceAndCheckHeader(ua_reduced_with_no_origin_trial_token_url(),
2820 /*ch_ua_reduced_expected=*/false,
2821 /*critical_ch_ua_reduced_expected=*/false);
2822}
2823
Ali Beyadf05102d2021-08-23 16:53:402824IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad7417fc22021-08-06 03:09:582825 NoAcceptChUaReducedWithValidOriginTrialToken) {
2826 // The response contained a valid Origin Trial token, but no Sec-CH-UA-Reduced
2827 // in the Accept-CH header.
2828 NavigateTwiceAndCheckHeader(
2829 ua_reduced_missing_with_valid_origin_trial_token_url(),
2830 /*ch_ua_reduced_expected=*/false,
2831 /*critical_ch_ua_reduced_expected=*/false);
2832}
2833
Ali Beyadf05102d2021-08-23 16:53:402834IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad821f4192021-08-20 16:21:282835 CriticalChUaReducedWithValidOriginTrialToken) {
Ali Beyad7417fc22021-08-06 03:09:582836 // The initial navigation also contains the Critical-CH header, so the
2837 // Sec-CH-UA-Reduced header should be set after the first navigation.
2838 NavigateTwiceAndCheckHeader(
2839 critical_ch_ua_reduced_with_valid_origin_trial_token_url(),
2840 /*ch_ua_reduced_expected=*/true,
2841 /*critical_ch_ua_reduced_expected=*/true);
2842}
2843
Ali Beyadf05102d2021-08-23 16:53:402844IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad7417fc22021-08-06 03:09:582845 CriticalChUaReducedWithInvalidOriginTrialToken) {
2846 // The Origin Trial token is invalid, so the Critical-CH should not have
2847 // resulted in the Sec-CH-UA-Reduced header being sent.
2848 NavigateTwiceAndCheckHeader(
2849 critical_ch_ua_reduced_with_invalid_origin_trial_token_url(),
2850 /*ch_ua_reduced_expected=*/false,
2851 /*critical_ch_ua_reduced_expected=*/false);
2852}
2853
Ali Beyadf05102d2021-08-23 16:53:402854IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad4074a9c52021-08-17 16:15:512855 IframeRequestUaReducedWithValidOriginTrialToken) {
2856 // The last resource request processed for this navigation will be an embedded
2857 // iframe request. Since Accept-CH has Sec-CH-UA-Reduced set on the top-level
2858 // level frame's response header, along with a valid origin trial token, the
2859 // iframe request should send Sec-CH-UA-Reduced and the reduced UA string in
2860 // the request header.
2861 NavigateAndCheckHeaders(accept_ch_ua_reduced_iframe_request_url(),
2862 /*ch_ua_reduced_expected=*/true);
2863 // Make sure the last intercepted URL was the request for the embedded iframe.
2864 EXPECT_EQ(last_request_url().path(), "/simple.html");
2865}
2866
2867IN_PROC_BROWSER_TEST_F(
Ali Beyadf05102d2021-08-23 16:53:402868 SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad4074a9c52021-08-17 16:15:512869 IframeRequestUaReducedWithValidOriginTrialTokenAndCriticalCH) {
2870 // The last resource request processed for this navigation will be an embedded
2871 // iframe request. Since Accept-CH has Sec-CH-UA-Reduced set on the top-level
2872 // level frame's response header, along with a valid origin trial token, the
2873 // iframe request should send Sec-CH-UA-Reduced and the reduced UA string in
2874 // the request header.
2875 NavigateAndCheckHeaders(critical_ch_ua_reduced_iframe_request_url(),
2876 /*ch_ua_reduced_expected=*/true);
2877 // Make sure the last intercepted URL was the request for the embedded iframe.
2878 EXPECT_EQ(last_request_url().path(), "/simple.html");
2879}
2880
Ali Beyadf05102d2021-08-23 16:53:402881IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad4074a9c52021-08-17 16:15:512882 SubresourceRequestUaReducedWithValidOriginTrialToken) {
2883 // The last resource request processed for this navigation will be a
2884 // subresource request for the stylesheet. Since Accept-CH has
2885 // Sec-CH-UA-Reduced set on the top-level level frame's response header, along
2886 // with a valid origin trial token, the subresource request should send
2887 // Sec-CH-UA-Reduced and the reduced UA string in the request header.
2888 NavigateAndCheckHeaders(accept_ch_ua_reduced_subresource_request_url(),
2889 /*ch_ua_reduced_expected=*/true);
2890 // Make sure the last intercepted URL was the subresource request for the
2891 // embedded stylesheet.
2892 EXPECT_EQ(last_request_url().path(), "/style.css");
2893}
2894
2895IN_PROC_BROWSER_TEST_F(
Ali Beyadf05102d2021-08-23 16:53:402896 SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad4074a9c52021-08-17 16:15:512897 SubresourceRequestUaReducedWithValidOriginTrialTokenAndCriticalCH) {
2898 // The last resource request processed for this navigation will be a
2899 // subresource request for the stylesheet. Since Accept-CH has
2900 // Sec-CH-UA-Reduced set on the top-level level frame's response header, along
2901 // with a valid origin trial token, the subresource request should send
2902 // Sec-CH-UA-Reduced and the reduced UA string in the request header.
2903 NavigateAndCheckHeaders(critical_ch_ua_reduced_subresource_request_url(),
2904 /*ch_ua_reduced_expected=*/true);
2905 // Make sure the last intercepted URL was the subresource request for the
2906 // embedded stylesheet.
2907 EXPECT_EQ(last_request_url().path(), "/style.css");
2908}
2909
Ali Beyadf05102d2021-08-23 16:53:402910IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad4074a9c52021-08-17 16:15:512911 UserAgentOverrideAcceptChUaReduced) {
Ali Beyad2618b472021-08-31 15:31:042912 base::HistogramTester histograms;
Ali Beyad4074a9c52021-08-17 16:15:512913 const std::string user_agent_override = "foo";
2914 SetUserAgentOverride(user_agent_override);
2915
2916 const GURL url = ua_reduced_with_valid_origin_trial_token_url();
2917 // First navigation to set the client hints in the response.
Lukasz Anforowiczb78290c2021-09-08 04:31:382918 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
Ali Beyad4074a9c52021-08-17 16:15:512919 // Second navigation has the Sec-CH-UA-Reduced client hint stored from the
2920 // first navigation's response.
Lukasz Anforowiczb78290c2021-09-08 04:31:382921 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
Ali Beyad4074a9c52021-08-17 16:15:512922
2923 // Since the UA override was set, the UA client hints are *not* added to the
2924 // request.
2925 CheckUaReducedClientHint(/*ch_ua_reduced_expected=*/false);
2926 // Make sure the overridden UA string is the one sent.
2927 CheckUserAgentString(user_agent_override);
Ali Beyad2618b472021-08-31 15:31:042928
2929 // The UserAgentStringType enum is not accessible in //chrome/browser, so
2930 // we just use the enum's integer value.
2931 histograms.ExpectBucketCount("Navigation.UserAgentStringType",
2932 /*NavigationRequest::kOverridden*/ 2, 2);
Ali Beyad4074a9c52021-08-17 16:15:512933}
2934
Ali Beyadf05102d2021-08-23 16:53:402935IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad4074a9c52021-08-17 16:15:512936 UserAgentOverrideSubresourceRequest) {
2937 const std::string user_agent_override = "foo";
2938 SetUserAgentOverride(user_agent_override);
2939
2940 const GURL url = accept_ch_ua_reduced_subresource_request_url();
2941 // First navigation to set the client hints in the response.
Lukasz Anforowiczb78290c2021-09-08 04:31:382942 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
Ali Beyad4074a9c52021-08-17 16:15:512943 // Second navigation has the Sec-CH-UA-Reduced client hint stored from the
2944 // first navigation's response.
Lukasz Anforowiczb78290c2021-09-08 04:31:382945 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
Ali Beyad4074a9c52021-08-17 16:15:512946
2947 // Since the UA override was set, the UA client hints are *not* added to the
2948 // request.
2949 CheckUaReducedClientHint(/*ch_ua_reduced_expected=*/false);
2950 // Make sure the overridden UA string is the one sent.
2951 CheckUserAgentString(user_agent_override);
2952}
2953
Ali Beyadf05102d2021-08-23 16:53:402954IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
Ali Beyad4074a9c52021-08-17 16:15:512955 UserAgentOverrideIframeRequest) {
2956 const std::string user_agent_override = "foo";
2957 SetUserAgentOverride(user_agent_override);
2958
2959 const GURL url = accept_ch_ua_reduced_iframe_request_url();
2960 // First navigation to set the client hints in the response.
Lukasz Anforowiczb78290c2021-09-08 04:31:382961 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
Ali Beyad4074a9c52021-08-17 16:15:512962 // Second navigation has the Sec-CH-UA-Reduced client hint stored from the
2963 // first navigation's response.
Lukasz Anforowiczb78290c2021-09-08 04:31:382964 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
Ali Beyad4074a9c52021-08-17 16:15:512965
2966 // Since the UA override was set, the UA client hints are *not* added to the
2967 // request.
2968 CheckUaReducedClientHint(/*ch_ua_reduced_expected=*/false);
2969 // Make sure the overridden UA string is the one sent.
2970 CheckUserAgentString(user_agent_override);
2971}
2972
Ali Beyad77dba952021-08-25 20:52:582973IN_PROC_BROWSER_TEST_F(SameOriginUaReducedOriginTrialBrowserTest,
2974 NoAcceptCHRemovesSecChUaReducedFromStorage) {
2975 // The first navigation sets Sec-CH-UA-Reduced in the client hints storage for
2976 // the origin.
2977 NavigateAndCheckHeaders(ua_reduced_with_valid_origin_trial_token_url(),
2978 /*ch_ua_reduced_expected=*/false);
2979 // The second navigation doesn't contain an Accept-CH header in the response,
2980 // so Sec-CH-UA-Reduced is removed from the storage.
2981 NavigateAndCheckHeaders(simple_request_url(),
2982 /*ch_ua_reduced_expected=*/true);
2983 // The third navigation doesn't contain a Sec-CH-UA-Reduced in the request
2984 // header because the second navigation caused it to get removed.
2985 NavigateAndCheckHeaders(ua_reduced_with_valid_origin_trial_token_url(),
2986 /*ch_ua_reduced_expected=*/false);
2987}
2988
Ali Beyadb052f5f2021-09-09 07:53:442989IN_PROC_BROWSER_TEST_F(
2990 SameOriginUaReducedOriginTrialBrowserTest,
2991 MissingAcceptCHInIframeResponseHeaderDoesNotRemoveChUaReduced) {
2992 // The first navigation sets Sec-CH-UA-Reduced in the client hints storage for
2993 // the origin. The iframe subresource request does not contain Accept-CH in
2994 // the response, but because it's not a top-level navigation, it should not
2995 // remove Sec-CH-UA-Reduced from the Accept-CH cache.
2996 NavigateAndCheckHeaders(accept_ch_ua_reduced_iframe_request_url(),
2997 /*ch_ua_reduced_expected=*/true);
2998 // The second navigation still finds Sec-CH-UA-Reduced in the Accept-CH cache.
2999 NavigateAndCheckHeaders(ua_reduced_with_valid_origin_trial_token_url(),
3000 /*ch_ua_reduced_expected=*/true);
3001}
3002
Ali Beyadf05102d2021-08-23 16:53:403003// Tests that the Sec-CH-UA-Reduced client hint and the reduced User-Agent
3004// string are sent on request headers for third-party embedded resources if the
3005// Origin Trial token from the top-level frame is valid and the permissions
3006// policy allows it.
3007class ThirdPartyUaReducedOriginTrialBrowserTest
3008 : public UaReducedOriginTrialBrowserTest {
3009 public:
3010 ThirdPartyUaReducedOriginTrialBrowserTest()
3011 : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
3012 https_server_.ServeFilesFromSourceDirectory(
3013 "chrome/test/data/client_hints");
3014 https_server_.RegisterRequestMonitor(base::BindRepeating(
3015 &ThirdPartyUaReducedOriginTrialBrowserTest::MonitorResourceRequest,
3016 base::Unretained(this)));
3017 EXPECT_TRUE(https_server_.Start());
3018 }
3019
3020 // The URL that was used to register the Origin Trial token.
3021 static constexpr char kFirstPartyOriginUrl[] = "https://my-site.com:44444";
3022
3023 void SetUpOnMainThread() override {
3024 InProcessBrowserTest::SetUpOnMainThread();
3025
3026 // We use a URLLoaderInterceptor, rather than the EmbeddedTestServer, since
3027 // the origin trial token in the response is associated with a fixed
3028 // origin, whereas EmbeddedTestServer serves content on a random port.
3029 url_loader_interceptor_ =
3030 std::make_unique<URLLoaderInterceptor>(base::BindRepeating(
3031 &ThirdPartyUaReducedOriginTrialBrowserTest::InterceptRequest,
3032 base::Unretained(this)));
3033 }
3034
3035 void TearDownOnMainThread() override {
3036 url_loader_interceptor_.reset();
3037 InProcessBrowserTest::TearDownOnMainThread();
3038 }
3039
3040 GURL accept_ch_ua_reduced_cross_origin_iframe_request_url() const {
3041 return GURL(base::StrCat(
3042 {kFirstPartyOriginUrl,
Ali Beyad52222ba12021-09-08 19:55:073043 "/accept_ch_ua_reduced_cross_origin_iframe_request.html"}));
Ali Beyadf05102d2021-08-23 16:53:403044 }
3045
3046 GURL accept_ch_ua_reduced_cross_origin_subresource_request_url() const {
3047 return GURL(base::StrCat(
3048 {kFirstPartyOriginUrl,
Ali Beyad52222ba12021-09-08 19:55:073049 "/accept_ch_ua_reduced_cross_origin_subresource_request.html"}));
Ali Beyadf05102d2021-08-23 16:53:403050 }
3051
3052 protected:
3053 const absl::optional<std::string>& GetLastUserAgentHeaderValue() override {
3054 base::AutoLock lock(last_request_lock_);
3055 return last_user_agent_;
3056 }
3057
3058 const absl::optional<std::string>& GetLastUaReducedClientHintValue()
3059 override {
3060 base::AutoLock lock(last_request_lock_);
3061 return last_sec_ch_ua_reduced_;
3062 }
3063
3064 const absl::optional<GURL>& GetLastRequestedURL() {
3065 base::AutoLock lock(last_request_lock_);
3066 return last_requested_url_;
3067 }
3068
3069 void SetUaReducedPermissionsPolicy(const std::string& value) {
3070 ua_reduced_permissions_policy_header_value_ = value;
3071 }
3072
3073 void SetValidOTToken(const bool valid_ot_token) {
3074 valid_ot_token_ = valid_ot_token;
3075 }
3076
3077 GURL GetServerOrigin() const { return https_server_.GetOrigin().GetURL(); }
3078
3079 private:
3080 // URLLoaderInterceptor callback
3081 bool InterceptRequest(URLLoaderInterceptor::RequestParams* params) {
3082 if (params->url_request.url.GetOrigin() != GURL(kFirstPartyOriginUrl)) {
3083 return false;
3084 }
3085 if (params->url_request.url.path() !=
Ali Beyad52222ba12021-09-08 19:55:073086 "/accept_ch_ua_reduced_cross_origin_iframe_request.html" &&
Ali Beyadf05102d2021-08-23 16:53:403087 params->url_request.url.path() !=
Ali Beyad52222ba12021-09-08 19:55:073088 "/accept_ch_ua_reduced_cross_origin_subresource_request.html") {
Ali Beyadf05102d2021-08-23 16:53:403089 return false;
3090 }
3091
3092 // Generated by running (in tools/origin_trials):
3093 // generate_token.py https://my-site.com:44444 UserAgentReduction
3094 // --expire-timestamp=2000000000
3095 //
3096 // The Origin Trial token expires in 2033. Generate a new token by then, or
3097 // find a better way to re-generate a test trial token.
3098 static constexpr const char kOriginTrialToken[] =
3099 "AziP2Iyo74PHkJAVVXJ1NBAyZd+"
3100 "GZFmTqpFtug4Wazsj5rQPFeCFjjZpiEYb086vZzi48lF1ydynMj/"
3101 "oLqqLXgEAAABeeyJvcmlnaW4iOiAiaHR0cHM6Ly9teS1zaXRlLmNvbTo0NDQ0NCIsICJmZ"
3102 "WF0dXJlIjogIlVzZXJBZ2VudFJlZHVjdGlvbiIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ="
3103 "=";
3104
3105 // Construct and send the response.
3106 std::string headers =
3107 "HTTP/1.1 200 OK\nContent-Type: text/html; charset=utf-8\n";
3108 base::StrAppend(&headers, {"Accept-CH: Sec-CH-UA-Reduced\n"});
3109 base::StrAppend(&headers,
3110 {"Permissions-Policy: ch-ua-reduced=",
3111 ua_reduced_permissions_policy_header_value_, "\n"});
3112 base::StrAppend(&headers, {"Origin-Trial: ",
3113 valid_ot_token_ ? kOriginTrialToken
3114 : "invalid-origin-trial-token",
3115 "\n\n"});
3116 std::string body = "<html><head>";
3117 if (params->url_request.url.path() ==
Ali Beyad52222ba12021-09-08 19:55:073118 "/accept_ch_ua_reduced_cross_origin_subresource_request.html") {
Ali Beyadf05102d2021-08-23 16:53:403119 base::StrAppend(&body, {BuildSubresourceHTML()});
3120 }
3121 base::StrAppend(&body, {"</head><body>"});
3122 if (params->url_request.url.path() ==
Ali Beyad52222ba12021-09-08 19:55:073123 "/accept_ch_ua_reduced_cross_origin_iframe_request.html") {
Ali Beyadf05102d2021-08-23 16:53:403124 base::StrAppend(&body, {BuildIframeHTML()});
3125 }
3126 base::StrAppend(&body, {"</body></html>"});
3127 URLLoaderInterceptor::WriteResponse(headers, body, params->client.get());
3128 return true;
3129 }
3130
3131 void SetLastUserAgent(const std::string* value) {
3132 base::AutoLock lock(last_request_lock_);
3133 if (value != nullptr) {
3134 last_user_agent_ = *value;
3135 } else {
3136 NOTREACHED();
3137 }
3138 }
3139
3140 void SetLastSecChUaReduced(const std::string* value) {
3141 base::AutoLock lock(last_request_lock_);
3142 if (value != nullptr) {
3143 last_sec_ch_ua_reduced_ = *value;
3144 } else {
3145 last_sec_ch_ua_reduced_ = absl::nullopt;
3146 }
3147 }
3148
3149 void SetLastRequestedURL(const GURL& url) {
3150 base::AutoLock lock(last_request_lock_);
3151 last_requested_url_ = url;
3152 }
3153
3154 // Called by |https_server_|.
3155 void MonitorResourceRequest(const net::test_server::HttpRequest& request) {
3156 SetLastRequestedURL(request.GetURL());
3157 auto it = request.headers.find("user-agent");
3158 SetLastUserAgent(it != request.headers.end() ? &it->second : nullptr);
3159 it = request.headers.find("sec-ch-ua-reduced");
3160 SetLastSecChUaReduced(it != request.headers.end() ? &it->second : nullptr);
3161 }
3162
3163 std::string BuildIframeHTML() {
3164 std::string html = "<iframe src=\"";
3165 base::StrAppend(
3166 &html, {https_server_.GetURL("/simple.html").spec(), "\"></iframe>"});
3167 return html;
3168 }
3169
3170 std::string BuildSubresourceHTML() {
3171 std::string html = "<link rel=\"stylesheet\" href=\"";
3172 base::StrAppend(&html,
3173 {https_server_.GetURL("/style.css").spec(), "\"></link>"});
3174 return html;
3175 }
3176
3177 std::unique_ptr<URLLoaderInterceptor> url_loader_interceptor_;
3178 net::EmbeddedTestServer https_server_;
3179 std::string ua_reduced_permissions_policy_header_value_;
3180 bool valid_ot_token_ = true;
3181 base::Lock last_request_lock_;
3182 absl::optional<std::string> last_user_agent_ GUARDED_BY(last_request_lock_);
3183 absl::optional<std::string> last_sec_ch_ua_reduced_
3184 GUARDED_BY(last_request_lock_);
3185 absl::optional<GURL> last_requested_url_ GUARDED_BY(last_request_lock_);
3186};
3187
3188constexpr const char
3189 ThirdPartyUaReducedOriginTrialBrowserTest::kFirstPartyOriginUrl[];
3190
3191IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3192 ThirdPartyIframeUaReducedWildcardPolicy) {
3193 SetUaReducedPermissionsPolicy("*"); // Allow all third-party sites.
3194
3195 NavigateAndCheckHeaders(
3196 accept_ch_ua_reduced_cross_origin_iframe_request_url(),
3197 /*ch_ua_reduced_expected=*/true);
3198
3199 // Make sure the last intercepted URL was the request for the embedded iframe.
3200 EXPECT_EQ(GetLastRequestedURL()->path(), "/simple.html");
3201}
3202
3203IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3204 ThirdPartySubresourceUaReducedWithWildcardPolicy) {
3205 SetUaReducedPermissionsPolicy("*"); // Allow all third-party sites.
3206
3207 NavigateAndCheckHeaders(
3208 accept_ch_ua_reduced_cross_origin_subresource_request_url(),
3209 /*ch_ua_reduced_expected=*/true);
3210
3211 // Make sure the last intercepted URL was the request for the embedded iframe.
3212 EXPECT_EQ(GetLastRequestedURL()->path(), "/style.css");
3213}
3214
3215IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3216 ThirdPartyIframeUaReducedSpecificPolicy) {
3217 std::string policy = "(self \"";
3218 base::StrAppend(&policy, {GetServerOrigin().spec(), "\")"});
3219 SetUaReducedPermissionsPolicy(policy); // Allow our third-party site only.
3220
3221 NavigateAndCheckHeaders(
3222 accept_ch_ua_reduced_cross_origin_iframe_request_url(),
3223 /*ch_ua_reduced_expected=*/true);
3224
3225 // Make sure the last intercepted URL was the request for the embedded iframe.
3226 EXPECT_EQ(GetLastRequestedURL()->path(), "/simple.html");
3227}
3228
3229IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3230 ThirdPartySubresourceUaReducedSpecificPolicy) {
3231 std::string policy = "(self \"";
3232 base::StrAppend(&policy, {GetServerOrigin().spec(), "\")"});
3233 SetUaReducedPermissionsPolicy(policy); // Allow our third-party site only.
3234
3235 NavigateAndCheckHeaders(
3236 accept_ch_ua_reduced_cross_origin_subresource_request_url(),
3237 /*ch_ua_reduced_expected=*/true);
3238
3239 // Make sure the last intercepted URL was the request for the embedded iframe.
3240 EXPECT_EQ(GetLastRequestedURL()->path(), "/style.css");
3241}
3242
3243IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3244 ThirdPartyIframeUaReducedPolicyNotAllowed) {
3245 SetUaReducedPermissionsPolicy(
3246 "(self)"); // Only allow self, no third-party sites.
3247
3248 NavigateAndCheckHeaders(
3249 accept_ch_ua_reduced_cross_origin_iframe_request_url(),
3250 /*ch_ua_reduced_expected=*/false);
3251
3252 // Make sure the last intercepted URL was the request for the embedded iframe.
3253 EXPECT_EQ(GetLastRequestedURL()->path(), "/simple.html");
3254}
3255
3256IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3257 ThirdPartySubresourceUaReducedPolicyNotAllowed) {
3258 SetUaReducedPermissionsPolicy(
3259 "(self)"); // Only allow self, no third-party sites.
3260
3261 NavigateAndCheckHeaders(
3262 accept_ch_ua_reduced_cross_origin_subresource_request_url(),
3263 /*ch_ua_reduced_expected=*/false);
3264
3265 // Make sure the last intercepted URL was the request for the embedded iframe.
3266 EXPECT_EQ(GetLastRequestedURL()->path(), "/style.css");
3267}
3268
3269IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3270 ThirdPartyIframeUaReducedInvalidOriginTrialToken) {
3271 SetUaReducedPermissionsPolicy("*"); // Allow all third-party sites.
3272 SetValidOTToken(false); // Origin Trial Token is invalid.
3273
3274 NavigateAndCheckHeaders(
3275 accept_ch_ua_reduced_cross_origin_iframe_request_url(),
3276 /*ch_ua_reduced_expected=*/false);
3277
3278 // Make sure the last intercepted URL was the request for the embedded iframe.
3279 EXPECT_EQ(GetLastRequestedURL()->path(), "/simple.html");
3280}
3281
3282IN_PROC_BROWSER_TEST_F(ThirdPartyUaReducedOriginTrialBrowserTest,
3283 ThirdPartySubresourceUaReducedInvalidOriginTrialToken) {
3284 SetUaReducedPermissionsPolicy("*"); // Allow all third-party sites.
3285 SetValidOTToken(false); // Origin Trial Token is invalid.
3286
3287 NavigateAndCheckHeaders(
3288 accept_ch_ua_reduced_cross_origin_subresource_request_url(),
3289 /*ch_ua_reduced_expected=*/false);
3290
3291 // Make sure the last intercepted URL was the request for the embedded iframe.
3292 EXPECT_EQ(GetLastRequestedURL()->path(), "/style.css");
Ali Beyad7417fc22021-08-06 03:09:583293}