| // Copyright 2014 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/http/http_server_properties_manager.h" |
| |
| #include <utility> |
| |
| #include "base/feature_list.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/json/json_writer.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/test/bind.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/values_test_util.h" |
| #include "base/time/default_tick_clock.h" |
| #include "base/time/time.h" |
| #include "base/values.h" |
| #include "net/base/features.h" |
| #include "net/base/ip_address.h" |
| #include "net/base/schemeful_site.h" |
| #include "net/http/http_network_session.h" |
| #include "net/http/http_server_properties.h" |
| #include "net/quic/quic_context.h" |
| #include "net/test/test_with_task_environment.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| namespace net { |
| |
| namespace { |
| |
| using base::StringPrintf; |
| using ::testing::_; |
| using ::testing::AtLeast; |
| using ::testing::Invoke; |
| using ::testing::Mock; |
| using ::testing::StrictMock; |
| |
| enum class NetworkAnonymizationKeyMode { |
| kDisabled, |
| kEnabled, |
| }; |
| |
| const NetworkAnonymizationKeyMode kNetworkAnonymizationKeyModes[] = { |
| NetworkAnonymizationKeyMode::kDisabled, |
| NetworkAnonymizationKeyMode::kEnabled, |
| }; |
| |
| std::unique_ptr<base::test::ScopedFeatureList> SetNetworkAnonymizationKeyMode( |
| NetworkAnonymizationKeyMode mode) { |
| auto feature_list = std::make_unique<base::test::ScopedFeatureList>(); |
| switch (mode) { |
| case NetworkAnonymizationKeyMode::kDisabled: |
| feature_list->InitAndDisableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| break; |
| case NetworkAnonymizationKeyMode::kEnabled: |
| feature_list->InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| break; |
| } |
| return feature_list; |
| } |
| |
| class MockPrefDelegate : public net::HttpServerProperties::PrefDelegate { |
| public: |
| MockPrefDelegate() = default; |
| |
| MockPrefDelegate(const MockPrefDelegate&) = delete; |
| MockPrefDelegate& operator=(const MockPrefDelegate&) = delete; |
| |
| ~MockPrefDelegate() override = default; |
| |
| // HttpServerProperties::PrefDelegate implementation. |
| const base::Value::Dict& GetServerProperties() const override { |
| return prefs_; |
| } |
| |
| void SetServerProperties(base::Value::Dict dict, |
| base::OnceClosure callback) override { |
| prefs_.clear(); |
| prefs_.Merge(std::move(dict)); |
| ++num_pref_updates_; |
| if (!prefs_changed_callback_.is_null()) |
| std::move(prefs_changed_callback_).Run(); |
| if (!extra_prefs_changed_callback_.is_null()) |
| std::move(extra_prefs_changed_callback_).Run(); |
| set_properties_callback_ = std::move(callback); |
| } |
| |
| void WaitForPrefLoad(base::OnceClosure callback) override { |
| CHECK(prefs_changed_callback_.is_null()); |
| prefs_changed_callback_ = std::move(callback); |
| } |
| |
| void InitializePrefs(base::Value::Dict dict) { |
| ASSERT_FALSE(prefs_changed_callback_.is_null()); |
| prefs_ = std::move(dict); |
| std::move(prefs_changed_callback_).Run(); |
| } |
| |
| int GetAndClearNumPrefUpdates() { |
| int out = num_pref_updates_; |
| num_pref_updates_ = 0; |
| return out; |
| } |
| |
| // Additional callback to call when prefs are updated, used to check prefs are |
| // updated on destruction. |
| void set_extra_update_prefs_callback(base::OnceClosure callback) { |
| extra_prefs_changed_callback_ = std::move(callback); |
| } |
| |
| // Returns the base::OnceCallback, if any, passed to the last call to |
| // SetServerProperties(). |
| base::OnceClosure GetSetPropertiesCallback() { |
| return std::move(set_properties_callback_); |
| } |
| |
| private: |
| base::Value::Dict prefs_; |
| base::OnceClosure prefs_changed_callback_; |
| base::OnceClosure extra_prefs_changed_callback_; |
| int num_pref_updates_ = 0; |
| |
| base::OnceClosure set_properties_callback_; |
| }; |
| |
| // Converts |server_info_map| to a base::Value::Dict by running it through an |
| // HttpServerPropertiesManager. Other fields are left empty. |
| base::Value::Dict ServerInfoMapToDict( |
| const HttpServerProperties::ServerInfoMap& server_info_map) { |
| std::unique_ptr<MockPrefDelegate> pref_delegate = |
| std::make_unique<MockPrefDelegate>(); |
| MockPrefDelegate* unowned_pref_delegate = pref_delegate.get(); |
| // Callback that shouldn't be invoked - this method short-circuits loading |
| // prefs by calling HttpServerPropertiesManager::WriteToPrefs() before prefs |
| // are loaded. |
| HttpServerPropertiesManager::OnPrefsLoadedCallback on_prefs_loaded_callback = |
| base::BindOnce( |
| [](std::unique_ptr<HttpServerProperties::ServerInfoMap> |
| server_info_map, |
| const IPAddress& last_quic_address, |
| std::unique_ptr<HttpServerProperties::QuicServerInfoMap> |
| quic_server_info_map, |
| std::unique_ptr<BrokenAlternativeServiceList> |
| broken_alternative_service_list, |
| std::unique_ptr<RecentlyBrokenAlternativeServices> |
| recently_broken_alternative_services) { ADD_FAILURE(); }); |
| HttpServerPropertiesManager manager( |
| std::move(pref_delegate), std::move(on_prefs_loaded_callback), |
| 10 /* max_server_configs_stored_in_properties */, nullptr /* net_log */, |
| base::DefaultTickClock::GetInstance()); |
| manager.WriteToPrefs( |
| server_info_map, HttpServerPropertiesManager::GetCannonicalSuffix(), |
| IPAddress() /* last_quic_address */, |
| HttpServerProperties::QuicServerInfoMap(10), |
| BrokenAlternativeServiceList(), RecentlyBrokenAlternativeServices(10), |
| base::OnceClosure()); |
| |
| return unowned_pref_delegate->GetServerProperties().Clone(); |
| } |
| |
| // Does the inverse of ServerInfoMapToDict(). Ignores fields other than the |
| // ServerInfoMap. |
| std::unique_ptr<HttpServerProperties::ServerInfoMap> DictToServerInfoMap( |
| base::Value::Dict dict) { |
| std::unique_ptr<MockPrefDelegate> pref_delegate = |
| std::make_unique<MockPrefDelegate>(); |
| MockPrefDelegate* unowned_pref_delegate = pref_delegate.get(); |
| |
| std::unique_ptr<HttpServerProperties::ServerInfoMap> out; |
| bool callback_invoked = false; |
| HttpServerPropertiesManager::OnPrefsLoadedCallback on_prefs_loaded_callback = |
| base::BindLambdaForTesting( |
| [&](std::unique_ptr<HttpServerProperties::ServerInfoMap> |
| server_info_map, |
| const IPAddress& last_quic_address, |
| std::unique_ptr<HttpServerProperties::QuicServerInfoMap> |
| quic_server_info_map, |
| std::unique_ptr<BrokenAlternativeServiceList> |
| broken_alternative_service_list, |
| std::unique_ptr<RecentlyBrokenAlternativeServices> |
| recently_broken_alternative_services) { |
| ASSERT_FALSE(callback_invoked); |
| callback_invoked = true; |
| out = std::move(server_info_map); |
| }); |
| |
| HttpServerPropertiesManager manager( |
| std::move(pref_delegate), std::move(on_prefs_loaded_callback), |
| 10 /* max_server_configs_stored_in_properties */, nullptr /* net_log */, |
| base::DefaultTickClock::GetInstance()); |
| |
| unowned_pref_delegate->InitializePrefs(std::move(dict)); |
| EXPECT_TRUE(callback_invoked); |
| return out; |
| } |
| |
| } // namespace |
| |
| class HttpServerPropertiesManagerTest : public testing::Test, |
| public WithTaskEnvironment { |
| public: |
| HttpServerPropertiesManagerTest(const HttpServerPropertiesManagerTest&) = |
| delete; |
| HttpServerPropertiesManagerTest& operator=( |
| const HttpServerPropertiesManagerTest&) = delete; |
| |
| protected: |
| HttpServerPropertiesManagerTest() |
| : WithTaskEnvironment( |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME) {} |
| |
| void SetUp() override { |
| one_day_from_now_ = base::Time::Now() + base::Days(1); |
| advertised_versions_ = DefaultSupportedQuicVersions(); |
| auto pref_delegate = std::make_unique<MockPrefDelegate>(); |
| pref_delegate_ = pref_delegate.get(); |
| |
| http_server_props_ = std::make_unique<HttpServerProperties>( |
| std::move(pref_delegate), /*net_log=*/nullptr, GetMockTickClock()); |
| |
| EXPECT_FALSE(http_server_props_->IsInitialized()); |
| EXPECT_EQ(0u, GetPendingMainThreadTaskCount()); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| } |
| |
| // Wrapper around |pref_delegate_|'s InitializePrefs() method that has a |
| // couple extra expectations about whether any tasks are posted, and if a pref |
| // update is queued. |
| // |
| // |expect_pref_update| should be true if a pref update is expected to be |
| // queued in response to the load. |
| void InitializePrefs(base::Value::Dict dict = base::Value::Dict(), |
| bool expect_pref_update = false) { |
| EXPECT_FALSE(http_server_props_->IsInitialized()); |
| pref_delegate_->InitializePrefs(std::move(dict)); |
| EXPECT_TRUE(http_server_props_->IsInitialized()); |
| if (!expect_pref_update) { |
| EXPECT_EQ(0u, GetPendingMainThreadTaskCount()); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| } else { |
| EXPECT_EQ(1u, GetPendingMainThreadTaskCount()); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| } |
| } |
| |
| void TearDown() override { |
| // Run pending non-delayed tasks but don't FastForwardUntilNoTasksRemain() |
| // as some delayed tasks may forever repost (e.g. because impl doesn't use a |
| // mock clock and doesn't see timings as having expired, ref. |
| // HttpServerProperties:: |
| // ScheduleBrokenAlternateProtocolMappingsExpiration()). |
| base::RunLoop().RunUntilIdle(); |
| http_server_props_.reset(); |
| } |
| |
| bool HasAlternativeService( |
| const url::SchemeHostPort& server, |
| const NetworkAnonymizationKey& network_anonymization_key) { |
| const AlternativeServiceInfoVector alternative_service_info_vector = |
| http_server_props_->GetAlternativeServiceInfos( |
| server, network_anonymization_key); |
| return !alternative_service_info_vector.empty(); |
| } |
| |
| // Returns a dictionary with only the version field populated. |
| static base::Value::Dict DictWithVersion() { |
| base::Value::Dict http_server_properties_dict; |
| http_server_properties_dict.Set("version", 5); |
| return http_server_properties_dict; |
| } |
| |
| raw_ptr<MockPrefDelegate> |
| pref_delegate_; // Owned by HttpServerPropertiesManager. |
| std::unique_ptr<HttpServerProperties> http_server_props_; |
| base::Time one_day_from_now_; |
| quic::ParsedQuicVersionVector advertised_versions_; |
| }; |
| |
| TEST_F(HttpServerPropertiesManagerTest, BadCachedHostPortPair) { |
| base::Value::Dict server_pref_dict; |
| |
| // Set supports_spdy for www.google.com:65536. |
| server_pref_dict.Set("supports_spdy", true); |
| |
| // Set up alternative_service for www.google.com:65536. |
| base::Value::Dict alternative_service_dict; |
| alternative_service_dict.Set("protocol_str", "h2"); |
| alternative_service_dict.Set("port", 80); |
| base::Value::List alternative_service_list; |
| alternative_service_list.Append(std::move(alternative_service_dict)); |
| server_pref_dict.Set("alternative_service", |
| std::move(alternative_service_list)); |
| |
| // Set up ServerNetworkStats for www.google.com:65536. |
| base::Value::Dict stats; |
| stats.Set("srtt", 10); |
| server_pref_dict.Set("network_stats", std::move(stats)); |
| |
| // Set the server preference for www.google.com:65536. |
| base::Value::Dict servers_dict; |
| servers_dict.Set("www.google.com:65536", std::move(server_pref_dict)); |
| base::Value::List servers_list; |
| servers_list.Append(std::move(servers_dict)); |
| base::Value::Dict http_server_properties_dict = DictWithVersion(); |
| http_server_properties_dict.Set("servers", std::move(servers_list)); |
| |
| // Set quic_server_info for www.google.com:65536. |
| base::Value::Dict quic_servers_dict; |
| base::Value::Dict quic_server_pref_dict1; |
| quic_server_pref_dict1.Set("server_info", "quic_server_info1"); |
| quic_servers_dict.Set("http://mail.google.com:65536", |
| std::move(quic_server_pref_dict1)); |
| |
| http_server_properties_dict.Set("quic_servers", std::move(quic_servers_dict)); |
| |
| // Set up the pref. |
| InitializePrefs(std::move(http_server_properties_dict)); |
| |
| // Verify that nothing is set. |
| HostPortPair google_host_port_pair = |
| HostPortPair::FromString("www.google.com:65536"); |
| url::SchemeHostPort gooler_server("http", google_host_port_pair.host(), |
| google_host_port_pair.port()); |
| |
| EXPECT_FALSE(http_server_props_->SupportsRequestPriority( |
| gooler_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(HasAlternativeService(gooler_server, NetworkAnonymizationKey())); |
| const ServerNetworkStats* stats1 = http_server_props_->GetServerNetworkStats( |
| gooler_server, NetworkAnonymizationKey()); |
| EXPECT_EQ(nullptr, stats1); |
| EXPECT_EQ(0u, http_server_props_->quic_server_info_map().size()); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, BadCachedAltProtocolPort) { |
| base::Value::Dict server_pref_dict; |
| |
| // Set supports_spdy for www.google.com:80. |
| server_pref_dict.Set("supports_spdy", true); |
| |
| // Set up alternative_service for www.google.com:80. |
| base::Value::Dict alternative_service_dict; |
| alternative_service_dict.Set("protocol_str", "h2"); |
| alternative_service_dict.Set("port", 65536); |
| base::Value::List alternative_service_list; |
| alternative_service_list.Append(std::move(alternative_service_dict)); |
| server_pref_dict.Set("alternative_service", |
| std::move(alternative_service_list)); |
| |
| // Set the server preference for www.google.com:80. |
| base::Value::Dict servers_dict; |
| servers_dict.Set("www.google.com:80", std::move(server_pref_dict)); |
| base::Value::List servers_list; |
| servers_list.Append(std::move(servers_dict)); |
| base::Value::Dict http_server_properties_dict = DictWithVersion(); |
| http_server_properties_dict.Set("servers", std::move(servers_list)); |
| |
| // Set up the pref. |
| InitializePrefs(std::move(http_server_properties_dict)); |
| |
| // Verify alternative service is not set. |
| EXPECT_FALSE( |
| HasAlternativeService(url::SchemeHostPort("http", "www.google.com", 80), |
| NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, SupportsSpdy) { |
| InitializePrefs(); |
| |
| // Add mail.google.com:443 as a supporting spdy server. |
| url::SchemeHostPort spdy_server("https", "mail.google.com", 443); |
| EXPECT_FALSE(http_server_props_->SupportsRequestPriority( |
| spdy_server, NetworkAnonymizationKey())); |
| http_server_props_->SetSupportsSpdy(spdy_server, NetworkAnonymizationKey(), |
| true); |
| // Setting the value to the same thing again should not trigger another pref |
| // update. |
| http_server_props_->SetSupportsSpdy(spdy_server, NetworkAnonymizationKey(), |
| true); |
| |
| // Run the task. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| // Setting the value to the same thing again should not trigger another pref |
| // update. |
| http_server_props_->SetSupportsSpdy(spdy_server, NetworkAnonymizationKey(), |
| true); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_EQ(0u, GetPendingMainThreadTaskCount()); |
| |
| EXPECT_TRUE(http_server_props_->SupportsRequestPriority( |
| spdy_server, NetworkAnonymizationKey())); |
| } |
| |
| // Regression test for crbug.com/670519. Test that there is only one pref update |
| // scheduled if multiple updates happen in a given time period. Subsequent pref |
| // update could also be scheduled once the previous scheduled update is |
| // completed. |
| TEST_F(HttpServerPropertiesManagerTest, |
| SinglePrefUpdateForTwoSpdyServerCacheChanges) { |
| InitializePrefs(); |
| |
| // Post an update task. SetSupportsSpdy calls ScheduleUpdatePrefs with a delay |
| // of 60ms. |
| url::SchemeHostPort spdy_server("https", "mail.google.com", 443); |
| EXPECT_FALSE(http_server_props_->SupportsRequestPriority( |
| spdy_server, NetworkAnonymizationKey())); |
| http_server_props_->SetSupportsSpdy(spdy_server, NetworkAnonymizationKey(), |
| true); |
| // The pref update task should be scheduled. |
| EXPECT_EQ(1u, GetPendingMainThreadTaskCount()); |
| |
| // Move forward the task runner short by 20ms. |
| FastForwardBy(HttpServerProperties::GetUpdatePrefsDelayForTesting() - |
| base::Milliseconds(20)); |
| |
| // Set another spdy server to trigger another call to |
| // ScheduleUpdatePrefs. There should be no new update posted. |
| url::SchemeHostPort spdy_server2("https", "drive.google.com", 443); |
| http_server_props_->SetSupportsSpdy(spdy_server2, NetworkAnonymizationKey(), |
| true); |
| EXPECT_EQ(1u, GetPendingMainThreadTaskCount()); |
| |
| // Move forward the extra 20ms. The pref update should be executed. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| FastForwardBy(base::Milliseconds(20)); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_EQ(0u, GetPendingMainThreadTaskCount()); |
| |
| EXPECT_TRUE(http_server_props_->SupportsRequestPriority( |
| spdy_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE(http_server_props_->SupportsRequestPriority( |
| spdy_server2, NetworkAnonymizationKey())); |
| // Set the third spdy server to trigger one more call to |
| // ScheduleUpdatePrefs. A new update task should be posted now since the |
| // previous one is completed. |
| url::SchemeHostPort spdy_server3("https", "maps.google.com", 443); |
| http_server_props_->SetSupportsSpdy(spdy_server3, NetworkAnonymizationKey(), |
| true); |
| EXPECT_EQ(1u, GetPendingMainThreadTaskCount()); |
| |
| // Run the task. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, GetAlternativeServiceInfos) { |
| InitializePrefs(); |
| |
| url::SchemeHostPort spdy_server_mail("http", "mail.google.com", 80); |
| EXPECT_FALSE( |
| HasAlternativeService(spdy_server_mail, NetworkAnonymizationKey())); |
| const AlternativeService alternative_service(kProtoHTTP2, "mail.google.com", |
| 443); |
| http_server_props_->SetHttp2AlternativeService( |
| spdy_server_mail, NetworkAnonymizationKey(), alternative_service, |
| one_day_from_now_); |
| // ExpectScheduleUpdatePrefs() should be called only once. |
| http_server_props_->SetHttp2AlternativeService( |
| spdy_server_mail, NetworkAnonymizationKey(), alternative_service, |
| one_day_from_now_); |
| |
| // Run the task. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| AlternativeServiceInfoVector alternative_service_info_vector = |
| http_server_props_->GetAlternativeServiceInfos(spdy_server_mail, |
| NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(alternative_service, |
| alternative_service_info_vector[0].alternative_service()); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, SetAlternativeServices) { |
| InitializePrefs(); |
| |
| url::SchemeHostPort spdy_server_mail("http", "mail.google.com", 80); |
| EXPECT_FALSE( |
| HasAlternativeService(spdy_server_mail, NetworkAnonymizationKey())); |
| AlternativeServiceInfoVector alternative_service_info_vector; |
| const AlternativeService alternative_service1(kProtoHTTP2, "mail.google.com", |
| 443); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service1, one_day_from_now_)); |
| const AlternativeService alternative_service2(kProtoQUIC, "mail.google.com", |
| 1234); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( |
| alternative_service2, one_day_from_now_, advertised_versions_)); |
| http_server_props_->SetAlternativeServices(spdy_server_mail, |
| NetworkAnonymizationKey(), |
| alternative_service_info_vector); |
| // ExpectScheduleUpdatePrefs() should be called only once. |
| http_server_props_->SetAlternativeServices(spdy_server_mail, |
| NetworkAnonymizationKey(), |
| alternative_service_info_vector); |
| |
| // Run the task. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| AlternativeServiceInfoVector alternative_service_info_vector2 = |
| http_server_props_->GetAlternativeServiceInfos(spdy_server_mail, |
| NetworkAnonymizationKey()); |
| ASSERT_EQ(2u, alternative_service_info_vector2.size()); |
| EXPECT_EQ(alternative_service1, |
| alternative_service_info_vector2[0].alternative_service()); |
| EXPECT_EQ(alternative_service2, |
| alternative_service_info_vector2[1].alternative_service()); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, SetAlternativeServicesEmpty) { |
| InitializePrefs(); |
| |
| url::SchemeHostPort spdy_server_mail("http", "mail.google.com", 80); |
| EXPECT_FALSE( |
| HasAlternativeService(spdy_server_mail, NetworkAnonymizationKey())); |
| const AlternativeService alternative_service(kProtoHTTP2, "mail.google.com", |
| 443); |
| http_server_props_->SetAlternativeServices(spdy_server_mail, |
| NetworkAnonymizationKey(), |
| AlternativeServiceInfoVector()); |
| |
| EXPECT_EQ(0u, GetPendingMainThreadTaskCount()); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| EXPECT_FALSE( |
| HasAlternativeService(spdy_server_mail, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, ConfirmAlternativeService) { |
| InitializePrefs(); |
| |
| url::SchemeHostPort spdy_server_mail; |
| AlternativeService alternative_service; |
| |
| spdy_server_mail = url::SchemeHostPort("http", "mail.google.com", 80); |
| EXPECT_FALSE( |
| HasAlternativeService(spdy_server_mail, NetworkAnonymizationKey())); |
| alternative_service = AlternativeService(kProtoHTTP2, "mail.google.com", 443); |
| |
| http_server_props_->SetHttp2AlternativeService( |
| spdy_server_mail, NetworkAnonymizationKey(), alternative_service, |
| one_day_from_now_); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| EXPECT_EQ(1u, GetPendingMainThreadTaskCount()); |
| |
| http_server_props_->MarkAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey()); |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_TRUE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| // In addition to the pref update task, there's now a task to mark the |
| // alternative service as no longer broken. |
| EXPECT_EQ(2u, GetPendingMainThreadTaskCount()); |
| |
| http_server_props_->ConfirmAlternativeService(alternative_service, |
| NetworkAnonymizationKey()); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| EXPECT_EQ(2u, GetPendingMainThreadTaskCount()); |
| |
| // Run the task. |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| } |
| |
| // Check the case that prefs are loaded only after setting alternative service |
| // info. Prefs should not be written until after the load happens. |
| TEST_F(HttpServerPropertiesManagerTest, LateLoadAlternativeServiceInfo) { |
| url::SchemeHostPort spdy_server_mail("http", "mail.google.com", 80); |
| EXPECT_FALSE( |
| HasAlternativeService(spdy_server_mail, NetworkAnonymizationKey())); |
| const AlternativeService alternative_service(kProtoHTTP2, "mail.google.com", |
| 443); |
| http_server_props_->SetHttp2AlternativeService( |
| spdy_server_mail, NetworkAnonymizationKey(), alternative_service, |
| one_day_from_now_); |
| |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_EQ(0u, GetPendingMainThreadTaskCount()); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| AlternativeServiceInfoVector alternative_service_info_vector = |
| http_server_props_->GetAlternativeServiceInfos(spdy_server_mail, |
| NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(alternative_service, |
| alternative_service_info_vector[0].alternative_service()); |
| |
| // Initializing prefs does not result in a task to write the prefs. |
| InitializePrefs(base::Value::Dict(), |
| /*expect_pref_update=*/true); |
| alternative_service_info_vector = |
| http_server_props_->GetAlternativeServiceInfos(spdy_server_mail, |
| NetworkAnonymizationKey()); |
| EXPECT_EQ(1u, alternative_service_info_vector.size()); |
| |
| // Updating the entry should result in a task to save prefs. Have to at least |
| // double (or half) the lifetime, to ensure the change triggers a save to |
| // prefs. |
| http_server_props_->SetHttp2AlternativeService( |
| spdy_server_mail, NetworkAnonymizationKey(), alternative_service, |
| one_day_from_now_ + base::Days(2)); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_EQ(1u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| alternative_service_info_vector = |
| http_server_props_->GetAlternativeServiceInfos(spdy_server_mail, |
| NetworkAnonymizationKey()); |
| EXPECT_EQ(1u, alternative_service_info_vector.size()); |
| } |
| |
| // Check the case that prefs are cleared before they're loaded. |
| TEST_F(HttpServerPropertiesManagerTest, |
| ClearPrefsBeforeLoadAlternativeServiceInfo) { |
| url::SchemeHostPort spdy_server_mail("http", "mail.google.com", 80); |
| EXPECT_FALSE( |
| HasAlternativeService(spdy_server_mail, NetworkAnonymizationKey())); |
| const AlternativeService alternative_service(kProtoHTTP2, "mail.google.com", |
| 443); |
| http_server_props_->SetHttp2AlternativeService( |
| spdy_server_mail, NetworkAnonymizationKey(), alternative_service, |
| one_day_from_now_); |
| |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_EQ(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| AlternativeServiceInfoVector alternative_service_info_vector = |
| http_server_props_->GetAlternativeServiceInfos(spdy_server_mail, |
| NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(alternative_service, |
| alternative_service_info_vector[0].alternative_service()); |
| |
| // Clearing prefs should result in a task to write the prefs. |
| bool callback_invoked_ = false; |
| http_server_props_->Clear(base::BindOnce( |
| [](bool* callback_invoked) { |
| EXPECT_FALSE(*callback_invoked); |
| *callback_invoked = true; |
| }, |
| &callback_invoked_)); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_FALSE(callback_invoked_); |
| std::move(pref_delegate_->GetSetPropertiesCallback()).Run(); |
| EXPECT_TRUE(callback_invoked_); |
| alternative_service_info_vector = |
| http_server_props_->GetAlternativeServiceInfos(spdy_server_mail, |
| NetworkAnonymizationKey()); |
| EXPECT_EQ(0u, alternative_service_info_vector.size()); |
| |
| // Re-creating the entry should result in a task to save prefs. |
| http_server_props_->SetHttp2AlternativeService( |
| spdy_server_mail, NetworkAnonymizationKey(), alternative_service, |
| one_day_from_now_); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_EQ(1u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| alternative_service_info_vector = |
| http_server_props_->GetAlternativeServiceInfos(spdy_server_mail, |
| NetworkAnonymizationKey()); |
| EXPECT_EQ(1u, alternative_service_info_vector.size()); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, |
| ConfirmBrokenUntilDefaultNetworkChanges) { |
| InitializePrefs(); |
| |
| url::SchemeHostPort spdy_server_mail; |
| AlternativeService alternative_service; |
| |
| spdy_server_mail = url::SchemeHostPort("http", "mail.google.com", 80); |
| EXPECT_FALSE( |
| HasAlternativeService(spdy_server_mail, NetworkAnonymizationKey())); |
| alternative_service = AlternativeService(kProtoHTTP2, "mail.google.com", 443); |
| |
| http_server_props_->SetHttp2AlternativeService( |
| spdy_server_mail, NetworkAnonymizationKey(), alternative_service, |
| one_day_from_now_); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| EXPECT_EQ(1u, GetPendingMainThreadTaskCount()); |
| |
| http_server_props_->MarkAlternativeServiceBrokenUntilDefaultNetworkChanges( |
| alternative_service, NetworkAnonymizationKey()); |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_TRUE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| // In addition to the pref update task, there's now a task to mark the |
| // alternative service as no longer broken. |
| EXPECT_EQ(2u, GetPendingMainThreadTaskCount()); |
| |
| http_server_props_->ConfirmAlternativeService(alternative_service, |
| NetworkAnonymizationKey()); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| EXPECT_EQ(2u, GetPendingMainThreadTaskCount()); |
| |
| // Run the task. |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, |
| OnDefaultNetworkChangedWithBrokenUntilDefaultNetworkChanges) { |
| InitializePrefs(); |
| |
| url::SchemeHostPort spdy_server_mail; |
| AlternativeService alternative_service; |
| |
| spdy_server_mail = url::SchemeHostPort("http", "mail.google.com", 80); |
| EXPECT_FALSE( |
| HasAlternativeService(spdy_server_mail, NetworkAnonymizationKey())); |
| alternative_service = AlternativeService(kProtoHTTP2, "mail.google.com", 443); |
| |
| http_server_props_->SetHttp2AlternativeService( |
| spdy_server_mail, NetworkAnonymizationKey(), alternative_service, |
| one_day_from_now_); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| EXPECT_EQ(1u, GetPendingMainThreadTaskCount()); |
| |
| http_server_props_->MarkAlternativeServiceBrokenUntilDefaultNetworkChanges( |
| alternative_service, NetworkAnonymizationKey()); |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_TRUE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| // In addition to the pref update task, there's now a task to mark the |
| // alternative service as no longer broken. |
| EXPECT_EQ(2u, GetPendingMainThreadTaskCount()); |
| |
| http_server_props_->OnDefaultNetworkChanged(); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| EXPECT_EQ(2u, GetPendingMainThreadTaskCount()); |
| |
| // Run the task. |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, OnDefaultNetworkChangedWithBrokenOnly) { |
| InitializePrefs(); |
| |
| url::SchemeHostPort spdy_server_mail; |
| AlternativeService alternative_service; |
| |
| spdy_server_mail = url::SchemeHostPort("http", "mail.google.com", 80); |
| EXPECT_FALSE( |
| HasAlternativeService(spdy_server_mail, NetworkAnonymizationKey())); |
| alternative_service = AlternativeService(kProtoHTTP2, "mail.google.com", 443); |
| |
| http_server_props_->SetHttp2AlternativeService( |
| spdy_server_mail, NetworkAnonymizationKey(), alternative_service, |
| one_day_from_now_); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| EXPECT_EQ(1u, GetPendingMainThreadTaskCount()); |
| |
| http_server_props_->MarkAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey()); |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_TRUE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| // In addition to the pref update task, there's now a task to mark the |
| // alternative service as no longer broken. |
| EXPECT_EQ(2u, GetPendingMainThreadTaskCount()); |
| |
| http_server_props_->OnDefaultNetworkChanged(); |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_TRUE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| EXPECT_EQ(2u, GetPendingMainThreadTaskCount()); |
| |
| // Run the task. |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| EXPECT_TRUE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, LastLocalAddressWhenQuicWorked) { |
| InitializePrefs(); |
| |
| IPAddress actual_address(127, 0, 0, 1); |
| EXPECT_FALSE(http_server_props_->HasLastLocalAddressWhenQuicWorked()); |
| EXPECT_FALSE( |
| http_server_props_->WasLastLocalAddressWhenQuicWorked(actual_address)); |
| http_server_props_->SetLastLocalAddressWhenQuicWorked(actual_address); |
| // Another task should not be scheduled. |
| http_server_props_->SetLastLocalAddressWhenQuicWorked(actual_address); |
| |
| // Run the task. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| EXPECT_TRUE( |
| http_server_props_->WasLastLocalAddressWhenQuicWorked(actual_address)); |
| |
| // Another task should not be scheduled. |
| http_server_props_->SetLastLocalAddressWhenQuicWorked(actual_address); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_EQ(0u, GetPendingMainThreadTaskCount()); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, ServerNetworkStats) { |
| InitializePrefs(); |
| |
| url::SchemeHostPort mail_server("http", "mail.google.com", 80); |
| const ServerNetworkStats* stats = http_server_props_->GetServerNetworkStats( |
| mail_server, NetworkAnonymizationKey()); |
| EXPECT_EQ(nullptr, stats); |
| ServerNetworkStats stats1; |
| stats1.srtt = base::Microseconds(10); |
| http_server_props_->SetServerNetworkStats(mail_server, |
| NetworkAnonymizationKey(), stats1); |
| // Another task should not be scheduled. |
| http_server_props_->SetServerNetworkStats(mail_server, |
| NetworkAnonymizationKey(), stats1); |
| |
| // Run the task. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| // Another task should not be scheduled. |
| http_server_props_->SetServerNetworkStats(mail_server, |
| NetworkAnonymizationKey(), stats1); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_EQ(GetPendingMainThreadTaskCount(), 0u); |
| |
| const ServerNetworkStats* stats2 = http_server_props_->GetServerNetworkStats( |
| mail_server, NetworkAnonymizationKey()); |
| EXPECT_EQ(10, stats2->srtt.ToInternalValue()); |
| |
| http_server_props_->ClearServerNetworkStats(mail_server, |
| NetworkAnonymizationKey()); |
| |
| // Run the task. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| EXPECT_EQ(nullptr, http_server_props_->GetServerNetworkStats( |
| mail_server, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, QuicServerInfo) { |
| InitializePrefs(); |
| |
| quic::QuicServerId mail_quic_server_id("mail.google.com", 80, false); |
| EXPECT_EQ(nullptr, http_server_props_->GetQuicServerInfo( |
| mail_quic_server_id, NetworkAnonymizationKey())); |
| std::string quic_server_info1("quic_server_info1"); |
| http_server_props_->SetQuicServerInfo( |
| mail_quic_server_id, NetworkAnonymizationKey(), quic_server_info1); |
| // Another task should not be scheduled. |
| http_server_props_->SetQuicServerInfo( |
| mail_quic_server_id, NetworkAnonymizationKey(), quic_server_info1); |
| |
| // Run the task. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| EXPECT_EQ(quic_server_info1, |
| *http_server_props_->GetQuicServerInfo(mail_quic_server_id, |
| NetworkAnonymizationKey())); |
| |
| // Another task should not be scheduled. |
| http_server_props_->SetQuicServerInfo( |
| mail_quic_server_id, NetworkAnonymizationKey(), quic_server_info1); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_EQ(0u, GetPendingMainThreadTaskCount()); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, Clear) { |
| InitializePrefs(); |
| |
| const url::SchemeHostPort spdy_server("https", "mail.google.com", 443); |
| const IPAddress actual_address(127, 0, 0, 1); |
| const quic::QuicServerId mail_quic_server_id("mail.google.com", 80, false); |
| const std::string quic_server_info1("quic_server_info1"); |
| const AlternativeService alternative_service(kProtoHTTP2, "mail.google.com", |
| 1234); |
| const AlternativeService broken_alternative_service( |
| kProtoHTTP2, "broken.google.com", 1234); |
| |
| AlternativeServiceInfoVector alt_svc_info_vector; |
| alt_svc_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service, one_day_from_now_)); |
| alt_svc_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| broken_alternative_service, one_day_from_now_)); |
| http_server_props_->SetAlternativeServices( |
| spdy_server, NetworkAnonymizationKey(), alt_svc_info_vector); |
| |
| http_server_props_->MarkAlternativeServiceBroken(broken_alternative_service, |
| NetworkAnonymizationKey()); |
| http_server_props_->SetSupportsSpdy(spdy_server, NetworkAnonymizationKey(), |
| true); |
| http_server_props_->SetLastLocalAddressWhenQuicWorked(actual_address); |
| ServerNetworkStats stats; |
| stats.srtt = base::Microseconds(10); |
| http_server_props_->SetServerNetworkStats(spdy_server, |
| NetworkAnonymizationKey(), stats); |
| |
| http_server_props_->SetQuicServerInfo( |
| mail_quic_server_id, NetworkAnonymizationKey(), quic_server_info1); |
| |
| // Advance time by just enough so that the prefs update task is executed but |
| // not the task to expire the brokenness of |broken_alternative_service|. |
| FastForwardBy(HttpServerProperties::GetUpdatePrefsDelayForTesting()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| broken_alternative_service, NetworkAnonymizationKey())); |
| EXPECT_TRUE(http_server_props_->SupportsRequestPriority( |
| spdy_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE(HasAlternativeService(spdy_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| http_server_props_->WasLastLocalAddressWhenQuicWorked(actual_address)); |
| const ServerNetworkStats* stats1 = http_server_props_->GetServerNetworkStats( |
| spdy_server, NetworkAnonymizationKey()); |
| EXPECT_EQ(10, stats1->srtt.ToInternalValue()); |
| EXPECT_EQ(quic_server_info1, |
| *http_server_props_->GetQuicServerInfo(mail_quic_server_id, |
| NetworkAnonymizationKey())); |
| |
| // Clear http server data, which should instantly update prefs. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| bool callback_invoked_ = false; |
| http_server_props_->Clear(base::BindOnce( |
| [](bool* callback_invoked) { |
| EXPECT_FALSE(*callback_invoked); |
| *callback_invoked = true; |
| }, |
| &callback_invoked_)); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_FALSE(callback_invoked_); |
| std::move(pref_delegate_->GetSetPropertiesCallback()).Run(); |
| EXPECT_TRUE(callback_invoked_); |
| |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| broken_alternative_service, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->SupportsRequestPriority( |
| spdy_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(HasAlternativeService(spdy_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->HasLastLocalAddressWhenQuicWorked()); |
| const ServerNetworkStats* stats2 = http_server_props_->GetServerNetworkStats( |
| spdy_server, NetworkAnonymizationKey()); |
| EXPECT_EQ(nullptr, stats2); |
| EXPECT_EQ(nullptr, http_server_props_->GetQuicServerInfo( |
| mail_quic_server_id, NetworkAnonymizationKey())); |
| } |
| |
| // https://crbug.com/444956: Add 200 alternative_service servers followed by |
| // supports_quic and verify we have read supports_quic from prefs. |
| TEST_F(HttpServerPropertiesManagerTest, BadLastLocalAddressWhenQuicWorked) { |
| base::Value::List servers_list; |
| |
| for (int i = 1; i <= 200; ++i) { |
| // Set up alternative_service for www.google.com:i. |
| base::Value::Dict server_dict; |
| base::Value::Dict alternative_service_dict; |
| alternative_service_dict.Set("protocol_str", "quic"); |
| alternative_service_dict.Set("port", i); |
| base::Value::List alternative_service_list; |
| alternative_service_list.Append(std::move(alternative_service_dict)); |
| server_dict.Set("alternative_service", std::move(alternative_service_list)); |
| server_dict.Set("server", StringPrintf("https://www.google.com:%d", i)); |
| server_dict.Set("anonymization", base::Value(base::Value::Type::LIST)); |
| servers_list.Append(std::move(server_dict)); |
| } |
| |
| // Set the server preference for http://mail.google.com server. |
| base::Value::Dict server_dict2; |
| server_dict2.Set("server", "https://mail.google.com"); |
| server_dict2.Set("anonymization", base::Value(base::Value::Type::LIST)); |
| servers_list.Append(std::move(server_dict2)); |
| |
| base::Value::Dict http_server_properties_dict = DictWithVersion(); |
| http_server_properties_dict.Set("servers", std::move(servers_list)); |
| |
| // Set up SupportsQuic for 127.0.0.1 |
| base::Value::Dict supports_quic; |
| supports_quic.Set("used_quic", true); |
| supports_quic.Set("address", "127.0.0.1"); |
| http_server_properties_dict.Set("supports_quic", std::move(supports_quic)); |
| |
| // Set up the pref. |
| InitializePrefs(std::move(http_server_properties_dict)); |
| |
| // Verify alternative service. |
| for (int i = 1; i <= 200; ++i) { |
| GURL server_gurl; |
| server_gurl = GURL(StringPrintf("https://www.google.com:%d", i)); |
| url::SchemeHostPort server(server_gurl); |
| AlternativeServiceInfoVector alternative_service_info_vector = |
| http_server_props_->GetAlternativeServiceInfos( |
| server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ( |
| kProtoQUIC, |
| alternative_service_info_vector[0].alternative_service().protocol); |
| EXPECT_EQ(i, alternative_service_info_vector[0].alternative_service().port); |
| } |
| |
| // Verify WasLastLocalAddressWhenQuicWorked. |
| ASSERT_TRUE(http_server_props_->WasLastLocalAddressWhenQuicWorked( |
| IPAddress::IPv4Localhost())); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, UpdatePrefsWithCache) { |
| InitializePrefs(); |
| |
| const url::SchemeHostPort server_www("https", "www.google.com", 80); |
| const url::SchemeHostPort server_mail("https", "mail.google.com", 80); |
| |
| // #1 & #2: Set alternate protocol. |
| AlternativeServiceInfoVector alternative_service_info_vector; |
| AlternativeService www_alternative_service1(kProtoHTTP2, "", 443); |
| base::Time expiration1; |
| ASSERT_TRUE(base::Time::FromUTCString("2036-12-01 10:00:00", &expiration1)); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| www_alternative_service1, expiration1)); |
| |
| AlternativeService www_alternative_service2(kProtoHTTP2, "www.google.com", |
| 1234); |
| base::Time expiration2; |
| ASSERT_TRUE(base::Time::FromUTCString("2036-12-31 10:00:00", &expiration2)); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| www_alternative_service2, expiration2)); |
| http_server_props_->SetAlternativeServices( |
| server_www, NetworkAnonymizationKey(), alternative_service_info_vector); |
| |
| AlternativeService mail_alternative_service(kProtoHTTP2, "foo.google.com", |
| 444); |
| base::Time expiration3 = base::Time::Max(); |
| http_server_props_->SetHttp2AlternativeService( |
| server_mail, NetworkAnonymizationKey(), mail_alternative_service, |
| expiration3); |
| |
| http_server_props_->MarkAlternativeServiceBroken(www_alternative_service2, |
| NetworkAnonymizationKey()); |
| http_server_props_->MarkAlternativeServiceRecentlyBroken( |
| mail_alternative_service, NetworkAnonymizationKey()); |
| |
| // #3: Set SPDY server map |
| http_server_props_->SetSupportsSpdy(server_www, NetworkAnonymizationKey(), |
| false); |
| http_server_props_->SetSupportsSpdy(server_mail, NetworkAnonymizationKey(), |
| true); |
| http_server_props_->SetSupportsSpdy( |
| url::SchemeHostPort("http", "not_persisted.com", 80), |
| NetworkAnonymizationKey(), false); |
| |
| // #4: Set ServerNetworkStats. |
| ServerNetworkStats stats; |
| stats.srtt = base::TimeDelta::FromInternalValue(42); |
| http_server_props_->SetServerNetworkStats(server_mail, |
| NetworkAnonymizationKey(), stats); |
| |
| // #5: Set quic_server_info string. |
| quic::QuicServerId mail_quic_server_id("mail.google.com", 80, false); |
| std::string quic_server_info1("quic_server_info1"); |
| http_server_props_->SetQuicServerInfo( |
| mail_quic_server_id, NetworkAnonymizationKey(), quic_server_info1); |
| |
| // #6: Set SupportsQuic. |
| IPAddress actual_address(127, 0, 0, 1); |
| http_server_props_->SetLastLocalAddressWhenQuicWorked(actual_address); |
| |
| base::Time time_before_prefs_update = base::Time::Now(); |
| |
| // Update Prefs. |
| // The task runner has a remaining pending task to expire |
| // |www_alternative_service2| in 5 minutes. Fast forward enough such |
| // that the prefs update task is executed but not the task to expire |
| // |broken_alternative_service|. |
| EXPECT_EQ(2u, GetPendingMainThreadTaskCount()); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| FastForwardBy(HttpServerProperties::GetUpdatePrefsDelayForTesting()); |
| EXPECT_EQ(1u, GetPendingMainThreadTaskCount()); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| base::Time time_after_prefs_update = base::Time::Now(); |
| |
| // Verify |pref_delegate_|'s server dict. |
| // In HttpServerPropertiesManager, broken alternative services' expiration |
| // times are converted from TimeTicks to Time before being written to JSON by |
| // using the difference between Time::Now() and TimeTicks::Now(). |
| // To verify these expiration times, |time_before_prefs_update| and |
| // |time_after_prefs_update| provide lower and upper bounds for the |
| // Time::Now() value used by the manager for this conversion. |
| // |
| // A copy of |pref_delegate_|'s server dict will be created, and the broken |
| // alternative service's "broken_until" field is removed and verified |
| // separately. The rest of the server dict copy is verified afterwards. |
| base::Value::Dict server_dict = pref_delegate_->GetServerProperties().Clone(); |
| |
| // Extract and remove the "broken_until" string for "www.google.com:1234". |
| base::Value::List* broken_alt_svc_list = |
| server_dict.FindList("broken_alternative_services"); |
| ASSERT_TRUE(broken_alt_svc_list); |
| ASSERT_EQ(2u, broken_alt_svc_list->size()); |
| base::Value& broken_alt_svcs_list_entry = (*broken_alt_svc_list)[0]; |
| const std::string* broken_until_str = |
| broken_alt_svcs_list_entry.GetDict().FindString("broken_until"); |
| ASSERT_TRUE(broken_until_str); |
| const std::string expiration_string = *broken_until_str; |
| broken_alt_svcs_list_entry.GetDict().Remove("broken_until"); |
| |
| // Expiration time of "www.google.com:1234" should be 5 minutes minus the |
| // update-prefs-delay from when the prefs were written. |
| int64_t expiration_int64; |
| ASSERT_TRUE(base::StringToInt64(expiration_string, &expiration_int64)); |
| base::TimeDelta expiration_delta = |
| base::Minutes(5) - HttpServerProperties::GetUpdatePrefsDelayForTesting(); |
| time_t time_t_of_prefs_update = static_cast<time_t>(expiration_int64); |
| EXPECT_LE((time_before_prefs_update + expiration_delta).ToTimeT(), |
| time_t_of_prefs_update); |
| EXPECT_GE((time_after_prefs_update + expiration_delta).ToTimeT(), |
| time_t_of_prefs_update); |
| |
| // Verify all other preferences. |
| const char expected_json[] = |
| "{" |
| "\"broken_alternative_services\":" |
| "[{\"anonymization\":[],\"broken_count\":1,\"host\":\"www.google.com\"," |
| "\"port\":1234,\"protocol_str\":\"h2\"}," |
| "{\"anonymization\":[],\"broken_count\":1,\"host\":\"foo.google.com\"," |
| "\"port\":444,\"protocol_str\":\"h2\"}]," |
| "\"quic_servers\":" |
| "[{\"anonymization\":[]," |
| "\"server_id\":\"https://mail.google.com:80\"," |
| "\"server_info\":\"quic_server_info1\"}]," |
| "\"servers\":[" |
| "{\"alternative_service\":[{\"advertised_alpns\":[]," |
| "\"expiration\":\"13756212000000000\",\"port\":443," |
| "\"protocol_str\":\"h2\"}," |
| "{\"advertised_alpns\":[],\"expiration\":\"13758804000000000\"," |
| "\"host\":\"www.google.com\",\"port\":1234,\"protocol_str\":\"h2\"}]," |
| "\"anonymization\":[]," |
| "\"server\":\"https://www.google.com:80\"}," |
| "{\"alternative_service\":[{\"advertised_alpns\":[]," |
| "\"expiration\":\"9223372036854775807\",\"host\":\"foo.google.com\"," |
| "\"port\":444,\"protocol_str\":\"h2\"}]," |
| "\"anonymization\":[]," |
| "\"network_stats\":{\"srtt\":42}," |
| "\"server\":\"https://mail.google.com:80\"," |
| "\"supports_spdy\":true}]," |
| "\"supports_quic\":{\"address\":\"127.0.0.1\",\"used_quic\":true}," |
| "\"version\":5}"; |
| |
| std::string preferences_json; |
| EXPECT_TRUE(base::JSONWriter::Write(server_dict, &preferences_json)); |
| EXPECT_EQ(expected_json, preferences_json); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, ParseAlternativeServiceInfo) { |
| InitializePrefs(); |
| |
| base::Value::Dict server_dict = base::test::ParseJsonDict( |
| "{\"alternative_service\":[{\"port\":443,\"protocol_str\":\"h2\"}," |
| "{\"port\":123,\"protocol_str\":\"quic\"," |
| "\"expiration\":\"9223372036854775807\"},{\"host\":\"example.org\"," |
| "\"port\":1234,\"protocol_str\":\"h2\"," |
| "\"expiration\":\"13758804000000000\"}]}"); |
| |
| const url::SchemeHostPort server("https", "example.com", 443); |
| HttpServerProperties::ServerInfo server_info; |
| EXPECT_TRUE(HttpServerPropertiesManager::ParseAlternativeServiceInfo( |
| server, server_dict, &server_info)); |
| |
| ASSERT_TRUE(server_info.alternative_services.has_value()); |
| AlternativeServiceInfoVector alternative_service_info_vector = |
| server_info.alternative_services.value(); |
| ASSERT_EQ(3u, alternative_service_info_vector.size()); |
| |
| EXPECT_EQ(kProtoHTTP2, |
| alternative_service_info_vector[0].alternative_service().protocol); |
| EXPECT_EQ("", alternative_service_info_vector[0].alternative_service().host); |
| EXPECT_EQ(443, alternative_service_info_vector[0].alternative_service().port); |
| // Expiration defaults to one day from now, testing with tolerance. |
| const base::Time now = base::Time::Now(); |
| const base::Time expiration = alternative_service_info_vector[0].expiration(); |
| EXPECT_LE(now + base::Hours(23), expiration); |
| EXPECT_GE(now + base::Days(1), expiration); |
| |
| EXPECT_EQ(kProtoQUIC, |
| alternative_service_info_vector[1].alternative_service().protocol); |
| EXPECT_EQ("", alternative_service_info_vector[1].alternative_service().host); |
| EXPECT_EQ(123, alternative_service_info_vector[1].alternative_service().port); |
| // numeric_limits<int64_t>::max() represents base::Time::Max(). |
| EXPECT_EQ(base::Time::Max(), alternative_service_info_vector[1].expiration()); |
| |
| EXPECT_EQ(kProtoHTTP2, |
| alternative_service_info_vector[2].alternative_service().protocol); |
| EXPECT_EQ("example.org", |
| alternative_service_info_vector[2].alternative_service().host); |
| EXPECT_EQ(1234, |
| alternative_service_info_vector[2].alternative_service().port); |
| base::Time expected_expiration; |
| ASSERT_TRUE( |
| base::Time::FromUTCString("2036-12-31 10:00:00", &expected_expiration)); |
| EXPECT_EQ(expected_expiration, |
| alternative_service_info_vector[2].expiration()); |
| |
| // No other fields should have been populated. |
| server_info.alternative_services.reset(); |
| EXPECT_TRUE(server_info.empty()); |
| } |
| |
| // Regression test for https://crbug.com/615497. |
| TEST_F(HttpServerPropertiesManagerTest, DoNotLoadAltSvcForInsecureOrigins) { |
| InitializePrefs(); |
| |
| base::Value::Dict server_dict = base::test::ParseJsonDict( |
| "{\"alternative_service\":[{\"port\":443,\"protocol_str\":\"h2\"," |
| "\"expiration\":\"9223372036854775807\"}]}"); |
| |
| const url::SchemeHostPort server("http", "example.com", 80); |
| HttpServerProperties::ServerInfo server_info; |
| EXPECT_FALSE(HttpServerPropertiesManager::ParseAlternativeServiceInfo( |
| server, server_dict, &server_info)); |
| EXPECT_TRUE(server_info.empty()); |
| } |
| |
| // Do not persist expired alternative service entries to disk. |
| TEST_F(HttpServerPropertiesManagerTest, DoNotPersistExpiredAlternativeService) { |
| InitializePrefs(); |
| |
| AlternativeServiceInfoVector alternative_service_info_vector; |
| |
| const AlternativeService broken_alternative_service( |
| kProtoHTTP2, "broken.example.com", 443); |
| const base::Time time_one_day_later = base::Time::Now() + base::Days(1); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| broken_alternative_service, time_one_day_later)); |
| // #1: MarkAlternativeServiceBroken(). |
| http_server_props_->MarkAlternativeServiceBroken(broken_alternative_service, |
| NetworkAnonymizationKey()); |
| |
| const AlternativeService expired_alternative_service( |
| kProtoHTTP2, "expired.example.com", 443); |
| const base::Time time_one_day_ago = base::Time::Now() - base::Days(1); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| expired_alternative_service, time_one_day_ago)); |
| |
| const AlternativeService valid_alternative_service(kProtoHTTP2, |
| "valid.example.com", 443); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| valid_alternative_service, time_one_day_later)); |
| |
| const url::SchemeHostPort server("https", "www.example.com", 443); |
| // #2: SetAlternativeServices(). |
| http_server_props_->SetAlternativeServices(server, NetworkAnonymizationKey(), |
| alternative_service_info_vector); |
| |
| // |net_test_task_runner_| has a remaining pending task to expire |
| // |broken_alternative_service| at |time_one_day_later|. Fast forward enough |
| // such that the prefs update task is executed but not the task to expire |
| // |broken_alternative_service|. |
| EXPECT_EQ(2U, GetPendingMainThreadTaskCount()); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| FastForwardBy(HttpServerProperties::GetUpdatePrefsDelayForTesting()); |
| EXPECT_EQ(1U, GetPendingMainThreadTaskCount()); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| const base::Value::Dict& pref_dict = pref_delegate_->GetServerProperties(); |
| |
| const base::Value::List* servers_list = pref_dict.FindList("servers"); |
| ASSERT_TRUE(servers_list); |
| auto it = servers_list->begin(); |
| const base::Value& server_pref_dict = *it; |
| ASSERT_TRUE(server_pref_dict.is_dict()); |
| |
| const std::string* server_str = |
| server_pref_dict.GetDict().FindString("server"); |
| ASSERT_TRUE(server_str); |
| EXPECT_EQ("https://www.example.com", *server_str); |
| |
| const base::Value* network_anonymization_key_value = |
| server_pref_dict.GetDict().Find("anonymization"); |
| ASSERT_TRUE(network_anonymization_key_value); |
| ASSERT_EQ(base::Value::Type::LIST, network_anonymization_key_value->type()); |
| EXPECT_TRUE(network_anonymization_key_value->GetList().empty()); |
| |
| const base::Value::List* altsvc_list = |
| server_pref_dict.GetDict().FindList("alternative_service"); |
| ASSERT_TRUE(altsvc_list); |
| |
| ASSERT_EQ(2u, altsvc_list->size()); |
| |
| const base::Value& altsvc_entry = (*altsvc_list)[0]; |
| ASSERT_TRUE(altsvc_entry.is_dict()); |
| const std::string* hostname = altsvc_entry.GetDict().FindString("host"); |
| |
| ASSERT_TRUE(hostname); |
| EXPECT_EQ("broken.example.com", *hostname); |
| |
| const base::Value& altsvc_entry2 = (*altsvc_list)[1]; |
| ASSERT_TRUE(altsvc_entry.is_dict()); |
| hostname = altsvc_entry2.GetDict().FindString("host"); |
| ASSERT_TRUE(hostname); |
| EXPECT_EQ("valid.example.com", *hostname); |
| } |
| |
| // Test that expired alternative service entries on disk are ignored. |
| TEST_F(HttpServerPropertiesManagerTest, DoNotLoadExpiredAlternativeService) { |
| InitializePrefs(); |
| |
| base::Value::List alternative_service_list; |
| base::Value::Dict expired_dict; |
| expired_dict.Set("protocol_str", "h2"); |
| expired_dict.Set("host", "expired.example.com"); |
| expired_dict.Set("port", 443); |
| base::Time time_one_day_ago = base::Time::Now() - base::Days(1); |
| expired_dict.Set("expiration", |
| base::NumberToString(time_one_day_ago.ToInternalValue())); |
| alternative_service_list.Append(std::move(expired_dict)); |
| |
| base::Value::Dict valid_dict; |
| valid_dict.Set("protocol_str", "h2"); |
| valid_dict.Set("host", "valid.example.com"); |
| valid_dict.Set("port", 443); |
| valid_dict.Set("expiration", |
| base::NumberToString(one_day_from_now_.ToInternalValue())); |
| alternative_service_list.Append(std::move(valid_dict)); |
| |
| base::Value::Dict server_pref_dict; |
| server_pref_dict.Set("alternative_service", |
| std::move(alternative_service_list)); |
| |
| const url::SchemeHostPort server("https", "example.com", 443); |
| HttpServerProperties::ServerInfo server_info; |
| ASSERT_TRUE(HttpServerPropertiesManager::ParseAlternativeServiceInfo( |
| server, server_pref_dict, &server_info)); |
| |
| ASSERT_TRUE(server_info.alternative_services.has_value()); |
| AlternativeServiceInfoVector alternative_service_info_vector = |
| server_info.alternative_services.value(); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| |
| EXPECT_EQ(kProtoHTTP2, |
| alternative_service_info_vector[0].alternative_service().protocol); |
| EXPECT_EQ("valid.example.com", |
| alternative_service_info_vector[0].alternative_service().host); |
| EXPECT_EQ(443, alternative_service_info_vector[0].alternative_service().port); |
| EXPECT_EQ(one_day_from_now_, alternative_service_info_vector[0].expiration()); |
| |
| // No other fields should have been populated. |
| server_info.alternative_services.reset(); |
| EXPECT_TRUE(server_info.empty()); |
| } |
| |
| // Make sure prefs are updated on destruction. |
| TEST_F(HttpServerPropertiesManagerTest, UpdatePrefsOnShutdown) { |
| InitializePrefs(); |
| |
| int pref_updates = 0; |
| pref_delegate_->set_extra_update_prefs_callback( |
| base::BindRepeating([](int* updates) { (*updates)++; }, &pref_updates)); |
| http_server_props_.reset(); |
| EXPECT_EQ(1, pref_updates); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, PersistAdvertisedVersionsToPref) { |
| InitializePrefs(); |
| |
| const url::SchemeHostPort server_www("https", "www.google.com", 80); |
| const url::SchemeHostPort server_mail("https", "mail.google.com", 80); |
| |
| // #1 & #2: Set alternate protocol. |
| AlternativeServiceInfoVector alternative_service_info_vector; |
| // Quic alternative service set with two advertised QUIC versions. |
| AlternativeService quic_alternative_service1(kProtoQUIC, "", 443); |
| base::Time expiration1; |
| ASSERT_TRUE(base::Time::FromUTCString("2036-12-01 10:00:00", &expiration1)); |
| quic::ParsedQuicVersionVector advertised_versions = { |
| quic::ParsedQuicVersion::Q046(), quic::ParsedQuicVersion::Q043()}; |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( |
| quic_alternative_service1, expiration1, advertised_versions)); |
| // HTTP/2 alternative service should not set any advertised version. |
| AlternativeService h2_alternative_service(kProtoHTTP2, "www.google.com", |
| 1234); |
| base::Time expiration2; |
| ASSERT_TRUE(base::Time::FromUTCString("2036-12-31 10:00:00", &expiration2)); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| h2_alternative_service, expiration2)); |
| http_server_props_->SetAlternativeServices( |
| server_www, NetworkAnonymizationKey(), alternative_service_info_vector); |
| |
| // Set another QUIC alternative service with a single advertised QUIC version. |
| AlternativeService mail_alternative_service(kProtoQUIC, "foo.google.com", |
| 444); |
| base::Time expiration3 = base::Time::Max(); |
| http_server_props_->SetQuicAlternativeService( |
| server_mail, NetworkAnonymizationKey(), mail_alternative_service, |
| expiration3, advertised_versions_); |
| // #3: Set ServerNetworkStats. |
| ServerNetworkStats stats; |
| stats.srtt = base::TimeDelta::FromInternalValue(42); |
| http_server_props_->SetServerNetworkStats(server_mail, |
| NetworkAnonymizationKey(), stats); |
| |
| // #4: Set quic_server_info string. |
| quic::QuicServerId mail_quic_server_id("mail.google.com", 80, false); |
| std::string quic_server_info1("quic_server_info1"); |
| http_server_props_->SetQuicServerInfo( |
| mail_quic_server_id, NetworkAnonymizationKey(), quic_server_info1); |
| |
| // #5: Set SupportsQuic. |
| IPAddress actual_address(127, 0, 0, 1); |
| http_server_props_->SetLastLocalAddressWhenQuicWorked(actual_address); |
| |
| // Update Prefs. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| // Verify preferences with correct advertised version field. |
| const char expected_json[] = |
| "{\"quic_servers\":[" |
| "{\"anonymization\":[]," |
| "\"server_id\":\"https://mail.google.com:80\"," |
| "\"server_info\":\"quic_server_info1\"}]," |
| "\"servers\":[" |
| "{\"alternative_service\":[{" |
| "\"advertised_alpns\":[\"h3-Q046\",\"h3-Q043\"],\"expiration\":" |
| "\"13756212000000000\"," |
| "\"port\":443,\"protocol_str\":\"quic\"},{\"advertised_alpns\":[]," |
| "\"expiration\":\"13758804000000000\",\"host\":\"www.google.com\"," |
| "\"port\":1234,\"protocol_str\":\"h2\"}]," |
| "\"anonymization\":[]," |
| "\"server\":\"https://www.google.com:80\"}," |
| "{\"alternative_service\":[{" |
| "\"advertised_alpns\":[\"h3\"]," |
| "\"expiration\":\"9223372036854775807\"," |
| "\"host\":\"foo.google.com\",\"port\":444,\"protocol_str\":\"quic\"}]," |
| "\"anonymization\":[]," |
| "\"network_stats\":{\"srtt\":42}," |
| "\"server\":\"https://mail.google.com:80\"}]," |
| "\"supports_quic\":{" |
| "\"address\":\"127.0.0.1\",\"used_quic\":true},\"version\":5}"; |
| |
| const base::Value::Dict& http_server_properties = |
| pref_delegate_->GetServerProperties(); |
| std::string preferences_json; |
| EXPECT_TRUE( |
| base::JSONWriter::Write(http_server_properties, &preferences_json)); |
| EXPECT_EQ(expected_json, preferences_json); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, ReadAdvertisedVersionsFromPref) { |
| InitializePrefs(); |
| |
| base::Value::Dict server_dict = base::test::ParseJsonDict( |
| "{\"alternative_service\":[" |
| "{\"port\":443,\"protocol_str\":\"quic\"}," |
| "{\"port\":123,\"protocol_str\":\"quic\"," |
| "\"expiration\":\"9223372036854775807\"," |
| // Add 33 which we know is not supported, as regression test for |
| // https://crbug.com/1061509 |
| "\"advertised_alpns\":[\"h3-Q033\",\"h3-Q046\",\"h3-Q043\"]}]}"); |
| |
| const url::SchemeHostPort server("https", "example.com", 443); |
| HttpServerProperties::ServerInfo server_info; |
| EXPECT_TRUE(HttpServerPropertiesManager::ParseAlternativeServiceInfo( |
| server, server_dict, &server_info)); |
| |
| ASSERT_TRUE(server_info.alternative_services.has_value()); |
| AlternativeServiceInfoVector alternative_service_info_vector = |
| server_info.alternative_services.value(); |
| ASSERT_EQ(2u, alternative_service_info_vector.size()); |
| |
| // Verify the first alternative service with no advertised version listed. |
| EXPECT_EQ(kProtoQUIC, |
| alternative_service_info_vector[0].alternative_service().protocol); |
| EXPECT_EQ("", alternative_service_info_vector[0].alternative_service().host); |
| EXPECT_EQ(443, alternative_service_info_vector[0].alternative_service().port); |
| // Expiration defaults to one day from now, testing with tolerance. |
| const base::Time now = base::Time::Now(); |
| const base::Time expiration = alternative_service_info_vector[0].expiration(); |
| EXPECT_LE(now + base::Hours(23), expiration); |
| EXPECT_GE(now + base::Days(1), expiration); |
| EXPECT_TRUE(alternative_service_info_vector[0].advertised_versions().empty()); |
| |
| // Verify the second alterntaive service with two advertised versions. |
| EXPECT_EQ(kProtoQUIC, |
| alternative_service_info_vector[1].alternative_service().protocol); |
| EXPECT_EQ("", alternative_service_info_vector[1].alternative_service().host); |
| EXPECT_EQ(123, alternative_service_info_vector[1].alternative_service().port); |
| EXPECT_EQ(base::Time::Max(), alternative_service_info_vector[1].expiration()); |
| // Verify advertised versions. |
| const quic::ParsedQuicVersionVector loaded_advertised_versions = |
| alternative_service_info_vector[1].advertised_versions(); |
| ASSERT_EQ(2u, loaded_advertised_versions.size()); |
| EXPECT_EQ(quic::ParsedQuicVersion::Q043(), loaded_advertised_versions[0]); |
| EXPECT_EQ(quic::ParsedQuicVersion::Q046(), loaded_advertised_versions[1]); |
| |
| // No other fields should have been populated. |
| server_info.alternative_services.reset(); |
| EXPECT_TRUE(server_info.empty()); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, |
| UpdatePrefWhenAdvertisedVersionsChange) { |
| InitializePrefs(); |
| |
| const url::SchemeHostPort server_www("https", "www.google.com", 80); |
| |
| // #1: Set alternate protocol. |
| AlternativeServiceInfoVector alternative_service_info_vector; |
| // Quic alternative service set with a single QUIC version: Q046. |
| AlternativeService quic_alternative_service1(kProtoQUIC, "", 443); |
| base::Time expiration1; |
| ASSERT_TRUE(base::Time::FromUTCString("2036-12-01 10:00:00", &expiration1)); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( |
| quic_alternative_service1, expiration1, advertised_versions_)); |
| http_server_props_->SetAlternativeServices( |
| server_www, NetworkAnonymizationKey(), alternative_service_info_vector); |
| |
| // Set quic_server_info string. |
| quic::QuicServerId mail_quic_server_id("mail.google.com", 80, false); |
| std::string quic_server_info1("quic_server_info1"); |
| http_server_props_->SetQuicServerInfo( |
| mail_quic_server_id, NetworkAnonymizationKey(), quic_server_info1); |
| |
| // Set SupportsQuic. |
| IPAddress actual_address(127, 0, 0, 1); |
| http_server_props_->SetLastLocalAddressWhenQuicWorked(actual_address); |
| |
| // Update Prefs. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| // Verify preferences with correct advertised version field. |
| const char expected_json[] = |
| "{\"quic_servers\":" |
| "[{\"anonymization\":[]," |
| "\"server_id\":\"https://mail.google.com:80\"," |
| "\"server_info\":\"quic_server_info1\"}]," |
| "\"servers\":[" |
| "{\"alternative_service\":[{" |
| "\"advertised_alpns\":[\"h3\"]," |
| "\"expiration\":\"13756212000000000\",\"port\":443," |
| "\"protocol_str\":\"quic\"}]," |
| "\"anonymization\":[]," |
| "\"server\":\"https://www.google.com:80\"}]," |
| "\"supports_quic\":" |
| "{\"address\":\"127.0.0.1\",\"used_quic\":true},\"version\":5}"; |
| |
| const base::Value::Dict& http_server_properties = |
| pref_delegate_->GetServerProperties(); |
| std::string preferences_json; |
| EXPECT_TRUE( |
| base::JSONWriter::Write(http_server_properties, &preferences_json)); |
| EXPECT_EQ(expected_json, preferences_json); |
| |
| // #2: Set AlternativeService with different advertised_versions for the same |
| // AlternativeService. |
| AlternativeServiceInfoVector alternative_service_info_vector_2; |
| // Quic alternative service set with two advertised QUIC versions. |
| quic::ParsedQuicVersionVector advertised_versions = { |
| quic::ParsedQuicVersion::Q046(), quic::ParsedQuicVersion::Q043()}; |
| alternative_service_info_vector_2.push_back( |
| AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( |
| quic_alternative_service1, expiration1, advertised_versions)); |
| http_server_props_->SetAlternativeServices( |
| server_www, NetworkAnonymizationKey(), alternative_service_info_vector_2); |
| |
| // Update Prefs. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| // Verify preferences updated with new advertised versions. |
| const char expected_json_updated[] = |
| "{\"quic_servers\":" |
| "[{\"anonymization\":[]," |
| "\"server_id\":\"https://mail.google.com:80\"," |
| "\"server_info\":\"quic_server_info1\"}]," |
| "\"servers\":[" |
| "{\"alternative_service\":" |
| "[{\"advertised_alpns\":[\"h3-Q046\",\"h3-Q043\"]," |
| "\"expiration\":\"13756212000000000\",\"port\":443," |
| "\"protocol_str\":\"quic\"}]," |
| "\"anonymization\":[]," |
| "\"server\":\"https://www.google.com:80\"}]," |
| "\"supports_quic\":" |
| "{\"address\":\"127.0.0.1\",\"used_quic\":true},\"version\":5}"; |
| EXPECT_TRUE( |
| base::JSONWriter::Write(http_server_properties, &preferences_json)); |
| EXPECT_EQ(expected_json_updated, preferences_json); |
| |
| // #3: Set AlternativeService with same advertised_versions. |
| AlternativeServiceInfoVector alternative_service_info_vector_3; |
| // A same set of QUIC versions but listed in a different order. |
| quic::ParsedQuicVersionVector advertised_versions_2 = { |
| quic::ParsedQuicVersion::Q043(), quic::ParsedQuicVersion::Q046()}; |
| alternative_service_info_vector_3.push_back( |
| AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( |
| quic_alternative_service1, expiration1, advertised_versions_2)); |
| http_server_props_->SetAlternativeServices( |
| server_www, NetworkAnonymizationKey(), alternative_service_info_vector_3); |
| |
| // Change in version ordering causes prefs update. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| // Verify preferences updated with new advertised versions. |
| const char expected_json_updated2[] = |
| "{\"quic_servers\":" |
| "[{\"anonymization\":[]," |
| "\"server_id\":\"https://mail.google.com:80\"," |
| "\"server_info\":\"quic_server_info1\"}]," |
| "\"servers\":[" |
| "{\"alternative_service\":" |
| "[{\"advertised_alpns\":[\"h3-Q043\",\"h3-Q046\"]," |
| "\"expiration\":\"13756212000000000\",\"port\":443," |
| "\"protocol_str\":\"quic\"}]," |
| "\"anonymization\":[]," |
| "\"server\":\"https://www.google.com:80\"}]," |
| "\"supports_quic\":" |
| "{\"address\":\"127.0.0.1\",\"used_quic\":true},\"version\":5}"; |
| EXPECT_TRUE( |
| base::JSONWriter::Write(http_server_properties, &preferences_json)); |
| EXPECT_EQ(expected_json_updated2, preferences_json); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, UpdateCacheWithPrefs) { |
| AlternativeService cached_broken_service(kProtoQUIC, "cached_broken", 443); |
| AlternativeService cached_broken_service2(kProtoQUIC, "cached_broken2", 443); |
| AlternativeService cached_recently_broken_service(kProtoQUIC, |
| "cached_rbroken", 443); |
| |
| http_server_props_->MarkAlternativeServiceBroken(cached_broken_service, |
| NetworkAnonymizationKey()); |
| http_server_props_->MarkAlternativeServiceBroken(cached_broken_service2, |
| NetworkAnonymizationKey()); |
| http_server_props_->MarkAlternativeServiceRecentlyBroken( |
| cached_recently_broken_service, NetworkAnonymizationKey()); |
| |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| // There should be a task to remove remove alt services from the cache of |
| // broken alt services. There should be no task to update the prefs, since the |
| // prefs file hasn't been loaded yet. |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| |
| // Load the |pref_delegate_| with some JSON to verify updating the cache from |
| // prefs. For the broken alternative services "www.google.com:1234" and |
| // "cached_broken", the expiration time will be one day from now. |
| |
| std::string expiration_str = |
| base::NumberToString(static_cast<int64_t>(one_day_from_now_.ToTimeT())); |
| |
| base::Value::Dict server_dict = base::test::ParseJsonDict( |
| "{" |
| "\"broken_alternative_services\":[" |
| "{\"broken_until\":\"" + |
| expiration_str + |
| "\"," |
| "\"host\":\"www.google.com\",\"anonymization\":[]," |
| "\"port\":1234,\"protocol_str\":\"h2\"}," |
| "{\"broken_count\":2,\"broken_until\":\"" + |
| expiration_str + |
| "\"," |
| "\"host\":\"cached_broken\",\"anonymization\":[]," |
| "\"port\":443,\"protocol_str\":\"quic\"}," |
| "{\"broken_count\":3," |
| "\"host\":\"cached_rbroken\",\"anonymization\":[]," |
| "\"port\":443,\"protocol_str\":\"quic\"}]," |
| "\"quic_servers\":[" |
| "{\"anonymization\":[]," |
| "\"server_id\":\"https://mail.google.com:80\"," |
| "\"server_info\":\"quic_server_info1\"}" |
| "]," |
| "\"servers\":[" |
| "{\"server\":\"https://www.google.com:80\"," |
| "\"anonymization\":[]," |
| "\"alternative_service\":[" |
| "{\"expiration\":\"13756212000000000\",\"port\":443," |
| "\"protocol_str\":\"h2\"}," |
| "{\"expiration\":\"13758804000000000\",\"host\":\"www.google.com\"," |
| "\"port\":1234,\"protocol_str\":\"h2\"}" |
| "]" |
| "}," |
| "{\"server\":\"https://mail.google.com:80\"," |
| "\"anonymization\":[]," |
| "\"alternative_service\":[" |
| "{\"expiration\":\"9223372036854775807\",\"host\":\"foo.google.com\"," |
| "\"port\":444,\"protocol_str\":\"h2\"}" |
| "]," |
| "\"network_stats\":{\"srtt\":42}" |
| "}" |
| "]," |
| "\"supports_quic\":" |
| "{\"address\":\"127.0.0.1\",\"used_quic\":true}," |
| "\"version\":5" |
| "}"); |
| |
| // Don't use the test fixture's InitializePrefs() method, since there are |
| // pending tasks. Initializing prefs should queue a pref update task, since |
| // prefs have been modified. |
| pref_delegate_->InitializePrefs(std::move(server_dict)); |
| EXPECT_TRUE(http_server_props_->IsInitialized()); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| |
| // Run until prefs are updated. |
| FastForwardBy(HttpServerProperties::GetUpdatePrefsDelayForTesting()); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| |
| // |
| // Verify alternative service info for https://www.google.com |
| // |
| AlternativeServiceInfoVector alternative_service_info_vector = |
| http_server_props_->GetAlternativeServiceInfos( |
| url::SchemeHostPort("https", "www.google.com", 80), |
| NetworkAnonymizationKey()); |
| ASSERT_EQ(2u, alternative_service_info_vector.size()); |
| |
| EXPECT_EQ(kProtoHTTP2, |
| alternative_service_info_vector[0].alternative_service().protocol); |
| EXPECT_EQ("www.google.com", |
| alternative_service_info_vector[0].alternative_service().host); |
| EXPECT_EQ(443, alternative_service_info_vector[0].alternative_service().port); |
| EXPECT_EQ( |
| "13756212000000000", |
| base::NumberToString( |
| alternative_service_info_vector[0].expiration().ToInternalValue())); |
| |
| EXPECT_EQ(kProtoHTTP2, |
| alternative_service_info_vector[1].alternative_service().protocol); |
| EXPECT_EQ("www.google.com", |
| alternative_service_info_vector[1].alternative_service().host); |
| EXPECT_EQ(1234, |
| alternative_service_info_vector[1].alternative_service().port); |
| EXPECT_EQ( |
| "13758804000000000", |
| base::NumberToString( |
| alternative_service_info_vector[1].expiration().ToInternalValue())); |
| |
| // |
| // Verify alternative service info for https://mail.google.com |
| // |
| alternative_service_info_vector = |
| http_server_props_->GetAlternativeServiceInfos( |
| url::SchemeHostPort("https", "mail.google.com", 80), |
| NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| |
| EXPECT_EQ(kProtoHTTP2, |
| alternative_service_info_vector[0].alternative_service().protocol); |
| EXPECT_EQ("foo.google.com", |
| alternative_service_info_vector[0].alternative_service().host); |
| EXPECT_EQ(444, alternative_service_info_vector[0].alternative_service().port); |
| EXPECT_EQ( |
| "9223372036854775807", |
| base::NumberToString( |
| alternative_service_info_vector[0].expiration().ToInternalValue())); |
| |
| // |
| // Verify broken alternative services. |
| // |
| AlternativeService prefs_broken_service(kProtoHTTP2, "www.google.com", 1234); |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| cached_broken_service, NetworkAnonymizationKey())); |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| cached_broken_service2, NetworkAnonymizationKey())); |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| prefs_broken_service, NetworkAnonymizationKey())); |
| |
| // Verify brokenness expiration times. |
| // |cached_broken_service|'s expiration time should've been overwritten by the |
| // prefs to be approximately 1 day from now. |cached_broken_service2|'s |
| // expiration time should still be 5 minutes due to being marked broken. |
| // |prefs_broken_service|'s expiration time should be approximately 1 day from |
| // now which comes from the prefs. |
| FastForwardBy(base::Minutes(5) - |
| HttpServerProperties::GetUpdatePrefsDelayForTesting()); |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| cached_broken_service, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| cached_broken_service2, NetworkAnonymizationKey())); |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| prefs_broken_service, NetworkAnonymizationKey())); |
| FastForwardBy(base::Days(1)); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| cached_broken_service, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| cached_broken_service2, NetworkAnonymizationKey())); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| prefs_broken_service, NetworkAnonymizationKey())); |
| |
| // Now that |prefs_broken_service|'s brokenness has expired, it should've |
| // been removed from the alternative services info vectors of all servers. |
| alternative_service_info_vector = |
| http_server_props_->GetAlternativeServiceInfos( |
| url::SchemeHostPort("https", "www.google.com", 80), |
| NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| |
| // |
| // Verify recently broken alternative services. |
| // |
| |
| // If an entry is already in cache, the broken count in the prefs should |
| // overwrite the one in the cache. |
| // |prefs_broken_service| should have broken-count 1 from prefs. |
| // |cached_recently_broken_service| should have broken-count 3 from prefs. |
| // |cached_broken_service| should have broken-count 2 from prefs. |
| // |cached_broken_service2| should have broken-count 1 from being marked |
| // broken. |
| |
| EXPECT_TRUE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| prefs_broken_service, NetworkAnonymizationKey())); |
| EXPECT_TRUE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| cached_recently_broken_service, NetworkAnonymizationKey())); |
| EXPECT_TRUE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| cached_broken_service, NetworkAnonymizationKey())); |
| EXPECT_TRUE(http_server_props_->WasAlternativeServiceRecentlyBroken( |
| cached_broken_service2, NetworkAnonymizationKey())); |
| // Make sure |prefs_broken_service| has the right expiration delay when marked |
| // broken. Since |prefs_broken_service| had no broken_count specified in the |
| // prefs, a broken_count value of 1 should have been assumed by |
| // |http_server_props_|. |
| http_server_props_->MarkAlternativeServiceBroken(prefs_broken_service, |
| NetworkAnonymizationKey()); |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardBy(base::Minutes(10) - base::TimeDelta::FromInternalValue(1)); |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| prefs_broken_service, NetworkAnonymizationKey())); |
| FastForwardBy(base::TimeDelta::FromInternalValue(1)); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| prefs_broken_service, NetworkAnonymizationKey())); |
| // Make sure |cached_recently_broken_service| has the right expiration delay |
| // when marked broken. |
| http_server_props_->MarkAlternativeServiceBroken( |
| cached_recently_broken_service, NetworkAnonymizationKey()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardBy(base::Minutes(40) - base::TimeDelta::FromInternalValue(1)); |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| cached_recently_broken_service, NetworkAnonymizationKey())); |
| FastForwardBy(base::TimeDelta::FromInternalValue(1)); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| cached_recently_broken_service, NetworkAnonymizationKey())); |
| // Make sure |cached_broken_service| has the right expiration delay when |
| // marked broken. |
| http_server_props_->MarkAlternativeServiceBroken(cached_broken_service, |
| NetworkAnonymizationKey()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardBy(base::Minutes(20) - base::TimeDelta::FromInternalValue(1)); |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| cached_broken_service, NetworkAnonymizationKey())); |
| FastForwardBy(base::TimeDelta::FromInternalValue(1)); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| cached_broken_service, NetworkAnonymizationKey())); |
| // Make sure |cached_broken_service2| has the right expiration delay when |
| // marked broken. |
| http_server_props_->MarkAlternativeServiceBroken(cached_broken_service2, |
| NetworkAnonymizationKey()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardBy(base::Minutes(10) - base::TimeDelta::FromInternalValue(1)); |
| EXPECT_TRUE(http_server_props_->IsAlternativeServiceBroken( |
| cached_broken_service2, NetworkAnonymizationKey())); |
| FastForwardBy(base::TimeDelta::FromInternalValue(1)); |
| EXPECT_FALSE(http_server_props_->IsAlternativeServiceBroken( |
| cached_broken_service2, NetworkAnonymizationKey())); |
| |
| // |
| // Verify ServerNetworkStats. |
| // |
| const ServerNetworkStats* server_network_stats = |
| http_server_props_->GetServerNetworkStats( |
| url::SchemeHostPort("https", "mail.google.com", 80), |
| NetworkAnonymizationKey()); |
| EXPECT_TRUE(server_network_stats); |
| EXPECT_EQ(server_network_stats->srtt, base::TimeDelta::FromInternalValue(42)); |
| |
| // |
| // Verify QUIC server info. |
| // |
| const std::string* quic_server_info = http_server_props_->GetQuicServerInfo( |
| quic::QuicServerId("mail.google.com", 80, false), |
| NetworkAnonymizationKey()); |
| EXPECT_EQ("quic_server_info1", *quic_server_info); |
| |
| // |
| // Verify supports QUIC. |
| // |
| IPAddress actual_address(127, 0, 0, 1); |
| EXPECT_TRUE( |
| http_server_props_->WasLastLocalAddressWhenQuicWorked(actual_address)); |
| EXPECT_EQ(4, pref_delegate_->GetAndClearNumPrefUpdates()); |
| } |
| |
| // Check the interaction of ForceHTTP11 with saving/restoring settings. |
| // In particular, ForceHTTP11 is not saved, and it should not overwrite or be |
| // overitten by loaded data. |
| TEST_F(HttpServerPropertiesManagerTest, ForceHTTP11) { |
| const url::SchemeHostPort kServer1("https", "foo.test", 443); |
| const url::SchemeHostPort kServer2("https", "bar.test", 443); |
| const url::SchemeHostPort kServer3("https", "baz.test", 443); |
| |
| // Create and initialize an HttpServerProperties with no state. |
| std::unique_ptr<MockPrefDelegate> pref_delegate = |
| std::make_unique<MockPrefDelegate>(); |
| MockPrefDelegate* unowned_pref_delegate = pref_delegate.get(); |
| std::unique_ptr<HttpServerProperties> properties = |
| std::make_unique<HttpServerProperties>(std::move(pref_delegate), |
| /*net_log=*/nullptr, |
| GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(base::Value::Dict()); |
| |
| // Set kServer1 to support H2, but require HTTP/1.1. Set kServer2 to only |
| // require HTTP/1.1. |
| EXPECT_FALSE( |
| properties->GetSupportsSpdy(kServer1, NetworkAnonymizationKey())); |
| EXPECT_FALSE(properties->RequiresHTTP11(kServer1, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties->GetSupportsSpdy(kServer2, NetworkAnonymizationKey())); |
| EXPECT_FALSE(properties->RequiresHTTP11(kServer2, NetworkAnonymizationKey())); |
| properties->SetSupportsSpdy(kServer1, NetworkAnonymizationKey(), true); |
| properties->SetHTTP11Required(kServer1, NetworkAnonymizationKey()); |
| properties->SetHTTP11Required(kServer2, NetworkAnonymizationKey()); |
| EXPECT_TRUE(properties->GetSupportsSpdy(kServer1, NetworkAnonymizationKey())); |
| EXPECT_TRUE(properties->RequiresHTTP11(kServer1, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties->GetSupportsSpdy(kServer2, NetworkAnonymizationKey())); |
| EXPECT_TRUE(properties->RequiresHTTP11(kServer2, NetworkAnonymizationKey())); |
| |
| // Wait until the data's been written to prefs, and then tear down the |
| // HttpServerProperties. |
| FastForwardBy(HttpServerProperties::GetUpdatePrefsDelayForTesting()); |
| base::Value::Dict saved_value = |
| unowned_pref_delegate->GetServerProperties().Clone(); |
| properties.reset(); |
| |
| // Only information on kServer1 should have been saved to prefs. |
| std::string preferences_json; |
| base::JSONWriter::Write(saved_value, &preferences_json); |
| EXPECT_EQ( |
| "{\"servers\":[" |
| "{\"anonymization\":[]," |
| "\"server\":\"https://foo.test\"," |
| "\"supports_spdy\":true}]," |
| "\"version\":5}", |
| preferences_json); |
| |
| // Create a new HttpServerProperties using the value saved to prefs above. |
| pref_delegate = std::make_unique<MockPrefDelegate>(); |
| unowned_pref_delegate = pref_delegate.get(); |
| properties = std::make_unique<HttpServerProperties>( |
| std::move(pref_delegate), /*net_log=*/nullptr, GetMockTickClock()); |
| |
| // Before the data has loaded, set kServer1 and kServer3 as requiring |
| // HTTP/1.1. |
| EXPECT_FALSE( |
| properties->GetSupportsSpdy(kServer1, NetworkAnonymizationKey())); |
| EXPECT_FALSE(properties->RequiresHTTP11(kServer1, NetworkAnonymizationKey())); |
| properties->SetHTTP11Required(kServer1, NetworkAnonymizationKey()); |
| properties->SetHTTP11Required(kServer3, NetworkAnonymizationKey()); |
| EXPECT_FALSE( |
| properties->GetSupportsSpdy(kServer1, NetworkAnonymizationKey())); |
| EXPECT_TRUE(properties->RequiresHTTP11(kServer1, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties->GetSupportsSpdy(kServer2, NetworkAnonymizationKey())); |
| EXPECT_FALSE(properties->RequiresHTTP11(kServer2, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties->GetSupportsSpdy(kServer3, NetworkAnonymizationKey())); |
| EXPECT_TRUE(properties->RequiresHTTP11(kServer3, NetworkAnonymizationKey())); |
| |
| // The data loads. |
| unowned_pref_delegate->InitializePrefs(std::move(saved_value)); |
| |
| // The properties should contain a combination of the old and new data. |
| EXPECT_TRUE(properties->GetSupportsSpdy(kServer1, NetworkAnonymizationKey())); |
| EXPECT_TRUE(properties->RequiresHTTP11(kServer1, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties->GetSupportsSpdy(kServer2, NetworkAnonymizationKey())); |
| EXPECT_FALSE(properties->RequiresHTTP11(kServer2, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties->GetSupportsSpdy(kServer3, NetworkAnonymizationKey())); |
| EXPECT_TRUE(properties->RequiresHTTP11(kServer3, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, NetworkAnonymizationKeyServerInfo) { |
| const SchemefulSite kSite1(GURL("https://foo.test/")); |
| const SchemefulSite kSite2(GURL("https://bar.test/")); |
| const SchemefulSite kOpaqueSite(GURL("data:text/plain,Hello World")); |
| const url::SchemeHostPort kServer("https", "baz.test", 443); |
| const url::SchemeHostPort kServer2("https", "zab.test", 443); |
| |
| HttpServerProperties::ServerInfo server_info; |
| server_info.supports_spdy = true; |
| |
| for (auto save_network_anonymization_key_mode : |
| kNetworkAnonymizationKeyModes) { |
| SCOPED_TRACE(static_cast<int>(save_network_anonymization_key_mode)); |
| |
| // Save prefs using |save_network_anonymization_key_mode|. |
| base::Value::Dict saved_value; |
| { |
| // Configure the the feature. |
| std::unique_ptr<base::test::ScopedFeatureList> feature_list = |
| SetNetworkAnonymizationKeyMode(save_network_anonymization_key_mode); |
| |
| // This parameter is normally calculated by HttpServerProperties based on |
| // the kPartitionHttpServerPropertiesByNetworkIsolationKey feature, but |
| // this test doesn't use that class. |
| bool use_network_anonymization_key = |
| save_network_anonymization_key_mode != |
| NetworkAnonymizationKeyMode::kDisabled; |
| |
| HttpServerProperties::ServerInfoMap server_info_map; |
| |
| // Add server info entry using two origins with value of |server_info|. |
| // NetworkAnonymizationKey's constructor takes the state of the |
| // kAppendFrameOriginToNetworkAnonymizationKey feature into account, so |
| // need to make sure to call the constructor after setting up the feature |
| // above. |
| HttpServerProperties::ServerInfoMapKey server_info_key( |
| kServer, NetworkAnonymizationKey::CreateCrossSite(kSite1), |
| use_network_anonymization_key); |
| server_info_map.Put(server_info_key, server_info); |
| |
| // Also add an etry with an opaque origin, if |
| // |use_network_anonymization_key| is true. This value should not be saved |
| // to disk, since opaque origins are only meaningful within a browsing |
| // session. |
| if (use_network_anonymization_key) { |
| HttpServerProperties::ServerInfoMapKey server_info_key2( |
| kServer2, NetworkAnonymizationKey::CreateSameSite(kOpaqueSite), |
| use_network_anonymization_key); |
| server_info_map.Put(server_info_key2, server_info); |
| } |
| |
| saved_value = ServerInfoMapToDict(server_info_map); |
| } |
| |
| for (auto load_network_anonymization_key_mode : |
| kNetworkAnonymizationKeyModes) { |
| SCOPED_TRACE(static_cast<int>(load_network_anonymization_key_mode)); |
| |
| std::unique_ptr<base::test::ScopedFeatureList> feature_list = |
| SetNetworkAnonymizationKeyMode(load_network_anonymization_key_mode); |
| std::unique_ptr<HttpServerProperties::ServerInfoMap> server_info_map2 = |
| DictToServerInfoMap(saved_value.Clone()); |
| ASSERT_TRUE(server_info_map2); |
| if (save_network_anonymization_key_mode == |
| NetworkAnonymizationKeyMode::kDisabled) { |
| // If NetworkAnonymizationKey was disabled when saving, it was saved |
| // with an empty NetworkAnonymizationKey, which should always be loaded |
| // successfully. This is needed to continue to support consumers that |
| // don't use NetworkAnonymizationKeys. |
| ASSERT_EQ(1u, server_info_map2->size()); |
| const HttpServerProperties::ServerInfoMapKey& server_info_key2 = |
| server_info_map2->begin()->first; |
| const HttpServerProperties::ServerInfo& server_info2 = |
| server_info_map2->begin()->second; |
| EXPECT_EQ(kServer, server_info_key2.server); |
| EXPECT_EQ(NetworkAnonymizationKey(), |
| server_info_key2.network_anonymization_key); |
| EXPECT_EQ(server_info, server_info2); |
| } else if (save_network_anonymization_key_mode == |
| load_network_anonymization_key_mode) { |
| // If the save and load modes are the same, the load should succeed, and |
| // the network anonymization keys should match. |
| ASSERT_EQ(1u, server_info_map2->size()); |
| const HttpServerProperties::ServerInfoMapKey& server_info_key2 = |
| server_info_map2->begin()->first; |
| const HttpServerProperties::ServerInfo& server_info2 = |
| server_info_map2->begin()->second; |
| EXPECT_EQ(kServer, server_info_key2.server); |
| EXPECT_EQ(NetworkAnonymizationKey::CreateCrossSite(kSite1), |
| server_info_key2.network_anonymization_key); |
| EXPECT_EQ(server_info, server_info2); |
| } else { |
| // Otherwise, the NetworkAnonymizationKey doesn't make sense with the |
| // current feature values, so the ServerInfo should be discarded. |
| EXPECT_EQ(0u, server_info_map2->size()); |
| } |
| } |
| } |
| } |
| |
| // Tests a full round trip with a NetworkAnonymizationKey, using the |
| // HttpServerProperties interface. |
| TEST_F(HttpServerPropertiesManagerTest, NetworkAnonymizationKeyIntegration) { |
| const SchemefulSite kSite(GURL("https://foo.test/")); |
| const auto kNetworkAnonymizationKey = |
| NetworkAnonymizationKey::CreateSameSite(kSite); |
| const url::SchemeHostPort kServer("https", "baz.test", 443); |
| |
| const SchemefulSite kOpaqueSite(GURL("data:text/plain,Hello World")); |
| const auto kOpaqueSiteNetworkAnonymizationKey = |
| NetworkAnonymizationKey::CreateSameSite(kOpaqueSite); |
| const url::SchemeHostPort kServer2("https", "zab.test", 443); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| |
| // Create and initialize an HttpServerProperties with no state. |
| std::unique_ptr<MockPrefDelegate> pref_delegate = |
| std::make_unique<MockPrefDelegate>(); |
| MockPrefDelegate* unowned_pref_delegate = pref_delegate.get(); |
| std::unique_ptr<HttpServerProperties> properties = |
| std::make_unique<HttpServerProperties>(std::move(pref_delegate), |
| /*net_log=*/nullptr, |
| GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(base::Value::Dict()); |
| |
| // Set a values using kNetworkAnonymizationKey. |
| properties->SetSupportsSpdy(kServer, kNetworkAnonymizationKey, true); |
| EXPECT_TRUE(properties->GetSupportsSpdy(kServer, kNetworkAnonymizationKey)); |
| EXPECT_FALSE( |
| properties->GetSupportsSpdy(kServer, kOpaqueSiteNetworkAnonymizationKey)); |
| EXPECT_FALSE(properties->GetSupportsSpdy(kServer, NetworkAnonymizationKey())); |
| |
| // Opaque origins should works with HttpServerProperties, but not be persisted |
| // to disk. |
| properties->SetSupportsSpdy(kServer2, kOpaqueSiteNetworkAnonymizationKey, |
| true); |
| EXPECT_FALSE(properties->GetSupportsSpdy(kServer2, kNetworkAnonymizationKey)); |
| EXPECT_TRUE(properties->GetSupportsSpdy(kServer2, |
| kOpaqueSiteNetworkAnonymizationKey)); |
| EXPECT_FALSE( |
| properties->GetSupportsSpdy(kServer2, NetworkAnonymizationKey())); |
| |
| // Wait until the data's been written to prefs, and then tear down the |
| // HttpServerProperties. |
| FastForwardBy(HttpServerProperties::GetUpdatePrefsDelayForTesting()); |
| base::Value::Dict saved_value = |
| unowned_pref_delegate->GetServerProperties().Clone(); |
| properties.reset(); |
| |
| // Create a new HttpServerProperties using the value saved to prefs above. |
| pref_delegate = std::make_unique<MockPrefDelegate>(); |
| unowned_pref_delegate = pref_delegate.get(); |
| properties = std::make_unique<HttpServerProperties>( |
| std::move(pref_delegate), /*net_log=*/nullptr, GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(std::move(saved_value)); |
| |
| // The information set using kNetworkAnonymizationKey on the original |
| // HttpServerProperties should also be set on the restored |
| // HttpServerProperties. |
| EXPECT_TRUE(properties->GetSupportsSpdy(kServer, kNetworkAnonymizationKey)); |
| EXPECT_FALSE( |
| properties->GetSupportsSpdy(kServer, kOpaqueSiteNetworkAnonymizationKey)); |
| EXPECT_FALSE(properties->GetSupportsSpdy(kServer, NetworkAnonymizationKey())); |
| |
| // The information set using kOpaqueSiteNetworkAnonymizationKey should not |
| // have been restored. |
| EXPECT_FALSE(properties->GetSupportsSpdy(kServer2, kNetworkAnonymizationKey)); |
| EXPECT_FALSE(properties->GetSupportsSpdy(kServer2, |
| kOpaqueSiteNetworkAnonymizationKey)); |
| EXPECT_FALSE( |
| properties->GetSupportsSpdy(kServer2, NetworkAnonymizationKey())); |
| } |
| |
| // Tests a full round trip to prefs and back in the canonical suffix case. |
| // Enable NetworkAnonymizationKeys, as they have some interactions with the |
| // canonical suffix logic. |
| TEST_F(HttpServerPropertiesManagerTest, |
| CanonicalSuffixRoundTripWithNetworkAnonymizationKey) { |
| const SchemefulSite kSite1(GURL("https://foo.test/")); |
| const SchemefulSite kSite2(GURL("https://bar.test/")); |
| const auto kNetworkAnonymizationKey1 = |
| NetworkAnonymizationKey::CreateSameSite(kSite1); |
| const auto kNetworkAnonymizationKey2 = |
| NetworkAnonymizationKey::CreateSameSite(kSite2); |
| // Three servers with the same canonical suffix (".c.youtube.com"). |
| const url::SchemeHostPort kServer1("https", "foo.c.youtube.com", 443); |
| const url::SchemeHostPort kServer2("https", "bar.c.youtube.com", 443); |
| const url::SchemeHostPort kServer3("https", "baz.c.youtube.com", 443); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| |
| // Create three alt service vectors of different lengths. |
| base::Time expiration = base::Time::Now() + base::Days(1); |
| AlternativeServiceInfo alt_service1 = |
| AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( |
| AlternativeService(kProtoQUIC, "foopy.c.youtube.com", 1234), |
| expiration, DefaultSupportedQuicVersions()); |
| AlternativeServiceInfo alt_service2 = |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| AlternativeService(kProtoHTTP2, "foopy.c.youtube.com", 443), |
| expiration); |
| AlternativeServiceInfo alt_service3 = |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| AlternativeService(kProtoHTTP2, "foopy2.c.youtube.com", 443), |
| expiration); |
| AlternativeServiceInfoVector alt_service_vector1 = {alt_service1}; |
| AlternativeServiceInfoVector alt_service_vector2 = {alt_service1, |
| alt_service2}; |
| AlternativeServiceInfoVector alt_service_vector3 = { |
| alt_service1, alt_service2, alt_service3}; |
| |
| // Create and initialize an HttpServerProperties with no state. |
| std::unique_ptr<MockPrefDelegate> pref_delegate = |
| std::make_unique<MockPrefDelegate>(); |
| MockPrefDelegate* unowned_pref_delegate = pref_delegate.get(); |
| std::unique_ptr<HttpServerProperties> properties = |
| std::make_unique<HttpServerProperties>(std::move(pref_delegate), |
| /*net_log=*/nullptr, |
| GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(base::Value::Dict()); |
| |
| // Set alternative services for kServer1 using kNetworkAnonymizationKey1. That |
| // information should be retrieved when fetching information for any server |
| // with the same canonical suffix, when using kNetworkAnonymizationKey1. |
| properties->SetAlternativeServices(kServer1, kNetworkAnonymizationKey1, |
| alt_service_vector1); |
| EXPECT_EQ( |
| 1u, properties |
| ->GetAlternativeServiceInfos(kServer1, kNetworkAnonymizationKey1) |
| .size()); |
| EXPECT_EQ( |
| 1u, properties |
| ->GetAlternativeServiceInfos(kServer2, kNetworkAnonymizationKey1) |
| .size()); |
| EXPECT_EQ( |
| 1u, properties |
| ->GetAlternativeServiceInfos(kServer3, kNetworkAnonymizationKey1) |
| .size()); |
| EXPECT_EQ( |
| 0u, properties |
| ->GetAlternativeServiceInfos(kServer1, kNetworkAnonymizationKey2) |
| .size()); |
| |
| // Set different alternative services for kServer2 using |
| // kNetworkAnonymizationKey1. It should not affect information retrieved for |
| // kServer1, but should for kServer2 and kServer3. |
| properties->SetAlternativeServices(kServer2, kNetworkAnonymizationKey1, |
| alt_service_vector2); |
| EXPECT_EQ( |
| 1u, properties |
| ->GetAlternativeServiceInfos(kServer1, kNetworkAnonymizationKey1) |
| .size()); |
| EXPECT_EQ( |
| 2u, properties |
| ->GetAlternativeServiceInfos(kServer2, kNetworkAnonymizationKey1) |
| .size()); |
| EXPECT_EQ( |
| 2u, properties |
| ->GetAlternativeServiceInfos(kServer3, kNetworkAnonymizationKey1) |
| .size()); |
| EXPECT_EQ( |
| 0u, properties |
| ->GetAlternativeServiceInfos(kServer1, kNetworkAnonymizationKey2) |
| .size()); |
| |
| // Set different information for kServer1 using kNetworkAnonymizationKey2. It |
| // should not affect information stored for kNetworkAnonymizationKey1. |
| properties->SetAlternativeServices(kServer1, kNetworkAnonymizationKey2, |
| alt_service_vector3); |
| EXPECT_EQ( |
| 1u, properties |
| ->GetAlternativeServiceInfos(kServer1, kNetworkAnonymizationKey1) |
| .size()); |
| EXPECT_EQ( |
| 2u, properties |
| ->GetAlternativeServiceInfos(kServer2, kNetworkAnonymizationKey1) |
| .size()); |
| EXPECT_EQ( |
| 2u, properties |
| ->GetAlternativeServiceInfos(kServer3, kNetworkAnonymizationKey1) |
| .size()); |
| EXPECT_EQ( |
| 3u, properties |
| ->GetAlternativeServiceInfos(kServer1, kNetworkAnonymizationKey2) |
| .size()); |
| EXPECT_EQ( |
| 3u, properties |
| ->GetAlternativeServiceInfos(kServer2, kNetworkAnonymizationKey2) |
| .size()); |
| EXPECT_EQ( |
| 3u, properties |
| ->GetAlternativeServiceInfos(kServer3, kNetworkAnonymizationKey2) |
| .size()); |
| |
| // Wait until the data's been written to prefs, and then tear down the |
| // HttpServerProperties. |
| FastForwardBy(HttpServerProperties::GetUpdatePrefsDelayForTesting()); |
| base::Value::Dict saved_value = |
| unowned_pref_delegate->GetServerProperties().Clone(); |
| properties.reset(); |
| |
| // Create a new HttpServerProperties using the value saved to prefs above. |
| pref_delegate = std::make_unique<MockPrefDelegate>(); |
| unowned_pref_delegate = pref_delegate.get(); |
| properties = std::make_unique<HttpServerProperties>( |
| std::move(pref_delegate), /*net_log=*/nullptr, GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(std::move(saved_value)); |
| |
| // Only the last of the values learned for kNetworkAnonymizationKey1 should |
| // have been saved, and the value for kNetworkAnonymizationKey2 as well. The |
| // canonical suffix logic should still be respected. |
| EXPECT_EQ( |
| 2u, properties |
| ->GetAlternativeServiceInfos(kServer1, kNetworkAnonymizationKey1) |
| .size()); |
| EXPECT_EQ( |
| 2u, properties |
| ->GetAlternativeServiceInfos(kServer2, kNetworkAnonymizationKey1) |
| .size()); |
| EXPECT_EQ( |
| 2u, properties |
| ->GetAlternativeServiceInfos(kServer3, kNetworkAnonymizationKey1) |
| .size()); |
| EXPECT_EQ( |
| 3u, properties |
| ->GetAlternativeServiceInfos(kServer1, kNetworkAnonymizationKey2) |
| .size()); |
| EXPECT_EQ( |
| 3u, properties |
| ->GetAlternativeServiceInfos(kServer2, kNetworkAnonymizationKey2) |
| .size()); |
| EXPECT_EQ( |
| 3u, properties |
| ->GetAlternativeServiceInfos(kServer3, kNetworkAnonymizationKey2) |
| .size()); |
| } |
| |
| // Tests a full round trip with a NetworkAnonymizationKey, using the |
| // HttpServerProperties interface and setting alternative services as broken. |
| TEST_F(HttpServerPropertiesManagerTest, |
| NetworkAnonymizationKeyBrokenAltServiceRoundTrip) { |
| const SchemefulSite kSite1(GURL("https://foo1.test/")); |
| const SchemefulSite kSite2(GURL("https://foo2.test/")); |
| const auto kNetworkAnonymizationKey1 = |
| NetworkAnonymizationKey::CreateSameSite(kSite1); |
| const auto kNetworkAnonymizationKey2 = |
| NetworkAnonymizationKey::CreateSameSite(kSite2); |
| |
| const AlternativeService kAlternativeService1(kProtoHTTP2, |
| "alt.service1.test", 443); |
| const AlternativeService kAlternativeService2(kProtoHTTP2, |
| "alt.service2.test", 443); |
| |
| for (auto save_network_anonymization_key_mode : |
| kNetworkAnonymizationKeyModes) { |
| SCOPED_TRACE(static_cast<int>(save_network_anonymization_key_mode)); |
| |
| // Save prefs using |save_network_anonymization_key_mode|. |
| base::Value::Dict saved_value; |
| { |
| // Configure the the feature. |
| std::unique_ptr<base::test::ScopedFeatureList> feature_list = |
| SetNetworkAnonymizationKeyMode(save_network_anonymization_key_mode); |
| |
| // Create and initialize an HttpServerProperties, must be done after |
| // setting the feature. |
| std::unique_ptr<MockPrefDelegate> pref_delegate = |
| std::make_unique<MockPrefDelegate>(); |
| MockPrefDelegate* unowned_pref_delegate = pref_delegate.get(); |
| std::unique_ptr<HttpServerProperties> properties = |
| std::make_unique<HttpServerProperties>(std::move(pref_delegate), |
| /*net_log=*/nullptr, |
| GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(base::Value::Dict()); |
| |
| // Set kAlternativeService1 as broken in the context of |
| // kNetworkAnonymizationKey1, and kAlternativeService2 as broken in the |
| // context of the empty NetworkAnonymizationKey2, and recently broken in |
| // the context of the empty NetworkAnonymizationKey. |
| properties->MarkAlternativeServiceBroken(kAlternativeService1, |
| kNetworkAnonymizationKey1); |
| properties->MarkAlternativeServiceRecentlyBroken( |
| kAlternativeService2, NetworkAnonymizationKey()); |
| properties->MarkAlternativeServiceBroken(kAlternativeService2, |
| kNetworkAnonymizationKey2); |
| |
| // Verify values were set. |
| EXPECT_TRUE(properties->IsAlternativeServiceBroken( |
| kAlternativeService1, kNetworkAnonymizationKey1)); |
| EXPECT_TRUE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService1, kNetworkAnonymizationKey1)); |
| // When NetworkAnonymizationKeys are disabled, kAlternativeService2 is |
| // marked as broken regardless of the values passed to |
| // NetworkAnonymizationKey's constructor. |
| EXPECT_EQ(save_network_anonymization_key_mode == |
| NetworkAnonymizationKeyMode::kDisabled, |
| properties->IsAlternativeServiceBroken( |
| kAlternativeService2, NetworkAnonymizationKey())); |
| EXPECT_TRUE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService2, NetworkAnonymizationKey())); |
| EXPECT_TRUE(properties->IsAlternativeServiceBroken( |
| kAlternativeService2, kNetworkAnonymizationKey2)); |
| EXPECT_TRUE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService2, kNetworkAnonymizationKey2)); |
| |
| // If NetworkAnonymizationKeys are enabled, there should be no |
| // cross-contamination of the NetworkAnonymizationKeys. |
| if (save_network_anonymization_key_mode != |
| NetworkAnonymizationKeyMode::kDisabled) { |
| EXPECT_FALSE(properties->IsAlternativeServiceBroken( |
| kAlternativeService2, kNetworkAnonymizationKey1)); |
| EXPECT_FALSE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService2, kNetworkAnonymizationKey1)); |
| EXPECT_FALSE(properties->IsAlternativeServiceBroken( |
| kAlternativeService1, NetworkAnonymizationKey())); |
| EXPECT_FALSE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService1, NetworkAnonymizationKey())); |
| EXPECT_FALSE(properties->IsAlternativeServiceBroken( |
| kAlternativeService1, kNetworkAnonymizationKey2)); |
| EXPECT_FALSE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService1, kNetworkAnonymizationKey2)); |
| } |
| |
| // Wait until the data's been written to prefs, and then create a copy of |
| // the prefs data. |
| FastForwardBy(HttpServerProperties::GetUpdatePrefsDelayForTesting()); |
| saved_value = unowned_pref_delegate->GetServerProperties().Clone(); |
| } |
| |
| // Now try and load the data in each of the feature modes. |
| for (auto load_network_anonymization_key_mode : |
| kNetworkAnonymizationKeyModes) { |
| SCOPED_TRACE(static_cast<int>(load_network_anonymization_key_mode)); |
| |
| std::unique_ptr<base::test::ScopedFeatureList> feature_list = |
| SetNetworkAnonymizationKeyMode(load_network_anonymization_key_mode); |
| |
| // Create a new HttpServerProperties, loading the data from before. |
| std::unique_ptr<MockPrefDelegate> pref_delegate = |
| std::make_unique<MockPrefDelegate>(); |
| MockPrefDelegate* unowned_pref_delegate = pref_delegate.get(); |
| std::unique_ptr<HttpServerProperties> properties = |
| std::make_unique<HttpServerProperties>(std::move(pref_delegate), |
| /*net_log=*/nullptr, |
| GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(saved_value.Clone()); |
| |
| if (save_network_anonymization_key_mode == |
| NetworkAnonymizationKeyMode::kDisabled) { |
| // If NetworkAnonymizationKey was disabled when saving, it was saved |
| // with an empty NetworkAnonymizationKey, which should always be loaded |
| // successfully. This is needed to continue to support consumers that |
| // don't use NetworkAnonymizationKeys. |
| EXPECT_TRUE(properties->IsAlternativeServiceBroken( |
| kAlternativeService1, NetworkAnonymizationKey())); |
| EXPECT_TRUE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService1, NetworkAnonymizationKey())); |
| EXPECT_TRUE(properties->IsAlternativeServiceBroken( |
| kAlternativeService2, NetworkAnonymizationKey())); |
| EXPECT_TRUE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService2, NetworkAnonymizationKey())); |
| } else if (save_network_anonymization_key_mode == |
| load_network_anonymization_key_mode) { |
| // If the save and load modes are the same, the load should succeed, and |
| // the network anonymization keys should match. |
| EXPECT_TRUE(properties->IsAlternativeServiceBroken( |
| kAlternativeService1, kNetworkAnonymizationKey1)); |
| EXPECT_TRUE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService1, kNetworkAnonymizationKey1)); |
| // When NetworkAnonymizationKeys are disabled, kAlternativeService2 is |
| // marked as broken regardless of the values passed to |
| // NetworkAnonymizationKey's constructor. |
| EXPECT_EQ(save_network_anonymization_key_mode == |
| NetworkAnonymizationKeyMode::kDisabled, |
| properties->IsAlternativeServiceBroken( |
| kAlternativeService2, NetworkAnonymizationKey())); |
| EXPECT_TRUE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService2, NetworkAnonymizationKey())); |
| EXPECT_TRUE(properties->IsAlternativeServiceBroken( |
| kAlternativeService2, kNetworkAnonymizationKey2)); |
| EXPECT_TRUE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService2, kNetworkAnonymizationKey2)); |
| |
| // If NetworkAnonymizationKeys are enabled, there should be no |
| // cross-contamination of the NetworkAnonymizationKeys. |
| if (save_network_anonymization_key_mode != |
| NetworkAnonymizationKeyMode::kDisabled) { |
| EXPECT_FALSE(properties->IsAlternativeServiceBroken( |
| kAlternativeService2, kNetworkAnonymizationKey1)); |
| EXPECT_FALSE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService2, kNetworkAnonymizationKey1)); |
| EXPECT_FALSE(properties->IsAlternativeServiceBroken( |
| kAlternativeService1, NetworkAnonymizationKey())); |
| EXPECT_FALSE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService1, NetworkAnonymizationKey())); |
| EXPECT_FALSE(properties->IsAlternativeServiceBroken( |
| kAlternativeService1, kNetworkAnonymizationKey2)); |
| EXPECT_FALSE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService1, kNetworkAnonymizationKey2)); |
| } |
| } else { |
| // Otherwise, only the values set with an empty NetworkAnonymizationKey |
| // should have been loaded successfully. |
| EXPECT_FALSE(properties->IsAlternativeServiceBroken( |
| kAlternativeService1, kNetworkAnonymizationKey1)); |
| EXPECT_FALSE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService1, kNetworkAnonymizationKey1)); |
| EXPECT_FALSE(properties->IsAlternativeServiceBroken( |
| kAlternativeService2, NetworkAnonymizationKey())); |
| EXPECT_TRUE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService2, NetworkAnonymizationKey())); |
| EXPECT_FALSE(properties->IsAlternativeServiceBroken( |
| kAlternativeService2, kNetworkAnonymizationKey2)); |
| // If the load mode is NetworkAnonymizationKeyMode::kDisabled, |
| // kNetworkAnonymizationKey2 is NetworkAnonymizationKey(). |
| EXPECT_EQ(load_network_anonymization_key_mode == |
| NetworkAnonymizationKeyMode::kDisabled, |
| properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService2, kNetworkAnonymizationKey2)); |
| |
| // There should be no cross-contamination of NetworkAnonymizationKeys, |
| // if NetworkAnonymizationKeys are enabled. |
| if (load_network_anonymization_key_mode != |
| NetworkAnonymizationKeyMode::kDisabled) { |
| EXPECT_FALSE(properties->IsAlternativeServiceBroken( |
| kAlternativeService2, kNetworkAnonymizationKey1)); |
| EXPECT_FALSE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService2, kNetworkAnonymizationKey1)); |
| EXPECT_FALSE(properties->IsAlternativeServiceBroken( |
| kAlternativeService1, NetworkAnonymizationKey())); |
| EXPECT_FALSE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService1, NetworkAnonymizationKey())); |
| EXPECT_FALSE(properties->IsAlternativeServiceBroken( |
| kAlternativeService1, kNetworkAnonymizationKey2)); |
| EXPECT_FALSE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService1, kNetworkAnonymizationKey2)); |
| } |
| } |
| } |
| } |
| } |
| |
| // Make sure broken alt services with opaque origins aren't saved. |
| TEST_F(HttpServerPropertiesManagerTest, |
| NetworkAnonymizationKeyBrokenAltServiceOpaqueOrigin) { |
| const SchemefulSite kOpaqueSite(GURL("data:text/plain,Hello World")); |
| const auto kNetworkAnonymizationKey = |
| NetworkAnonymizationKey::CreateSameSite(kOpaqueSite); |
| const AlternativeService kAlternativeService(kProtoHTTP2, "alt.service1.test", |
| 443); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| |
| // Create and initialize an HttpServerProperties, must be done after |
| // setting the feature. |
| std::unique_ptr<MockPrefDelegate> pref_delegate = |
| std::make_unique<MockPrefDelegate>(); |
| MockPrefDelegate* unowned_pref_delegate = pref_delegate.get(); |
| std::unique_ptr<HttpServerProperties> properties = |
| std::make_unique<HttpServerProperties>(std::move(pref_delegate), |
| /*net_log=*/nullptr, |
| GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(base::Value::Dict()); |
| |
| properties->MarkAlternativeServiceBroken(kAlternativeService, |
| kNetworkAnonymizationKey); |
| |
| // Verify values were set. |
| EXPECT_TRUE(properties->IsAlternativeServiceBroken(kAlternativeService, |
| kNetworkAnonymizationKey)); |
| EXPECT_TRUE(properties->WasAlternativeServiceRecentlyBroken( |
| kAlternativeService, kNetworkAnonymizationKey)); |
| |
| // Wait until the data's been written to prefs, and then create a copy of |
| // the prefs data. |
| FastForwardBy(HttpServerProperties::GetUpdatePrefsDelayForTesting()); |
| |
| // No information should have been saved to prefs. |
| std::string preferences_json; |
| base::JSONWriter::Write(unowned_pref_delegate->GetServerProperties(), |
| &preferences_json); |
| EXPECT_EQ("{\"servers\":[],\"version\":5}", preferences_json); |
| } |
| |
| // Tests a full round trip with a NetworkAnonymizationKey, using the |
| // HttpServerProperties interface and setting QuicServerInfo. |
| TEST_F(HttpServerPropertiesManagerTest, |
| NetworkAnonymizationKeyQuicServerInfoRoundTrip) { |
| const SchemefulSite kSite1(GURL("https://foo1.test/")); |
| const SchemefulSite kSite2(GURL("https://foo2.test/")); |
| const auto kNetworkAnonymizationKey1 = |
| NetworkAnonymizationKey::CreateSameSite(kSite1); |
| const auto kNetworkAnonymizationKey2 = |
| NetworkAnonymizationKey::CreateSameSite(kSite2); |
| |
| const quic::QuicServerId kServer1("foo", 443, |
| false /* privacy_mode_enabled */); |
| const quic::QuicServerId kServer2("foo", 443, |
| true /* privacy_mode_enabled */); |
| |
| const char kQuicServerInfo1[] = "info1"; |
| const char kQuicServerInfo2[] = "info2"; |
| const char kQuicServerInfo3[] = "info3"; |
| |
| for (auto save_network_anonymization_key_mode : |
| kNetworkAnonymizationKeyModes) { |
| SCOPED_TRACE(static_cast<int>(save_network_anonymization_key_mode)); |
| |
| // Save prefs using |save_network_anonymization_key_mode|. |
| base::Value::Dict saved_value; |
| { |
| // Configure the the feature. |
| std::unique_ptr<base::test::ScopedFeatureList> feature_list = |
| SetNetworkAnonymizationKeyMode(save_network_anonymization_key_mode); |
| |
| // Create and initialize an HttpServerProperties, must be done after |
| // setting the feature. |
| std::unique_ptr<MockPrefDelegate> pref_delegate = |
| std::make_unique<MockPrefDelegate>(); |
| MockPrefDelegate* unowned_pref_delegate = pref_delegate.get(); |
| std::unique_ptr<HttpServerProperties> properties = |
| std::make_unique<HttpServerProperties>(std::move(pref_delegate), |
| /*net_log=*/nullptr, |
| GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(base::Value::Dict()); |
| |
| // Set kServer1 to kQuicServerInfo1 in the context of |
| // kNetworkAnonymizationKey1, Set kServer2 to kQuicServerInfo2 in the |
| // context of kNetworkAnonymizationKey2, and kServer1 to kQuicServerInfo3 |
| // in the context of NetworkAnonymizationKey(). |
| properties->SetQuicServerInfo(kServer1, kNetworkAnonymizationKey1, |
| kQuicServerInfo1); |
| properties->SetQuicServerInfo(kServer2, kNetworkAnonymizationKey2, |
| kQuicServerInfo2); |
| properties->SetQuicServerInfo(kServer1, NetworkAnonymizationKey(), |
| kQuicServerInfo3); |
| |
| // Verify values were set. |
| if (save_network_anonymization_key_mode != |
| NetworkAnonymizationKeyMode::kDisabled) { |
| EXPECT_EQ(kQuicServerInfo1, *properties->GetQuicServerInfo( |
| kServer1, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer1, kNetworkAnonymizationKey2)); |
| EXPECT_EQ(kQuicServerInfo3, *properties->GetQuicServerInfo( |
| kServer1, NetworkAnonymizationKey())); |
| |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer2, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(kQuicServerInfo2, *properties->GetQuicServerInfo( |
| kServer2, kNetworkAnonymizationKey2)); |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer2, NetworkAnonymizationKey())); |
| } else { |
| EXPECT_EQ(kQuicServerInfo3, *properties->GetQuicServerInfo( |
| kServer1, NetworkAnonymizationKey())); |
| EXPECT_EQ(kQuicServerInfo2, *properties->GetQuicServerInfo( |
| kServer2, NetworkAnonymizationKey())); |
| } |
| |
| // Wait until the data's been written to prefs, and then create a copy of |
| // the prefs data. |
| FastForwardBy(HttpServerProperties::GetUpdatePrefsDelayForTesting()); |
| saved_value = unowned_pref_delegate->GetServerProperties().Clone(); |
| } |
| |
| // Now try and load the data in each of the feature modes. |
| for (auto load_network_anonymization_key_mode : |
| kNetworkAnonymizationKeyModes) { |
| SCOPED_TRACE(static_cast<int>(load_network_anonymization_key_mode)); |
| |
| std::unique_ptr<base::test::ScopedFeatureList> feature_list = |
| SetNetworkAnonymizationKeyMode(load_network_anonymization_key_mode); |
| |
| // Create a new HttpServerProperties, loading the data from before. |
| std::unique_ptr<MockPrefDelegate> pref_delegate = |
| std::make_unique<MockPrefDelegate>(); |
| MockPrefDelegate* unowned_pref_delegate = pref_delegate.get(); |
| std::unique_ptr<HttpServerProperties> properties = |
| std::make_unique<HttpServerProperties>(std::move(pref_delegate), |
| /*net_log=*/nullptr, |
| GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(saved_value.Clone()); |
| |
| if (save_network_anonymization_key_mode == |
| NetworkAnonymizationKeyMode::kDisabled) { |
| // If NetworkAnonymizationKey was disabled when saving, entries were |
| // saved with an empty NetworkAnonymizationKey, which should always be |
| // loaded successfully. This is needed to continue to support consumers |
| // that don't use NetworkAnonymizationKeys. |
| EXPECT_EQ(kQuicServerInfo3, *properties->GetQuicServerInfo( |
| kServer1, NetworkAnonymizationKey())); |
| EXPECT_EQ(kQuicServerInfo2, *properties->GetQuicServerInfo( |
| kServer2, NetworkAnonymizationKey())); |
| if (load_network_anonymization_key_mode != |
| NetworkAnonymizationKeyMode::kDisabled) { |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer1, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer1, kNetworkAnonymizationKey2)); |
| |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer2, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer2, kNetworkAnonymizationKey2)); |
| } |
| } else if (save_network_anonymization_key_mode == |
| load_network_anonymization_key_mode) { |
| // If the save and load modes are the same, the load should succeed, and |
| // the network anonymization keys should match. |
| EXPECT_EQ(kQuicServerInfo1, *properties->GetQuicServerInfo( |
| kServer1, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer1, kNetworkAnonymizationKey2)); |
| EXPECT_EQ(kQuicServerInfo3, *properties->GetQuicServerInfo( |
| kServer1, NetworkAnonymizationKey())); |
| |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer2, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(kQuicServerInfo2, *properties->GetQuicServerInfo( |
| kServer2, kNetworkAnonymizationKey2)); |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer2, NetworkAnonymizationKey())); |
| } else { |
| // Otherwise, only the value set with an empty NetworkAnonymizationKey |
| // should have been loaded successfully. |
| EXPECT_EQ(kQuicServerInfo3, *properties->GetQuicServerInfo( |
| kServer1, NetworkAnonymizationKey())); |
| |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer2, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer2, kNetworkAnonymizationKey2)); |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer2, NetworkAnonymizationKey())); |
| |
| // There should be no cross-contamination of NetworkAnonymizationKeys, |
| // if NetworkAnonymizationKeys are enabled. |
| if (load_network_anonymization_key_mode != |
| NetworkAnonymizationKeyMode::kDisabled) { |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer1, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(nullptr, properties->GetQuicServerInfo( |
| kServer1, kNetworkAnonymizationKey2)); |
| } |
| } |
| } |
| } |
| } |
| |
| // Tests a full round trip to prefs and back in the canonical suffix for |
| // QuicServerInfo case. Enable NetworkAnonymizationKeys, as they have some |
| // interactions with the canonical suffix logic. |
| TEST_F(HttpServerPropertiesManagerTest, |
| NetworkAnonymizationKeyQuicServerInfoCanonicalSuffixRoundTrip) { |
| const SchemefulSite kSite1(GURL("https://foo.test/")); |
| const SchemefulSite kSite2(GURL("https://bar.test/")); |
| const auto kNetworkAnonymizationKey1 = |
| NetworkAnonymizationKey::CreateSameSite(kSite1); |
| const auto kNetworkAnonymizationKey2 = |
| NetworkAnonymizationKey::CreateSameSite(kSite2); |
| |
| // Three servers with the same canonical suffix (".c.youtube.com"). |
| const quic::QuicServerId kServer1("foo.c.youtube.com", 443, |
| false /* privacy_mode_enabled */); |
| const quic::QuicServerId kServer2("bar.c.youtube.com", 443, |
| false /* privacy_mode_enabled */); |
| const quic::QuicServerId kServer3("baz.c.youtube.com", 443, |
| false /* privacy_mode_enabled */); |
| |
| const char kQuicServerInfo1[] = "info1"; |
| const char kQuicServerInfo2[] = "info2"; |
| const char kQuicServerInfo3[] = "info3"; |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| |
| // Create and initialize an HttpServerProperties with no state. |
| std::unique_ptr<MockPrefDelegate> pref_delegate = |
| std::make_unique<MockPrefDelegate>(); |
| MockPrefDelegate* unowned_pref_delegate = pref_delegate.get(); |
| std::unique_ptr<HttpServerProperties> properties = |
| std::make_unique<HttpServerProperties>(std::move(pref_delegate), |
| /*net_log=*/nullptr, |
| GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(base::Value::Dict()); |
| |
| // Set kQuicServerInfo1 for kServer1 using kNetworkAnonymizationKey1. That |
| // information should be retrieved when fetching information for any server |
| // with the same canonical suffix, when using kNetworkAnonymizationKey1. |
| properties->SetQuicServerInfo(kServer1, kNetworkAnonymizationKey1, |
| kQuicServerInfo1); |
| EXPECT_EQ(kQuicServerInfo1, *properties->GetQuicServerInfo( |
| kServer1, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(kQuicServerInfo1, *properties->GetQuicServerInfo( |
| kServer2, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(kQuicServerInfo1, *properties->GetQuicServerInfo( |
| kServer3, kNetworkAnonymizationKey1)); |
| EXPECT_FALSE( |
| properties->GetQuicServerInfo(kServer1, kNetworkAnonymizationKey2)); |
| |
| // Set kQuicServerInfo2 for kServer2 using kNetworkAnonymizationKey1. It |
| // should not affect information retrieved for kServer1, but should for |
| // kServer2 and kServer3. |
| properties->SetQuicServerInfo(kServer2, kNetworkAnonymizationKey1, |
| kQuicServerInfo2); |
| EXPECT_EQ(kQuicServerInfo1, *properties->GetQuicServerInfo( |
| kServer1, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(kQuicServerInfo2, *properties->GetQuicServerInfo( |
| kServer2, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(kQuicServerInfo2, *properties->GetQuicServerInfo( |
| kServer3, kNetworkAnonymizationKey1)); |
| EXPECT_FALSE( |
| properties->GetQuicServerInfo(kServer1, kNetworkAnonymizationKey2)); |
| |
| // Set kQuicServerInfo3 for kServer1 using kNetworkAnonymizationKey2. It |
| // should not affect information stored for kNetworkAnonymizationKey1. |
| properties->SetQuicServerInfo(kServer1, kNetworkAnonymizationKey2, |
| kQuicServerInfo3); |
| EXPECT_EQ(kQuicServerInfo1, *properties->GetQuicServerInfo( |
| kServer1, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(kQuicServerInfo2, *properties->GetQuicServerInfo( |
| kServer2, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(kQuicServerInfo2, *properties->GetQuicServerInfo( |
| kServer3, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(kQuicServerInfo3, *properties->GetQuicServerInfo( |
| kServer1, kNetworkAnonymizationKey2)); |
| EXPECT_EQ(kQuicServerInfo3, *properties->GetQuicServerInfo( |
| kServer2, kNetworkAnonymizationKey2)); |
| EXPECT_EQ(kQuicServerInfo3, *properties->GetQuicServerInfo( |
| kServer3, kNetworkAnonymizationKey2)); |
| |
| // Wait until the data's been written to prefs, and then tear down the |
| // HttpServerProperties. |
| FastForwardBy(HttpServerProperties::GetUpdatePrefsDelayForTesting()); |
| base::Value::Dict saved_value = |
| unowned_pref_delegate->GetServerProperties().Clone(); |
| properties.reset(); |
| |
| // Create a new HttpServerProperties using the value saved to prefs above. |
| pref_delegate = std::make_unique<MockPrefDelegate>(); |
| unowned_pref_delegate = pref_delegate.get(); |
| properties = std::make_unique<HttpServerProperties>( |
| std::move(pref_delegate), /*net_log=*/nullptr, GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(std::move(saved_value)); |
| |
| // All values should have been saved and be retrievable by suffix-matching |
| // servers. |
| // |
| // TODO(mmenke): The rest of this test corresponds exactly to behavior in |
| // CanonicalSuffixRoundTripWithNetworkAnonymizationKey. It seems like these |
| // lines should correspond as well. |
| EXPECT_EQ(kQuicServerInfo1, *properties->GetQuicServerInfo( |
| kServer1, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(kQuicServerInfo2, *properties->GetQuicServerInfo( |
| kServer2, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(kQuicServerInfo2, *properties->GetQuicServerInfo( |
| kServer3, kNetworkAnonymizationKey1)); |
| EXPECT_EQ(kQuicServerInfo3, *properties->GetQuicServerInfo( |
| kServer1, kNetworkAnonymizationKey2)); |
| EXPECT_EQ(kQuicServerInfo3, *properties->GetQuicServerInfo( |
| kServer2, kNetworkAnonymizationKey2)); |
| EXPECT_EQ(kQuicServerInfo3, *properties->GetQuicServerInfo( |
| kServer3, kNetworkAnonymizationKey2)); |
| } |
| |
| // Make sure QuicServerInfo associated with NetworkAnonymizationKeys with opaque |
| // origins aren't saved. |
| TEST_F(HttpServerPropertiesManagerTest, |
| NetworkAnonymizationKeyQuicServerInfoOpaqueOrigin) { |
| const SchemefulSite kOpaqueSite(GURL("data:text/plain,Hello World")); |
| const auto kNetworkAnonymizationKey = |
| NetworkAnonymizationKey::CreateSameSite(kOpaqueSite); |
| const quic::QuicServerId kServer("foo", 443, |
| false /* privacy_mode_enabled */); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| |
| // Create and initialize an HttpServerProperties, must be done after |
| // setting the feature. |
| std::unique_ptr<MockPrefDelegate> pref_delegate = |
| std::make_unique<MockPrefDelegate>(); |
| MockPrefDelegate* unowned_pref_delegate = pref_delegate.get(); |
| std::unique_ptr<HttpServerProperties> properties = |
| std::make_unique<HttpServerProperties>(std::move(pref_delegate), |
| /*net_log=*/nullptr, |
| GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(base::Value::Dict()); |
| |
| properties->SetQuicServerInfo(kServer, kNetworkAnonymizationKey, |
| "QuicServerInfo"); |
| EXPECT_TRUE(properties->GetQuicServerInfo(kServer, kNetworkAnonymizationKey)); |
| |
| // Wait until the data's been written to prefs, and then create a copy of |
| // the prefs data. |
| FastForwardBy(HttpServerProperties::GetUpdatePrefsDelayForTesting()); |
| |
| // No information should have been saved to prefs. |
| std::string preferences_json; |
| base::JSONWriter::Write(unowned_pref_delegate->GetServerProperties(), |
| &preferences_json); |
| EXPECT_EQ("{\"quic_servers\":[],\"servers\":[],\"version\":5}", |
| preferences_json); |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, AdvertisedVersionsRoundTrip) { |
| for (const quic::ParsedQuicVersion& version : AllSupportedQuicVersions()) { |
| if (version.AlpnDeferToRFCv1()) { |
| // These versions currently do not support Alt-Svc. |
| continue; |
| } |
| // Reset test infrastructure. |
| TearDown(); |
| SetUp(); |
| InitializePrefs(); |
| // Create alternate version information. |
| const url::SchemeHostPort server("https", "quic.example.org", 443); |
| AlternativeServiceInfoVector alternative_service_info_vector_in; |
| AlternativeService quic_alternative_service(kProtoQUIC, "", 443); |
| base::Time expiration; |
| ASSERT_TRUE(base::Time::FromUTCString("2036-12-01 10:00:00", &expiration)); |
| quic::ParsedQuicVersionVector advertised_versions = {version}; |
| alternative_service_info_vector_in.push_back( |
| AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( |
| quic_alternative_service, expiration, advertised_versions)); |
| http_server_props_->SetAlternativeServices( |
| server, NetworkAnonymizationKey(), alternative_service_info_vector_in); |
| // Save to JSON. |
| EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); |
| EXPECT_NE(0u, GetPendingMainThreadTaskCount()); |
| FastForwardUntilNoTasksRemain(); |
| EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); |
| const base::Value::Dict& http_server_properties = |
| pref_delegate_->GetServerProperties(); |
| std::string preferences_json; |
| EXPECT_TRUE( |
| base::JSONWriter::Write(http_server_properties, &preferences_json)); |
| // Reset test infrastructure. |
| TearDown(); |
| SetUp(); |
| InitializePrefs(); |
| // Read from JSON. |
| base::Value::Dict preferences_dict = |
| base::test::ParseJsonDict(preferences_json); |
| ASSERT_FALSE(preferences_dict.empty()); |
| const base::Value::List* servers_list = |
| preferences_dict.FindList("servers"); |
| ASSERT_TRUE(servers_list); |
| ASSERT_EQ(servers_list->size(), 1u); |
| const base::Value& server_dict = (*servers_list)[0]; |
| HttpServerProperties::ServerInfo server_info; |
| EXPECT_TRUE(HttpServerPropertiesManager::ParseAlternativeServiceInfo( |
| server, server_dict.GetDict(), &server_info)); |
| ASSERT_TRUE(server_info.alternative_services.has_value()); |
| AlternativeServiceInfoVector alternative_service_info_vector_out = |
| server_info.alternative_services.value(); |
| ASSERT_EQ(1u, alternative_service_info_vector_out.size()); |
| EXPECT_EQ( |
| kProtoQUIC, |
| alternative_service_info_vector_out[0].alternative_service().protocol); |
| // Ensure we correctly parsed the version. |
| EXPECT_EQ(advertised_versions, |
| alternative_service_info_vector_out[0].advertised_versions()); |
| } |
| } |
| |
| TEST_F(HttpServerPropertiesManagerTest, SameOrderAfterReload) { |
| const SchemefulSite kSite1(GURL("https://foo.test/")); |
| const SchemefulSite kSite2(GURL("https://bar.test/")); |
| const auto kNetworkAnonymizationKey1 = |
| NetworkAnonymizationKey::CreateSameSite(kSite1); |
| const auto kNetworkAnonymizationKey2 = |
| NetworkAnonymizationKey::CreateSameSite(kSite2); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| |
| // Create and initialize an HttpServerProperties with no state. |
| std::unique_ptr<MockPrefDelegate> pref_delegate = |
| std::make_unique<MockPrefDelegate>(); |
| MockPrefDelegate* unowned_pref_delegate = pref_delegate.get(); |
| std::unique_ptr<HttpServerProperties> properties = |
| std::make_unique<HttpServerProperties>(std::move(pref_delegate), |
| /*net_log=*/nullptr, |
| GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(base::Value::Dict()); |
| |
| // Set alternative_service info. |
| base::Time expiration = base::Time::Now() + base::Days(1); |
| AlternativeServiceInfo alt_service1 = |
| AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( |
| AlternativeService(kProtoQUIC, "1.example", 1234), expiration, |
| DefaultSupportedQuicVersions()); |
| AlternativeServiceInfo alt_service2 = |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| AlternativeService(kProtoHTTP2, "2.example", 443), expiration); |
| AlternativeServiceInfo alt_service3 = |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| AlternativeService(kProtoHTTP2, "3.example", 443), expiration); |
| const url::SchemeHostPort kServer1("https", "1.example", 443); |
| const url::SchemeHostPort kServer2("https", "2.example", 443); |
| const url::SchemeHostPort kServer3("https", "3.example", 443); |
| properties->SetAlternativeServices(kServer1, kNetworkAnonymizationKey1, |
| {alt_service1}); |
| properties->SetAlternativeServices(kServer2, kNetworkAnonymizationKey1, |
| {alt_service2}); |
| properties->SetAlternativeServices(kServer3, kNetworkAnonymizationKey2, |
| {alt_service3}); |
| |
| // Set quic_server_info. |
| quic::QuicServerId quic_server_id1("quic1.example", 80, false); |
| quic::QuicServerId quic_server_id2("quic2.example", 80, false); |
| quic::QuicServerId quic_server_id3("quic3.example", 80, false); |
| properties->SetQuicServerInfo(quic_server_id1, kNetworkAnonymizationKey1, |
| "quic_server_info1"); |
| properties->SetQuicServerInfo(quic_server_id2, kNetworkAnonymizationKey1, |
| "quic_server_info2"); |
| properties->SetQuicServerInfo(quic_server_id3, kNetworkAnonymizationKey2, |
| "quic_server_info3"); |
| |
| // Set broken_alternative_service info. |
| AlternativeService broken_service1(kProtoQUIC, "broken1.example", 443); |
| AlternativeService broken_service2(kProtoQUIC, "broken2.example", 443); |
| AlternativeService broken_service3(kProtoQUIC, "broken3.example", 443); |
| properties->MarkAlternativeServiceBroken(broken_service1, |
| kNetworkAnonymizationKey1); |
| FastForwardBy(base::Milliseconds(1)); |
| properties->MarkAlternativeServiceBroken(broken_service2, |
| kNetworkAnonymizationKey1); |
| FastForwardBy(base::Milliseconds(1)); |
| properties->MarkAlternativeServiceBroken(broken_service3, |
| kNetworkAnonymizationKey2); |
| |
| // The first item of `server_info_map` must be the latest item. |
| EXPECT_EQ(3u, properties->server_info_map_for_testing().size()); |
| EXPECT_EQ( |
| properties->server_info_map_for_testing().begin()->first.server.host(), |
| "3.example"); |
| |
| // The first item of `recently_broken_alternative_services` must be the latest |
| // item. |
| EXPECT_EQ(3u, properties->broken_alternative_services_for_testing() |
| .recently_broken_alternative_services() |
| .size()); |
| EXPECT_EQ("broken3.example", |
| properties->broken_alternative_services_for_testing() |
| .recently_broken_alternative_services() |
| .begin() |
| ->first.alternative_service.host); |
| |
| // The first item of `quic_server_info_map` must be the latest item. |
| EXPECT_EQ(3u, properties->quic_server_info_map_for_testing().size()); |
| EXPECT_EQ("quic3.example", properties->quic_server_info_map_for_testing() |
| .begin() |
| ->first.server_id.host()); |
| |
| // The first item of `broken_alternative_service_list` must be the oldest |
| // item. |
| EXPECT_EQ(3u, properties->broken_alternative_services_for_testing() |
| .broken_alternative_service_list() |
| .size()); |
| EXPECT_EQ("broken1.example", |
| properties->broken_alternative_services_for_testing() |
| .broken_alternative_service_list() |
| .begin() |
| ->first.alternative_service.host); |
| |
| // Wait until the data's been written to prefs, and then tear down the |
| // HttpServerProperties. |
| FastForwardBy(HttpServerProperties::GetUpdatePrefsDelayForTesting()); |
| base::Value::Dict saved_value = |
| unowned_pref_delegate->GetServerProperties().Clone(); |
| |
| // Create a new HttpServerProperties using the value saved to prefs above. |
| pref_delegate = std::make_unique<MockPrefDelegate>(); |
| unowned_pref_delegate = pref_delegate.get(); |
| properties = std::make_unique<HttpServerProperties>( |
| std::move(pref_delegate), /*net_log=*/nullptr, GetMockTickClock()); |
| unowned_pref_delegate->InitializePrefs(std::move(saved_value)); |
| |
| // The first item of `server_info_map` must be the latest item. |
| EXPECT_EQ(3u, properties->server_info_map_for_testing().size()); |
| EXPECT_EQ( |
| properties->server_info_map_for_testing().begin()->first.server.host(), |
| "3.example"); |
| |
| // The first item of `recently_broken_alternative_services` must be the latest |
| // item. |
| EXPECT_EQ(3u, properties->broken_alternative_services_for_testing() |
| .recently_broken_alternative_services() |
| .size()); |
| EXPECT_EQ("broken3.example", |
| properties->broken_alternative_services_for_testing() |
| .recently_broken_alternative_services() |
| .begin() |
| ->first.alternative_service.host); |
| |
| // The first item of `quic_server_info_map` must be the latest item. |
| EXPECT_EQ(3u, properties->quic_server_info_map_for_testing().size()); |
| EXPECT_EQ("quic3.example", properties->quic_server_info_map_for_testing() |
| .begin() |
| ->first.server_id.host()); |
| |
| // The first item of `broken_alternative_service_list` must be the oldest |
| // item. |
| EXPECT_EQ(3u, properties->broken_alternative_services_for_testing() |
| .broken_alternative_service_list() |
| .size()); |
| EXPECT_EQ("broken1.example", |
| properties->broken_alternative_services_for_testing() |
| .broken_alternative_service_list() |
| .begin() |
| ->first.alternative_service.host); |
| } |
| |
| } // namespace net |