| // Copyright 2012 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.h" |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/check.h" |
| #include "base/feature_list.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/json/json_writer.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/run_loop.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/simple_test_clock.h" |
| #include "base/test/task_environment.h" |
| #include "base/time/time.h" |
| #include "base/values.h" |
| #include "net/base/features.h" |
| #include "net/base/host_port_pair.h" |
| #include "net/base/ip_address.h" |
| #include "net/base/schemeful_site.h" |
| #include "net/http/http_network_session.h" |
| #include "net/test/test_with_task_environment.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| namespace net { |
| |
| const base::TimeDelta BROKEN_ALT_SVC_EXPIRE_DELAYS[10] = { |
| base::Seconds(300), base::Seconds(600), base::Seconds(1200), |
| base::Seconds(2400), base::Seconds(4800), base::Seconds(9600), |
| base::Seconds(19200), base::Seconds(38400), base::Seconds(76800), |
| base::Seconds(153600), |
| }; |
| |
| class HttpServerPropertiesPeer { |
| public: |
| static void AddBrokenAlternativeServiceWithExpirationTime( |
| HttpServerProperties* impl, |
| const AlternativeService& alternative_service, |
| base::TimeTicks when, |
| const NetworkAnonymizationKey network_anonymization_key = |
| NetworkAnonymizationKey()) { |
| BrokenAlternativeService broken_alternative_service( |
| alternative_service, network_anonymization_key, |
| true /* use_network_anonymization_key */); |
| BrokenAlternativeServiceList::iterator unused_it; |
| impl->broken_alternative_services_.AddToBrokenListAndMap( |
| broken_alternative_service, when, &unused_it); |
| auto it = |
| impl->broken_alternative_services_.recently_broken_alternative_services_ |
| .Get(broken_alternative_service); |
| if (it == impl->broken_alternative_services_ |
| .recently_broken_alternative_services_.end()) { |
| impl->broken_alternative_services_.recently_broken_alternative_services_ |
| .Put(broken_alternative_service, 1); |
| } else { |
| it->second++; |
| } |
| } |
| |
| static void ExpireBrokenAlternateProtocolMappings( |
| HttpServerProperties* impl) { |
| impl->broken_alternative_services_.ExpireBrokenAlternateProtocolMappings(); |
| } |
| }; |
| |
| namespace { |
| |
| // Creates a ServerInfoMapKey without a NetworkAnonymizationKey. |
| HttpServerProperties::ServerInfoMapKey CreateSimpleKey( |
| const url::SchemeHostPort& server) { |
| return HttpServerProperties::ServerInfoMapKey( |
| server, net::NetworkAnonymizationKey(), |
| false /* use_network_anonymization_key */); |
| } |
| |
| class HttpServerPropertiesTest : public TestWithTaskEnvironment { |
| protected: |
| HttpServerPropertiesTest() |
| : TestWithTaskEnvironment( |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME), |
| // Many tests assume partitioning is disabled by default. |
| feature_list_(CreateFeatureListWithPartitioningDisabled()), |
| test_tick_clock_(GetMockTickClock()), |
| impl_(nullptr /* pref_delegate */, |
| nullptr /* net_log */, |
| test_tick_clock_, |
| &test_clock_) { |
| // Set |test_clock_| to some random time. |
| test_clock_.Advance(base::Seconds(12345)); |
| |
| SchemefulSite site1(GURL("https://foo.test/")); |
| network_anonymization_key1_ = |
| NetworkAnonymizationKey::CreateSameSite(site1); |
| SchemefulSite site2(GURL("https://bar.test/")); |
| network_anonymization_key2_ = |
| NetworkAnonymizationKey::CreateSameSite(site2); |
| } |
| |
| // This is a little awkward, but need to create and configure the |
| // ScopedFeatureList before creating the HttpServerProperties. |
| static std::unique_ptr<base::test::ScopedFeatureList> |
| CreateFeatureListWithPartitioningDisabled() { |
| std::unique_ptr<base::test::ScopedFeatureList> feature_list = |
| std::make_unique<base::test::ScopedFeatureList>(); |
| feature_list->InitAndDisableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| return feature_list; |
| } |
| |
| bool HasAlternativeService( |
| const url::SchemeHostPort& origin, |
| const NetworkAnonymizationKey& network_anonymization_key) { |
| const AlternativeServiceInfoVector alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(origin, network_anonymization_key); |
| return !alternative_service_info_vector.empty(); |
| } |
| |
| void SetAlternativeService(const url::SchemeHostPort& origin, |
| const AlternativeService& alternative_service) { |
| const base::Time expiration = test_clock_.Now() + base::Days(1); |
| if (alternative_service.protocol == kProtoQUIC) { |
| impl_.SetQuicAlternativeService(origin, NetworkAnonymizationKey(), |
| alternative_service, expiration, |
| DefaultSupportedQuicVersions()); |
| } else { |
| impl_.SetHttp2AlternativeService(origin, NetworkAnonymizationKey(), |
| alternative_service, expiration); |
| } |
| } |
| |
| void MarkBrokenAndLetExpireAlternativeServiceNTimes( |
| const AlternativeService& alternative_service, |
| int num_times) {} |
| |
| std::unique_ptr<base::test::ScopedFeatureList> feature_list_; |
| |
| raw_ptr<const base::TickClock> test_tick_clock_; |
| base::SimpleTestClock test_clock_; |
| |
| // Two different non-empty network isolation keys for use in tests that need |
| // them. |
| NetworkAnonymizationKey network_anonymization_key1_; |
| NetworkAnonymizationKey network_anonymization_key2_; |
| |
| HttpServerProperties impl_; |
| }; |
| |
| TEST_F(HttpServerPropertiesTest, SetSupportsSpdy) { |
| // Check spdy servers are correctly set with SchemeHostPort key. |
| url::SchemeHostPort https_www_server("https", "www.google.com", 443); |
| url::SchemeHostPort http_photo_server("http", "photos.google.com", 80); |
| url::SchemeHostPort https_mail_server("https", "mail.google.com", 443); |
| // Servers with port equal to default port in scheme will drop port components |
| // when calling Serialize(). |
| |
| url::SchemeHostPort http_google_server("http", "www.google.com", 443); |
| url::SchemeHostPort https_photos_server("https", "photos.google.com", 443); |
| url::SchemeHostPort valid_google_server((GURL("https://www.google.com"))); |
| |
| impl_.SetSupportsSpdy(https_www_server, NetworkAnonymizationKey(), true); |
| impl_.SetSupportsSpdy(http_photo_server, NetworkAnonymizationKey(), true); |
| impl_.SetSupportsSpdy(https_mail_server, NetworkAnonymizationKey(), false); |
| EXPECT_TRUE( |
| impl_.GetSupportsSpdy(https_www_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.SupportsRequestPriority(https_www_server, |
| NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| impl_.GetSupportsSpdy(http_photo_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.SupportsRequestPriority(http_photo_server, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| impl_.GetSupportsSpdy(https_mail_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.SupportsRequestPriority(https_mail_server, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| impl_.GetSupportsSpdy(http_google_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.SupportsRequestPriority(http_google_server, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| impl_.GetSupportsSpdy(https_photos_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.SupportsRequestPriority(https_photos_server, |
| NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| impl_.GetSupportsSpdy(valid_google_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.SupportsRequestPriority(valid_google_server, |
| NetworkAnonymizationKey())); |
| |
| // Flip values of two servers. |
| impl_.SetSupportsSpdy(https_www_server, NetworkAnonymizationKey(), false); |
| impl_.SetSupportsSpdy(https_mail_server, NetworkAnonymizationKey(), true); |
| EXPECT_FALSE( |
| impl_.GetSupportsSpdy(https_www_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.SupportsRequestPriority(https_www_server, |
| NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| impl_.GetSupportsSpdy(https_mail_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.SupportsRequestPriority(https_mail_server, |
| NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesTest, SetSupportsSpdyWebSockets) { |
| // The https and wss servers should be treated as the same server, as should |
| // the http and ws servers. |
| url::SchemeHostPort https_server("https", "www.test.com", 443); |
| url::SchemeHostPort wss_server("wss", "www.test.com", 443); |
| url::SchemeHostPort http_server("http", "www.test.com", 443); |
| url::SchemeHostPort ws_server("ws", "www.test.com", 443); |
| |
| EXPECT_FALSE(impl_.GetSupportsSpdy(https_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.GetSupportsSpdy(wss_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.GetSupportsSpdy(http_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.GetSupportsSpdy(ws_server, NetworkAnonymizationKey())); |
| |
| impl_.SetSupportsSpdy(wss_server, NetworkAnonymizationKey(), true); |
| EXPECT_TRUE(impl_.GetSupportsSpdy(https_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.GetSupportsSpdy(wss_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.GetSupportsSpdy(http_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.GetSupportsSpdy(ws_server, NetworkAnonymizationKey())); |
| |
| impl_.SetSupportsSpdy(http_server, NetworkAnonymizationKey(), true); |
| EXPECT_TRUE(impl_.GetSupportsSpdy(https_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.GetSupportsSpdy(wss_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.GetSupportsSpdy(http_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.GetSupportsSpdy(ws_server, NetworkAnonymizationKey())); |
| |
| impl_.SetSupportsSpdy(https_server, NetworkAnonymizationKey(), false); |
| EXPECT_FALSE(impl_.GetSupportsSpdy(https_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.GetSupportsSpdy(wss_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.GetSupportsSpdy(http_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.GetSupportsSpdy(ws_server, NetworkAnonymizationKey())); |
| |
| impl_.SetSupportsSpdy(ws_server, NetworkAnonymizationKey(), false); |
| EXPECT_FALSE(impl_.GetSupportsSpdy(https_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.GetSupportsSpdy(wss_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.GetSupportsSpdy(http_server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.GetSupportsSpdy(ws_server, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesTest, SetSupportsSpdyWithNetworkIsolationKey) { |
| const url::SchemeHostPort kServer("https", "foo.test", 443); |
| |
| EXPECT_FALSE(impl_.GetSupportsSpdy(kServer, network_anonymization_key1_)); |
| EXPECT_FALSE( |
| impl_.SupportsRequestPriority(kServer, network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.GetSupportsSpdy(kServer, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| impl_.SupportsRequestPriority(kServer, NetworkAnonymizationKey())); |
| |
| // Without network isolation keys enabled for HttpServerProperties, passing in |
| // a NetworkAnonymizationKey should have no effect on behavior. |
| for (const auto& network_anonymization_key_to_set : |
| {NetworkAnonymizationKey(), network_anonymization_key1_}) { |
| impl_.SetSupportsSpdy(kServer, network_anonymization_key_to_set, true); |
| EXPECT_TRUE(impl_.GetSupportsSpdy(kServer, network_anonymization_key1_)); |
| EXPECT_TRUE( |
| impl_.SupportsRequestPriority(kServer, network_anonymization_key1_)); |
| EXPECT_TRUE(impl_.GetSupportsSpdy(kServer, NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| impl_.SupportsRequestPriority(kServer, NetworkAnonymizationKey())); |
| |
| impl_.SetSupportsSpdy(kServer, network_anonymization_key_to_set, false); |
| EXPECT_FALSE(impl_.GetSupportsSpdy(kServer, network_anonymization_key1_)); |
| EXPECT_FALSE( |
| impl_.SupportsRequestPriority(kServer, network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.GetSupportsSpdy(kServer, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| impl_.SupportsRequestPriority(kServer, NetworkAnonymizationKey())); |
| } |
| |
| // With network isolation keys enabled for HttpServerProperties, the |
| // NetworkAnonymizationKey argument should be respected. |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| // Since HttpServerProperties caches the feature value, have to create a new |
| // one. |
| HttpServerProperties properties(nullptr /* pref_delegate */, |
| nullptr /* net_log */, test_tick_clock_, |
| &test_clock_); |
| |
| EXPECT_FALSE( |
| properties.GetSupportsSpdy(kServer, network_anonymization_key1_)); |
| EXPECT_FALSE( |
| properties.SupportsRequestPriority(kServer, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.GetSupportsSpdy(kServer, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties.SupportsRequestPriority(kServer, NetworkAnonymizationKey())); |
| |
| properties.SetSupportsSpdy(kServer, network_anonymization_key1_, true); |
| EXPECT_TRUE(properties.GetSupportsSpdy(kServer, network_anonymization_key1_)); |
| EXPECT_TRUE( |
| properties.SupportsRequestPriority(kServer, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.GetSupportsSpdy(kServer, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties.SupportsRequestPriority(kServer, NetworkAnonymizationKey())); |
| |
| properties.SetSupportsSpdy(kServer, NetworkAnonymizationKey(), true); |
| EXPECT_TRUE(properties.GetSupportsSpdy(kServer, network_anonymization_key1_)); |
| EXPECT_TRUE( |
| properties.SupportsRequestPriority(kServer, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.GetSupportsSpdy(kServer, NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| properties.SupportsRequestPriority(kServer, NetworkAnonymizationKey())); |
| |
| properties.SetSupportsSpdy(kServer, network_anonymization_key1_, false); |
| EXPECT_FALSE( |
| properties.GetSupportsSpdy(kServer, network_anonymization_key1_)); |
| EXPECT_FALSE( |
| properties.SupportsRequestPriority(kServer, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.GetSupportsSpdy(kServer, NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| properties.SupportsRequestPriority(kServer, NetworkAnonymizationKey())); |
| |
| properties.SetSupportsSpdy(kServer, NetworkAnonymizationKey(), false); |
| EXPECT_FALSE( |
| properties.GetSupportsSpdy(kServer, network_anonymization_key1_)); |
| EXPECT_FALSE( |
| properties.SupportsRequestPriority(kServer, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.GetSupportsSpdy(kServer, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties.SupportsRequestPriority(kServer, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesTest, LoadSupportsSpdy) { |
| HttpServerProperties::ServerInfo supports_spdy; |
| supports_spdy.supports_spdy = true; |
| HttpServerProperties::ServerInfo no_spdy; |
| no_spdy.supports_spdy = false; |
| |
| url::SchemeHostPort spdy_server_google("https", "www.google.com", 443); |
| url::SchemeHostPort spdy_server_photos("https", "photos.google.com", 443); |
| url::SchemeHostPort spdy_server_docs("https", "docs.google.com", 443); |
| url::SchemeHostPort spdy_server_mail("https", "mail.google.com", 443); |
| |
| // Check by initializing empty spdy servers. |
| std::unique_ptr<HttpServerProperties::ServerInfoMap> spdy_servers = |
| std::make_unique<HttpServerProperties::ServerInfoMap>(); |
| impl_.OnServerInfoLoadedForTesting(std::move(spdy_servers)); |
| EXPECT_FALSE( |
| impl_.GetSupportsSpdy(spdy_server_google, NetworkAnonymizationKey())); |
| |
| // Check by initializing www.google.com:443 and photos.google.com:443 as spdy |
| // servers. |
| std::unique_ptr<HttpServerProperties::ServerInfoMap> spdy_servers1 = |
| std::make_unique<HttpServerProperties::ServerInfoMap>(); |
| spdy_servers1->Put(CreateSimpleKey(spdy_server_google), supports_spdy); |
| spdy_servers1->Put(CreateSimpleKey(spdy_server_photos), no_spdy); |
| impl_.OnServerInfoLoadedForTesting(std::move(spdy_servers1)); |
| // Note: these calls affect MRU order. |
| EXPECT_TRUE( |
| impl_.GetSupportsSpdy(spdy_server_google, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| impl_.GetSupportsSpdy(spdy_server_photos, NetworkAnonymizationKey())); |
| |
| // Verify google and photos are in the list in MRU order. |
| ASSERT_EQ(2U, impl_.server_info_map_for_testing().size()); |
| auto it = impl_.server_info_map_for_testing().begin(); |
| EXPECT_EQ(spdy_server_photos, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(it->second.supports_spdy.has_value()); |
| EXPECT_FALSE(*it->second.supports_spdy); |
| ++it; |
| EXPECT_EQ(spdy_server_google, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(it->second.supports_spdy.has_value()); |
| EXPECT_TRUE(*it->second.supports_spdy); |
| |
| // Check by initializing mail.google.com:443 and docs.google.com:443. |
| std::unique_ptr<HttpServerProperties::ServerInfoMap> spdy_servers2 = |
| std::make_unique<HttpServerProperties::ServerInfoMap>(); |
| spdy_servers2->Put(CreateSimpleKey(spdy_server_mail), supports_spdy); |
| spdy_servers2->Put(CreateSimpleKey(spdy_server_docs), supports_spdy); |
| impl_.OnServerInfoLoadedForTesting(std::move(spdy_servers2)); |
| |
| // Verify all the servers are in the list in MRU order. Note that |
| // OnServerInfoLoadedForTesting will put existing spdy server entries in |
| // front of newly added entries. |
| ASSERT_EQ(4U, impl_.server_info_map_for_testing().size()); |
| it = impl_.server_info_map_for_testing().begin(); |
| EXPECT_EQ(spdy_server_photos, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(it->second.supports_spdy.has_value()); |
| EXPECT_FALSE(*it->second.supports_spdy); |
| ++it; |
| EXPECT_EQ(spdy_server_google, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(it->second.supports_spdy.has_value()); |
| EXPECT_TRUE(*it->second.supports_spdy); |
| ++it; |
| EXPECT_EQ(spdy_server_docs, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(it->second.supports_spdy.has_value()); |
| EXPECT_TRUE(*it->second.supports_spdy); |
| ++it; |
| EXPECT_EQ(spdy_server_mail, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(it->second.supports_spdy.has_value()); |
| EXPECT_TRUE(*it->second.supports_spdy); |
| |
| // Check these in reverse MRU order so that MRU order stays the same. |
| EXPECT_TRUE( |
| impl_.GetSupportsSpdy(spdy_server_mail, NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| impl_.GetSupportsSpdy(spdy_server_docs, NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| impl_.GetSupportsSpdy(spdy_server_google, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| impl_.GetSupportsSpdy(spdy_server_photos, NetworkAnonymizationKey())); |
| |
| // Verify that old values loaded from disk take precedence over newer learned |
| // values and also verify the recency list order is unchanged. |
| std::unique_ptr<HttpServerProperties::ServerInfoMap> spdy_servers3 = |
| std::make_unique<HttpServerProperties::ServerInfoMap>(); |
| spdy_servers3->Put(CreateSimpleKey(spdy_server_mail), no_spdy); |
| spdy_servers3->Put(CreateSimpleKey(spdy_server_photos), supports_spdy); |
| impl_.OnServerInfoLoadedForTesting(std::move(spdy_servers3)); |
| |
| // Verify the entries are in the same order. |
| ASSERT_EQ(4U, impl_.server_info_map_for_testing().size()); |
| it = impl_.server_info_map_for_testing().begin(); |
| EXPECT_EQ(spdy_server_photos, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(it->second.supports_spdy.has_value()); |
| EXPECT_TRUE(*it->second.supports_spdy); |
| ++it; |
| EXPECT_EQ(spdy_server_google, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(it->second.supports_spdy.has_value()); |
| EXPECT_TRUE(*it->second.supports_spdy); |
| ++it; |
| EXPECT_EQ(spdy_server_docs, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(it->second.supports_spdy.has_value()); |
| EXPECT_TRUE(*it->second.supports_spdy); |
| ++it; |
| EXPECT_EQ(spdy_server_mail, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(it->second.supports_spdy.has_value()); |
| EXPECT_FALSE(*it->second.supports_spdy); |
| |
| // Verify photos server doesn't support SPDY and other servers support SPDY. |
| EXPECT_FALSE( |
| impl_.GetSupportsSpdy(spdy_server_mail, NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| impl_.GetSupportsSpdy(spdy_server_docs, NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| impl_.GetSupportsSpdy(spdy_server_google, NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| impl_.GetSupportsSpdy(spdy_server_photos, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesTest, SupportsRequestPriority) { |
| url::SchemeHostPort spdy_server_empty("https", std::string(), 443); |
| EXPECT_FALSE(impl_.SupportsRequestPriority(spdy_server_empty, |
| NetworkAnonymizationKey())); |
| |
| // Add www.google.com:443 as supporting SPDY. |
| url::SchemeHostPort spdy_server_google("https", "www.google.com", 443); |
| impl_.SetSupportsSpdy(spdy_server_google, NetworkAnonymizationKey(), true); |
| EXPECT_TRUE(impl_.SupportsRequestPriority(spdy_server_google, |
| NetworkAnonymizationKey())); |
| |
| // Add mail.google.com:443 as not supporting SPDY. |
| url::SchemeHostPort spdy_server_mail("https", "mail.google.com", 443); |
| EXPECT_FALSE(impl_.SupportsRequestPriority(spdy_server_mail, |
| NetworkAnonymizationKey())); |
| |
| // Add docs.google.com:443 as supporting SPDY. |
| url::SchemeHostPort spdy_server_docs("https", "docs.google.com", 443); |
| impl_.SetSupportsSpdy(spdy_server_docs, NetworkAnonymizationKey(), true); |
| EXPECT_TRUE(impl_.SupportsRequestPriority(spdy_server_docs, |
| NetworkAnonymizationKey())); |
| |
| // Add www.youtube.com:443 as supporting QUIC. |
| url::SchemeHostPort youtube_server("https", "www.youtube.com", 443); |
| const AlternativeService alternative_service1(kProtoQUIC, "www.youtube.com", |
| 443); |
| SetAlternativeService(youtube_server, alternative_service1); |
| EXPECT_TRUE( |
| impl_.SupportsRequestPriority(youtube_server, NetworkAnonymizationKey())); |
| |
| // Add www.example.com:443 with two alternative services, one supporting QUIC. |
| url::SchemeHostPort example_server("https", "www.example.com", 443); |
| const AlternativeService alternative_service2(kProtoHTTP2, "", 443); |
| SetAlternativeService(example_server, alternative_service2); |
| SetAlternativeService(example_server, alternative_service1); |
| EXPECT_TRUE( |
| impl_.SupportsRequestPriority(example_server, NetworkAnonymizationKey())); |
| |
| // Verify all the entries are the same after additions. |
| EXPECT_TRUE(impl_.SupportsRequestPriority(spdy_server_google, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.SupportsRequestPriority(spdy_server_mail, |
| NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.SupportsRequestPriority(spdy_server_docs, |
| NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| impl_.SupportsRequestPriority(youtube_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| impl_.SupportsRequestPriority(example_server, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesTest, ClearSupportsSpdy) { |
| // Add www.google.com:443 and mail.google.com:443 as supporting SPDY. |
| url::SchemeHostPort spdy_server_google("https", "www.google.com", 443); |
| impl_.SetSupportsSpdy(spdy_server_google, NetworkAnonymizationKey(), true); |
| url::SchemeHostPort spdy_server_mail("https", "mail.google.com", 443); |
| impl_.SetSupportsSpdy(spdy_server_mail, NetworkAnonymizationKey(), true); |
| |
| EXPECT_TRUE( |
| impl_.GetSupportsSpdy(spdy_server_google, NetworkAnonymizationKey())); |
| EXPECT_TRUE( |
| impl_.GetSupportsSpdy(spdy_server_mail, NetworkAnonymizationKey())); |
| |
| base::RunLoop run_loop; |
| bool callback_invoked_ = false; |
| impl_.Clear(base::BindOnce( |
| [](bool* callback_invoked, base::OnceClosure quit_closure) { |
| *callback_invoked = true; |
| std::move(quit_closure).Run(); |
| }, |
| &callback_invoked_, run_loop.QuitClosure())); |
| EXPECT_FALSE( |
| impl_.GetSupportsSpdy(spdy_server_google, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| impl_.GetSupportsSpdy(spdy_server_mail, NetworkAnonymizationKey())); |
| |
| // Callback should be run asynchronously. |
| EXPECT_FALSE(callback_invoked_); |
| run_loop.Run(); |
| EXPECT_TRUE(callback_invoked_); |
| } |
| |
| TEST_F(HttpServerPropertiesTest, MRUOfServerInfoMap) { |
| url::SchemeHostPort spdy_server_google("https", "www.google.com", 443); |
| url::SchemeHostPort spdy_server_mail("https", "mail.google.com", 443); |
| |
| // Add www.google.com:443 as supporting SPDY. |
| impl_.SetSupportsSpdy(spdy_server_google, NetworkAnonymizationKey(), true); |
| ASSERT_EQ(1u, impl_.server_info_map_for_testing().size()); |
| auto it = impl_.server_info_map_for_testing().begin(); |
| ASSERT_EQ(spdy_server_google, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| |
| // Add mail.google.com:443 as supporting SPDY. Verify mail.google.com:443 and |
| // www.google.com:443 are in the list. |
| impl_.SetSupportsSpdy(spdy_server_mail, NetworkAnonymizationKey(), true); |
| ASSERT_EQ(2u, impl_.server_info_map_for_testing().size()); |
| it = impl_.server_info_map_for_testing().begin(); |
| ASSERT_EQ(spdy_server_mail, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ++it; |
| ASSERT_EQ(spdy_server_google, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| |
| // Get www.google.com:443. It should become the most-recently-used server. |
| EXPECT_TRUE( |
| impl_.GetSupportsSpdy(spdy_server_google, NetworkAnonymizationKey())); |
| ASSERT_EQ(2u, impl_.server_info_map_for_testing().size()); |
| it = impl_.server_info_map_for_testing().begin(); |
| ASSERT_EQ(spdy_server_google, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ++it; |
| ASSERT_EQ(spdy_server_mail, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| } |
| |
| typedef HttpServerPropertiesTest AlternateProtocolServerPropertiesTest; |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, Basic) { |
| url::SchemeHostPort test_server("http", "foo", 80); |
| EXPECT_FALSE(HasAlternativeService(test_server, NetworkAnonymizationKey())); |
| |
| AlternativeService alternative_service(kProtoHTTP2, "foo", 443); |
| SetAlternativeService(test_server, alternative_service); |
| const AlternativeServiceInfoVector alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(alternative_service, |
| alternative_service_info_vector[0].alternative_service()); |
| |
| impl_.Clear(base::OnceClosure()); |
| EXPECT_FALSE(HasAlternativeService(test_server, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, ExcludeOrigin) { |
| AlternativeServiceInfoVector alternative_service_info_vector; |
| base::Time expiration = test_clock_.Now() + base::Days(1); |
| // Same hostname, same port, TCP: should be ignored. |
| AlternativeServiceInfo alternative_service_info1 = |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| AlternativeService(kProtoHTTP2, "foo", 443), expiration); |
| alternative_service_info_vector.push_back(alternative_service_info1); |
| // Different hostname: GetAlternativeServiceInfos should return this one. |
| AlternativeServiceInfo alternative_service_info2 = |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| AlternativeService(kProtoHTTP2, "bar", 443), expiration); |
| alternative_service_info_vector.push_back(alternative_service_info2); |
| // Different port: GetAlternativeServiceInfos should return this one too. |
| AlternativeServiceInfo alternative_service_info3 = |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| AlternativeService(kProtoHTTP2, "foo", 80), expiration); |
| alternative_service_info_vector.push_back(alternative_service_info3); |
| // QUIC: GetAlternativeServices should return this one too. |
| AlternativeServiceInfo alternative_service_info4 = |
| AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( |
| AlternativeService(kProtoQUIC, "foo", 443), expiration, |
| DefaultSupportedQuicVersions()); |
| alternative_service_info_vector.push_back(alternative_service_info4); |
| |
| url::SchemeHostPort test_server("https", "foo", 443); |
| impl_.SetAlternativeServices(test_server, NetworkAnonymizationKey(), |
| alternative_service_info_vector); |
| |
| const AlternativeServiceInfoVector alternative_service_info_vector2 = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(3u, alternative_service_info_vector2.size()); |
| EXPECT_EQ(alternative_service_info2, alternative_service_info_vector2[0]); |
| EXPECT_EQ(alternative_service_info3, alternative_service_info_vector2[1]); |
| EXPECT_EQ(alternative_service_info4, alternative_service_info_vector2[2]); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, Set) { |
| // |test_server1| has an alternative service, which will not be |
| // affected by OnServerInfoLoadedForTesting(), because |
| // |server_info_map| does not have an entry for |
| // |test_server1|. |
| url::SchemeHostPort test_server1("http", "foo1", 80); |
| const AlternativeService alternative_service1(kProtoHTTP2, "bar1", 443); |
| const base::Time now = test_clock_.Now(); |
| base::Time expiration1 = now + base::Days(1); |
| // 1st entry in the memory. |
| impl_.SetHttp2AlternativeService(test_server1, NetworkAnonymizationKey(), |
| alternative_service1, expiration1); |
| |
| // |test_server2| has an alternative service, which will be |
| // overwritten by OnServerInfoLoadedForTesting(), because |
| // |server_info_map| has an entry for |test_server2|. |
| AlternativeServiceInfoVector alternative_service_info_vector; |
| const AlternativeService alternative_service2(kProtoHTTP2, "bar2", 443); |
| base::Time expiration2 = now + base::Days(2); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service2, expiration2)); |
| url::SchemeHostPort test_server2("http", "foo2", 80); |
| // 0th entry in the memory. |
| impl_.SetAlternativeServices(test_server2, NetworkAnonymizationKey(), |
| alternative_service_info_vector); |
| |
| // Prepare |server_info_map| to be loaded by OnServerInfoLoadedForTesting(). |
| std::unique_ptr<HttpServerProperties::ServerInfoMap> server_info_map = |
| std::make_unique<HttpServerProperties::ServerInfoMap>(); |
| const AlternativeService alternative_service3(kProtoHTTP2, "bar3", 123); |
| base::Time expiration3 = now + base::Days(3); |
| const AlternativeServiceInfo alternative_service_info1 = |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service3, expiration3); |
| // Simulate updating data for 0th entry with data from Preferences. |
| server_info_map->GetOrPut(CreateSimpleKey(test_server2)) |
| ->second.alternative_services = |
| AlternativeServiceInfoVector(/*size=*/1, alternative_service_info1); |
| |
| url::SchemeHostPort test_server3("http", "foo3", 80); |
| const AlternativeService alternative_service4(kProtoHTTP2, "bar4", 1234); |
| base::Time expiration4 = now + base::Days(4); |
| const AlternativeServiceInfo alternative_service_info2 = |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service4, expiration4); |
| // Add an old entry from Preferences, this will be added to end of recency |
| // list. |
| server_info_map->GetOrPut(CreateSimpleKey(test_server3)) |
| ->second.alternative_services = |
| AlternativeServiceInfoVector(/*size=*/1, alternative_service_info2); |
| |
| // MRU list will be test_server2, test_server1, test_server3. |
| impl_.OnServerInfoLoadedForTesting(std::move(server_info_map)); |
| |
| // Verify server_info_map. |
| const HttpServerProperties::ServerInfoMap& map = |
| impl_.server_info_map_for_testing(); |
| ASSERT_EQ(3u, map.size()); |
| auto map_it = map.begin(); |
| |
| EXPECT_EQ(test_server2, map_it->first.server); |
| EXPECT_TRUE(map_it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(map_it->second.alternative_services.has_value()); |
| const AlternativeServiceInfoVector* service_info = |
| &map_it->second.alternative_services.value(); |
| ASSERT_EQ(1u, service_info->size()); |
| EXPECT_EQ(alternative_service3, (*service_info)[0].alternative_service()); |
| EXPECT_EQ(expiration3, (*service_info)[0].expiration()); |
| |
| ++map_it; |
| EXPECT_EQ(test_server1, map_it->first.server); |
| EXPECT_TRUE(map_it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(map_it->second.alternative_services.has_value()); |
| service_info = &map_it->second.alternative_services.value(); |
| ASSERT_EQ(1u, service_info->size()); |
| EXPECT_EQ(alternative_service1, (*service_info)[0].alternative_service()); |
| EXPECT_EQ(expiration1, (*service_info)[0].expiration()); |
| |
| ++map_it; |
| EXPECT_EQ(map_it->first.server, test_server3); |
| EXPECT_TRUE(map_it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(map_it->second.alternative_services.has_value()); |
| service_info = &map_it->second.alternative_services.value(); |
| ASSERT_EQ(1u, service_info->size()); |
| EXPECT_EQ(alternative_service4, (*service_info)[0].alternative_service()); |
| EXPECT_EQ(expiration4, (*service_info)[0].expiration()); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, SetWebSockets) { |
| // The https and wss servers should be treated as the same server, as should |
| // the http and ws servers. |
| url::SchemeHostPort https_server("https", "www.test.com", 443); |
| url::SchemeHostPort wss_server("wss", "www.test.com", 443); |
| url::SchemeHostPort http_server("http", "www.test.com", 443); |
| url::SchemeHostPort ws_server("ws", "www.test.com", 443); |
| |
| AlternativeService alternative_service(kProtoHTTP2, "bar", 443); |
| |
| EXPECT_EQ( |
| 0u, |
| impl_.GetAlternativeServiceInfos(https_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 0u, |
| impl_.GetAlternativeServiceInfos(wss_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 0u, |
| impl_.GetAlternativeServiceInfos(http_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 0u, impl_.GetAlternativeServiceInfos(ws_server, NetworkAnonymizationKey()) |
| .size()); |
| |
| SetAlternativeService(wss_server, alternative_service); |
| EXPECT_EQ( |
| 1u, |
| impl_.GetAlternativeServiceInfos(https_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 1u, |
| impl_.GetAlternativeServiceInfos(wss_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 0u, |
| impl_.GetAlternativeServiceInfos(http_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 0u, impl_.GetAlternativeServiceInfos(ws_server, NetworkAnonymizationKey()) |
| .size()); |
| |
| SetAlternativeService(http_server, alternative_service); |
| EXPECT_EQ( |
| 1u, |
| impl_.GetAlternativeServiceInfos(https_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 1u, |
| impl_.GetAlternativeServiceInfos(wss_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 1u, |
| impl_.GetAlternativeServiceInfos(http_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 1u, impl_.GetAlternativeServiceInfos(ws_server, NetworkAnonymizationKey()) |
| .size()); |
| |
| impl_.SetAlternativeServices(https_server, NetworkAnonymizationKey(), |
| AlternativeServiceInfoVector()); |
| EXPECT_EQ( |
| 0u, |
| impl_.GetAlternativeServiceInfos(https_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 0u, |
| impl_.GetAlternativeServiceInfos(wss_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 1u, |
| impl_.GetAlternativeServiceInfos(http_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 1u, impl_.GetAlternativeServiceInfos(ws_server, NetworkAnonymizationKey()) |
| .size()); |
| |
| impl_.SetAlternativeServices(ws_server, NetworkAnonymizationKey(), |
| AlternativeServiceInfoVector()); |
| EXPECT_EQ( |
| 0u, |
| impl_.GetAlternativeServiceInfos(https_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 0u, |
| impl_.GetAlternativeServiceInfos(wss_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 0u, |
| impl_.GetAlternativeServiceInfos(http_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 0u, impl_.GetAlternativeServiceInfos(ws_server, NetworkAnonymizationKey()) |
| .size()); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, SetWithNetworkIsolationKey) { |
| const url::SchemeHostPort kServer("https", "foo.test", 443); |
| const AlternativeServiceInfoVector kAlternativeServices( |
| {AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| AlternativeService(kProtoHTTP2, "foo", 443), |
| base::Time::Now() + base::Days(1) /* expiration */)}); |
| |
| EXPECT_TRUE( |
| impl_.GetAlternativeServiceInfos(kServer, network_anonymization_key1_) |
| .empty()); |
| EXPECT_TRUE( |
| impl_.GetAlternativeServiceInfos(kServer, NetworkAnonymizationKey()) |
| .empty()); |
| |
| // Without network isolation keys enabled for HttpServerProperties, passing in |
| // a NetworkAnonymizationKey should have no effect on behavior. |
| for (const auto& network_anonymization_key_to_set : |
| {NetworkAnonymizationKey(), network_anonymization_key1_}) { |
| impl_.SetAlternativeServices(kServer, network_anonymization_key_to_set, |
| kAlternativeServices); |
| EXPECT_EQ(kAlternativeServices, impl_.GetAlternativeServiceInfos( |
| kServer, network_anonymization_key1_)); |
| EXPECT_EQ(kAlternativeServices, impl_.GetAlternativeServiceInfos( |
| kServer, NetworkAnonymizationKey())); |
| |
| impl_.SetAlternativeServices(kServer, network_anonymization_key_to_set, |
| AlternativeServiceInfoVector()); |
| EXPECT_TRUE( |
| impl_.GetAlternativeServiceInfos(kServer, network_anonymization_key1_) |
| .empty()); |
| EXPECT_TRUE( |
| impl_.GetAlternativeServiceInfos(kServer, NetworkAnonymizationKey()) |
| .empty()); |
| } |
| |
| // Check that with network isolation keys enabled for HttpServerProperties, |
| // the NetworkAnonymizationKey argument is respected. |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| // Since HttpServerProperties caches the feature value, have to create a new |
| // one. |
| HttpServerProperties properties(nullptr /* pref_delegate */, |
| nullptr /* net_log */, test_tick_clock_, |
| &test_clock_); |
| |
| properties.SetAlternativeServices(kServer, network_anonymization_key1_, |
| kAlternativeServices); |
| EXPECT_EQ(kAlternativeServices, properties.GetAlternativeServiceInfos( |
| kServer, network_anonymization_key1_)); |
| EXPECT_TRUE( |
| properties.GetAlternativeServiceInfos(kServer, NetworkAnonymizationKey()) |
| .empty()); |
| |
| properties.SetAlternativeServices(kServer, NetworkAnonymizationKey(), |
| kAlternativeServices); |
| EXPECT_EQ(kAlternativeServices, properties.GetAlternativeServiceInfos( |
| kServer, network_anonymization_key1_)); |
| EXPECT_EQ(kAlternativeServices, properties.GetAlternativeServiceInfos( |
| kServer, NetworkAnonymizationKey())); |
| |
| properties.SetAlternativeServices(kServer, network_anonymization_key1_, |
| AlternativeServiceInfoVector()); |
| EXPECT_TRUE( |
| properties |
| .GetAlternativeServiceInfos(kServer, network_anonymization_key1_) |
| .empty()); |
| EXPECT_EQ(kAlternativeServices, properties.GetAlternativeServiceInfos( |
| kServer, NetworkAnonymizationKey())); |
| |
| properties.SetAlternativeServices(kServer, NetworkAnonymizationKey(), |
| AlternativeServiceInfoVector()); |
| EXPECT_TRUE( |
| properties |
| .GetAlternativeServiceInfos(kServer, network_anonymization_key1_) |
| .empty()); |
| EXPECT_TRUE( |
| properties.GetAlternativeServiceInfos(kServer, NetworkAnonymizationKey()) |
| .empty()); |
| } |
| |
| // Regression test for https://crbug.com/504032: |
| // OnServerInfoLoadedForTesting() should not crash if there is an |
| // empty hostname is the mapping. |
| TEST_F(AlternateProtocolServerPropertiesTest, SetWithEmptyHostname) { |
| url::SchemeHostPort server("https", "foo", 443); |
| const AlternativeService alternative_service_with_empty_hostname(kProtoHTTP2, |
| "", 1234); |
| const AlternativeService alternative_service_with_foo_hostname(kProtoHTTP2, |
| "foo", 1234); |
| SetAlternativeService(server, alternative_service_with_empty_hostname); |
| impl_.MarkAlternativeServiceBroken(alternative_service_with_foo_hostname, |
| NetworkAnonymizationKey()); |
| |
| std::unique_ptr<HttpServerProperties::ServerInfoMap> server_info_map = |
| std::make_unique<HttpServerProperties::ServerInfoMap>(); |
| impl_.OnServerInfoLoadedForTesting(std::move(server_info_map)); |
| |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken( |
| alternative_service_with_foo_hostname, NetworkAnonymizationKey())); |
| const AlternativeServiceInfoVector alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(alternative_service_with_foo_hostname, |
| alternative_service_info_vector[0].alternative_service()); |
| } |
| |
| // Regression test for https://crbug.com/516486: |
| // GetAlternativeServiceInfos() should remove |server_info_map_| |
| // elements with empty value. |
| TEST_F(AlternateProtocolServerPropertiesTest, DISABLED_EmptyVector) { |
| url::SchemeHostPort server("https", "foo", 443); |
| const AlternativeService alternative_service(kProtoHTTP2, "bar", 443); |
| base::Time expiration = test_clock_.Now() - base::Days(1); |
| const AlternativeServiceInfo alternative_service_info = |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service, expiration); |
| std::unique_ptr<HttpServerProperties::ServerInfoMap> server_info_map = |
| std::make_unique<HttpServerProperties::ServerInfoMap>(); |
| server_info_map->GetOrPut(CreateSimpleKey(server)) |
| ->second.alternative_services = AlternativeServiceInfoVector( |
| /*size=*/1, alternative_service_info); |
| |
| // Prepare |server_info_map_| with a single key that has a single |
| // AlternativeServiceInfo with identical hostname and port. |
| impl_.OnServerInfoLoadedForTesting(std::move(server_info_map)); |
| |
| // GetAlternativeServiceInfos() should remove such AlternativeServiceInfo from |
| // |server_info_map_|, emptying the AlternativeServiceInfoVector |
| // corresponding to |server|. |
| ASSERT_TRUE( |
| impl_.GetAlternativeServiceInfos(server, NetworkAnonymizationKey()) |
| .empty()); |
| |
| // GetAlternativeServiceInfos() should remove this key from |
| // |server_info_map_|, and SetAlternativeServices() should not crash. |
| impl_.SetAlternativeServices( |
| server, NetworkAnonymizationKey(), |
| AlternativeServiceInfoVector(/*size=*/1, alternative_service_info)); |
| |
| // There should still be no alternative service assigned to |server|. |
| ASSERT_TRUE( |
| impl_.GetAlternativeServiceInfos(server, NetworkAnonymizationKey()) |
| .empty()); |
| } |
| |
| // Regression test for https://crbug.com/516486 for the canonical host case. |
| TEST_F(AlternateProtocolServerPropertiesTest, EmptyVectorForCanonical) { |
| url::SchemeHostPort server("https", "foo.c.youtube.com", 443); |
| url::SchemeHostPort canonical_server("https", "bar.c.youtube.com", 443); |
| const AlternativeService alternative_service(kProtoHTTP2, "", 443); |
| base::Time expiration = test_clock_.Now() - base::Days(1); |
| const AlternativeServiceInfo alternative_service_info = |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service, expiration); |
| std::unique_ptr<HttpServerProperties::ServerInfoMap> server_info_map = |
| std::make_unique<HttpServerProperties::ServerInfoMap>(); |
| server_info_map->GetOrPut(CreateSimpleKey(canonical_server)) |
| ->second.alternative_services = |
| AlternativeServiceInfoVector(/*size=*/1, alternative_service_info); |
| |
| // Prepare |server_info_map_| with a single key that has a single |
| // AlternativeServiceInfo with identical hostname and port. |
| impl_.OnServerInfoLoadedForTesting(std::move(server_info_map)); |
| |
| // GetAlternativeServiceInfos() should remove such AlternativeServiceInfo from |
| // |server_info_map_|, emptying the AlternativeServiceInfoVector |
| // corresponding to |canonical_server|, even when looking up |
| // alternative services for |server|. |
| ASSERT_TRUE( |
| impl_.GetAlternativeServiceInfos(server, NetworkAnonymizationKey()) |
| .empty()); |
| |
| // GetAlternativeServiceInfos() should remove this key from |
| // |server_info_map_|, and SetAlternativeServices() should not crash. |
| impl_.SetAlternativeServices( |
| canonical_server, NetworkAnonymizationKey(), |
| AlternativeServiceInfoVector(/*size=*/1, alternative_service_info)); |
| |
| // There should still be no alternative service assigned to |
| // |canonical_server|. |
| ASSERT_TRUE(impl_ |
| .GetAlternativeServiceInfos(canonical_server, |
| NetworkAnonymizationKey()) |
| .empty()); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, ClearServerWithCanonical) { |
| url::SchemeHostPort server("https", "foo.c.youtube.com", 443); |
| url::SchemeHostPort canonical_server("https", "bar.c.youtube.com", 443); |
| const AlternativeService alternative_service(kProtoQUIC, "", 443); |
| base::Time expiration = test_clock_.Now() + base::Days(1); |
| const AlternativeServiceInfo alternative_service_info = |
| AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( |
| alternative_service, expiration, DefaultSupportedQuicVersions()); |
| |
| impl_.SetAlternativeServices( |
| canonical_server, NetworkAnonymizationKey(), |
| AlternativeServiceInfoVector(/*size=*/1, alternative_service_info)); |
| |
| // Make sure the canonical service is returned for the other server. |
| const AlternativeServiceInfoVector alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(kProtoQUIC, |
| alternative_service_info_vector[0].alternative_service().protocol); |
| EXPECT_EQ(443, alternative_service_info_vector[0].alternative_service().port); |
| |
| // Now clear the alternatives for the other server and make sure it stays |
| // cleared. |
| // GetAlternativeServices() should remove this key from |
| // |server_info_map_|, and SetAlternativeServices() should not crash. |
| impl_.SetAlternativeServices(server, NetworkAnonymizationKey(), |
| AlternativeServiceInfoVector()); |
| |
| ASSERT_TRUE( |
| impl_.GetAlternativeServiceInfos(server, NetworkAnonymizationKey()) |
| .empty()); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, MRUOfGetAlternativeServiceInfos) { |
| url::SchemeHostPort test_server1("http", "foo1", 80); |
| const AlternativeService alternative_service1(kProtoHTTP2, "foo1", 443); |
| SetAlternativeService(test_server1, alternative_service1); |
| url::SchemeHostPort test_server2("http", "foo2", 80); |
| const AlternativeService alternative_service2(kProtoHTTP2, "foo2", 1234); |
| SetAlternativeService(test_server2, alternative_service2); |
| |
| const HttpServerProperties::ServerInfoMap& map = |
| impl_.server_info_map_for_testing(); |
| auto it = map.begin(); |
| EXPECT_EQ(test_server2, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(it->second.alternative_services.has_value()); |
| ASSERT_EQ(1u, it->second.alternative_services->size()); |
| EXPECT_EQ(alternative_service2, |
| it->second.alternative_services.value()[0].alternative_service()); |
| |
| const AlternativeServiceInfoVector alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(test_server1, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(alternative_service1, |
| alternative_service_info_vector[0].alternative_service()); |
| |
| // GetAlternativeServices should reorder the AlternateProtocol map. |
| it = map.begin(); |
| EXPECT_EQ(test_server1, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(it->second.alternative_services.has_value()); |
| ASSERT_EQ(1u, it->second.alternative_services->size()); |
| EXPECT_EQ(alternative_service1, |
| it->second.alternative_services.value()[0].alternative_service()); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, SetBroken) { |
| url::SchemeHostPort test_server("http", "foo", 80); |
| const AlternativeService alternative_service1(kProtoHTTP2, "foo", 443); |
| SetAlternativeService(test_server, alternative_service1); |
| AlternativeServiceInfoVector alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(alternative_service1, |
| alternative_service_info_vector[0].alternative_service()); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey())); |
| |
| // GetAlternativeServiceInfos should return the broken alternative service. |
| impl_.MarkAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey()); |
| alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(alternative_service1, |
| alternative_service_info_vector[0].alternative_service()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey())); |
| |
| // SetAlternativeServices should add a broken alternative service to the map. |
| AlternativeServiceInfoVector alternative_service_info_vector2; |
| base::Time expiration = test_clock_.Now() + base::Days(1); |
| alternative_service_info_vector2.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service1, expiration)); |
| const AlternativeService alternative_service2(kProtoHTTP2, "foo", 1234); |
| alternative_service_info_vector2.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service2, expiration)); |
| impl_.SetAlternativeServices(test_server, NetworkAnonymizationKey(), |
| alternative_service_info_vector2); |
| alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(2u, alternative_service_info_vector.size()); |
| EXPECT_EQ(alternative_service1, |
| alternative_service_info_vector[0].alternative_service()); |
| EXPECT_EQ(alternative_service2, |
| alternative_service_info_vector[1].alternative_service()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service2, |
| NetworkAnonymizationKey())); |
| |
| // SetAlternativeService should add a broken alternative service to the map. |
| SetAlternativeService(test_server, alternative_service1); |
| alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(alternative_service1, |
| alternative_service_info_vector[0].alternative_service()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, |
| SetBrokenUntilDefaultNetworkChanges) { |
| url::SchemeHostPort test_server("http", "foo", 80); |
| const AlternativeService alternative_service1(kProtoHTTP2, "foo", 443); |
| SetAlternativeService(test_server, alternative_service1); |
| AlternativeServiceInfoVector alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(alternative_service1, |
| alternative_service_info_vector[0].alternative_service()); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey())); |
| |
| // Mark the alternative service as broken until the default network changes. |
| impl_.MarkAlternativeServiceBrokenUntilDefaultNetworkChanges( |
| alternative_service1, NetworkAnonymizationKey()); |
| // The alternative service should be persisted and marked as broken. |
| alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(alternative_service1, |
| alternative_service_info_vector[0].alternative_service()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey())); |
| |
| // SetAlternativeServices should add a broken alternative service to the map. |
| AlternativeServiceInfoVector alternative_service_info_vector2; |
| base::Time expiration = test_clock_.Now() + base::Days(1); |
| alternative_service_info_vector2.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service1, expiration)); |
| const AlternativeService alternative_service2(kProtoHTTP2, "foo", 1234); |
| alternative_service_info_vector2.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service2, expiration)); |
| impl_.SetAlternativeServices(test_server, NetworkAnonymizationKey(), |
| alternative_service_info_vector2); |
| alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(2u, alternative_service_info_vector.size()); |
| EXPECT_EQ(alternative_service1, |
| alternative_service_info_vector[0].alternative_service()); |
| EXPECT_EQ(alternative_service2, |
| alternative_service_info_vector[1].alternative_service()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service2, |
| NetworkAnonymizationKey())); |
| |
| // SetAlternativeService should add a broken alternative service to the map. |
| SetAlternativeService(test_server, alternative_service1); |
| alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(alternative_service1, |
| alternative_service_info_vector[0].alternative_service()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, MaxAge) { |
| AlternativeServiceInfoVector alternative_service_info_vector; |
| base::Time now = test_clock_.Now(); |
| base::TimeDelta one_day = base::Days(1); |
| |
| // First alternative service expired one day ago, should not be returned by |
| // GetAlternativeServiceInfos(). |
| const AlternativeService alternative_service1(kProtoHTTP2, "foo", 443); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service1, now - one_day)); |
| |
| // Second alterrnative service will expire one day from now, should be |
| // returned by GetAlternativeSerices(). |
| const AlternativeService alternative_service2(kProtoHTTP2, "bar", 1234); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service2, now + one_day)); |
| |
| url::SchemeHostPort test_server("http", "foo", 80); |
| impl_.SetAlternativeServices(test_server, NetworkAnonymizationKey(), |
| alternative_service_info_vector); |
| |
| AlternativeServiceInfoVector alternative_service_info_vector2 = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector2.size()); |
| EXPECT_EQ(alternative_service2, |
| alternative_service_info_vector2[0].alternative_service()); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, MaxAgeCanonical) { |
| AlternativeServiceInfoVector alternative_service_info_vector; |
| base::Time now = test_clock_.Now(); |
| base::TimeDelta one_day = base::Days(1); |
| |
| // First alternative service expired one day ago, should not be returned by |
| // GetAlternativeServiceInfos(). |
| const AlternativeService alternative_service1(kProtoHTTP2, "foo", 443); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service1, now - one_day)); |
| |
| // Second alterrnative service will expire one day from now, should be |
| // returned by GetAlternativeSerices(). |
| const AlternativeService alternative_service2(kProtoHTTP2, "bar", 1234); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service2, now + one_day)); |
| |
| url::SchemeHostPort canonical_server("https", "bar.c.youtube.com", 443); |
| impl_.SetAlternativeServices(canonical_server, NetworkAnonymizationKey(), |
| alternative_service_info_vector); |
| |
| url::SchemeHostPort test_server("https", "foo.c.youtube.com", 443); |
| AlternativeServiceInfoVector alternative_service_info_vector2 = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector2.size()); |
| EXPECT_EQ(alternative_service2, |
| alternative_service_info_vector2[0].alternative_service()); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, AlternativeServiceWithScheme) { |
| AlternativeServiceInfoVector alternative_service_info_vector; |
| const AlternativeService alternative_service1(kProtoHTTP2, "foo", 443); |
| base::Time expiration = test_clock_.Now() + base::Days(1); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service1, expiration)); |
| const AlternativeService alternative_service2(kProtoHTTP2, "bar", 1234); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service2, expiration)); |
| // Set Alt-Svc list for |http_server|. |
| url::SchemeHostPort http_server("http", "foo", 80); |
| impl_.SetAlternativeServices(http_server, NetworkAnonymizationKey(), |
| alternative_service_info_vector); |
| |
| const net::HttpServerProperties::ServerInfoMap& map = |
| impl_.server_info_map_for_testing(); |
| auto it = map.begin(); |
| EXPECT_EQ(http_server, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(it->second.alternative_services.has_value()); |
| ASSERT_EQ(2u, it->second.alternative_services->size()); |
| EXPECT_EQ(alternative_service1, |
| it->second.alternative_services.value()[0].alternative_service()); |
| EXPECT_EQ(alternative_service2, |
| it->second.alternative_services.value()[1].alternative_service()); |
| |
| // Check Alt-Svc list should not be set for |https_server|. |
| url::SchemeHostPort https_server("https", "foo", 80); |
| EXPECT_EQ( |
| 0u, |
| impl_.GetAlternativeServiceInfos(https_server, NetworkAnonymizationKey()) |
| .size()); |
| |
| // Set Alt-Svc list for |https_server|. |
| impl_.SetAlternativeServices(https_server, NetworkAnonymizationKey(), |
| alternative_service_info_vector); |
| EXPECT_EQ( |
| 2u, |
| impl_.GetAlternativeServiceInfos(https_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 2u, |
| impl_.GetAlternativeServiceInfos(http_server, NetworkAnonymizationKey()) |
| .size()); |
| |
| // Clear Alt-Svc list for |http_server|. |
| impl_.SetAlternativeServices(http_server, NetworkAnonymizationKey(), |
| AlternativeServiceInfoVector()); |
| |
| EXPECT_EQ( |
| 0u, |
| impl_.GetAlternativeServiceInfos(http_server, NetworkAnonymizationKey()) |
| .size()); |
| EXPECT_EQ( |
| 2u, |
| impl_.GetAlternativeServiceInfos(https_server, NetworkAnonymizationKey()) |
| .size()); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, ClearAlternativeServices) { |
| AlternativeServiceInfoVector alternative_service_info_vector; |
| const AlternativeService alternative_service1(kProtoHTTP2, "foo", 443); |
| base::Time expiration = test_clock_.Now() + base::Days(1); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service1, expiration)); |
| const AlternativeService alternative_service2(kProtoHTTP2, "bar", 1234); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| alternative_service2, expiration)); |
| url::SchemeHostPort test_server("http", "foo", 80); |
| impl_.SetAlternativeServices(test_server, NetworkAnonymizationKey(), |
| alternative_service_info_vector); |
| |
| const net::HttpServerProperties::ServerInfoMap& map = |
| impl_.server_info_map_for_testing(); |
| auto it = map.begin(); |
| EXPECT_EQ(test_server, it->first.server); |
| EXPECT_TRUE(it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(it->second.alternative_services.has_value()); |
| ASSERT_EQ(2u, it->second.alternative_services->size()); |
| EXPECT_EQ(alternative_service1, |
| it->second.alternative_services.value()[0].alternative_service()); |
| EXPECT_EQ(alternative_service2, |
| it->second.alternative_services.value()[1].alternative_service()); |
| |
| impl_.SetAlternativeServices(test_server, NetworkAnonymizationKey(), |
| AlternativeServiceInfoVector()); |
| EXPECT_TRUE(map.empty()); |
| } |
| |
| // A broken alternative service in the mapping carries meaningful information, |
| // therefore it should not be ignored by SetAlternativeService(). In |
| // particular, an alternative service mapped to an origin shadows alternative |
| // services of canonical hosts. |
| TEST_F(AlternateProtocolServerPropertiesTest, BrokenShadowsCanonical) { |
| url::SchemeHostPort test_server("https", "foo.c.youtube.com", 443); |
| url::SchemeHostPort canonical_server("https", "bar.c.youtube.com", 443); |
| AlternativeService canonical_alternative_service(kProtoQUIC, |
| "bar.c.youtube.com", 1234); |
| SetAlternativeService(canonical_server, canonical_alternative_service); |
| AlternativeServiceInfoVector alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(canonical_alternative_service, |
| alternative_service_info_vector[0].alternative_service()); |
| |
| const AlternativeService broken_alternative_service(kProtoHTTP2, "foo", 443); |
| impl_.MarkAlternativeServiceBroken(broken_alternative_service, |
| NetworkAnonymizationKey()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(broken_alternative_service, |
| NetworkAnonymizationKey())); |
| |
| SetAlternativeService(test_server, broken_alternative_service); |
| alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(broken_alternative_service, |
| alternative_service_info_vector[0].alternative_service()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(broken_alternative_service, |
| NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, ClearBroken) { |
| url::SchemeHostPort test_server("http", "foo", 80); |
| const AlternativeService alternative_service(kProtoHTTP2, "foo", 443); |
| SetAlternativeService(test_server, alternative_service); |
| impl_.MarkAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey()); |
| ASSERT_TRUE(HasAlternativeService(test_server, NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| // SetAlternativeServices should leave a broken alternative service marked |
| // as such. |
| impl_.SetAlternativeServices(test_server, NetworkAnonymizationKey(), |
| AlternativeServiceInfoVector()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, |
| MarkBrokenWithNetworkIsolationKey) { |
| url::SchemeHostPort server("http", "foo", 80); |
| const AlternativeService alternative_service(kProtoHTTP2, "foo", 443); |
| const base::Time expiration = test_clock_.Now() + base::Days(1); |
| |
| // Without NetworkIsolationKeys enabled, the NetworkAnonymizationKey parameter |
| // should be ignored. |
| impl_.SetHttp2AlternativeService(server, network_anonymization_key1_, |
| alternative_service, expiration); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key2_)); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| impl_.MarkAlternativeServiceBroken(alternative_service, |
| network_anonymization_key1_); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key1_)); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key2_)); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| impl_.ConfirmAlternativeService(alternative_service, |
| network_anonymization_key2_); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key2_)); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| // Since HttpServerProperties caches the feature value, have to create a new |
| // one. |
| HttpServerProperties properties(nullptr /* pref_delegate */, |
| nullptr /* net_log */, test_tick_clock_, |
| &test_clock_); |
| |
| properties.SetHttp2AlternativeService(server, network_anonymization_key1_, |
| alternative_service, expiration); |
| properties.SetHttp2AlternativeService(server, network_anonymization_key2_, |
| alternative_service, expiration); |
| |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| properties.MarkAlternativeServiceBroken(alternative_service, |
| network_anonymization_key1_); |
| EXPECT_TRUE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| properties.MarkAlternativeServiceBroken(alternative_service, |
| network_anonymization_key2_); |
| EXPECT_TRUE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| properties.ConfirmAlternativeService(alternative_service, |
| network_anonymization_key1_); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| properties.ConfirmAlternativeService(alternative_service, |
| network_anonymization_key2_); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, MarkRecentlyBroken) { |
| url::SchemeHostPort server("http", "foo", 80); |
| const AlternativeService alternative_service(kProtoHTTP2, "foo", 443); |
| SetAlternativeService(server, alternative_service); |
| |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| impl_.MarkAlternativeServiceRecentlyBroken(alternative_service, |
| NetworkAnonymizationKey()); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| impl_.ConfirmAlternativeService(alternative_service, |
| NetworkAnonymizationKey()); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, |
| MarkRecentlyBrokenWithNetworkIsolationKey) { |
| url::SchemeHostPort server("http", "foo", 80); |
| const AlternativeService alternative_service(kProtoHTTP2, "foo", 443); |
| const base::Time expiration = test_clock_.Now() + base::Days(1); |
| |
| // Without NetworkIsolationKeys enabled, the NetworkAnonymizationKey parameter |
| // should be ignored. |
| impl_.SetHttp2AlternativeService(server, network_anonymization_key1_, |
| alternative_service, expiration); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key2_)); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| impl_.MarkAlternativeServiceRecentlyBroken(alternative_service, |
| network_anonymization_key1_); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key1_)); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key2_)); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| impl_.ConfirmAlternativeService(alternative_service, |
| network_anonymization_key2_); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key2_)); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| // Since HttpServerProperties caches the feature value, have to create a new |
| // one. |
| HttpServerProperties properties(nullptr /* pref_delegate */, |
| nullptr /* net_log */, test_tick_clock_, |
| &test_clock_); |
| |
| properties.SetHttp2AlternativeService(server, network_anonymization_key1_, |
| alternative_service, expiration); |
| properties.SetHttp2AlternativeService(server, network_anonymization_key2_, |
| alternative_service, expiration); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| properties.MarkAlternativeServiceRecentlyBroken(alternative_service, |
| network_anonymization_key1_); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| properties.MarkAlternativeServiceRecentlyBroken(alternative_service, |
| network_anonymization_key2_); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| properties.ConfirmAlternativeService(alternative_service, |
| network_anonymization_key1_); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| properties.ConfirmAlternativeService(alternative_service, |
| network_anonymization_key2_); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, |
| MarkBrokenUntilDefaultNetworkChanges) { |
| url::SchemeHostPort server("http", "foo", 80); |
| const AlternativeService alternative_service(kProtoHTTP2, "foo", 443); |
| SetAlternativeService(server, alternative_service); |
| |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| impl_.MarkAlternativeServiceBrokenUntilDefaultNetworkChanges( |
| alternative_service, NetworkAnonymizationKey()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| impl_.ConfirmAlternativeService(alternative_service, |
| NetworkAnonymizationKey()); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, |
| MarkBrokenUntilDefaultNetworkChangesWithNetworkIsolationKey) { |
| url::SchemeHostPort server("http", "foo", 80); |
| const AlternativeService alternative_service(kProtoHTTP2, "foo", 443); |
| const base::Time expiration = test_clock_.Now() + base::Days(1); |
| |
| // Without NetworkIsolationKeys enabled, the NetworkAnonymizationKey parameter |
| // should be ignored. |
| impl_.SetHttp2AlternativeService(server, network_anonymization_key1_, |
| alternative_service, expiration); |
| |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key2_)); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| impl_.MarkAlternativeServiceBrokenUntilDefaultNetworkChanges( |
| alternative_service, network_anonymization_key1_); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key1_)); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key2_)); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| impl_.ConfirmAlternativeService(alternative_service, |
| network_anonymization_key2_); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| network_anonymization_key2_)); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| // Since HttpServerProperties caches the feature value, have to create a new |
| // one. |
| HttpServerProperties properties(nullptr /* pref_delegate */, |
| nullptr /* net_log */, test_tick_clock_, |
| &test_clock_); |
| |
| properties.SetHttp2AlternativeService(server, network_anonymization_key1_, |
| alternative_service, expiration); |
| properties.SetHttp2AlternativeService(server, network_anonymization_key2_, |
| alternative_service, expiration); |
| |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| properties.MarkAlternativeServiceBrokenUntilDefaultNetworkChanges( |
| alternative_service, network_anonymization_key1_); |
| EXPECT_TRUE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| properties.MarkAlternativeServiceBrokenUntilDefaultNetworkChanges( |
| alternative_service, network_anonymization_key2_); |
| EXPECT_TRUE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| properties.ConfirmAlternativeService(alternative_service, |
| network_anonymization_key1_); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| properties.ConfirmAlternativeService(alternative_service, |
| network_anonymization_key2_); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, OnDefaultNetworkChanged) { |
| url::SchemeHostPort server("http", "foo", 80); |
| const AlternativeService alternative_service(kProtoHTTP2, "foo", 443); |
| |
| SetAlternativeService(server, alternative_service); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| impl_.MarkAlternativeServiceBrokenUntilDefaultNetworkChanges( |
| alternative_service, NetworkAnonymizationKey()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| // Default network change clears alt svc broken until default network changes. |
| impl_.OnDefaultNetworkChanged(); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| impl_.MarkAlternativeServiceBrokenUntilDefaultNetworkChanges( |
| alternative_service, NetworkAnonymizationKey()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| impl_.MarkAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| // Default network change doesn't affect alt svc that was simply marked broken |
| // most recently. |
| impl_.OnDefaultNetworkChanged(); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| impl_.MarkAlternativeServiceBrokenUntilDefaultNetworkChanges( |
| alternative_service, NetworkAnonymizationKey()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| // Default network change clears alt svc that was marked broken until default |
| // network change most recently even if the alt svc was initially marked |
| // broken. |
| impl_.OnDefaultNetworkChanged(); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, |
| OnDefaultNetworkChangedWithNetworkIsolationKey) { |
| url::SchemeHostPort server("http", "foo", 80); |
| const AlternativeService alternative_service(kProtoHTTP2, "foo", 443); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| // Since HttpServerProperties caches the feature value, have to create a new |
| // one. |
| HttpServerProperties properties(nullptr /* pref_delegate */, |
| nullptr /* net_log */, test_tick_clock_, |
| &test_clock_); |
| |
| const base::Time expiration = test_clock_.Now() + base::Days(1); |
| properties.SetHttp2AlternativeService(server, network_anonymization_key1_, |
| alternative_service, expiration); |
| properties.SetHttp2AlternativeService(server, network_anonymization_key2_, |
| alternative_service, expiration); |
| |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| properties.MarkAlternativeServiceBrokenUntilDefaultNetworkChanges( |
| alternative_service, network_anonymization_key1_); |
| properties.MarkAlternativeServiceBrokenUntilDefaultNetworkChanges( |
| alternative_service, network_anonymization_key2_); |
| EXPECT_TRUE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| // Default network change clears alt svc broken until default network changes. |
| properties.OnDefaultNetworkChanged(); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, Canonical) { |
| url::SchemeHostPort test_server("https", "foo.c.youtube.com", 443); |
| EXPECT_FALSE(HasAlternativeService(test_server, NetworkAnonymizationKey())); |
| |
| url::SchemeHostPort canonical_server("https", "bar.c.youtube.com", 443); |
| EXPECT_FALSE( |
| HasAlternativeService(canonical_server, NetworkAnonymizationKey())); |
| |
| AlternativeServiceInfoVector alternative_service_info_vector; |
| const AlternativeService canonical_alternative_service1( |
| kProtoQUIC, "bar.c.youtube.com", 1234); |
| base::Time expiration = test_clock_.Now() + base::Days(1); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( |
| canonical_alternative_service1, expiration, |
| DefaultSupportedQuicVersions())); |
| const AlternativeService canonical_alternative_service2(kProtoHTTP2, "", 443); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| canonical_alternative_service2, expiration)); |
| impl_.SetAlternativeServices(canonical_server, NetworkAnonymizationKey(), |
| alternative_service_info_vector); |
| |
| // Since |test_server| does not have an alternative service itself, |
| // GetAlternativeServiceInfos should return those of |canonical_server|. |
| AlternativeServiceInfoVector alternative_service_info_vector2 = |
| impl_.GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(2u, alternative_service_info_vector2.size()); |
| EXPECT_EQ(canonical_alternative_service1, |
| alternative_service_info_vector2[0].alternative_service()); |
| |
| // Since |canonical_alternative_service2| has an empty host, |
| // GetAlternativeServiceInfos should substitute the hostname of its |origin| |
| // argument. |
| EXPECT_EQ(test_server.host(), |
| alternative_service_info_vector2[1].alternative_service().host); |
| EXPECT_EQ(canonical_alternative_service2.protocol, |
| alternative_service_info_vector2[1].alternative_service().protocol); |
| EXPECT_EQ(canonical_alternative_service2.port, |
| alternative_service_info_vector2[1].alternative_service().port); |
| |
| // Verify the canonical suffix. |
| EXPECT_EQ(".c.youtube.com", |
| *impl_.GetCanonicalSuffixForTesting(test_server.host())); |
| EXPECT_EQ(".c.youtube.com", |
| *impl_.GetCanonicalSuffixForTesting(canonical_server.host())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, ClearCanonical) { |
| url::SchemeHostPort test_server("https", "foo.c.youtube.com", 443); |
| url::SchemeHostPort canonical_server("https", "bar.c.youtube.com", 443); |
| AlternativeService canonical_alternative_service(kProtoQUIC, |
| "bar.c.youtube.com", 1234); |
| |
| SetAlternativeService(canonical_server, canonical_alternative_service); |
| impl_.SetAlternativeServices(canonical_server, NetworkAnonymizationKey(), |
| AlternativeServiceInfoVector()); |
| EXPECT_FALSE(HasAlternativeService(test_server, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, |
| CanonicalWithNetworkIsolationKey) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| // Since HttpServerProperties caches the feature value, have to create a new |
| // one. |
| HttpServerProperties properties(nullptr /* pref_delegate */, |
| nullptr /* net_log */, test_tick_clock_, |
| &test_clock_); |
| |
| url::SchemeHostPort test_server("https", "foo.c.youtube.com", 443); |
| EXPECT_FALSE(HasAlternativeService(test_server, network_anonymization_key1_)); |
| |
| url::SchemeHostPort canonical_server1("https", "bar.c.youtube.com", 443); |
| EXPECT_FALSE( |
| HasAlternativeService(canonical_server1, network_anonymization_key1_)); |
| |
| AlternativeServiceInfoVector alternative_service_info_vector; |
| const AlternativeService canonical_alternative_service1( |
| kProtoQUIC, "bar.c.youtube.com", 1234); |
| base::Time expiration = test_clock_.Now() + base::Days(1); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( |
| canonical_alternative_service1, expiration, |
| DefaultSupportedQuicVersions())); |
| const AlternativeService canonical_alternative_service2(kProtoHTTP2, "", 443); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| canonical_alternative_service2, expiration)); |
| properties.SetAlternativeServices(canonical_server1, |
| network_anonymization_key1_, |
| alternative_service_info_vector); |
| |
| // Since |test_server| does not have an alternative service itself, |
| // GetAlternativeServiceInfos should return those of |canonical_server|. |
| AlternativeServiceInfoVector alternative_service_info_vector2 = |
| properties.GetAlternativeServiceInfos(test_server, |
| network_anonymization_key1_); |
| ASSERT_EQ(2u, alternative_service_info_vector2.size()); |
| EXPECT_EQ(canonical_alternative_service1, |
| alternative_service_info_vector2[0].alternative_service()); |
| |
| // Canonical information should not be visible for other NetworkIsolationKeys. |
| EXPECT_TRUE( |
| properties |
| .GetAlternativeServiceInfos(test_server, network_anonymization_key2_) |
| .empty()); |
| EXPECT_TRUE( |
| properties |
| .GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()) |
| .empty()); |
| |
| // Now add an alternative service entry for network_anonymization_key2_ for a |
| // different server and different NetworkAnonymizationKey, but with the same |
| // canonical suffix. |
| url::SchemeHostPort canonical_server2("https", "shrimp.c.youtube.com", 443); |
| properties.SetAlternativeServices(canonical_server2, |
| network_anonymization_key2_, |
| {alternative_service_info_vector[0]}); |
| |
| // The canonical server information should reachable, and different, for both |
| // NetworkIsolationKeys. |
| EXPECT_EQ(1u, properties |
| .GetAlternativeServiceInfos(test_server, |
| network_anonymization_key2_) |
| .size()); |
| EXPECT_EQ(2u, properties |
| .GetAlternativeServiceInfos(test_server, |
| network_anonymization_key1_) |
| .size()); |
| EXPECT_TRUE( |
| properties |
| .GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()) |
| .empty()); |
| |
| // Clearing the alternate service state of network_anonymization_key1_'s |
| // canonical server should only affect network_anonymization_key1_. |
| properties.SetAlternativeServices(canonical_server1, |
| network_anonymization_key1_, {}); |
| EXPECT_EQ(1u, properties |
| .GetAlternativeServiceInfos(test_server, |
| network_anonymization_key2_) |
| .size()); |
| EXPECT_TRUE( |
| properties |
| .GetAlternativeServiceInfos(test_server, network_anonymization_key1_) |
| .empty()); |
| EXPECT_TRUE( |
| properties |
| .GetAlternativeServiceInfos(test_server, NetworkAnonymizationKey()) |
| .empty()); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, CanonicalBroken) { |
| url::SchemeHostPort test_server("https", "foo.c.youtube.com", 443); |
| url::SchemeHostPort canonical_server("https", "bar.c.youtube.com", 443); |
| AlternativeService canonical_alternative_service(kProtoQUIC, |
| "bar.c.youtube.com", 1234); |
| |
| SetAlternativeService(canonical_server, canonical_alternative_service); |
| EXPECT_TRUE(HasAlternativeService(test_server, NetworkAnonymizationKey())); |
| impl_.MarkAlternativeServiceBroken(canonical_alternative_service, |
| NetworkAnonymizationKey()); |
| EXPECT_FALSE(HasAlternativeService(test_server, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, |
| CanonicalBrokenUntilDefaultNetworkChanges) { |
| url::SchemeHostPort test_server("https", "foo.c.youtube.com", 443); |
| url::SchemeHostPort canonical_server("https", "bar.c.youtube.com", 443); |
| AlternativeService canonical_alternative_service(kProtoQUIC, |
| "bar.c.youtube.com", 1234); |
| |
| SetAlternativeService(canonical_server, canonical_alternative_service); |
| EXPECT_TRUE(HasAlternativeService(test_server, NetworkAnonymizationKey())); |
| impl_.MarkAlternativeServiceBrokenUntilDefaultNetworkChanges( |
| canonical_alternative_service, NetworkAnonymizationKey()); |
| EXPECT_FALSE(HasAlternativeService(test_server, NetworkAnonymizationKey())); |
| } |
| |
| // Adding an alternative service for a new host overrides canonical host. |
| TEST_F(AlternateProtocolServerPropertiesTest, CanonicalOverride) { |
| url::SchemeHostPort foo_server("https", "foo.c.youtube.com", 443); |
| url::SchemeHostPort bar_server("https", "bar.c.youtube.com", 443); |
| AlternativeService bar_alternative_service(kProtoQUIC, "bar.c.youtube.com", |
| 1234); |
| SetAlternativeService(bar_server, bar_alternative_service); |
| AlternativeServiceInfoVector alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(foo_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(bar_alternative_service, |
| alternative_service_info_vector[0].alternative_service()); |
| |
| url::SchemeHostPort qux_server("https", "qux.c.youtube.com", 443); |
| AlternativeService qux_alternative_service(kProtoQUIC, "qux.c.youtube.com", |
| 443); |
| SetAlternativeService(qux_server, qux_alternative_service); |
| alternative_service_info_vector = |
| impl_.GetAlternativeServiceInfos(foo_server, NetworkAnonymizationKey()); |
| ASSERT_EQ(1u, alternative_service_info_vector.size()); |
| EXPECT_EQ(qux_alternative_service, |
| alternative_service_info_vector[0].alternative_service()); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, ClearWithCanonical) { |
| url::SchemeHostPort test_server("https", "foo.c.youtube.com", 443); |
| url::SchemeHostPort canonical_server("https", "bar.c.youtube.com", 443); |
| AlternativeService canonical_alternative_service(kProtoQUIC, |
| "bar.c.youtube.com", 1234); |
| |
| SetAlternativeService(canonical_server, canonical_alternative_service); |
| impl_.Clear(base::OnceClosure()); |
| EXPECT_FALSE(HasAlternativeService(test_server, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, |
| ExpireBrokenAlternateProtocolMappings) { |
| url::SchemeHostPort server("https", "foo", 443); |
| AlternativeService alternative_service(kProtoQUIC, "foo", 443); |
| SetAlternativeService(server, alternative_service); |
| EXPECT_TRUE(HasAlternativeService(server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| base::TimeTicks past = test_tick_clock_->NowTicks() - base::Seconds(42); |
| HttpServerPropertiesPeer::AddBrokenAlternativeServiceWithExpirationTime( |
| &impl_, alternative_service, past); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| |
| HttpServerPropertiesPeer::ExpireBrokenAlternateProtocolMappings(&impl_); |
| EXPECT_FALSE(HasAlternativeService(server, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| alternative_service, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, |
| ExpireBrokenAlternateProtocolMappingsWithNetworkIsolationKey) { |
| url::SchemeHostPort server("https", "foo", 443); |
| AlternativeService alternative_service(kProtoHTTP2, "foo", 444); |
| base::TimeTicks past = test_tick_clock_->NowTicks() - base::Seconds(42); |
| base::TimeTicks future = test_tick_clock_->NowTicks() + base::Seconds(42); |
| const base::Time alt_service_expiration = test_clock_.Now() + base::Days(1); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| // Since HttpServerProperties caches the feature value, have to create a new |
| // one. |
| HttpServerProperties properties(nullptr /* pref_delegate */, |
| nullptr /* net_log */, test_tick_clock_, |
| &test_clock_); |
| |
| properties.SetHttp2AlternativeService(server, network_anonymization_key1_, |
| alternative_service, |
| alt_service_expiration); |
| properties.SetHttp2AlternativeService(server, network_anonymization_key2_, |
| alternative_service, |
| alt_service_expiration); |
| |
| EXPECT_FALSE( |
| properties.GetAlternativeServiceInfos(server, network_anonymization_key1_) |
| .empty()); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE( |
| properties.GetAlternativeServiceInfos(server, network_anonymization_key2_) |
| .empty()); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| // Set broken alternative service with expiration date in the past for |
| // |network_anonymization_key1_|. |
| HttpServerPropertiesPeer::AddBrokenAlternativeServiceWithExpirationTime( |
| &properties, alternative_service, past, network_anonymization_key1_); |
| EXPECT_TRUE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_FALSE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| // Set broken alternative service with expiration date in the future for |
| // |network_anonymization_key1_|. |
| HttpServerPropertiesPeer::AddBrokenAlternativeServiceWithExpirationTime( |
| &properties, alternative_service, future, network_anonymization_key2_); |
| EXPECT_TRUE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| |
| // Only the broken entry for |network_anonymization_key1_| should be expired. |
| HttpServerPropertiesPeer::ExpireBrokenAlternateProtocolMappings(&properties); |
| EXPECT_TRUE( |
| properties.GetAlternativeServiceInfos(server, network_anonymization_key1_) |
| .empty()); |
| EXPECT_FALSE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key1_)); |
| EXPECT_FALSE( |
| properties.GetAlternativeServiceInfos(server, network_anonymization_key2_) |
| .empty()); |
| EXPECT_TRUE(properties.IsAlternativeServiceBroken( |
| alternative_service, network_anonymization_key2_)); |
| EXPECT_TRUE(properties.WasAlternativeServiceRecentlyBroken( |
| alternative_service, network_anonymization_key2_)); |
| } |
| |
| // Regression test for https://crbug.com/505413. |
| TEST_F(AlternateProtocolServerPropertiesTest, RemoveExpiredBrokenAltSvc) { |
| url::SchemeHostPort foo_server("https", "foo", 443); |
| AlternativeService bar_alternative_service(kProtoQUIC, "bar", 443); |
| SetAlternativeService(foo_server, bar_alternative_service); |
| EXPECT_TRUE(HasAlternativeService(foo_server, NetworkAnonymizationKey())); |
| |
| url::SchemeHostPort bar_server1("http", "bar", 80); |
| AlternativeService nohost_alternative_service(kProtoQUIC, "", 443); |
| SetAlternativeService(bar_server1, nohost_alternative_service); |
| EXPECT_TRUE(HasAlternativeService(bar_server1, NetworkAnonymizationKey())); |
| |
| url::SchemeHostPort bar_server2("https", "bar", 443); |
| AlternativeService baz_alternative_service(kProtoQUIC, "baz", 1234); |
| SetAlternativeService(bar_server2, baz_alternative_service); |
| EXPECT_TRUE(HasAlternativeService(bar_server2, NetworkAnonymizationKey())); |
| |
| // Mark "bar:443" as broken. |
| base::TimeTicks past = test_tick_clock_->NowTicks() - base::Seconds(42); |
| HttpServerPropertiesPeer::AddBrokenAlternativeServiceWithExpirationTime( |
| &impl_, bar_alternative_service, past); |
| |
| // Expire brokenness of "bar:443". |
| HttpServerPropertiesPeer::ExpireBrokenAlternateProtocolMappings(&impl_); |
| |
| // "foo:443" should have no alternative service now. |
| EXPECT_FALSE(HasAlternativeService(foo_server, NetworkAnonymizationKey())); |
| // "bar:80" should have no alternative service now. |
| EXPECT_FALSE(HasAlternativeService(bar_server1, NetworkAnonymizationKey())); |
| // The alternative service of "bar:443" should be unaffected. |
| EXPECT_TRUE(HasAlternativeService(bar_server2, NetworkAnonymizationKey())); |
| |
| EXPECT_TRUE(impl_.WasAlternativeServiceRecentlyBroken( |
| bar_alternative_service, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.WasAlternativeServiceRecentlyBroken( |
| baz_alternative_service, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, |
| SetBrokenAlternativeServicesDelayParams1) { |
| url::SchemeHostPort server("https", "foo", 443); |
| AlternativeService alternative_service(kProtoQUIC, "foo", 443); |
| SetAlternativeService(server, alternative_service); |
| |
| const base::TimeDelta initial_delay = base::Seconds(1); |
| impl_.SetBrokenAlternativeServicesDelayParams(initial_delay, true); |
| for (int i = 0; i < 10; ++i) { |
| impl_.MarkAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey()); |
| // |impl_| should have posted task to expire the brokenness of |
| // |alternative_service| |
| EXPECT_EQ(1u, GetPendingMainThreadTaskCount()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| |
| // Advance time by just enough so that |alternative_service|'s brokenness |
| // expires. |
| FastForwardBy(initial_delay * (1 << i)); |
| |
| // Ensure brokenness of |alternative_service| has expired. |
| EXPECT_EQ(0u, GetPendingMainThreadTaskCount()); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| } |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, |
| SetBrokenAlternativeServicesDelayParams2) { |
| url::SchemeHostPort server("https", "foo", 443); |
| AlternativeService alternative_service(kProtoQUIC, "foo", 443); |
| SetAlternativeService(server, alternative_service); |
| |
| const base::TimeDelta initial_delay = base::Seconds(5); |
| impl_.SetBrokenAlternativeServicesDelayParams(initial_delay, false); |
| for (int i = 0; i < 10; ++i) { |
| impl_.MarkAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey()); |
| // |impl_| should have posted task to expire the brokenness of |
| // |alternative_service| |
| EXPECT_EQ(1u, GetPendingMainThreadTaskCount()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| |
| // Advance time by just enough so that |alternative_service|'s brokenness |
| // expires. |
| if (i == 0) { |
| FastForwardBy(initial_delay); |
| } else { |
| FastForwardBy(base::Seconds(300) * (1 << (i - 1))); |
| } |
| |
| // Ensure brokenness of |alternative_service| has expired. |
| EXPECT_EQ(0u, GetPendingMainThreadTaskCount()); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service, |
| NetworkAnonymizationKey())); |
| } |
| } |
| |
| // Regression test for https://crbug.com/724302 |
| TEST_F(AlternateProtocolServerPropertiesTest, RemoveExpiredBrokenAltSvc2) { |
| // This test will mark an alternative service A that has already been marked |
| // broken many times, then immediately mark another alternative service B as |
| // broken for the first time. Because A's been marked broken many times |
| // already, its brokenness will be scheduled to expire much further in the |
| // future than B, even though it was marked broken before B. This test makes |
| // sure that even though A was marked broken before B, B's brokenness should |
| // expire before A. |
| |
| url::SchemeHostPort server1("https", "foo", 443); |
| AlternativeService alternative_service1(kProtoQUIC, "foo", 443); |
| SetAlternativeService(server1, alternative_service1); |
| |
| url::SchemeHostPort server2("https", "bar", 443); |
| AlternativeService alternative_service2(kProtoQUIC, "bar", 443); |
| SetAlternativeService(server2, alternative_service2); |
| |
| // Repeatedly mark alt svc 1 broken and wait for its brokenness to expire. |
| // This will increase its time until expiration. |
| for (int i = 0; i < 3; ++i) { |
| impl_.MarkAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey()); |
| |
| // |impl_| should have posted task to expire the brokenness of |
| // |alternative_service1| |
| EXPECT_EQ(1u, GetPendingMainThreadTaskCount()); |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey())); |
| |
| // Advance time by just enough so that |alternative_service1|'s brokenness |
| // expires. |
| FastForwardBy(BROKEN_ALT_SVC_EXPIRE_DELAYS[i]); |
| |
| // Ensure brokenness of |alternative_service1| has expired. |
| EXPECT_EQ(0u, GetPendingMainThreadTaskCount()); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey())); |
| } |
| |
| impl_.MarkAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey()); |
| impl_.MarkAlternativeServiceBroken(alternative_service2, |
| NetworkAnonymizationKey()); |
| |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service2, |
| NetworkAnonymizationKey())); |
| |
| // Advance time by just enough so that |alternative_service2|'s brokennness |
| // expires. |
| FastForwardBy(BROKEN_ALT_SVC_EXPIRE_DELAYS[0]); |
| |
| EXPECT_TRUE(impl_.IsAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service2, |
| NetworkAnonymizationKey())); |
| |
| // Advance time by enough so that |alternative_service1|'s brokenness expires. |
| FastForwardBy(BROKEN_ALT_SVC_EXPIRE_DELAYS[3] - |
| BROKEN_ALT_SVC_EXPIRE_DELAYS[0]); |
| |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service1, |
| NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.IsAlternativeServiceBroken(alternative_service2, |
| NetworkAnonymizationKey())); |
| } |
| |
| // Regression test for https://crbug.com/994537. Having a ServerInfo entry |
| // without a populated |alternative_services| value would cause |
| // OnExpireBrokenAlternativeService() to hang.. |
| TEST_F(AlternateProtocolServerPropertiesTest, RemoveExpiredBrokenAltSvc3) { |
| // Add an altertive service entry. |
| const url::SchemeHostPort kServer1("https", "foo", 443); |
| const AlternativeService kAltService(kProtoQUIC, "bar", 443); |
| SetAlternativeService(kServer1, kAltService); |
| EXPECT_TRUE(HasAlternativeService(kServer1, NetworkAnonymizationKey())); |
| |
| // Add an entry to ServerInfo for another server, without an alternative |
| // service value. |
| const url::SchemeHostPort kServer2("http", "bar", 80); |
| impl_.SetSupportsSpdy(kServer2, NetworkAnonymizationKey(), false); |
| |
| // Mark kAltService as broken. |
| base::TimeTicks past = test_tick_clock_->NowTicks() - base::Seconds(42); |
| HttpServerPropertiesPeer::AddBrokenAlternativeServiceWithExpirationTime( |
| &impl_, kAltService, past); |
| |
| // Expire brokenness of kAltService. This call should not hang. |
| HttpServerPropertiesPeer::ExpireBrokenAlternateProtocolMappings(&impl_); |
| |
| EXPECT_FALSE(HasAlternativeService(kServer1, NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(AlternateProtocolServerPropertiesTest, |
| GetAlternativeServiceInfoAsValue) { |
| base::Time::Exploded now_exploded; |
| now_exploded.year = 2018; |
| now_exploded.month = 1; |
| now_exploded.day_of_week = 3; |
| now_exploded.day_of_month = 24; |
| now_exploded.hour = 15; |
| now_exploded.minute = 12; |
| now_exploded.second = 53; |
| now_exploded.millisecond = 0; |
| base::Time now; |
| bool result = base::Time::FromLocalExploded(now_exploded, &now); |
| DCHECK(result); |
| test_clock_.SetNow(now); |
| |
| AlternativeServiceInfoVector alternative_service_info_vector; |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| AlternativeService(kProtoHTTP2, "foo", 443), now + base::Minutes(1))); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( |
| AlternativeService(kProtoQUIC, "bar", 443), now + base::Hours(1), |
| DefaultSupportedQuicVersions())); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( |
| AlternativeService(kProtoQUIC, "baz", 443), now + base::Hours(1), |
| DefaultSupportedQuicVersions())); |
| |
| impl_.SetAlternativeServices(url::SchemeHostPort("https", "youtube.com", 443), |
| NetworkAnonymizationKey(), |
| alternative_service_info_vector); |
| |
| impl_.MarkAlternativeServiceBroken(AlternativeService(kProtoQUIC, "bar", 443), |
| NetworkAnonymizationKey()); |
| |
| impl_.MarkAlternativeServiceBrokenUntilDefaultNetworkChanges( |
| AlternativeService(kProtoQUIC, "baz", 443), NetworkAnonymizationKey()); |
| |
| alternative_service_info_vector.clear(); |
| alternative_service_info_vector.push_back( |
| AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( |
| AlternativeService(kProtoHTTP2, "foo2", 443), now + base::Days(1))); |
| impl_.SetAlternativeServices(url::SchemeHostPort("http", "test.com", 80), |
| NetworkAnonymizationKey(), |
| alternative_service_info_vector); |
| |
| const char expected_json[] = |
| "[" |
| "{" |
| "\"alternative_service\":" |
| "[\"h2 foo2:443, expires 2018-01-25 15:12:53\"]," |
| "\"network_anonymization_key\":\"null\"," |
| "\"server\":\"http://test.com\"" |
| "}," |
| "{" |
| "\"alternative_service\":" |
| "[\"h2 foo:443, expires 2018-01-24 15:13:53\"," |
| "\"quic bar:443, expires 2018-01-24 16:12:53" |
| " (broken until 2018-01-24 15:17:53)\"," |
| "\"quic baz:443, expires 2018-01-24 16:12:53" |
| " (broken until 2018-01-24 15:17:53)\"]," |
| "\"network_anonymization_key\":\"null\"," |
| "\"server\":\"https://youtube.com\"" |
| "}" |
| "]"; |
| |
| base::Value alternative_service_info_value = |
| impl_.GetAlternativeServiceInfoAsValue(); |
| std::string alternative_service_info_json; |
| base::JSONWriter::Write(alternative_service_info_value, |
| &alternative_service_info_json); |
| EXPECT_EQ(expected_json, alternative_service_info_json); |
| } |
| |
| TEST_F(HttpServerPropertiesTest, LoadLastLocalAddressWhenQuicWorked) { |
| const IPAddress kEmptyAddress; |
| const IPAddress kValidAddress1 = IPAddress::IPv4Localhost(); |
| const IPAddress kValidAddress2 = IPAddress::IPv6Localhost(); |
| |
| // Check by initializing empty address. |
| impl_.OnLastLocalAddressWhenQuicWorkedForTesting(kEmptyAddress); |
| EXPECT_FALSE(impl_.HasLastLocalAddressWhenQuicWorked()); |
| // Empty address should not be considered an address that was used when QUIC |
| // worked. |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kEmptyAddress)); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress1)); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress2)); |
| |
| // Check by initializing with a valid address. |
| impl_.OnLastLocalAddressWhenQuicWorkedForTesting(kValidAddress1); |
| EXPECT_TRUE(impl_.HasLastLocalAddressWhenQuicWorked()); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kEmptyAddress)); |
| EXPECT_TRUE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress1)); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress2)); |
| |
| // Try another valid address. |
| impl_.OnLastLocalAddressWhenQuicWorkedForTesting(kValidAddress2); |
| EXPECT_TRUE(impl_.HasLastLocalAddressWhenQuicWorked()); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kEmptyAddress)); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress1)); |
| EXPECT_TRUE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress2)); |
| |
| // And loading an empty address clears the current one. |
| // TODO(mmenke): This seems like a bug, since if we've learned the current |
| // network supports QUIC, surely we want to save that to disk? Seems like a |
| // pre-existing value should take precedence, if non-empty, since if the |
| // current network is already known to support QUIC, the loaded value is no |
| // longer relevant. |
| impl_.OnLastLocalAddressWhenQuicWorkedForTesting(kEmptyAddress); |
| EXPECT_FALSE(impl_.HasLastLocalAddressWhenQuicWorked()); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kEmptyAddress)); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress1)); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress2)); |
| } |
| |
| TEST_F(HttpServerPropertiesTest, SetLastLocalAddressWhenQuicWorked) { |
| const IPAddress kEmptyAddress; |
| const IPAddress kValidAddress1 = IPAddress::IPv4Localhost(); |
| const IPAddress kValidAddress2 = IPAddress::IPv6Localhost(); |
| |
| EXPECT_FALSE(impl_.HasLastLocalAddressWhenQuicWorked()); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kEmptyAddress)); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress1)); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress2)); |
| |
| // Set to a valid address. |
| impl_.SetLastLocalAddressWhenQuicWorked(kValidAddress1); |
| EXPECT_TRUE(impl_.HasLastLocalAddressWhenQuicWorked()); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kEmptyAddress)); |
| EXPECT_TRUE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress1)); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress2)); |
| |
| // Clear only this value. |
| impl_.ClearLastLocalAddressWhenQuicWorked(); |
| EXPECT_FALSE(impl_.HasLastLocalAddressWhenQuicWorked()); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kEmptyAddress)); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress1)); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress2)); |
| |
| // Try another valid address. |
| impl_.SetLastLocalAddressWhenQuicWorked(kValidAddress2); |
| EXPECT_TRUE(impl_.HasLastLocalAddressWhenQuicWorked()); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kEmptyAddress)); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress1)); |
| EXPECT_TRUE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress2)); |
| |
| // Clear all values. |
| impl_.Clear(base::OnceClosure()); |
| EXPECT_FALSE(impl_.HasLastLocalAddressWhenQuicWorked()); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kEmptyAddress)); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress1)); |
| EXPECT_FALSE(impl_.WasLastLocalAddressWhenQuicWorked(kValidAddress2)); |
| } |
| |
| TEST_F(HttpServerPropertiesTest, LoadServerNetworkStats) { |
| url::SchemeHostPort google_server("https", "www.google.com", 443); |
| |
| // Check by initializing empty ServerNetworkStats. |
| std::unique_ptr<HttpServerProperties::ServerInfoMap> load_server_info_map = |
| std::make_unique<HttpServerProperties::ServerInfoMap>(); |
| impl_.OnServerInfoLoadedForTesting(std::move(load_server_info_map)); |
| const ServerNetworkStats* stats = |
| impl_.GetServerNetworkStats(google_server, NetworkAnonymizationKey()); |
| EXPECT_EQ(nullptr, stats); |
| |
| // Check by initializing with www.google.com:443. |
| ServerNetworkStats stats_google; |
| stats_google.srtt = base::Microseconds(10); |
| stats_google.bandwidth_estimate = quic::QuicBandwidth::FromBitsPerSecond(100); |
| load_server_info_map = |
| std::make_unique<HttpServerProperties::ServerInfoMap>(); |
| load_server_info_map->GetOrPut(CreateSimpleKey(google_server)) |
| ->second.server_network_stats = stats_google; |
| impl_.OnServerInfoLoadedForTesting(std::move(load_server_info_map)); |
| |
| // Verify data for www.google.com:443. |
| ASSERT_EQ(1u, impl_.server_info_map_for_testing().size()); |
| EXPECT_EQ(stats_google, *(impl_.GetServerNetworkStats( |
| google_server, NetworkAnonymizationKey()))); |
| |
| // Test recency order and overwriting of data. |
| // |
| // |docs_server| has a ServerNetworkStats, which will be overwritten by |
| // OnServerInfoLoadedForTesting(), because |server_network_stats_map| has an |
| // entry for |docs_server|. |
| url::SchemeHostPort docs_server("https", "docs.google.com", 443); |
| ServerNetworkStats stats_docs; |
| stats_docs.srtt = base::Microseconds(20); |
| stats_docs.bandwidth_estimate = quic::QuicBandwidth::FromBitsPerSecond(200); |
| // Recency order will be |docs_server| and |google_server|. |
| impl_.SetServerNetworkStats(docs_server, NetworkAnonymizationKey(), |
| stats_docs); |
| |
| // Prepare |server_info_map| to be loaded by OnServerInfoLoadedForTesting(). |
| std::unique_ptr<HttpServerProperties::ServerInfoMap> server_info_map = |
| std::make_unique<HttpServerProperties::ServerInfoMap>(); |
| |
| // Change the values for |docs_server|. |
| ServerNetworkStats new_stats_docs; |
| new_stats_docs.srtt = base::Microseconds(25); |
| new_stats_docs.bandwidth_estimate = |
| quic::QuicBandwidth::FromBitsPerSecond(250); |
| server_info_map->GetOrPut(CreateSimpleKey(docs_server)) |
| ->second.server_network_stats = new_stats_docs; |
| // Add data for mail.google.com:443. |
| url::SchemeHostPort mail_server("https", "mail.google.com", 443); |
| ServerNetworkStats stats_mail; |
| stats_mail.srtt = base::Microseconds(30); |
| stats_mail.bandwidth_estimate = quic::QuicBandwidth::FromBitsPerSecond(300); |
| server_info_map->GetOrPut(CreateSimpleKey(mail_server)) |
| ->second.server_network_stats = stats_mail; |
| |
| // Recency order will be |docs_server|, |google_server| and |mail_server|. |
| impl_.OnServerInfoLoadedForTesting(std::move(server_info_map)); |
| |
| const HttpServerProperties::ServerInfoMap& map = |
| impl_.server_info_map_for_testing(); |
| ASSERT_EQ(3u, map.size()); |
| auto map_it = map.begin(); |
| |
| EXPECT_EQ(docs_server, map_it->first.server); |
| EXPECT_TRUE(map_it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(map_it->second.server_network_stats.has_value()); |
| EXPECT_EQ(new_stats_docs, *map_it->second.server_network_stats); |
| ++map_it; |
| EXPECT_EQ(google_server, map_it->first.server); |
| EXPECT_TRUE(map_it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(map_it->second.server_network_stats.has_value()); |
| EXPECT_EQ(stats_google, *map_it->second.server_network_stats); |
| ++map_it; |
| EXPECT_EQ(mail_server, map_it->first.server); |
| EXPECT_TRUE(map_it->first.network_anonymization_key.IsEmpty()); |
| ASSERT_TRUE(map_it->second.server_network_stats.has_value()); |
| EXPECT_EQ(stats_mail, *map_it->second.server_network_stats); |
| } |
| |
| TEST_F(HttpServerPropertiesTest, SetServerNetworkStats) { |
| url::SchemeHostPort foo_http_server("http", "foo", 443); |
| url::SchemeHostPort foo_https_server("https", "foo", 443); |
| EXPECT_EQ(nullptr, impl_.GetServerNetworkStats(foo_http_server, |
| NetworkAnonymizationKey())); |
| EXPECT_EQ(nullptr, impl_.GetServerNetworkStats(foo_https_server, |
| NetworkAnonymizationKey())); |
| |
| ServerNetworkStats stats1; |
| stats1.srtt = base::Microseconds(10); |
| stats1.bandwidth_estimate = quic::QuicBandwidth::FromBitsPerSecond(100); |
| impl_.SetServerNetworkStats(foo_http_server, NetworkAnonymizationKey(), |
| stats1); |
| |
| const ServerNetworkStats* stats2 = |
| impl_.GetServerNetworkStats(foo_http_server, NetworkAnonymizationKey()); |
| EXPECT_EQ(10, stats2->srtt.ToInternalValue()); |
| EXPECT_EQ(100, stats2->bandwidth_estimate.ToBitsPerSecond()); |
| // Https server should have nothing set for server network stats. |
| EXPECT_EQ(nullptr, impl_.GetServerNetworkStats(foo_https_server, |
| NetworkAnonymizationKey())); |
| |
| impl_.Clear(base::OnceClosure()); |
| EXPECT_EQ(nullptr, impl_.GetServerNetworkStats(foo_http_server, |
| NetworkAnonymizationKey())); |
| EXPECT_EQ(nullptr, impl_.GetServerNetworkStats(foo_https_server, |
| NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesTest, ClearServerNetworkStats) { |
| ServerNetworkStats stats; |
| stats.srtt = base::Microseconds(10); |
| stats.bandwidth_estimate = quic::QuicBandwidth::FromBitsPerSecond(100); |
| url::SchemeHostPort foo_https_server("https", "foo", 443); |
| impl_.SetServerNetworkStats(foo_https_server, NetworkAnonymizationKey(), |
| stats); |
| |
| impl_.ClearServerNetworkStats(foo_https_server, NetworkAnonymizationKey()); |
| EXPECT_EQ(nullptr, impl_.GetServerNetworkStats(foo_https_server, |
| NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesTest, OnQuicServerInfoMapLoaded) { |
| quic::QuicServerId google_quic_server_id("www.google.com", 443, true); |
| HttpServerProperties::QuicServerInfoMapKey google_key( |
| google_quic_server_id, NetworkAnonymizationKey(), |
| false /* use_network_anonymization_key */); |
| |
| const int kMaxQuicServerEntries = 10; |
| impl_.SetMaxServerConfigsStoredInProperties(kMaxQuicServerEntries); |
| EXPECT_EQ(10u, impl_.quic_server_info_map().max_size()); |
| |
| // Check empty map. |
| std::unique_ptr<HttpServerProperties::QuicServerInfoMap> |
| init_quic_server_info_map = |
| std::make_unique<HttpServerProperties::QuicServerInfoMap>( |
| kMaxQuicServerEntries); |
| impl_.OnQuicServerInfoMapLoadedForTesting( |
| std::move(init_quic_server_info_map)); |
| EXPECT_EQ(0u, impl_.quic_server_info_map().size()); |
| |
| // Check by initializing with www.google.com:443. |
| std::string google_server_info("google_quic_server_info"); |
| init_quic_server_info_map = |
| std::make_unique<HttpServerProperties::QuicServerInfoMap>( |
| kMaxQuicServerEntries); |
| init_quic_server_info_map->Put(google_key, google_server_info); |
| impl_.OnQuicServerInfoMapLoadedForTesting( |
| std::move(init_quic_server_info_map)); |
| |
| // Verify data for www.google.com:443. |
| EXPECT_EQ(1u, impl_.quic_server_info_map().size()); |
| EXPECT_EQ(google_server_info, |
| *impl_.GetQuicServerInfo(google_quic_server_id, |
| NetworkAnonymizationKey())); |
| |
| // Test recency order and overwriting of data. |
| // |
| // |docs_server| has a QuicServerInfo, which will be overwritten by |
| // SetQuicServerInfoMap(), because |quic_server_info_map| has an |
| // entry for |docs_server|. |
| quic::QuicServerId docs_quic_server_id("docs.google.com", 443, true); |
| HttpServerProperties::QuicServerInfoMapKey docs_key( |
| docs_quic_server_id, NetworkAnonymizationKey(), |
| false /* use_network_anonymization_key */); |
| std::string docs_server_info("docs_quic_server_info"); |
| impl_.SetQuicServerInfo(docs_quic_server_id, NetworkAnonymizationKey(), |
| docs_server_info); |
| |
| // Recency order will be |docs_server| and |google_server|. |
| const HttpServerProperties::QuicServerInfoMap& map = |
| impl_.quic_server_info_map(); |
| ASSERT_EQ(2u, map.size()); |
| auto map_it = map.begin(); |
| EXPECT_EQ(map_it->first, docs_key); |
| EXPECT_EQ(docs_server_info, map_it->second); |
| ++map_it; |
| EXPECT_EQ(map_it->first, google_key); |
| EXPECT_EQ(google_server_info, map_it->second); |
| |
| // Prepare |quic_server_info_map| to be loaded by |
| // SetQuicServerInfoMap(). |
| std::unique_ptr<HttpServerProperties::QuicServerInfoMap> |
| quic_server_info_map = |
| std::make_unique<HttpServerProperties::QuicServerInfoMap>( |
| kMaxQuicServerEntries); |
| // Change the values for |docs_server|. |
| std::string new_docs_server_info("new_docs_quic_server_info"); |
| quic_server_info_map->Put(docs_key, new_docs_server_info); |
| // Add data for mail.google.com:443. |
| quic::QuicServerId mail_quic_server_id("mail.google.com", 443, true); |
| HttpServerProperties::QuicServerInfoMapKey mail_key( |
| mail_quic_server_id, NetworkAnonymizationKey(), |
| false /* use_network_anonymization_key */); |
| std::string mail_server_info("mail_quic_server_info"); |
| quic_server_info_map->Put(mail_key, mail_server_info); |
| impl_.OnQuicServerInfoMapLoadedForTesting(std::move(quic_server_info_map)); |
| |
| // Recency order will be |docs_server|, |google_server| and |mail_server|. |
| const HttpServerProperties::QuicServerInfoMap& memory_map = |
| impl_.quic_server_info_map(); |
| ASSERT_EQ(3u, memory_map.size()); |
| auto memory_map_it = memory_map.begin(); |
| EXPECT_EQ(memory_map_it->first, docs_key); |
| EXPECT_EQ(new_docs_server_info, memory_map_it->second); |
| ++memory_map_it; |
| EXPECT_EQ(memory_map_it->first, google_key); |
| EXPECT_EQ(google_server_info, memory_map_it->second); |
| ++memory_map_it; |
| EXPECT_EQ(memory_map_it->first, mail_key); |
| EXPECT_EQ(mail_server_info, memory_map_it->second); |
| |
| // Shrink the size of |quic_server_info_map| and verify the MRU order is |
| // maintained. |
| impl_.SetMaxServerConfigsStoredInProperties(2); |
| EXPECT_EQ(2u, impl_.quic_server_info_map().max_size()); |
| |
| const HttpServerProperties::QuicServerInfoMap& memory_map1 = |
| impl_.quic_server_info_map(); |
| ASSERT_EQ(2u, memory_map1.size()); |
| auto memory_map1_it = memory_map1.begin(); |
| EXPECT_EQ(memory_map1_it->first, docs_key); |
| EXPECT_EQ(new_docs_server_info, memory_map1_it->second); |
| ++memory_map1_it; |
| EXPECT_EQ(memory_map1_it->first, google_key); |
| EXPECT_EQ(google_server_info, memory_map1_it->second); |
| // |QuicServerInfo| for |mail_quic_server_id| shouldn't be there. |
| EXPECT_EQ(nullptr, impl_.GetQuicServerInfo(mail_quic_server_id, |
| NetworkAnonymizationKey())); |
| } |
| |
| TEST_F(HttpServerPropertiesTest, SetQuicServerInfo) { |
| quic::QuicServerId server1("foo", 80, false /* privacy_mode_enabled */); |
| quic::QuicServerId server2("foo", 80, true /* privacy_mode_enabled */); |
| |
| std::string quic_server_info1("quic_server_info1"); |
| std::string quic_server_info2("quic_server_info2"); |
| std::string quic_server_info3("quic_server_info3"); |
| |
| // Without network isolation keys enabled for HttpServerProperties, passing in |
| // a NetworkAnonymizationKey should have no effect on behavior. |
| impl_.SetQuicServerInfo(server1, NetworkAnonymizationKey(), |
| quic_server_info1); |
| EXPECT_EQ(quic_server_info1, |
| *(impl_.GetQuicServerInfo(server1, NetworkAnonymizationKey()))); |
| EXPECT_FALSE(impl_.GetQuicServerInfo(server2, NetworkAnonymizationKey())); |
| EXPECT_EQ(quic_server_info1, |
| *(impl_.GetQuicServerInfo(server1, network_anonymization_key1_))); |
| EXPECT_FALSE(impl_.GetQuicServerInfo(server2, network_anonymization_key1_)); |
| |
| impl_.SetQuicServerInfo(server2, network_anonymization_key1_, |
| quic_server_info2); |
| EXPECT_EQ(quic_server_info1, |
| *(impl_.GetQuicServerInfo(server1, NetworkAnonymizationKey()))); |
| EXPECT_EQ(quic_server_info2, |
| *(impl_.GetQuicServerInfo(server2, NetworkAnonymizationKey()))); |
| EXPECT_EQ(quic_server_info1, |
| *(impl_.GetQuicServerInfo(server1, network_anonymization_key1_))); |
| EXPECT_EQ(quic_server_info2, |
| *(impl_.GetQuicServerInfo(server2, network_anonymization_key1_))); |
| |
| impl_.SetQuicServerInfo(server1, network_anonymization_key1_, |
| quic_server_info3); |
| EXPECT_EQ(quic_server_info3, |
| *(impl_.GetQuicServerInfo(server1, NetworkAnonymizationKey()))); |
| EXPECT_EQ(quic_server_info2, |
| *(impl_.GetQuicServerInfo(server2, NetworkAnonymizationKey()))); |
| EXPECT_EQ(quic_server_info3, |
| *(impl_.GetQuicServerInfo(server1, network_anonymization_key1_))); |
| EXPECT_EQ(quic_server_info2, |
| *(impl_.GetQuicServerInfo(server2, network_anonymization_key1_))); |
| |
| impl_.Clear(base::OnceClosure()); |
| EXPECT_FALSE(impl_.GetQuicServerInfo(server1, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.GetQuicServerInfo(server2, NetworkAnonymizationKey())); |
| EXPECT_FALSE(impl_.GetQuicServerInfo(server1, network_anonymization_key1_)); |
| EXPECT_FALSE(impl_.GetQuicServerInfo(server2, network_anonymization_key1_)); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| // Since HttpServerProperties caches the feature value, have to create a new |
| // one. |
| HttpServerProperties properties(nullptr /* pref_delegate */, |
| nullptr /* net_log */, test_tick_clock_, |
| &test_clock_); |
| |
| properties.SetQuicServerInfo(server1, NetworkAnonymizationKey(), |
| quic_server_info1); |
| EXPECT_EQ(quic_server_info1, *(properties.GetQuicServerInfo( |
| server1, NetworkAnonymizationKey()))); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server2, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server1, network_anonymization_key1_)); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server2, network_anonymization_key1_)); |
| |
| properties.SetQuicServerInfo(server1, network_anonymization_key1_, |
| quic_server_info2); |
| EXPECT_EQ(quic_server_info1, *(properties.GetQuicServerInfo( |
| server1, NetworkAnonymizationKey()))); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server2, NetworkAnonymizationKey())); |
| EXPECT_EQ(quic_server_info2, *(properties.GetQuicServerInfo( |
| server1, network_anonymization_key1_))); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server2, network_anonymization_key1_)); |
| |
| properties.SetQuicServerInfo(server2, network_anonymization_key1_, |
| quic_server_info3); |
| EXPECT_EQ(quic_server_info1, *(properties.GetQuicServerInfo( |
| server1, NetworkAnonymizationKey()))); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server2, NetworkAnonymizationKey())); |
| EXPECT_EQ(quic_server_info2, *(properties.GetQuicServerInfo( |
| server1, network_anonymization_key1_))); |
| EXPECT_EQ(quic_server_info3, *(properties.GetQuicServerInfo( |
| server2, network_anonymization_key1_))); |
| |
| properties.Clear(base::OnceClosure()); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server1, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server2, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server1, network_anonymization_key1_)); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server2, network_anonymization_key1_)); |
| } |
| |
| // Tests that GetQuicServerInfo() returns server info of a host |
| // with the same canonical suffix when there is no exact host match. |
| TEST_F(HttpServerPropertiesTest, QuicServerInfoCanonicalSuffixMatch) { |
| // Set up HttpServerProperties. |
| // Add a host with a canonical suffix. |
| quic::QuicServerId foo_server_id("foo.googlevideo.com", 443, false); |
| std::string foo_server_info("foo_server_info"); |
| impl_.SetQuicServerInfo(foo_server_id, NetworkAnonymizationKey(), |
| foo_server_info); |
| |
| // Add a host that has a different canonical suffix. |
| quic::QuicServerId baz_server_id("baz.video.com", 443, false); |
| std::string baz_server_info("baz_server_info"); |
| impl_.SetQuicServerInfo(baz_server_id, NetworkAnonymizationKey(), |
| baz_server_info); |
| |
| // Create SchemeHostPort with a host that has the initial canonical suffix. |
| quic::QuicServerId bar_server_id("bar.googlevideo.com", 443, false); |
| |
| // Check the the server info associated with "foo" is returned for "bar". |
| const std::string* bar_server_info = |
| impl_.GetQuicServerInfo(bar_server_id, NetworkAnonymizationKey()); |
| ASSERT_TRUE(bar_server_info != nullptr); |
| EXPECT_EQ(foo_server_info, *bar_server_info); |
| } |
| |
| // Make sure that canonical suffices respect NetworkIsolationKeys when using |
| // QuicServerInfo methods. |
| TEST_F(HttpServerPropertiesTest, |
| QuicServerInfoCanonicalSuffixMatchWithNetworkIsolationKey) { |
| // Two servers with same canonical suffix. |
| quic::QuicServerId server1("foo.googlevideo.com", 80, |
| false /* privacy_mode_enabled */); |
| quic::QuicServerId server2("bar.googlevideo.com", 80, |
| false /* privacy_mode_enabled */); |
| |
| std::string server_info1("server_info1"); |
| std::string server_info2("server_info2"); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| features::kPartitionHttpServerPropertiesByNetworkIsolationKey); |
| // Since HttpServerProperties caches the feature value, have to create a new |
| // one. |
| HttpServerProperties properties(nullptr /* pref_delegate */, |
| nullptr /* net_log */, test_tick_clock_, |
| &test_clock_); |
| |
| // Set QuicServerInfo for one canononical suffix and |
| // |network_anonymization_key1_|. It should be accessible via another |
| // SchemeHostPort, but only when the NetworkIsolationKeys match. |
| properties.SetQuicServerInfo(server1, network_anonymization_key1_, |
| server_info1); |
| const std::string* fetched_server_info = |
| properties.GetQuicServerInfo(server1, network_anonymization_key1_); |
| ASSERT_TRUE(fetched_server_info); |
| EXPECT_EQ(server_info1, *fetched_server_info); |
| fetched_server_info = |
| properties.GetQuicServerInfo(server2, network_anonymization_key1_); |
| ASSERT_TRUE(fetched_server_info); |
| EXPECT_EQ(server_info1, *fetched_server_info); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server1, network_anonymization_key2_)); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server2, network_anonymization_key2_)); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server1, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server2, NetworkAnonymizationKey())); |
| |
| // Set different QuicServerInfo for the same canononical suffix and |
| // |network_anonymization_key2_|. Both infos should be retriveable by using |
| // the different NetworkIsolationKeys. |
| properties.SetQuicServerInfo(server1, network_anonymization_key2_, |
| server_info2); |
| fetched_server_info = |
| properties.GetQuicServerInfo(server1, network_anonymization_key1_); |
| ASSERT_TRUE(fetched_server_info); |
| EXPECT_EQ(server_info1, *fetched_server_info); |
| fetched_server_info = |
| properties.GetQuicServerInfo(server2, network_anonymization_key1_); |
| ASSERT_TRUE(fetched_server_info); |
| EXPECT_EQ(server_info1, *fetched_server_info); |
| fetched_server_info = |
| properties.GetQuicServerInfo(server1, network_anonymization_key2_); |
| ASSERT_TRUE(fetched_server_info); |
| EXPECT_EQ(server_info2, *fetched_server_info); |
| fetched_server_info = |
| properties.GetQuicServerInfo(server2, network_anonymization_key2_); |
| ASSERT_TRUE(fetched_server_info); |
| EXPECT_EQ(server_info2, *fetched_server_info); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server1, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server2, NetworkAnonymizationKey())); |
| |
| // Clearing should destroy all information. |
| properties.Clear(base::OnceClosure()); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server1, network_anonymization_key1_)); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server2, network_anonymization_key1_)); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server1, network_anonymization_key2_)); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server2, network_anonymization_key2_)); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server1, NetworkAnonymizationKey())); |
| EXPECT_FALSE( |
| properties.GetQuicServerInfo(server2, NetworkAnonymizationKey())); |
| } |
| |
| // Verifies that GetQuicServerInfo() returns the MRU entry if multiple records |
| // match a given canonical host. |
| TEST_F(HttpServerPropertiesTest, |
| QuicServerInfoCanonicalSuffixMatchReturnsMruEntry) { |
| // Set up HttpServerProperties by adding two hosts with the same canonical |
| // suffixes. |
| quic::QuicServerId h1_server_id("h1.googlevideo.com", 443, false); |
| std::string h1_server_info("h1_server_info"); |
| impl_.SetQuicServerInfo(h1_server_id, NetworkAnonymizationKey(), |
| h1_server_info); |
| |
| quic::QuicServerId h2_server_id("h2.googlevideo.com", 443, false); |
| std::string h2_server_info("h2_server_info"); |
| impl_.SetQuicServerInfo(h2_server_id, NetworkAnonymizationKey(), |
| h2_server_info); |
| |
| // Create quic::QuicServerId to use for the search. |
| quic::QuicServerId foo_server_id("foo.googlevideo.com", 443, false); |
| |
| // Check that 'h2' info is returned since it is MRU. |
| const std::string* server_info = |
| impl_.GetQuicServerInfo(foo_server_id, NetworkAnonymizationKey()); |
| ASSERT_TRUE(server_info != nullptr); |
| EXPECT_EQ(h2_server_info, *server_info); |
| |
| // Access 'h1' info, so it becomes MRU. |
| impl_.GetQuicServerInfo(h1_server_id, NetworkAnonymizationKey()); |
| |
| // Check that 'h1' info is returned since it is MRU now. |
| server_info = |
| impl_.GetQuicServerInfo(foo_server_id, NetworkAnonymizationKey()); |
| ASSERT_TRUE(server_info != nullptr); |
| EXPECT_EQ(h1_server_info, *server_info); |
| } |
| |
| // Verifies that |GetQuicServerInfo| doesn't change the MRU order of the server |
| // info map when a record is matched based on a canonical name. |
| TEST_F(HttpServerPropertiesTest, |
| QuicServerInfoCanonicalSuffixMatchDoesntChangeOrder) { |
| // Add a host with a matching canonical name. |
| quic::QuicServerId h1_server_id("h1.googlevideo.com", 443, false); |
| HttpServerProperties::QuicServerInfoMapKey h1_key( |
| h1_server_id, NetworkAnonymizationKey(), |
| false /* use_network_anonymization_key */); |
| std::string h1_server_info("h1_server_info"); |
| impl_.SetQuicServerInfo(h1_server_id, NetworkAnonymizationKey(), |
| h1_server_info); |
| |
| // Add a host hosts with a non-matching canonical name. |
| quic::QuicServerId h2_server_id("h2.video.com", 443, false); |
| HttpServerProperties::QuicServerInfoMapKey h2_key( |
| h2_server_id, NetworkAnonymizationKey(), |
| false /* use_network_anonymization_key */); |
| std::string h2_server_info("h2_server_info"); |
| impl_.SetQuicServerInfo(h2_server_id, NetworkAnonymizationKey(), |
| h2_server_info); |
| |
| // Check that "h2.video.com" is the MRU entry in the map. |
| EXPECT_EQ(h2_key, impl_.quic_server_info_map().begin()->first); |
| |
| // Search for the entry that matches the canonical name |
| // ("h1.googlevideo.com"). |
| quic::QuicServerId foo_server_id("foo.googlevideo.com", 443, false); |
| const std::string* server_info = |
| impl_.GetQuicServerInfo(foo_server_id, NetworkAnonymizationKey()); |
| ASSERT_TRUE(server_info != nullptr); |
| |
| // Check that the search (although successful) hasn't changed the MRU order of |
| // the map. |
| EXPECT_EQ(h2_key, impl_.quic_server_info_map().begin()->first); |
| |
| // Search for "h1.googlevideo.com" directly, so it becomes MRU |
| impl_.GetQuicServerInfo(h1_server_id, NetworkAnonymizationKey()); |
| |
| // Check that "h1.googlevideo.com" is the MRU entry now. |
| EXPECT_EQ(h1_key, impl_.quic_server_info_map().begin()->first); |
| } |
| |
| // Tests that the canonical host matching works for hosts stored in memory cache |
| // and the ones loaded from persistent storage, i.e. server info added |
| // using SetQuicServerInfo() and SetQuicServerInfoMap() is taken into |
| // cosideration when searching for server info for a host with the same |
| // canonical suffix. |
| TEST_F(HttpServerPropertiesTest, QuicServerInfoCanonicalSuffixMatchSetInfoMap) { |
| // Add a host info using SetQuicServerInfo(). That will simulate an info |
| // entry stored in memory cache. |
| quic::QuicServerId h1_server_id("h1.googlevideo.com", 443, false); |
| std::string h1_server_info("h1_server_info_memory_cache"); |
| impl_.SetQuicServerInfo(h1_server_id, NetworkAnonymizationKey(), |
| h1_server_info); |
| |
| // Prepare a map with host info and add it using SetQuicServerInfoMap(). That |
| // will simulate info records read from the persistence storage. |
| quic::QuicServerId h2_server_id("h2.googlevideo.com", 443, false); |
| HttpServerProperties::QuicServerInfoMapKey h2_key( |
| h2_server_id, NetworkAnonymizationKey(), |
| false /* use_network_anonymization_key */); |
| std::string h2_server_info("h2_server_info_from_disk"); |
| |
| quic::QuicServerId h3_server_id("h3.ggpht.com", 443, false); |
| HttpServerProperties::QuicServerInfoMapKey h3_key( |
| h3_server_id, NetworkAnonymizationKey(), |
| false /* use_network_anonymization_key */); |
| std::string h3_server_info("h3_server_info_from_disk"); |
| |
| const int kMaxQuicServerEntries = 10; |
| impl_.SetMaxServerConfigsStoredInProperties(kMaxQuicServerEntries); |
| |
| std::unique_ptr<HttpServerProperties::QuicServerInfoMap> |
| quic_server_info_map = |
| std::make_unique<HttpServerProperties::QuicServerInfoMap>( |
| kMaxQuicServerEntries); |
| quic_server_info_map->Put(h2_key, h2_server_info); |
| quic_server_info_map->Put(h3_key, h3_server_info); |
| impl_.OnQuicServerInfoMapLoadedForTesting(std::move(quic_server_info_map)); |
| |
| // Check that the server info from the memory cache is returned since unique |
| // entries from the memory cache are added after entries from the |
| // persistence storage and, therefore, are most recently used. |
| quic::QuicServerId foo_server_id("foo.googlevideo.com", 443, false); |
| const std::string* server_info = |
| impl_.GetQuicServerInfo(foo_server_id, NetworkAnonymizationKey()); |
| ASSERT_TRUE(server_info != nullptr); |
| EXPECT_EQ(h1_server_info, *server_info); |
| |
| // Check that server info that was added using SetQuicServerInfoMap() can be |
| // found. |
| foo_server_id = quic::QuicServerId("foo.ggpht.com", 443, false); |
| server_info = |
| impl_.GetQuicServerInfo(foo_server_id, NetworkAnonymizationKey()); |
| ASSERT_TRUE(server_info != nullptr); |
| EXPECT_EQ(h3_server_info, *server_info); |
| } |
| |
| } // namespace |
| |
| } // namespace net |