| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h" |
| |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/platform/web_runtime_features.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h" |
| #include "third_party/blink/renderer/platform/network/http_names.h" |
| #include "third_party/blink/renderer/platform/weborigin/kurl.h" |
| |
| namespace blink { |
| |
| class ClientHintsPreferencesTest : public testing::Test {}; |
| |
| TEST_F(ClientHintsPreferencesTest, BasicSecure) { |
| struct TestCase { |
| const char* header_value; |
| bool expectation_resource_width; |
| bool expectation_dpr; |
| bool expectation_viewport_width; |
| bool expectation_rtt; |
| bool expectation_downlink; |
| bool expectation_ect; |
| bool expectation_lang; |
| bool expectation_ua; |
| bool expectation_ua_arch; |
| bool expectation_ua_platform; |
| bool expectation_ua_model; |
| bool expectation_ua_full_version; |
| } cases[] = { |
| {"width, dpr, viewportWidth", true, true, false, false, false, false, |
| false, false, false, false, false, false}, |
| {"WiDtH, dPr, viewport-width, rtt, downlink, ect, lang", true, true, true, |
| true, true, true, true, false, false, false, false, false}, |
| {"WiDtH, dPr, viewport-width, rtt, downlink, effective-connection-type", |
| true, true, true, true, true, false, false, false, false, false, false, |
| false}, |
| {"WIDTH, DPR, VIWEPROT-Width", true, true, false, false, false, false, |
| false, false, false, false, false, false}, |
| {"VIewporT-Width, wutwut, width", true, false, true, false, false, false, |
| false, false, false, false, false, false}, |
| {"dprw", false, false, false, false, false, false, false, false, false, |
| false, false, false}, |
| {"DPRW", false, false, false, false, false, false, false, false, false, |
| false, false, false}, |
| {"sec-ch-ua", false, false, false, false, false, false, false, true, |
| false, false, false, false}, |
| {"sec-ch-ua-arch", false, false, false, false, false, false, false, false, |
| true, false, false, false}, |
| {"sec-ch-ua-platform", false, false, false, false, false, false, false, |
| false, false, true, false, false}, |
| {"sec-ch-ua-model", false, false, false, false, false, false, false, |
| false, false, false, true, false}, |
| {"sec-ch-ua, sec-ch-ua-arch, sec-ch-ua-platform, sec-ch-ua-model, " |
| "sec-ch-ua-full-version", |
| false, false, false, false, false, false, false, true, true, true, true, |
| true}, |
| }; |
| |
| for (const auto& test_case : cases) { |
| SCOPED_TRACE(testing::Message() << test_case.header_value); |
| ClientHintsPreferences preferences; |
| const KURL kurl(String::FromUTF8("https://www.google.com/")); |
| preferences.UpdateFromHttpEquivAcceptCH(test_case.header_value, kurl, |
| nullptr); |
| EXPECT_EQ(test_case.expectation_resource_width, |
| preferences.ShouldSend( |
| network::mojom::WebClientHintsType::kResourceWidth)); |
| EXPECT_EQ(test_case.expectation_dpr, |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kDpr)); |
| EXPECT_EQ(test_case.expectation_viewport_width, |
| preferences.ShouldSend( |
| network::mojom::WebClientHintsType::kViewportWidth)); |
| EXPECT_EQ(test_case.expectation_rtt, |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kRtt)); |
| EXPECT_EQ( |
| test_case.expectation_downlink, |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kDownlink)); |
| EXPECT_EQ(test_case.expectation_ect, |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kEct)); |
| EXPECT_EQ( |
| test_case.expectation_lang, |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kLang)); |
| EXPECT_EQ(test_case.expectation_ua, |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUA)); |
| EXPECT_EQ( |
| test_case.expectation_ua_arch, |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUAArch)); |
| EXPECT_EQ(test_case.expectation_ua_platform, |
| preferences.ShouldSend( |
| network::mojom::WebClientHintsType::kUAPlatform)); |
| EXPECT_EQ( |
| test_case.expectation_ua_model, |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUAModel)); |
| |
| // Calling UpdateFromHttpEquivAcceptCH with an invalid header should |
| // have no impact on client hint preferences. |
| preferences.UpdateFromHttpEquivAcceptCH("1, 42,", kurl, nullptr); |
| EXPECT_EQ(test_case.expectation_resource_width, |
| preferences.ShouldSend( |
| network::mojom::WebClientHintsType::kResourceWidth)); |
| EXPECT_EQ(test_case.expectation_dpr, |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kDpr)); |
| EXPECT_EQ(test_case.expectation_viewport_width, |
| preferences.ShouldSend( |
| network::mojom::WebClientHintsType::kViewportWidth)); |
| |
| // Calling UpdateFromHttpEquivAcceptCH with empty header is also a |
| // no-op, since ClientHintsPreferences only deals with http-equiv, and |
| // hence merge. |
| preferences.UpdateFromHttpEquivAcceptCH("", kurl, nullptr); |
| EXPECT_EQ(test_case.expectation_resource_width, |
| preferences.ShouldSend( |
| network::mojom::WebClientHintsType::kResourceWidth)); |
| EXPECT_EQ(test_case.expectation_dpr, |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kDpr)); |
| EXPECT_EQ(test_case.expectation_viewport_width, |
| preferences.ShouldSend( |
| network::mojom::WebClientHintsType::kViewportWidth)); |
| } |
| } |
| |
| // Verify that the set of enabled client hints is merged every time |
| // Update*() methods are called. |
| TEST_F(ClientHintsPreferencesTest, SecureEnabledTypesMerge) { |
| ClientHintsPreferences preferences; |
| const KURL kurl(String::FromUTF8("https://www.google.com/")); |
| preferences.UpdateFromHttpEquivAcceptCH("rtt, downlink", kurl, nullptr); |
| |
| EXPECT_FALSE(preferences.ShouldSend( |
| network::mojom::WebClientHintsType::kResourceWidth)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kDpr)); |
| EXPECT_FALSE(preferences.ShouldSend( |
| network::mojom::WebClientHintsType::kViewportWidth)); |
| EXPECT_TRUE(preferences.ShouldSend(network::mojom::WebClientHintsType::kRtt)); |
| EXPECT_TRUE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kDownlink)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kEct)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kLang)); |
| EXPECT_FALSE(preferences.ShouldSend(network::mojom::WebClientHintsType::kUA)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUAArch)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUAPlatform)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUAModel)); |
| |
| // Calling UpdateFromHttpEquivAcceptCH with an invalid header should |
| // have no impact on client hint preferences. |
| preferences.UpdateFromHttpEquivAcceptCH("1,,42", kurl, nullptr); |
| EXPECT_FALSE(preferences.ShouldSend( |
| network::mojom::WebClientHintsType::kResourceWidth)); |
| EXPECT_TRUE(preferences.ShouldSend(network::mojom::WebClientHintsType::kRtt)); |
| EXPECT_TRUE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kDownlink)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kEct)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kLang)); |
| EXPECT_FALSE(preferences.ShouldSend(network::mojom::WebClientHintsType::kUA)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUAArch)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUAPlatform)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUAModel)); |
| |
| // Calling UpdateFromHttpEquivAcceptCH with "width" header should |
| // replace add width to preferences |
| preferences.UpdateFromHttpEquivAcceptCH("width", kurl, nullptr); |
| EXPECT_TRUE(preferences.ShouldSend( |
| network::mojom::WebClientHintsType::kResourceWidth)); |
| EXPECT_TRUE(preferences.ShouldSend(network::mojom::WebClientHintsType::kRtt)); |
| EXPECT_TRUE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kDownlink)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kEct)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kLang)); |
| EXPECT_FALSE(preferences.ShouldSend(network::mojom::WebClientHintsType::kUA)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUAArch)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUAPlatform)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUAModel)); |
| |
| // Calling UpdateFromHttpEquivAcceptCH with empty header should not |
| // change anything. |
| preferences.UpdateFromHttpEquivAcceptCH("", kurl, nullptr); |
| EXPECT_TRUE(preferences.ShouldSend( |
| network::mojom::WebClientHintsType::kResourceWidth)); |
| EXPECT_TRUE(preferences.ShouldSend(network::mojom::WebClientHintsType::kRtt)); |
| EXPECT_TRUE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kDownlink)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kEct)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kLang)); |
| EXPECT_FALSE(preferences.ShouldSend(network::mojom::WebClientHintsType::kUA)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUAArch)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUAPlatform)); |
| EXPECT_FALSE( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kUAModel)); |
| } |
| |
| TEST_F(ClientHintsPreferencesTest, Insecure) { |
| for (const auto& use_secure_url : {false, true}) { |
| ClientHintsPreferences preferences; |
| const KURL kurl = use_secure_url |
| ? KURL(String::FromUTF8("https://www.google.com/")) |
| : KURL(String::FromUTF8("http://www.google.com/")); |
| preferences.UpdateFromHttpEquivAcceptCH("dpr", kurl, nullptr); |
| EXPECT_EQ(use_secure_url, |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kDpr)); |
| } |
| } |
| |
| // Verify that the client hints header and the lifetime header is parsed |
| // correctly. |
| TEST_F(ClientHintsPreferencesTest, ParseHeaders) { |
| struct TestCase { |
| const char* accept_ch_header_value; |
| bool expect_device_memory; |
| bool expect_width; |
| bool expect_dpr; |
| bool expect_viewport_width; |
| bool expect_rtt; |
| bool expect_downlink; |
| bool expect_ect; |
| bool expect_lang; |
| bool expect_ua; |
| bool expect_ua_arch; |
| bool expect_ua_platform; |
| bool expect_ua_model; |
| bool expect_ua_full_version; |
| } test_cases[] = { |
| {"width, dpr, viewportWidth, lang", false, true, true, false, false, |
| false, false, true, false, false, false, false, false}, |
| {"width, dpr, viewportWidth", false, true, true, false, false, false, |
| false, false, false, false, false, false, false}, |
| {"width, dpr, viewportWidth", false, true, true, false, false, false, |
| false, false, false, false, false, false, false}, |
| {"width, dpr, viewportWidth", false, true, true, false, false, false, |
| false, false, false, false, false, false, false}, |
| {"width, dpr, rtt, downlink, ect", false, true, true, false, true, true, |
| true, false, false, false, false, false, false}, |
| {"device-memory", true, false, false, false, false, false, false, false, |
| false, false, false, false, false}, |
| {"dpr rtt", false, false, false, false, false, false, false, false, false, |
| false, false, false, false}, |
| {"sec-ch-ua, sec-ch-ua-arch, sec-ch-ua-platform, sec-ch-ua-model, " |
| "sec-ch-ua-full-version", |
| false, false, false, false, false, false, false, false, true, true, true, |
| true, true}, |
| }; |
| |
| for (const auto& test : test_cases) { |
| ClientHintsPreferences preferences; |
| WebEnabledClientHints enabled_types = |
| preferences.GetWebEnabledClientHints(); |
| EXPECT_FALSE(enabled_types.IsEnabled( |
| network::mojom::WebClientHintsType::kDeviceMemory)); |
| EXPECT_FALSE( |
| enabled_types.IsEnabled(network::mojom::WebClientHintsType::kDpr)); |
| EXPECT_FALSE(enabled_types.IsEnabled( |
| network::mojom::WebClientHintsType::kResourceWidth)); |
| EXPECT_FALSE(enabled_types.IsEnabled( |
| network::mojom::WebClientHintsType::kViewportWidth)); |
| EXPECT_FALSE( |
| enabled_types.IsEnabled(network::mojom::WebClientHintsType::kRtt)); |
| EXPECT_FALSE( |
| enabled_types.IsEnabled(network::mojom::WebClientHintsType::kDownlink)); |
| EXPECT_FALSE( |
| enabled_types.IsEnabled(network::mojom::WebClientHintsType::kEct)); |
| EXPECT_FALSE( |
| enabled_types.IsEnabled(network::mojom::WebClientHintsType::kLang)); |
| EXPECT_FALSE( |
| enabled_types.IsEnabled(network::mojom::WebClientHintsType::kUA)); |
| EXPECT_FALSE( |
| enabled_types.IsEnabled(network::mojom::WebClientHintsType::kUAArch)); |
| EXPECT_FALSE(enabled_types.IsEnabled( |
| network::mojom::WebClientHintsType::kUAPlatform)); |
| EXPECT_FALSE( |
| enabled_types.IsEnabled(network::mojom::WebClientHintsType::kUAModel)); |
| |
| const KURL kurl(String::FromUTF8("https://www.google.com/")); |
| preferences.UpdateFromHttpEquivAcceptCH(test.accept_ch_header_value, kurl, |
| nullptr); |
| |
| enabled_types = preferences.GetWebEnabledClientHints(); |
| |
| EXPECT_EQ(test.expect_device_memory, |
| enabled_types.IsEnabled( |
| network::mojom::WebClientHintsType::kDeviceMemory)); |
| EXPECT_EQ(test.expect_dpr, enabled_types.IsEnabled( |
| network::mojom::WebClientHintsType::kDpr)); |
| EXPECT_EQ(test.expect_width, |
| enabled_types.IsEnabled( |
| network::mojom::WebClientHintsType::kResourceWidth)); |
| EXPECT_EQ(test.expect_viewport_width, |
| enabled_types.IsEnabled( |
| network::mojom::WebClientHintsType::kViewportWidth)); |
| EXPECT_EQ(test.expect_rtt, enabled_types.IsEnabled( |
| network::mojom::WebClientHintsType::kRtt)); |
| EXPECT_EQ( |
| test.expect_downlink, |
| enabled_types.IsEnabled(network::mojom::WebClientHintsType::kDownlink)); |
| EXPECT_EQ(test.expect_ect, enabled_types.IsEnabled( |
| network::mojom::WebClientHintsType::kEct)); |
| EXPECT_EQ(test.expect_lang, enabled_types.IsEnabled( |
| network::mojom::WebClientHintsType::kLang)); |
| EXPECT_EQ(test.expect_ua, |
| enabled_types.IsEnabled(network::mojom::WebClientHintsType::kUA)); |
| EXPECT_EQ( |
| test.expect_ua_arch, |
| enabled_types.IsEnabled(network::mojom::WebClientHintsType::kUAArch)); |
| EXPECT_EQ(test.expect_ua_platform, |
| enabled_types.IsEnabled( |
| network::mojom::WebClientHintsType::kUAPlatform)); |
| EXPECT_EQ( |
| test.expect_ua_model, |
| enabled_types.IsEnabled(network::mojom::WebClientHintsType::kUAModel)); |
| } |
| } |
| |
| } // namespace blink |