// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/http/http_server_properties_manager.h" #include "base/json/json_reader.h" #include "base/json/json_writer.h" #include "base/macros.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/test/test_simple_task_runner.h" #include "base/thread_task_runner_handle.h" #include "base/values.h" #include "net/base/ip_address.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::Invoke; using ::testing::Mock; using ::testing::StrictMock; class MockPrefDelegate : public net::HttpServerPropertiesManager::PrefDelegate { public: MockPrefDelegate() {} ~MockPrefDelegate() override {} // HttpServerPropertiesManager::PrefDelegate implementation. bool HasServerProperties() override { return true; } const base::DictionaryValue& GetServerProperties() const override { return prefs_; } void SetServerProperties(const base::DictionaryValue& value) override { prefs_.Clear(); prefs_.MergeDictionary(&value); if (!prefs_changed_callback_.is_null()) prefs_changed_callback_.Run(); } void StartListeningForUpdates(const base::Closure& callback) override { CHECK(prefs_changed_callback_.is_null()); prefs_changed_callback_ = callback; } void StopListeningForUpdates() override { CHECK(!prefs_changed_callback_.is_null()); prefs_changed_callback_ = base::Closure(); } void SetPrefs(const base::DictionaryValue& value) { // prefs_ = value; prefs_.Clear(); prefs_.MergeDictionary(&value); if (!prefs_changed_callback_.is_null()) prefs_changed_callback_.Run(); } private: base::DictionaryValue prefs_; base::Closure prefs_changed_callback_; DISALLOW_COPY_AND_ASSIGN(MockPrefDelegate); }; class TestingHttpServerPropertiesManager : public HttpServerPropertiesManager { public: TestingHttpServerPropertiesManager( HttpServerPropertiesManager::PrefDelegate* pref_delegate, scoped_refptr io_task_runner) : HttpServerPropertiesManager(pref_delegate, io_task_runner) { InitializeOnNetworkThread(); } ~TestingHttpServerPropertiesManager() override {} // Make these methods public for testing. using HttpServerPropertiesManager::ScheduleUpdateCacheOnPrefThread; // Post tasks without a delay during tests. void StartPrefsUpdateTimerOnNetworkThread(base::TimeDelta delay) override { HttpServerPropertiesManager::StartPrefsUpdateTimerOnNetworkThread( base::TimeDelta()); } void UpdateCacheFromPrefsOnUIConcrete() { HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread(); } // Post tasks without a delay during tests. void StartCacheUpdateTimerOnPrefThread(base::TimeDelta delay) override { HttpServerPropertiesManager::StartCacheUpdateTimerOnPrefThread( base::TimeDelta()); } void UpdatePrefsFromCacheOnNetworkThreadConcrete( const base::Closure& callback) { HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread(callback); } void ScheduleUpdatePrefsOnNetworkThreadConcrete(Location location) { HttpServerPropertiesManager::ScheduleUpdatePrefsOnNetworkThread(location); } void ScheduleUpdatePrefsOnNetworkThread() { // Picked a random Location as caller. HttpServerPropertiesManager::ScheduleUpdatePrefsOnNetworkThread( DETECTED_CORRUPTED_PREFS); } MOCK_METHOD0(UpdateCacheFromPrefsOnPrefThread, void()); MOCK_METHOD1(UpdatePrefsFromCacheOnNetworkThread, void(const base::Closure&)); MOCK_METHOD1(ScheduleUpdatePrefsOnNetworkThread, void(Location location)); MOCK_METHOD7(UpdateCacheFromPrefsOnNetworkThread, void(std::vector* spdy_servers, SpdySettingsMap* spdy_settings_map, AlternativeServiceMap* alternative_service_map, IPAddress* last_quic_address, ServerNetworkStatsMap* server_network_stats_map, QuicServerInfoMap* quic_server_info_map, bool detected_corrupted_prefs)); MOCK_METHOD7(UpdatePrefsOnPrefThread, void(base::ListValue* spdy_server_list, SpdySettingsMap* spdy_settings_map, AlternativeServiceMap* alternative_service_map, IPAddress* last_quic_address, ServerNetworkStatsMap* server_network_stats_map, QuicServerInfoMap* quic_server_info_map, const base::Closure& completion)); private: DISALLOW_COPY_AND_ASSIGN(TestingHttpServerPropertiesManager); }; } // namespace // TODO(rtenneti): After we stop supporting version 3 and everyone has migrated // to version 4, delete the following code. static const int kHttpServerPropertiesVersions[] = {3, 4}; class HttpServerPropertiesManagerTest : public testing::TestWithParam { protected: HttpServerPropertiesManagerTest() {} void SetUp() override { one_day_from_now_ = base::Time::Now() + base::TimeDelta::FromDays(1); pref_delegate_ = new MockPrefDelegate; http_server_props_manager_.reset( new StrictMock( pref_delegate_, base::ThreadTaskRunnerHandle::Get())); ExpectCacheUpdate(); base::RunLoop().RunUntilIdle(); } void TearDown() override { if (http_server_props_manager_.get()) http_server_props_manager_->ShutdownOnPrefThread(); base::RunLoop().RunUntilIdle(); http_server_props_manager_.reset(); } void ExpectCacheUpdate() { EXPECT_CALL(*http_server_props_manager_, UpdateCacheFromPrefsOnPrefThread()) .WillOnce(Invoke(http_server_props_manager_.get(), &TestingHttpServerPropertiesManager:: UpdateCacheFromPrefsOnUIConcrete)); } void ExpectScheduleUpdatePrefsOnNetworkThread() { EXPECT_CALL(*http_server_props_manager_, ScheduleUpdatePrefsOnNetworkThread(_)) .WillOnce(Invoke(http_server_props_manager_.get(), &TestingHttpServerPropertiesManager:: ScheduleUpdatePrefsOnNetworkThreadConcrete)); } void ExpectScheduleUpdatePrefsOnNetworkThreadRepeatedly() { EXPECT_CALL(*http_server_props_manager_, ScheduleUpdatePrefsOnNetworkThread(_)) .WillRepeatedly(Invoke(http_server_props_manager_.get(), &TestingHttpServerPropertiesManager:: ScheduleUpdatePrefsOnNetworkThreadConcrete)); } void ExpectPrefsUpdate() { EXPECT_CALL(*http_server_props_manager_, UpdatePrefsFromCacheOnNetworkThread(_)) .WillOnce(Invoke(http_server_props_manager_.get(), &TestingHttpServerPropertiesManager:: UpdatePrefsFromCacheOnNetworkThreadConcrete)); } void ExpectPrefsUpdateRepeatedly() { EXPECT_CALL(*http_server_props_manager_, UpdatePrefsFromCacheOnNetworkThread(_)) .WillRepeatedly( Invoke(http_server_props_manager_.get(), &TestingHttpServerPropertiesManager:: UpdatePrefsFromCacheOnNetworkThreadConcrete)); } bool HasAlternativeService(const HostPortPair& server) { const AlternativeServiceVector alternative_service_vector = http_server_props_manager_->GetAlternativeServices(server); return !alternative_service_vector.empty(); } MockPrefDelegate* pref_delegate_; // Owned by HttpServerPropertiesManager. scoped_ptr http_server_props_manager_; base::Time one_day_from_now_; private: DISALLOW_COPY_AND_ASSIGN(HttpServerPropertiesManagerTest); }; INSTANTIATE_TEST_CASE_P(Tests, HttpServerPropertiesManagerTest, ::testing::ValuesIn(kHttpServerPropertiesVersions)); TEST_P(HttpServerPropertiesManagerTest, SingleUpdateForTwoSpdyServerPrefChanges) { ExpectCacheUpdate(); // Set up the prefs for www.google.com:80 and mail.google.com:80 and then set // it twice. Only expect a single cache update. base::DictionaryValue* server_pref_dict = new base::DictionaryValue; HostPortPair google_server("www.google.com", 80); HostPortPair mail_server("mail.google.com", 80); // Set supports_spdy for www.google.com:80. server_pref_dict->SetBoolean("supports_spdy", true); // Set up alternative_services for www.google.com:80. base::DictionaryValue* alternative_service_dict0 = new base::DictionaryValue; alternative_service_dict0->SetInteger("port", 443); alternative_service_dict0->SetString("protocol_str", "npn-h2"); base::DictionaryValue* alternative_service_dict1 = new base::DictionaryValue; alternative_service_dict1->SetInteger("port", 1234); alternative_service_dict1->SetString("protocol_str", "quic"); base::ListValue* alternative_service_list0 = new base::ListValue; alternative_service_list0->Append(alternative_service_dict0); alternative_service_list0->Append(alternative_service_dict1); server_pref_dict->SetWithoutPathExpansion("alternative_service", alternative_service_list0); // Set up ServerNetworkStats for www.google.com:80. base::DictionaryValue* stats = new base::DictionaryValue; stats->SetInteger("srtt", 10); server_pref_dict->SetWithoutPathExpansion("network_stats", stats); // Set the server preference for www.google.com:80. base::DictionaryValue* servers_dict = new base::DictionaryValue; servers_dict->SetWithoutPathExpansion("www.google.com:80", server_pref_dict); base::ListValue* servers_list = nullptr; if (GetParam() == 4) { servers_list = new base::ListValue; // |servers_list| takes ownership of |servers_dict|. servers_list->AppendIfNotPresent(servers_dict); servers_dict = new base::DictionaryValue; } // Set the preference for mail.google.com server. base::DictionaryValue* server_pref_dict1 = new base::DictionaryValue; // Set supports_spdy for mail.google.com:80 server_pref_dict1->SetBoolean("supports_spdy", true); // Set up alternative_services for mail.google.com:80. base::DictionaryValue* alternative_service_dict2 = new base::DictionaryValue; alternative_service_dict2->SetString("protocol_str", "npn-spdy/3.1"); alternative_service_dict2->SetInteger("port", 444); base::ListValue* alternative_service_list1 = new base::ListValue; alternative_service_list1->Append(alternative_service_dict2); server_pref_dict1->SetWithoutPathExpansion("alternative_service", alternative_service_list1); // Set up ServerNetworkStats for mail.google.com:80 and it is the MRU server. base::DictionaryValue* stats1 = new base::DictionaryValue; stats1->SetInteger("srtt", 20); server_pref_dict1->SetWithoutPathExpansion("network_stats", stats1); // Set the server preference for mail.google.com:80. servers_dict->SetWithoutPathExpansion("mail.google.com:80", server_pref_dict1); base::DictionaryValue http_server_properties_dict; if (GetParam() == 4) { // |servers_list| takes ownership of |servers_dict|. servers_list->AppendIfNotPresent(servers_dict); HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, -1); http_server_properties_dict.SetWithoutPathExpansion("servers", servers_list); } else { HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, GetParam()); http_server_properties_dict.SetWithoutPathExpansion("servers", servers_dict); } base::DictionaryValue* supports_quic = new base::DictionaryValue; supports_quic->SetBoolean("used_quic", true); supports_quic->SetString("address", "127.0.0.1"); http_server_properties_dict.SetWithoutPathExpansion("supports_quic", supports_quic); // Set quic_server_info for www.google.com:80, mail.google.com:80 and // play.google.com:80 and verify the MRU. http_server_props_manager_->SetMaxServerConfigsStoredInProperties(3); base::DictionaryValue* quic_servers_dict = new base::DictionaryValue; base::DictionaryValue* quic_server_pref_dict1 = new base::DictionaryValue; std::string quic_server_info1("quic_server_info1"); quic_server_pref_dict1->SetStringWithoutPathExpansion("server_info", quic_server_info1); base::DictionaryValue* quic_server_pref_dict2 = new base::DictionaryValue; std::string quic_server_info2("quic_server_info2"); quic_server_pref_dict2->SetStringWithoutPathExpansion("server_info", quic_server_info2); base::DictionaryValue* quic_server_pref_dict3 = new base::DictionaryValue; std::string quic_server_info3("quic_server_info3"); quic_server_pref_dict3->SetStringWithoutPathExpansion("server_info", quic_server_info3); // Set the quic_server_info1 for www.google.com server. QuicServerId google_quic_server_id("www.google.com", 80); quic_servers_dict->SetWithoutPathExpansion(google_quic_server_id.ToString(), quic_server_pref_dict1); // Set the quic_server_info2 for mail.google.com server. QuicServerId mail_quic_server_id("mail.google.com", 80); quic_servers_dict->SetWithoutPathExpansion(mail_quic_server_id.ToString(), quic_server_pref_dict2); // Set the quic_server_info3 for play.google.com server. QuicServerId play_quic_server_id("play.google.com", 80); quic_servers_dict->SetWithoutPathExpansion(play_quic_server_id.ToString(), quic_server_pref_dict3); http_server_properties_dict.SetWithoutPathExpansion("quic_servers", quic_servers_dict); // Set the same value for kHttpServerProperties multiple times. pref_delegate_->SetPrefs(http_server_properties_dict); pref_delegate_->SetPrefs(http_server_properties_dict); base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); // Verify SupportsSpdy. EXPECT_TRUE( http_server_props_manager_->SupportsRequestPriority(google_server)); EXPECT_TRUE(http_server_props_manager_->SupportsRequestPriority(mail_server)); EXPECT_FALSE(http_server_props_manager_->SupportsRequestPriority( HostPortPair::FromString("foo.google.com:1337"))); // Verify alternative service. if (GetParam() == 4) { const AlternativeServiceMap& map = http_server_props_manager_->alternative_service_map(); ASSERT_EQ(2u, map.size()); AlternativeServiceMap::const_iterator map_it = map.begin(); EXPECT_EQ("mail.google.com", map_it->first.host()); ASSERT_EQ(1u, map_it->second.size()); EXPECT_EQ(NPN_SPDY_3_1, map_it->second[0].alternative_service.protocol); EXPECT_TRUE(map_it->second[0].alternative_service.host.empty()); EXPECT_EQ(444, map_it->second[0].alternative_service.port); ++map_it; EXPECT_EQ("www.google.com", map_it->first.host()); ASSERT_EQ(2u, map_it->second.size()); EXPECT_EQ(NPN_HTTP_2, map_it->second[0].alternative_service.protocol); EXPECT_TRUE(map_it->second[0].alternative_service.host.empty()); EXPECT_EQ(443, map_it->second[0].alternative_service.port); EXPECT_EQ(QUIC, map_it->second[1].alternative_service.protocol); EXPECT_TRUE(map_it->second[1].alternative_service.host.empty()); EXPECT_EQ(1234, map_it->second[1].alternative_service.port); } else { const AlternativeServiceMap& map = http_server_props_manager_->alternative_service_map(); ASSERT_EQ(2u, map.size()); AlternativeServiceMap::const_iterator map_it = map.begin(); EXPECT_EQ("www.google.com", map_it->first.host()); ASSERT_EQ(2u, map_it->second.size()); EXPECT_EQ(NPN_HTTP_2, map_it->second[0].alternative_service.protocol); EXPECT_TRUE(map_it->second[0].alternative_service.host.empty()); EXPECT_EQ(443, map_it->second[0].alternative_service.port); EXPECT_EQ(QUIC, map_it->second[1].alternative_service.protocol); EXPECT_TRUE(map_it->second[1].alternative_service.host.empty()); EXPECT_EQ(1234, map_it->second[1].alternative_service.port); ++map_it; EXPECT_EQ("mail.google.com", map_it->first.host()); ASSERT_EQ(1u, map_it->second.size()); EXPECT_EQ(NPN_SPDY_3_1, map_it->second[0].alternative_service.protocol); EXPECT_TRUE(map_it->second[0].alternative_service.host.empty()); EXPECT_EQ(444, map_it->second[0].alternative_service.port); } // Verify SupportsQuic. IPAddress last_address; EXPECT_TRUE(http_server_props_manager_->GetSupportsQuic(&last_address)); EXPECT_EQ("127.0.0.1", last_address.ToString()); // Verify ServerNetworkStats. const ServerNetworkStats* stats2 = http_server_props_manager_->GetServerNetworkStats(google_server); EXPECT_EQ(10, stats2->srtt.ToInternalValue()); const ServerNetworkStats* stats3 = http_server_props_manager_->GetServerNetworkStats(mail_server); EXPECT_EQ(20, stats3->srtt.ToInternalValue()); // Verify QuicServerInfo. EXPECT_EQ(quic_server_info1, *http_server_props_manager_->GetQuicServerInfo( google_quic_server_id)); EXPECT_EQ(quic_server_info2, *http_server_props_manager_->GetQuicServerInfo( mail_quic_server_id)); EXPECT_EQ(quic_server_info3, *http_server_props_manager_->GetQuicServerInfo( play_quic_server_id)); // Verify the MRU order. http_server_props_manager_->SetMaxServerConfigsStoredInProperties(2); EXPECT_EQ(nullptr, http_server_props_manager_->GetQuicServerInfo( google_quic_server_id)); EXPECT_EQ(quic_server_info2, *http_server_props_manager_->GetQuicServerInfo( mail_quic_server_id)); EXPECT_EQ(quic_server_info3, *http_server_props_manager_->GetQuicServerInfo( play_quic_server_id)); } TEST_P(HttpServerPropertiesManagerTest, BadCachedHostPortPair) { ExpectCacheUpdate(); // The prefs are automaticalls updated in the case corruption is detected. ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); base::DictionaryValue* server_pref_dict = new base::DictionaryValue; // Set supports_spdy for www.google.com:65536. server_pref_dict->SetBoolean("supports_spdy", true); // Set up alternative_service for www.google.com:65536. base::DictionaryValue* alternative_service_dict = new base::DictionaryValue; alternative_service_dict->SetString("protocol_str", "npn-h2"); alternative_service_dict->SetInteger("port", 80); base::ListValue* alternative_service_list = new base::ListValue; alternative_service_list->Append(alternative_service_dict); server_pref_dict->SetWithoutPathExpansion("alternative_service", alternative_service_list); // Set up ServerNetworkStats for www.google.com:65536. base::DictionaryValue* stats = new base::DictionaryValue; stats->SetInteger("srtt", 10); server_pref_dict->SetWithoutPathExpansion("network_stats", stats); // Set the server preference for www.google.com:65536. base::DictionaryValue* servers_dict = new base::DictionaryValue; servers_dict->SetWithoutPathExpansion("www.google.com:65536", server_pref_dict); base::DictionaryValue http_server_properties_dict; if (GetParam() == 4) { base::ListValue* servers_list = new base::ListValue; // |servers_list| takes ownership of |servers_dict|. servers_list->AppendIfNotPresent(servers_dict); HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, -1); http_server_properties_dict.SetWithoutPathExpansion("servers", servers_list); } else { HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, GetParam()); http_server_properties_dict.SetWithoutPathExpansion("servers", servers_dict); } // Set quic_server_info for www.google.com:65536. base::DictionaryValue* quic_servers_dict = new base::DictionaryValue; base::DictionaryValue* quic_server_pref_dict1 = new base::DictionaryValue; quic_server_pref_dict1->SetStringWithoutPathExpansion("server_info", "quic_server_info1"); quic_servers_dict->SetWithoutPathExpansion("http://mail.google.com:65536", quic_server_pref_dict1); http_server_properties_dict.SetWithoutPathExpansion("quic_servers", quic_servers_dict); // Set up the pref. pref_delegate_->SetPrefs(http_server_properties_dict); base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); // Verify that nothing is set. EXPECT_FALSE(http_server_props_manager_->SupportsRequestPriority( HostPortPair::FromString("www.google.com:65536"))); EXPECT_FALSE( HasAlternativeService(HostPortPair::FromString("www.google.com:65536"))); const ServerNetworkStats* stats1 = http_server_props_manager_->GetServerNetworkStats( HostPortPair::FromString("www.google.com:65536")); EXPECT_EQ(nullptr, stats1); EXPECT_EQ(0u, http_server_props_manager_->quic_server_info_map().size()); } TEST_P(HttpServerPropertiesManagerTest, BadCachedAltProtocolPort) { ExpectCacheUpdate(); // The prefs are automaticalls updated in the case corruption is detected. ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); base::DictionaryValue* server_pref_dict = new base::DictionaryValue; // Set supports_spdy for www.google.com:80. server_pref_dict->SetBoolean("supports_spdy", true); // Set up alternative_service for www.google.com:80. base::DictionaryValue* alternative_service_dict = new base::DictionaryValue; alternative_service_dict->SetString("protocol_str", "npn-h2"); alternative_service_dict->SetInteger("port", 65536); base::ListValue* alternative_service_list = new base::ListValue; alternative_service_list->Append(alternative_service_dict); server_pref_dict->SetWithoutPathExpansion("alternative_service", alternative_service_list); // Set the server preference for www.google.com:80. base::DictionaryValue* servers_dict = new base::DictionaryValue; servers_dict->SetWithoutPathExpansion("www.google.com:80", server_pref_dict); base::DictionaryValue http_server_properties_dict; if (GetParam() == 4) { base::ListValue* servers_list = new base::ListValue; // |servers_list| takes ownership of |servers_dict|. servers_list->AppendIfNotPresent(servers_dict); HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, -1); http_server_properties_dict.SetWithoutPathExpansion("servers", servers_list); } else { HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, GetParam()); http_server_properties_dict.SetWithoutPathExpansion("servers", servers_dict); } // Set up the pref. pref_delegate_->SetPrefs(http_server_properties_dict); base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); // Verify alternative service is not set. EXPECT_FALSE( HasAlternativeService(HostPortPair::FromString("www.google.com:80"))); } TEST_P(HttpServerPropertiesManagerTest, SupportsSpdy) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); // Post an update task to the network thread. SetSupportsSpdy calls // ScheduleUpdatePrefsOnNetworkThread. // Add mail.google.com:443 as a supporting spdy server. HostPortPair spdy_server_mail("mail.google.com", 443); EXPECT_FALSE( http_server_props_manager_->SupportsRequestPriority(spdy_server_mail)); http_server_props_manager_->SetSupportsSpdy(spdy_server_mail, true); // ExpectScheduleUpdatePrefsOnNetworkThread() should be called only once. http_server_props_manager_->SetSupportsSpdy(spdy_server_mail, true); // Run the task. base::RunLoop().RunUntilIdle(); EXPECT_TRUE( http_server_props_manager_->SupportsRequestPriority(spdy_server_mail)); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); } TEST_P(HttpServerPropertiesManagerTest, SetSpdySetting) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); // Add SpdySetting for mail.google.com:443. HostPortPair spdy_server_mail("mail.google.com", 443); const SpdySettingsIds id1 = SETTINGS_UPLOAD_BANDWIDTH; const SpdySettingsFlags flags1 = SETTINGS_FLAG_PLEASE_PERSIST; const uint32_t value1 = 31337; http_server_props_manager_->SetSpdySetting( spdy_server_mail, id1, flags1, value1); // Run the task. base::RunLoop().RunUntilIdle(); const SettingsMap& settings_map1_ret = http_server_props_manager_->GetSpdySettings(spdy_server_mail); ASSERT_EQ(1U, settings_map1_ret.size()); SettingsMap::const_iterator it1_ret = settings_map1_ret.find(id1); EXPECT_TRUE(it1_ret != settings_map1_ret.end()); SettingsFlagsAndValue flags_and_value1_ret = it1_ret->second; EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1_ret.first); EXPECT_EQ(value1, flags_and_value1_ret.second); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); } TEST_P(HttpServerPropertiesManagerTest, ClearSpdySetting) { ExpectPrefsUpdateRepeatedly(); ExpectScheduleUpdatePrefsOnNetworkThreadRepeatedly(); // Add SpdySetting for mail.google.com:443. HostPortPair spdy_server_mail("mail.google.com", 443); const SpdySettingsIds id1 = SETTINGS_UPLOAD_BANDWIDTH; const SpdySettingsFlags flags1 = SETTINGS_FLAG_PLEASE_PERSIST; const uint32_t value1 = 31337; http_server_props_manager_->SetSpdySetting( spdy_server_mail, id1, flags1, value1); // Run the task. base::RunLoop().RunUntilIdle(); const SettingsMap& settings_map1_ret = http_server_props_manager_->GetSpdySettings(spdy_server_mail); ASSERT_EQ(1U, settings_map1_ret.size()); SettingsMap::const_iterator it1_ret = settings_map1_ret.find(id1); EXPECT_TRUE(it1_ret != settings_map1_ret.end()); SettingsFlagsAndValue flags_and_value1_ret = it1_ret->second; EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1_ret.first); EXPECT_EQ(value1, flags_and_value1_ret.second); // Clear SpdySetting for mail.google.com:443. http_server_props_manager_->ClearSpdySettings(spdy_server_mail); // Run the task. base::RunLoop().RunUntilIdle(); // Verify that there are no entries in the settings map for // mail.google.com:443. const SettingsMap& settings_map2_ret = http_server_props_manager_->GetSpdySettings(spdy_server_mail); ASSERT_EQ(0U, settings_map2_ret.size()); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); } TEST_P(HttpServerPropertiesManagerTest, ClearAllSpdySetting) { ExpectPrefsUpdateRepeatedly(); ExpectScheduleUpdatePrefsOnNetworkThreadRepeatedly(); // Add SpdySetting for mail.google.com:443. HostPortPair spdy_server_mail("mail.google.com", 443); const SpdySettingsIds id1 = SETTINGS_UPLOAD_BANDWIDTH; const SpdySettingsFlags flags1 = SETTINGS_FLAG_PLEASE_PERSIST; const uint32_t value1 = 31337; http_server_props_manager_->SetSpdySetting( spdy_server_mail, id1, flags1, value1); // Run the task. base::RunLoop().RunUntilIdle(); const SettingsMap& settings_map1_ret = http_server_props_manager_->GetSpdySettings(spdy_server_mail); ASSERT_EQ(1U, settings_map1_ret.size()); SettingsMap::const_iterator it1_ret = settings_map1_ret.find(id1); EXPECT_TRUE(it1_ret != settings_map1_ret.end()); SettingsFlagsAndValue flags_and_value1_ret = it1_ret->second; EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1_ret.first); EXPECT_EQ(value1, flags_and_value1_ret.second); // Clear All SpdySettings. http_server_props_manager_->ClearAllSpdySettings(); // Run the task. base::RunLoop().RunUntilIdle(); // Verify that there are no entries in the settings map. const SpdySettingsMap& spdy_settings_map2_ret = http_server_props_manager_->spdy_settings_map(); ASSERT_EQ(0U, spdy_settings_map2_ret.size()); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); } TEST_P(HttpServerPropertiesManagerTest, GetAlternativeServices) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); HostPortPair spdy_server_mail("mail.google.com", 80); EXPECT_FALSE(HasAlternativeService(spdy_server_mail)); const AlternativeService alternative_service(NPN_HTTP_2, "mail.google.com", 443); http_server_props_manager_->SetAlternativeService( spdy_server_mail, alternative_service, 1.0, one_day_from_now_); // ExpectScheduleUpdatePrefsOnNetworkThread() should be called only once. http_server_props_manager_->SetAlternativeService( spdy_server_mail, alternative_service, 1.0, one_day_from_now_); // Run the task. base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); AlternativeServiceVector alternative_service_vector = http_server_props_manager_->GetAlternativeServices(spdy_server_mail); ASSERT_EQ(1u, alternative_service_vector.size()); EXPECT_EQ(alternative_service, alternative_service_vector[0]); } TEST_P(HttpServerPropertiesManagerTest, SetAlternativeServices) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); HostPortPair spdy_server_mail("mail.google.com", 80); EXPECT_FALSE(HasAlternativeService(spdy_server_mail)); AlternativeServiceInfoVector alternative_service_info_vector; const AlternativeService alternative_service1(NPN_HTTP_2, "mail.google.com", 443); alternative_service_info_vector.push_back( AlternativeServiceInfo(alternative_service1, 1.0, one_day_from_now_)); const AlternativeService alternative_service2(QUIC, "mail.google.com", 1234); alternative_service_info_vector.push_back( AlternativeServiceInfo(alternative_service2, 1.0, one_day_from_now_)); http_server_props_manager_->SetAlternativeServices( spdy_server_mail, alternative_service_info_vector); // ExpectScheduleUpdatePrefsOnNetworkThread() should be called only once. http_server_props_manager_->SetAlternativeServices( spdy_server_mail, alternative_service_info_vector); // Run the task. base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); AlternativeServiceVector alternative_service_vector = http_server_props_manager_->GetAlternativeServices(spdy_server_mail); ASSERT_EQ(2u, alternative_service_vector.size()); EXPECT_EQ(alternative_service1, alternative_service_vector[0]); EXPECT_EQ(alternative_service2, alternative_service_vector[1]); } TEST_P(HttpServerPropertiesManagerTest, SetAlternativeServicesEmpty) { HostPortPair spdy_server_mail("mail.google.com", 80); EXPECT_FALSE(HasAlternativeService(spdy_server_mail)); const AlternativeService alternative_service(NPN_HTTP_2, "mail.google.com", 443); http_server_props_manager_->SetAlternativeServices( spdy_server_mail, AlternativeServiceInfoVector()); // ExpectScheduleUpdatePrefsOnNetworkThread() should not be called. // Run the task. base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); EXPECT_FALSE(HasAlternativeService(spdy_server_mail)); } TEST_P(HttpServerPropertiesManagerTest, ClearAlternativeServices) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); HostPortPair spdy_server_mail("mail.google.com", 80); EXPECT_FALSE(HasAlternativeService(spdy_server_mail)); AlternativeService alternative_service(NPN_HTTP_2, "mail.google.com", 443); http_server_props_manager_->SetAlternativeService( spdy_server_mail, alternative_service, 1.0, one_day_from_now_); ExpectScheduleUpdatePrefsOnNetworkThread(); http_server_props_manager_->ClearAlternativeServices(spdy_server_mail); // ExpectScheduleUpdatePrefsOnNetworkThread() should be called only once. http_server_props_manager_->ClearAlternativeServices(spdy_server_mail); // Run the task. base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); EXPECT_FALSE(HasAlternativeService(spdy_server_mail)); } TEST_P(HttpServerPropertiesManagerTest, ConfirmAlternativeService) { ExpectPrefsUpdate(); HostPortPair spdy_server_mail("mail.google.com", 80); EXPECT_FALSE(HasAlternativeService(spdy_server_mail)); AlternativeService alternative_service(NPN_HTTP_2, "mail.google.com", 443); ExpectScheduleUpdatePrefsOnNetworkThread(); http_server_props_manager_->SetAlternativeService( spdy_server_mail, alternative_service, 1.0, one_day_from_now_); EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken( alternative_service)); EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken( alternative_service)); ExpectScheduleUpdatePrefsOnNetworkThread(); http_server_props_manager_->MarkAlternativeServiceBroken(alternative_service); EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken( alternative_service)); EXPECT_TRUE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken( alternative_service)); ExpectScheduleUpdatePrefsOnNetworkThread(); http_server_props_manager_->ConfirmAlternativeService(alternative_service); EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken( alternative_service)); EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken( alternative_service)); // ExpectScheduleUpdatePrefsOnNetworkThread() should be called only once. http_server_props_manager_->ConfirmAlternativeService(alternative_service); EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken( alternative_service)); EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken( alternative_service)); // Run the task. base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken( alternative_service)); EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken( alternative_service)); } TEST_P(HttpServerPropertiesManagerTest, SupportsQuic) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); IPAddress address; EXPECT_FALSE(http_server_props_manager_->GetSupportsQuic(&address)); IPAddress actual_address(127, 0, 0, 1); http_server_props_manager_->SetSupportsQuic(true, actual_address); // ExpectScheduleUpdatePrefsOnNetworkThread() should be called only once. http_server_props_manager_->SetSupportsQuic(true, actual_address); // Run the task. base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); EXPECT_TRUE(http_server_props_manager_->GetSupportsQuic(&address)); EXPECT_EQ(actual_address, address); } TEST_P(HttpServerPropertiesManagerTest, ServerNetworkStats) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); HostPortPair mail_server("mail.google.com", 80); const ServerNetworkStats* stats = http_server_props_manager_->GetServerNetworkStats(mail_server); EXPECT_EQ(nullptr, stats); ServerNetworkStats stats1; stats1.srtt = base::TimeDelta::FromMicroseconds(10); http_server_props_manager_->SetServerNetworkStats(mail_server, stats1); // ExpectScheduleUpdatePrefsOnNetworkThread() should be called only once. http_server_props_manager_->SetServerNetworkStats(mail_server, stats1); // Run the task. base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); const ServerNetworkStats* stats2 = http_server_props_manager_->GetServerNetworkStats(mail_server); EXPECT_EQ(10, stats2->srtt.ToInternalValue()); } TEST_P(HttpServerPropertiesManagerTest, QuicServerInfo) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThread(); QuicServerId mail_quic_server_id("mail.google.com", 80); EXPECT_EQ(nullptr, http_server_props_manager_->GetQuicServerInfo(mail_quic_server_id)); std::string quic_server_info1("quic_server_info1"); http_server_props_manager_->SetQuicServerInfo(mail_quic_server_id, quic_server_info1); // ExpectScheduleUpdatePrefsOnNetworkThread() should be called only once. http_server_props_manager_->SetQuicServerInfo(mail_quic_server_id, quic_server_info1); // Run the task. base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); EXPECT_EQ(quic_server_info1, *http_server_props_manager_->GetQuicServerInfo( mail_quic_server_id)); } TEST_P(HttpServerPropertiesManagerTest, Clear) { ExpectPrefsUpdate(); ExpectScheduleUpdatePrefsOnNetworkThreadRepeatedly(); HostPortPair spdy_server_mail("mail.google.com", 443); http_server_props_manager_->SetSupportsSpdy(spdy_server_mail, true); AlternativeService alternative_service(NPN_HTTP_2, "mail.google.com", 1234); http_server_props_manager_->SetAlternativeService( spdy_server_mail, alternative_service, 1.0, one_day_from_now_); IPAddress actual_address(127, 0, 0, 1); http_server_props_manager_->SetSupportsQuic(true, actual_address); ServerNetworkStats stats; stats.srtt = base::TimeDelta::FromMicroseconds(10); http_server_props_manager_->SetServerNetworkStats(spdy_server_mail, stats); QuicServerId mail_quic_server_id("mail.google.com", 80); std::string quic_server_info1("quic_server_info1"); http_server_props_manager_->SetQuicServerInfo(mail_quic_server_id, quic_server_info1); const SpdySettingsIds id1 = SETTINGS_UPLOAD_BANDWIDTH; const SpdySettingsFlags flags1 = SETTINGS_FLAG_PLEASE_PERSIST; const uint32_t value1 = 31337; http_server_props_manager_->SetSpdySetting(spdy_server_mail, id1, flags1, value1); // Run the task. base::RunLoop().RunUntilIdle(); EXPECT_TRUE( http_server_props_manager_->SupportsRequestPriority(spdy_server_mail)); EXPECT_TRUE(HasAlternativeService(spdy_server_mail)); IPAddress address; EXPECT_TRUE(http_server_props_manager_->GetSupportsQuic(&address)); EXPECT_EQ(actual_address, address); const ServerNetworkStats* stats1 = http_server_props_manager_->GetServerNetworkStats(spdy_server_mail); EXPECT_EQ(10, stats1->srtt.ToInternalValue()); EXPECT_EQ(quic_server_info1, *http_server_props_manager_->GetQuicServerInfo( mail_quic_server_id)); // Check SPDY settings values. const SettingsMap& settings_map1_ret = http_server_props_manager_->GetSpdySettings(spdy_server_mail); ASSERT_EQ(1U, settings_map1_ret.size()); SettingsMap::const_iterator it1_ret = settings_map1_ret.find(id1); EXPECT_TRUE(it1_ret != settings_map1_ret.end()); SettingsFlagsAndValue flags_and_value1_ret = it1_ret->second; EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1_ret.first); EXPECT_EQ(value1, flags_and_value1_ret.second); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); ExpectPrefsUpdate(); // Clear http server data, time out if we do not get a completion callback. http_server_props_manager_->Clear(base::MessageLoop::QuitWhenIdleClosure()); base::RunLoop().Run(); EXPECT_FALSE( http_server_props_manager_->SupportsRequestPriority(spdy_server_mail)); EXPECT_FALSE(HasAlternativeService(spdy_server_mail)); EXPECT_FALSE(http_server_props_manager_->GetSupportsQuic(&address)); const ServerNetworkStats* stats2 = http_server_props_manager_->GetServerNetworkStats(spdy_server_mail); EXPECT_EQ(nullptr, stats2); EXPECT_EQ(nullptr, http_server_props_manager_->GetQuicServerInfo(mail_quic_server_id)); const SettingsMap& settings_map2_ret = http_server_props_manager_->GetSpdySettings(spdy_server_mail); EXPECT_EQ(0U, settings_map2_ret.size()); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); } // https://crbug.com/444956: Add 200 alternative_service servers followed by // supports_quic and verify we have read supports_quic from prefs. TEST_P(HttpServerPropertiesManagerTest, BadSupportsQuic) { ExpectCacheUpdate(); base::DictionaryValue* servers_dict = new base::DictionaryValue; base::ListValue* servers_list = nullptr; if (GetParam() == 4) servers_list = new base::ListValue; for (int i = 0; i < 200; ++i) { // Set up alternative_service for www.google.com:i. base::DictionaryValue* alternative_service_dict = new base::DictionaryValue; alternative_service_dict->SetString("protocol_str", "quic"); alternative_service_dict->SetInteger("port", i); base::ListValue* alternative_service_list = new base::ListValue; alternative_service_list->Append(alternative_service_dict); base::DictionaryValue* server_pref_dict = new base::DictionaryValue; server_pref_dict->SetWithoutPathExpansion("alternative_service", alternative_service_list); if (GetParam() == 4) { servers_dict->SetWithoutPathExpansion( StringPrintf("www.google.com:%d", i), server_pref_dict); // |servers_list| takes ownership of |servers_dict|. servers_list->AppendIfNotPresent(servers_dict); servers_dict = new base::DictionaryValue; } else { servers_dict->SetWithoutPathExpansion( StringPrintf("www.google.com:%d", i), server_pref_dict); } } // Set the preference for mail.google.com server. base::DictionaryValue* server_pref_dict1 = new base::DictionaryValue; // Set the server preference for mail.google.com:80. servers_dict->SetWithoutPathExpansion("mail.google.com:80", server_pref_dict1); base::DictionaryValue http_server_properties_dict; if (GetParam() == 4) { // |servers_list| takes ownership of |servers_dict|. servers_list->AppendIfNotPresent(servers_dict); HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, -1); http_server_properties_dict.SetWithoutPathExpansion("servers", servers_list); } else { HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, GetParam()); http_server_properties_dict.SetWithoutPathExpansion("servers", servers_dict); } // Set up SupportsQuic for 127.0.0.1 base::DictionaryValue* supports_quic = new base::DictionaryValue; supports_quic->SetBoolean("used_quic", true); supports_quic->SetString("address", "127.0.0.1"); http_server_properties_dict.SetWithoutPathExpansion("supports_quic", supports_quic); // Set up the pref. pref_delegate_->SetPrefs(http_server_properties_dict); base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); // Verify alternative service. for (int i = 0; i < 200; ++i) { std::string server = StringPrintf("www.google.com:%d", i); AlternativeServiceVector alternative_service_vector = http_server_props_manager_->GetAlternativeServices( HostPortPair::FromString(server)); ASSERT_EQ(1u, alternative_service_vector.size()); EXPECT_EQ(QUIC, alternative_service_vector[0].protocol); EXPECT_EQ(i, alternative_service_vector[0].port); } // Verify SupportsQuic. IPAddress address; ASSERT_TRUE(http_server_props_manager_->GetSupportsQuic(&address)); EXPECT_EQ("127.0.0.1", address.ToString()); } TEST_P(HttpServerPropertiesManagerTest, UpdateCacheWithPrefs) { ExpectScheduleUpdatePrefsOnNetworkThreadRepeatedly(); const HostPortPair server_www("www.google.com", 80); const HostPortPair server_mail("mail.google.com", 80); // Set alternate protocol. AlternativeServiceInfoVector alternative_service_info_vector; AlternativeService www_alternative_service1(NPN_HTTP_2, "", 443); base::Time expiration1; ASSERT_TRUE(base::Time::FromUTCString("2036-12-01 10:00:00", &expiration1)); alternative_service_info_vector.push_back( AlternativeServiceInfo(www_alternative_service1, 1.0, expiration1)); AlternativeService www_alternative_service2(NPN_HTTP_2, "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(www_alternative_service2, 0.7, expiration2)); http_server_props_manager_->SetAlternativeServices( server_www, alternative_service_info_vector); AlternativeService mail_alternative_service(NPN_SPDY_3_1, "foo.google.com", 444); base::Time expiration3 = base::Time::Max(); http_server_props_manager_->SetAlternativeService( server_mail, mail_alternative_service, 0.2, expiration3); // Set ServerNetworkStats. ServerNetworkStats stats; stats.srtt = base::TimeDelta::FromInternalValue(42); http_server_props_manager_->SetServerNetworkStats(server_mail, stats); // Set quic_server_info string. QuicServerId mail_quic_server_id("mail.google.com", 80); std::string quic_server_info1("quic_server_info1"); http_server_props_manager_->SetQuicServerInfo(mail_quic_server_id, quic_server_info1); // Set SupportsQuic. IPAddress actual_address(127, 0, 0, 1); http_server_props_manager_->SetSupportsQuic(true, actual_address); // Update cache. ExpectPrefsUpdate(); ExpectCacheUpdate(); http_server_props_manager_->ScheduleUpdateCacheOnPrefThread(); base::RunLoop().RunUntilIdle(); // Verify preferences. const char expected_json[] = "{\"quic_servers\":{\"https://" "mail.google.com:80\":{\"server_info\":\"quic_server_info1\"}}," "\"servers\":[" "{\"www.google.com:80\":{" "\"alternative_service\":[{\"expiration\":\"13756212000000000\"," "\"port\":443,\"probability\":1.0,\"protocol_str\":\"npn-h2\"}," "{\"expiration\":\"13758804000000000\",\"host\":\"www.google.com\"," "\"port\":1234,\"probability\":0.7,\"protocol_str\":\"npn-h2\"}]}}," "{\"mail.google.com:80\":{\"alternative_service\":[{" "\"expiration\":\"9223372036854775807\",\"host\":\"foo.google.com\"," "\"port\":444,\"probability\":0.2,\"protocol_str\":\"npn-spdy/3.1\"}]," "\"network_stats\":{\"srtt\":42}}}" "]," "\"supports_quic\":{\"address\":\"127.0.0.1\",\"used_quic\":true}," "\"version\":4}"; const base::Value* 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_P(HttpServerPropertiesManagerTest, AddToAlternativeServiceMap) { scoped_ptr server_value = base::JSONReader::Read( "{\"alternative_service\":[{\"port\":443,\"protocol_str\":\"npn-h2\"}," "{\"port\":123,\"protocol_str\":\"quic\",\"probability\":0.7," "\"expiration\":\"9223372036854775807\"},{\"host\":\"example.org\"," "\"port\":1234,\"protocol_str\":\"npn-h2\",\"probability\":0.2," "\"expiration\":\"13758804000000000\"}]}"); ASSERT_TRUE(server_value); base::DictionaryValue* server_dict; ASSERT_TRUE(server_value->GetAsDictionary(&server_dict)); const HostPortPair host_port_pair("example.com", 443); AlternativeServiceMap alternative_service_map(/*max_size=*/5); EXPECT_TRUE(http_server_props_manager_->AddToAlternativeServiceMap( host_port_pair, *server_dict, &alternative_service_map)); AlternativeServiceMap::iterator it = alternative_service_map.Get(host_port_pair); ASSERT_NE(alternative_service_map.end(), it); AlternativeServiceInfoVector alternative_service_info_vector = it->second; ASSERT_EQ(3u, alternative_service_info_vector.size()); EXPECT_EQ(NPN_HTTP_2, 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); // Probability defaults to 1.0. EXPECT_DOUBLE_EQ(1.0, alternative_service_info_vector[0].probability); // 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::TimeDelta::FromHours(23), expiration); EXPECT_GE(now + base::TimeDelta::FromDays(1), expiration); EXPECT_EQ(QUIC, 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_DOUBLE_EQ(0.7, alternative_service_info_vector[1].probability); // numeric_limits::max() represents base::Time::Max(). EXPECT_EQ(base::Time::Max(), alternative_service_info_vector[1].expiration); EXPECT_EQ(NPN_HTTP_2, 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); EXPECT_DOUBLE_EQ(0.2, alternative_service_info_vector[2].probability); 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); } // Do not persist expired or broken alternative service entries to disk. TEST_P(HttpServerPropertiesManagerTest, DoNotPersistExpiredOrBrokenAlternativeService) { ExpectScheduleUpdatePrefsOnNetworkThreadRepeatedly(); AlternativeServiceInfoVector alternative_service_info_vector; const AlternativeService broken_alternative_service( NPN_HTTP_2, "broken.example.com", 443); const base::Time time_one_day_later = base::Time::Now() + base::TimeDelta::FromDays(1); alternative_service_info_vector.push_back(AlternativeServiceInfo( broken_alternative_service, 1.0, time_one_day_later)); http_server_props_manager_->MarkAlternativeServiceBroken( broken_alternative_service); const AlternativeService expired_alternative_service( NPN_HTTP_2, "expired.example.com", 443); const base::Time time_one_day_ago = base::Time::Now() - base::TimeDelta::FromDays(1); alternative_service_info_vector.push_back(AlternativeServiceInfo( expired_alternative_service, 1.0, time_one_day_ago)); const AlternativeService valid_alternative_service(NPN_HTTP_2, "valid.example.com", 443); alternative_service_info_vector.push_back(AlternativeServiceInfo( valid_alternative_service, 1.0, time_one_day_later)); const HostPortPair host_port_pair("www.example.com", 443); http_server_props_manager_->SetAlternativeServices( host_port_pair, alternative_service_info_vector); // Update cache. ExpectPrefsUpdate(); ExpectCacheUpdate(); http_server_props_manager_->ScheduleUpdateCacheOnPrefThread(); base::RunLoop().RunUntilIdle(); const base::DictionaryValue& pref_dict = pref_delegate_->GetServerProperties(); const base::ListValue* servers_list = nullptr; ASSERT_TRUE(pref_dict.GetListWithoutPathExpansion("servers", &servers_list)); base::ListValue::const_iterator it = servers_list->begin(); const base::DictionaryValue* server_pref_dict; ASSERT_TRUE((*it)->GetAsDictionary(&server_pref_dict)); const base::DictionaryValue* example_pref_dict; ASSERT_TRUE(server_pref_dict->GetDictionaryWithoutPathExpansion( "www.example.com:443", &example_pref_dict)); const base::ListValue* altsvc_list; ASSERT_TRUE(example_pref_dict->GetList("alternative_service", &altsvc_list)); ASSERT_EQ(1u, altsvc_list->GetSize()); const base::DictionaryValue* altsvc_entry; ASSERT_TRUE(altsvc_list->GetDictionary(0, &altsvc_entry)); std::string hostname; ASSERT_TRUE(altsvc_entry->GetString("host", &hostname)); EXPECT_EQ("valid.example.com", hostname); } // Test that expired alternative service entries on disk are ignored. TEST_P(HttpServerPropertiesManagerTest, DoNotLoadExpiredAlternativeService) { scoped_ptr alternative_service_list(new base::ListValue); base::DictionaryValue* expired_dict = new base::DictionaryValue; expired_dict->SetString("protocol_str", "npn-h2"); expired_dict->SetString("host", "expired.example.com"); expired_dict->SetInteger("port", 443); expired_dict->SetDouble("probability", 1.0); base::Time time_one_day_ago = base::Time::Now() - base::TimeDelta::FromDays(1); expired_dict->SetString( "expiration", base::Int64ToString(time_one_day_ago.ToInternalValue())); alternative_service_list->Append(expired_dict); base::DictionaryValue* valid_dict = new base::DictionaryValue; valid_dict->SetString("protocol_str", "npn-h2"); valid_dict->SetString("host", "valid.example.com"); valid_dict->SetInteger("port", 443); valid_dict->SetDouble("probability", 1.0); valid_dict->SetString( "expiration", base::Int64ToString(one_day_from_now_.ToInternalValue())); alternative_service_list->Append(valid_dict); base::DictionaryValue server_pref_dict; server_pref_dict.SetWithoutPathExpansion("alternative_service", alternative_service_list.release()); const HostPortPair host_port_pair("example.com", 443); AlternativeServiceMap alternative_service_map(/*max_size=*/5); ASSERT_TRUE(http_server_props_manager_->AddToAlternativeServiceMap( host_port_pair, server_pref_dict, &alternative_service_map)); AlternativeServiceMap::iterator it = alternative_service_map.Get(host_port_pair); ASSERT_NE(alternative_service_map.end(), it); AlternativeServiceInfoVector alternative_service_info_vector = it->second; ASSERT_EQ(1u, alternative_service_info_vector.size()); EXPECT_EQ(NPN_HTTP_2, 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_DOUBLE_EQ(1.0, alternative_service_info_vector[0].probability); EXPECT_EQ(one_day_from_now_, alternative_service_info_vector[0].expiration); } TEST_P(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache0) { // Post an update task to the UI thread. http_server_props_manager_->ScheduleUpdateCacheOnPrefThread(); // Shutdown comes before the task is executed. http_server_props_manager_->ShutdownOnPrefThread(); http_server_props_manager_.reset(); // Run the task after shutdown and deletion. base::RunLoop().RunUntilIdle(); } TEST_P(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache1) { // Post an update task. http_server_props_manager_->ScheduleUpdateCacheOnPrefThread(); // Shutdown comes before the task is executed. http_server_props_manager_->ShutdownOnPrefThread(); // Run the task after shutdown, but before deletion. base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); http_server_props_manager_.reset(); base::RunLoop().RunUntilIdle(); } TEST_P(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache2) { http_server_props_manager_->UpdateCacheFromPrefsOnUIConcrete(); // Shutdown comes before the task is executed. http_server_props_manager_->ShutdownOnPrefThread(); // Run the task after shutdown, but before deletion. base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); http_server_props_manager_.reset(); base::RunLoop().RunUntilIdle(); } // // Tests for shutdown when updating prefs. // TEST_P(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs0) { // Post an update task to the IO thread. http_server_props_manager_->ScheduleUpdatePrefsOnNetworkThread(); // Shutdown comes before the task is executed. http_server_props_manager_->ShutdownOnPrefThread(); http_server_props_manager_.reset(); // Run the task after shutdown and deletion. base::RunLoop().RunUntilIdle(); } TEST_P(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs1) { ExpectPrefsUpdate(); // Post an update task. http_server_props_manager_->ScheduleUpdatePrefsOnNetworkThread(); // Shutdown comes before the task is executed. http_server_props_manager_->ShutdownOnPrefThread(); // Run the task after shutdown, but before deletion. base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); http_server_props_manager_.reset(); base::RunLoop().RunUntilIdle(); } TEST_P(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs2) { // This posts a task to the UI thread. http_server_props_manager_->UpdatePrefsFromCacheOnNetworkThreadConcrete( base::Closure()); // Shutdown comes before the task is executed. http_server_props_manager_->ShutdownOnPrefThread(); // Run the task after shutdown, but before deletion. base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(http_server_props_manager_.get()); http_server_props_manager_.reset(); base::RunLoop().RunUntilIdle(); } } // namespace net