blob: a0db4ee39dfd5693e98f8383e32de1d127486d6b [file] [log] [blame]
// 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