blob: f503f2691d3ce740d95803fca21d147a43654213 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/http/http_server_properties_manager.h"
#include <utility>
#include "base/bind.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "net/base/ip_address.h"
#include "net/http/http_network_session.h"
#include "net/test/test_with_scoped_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace net {
namespace {
using base::StringPrintf;
using ::testing::_;
using ::testing::AtLeast;
using ::testing::Invoke;
using ::testing::Mock;
using ::testing::StrictMock;
class MockPrefDelegate : public net::HttpServerPropertiesManager::PrefDelegate {
public:
MockPrefDelegate() = default;
~MockPrefDelegate() override = default;
// HttpServerPropertiesManager::PrefDelegate implementation.
const base::DictionaryValue* GetServerProperties() const override {
return &prefs_;
}
void SetServerProperties(const base::DictionaryValue& value,
base::OnceClosure callback) override {
prefs_.Clear();
prefs_.MergeDictionary(&value);
++num_pref_updates_;
if (!prefs_changed_callback_.is_null())
prefs_changed_callback_.Run();
if (!extra_prefs_changed_callback_.is_null())
extra_prefs_changed_callback_.Run();
set_properties_callback_ = std::move(callback);
}
void StartListeningForUpdates(const base::Closure& callback) override {
CHECK(prefs_changed_callback_.is_null());
prefs_changed_callback_ = callback;
}
void SetPrefs(const base::DictionaryValue& value) {
// prefs_ = value;
prefs_.Clear();
prefs_.MergeDictionary(&value);
if (!prefs_changed_callback_.is_null())
prefs_changed_callback_.Run();
}
int GetAndClearNumPrefUpdates() {
int out = num_pref_updates_;
num_pref_updates_ = 0;
return out;
}
// Additional callback to call when prefs are updated, used to check prefs are
// updated on destruction.
void set_extra_update_prefs_callback(const base::Closure& callback) {
extra_prefs_changed_callback_ = callback;
}
// Returns the base::OnceCallback, if any, passed to the last call to
// SetServerProperties().
base::OnceClosure GetSetPropertiesCallback() {
return std::move(set_properties_callback_);
}
private:
base::DictionaryValue prefs_;
base::Closure prefs_changed_callback_;
base::Closure extra_prefs_changed_callback_;
int num_pref_updates_ = 0;
base::OnceClosure set_properties_callback_;
DISALLOW_COPY_AND_ASSIGN(MockPrefDelegate);
};
} // namespace
// TODO(rtenneti): After we stop supporting version 3 and everyone has migrated
// to version 4, delete the following code.
static const int kHttpServerPropertiesVersions[] = {3, 4, 5};
class HttpServerPropertiesManagerTest : public testing::TestWithParam<int>,
public WithScopedTaskEnvironment {
protected:
HttpServerPropertiesManagerTest()
: WithScopedTaskEnvironment(
base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME) {}
void SetUp() override {
one_day_from_now_ = base::Time::Now() + base::TimeDelta::FromDays(1);
advertised_versions_ = HttpNetworkSession::Params().quic_supported_versions;
pref_delegate_ = new MockPrefDelegate;
http_server_props_manager_ = std::make_unique<HttpServerPropertiesManager>(
base::WrapUnique(pref_delegate_), /*net_log=*/nullptr,
GetMockTickClock());
EXPECT_FALSE(http_server_props_manager_->IsInitialized());
pref_delegate_->SetPrefs(base::DictionaryValue());
EXPECT_TRUE(http_server_props_manager_->IsInitialized());
EXPECT_FALSE(MainThreadHasPendingTask());
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
}
void TearDown() override {
// Run pending non-delayed tasks but don't FastForwardUntilNoTasksRemain()
// as some delayed tasks may forever repost (e.g. because impl doesn't use a
// mock clock and doesn't see timings as having expired, ref.
// HttpServerPropertiesImpl::
// ScheduleBrokenAlternateProtocolMappingsExpiration()).
base::RunLoop().RunUntilIdle();
http_server_props_manager_.reset();
}
bool HasAlternativeService(const url::SchemeHostPort& server) {
const AlternativeServiceInfoVector alternative_service_info_vector =
http_server_props_manager_->GetAlternativeServiceInfos(server);
return !alternative_service_info_vector.empty();
}
MockPrefDelegate* pref_delegate_; // Owned by HttpServerPropertiesManager.
std::unique_ptr<HttpServerPropertiesManager> http_server_props_manager_;
base::Time one_day_from_now_;
quic::QuicTransportVersionVector advertised_versions_;
private:
DISALLOW_COPY_AND_ASSIGN(HttpServerPropertiesManagerTest);
};
INSTANTIATE_TEST_CASE_P(/* no prefix */,
HttpServerPropertiesManagerTest,
::testing::ValuesIn(kHttpServerPropertiesVersions));
TEST_P(HttpServerPropertiesManagerTest,
SingleUpdateForTwoSpdyServerPrefChanges) {
// Set up the prefs for https://www.google.com and https://mail.google.com and
// then set it twice. Only expect a single cache update.
auto server_pref_dict = std::make_unique<base::DictionaryValue>();
url::SchemeHostPort google_server("https", "www.google.com", 443);
url::SchemeHostPort mail_server("https", "mail.google.com", 443);
// Set supports_spdy for https://www.google.com:443.
server_pref_dict->SetBoolean("supports_spdy", true);
// Set up alternative_services for https://www.google.com.
auto alternative_service_dict0 = std::make_unique<base::DictionaryValue>();
alternative_service_dict0->SetInteger("port", 443);
alternative_service_dict0->SetString("protocol_str", "h2");
auto alternative_service_dict1 = std::make_unique<base::DictionaryValue>();
alternative_service_dict1->SetInteger("port", 1234);
alternative_service_dict1->SetString("protocol_str", "quic");
auto alternative_service_list0 = std::make_unique<base::ListValue>();
alternative_service_list0->Append(std::move(alternative_service_dict0));
alternative_service_list0->Append(std::move(alternative_service_dict1));
server_pref_dict->SetWithoutPathExpansion(
"alternative_service", std::move(alternative_service_list0));
// Set up ServerNetworkStats for https://www.google.com.
auto stats = std::make_unique<base::DictionaryValue>();
stats->SetInteger("srtt", 10);
server_pref_dict->SetWithoutPathExpansion("network_stats", std::move(stats));
// Set the server preference for https://www.google.com.
auto servers_dict = std::make_unique<base::DictionaryValue>();
servers_dict->SetWithoutPathExpansion(
GetParam() >= 5 ? "https://www.google.com" : "www.google.com:443",
std::move(server_pref_dict));
std::unique_ptr<base::ListValue> servers_list;
if (GetParam() >= 4) {
servers_list = std::make_unique<base::ListValue>();
servers_list->Append(std::move(servers_dict));
servers_dict = std::make_unique<base::DictionaryValue>();
}
// Set the preference for mail.google.com server.
auto server_pref_dict1 = std::make_unique<base::DictionaryValue>();
// Set supports_spdy for https://mail.google.com.
server_pref_dict1->SetBoolean("supports_spdy", true);
// Set up alternative_services for https://mail.google.com.
auto alternative_service_dict2 = std::make_unique<base::DictionaryValue>();
alternative_service_dict2->SetString("protocol_str", "h2");
alternative_service_dict2->SetInteger("port", 444);
auto alternative_service_list1 = std::make_unique<base::ListValue>();
alternative_service_list1->Append(std::move(alternative_service_dict2));
server_pref_dict1->SetWithoutPathExpansion(
"alternative_service", std::move(alternative_service_list1));
// Set up ServerNetworkStats for https://mail.google.com and it is the MRU
// server.
auto stats1 = std::make_unique<base::DictionaryValue>();
stats1->SetInteger("srtt", 20);
server_pref_dict1->SetWithoutPathExpansion("network_stats",
std::move(stats1));
// Set the server preference for https://mail.google.com.
servers_dict->SetWithoutPathExpansion(
GetParam() >= 5 ? "https://mail.google.com" : "mail.google.com:443",
std::move(server_pref_dict1));
base::DictionaryValue http_server_properties_dict;
if (GetParam() >= 4) {
servers_list->AppendIfNotPresent(std::move(servers_dict));
if (GetParam() == 5) {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, -1);
} else {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict,
GetParam());
}
http_server_properties_dict.SetWithoutPathExpansion(
"servers", std::move(servers_list));
} else {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict,
GetParam());
http_server_properties_dict.SetWithoutPathExpansion(
"servers", std::move(servers_dict));
}
auto supports_quic = std::make_unique<base::DictionaryValue>();
supports_quic->SetBoolean("used_quic", true);
supports_quic->SetString("address", "127.0.0.1");
http_server_properties_dict.SetWithoutPathExpansion("supports_quic",
std::move(supports_quic));
// Set quic_server_info for https://www.google.com, https://mail.google.com
// and https://play.google.com and verify the MRU.
http_server_props_manager_->SetMaxServerConfigsStoredInProperties(3);
auto quic_servers_dict = std::make_unique<base::DictionaryValue>();
auto quic_server_pref_dict1 = std::make_unique<base::DictionaryValue>();
std::string quic_server_info1("quic_server_info1");
quic_server_pref_dict1->SetKey("server_info", base::Value(quic_server_info1));
auto quic_server_pref_dict2 = std::make_unique<base::DictionaryValue>();
std::string quic_server_info2("quic_server_info2");
quic_server_pref_dict2->SetKey("server_info", base::Value(quic_server_info2));
auto quic_server_pref_dict3 = std::make_unique<base::DictionaryValue>();
std::string quic_server_info3("quic_server_info3");
quic_server_pref_dict3->SetKey("server_info", base::Value(quic_server_info3));
// Set the quic_server_info1 for https://www.google.com.
quic::QuicServerId google_quic_server_id("www.google.com", 443, false);
quic_servers_dict->SetWithoutPathExpansion("https://www.google.com",
std::move(quic_server_pref_dict1));
// Set the quic_server_info2 for https://mail.google.com.
quic::QuicServerId mail_quic_server_id("mail.google.com", 443, false);
quic_servers_dict->SetWithoutPathExpansion("https://mail.google.com",
std::move(quic_server_pref_dict2));
// Set the quic_server_info3 for https://play.google.com.
quic::QuicServerId play_quic_server_id("play.google.com", 443, false);
quic_servers_dict->SetWithoutPathExpansion("https://play.google.com",
std::move(quic_server_pref_dict3));
http_server_properties_dict.SetWithoutPathExpansion(
"quic_servers", std::move(quic_servers_dict));
// Set the same value for kHttpServerProperties multiple times.
pref_delegate_->SetPrefs(http_server_properties_dict);
pref_delegate_->SetPrefs(http_server_properties_dict);
// Should be a delayed task to update the cache from the prefs file.
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
// Verify SupportsSpdy.
EXPECT_TRUE(
http_server_props_manager_->SupportsRequestPriority(google_server));
EXPECT_TRUE(http_server_props_manager_->SupportsRequestPriority(mail_server));
HostPortPair foo_host_port_pair =
HostPortPair::FromString("foo.google.com:1337");
url::SchemeHostPort foo_server("http", foo_host_port_pair.host(),
foo_host_port_pair.port());
EXPECT_FALSE(http_server_props_manager_->SupportsRequestPriority(foo_server));
// Verify alternative service.
const AlternativeServiceMap& map =
http_server_props_manager_->alternative_service_map();
ASSERT_EQ(2u, map.size());
auto map_it = map.begin();
EXPECT_EQ("www.google.com", map_it->first.host());
ASSERT_EQ(2u, map_it->second.size());
EXPECT_EQ(kProtoHTTP2, map_it->second[0].alternative_service().protocol);
EXPECT_TRUE(map_it->second[0].alternative_service().host.empty());
EXPECT_EQ(443, map_it->second[0].alternative_service().port);
EXPECT_EQ(kProtoQUIC, map_it->second[1].alternative_service().protocol);
EXPECT_TRUE(map_it->second[1].alternative_service().host.empty());
EXPECT_EQ(1234, map_it->second[1].alternative_service().port);
++map_it;
EXPECT_EQ("mail.google.com", map_it->first.host());
ASSERT_EQ(1u, map_it->second.size());
EXPECT_EQ(kProtoHTTP2, map_it->second[0].alternative_service().protocol);
EXPECT_TRUE(map_it->second[0].alternative_service().host.empty());
EXPECT_EQ(444, map_it->second[0].alternative_service().port);
// Verify SupportsQuic.
IPAddress last_address;
EXPECT_TRUE(http_server_props_manager_->GetSupportsQuic(&last_address));
EXPECT_EQ("127.0.0.1", last_address.ToString());
// Verify ServerNetworkStats.
const ServerNetworkStats* stats2 =
http_server_props_manager_->GetServerNetworkStats(google_server);
EXPECT_EQ(10, stats2->srtt.ToInternalValue());
const ServerNetworkStats* stats3 =
http_server_props_manager_->GetServerNetworkStats(mail_server);
EXPECT_EQ(20, stats3->srtt.ToInternalValue());
// Verify QuicServerInfo.
EXPECT_EQ(quic_server_info1, *http_server_props_manager_->GetQuicServerInfo(
google_quic_server_id));
EXPECT_EQ(quic_server_info2, *http_server_props_manager_->GetQuicServerInfo(
mail_quic_server_id));
EXPECT_EQ(quic_server_info3, *http_server_props_manager_->GetQuicServerInfo(
play_quic_server_id));
// Verify the MRU order.
http_server_props_manager_->SetMaxServerConfigsStoredInProperties(2);
EXPECT_EQ(nullptr, http_server_props_manager_->GetQuicServerInfo(
google_quic_server_id));
EXPECT_EQ(quic_server_info2, *http_server_props_manager_->GetQuicServerInfo(
mail_quic_server_id));
EXPECT_EQ(quic_server_info3, *http_server_props_manager_->GetQuicServerInfo(
play_quic_server_id));
}
TEST_P(HttpServerPropertiesManagerTest, BadCachedHostPortPair) {
auto server_pref_dict = std::make_unique<base::DictionaryValue>();
// Set supports_spdy for www.google.com:65536.
server_pref_dict->SetBoolean("supports_spdy", true);
// Set up alternative_service for www.google.com:65536.
auto alternative_service_dict = std::make_unique<base::DictionaryValue>();
alternative_service_dict->SetString("protocol_str", "h2");
alternative_service_dict->SetInteger("port", 80);
auto alternative_service_list = std::make_unique<base::ListValue>();
alternative_service_list->Append(std::move(alternative_service_dict));
server_pref_dict->SetWithoutPathExpansion(
"alternative_service", std::move(alternative_service_list));
// Set up ServerNetworkStats for www.google.com:65536.
auto stats = std::make_unique<base::DictionaryValue>();
stats->SetInteger("srtt", 10);
server_pref_dict->SetWithoutPathExpansion("network_stats", std::move(stats));
// Set the server preference for www.google.com:65536.
auto servers_dict = std::make_unique<base::DictionaryValue>();
servers_dict->SetWithoutPathExpansion("www.google.com:65536",
std::move(server_pref_dict));
base::DictionaryValue http_server_properties_dict;
if (GetParam() >= 4) {
auto servers_list = std::make_unique<base::ListValue>();
servers_list->Append(std::move(servers_dict));
if (GetParam() == 5) {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, -1);
} else {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict,
GetParam());
}
http_server_properties_dict.SetWithoutPathExpansion(
"servers", std::move(servers_list));
} else {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict,
GetParam());
http_server_properties_dict.SetWithoutPathExpansion(
"servers", std::move(servers_dict));
}
// Set quic_server_info for www.google.com:65536.
auto quic_servers_dict = std::make_unique<base::DictionaryValue>();
auto quic_server_pref_dict1 = std::make_unique<base::DictionaryValue>();
quic_server_pref_dict1->SetKey("server_info",
base::Value("quic_server_info1"));
quic_servers_dict->SetWithoutPathExpansion("http://mail.google.com:65536",
std::move(quic_server_pref_dict1));
http_server_properties_dict.SetWithoutPathExpansion(
"quic_servers", std::move(quic_servers_dict));
// Set up the pref.
pref_delegate_->SetPrefs(http_server_properties_dict);
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
// Prefs should have been overwritten, due to the bad data.
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
// Verify that nothing is set.
HostPortPair google_host_port_pair =
HostPortPair::FromString("www.google.com:65536");
url::SchemeHostPort gooler_server("http", google_host_port_pair.host(),
google_host_port_pair.port());
EXPECT_FALSE(
http_server_props_manager_->SupportsRequestPriority(gooler_server));
EXPECT_FALSE(HasAlternativeService(gooler_server));
const ServerNetworkStats* stats1 =
http_server_props_manager_->GetServerNetworkStats(gooler_server);
EXPECT_EQ(nullptr, stats1);
EXPECT_EQ(0u, http_server_props_manager_->quic_server_info_map().size());
}
TEST_P(HttpServerPropertiesManagerTest, BadCachedAltProtocolPort) {
auto server_pref_dict = std::make_unique<base::DictionaryValue>();
// Set supports_spdy for www.google.com:80.
server_pref_dict->SetBoolean("supports_spdy", true);
// Set up alternative_service for www.google.com:80.
auto alternative_service_dict = std::make_unique<base::DictionaryValue>();
alternative_service_dict->SetString("protocol_str", "h2");
alternative_service_dict->SetInteger("port", 65536);
auto alternative_service_list = std::make_unique<base::ListValue>();
alternative_service_list->Append(std::move(alternative_service_dict));
server_pref_dict->SetWithoutPathExpansion(
"alternative_service", std::move(alternative_service_list));
// Set the server preference for www.google.com:80.
auto servers_dict = std::make_unique<base::DictionaryValue>();
servers_dict->SetWithoutPathExpansion("www.google.com:80",
std::move(server_pref_dict));
base::DictionaryValue http_server_properties_dict;
if (GetParam() >= 4) {
auto servers_list = std::make_unique<base::ListValue>();
servers_list->Append(std::move(servers_dict));
if (GetParam() == 5) {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, -1);
} else {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict,
GetParam());
}
http_server_properties_dict.SetWithoutPathExpansion(
"servers", std::move(servers_list));
} else {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict,
GetParam());
http_server_properties_dict.SetWithoutPathExpansion(
"servers", std::move(servers_dict));
}
// Set up the pref.
pref_delegate_->SetPrefs(http_server_properties_dict);
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
// Prefs should have been overwritten, due to the bad data.
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
// Verify alternative service is not set.
EXPECT_FALSE(
HasAlternativeService(url::SchemeHostPort("http", "www.google.com", 80)));
}
TEST_P(HttpServerPropertiesManagerTest, SupportsSpdy) {
// Add mail.google.com:443 as a supporting spdy server.
url::SchemeHostPort spdy_server("https", "mail.google.com", 443);
EXPECT_FALSE(
http_server_props_manager_->SupportsRequestPriority(spdy_server));
http_server_props_manager_->SetSupportsSpdy(spdy_server, true);
// Setting the value to the same thing again should not trigger another pref
// update.
http_server_props_manager_->SetSupportsSpdy(spdy_server, true);
// Run the task.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
// Setting the value to the same thing again should not trigger another pref
// update.
http_server_props_manager_->SetSupportsSpdy(spdy_server, true);
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_FALSE(MainThreadHasPendingTask());
EXPECT_TRUE(http_server_props_manager_->SupportsRequestPriority(spdy_server));
}
// Regression test for crbug.com/670519. Test that there is only one pref update
// scheduled if multiple updates happen in a given time period. Subsequent pref
// update could also be scheduled once the previous scheduled update is
// completed.
TEST_P(HttpServerPropertiesManagerTest,
SinglePrefUpdateForTwoSpdyServerCacheChanges) {
// Post an update task. SetSupportsSpdy calls ScheduleUpdatePrefs with a delay
// of 60ms.
url::SchemeHostPort spdy_server("https", "mail.google.com", 443);
EXPECT_FALSE(
http_server_props_manager_->SupportsRequestPriority(spdy_server));
http_server_props_manager_->SetSupportsSpdy(spdy_server, true);
// The pref update task should be scheduled.
EXPECT_EQ(1u, GetPendingMainThreadTaskCount());
// Move forward the task runner short by 20ms.
FastForwardBy(HttpServerPropertiesManager::GetUpdatePrefsDelayForTesting() -
base::TimeDelta::FromMilliseconds(20));
// Set another spdy server to trigger another call to
// ScheduleUpdatePrefs. There should be no new update posted.
url::SchemeHostPort spdy_server2("https", "drive.google.com", 443);
http_server_props_manager_->SetSupportsSpdy(spdy_server2, true);
EXPECT_EQ(1u, GetPendingMainThreadTaskCount());
// Move forward the extra 20ms. The pref update should be executed.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
FastForwardBy(base::TimeDelta::FromMilliseconds(20));
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_FALSE(MainThreadHasPendingTask());
EXPECT_TRUE(http_server_props_manager_->SupportsRequestPriority(spdy_server));
EXPECT_TRUE(
http_server_props_manager_->SupportsRequestPriority(spdy_server2));
// Set the third spdy server to trigger one more call to
// ScheduleUpdatePrefs. A new update task should be posted now since the
// previous one is completed.
url::SchemeHostPort spdy_server3("https", "maps.google.com", 443);
http_server_props_manager_->SetSupportsSpdy(spdy_server3, true);
EXPECT_EQ(1u, GetPendingMainThreadTaskCount());
// Run the task.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
}
TEST_P(HttpServerPropertiesManagerTest, GetAlternativeServiceInfos) {
url::SchemeHostPort spdy_server_mail("http", "mail.google.com", 80);
EXPECT_FALSE(HasAlternativeService(spdy_server_mail));
const AlternativeService alternative_service(kProtoHTTP2, "mail.google.com",
443);
http_server_props_manager_->SetHttp2AlternativeService(
spdy_server_mail, alternative_service, one_day_from_now_);
// ExpectScheduleUpdatePrefs() should be called only once.
http_server_props_manager_->SetHttp2AlternativeService(
spdy_server_mail, alternative_service, one_day_from_now_);
// Run the task.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
AlternativeServiceInfoVector alternative_service_info_vector =
http_server_props_manager_->GetAlternativeServiceInfos(spdy_server_mail);
ASSERT_EQ(1u, alternative_service_info_vector.size());
EXPECT_EQ(alternative_service,
alternative_service_info_vector[0].alternative_service());
}
TEST_P(HttpServerPropertiesManagerTest, SetAlternativeServices) {
url::SchemeHostPort spdy_server_mail("http", "mail.google.com", 80);
EXPECT_FALSE(HasAlternativeService(spdy_server_mail));
AlternativeServiceInfoVector alternative_service_info_vector;
const AlternativeService alternative_service1(kProtoHTTP2, "mail.google.com",
443);
alternative_service_info_vector.push_back(
AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
alternative_service1, one_day_from_now_));
const AlternativeService alternative_service2(kProtoQUIC, "mail.google.com",
1234);
alternative_service_info_vector.push_back(
AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
alternative_service2, one_day_from_now_, advertised_versions_));
http_server_props_manager_->SetAlternativeServices(
spdy_server_mail, alternative_service_info_vector);
// ExpectScheduleUpdatePrefs() should be called only once.
http_server_props_manager_->SetAlternativeServices(
spdy_server_mail, alternative_service_info_vector);
// Run the task.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
AlternativeServiceInfoVector alternative_service_info_vector2 =
http_server_props_manager_->GetAlternativeServiceInfos(spdy_server_mail);
ASSERT_EQ(2u, alternative_service_info_vector2.size());
EXPECT_EQ(alternative_service1,
alternative_service_info_vector2[0].alternative_service());
EXPECT_EQ(alternative_service2,
alternative_service_info_vector2[1].alternative_service());
}
TEST_P(HttpServerPropertiesManagerTest, SetAlternativeServicesEmpty) {
url::SchemeHostPort spdy_server_mail("http", "mail.google.com", 80);
EXPECT_FALSE(HasAlternativeService(spdy_server_mail));
const AlternativeService alternative_service(kProtoHTTP2, "mail.google.com",
443);
http_server_props_manager_->SetAlternativeServices(
spdy_server_mail, AlternativeServiceInfoVector());
EXPECT_FALSE(MainThreadHasPendingTask());
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_FALSE(HasAlternativeService(spdy_server_mail));
}
TEST_P(HttpServerPropertiesManagerTest, ConfirmAlternativeService) {
url::SchemeHostPort spdy_server_mail;
AlternativeService alternative_service;
spdy_server_mail = url::SchemeHostPort("http", "mail.google.com", 80);
EXPECT_FALSE(HasAlternativeService(spdy_server_mail));
alternative_service = AlternativeService(kProtoHTTP2, "mail.google.com", 443);
http_server_props_manager_->SetHttp2AlternativeService(
spdy_server_mail, alternative_service, one_day_from_now_);
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
EXPECT_EQ(1u, GetPendingMainThreadTaskCount());
http_server_props_manager_->MarkAlternativeServiceBroken(alternative_service);
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_TRUE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
// In addition to the pref update task, there's now a task to mark the
// alternative service as no longer broken.
EXPECT_EQ(2u, GetPendingMainThreadTaskCount());
http_server_props_manager_->ConfirmAlternativeService(alternative_service);
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
EXPECT_EQ(2u, GetPendingMainThreadTaskCount());
// Run the task.
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
}
TEST_P(HttpServerPropertiesManagerTest,
ConfirmBrokenUntilDefaultNetworkChanges) {
url::SchemeHostPort spdy_server_mail;
AlternativeService alternative_service;
spdy_server_mail = url::SchemeHostPort("http", "mail.google.com", 80);
EXPECT_FALSE(HasAlternativeService(spdy_server_mail));
alternative_service = AlternativeService(kProtoHTTP2, "mail.google.com", 443);
http_server_props_manager_->SetHttp2AlternativeService(
spdy_server_mail, alternative_service, one_day_from_now_);
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
EXPECT_EQ(1u, GetPendingMainThreadTaskCount());
http_server_props_manager_
->MarkAlternativeServiceBrokenUntilDefaultNetworkChanges(
alternative_service);
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_TRUE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
// In addition to the pref update task, there's now a task to mark the
// alternative service as no longer broken.
EXPECT_EQ(2u, GetPendingMainThreadTaskCount());
http_server_props_manager_->ConfirmAlternativeService(alternative_service);
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
EXPECT_EQ(2u, GetPendingMainThreadTaskCount());
// Run the task.
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
}
TEST_P(HttpServerPropertiesManagerTest,
OnDefaultNetworkChangedWithBrokenUntilDefaultNetworkChanges) {
url::SchemeHostPort spdy_server_mail;
AlternativeService alternative_service;
spdy_server_mail = url::SchemeHostPort("http", "mail.google.com", 80);
EXPECT_FALSE(HasAlternativeService(spdy_server_mail));
alternative_service = AlternativeService(kProtoHTTP2, "mail.google.com", 443);
http_server_props_manager_->SetHttp2AlternativeService(
spdy_server_mail, alternative_service, one_day_from_now_);
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
EXPECT_EQ(1u, GetPendingMainThreadTaskCount());
http_server_props_manager_
->MarkAlternativeServiceBrokenUntilDefaultNetworkChanges(
alternative_service);
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_TRUE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
// In addition to the pref update task, there's now a task to mark the
// alternative service as no longer broken.
EXPECT_EQ(2u, GetPendingMainThreadTaskCount());
http_server_props_manager_->OnDefaultNetworkChanged();
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
EXPECT_EQ(2u, GetPendingMainThreadTaskCount());
// Run the task.
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
}
TEST_P(HttpServerPropertiesManagerTest, OnDefaultNetworkChangedWithBrokenOnly) {
url::SchemeHostPort spdy_server_mail;
AlternativeService alternative_service;
spdy_server_mail = url::SchemeHostPort("http", "mail.google.com", 80);
EXPECT_FALSE(HasAlternativeService(spdy_server_mail));
alternative_service = AlternativeService(kProtoHTTP2, "mail.google.com", 443);
http_server_props_manager_->SetHttp2AlternativeService(
spdy_server_mail, alternative_service, one_day_from_now_);
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
EXPECT_EQ(1u, GetPendingMainThreadTaskCount());
http_server_props_manager_->MarkAlternativeServiceBroken(alternative_service);
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_TRUE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
// In addition to the pref update task, there's now a task to mark the
// alternative service as no longer broken.
EXPECT_EQ(2u, GetPendingMainThreadTaskCount());
http_server_props_manager_->OnDefaultNetworkChanged();
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_TRUE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
EXPECT_EQ(2u, GetPendingMainThreadTaskCount());
// Run the task.
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
alternative_service));
EXPECT_TRUE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
alternative_service));
}
TEST_P(HttpServerPropertiesManagerTest, SupportsQuic) {
IPAddress address;
EXPECT_FALSE(http_server_props_manager_->GetSupportsQuic(&address));
IPAddress actual_address(127, 0, 0, 1);
http_server_props_manager_->SetSupportsQuic(true, actual_address);
// Another task should not be scheduled.
http_server_props_manager_->SetSupportsQuic(true, actual_address);
// Run the task.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_TRUE(http_server_props_manager_->GetSupportsQuic(&address));
EXPECT_EQ(actual_address, address);
// Another task should not be scheduled.
http_server_props_manager_->SetSupportsQuic(true, actual_address);
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_FALSE(MainThreadHasPendingTask());
}
TEST_P(HttpServerPropertiesManagerTest, ServerNetworkStats) {
url::SchemeHostPort mail_server("http", "mail.google.com", 80);
const ServerNetworkStats* stats =
http_server_props_manager_->GetServerNetworkStats(mail_server);
EXPECT_EQ(nullptr, stats);
ServerNetworkStats stats1;
stats1.srtt = base::TimeDelta::FromMicroseconds(10);
http_server_props_manager_->SetServerNetworkStats(mail_server, stats1);
// Another task should not be scheduled.
http_server_props_manager_->SetServerNetworkStats(mail_server, stats1);
// Run the task.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
// Another task should not be scheduled.
http_server_props_manager_->SetServerNetworkStats(mail_server, stats1);
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_FALSE(MainThreadHasPendingTask());
const ServerNetworkStats* stats2 =
http_server_props_manager_->GetServerNetworkStats(mail_server);
EXPECT_EQ(10, stats2->srtt.ToInternalValue());
http_server_props_manager_->ClearServerNetworkStats(mail_server);
// Run the task.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_EQ(nullptr,
http_server_props_manager_->GetServerNetworkStats(mail_server));
}
TEST_P(HttpServerPropertiesManagerTest, QuicServerInfo) {
quic::QuicServerId mail_quic_server_id("mail.google.com", 80, false);
EXPECT_EQ(nullptr,
http_server_props_manager_->GetQuicServerInfo(mail_quic_server_id));
std::string quic_server_info1("quic_server_info1");
http_server_props_manager_->SetQuicServerInfo(mail_quic_server_id,
quic_server_info1);
// Another task should not be scheduled.
http_server_props_manager_->SetQuicServerInfo(mail_quic_server_id,
quic_server_info1);
// Run the task.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_EQ(quic_server_info1, *http_server_props_manager_->GetQuicServerInfo(
mail_quic_server_id));
// Another task should not be scheduled.
http_server_props_manager_->SetQuicServerInfo(mail_quic_server_id,
quic_server_info1);
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_FALSE(MainThreadHasPendingTask());
}
TEST_P(HttpServerPropertiesManagerTest, Clear) {
const url::SchemeHostPort spdy_server("https", "mail.google.com", 443);
const IPAddress actual_address(127, 0, 0, 1);
const quic::QuicServerId mail_quic_server_id("mail.google.com", 80, false);
const std::string quic_server_info1("quic_server_info1");
const AlternativeService alternative_service(kProtoHTTP2, "mail.google.com",
1234);
const AlternativeService broken_alternative_service(
kProtoHTTP2, "broken.google.com", 1234);
AlternativeServiceInfoVector alt_svc_info_vector;
alt_svc_info_vector.push_back(
AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
alternative_service, one_day_from_now_));
alt_svc_info_vector.push_back(
AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
broken_alternative_service, one_day_from_now_));
http_server_props_manager_->SetAlternativeServices(spdy_server,
alt_svc_info_vector);
http_server_props_manager_->MarkAlternativeServiceBroken(
broken_alternative_service);
http_server_props_manager_->SetSupportsSpdy(spdy_server, true);
http_server_props_manager_->SetSupportsQuic(true, actual_address);
ServerNetworkStats stats;
stats.srtt = base::TimeDelta::FromMicroseconds(10);
http_server_props_manager_->SetServerNetworkStats(spdy_server, stats);
http_server_props_manager_->SetQuicServerInfo(mail_quic_server_id,
quic_server_info1);
// Advance time by just enough so that the prefs update task is executed but
// not the task to expire the brokenness of |broken_alternative_service|.
FastForwardBy(HttpServerPropertiesManager::GetUpdatePrefsDelayForTesting());
EXPECT_TRUE(MainThreadHasPendingTask());
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
broken_alternative_service));
EXPECT_TRUE(http_server_props_manager_->SupportsRequestPriority(spdy_server));
EXPECT_TRUE(HasAlternativeService(spdy_server));
IPAddress address;
EXPECT_TRUE(http_server_props_manager_->GetSupportsQuic(&address));
EXPECT_EQ(actual_address, address);
const ServerNetworkStats* stats1 =
http_server_props_manager_->GetServerNetworkStats(spdy_server);
EXPECT_EQ(10, stats1->srtt.ToInternalValue());
EXPECT_EQ(quic_server_info1, *http_server_props_manager_->GetQuicServerInfo(
mail_quic_server_id));
// Clear http server data, which should instantly update prefs.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
bool callback_invoked_ = false;
http_server_props_manager_->Clear(
base::BindOnce([](bool* callback_invoked) { *callback_invoked = true; },
&callback_invoked_));
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_FALSE(callback_invoked_);
std::move(pref_delegate_->GetSetPropertiesCallback()).Run();
EXPECT_TRUE(callback_invoked_);
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
broken_alternative_service));
EXPECT_FALSE(
http_server_props_manager_->SupportsRequestPriority(spdy_server));
EXPECT_FALSE(HasAlternativeService(spdy_server));
EXPECT_FALSE(http_server_props_manager_->GetSupportsQuic(&address));
const ServerNetworkStats* stats2 =
http_server_props_manager_->GetServerNetworkStats(spdy_server);
EXPECT_EQ(nullptr, stats2);
EXPECT_EQ(nullptr,
http_server_props_manager_->GetQuicServerInfo(mail_quic_server_id));
}
// https://crbug.com/444956: Add 200 alternative_service servers followed by
// supports_quic and verify we have read supports_quic from prefs.
TEST_P(HttpServerPropertiesManagerTest, BadSupportsQuic) {
auto servers_dict = std::make_unique<base::DictionaryValue>();
std::unique_ptr<base::ListValue> servers_list;
if (GetParam() >= 4)
servers_list = std::make_unique<base::ListValue>();
for (int i = 1; i <= 200; ++i) {
// Set up alternative_service for www.google.com:i.
auto alternative_service_dict = std::make_unique<base::DictionaryValue>();
alternative_service_dict->SetString("protocol_str", "quic");
alternative_service_dict->SetInteger("port", i);
auto alternative_service_list = std::make_unique<base::ListValue>();
alternative_service_list->Append(std::move(alternative_service_dict));
auto server_pref_dict = std::make_unique<base::DictionaryValue>();
server_pref_dict->SetWithoutPathExpansion(
"alternative_service", std::move(alternative_service_list));
if (GetParam() >= 5) {
servers_dict->SetWithoutPathExpansion(
StringPrintf("https://www.google.com:%d", i),
std::move(server_pref_dict));
} else {
servers_dict->SetWithoutPathExpansion(
StringPrintf("www.google.com:%d", i), std::move(server_pref_dict));
}
if (GetParam() >= 4) {
servers_list->AppendIfNotPresent(std::move(servers_dict));
servers_dict = std::make_unique<base::DictionaryValue>();
}
}
// Set the server preference for http://mail.google.com server.
auto server_pref_dict1 = std::make_unique<base::DictionaryValue>();
if (GetParam() >= 5) {
servers_dict->SetWithoutPathExpansion("https://mail.google.com",
std::move(server_pref_dict1));
} else {
servers_dict->SetWithoutPathExpansion("mail.google.com:80",
std::move(server_pref_dict1));
}
base::DictionaryValue http_server_properties_dict;
if (GetParam() >= 4) {
servers_list->AppendIfNotPresent(std::move(servers_dict));
if (GetParam() == 5) {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict, -1);
} else {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict,
GetParam());
}
http_server_properties_dict.SetWithoutPathExpansion(
"servers", std::move(servers_list));
} else {
HttpServerPropertiesManager::SetVersion(&http_server_properties_dict,
GetParam());
http_server_properties_dict.SetWithoutPathExpansion(
"servers", std::move(servers_dict));
}
// Set up SupportsQuic for 127.0.0.1
auto supports_quic = std::make_unique<base::DictionaryValue>();
supports_quic->SetBoolean("used_quic", true);
supports_quic->SetString("address", "127.0.0.1");
http_server_properties_dict.SetWithoutPathExpansion("supports_quic",
std::move(supports_quic));
// Set up the pref.
pref_delegate_->SetPrefs(http_server_properties_dict);
FastForwardUntilNoTasksRemain();
// Verify alternative service.
for (int i = 1; i <= 200; ++i) {
GURL server_gurl;
if (GetParam() >= 5) {
server_gurl = GURL(StringPrintf("https://www.google.com:%d", i));
} else {
server_gurl = GURL(StringPrintf("https://www.google.com:%d", i));
}
url::SchemeHostPort server(server_gurl);
AlternativeServiceInfoVector alternative_service_info_vector =
http_server_props_manager_->GetAlternativeServiceInfos(server);
ASSERT_EQ(1u, alternative_service_info_vector.size());
EXPECT_EQ(
kProtoQUIC,
alternative_service_info_vector[0].alternative_service().protocol);
EXPECT_EQ(i, alternative_service_info_vector[0].alternative_service().port);
}
// Verify SupportsQuic.
IPAddress address;
ASSERT_TRUE(http_server_props_manager_->GetSupportsQuic(&address));
EXPECT_EQ("127.0.0.1", address.ToString());
}
TEST_P(HttpServerPropertiesManagerTest, UpdatePrefsWithCache) {
const url::SchemeHostPort server_www("https", "www.google.com", 80);
const url::SchemeHostPort server_mail("https", "mail.google.com", 80);
// #1 & #2: Set alternate protocol.
AlternativeServiceInfoVector alternative_service_info_vector;
AlternativeService www_alternative_service1(kProtoHTTP2, "", 443);
base::Time expiration1;
ASSERT_TRUE(base::Time::FromUTCString("2036-12-01 10:00:00", &expiration1));
alternative_service_info_vector.push_back(
AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
www_alternative_service1, expiration1));
AlternativeService www_alternative_service2(kProtoHTTP2, "www.google.com",
1234);
base::Time expiration2;
ASSERT_TRUE(base::Time::FromUTCString("2036-12-31 10:00:00", &expiration2));
alternative_service_info_vector.push_back(
AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
www_alternative_service2, expiration2));
ASSERT_TRUE(http_server_props_manager_->SetAlternativeServices(
server_www, alternative_service_info_vector));
AlternativeService mail_alternative_service(kProtoHTTP2, "foo.google.com",
444);
base::Time expiration3 = base::Time::Max();
ASSERT_TRUE(http_server_props_manager_->SetHttp2AlternativeService(
server_mail, mail_alternative_service, expiration3));
http_server_props_manager_->MarkAlternativeServiceBroken(
www_alternative_service2);
http_server_props_manager_->MarkAlternativeServiceRecentlyBroken(
mail_alternative_service);
// #3: Set SPDY server map
http_server_props_manager_->SetSupportsSpdy(server_www, false);
http_server_props_manager_->SetSupportsSpdy(server_mail, true);
http_server_props_manager_->SetSupportsSpdy(
url::SchemeHostPort("http", "not_persisted.com", 80), false);
// #4: Set ServerNetworkStats.
ServerNetworkStats stats;
stats.srtt = base::TimeDelta::FromInternalValue(42);
http_server_props_manager_->SetServerNetworkStats(server_mail, stats);
// #5: Set quic_server_info string.
quic::QuicServerId mail_quic_server_id("mail.google.com", 80, false);
std::string quic_server_info1("quic_server_info1");
http_server_props_manager_->SetQuicServerInfo(mail_quic_server_id,
quic_server_info1);
// #6: Set SupportsQuic.
IPAddress actual_address(127, 0, 0, 1);
http_server_props_manager_->SetSupportsQuic(true, actual_address);
base::Time time_before_prefs_update = base::Time::Now();
// Update Prefs.
// The task runner has a remaining pending task to expire
// |www_alternative_service2| in 5 minutes. Fast forward enough such
// that the prefs update task is executed but not the task to expire
// |broken_alternative_service|.
EXPECT_EQ(2u, GetPendingMainThreadTaskCount());
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
FastForwardBy(HttpServerPropertiesManager::GetUpdatePrefsDelayForTesting());
EXPECT_EQ(1u, GetPendingMainThreadTaskCount());
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
base::Time time_after_prefs_update = base::Time::Now();
// Verify |pref_delegate_|'s server dict.
// In HttpServerPropertiesManager, broken alternative services' expiration
// times are converted from TimeTicks to Time before being written to JSON by
// using the difference between Time::Now() and TimeTicks::Now().
// To verify these expiration times, |time_before_prefs_update| and
// |time_after_prefs_update| provide lower and upper bounds for the
// Time::Now() value used by the manager for this conversion.
//
// A copy of |pref_delegate_|'s server dict will be created, and the broken
// alternative service's "broken_until" field is removed and verified
// separately. The rest of the server dict copy is verified afterwards.
base::Value server_value_copy =
pref_delegate_->GetServerProperties()->Clone();
// Extract and remove the "broken_until" string for "www.google.com:1234".
base::DictionaryValue* server_dict;
ASSERT_TRUE(server_value_copy.GetAsDictionary(&server_dict));
base::ListValue* broken_alt_svc_list;
ASSERT_TRUE(server_dict->GetList("broken_alternative_services",
&broken_alt_svc_list));
ASSERT_EQ(2u, broken_alt_svc_list->GetSize());
base::DictionaryValue* broken_alt_svcs_list_entry;
ASSERT_TRUE(
broken_alt_svc_list->GetDictionary(0, &broken_alt_svcs_list_entry));
ASSERT_TRUE(broken_alt_svcs_list_entry->HasKey("broken_until"));
std::string expiration_string;
ASSERT_TRUE(broken_alt_svcs_list_entry->GetStringWithoutPathExpansion(
"broken_until", &expiration_string));
broken_alt_svcs_list_entry->RemoveWithoutPathExpansion("broken_until",
nullptr);
// Expiration time of "www.google.com:1234" should be 5 minutes minus the
// update-prefs-delay from when the prefs were written.
int64_t expiration_int64;
ASSERT_TRUE(base::StringToInt64(expiration_string, &expiration_int64));
base::TimeDelta expiration_delta =
base::TimeDelta::FromMinutes(5) -
HttpServerPropertiesManager::GetUpdatePrefsDelayForTesting();
time_t time_t_of_prefs_update = static_cast<time_t>(expiration_int64);
EXPECT_LE((time_before_prefs_update + expiration_delta).ToTimeT(),
time_t_of_prefs_update);
EXPECT_GE((time_after_prefs_update + expiration_delta).ToTimeT(),
time_t_of_prefs_update);
// Verify all other preferences.
const char expected_json[] =
"{"
"\"broken_alternative_services\":"
"[{\"broken_count\":1,\"host\":\"www.google.com\",\"port\":1234,"
"\"protocol_str\":\"h2\"},"
"{\"broken_count\":1,\"host\":\"foo.google.com\",\"port\":444,"
"\"protocol_str\":\"h2\"}],"
"\"quic_servers\":"
"{\"https://mail.google.com:80\":"
"{\"server_info\":\"quic_server_info1\"}},"
"\"servers\":["
"{\"https://www.google.com:80\":{"
"\"alternative_service\":[{\"advertised_versions\":[],"
"\"expiration\":\"13756212000000000\",\"port\":443,"
"\"protocol_str\":\"h2\"},"
"{\"advertised_versions\":[],\"expiration\":\"13758804000000000\","
"\"host\":\"www.google.com\",\"port\":1234,\"protocol_str\":\"h2\"}]}},"
"{\"https://mail.google.com:80\":{"
"\"alternative_service\":[{\"advertised_versions\":[],"
"\"expiration\":\"9223372036854775807\",\"host\":\"foo.google.com\","
"\"port\":444,\"protocol_str\":\"h2\"}],"
"\"network_stats\":{\"srtt\":42},"
"\"supports_spdy\":true}}],"
"\"supports_quic\":{\"address\":\"127.0.0.1\",\"used_quic\":true},"
"\"version\":5}";
std::string preferences_json;
EXPECT_TRUE(base::JSONWriter::Write(server_value_copy, &preferences_json));
EXPECT_EQ(expected_json, preferences_json);
}
TEST_P(HttpServerPropertiesManagerTest,
SingleCacheUpdateForMultipleUpdatesScheduled) {
EXPECT_EQ(0u, GetPendingMainThreadTaskCount());
// Update cache.
http_server_props_manager_->ScheduleUpdateCacheForTesting();
EXPECT_EQ(1u, GetPendingMainThreadTaskCount());
// Move forward the task runner short by 20ms.
FastForwardBy(HttpServerPropertiesManager::GetUpdateCacheDelayForTesting() -
base::TimeDelta::FromMilliseconds(20));
// Schedule a new cache update within the time window should be a no-op.
http_server_props_manager_->ScheduleUpdateCacheForTesting();
EXPECT_EQ(1u, GetPendingMainThreadTaskCount());
// Move forward the task runner the extra 20ms, now the cache update should be
// executed.
FastForwardBy(base::TimeDelta::FromMilliseconds(20));
// Since this test has no pref corruption, there shouldn't be any pref update.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_FALSE(MainThreadHasPendingTask());
// Schedule one more cache update. The task should be successfully scheduled
// on the task runner.
http_server_props_manager_->ScheduleUpdateCacheForTesting();
EXPECT_EQ(1u, GetPendingMainThreadTaskCount());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
}
TEST_P(HttpServerPropertiesManagerTest, AddToAlternativeServiceMap) {
std::unique_ptr<base::Value> server_value = base::JSONReader::Read(
"{\"alternative_service\":[{\"port\":443,\"protocol_str\":\"h2\"},"
"{\"port\":123,\"protocol_str\":\"quic\","
"\"expiration\":\"9223372036854775807\"},{\"host\":\"example.org\","
"\"port\":1234,\"protocol_str\":\"h2\","
"\"expiration\":\"13758804000000000\"}]}");
ASSERT_TRUE(server_value);
base::DictionaryValue* server_dict;
ASSERT_TRUE(server_value->GetAsDictionary(&server_dict));
const url::SchemeHostPort server("https", "example.com", 443);
AlternativeServiceMap alternative_service_map;
EXPECT_TRUE(http_server_props_manager_->AddToAlternativeServiceMap(
server, *server_dict, &alternative_service_map));
auto it = alternative_service_map.Get(server);
ASSERT_NE(alternative_service_map.end(), it);
AlternativeServiceInfoVector alternative_service_info_vector = it->second;
ASSERT_EQ(3u, alternative_service_info_vector.size());
EXPECT_EQ(kProtoHTTP2,
alternative_service_info_vector[0].alternative_service().protocol);
EXPECT_EQ("", alternative_service_info_vector[0].alternative_service().host);
EXPECT_EQ(443, alternative_service_info_vector[0].alternative_service().port);
// Expiration defaults to one day from now, testing with tolerance.
const base::Time now = base::Time::Now();
const base::Time expiration = alternative_service_info_vector[0].expiration();
EXPECT_LE(now + base::TimeDelta::FromHours(23), expiration);
EXPECT_GE(now + base::TimeDelta::FromDays(1), expiration);
EXPECT_EQ(kProtoQUIC,
alternative_service_info_vector[1].alternative_service().protocol);
EXPECT_EQ("", alternative_service_info_vector[1].alternative_service().host);
EXPECT_EQ(123, alternative_service_info_vector[1].alternative_service().port);
// numeric_limits<int64_t>::max() represents base::Time::Max().
EXPECT_EQ(base::Time::Max(), alternative_service_info_vector[1].expiration());
EXPECT_EQ(kProtoHTTP2,
alternative_service_info_vector[2].alternative_service().protocol);
EXPECT_EQ("example.org",
alternative_service_info_vector[2].alternative_service().host);
EXPECT_EQ(1234,
alternative_service_info_vector[2].alternative_service().port);
base::Time expected_expiration;
ASSERT_TRUE(
base::Time::FromUTCString("2036-12-31 10:00:00", &expected_expiration));
EXPECT_EQ(expected_expiration,
alternative_service_info_vector[2].expiration());
}
// Regression test for https://crbug.com/615497.
TEST_P(HttpServerPropertiesManagerTest, DoNotLoadAltSvcForInsecureOrigins) {
std::unique_ptr<base::Value> server_value = base::JSONReader::Read(
"{\"alternative_service\":[{\"port\":443,\"protocol_str\":\"h2\","
"\"expiration\":\"9223372036854775807\"}]}");
ASSERT_TRUE(server_value);
base::DictionaryValue* server_dict;
ASSERT_TRUE(server_value->GetAsDictionary(&server_dict));
const url::SchemeHostPort server("http", "example.com", 80);
AlternativeServiceMap alternative_service_map;
EXPECT_FALSE(http_server_props_manager_->AddToAlternativeServiceMap(
server, *server_dict, &alternative_service_map));
auto it = alternative_service_map.Get(server);
EXPECT_EQ(alternative_service_map.end(), it);
}
// Do not persist expired alternative service entries to disk.
TEST_P(HttpServerPropertiesManagerTest, DoNotPersistExpiredAlternativeService) {
AlternativeServiceInfoVector alternative_service_info_vector;
const AlternativeService broken_alternative_service(
kProtoHTTP2, "broken.example.com", 443);
const base::Time time_one_day_later =
base::Time::Now() + base::TimeDelta::FromDays(1);
alternative_service_info_vector.push_back(
AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
broken_alternative_service, time_one_day_later));
// #1: MarkAlternativeServiceBroken().
http_server_props_manager_->MarkAlternativeServiceBroken(
broken_alternative_service);
const AlternativeService expired_alternative_service(
kProtoHTTP2, "expired.example.com", 443);
const base::Time time_one_day_ago =
base::Time::Now() - base::TimeDelta::FromDays(1);
alternative_service_info_vector.push_back(
AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
expired_alternative_service, time_one_day_ago));
const AlternativeService valid_alternative_service(kProtoHTTP2,
"valid.example.com", 443);
alternative_service_info_vector.push_back(
AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
valid_alternative_service, time_one_day_later));
const url::SchemeHostPort server("https", "www.example.com", 443);
// #2: SetAlternativeServices().
ASSERT_TRUE(http_server_props_manager_->SetAlternativeServices(
server, alternative_service_info_vector));
// |net_test_task_runner_| has a remaining pending task to expire
// |broken_alternative_service| at |time_one_day_later|. Fast forward enough
// such that the prefs update task is executed but not the task to expire
// |broken_alternative_service|.
EXPECT_EQ(2U, GetPendingMainThreadTaskCount());
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
FastForwardBy(HttpServerPropertiesManager::GetUpdatePrefsDelayForTesting());
EXPECT_EQ(1U, GetPendingMainThreadTaskCount());
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
const base::DictionaryValue* pref_dict =
pref_delegate_->GetServerProperties();
const base::ListValue* servers_list = nullptr;
ASSERT_TRUE(pref_dict->GetListWithoutPathExpansion("servers", &servers_list));
auto it = servers_list->begin();
const base::DictionaryValue* server_pref_dict;
ASSERT_TRUE(it->GetAsDictionary(&server_pref_dict));
const base::DictionaryValue* example_pref_dict;
ASSERT_TRUE(server_pref_dict->GetDictionaryWithoutPathExpansion(
"https://www.example.com", &example_pref_dict));
const base::ListValue* altsvc_list;
ASSERT_TRUE(example_pref_dict->GetList("alternative_service", &altsvc_list));
ASSERT_EQ(2u, altsvc_list->GetSize());
const base::DictionaryValue* altsvc_entry;
std::string hostname;
ASSERT_TRUE(altsvc_list->GetDictionary(0, &altsvc_entry));
ASSERT_TRUE(altsvc_entry->GetString("host", &hostname));
EXPECT_EQ("broken.example.com", hostname);
ASSERT_TRUE(altsvc_list->GetDictionary(1, &altsvc_entry));
ASSERT_TRUE(altsvc_entry->GetString("host", &hostname));
EXPECT_EQ("valid.example.com", hostname);
}
// Test that expired alternative service entries on disk are ignored.
TEST_P(HttpServerPropertiesManagerTest, DoNotLoadExpiredAlternativeService) {
auto alternative_service_list = std::make_unique<base::ListValue>();
auto expired_dict = std::make_unique<base::DictionaryValue>();
expired_dict->SetString("protocol_str", "h2");
expired_dict->SetString("host", "expired.example.com");
expired_dict->SetInteger("port", 443);
base::Time time_one_day_ago =
base::Time::Now() - base::TimeDelta::FromDays(1);
expired_dict->SetString(
"expiration", base::Int64ToString(time_one_day_ago.ToInternalValue()));
alternative_service_list->Append(std::move(expired_dict));
auto valid_dict = std::make_unique<base::DictionaryValue>();
valid_dict->SetString("protocol_str", "h2");
valid_dict->SetString("host", "valid.example.com");
valid_dict->SetInteger("port", 443);
valid_dict->SetString(
"expiration", base::Int64ToString(one_day_from_now_.ToInternalValue()));
alternative_service_list->Append(std::move(valid_dict));
base::DictionaryValue server_pref_dict;
server_pref_dict.SetWithoutPathExpansion("alternative_service",
std::move(alternative_service_list));
const url::SchemeHostPort server("https", "example.com", 443);
AlternativeServiceMap alternative_service_map;
ASSERT_TRUE(http_server_props_manager_->AddToAlternativeServiceMap(
server, server_pref_dict, &alternative_service_map));
auto it = alternative_service_map.Get(server);
ASSERT_NE(alternative_service_map.end(), it);
AlternativeServiceInfoVector alternative_service_info_vector = it->second;
ASSERT_EQ(1u, alternative_service_info_vector.size());
EXPECT_EQ(kProtoHTTP2,
alternative_service_info_vector[0].alternative_service().protocol);
EXPECT_EQ("valid.example.com",
alternative_service_info_vector[0].alternative_service().host);
EXPECT_EQ(443, alternative_service_info_vector[0].alternative_service().port);
EXPECT_EQ(one_day_from_now_, alternative_service_info_vector[0].expiration());
}
// Make sure prefs are updated on destruction.
TEST_P(HttpServerPropertiesManagerTest, UpdatePrefsOnShutdown) {
int pref_updates = 0;
pref_delegate_->set_extra_update_prefs_callback(
base::Bind([](int* updates) { (*updates)++; }, &pref_updates));
http_server_props_manager_.reset();
EXPECT_EQ(1, pref_updates);
}
TEST_P(HttpServerPropertiesManagerTest, PersistAdvertisedVersionsToPref) {
const url::SchemeHostPort server_www("https", "www.google.com", 80);
const url::SchemeHostPort server_mail("https", "mail.google.com", 80);
// #1 & #2: Set alternate protocol.
AlternativeServiceInfoVector alternative_service_info_vector;
// Quic alternative service set with two advertised QUIC versions.
AlternativeService quic_alternative_service1(kProtoQUIC, "", 443);
base::Time expiration1;
ASSERT_TRUE(base::Time::FromUTCString("2036-12-01 10:00:00", &expiration1));
quic::QuicTransportVersionVector advertised_versions = {
quic::QUIC_VERSION_44, quic::QUIC_VERSION_39};
alternative_service_info_vector.push_back(
AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
quic_alternative_service1, expiration1, advertised_versions));
// HTTP/2 alternative service should not set any advertised version.
AlternativeService h2_alternative_service(kProtoHTTP2, "www.google.com",
1234);
base::Time expiration2;
ASSERT_TRUE(base::Time::FromUTCString("2036-12-31 10:00:00", &expiration2));
alternative_service_info_vector.push_back(
AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
h2_alternative_service, expiration2));
ASSERT_TRUE(http_server_props_manager_->SetAlternativeServices(
server_www, alternative_service_info_vector));
// Set another QUIC alternative service with a single advertised QUIC version.
AlternativeService mail_alternative_service(kProtoQUIC, "foo.google.com",
444);
base::Time expiration3 = base::Time::Max();
ASSERT_TRUE(http_server_props_manager_->SetQuicAlternativeService(
server_mail, mail_alternative_service, expiration3,
advertised_versions_));
// #3: Set ServerNetworkStats.
ServerNetworkStats stats;
stats.srtt = base::TimeDelta::FromInternalValue(42);
http_server_props_manager_->SetServerNetworkStats(server_mail, stats);
// #4: Set quic_server_info string.
quic::QuicServerId mail_quic_server_id("mail.google.com", 80, false);
std::string quic_server_info1("quic_server_info1");
http_server_props_manager_->SetQuicServerInfo(mail_quic_server_id,
quic_server_info1);
// #5: Set SupportsQuic.
IPAddress actual_address(127, 0, 0, 1);
http_server_props_manager_->SetSupportsQuic(true, actual_address);
// Update Prefs.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_NE(0u, GetPendingMainThreadTaskCount());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
// Verify preferences with correct advertised version field.
const char expected_json[] =
"{\"quic_servers\":{\"https://mail.google.com:80\":{"
"\"server_info\":\"quic_server_info1\"}},\"servers\":["
"{\"https://www.google.com:80\":{\"alternative_service\":[{"
"\"advertised_versions\":[39,44],\"expiration\":\"13756212000000000\","
"\"port\":443,\"protocol_str\":\"quic\"},{\"advertised_versions\":[],"
"\"expiration\":\"13758804000000000\",\"host\":\"www.google.com\","
"\"port\":1234,\"protocol_str\":\"h2\"}]}},"
"{\"https://mail.google.com:80\":{\"alternative_service\":[{"
"\"advertised_versions\":[46],\"expiration\":\"9223372036854775807\","
"\"host\":\"foo.google.com\",\"port\":444,\"protocol_str\":\"quic\"}],"
"\"network_stats\":{\"srtt\":42}}}],\"supports_quic\":{"
"\"address\":\"127.0.0.1\",\"used_quic\":true},\"version\":5}";
const base::Value* http_server_properties =
pref_delegate_->GetServerProperties();
std::string preferences_json;
EXPECT_TRUE(
base::JSONWriter::Write(*http_server_properties, &preferences_json));
EXPECT_EQ(expected_json, preferences_json);
}
TEST_P(HttpServerPropertiesManagerTest, ReadAdvertisedVersionsFromPref) {
std::unique_ptr<base::Value> server_value = base::JSONReader::Read(
"{\"alternative_service\":["
"{\"port\":443,\"protocol_str\":\"quic\"},"
"{\"port\":123,\"protocol_str\":\"quic\","
"\"expiration\":\"9223372036854775807\","
"\"advertised_versions\":[44,39]}]}");
ASSERT_TRUE(server_value);
base::DictionaryValue* server_dict;
ASSERT_TRUE(server_value->GetAsDictionary(&server_dict));
const url::SchemeHostPort server("https", "example.com", 443);
AlternativeServiceMap alternative_service_map;
EXPECT_TRUE(http_server_props_manager_->AddToAlternativeServiceMap(
server, *server_dict, &alternative_service_map));
auto it = alternative_service_map.Get(server);
ASSERT_NE(alternative_service_map.end(), it);
AlternativeServiceInfoVector alternative_service_info_vector = it->second;
ASSERT_EQ(2u, alternative_service_info_vector.size());
// Verify the first alternative service with no advertised version listed.
EXPECT_EQ(kProtoQUIC,
alternative_service_info_vector[0].alternative_service().protocol);
EXPECT_EQ("", alternative_service_info_vector[0].alternative_service().host);
EXPECT_EQ(443, alternative_service_info_vector[0].alternative_service().port);
// Expiration defaults to one day from now, testing with tolerance.
const base::Time now = base::Time::Now();
const base::Time expiration = alternative_service_info_vector[0].expiration();
EXPECT_LE(now + base::TimeDelta::FromHours(23), expiration);
EXPECT_GE(now + base::TimeDelta::FromDays(1), expiration);
EXPECT_TRUE(alternative_service_info_vector[0].advertised_versions().empty());
// Verify the second alterntaive service with two advertised versions.
EXPECT_EQ(kProtoQUIC,
alternative_service_info_vector[1].alternative_service().protocol);
EXPECT_EQ("", alternative_service_info_vector[1].alternative_service().host);
EXPECT_EQ(123, alternative_service_info_vector[1].alternative_service().port);
EXPECT_EQ(base::Time::Max(), alternative_service_info_vector[1].expiration());
// Verify advertised versions.
const quic::QuicTransportVersionVector loaded_advertised_versions =
alternative_service_info_vector[1].advertised_versions();
EXPECT_EQ(2u, loaded_advertised_versions.size());
EXPECT_EQ(quic::QUIC_VERSION_39, loaded_advertised_versions[0]);
EXPECT_EQ(quic::QUIC_VERSION_44, loaded_advertised_versions[1]);
}
TEST_P(HttpServerPropertiesManagerTest,
UpdatePrefWhenAdvertisedVersionsChange) {
const url::SchemeHostPort server_www("https", "www.google.com", 80);
// #1: Set alternate protocol.
AlternativeServiceInfoVector alternative_service_info_vector;
// Quic alternative service set with a single QUIC version:
// quic::QUIC_VERSION_44.
AlternativeService quic_alternative_service1(kProtoQUIC, "", 443);
base::Time expiration1;
ASSERT_TRUE(base::Time::FromUTCString("2036-12-01 10:00:00", &expiration1));
alternative_service_info_vector.push_back(
AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
quic_alternative_service1, expiration1, advertised_versions_));
ASSERT_TRUE(http_server_props_manager_->SetAlternativeServices(
server_www, alternative_service_info_vector));
// Set quic_server_info string.
quic::QuicServerId mail_quic_server_id("mail.google.com", 80, false);
std::string quic_server_info1("quic_server_info1");
http_server_props_manager_->SetQuicServerInfo(mail_quic_server_id,
quic_server_info1);
// Set SupportsQuic.
IPAddress actual_address(127, 0, 0, 1);
http_server_props_manager_->SetSupportsQuic(true, actual_address);
// Update Prefs.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
// Verify preferences with correct advertised version field.
const char expected_json[] =
"{\"quic_servers\":{\"https://mail.google.com:80\":"
"{\"server_info\":\"quic_server_info1\"}},\"servers\":["
"{\"https://www.google.com:80\":"
#if defined(COBALT_QUIC46)
"{\"alternative_service\":[{\"advertised_versions\":[46],"
#else
"{\"alternative_service\":[{\"advertised_versions\":[43],"
#endif
"\"expiration\":\"13756212000000000\",\"port\":443,"
"\"protocol_str\":\"quic\"}]}}],\"supports_quic\":"
"{\"address\":\"127.0.0.1\",\"used_quic\":true},\"version\":5}";
const base::Value* http_server_properties =
pref_delegate_->GetServerProperties();
std::string preferences_json;
EXPECT_TRUE(
base::JSONWriter::Write(*http_server_properties, &preferences_json));
EXPECT_EQ(expected_json, preferences_json);
// #2: Set AlternativeService with different advertised_versions for the same
// AlternativeService.
AlternativeServiceInfoVector alternative_service_info_vector_2;
// Quic alternative service set with two advertised QUIC versions.
quic::QuicTransportVersionVector advertised_versions = {
#if defined(COBALT_QUIC46)
quic::QUIC_VERSION_44,
quic::QUIC_VERSION_39
};
#else
quic::QUIC_VERSION_44,
quic::QUIC_VERSION_35
};
#endif
alternative_service_info_vector_2.push_back(
AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
quic_alternative_service1, expiration1, advertised_versions));
ASSERT_TRUE(http_server_props_manager_->SetAlternativeServices(
server_www, alternative_service_info_vector_2));
// Update Prefs.
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardUntilNoTasksRemain();
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
// Verify preferences updated with new advertised versions.
const char expected_json_updated[] =
"{\"quic_servers\":{\"https://mail.google.com:80\":"
"{\"server_info\":\"quic_server_info1\"}},\"servers\":["
"{\"https://www.google.com:80\":"
#if defined(COBALT_QUIC46)
"{\"alternative_service\":[{\"advertised_versions\":[39,44],"
#else
"{\"alternative_service\":[{\"advertised_versions\":[35,44],"
#endif
"\"expiration\":\"13756212000000000\",\"port\":443,"
"\"protocol_str\":\"quic\"}]}}],\"supports_quic\":"
"{\"address\":\"127.0.0.1\",\"used_quic\":true},\"version\":5}";
EXPECT_TRUE(
base::JSONWriter::Write(*http_server_properties, &preferences_json));
EXPECT_EQ(expected_json_updated, preferences_json);
// #3: Set AlternativeService with same advertised_versions.
AlternativeServiceInfoVector alternative_service_info_vector_3;
// A same set of QUIC versions but listed in a different order.
quic::QuicTransportVersionVector advertised_versions_2 = {
#if defined(COBALT_QUIC46)
quic::QUIC_VERSION_39, quic::QUIC_VERSION_44};
#else
quic::QUIC_VERSION_35, quic::QUIC_VERSION_44};
#endif
alternative_service_info_vector_3.push_back(
AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
quic_alternative_service1, expiration1, advertised_versions_2));
ASSERT_FALSE(http_server_props_manager_->SetAlternativeServices(
server_www, alternative_service_info_vector_3));
// No Prefs update.
EXPECT_FALSE(MainThreadHasPendingTask());
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
}
TEST_P(HttpServerPropertiesManagerTest, UpdateCacheWithPrefs) {
AlternativeService cached_broken_service(kProtoQUIC, "cached_broken", 443);
AlternativeService cached_broken_service2(kProtoQUIC, "cached_broken2", 443);
AlternativeService cached_recently_broken_service(kProtoQUIC,
"cached_rbroken", 443);
http_server_props_manager_->MarkAlternativeServiceBroken(
cached_broken_service);
http_server_props_manager_->MarkAlternativeServiceBroken(
cached_broken_service2);
http_server_props_manager_->MarkAlternativeServiceRecentlyBroken(
cached_recently_broken_service);
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_TRUE(MainThreadHasPendingTask());
// Run the prefs update task but not the expiration task for
// |cached_broken_service|.
FastForwardBy(HttpServerPropertiesManager::GetUpdatePrefsDelayForTesting());
EXPECT_TRUE(MainThreadHasPendingTask());
EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates());
// Load the |pref_delegate_| with some JSON to verify updating the cache from
// prefs. For the broken alternative services "www.google.com:1234" and
// "cached_broken", the expiration time will be one day from now.
std::string expiration_str =
base::Int64ToString(static_cast<int64_t>(one_day_from_now_.ToTimeT()));
std::unique_ptr<base::Value> server_value = base::JSONReader::Read(
"{"
"\"broken_alternative_services\":["
"{\"broken_until\":\"" +
expiration_str +
"\","
"\"host\":\"www.google.com\",\"port\":1234,\"protocol_str\":\"h2\"},"
"{\"broken_count\":2,\"broken_until\":\"" +
expiration_str +
"\","
"\"host\":\"cached_broken\",\"port\":443,\"protocol_str\":\"quic\"},"
"{\"broken_count\":3,"
"\"host\":\"cached_rbroken\",\"port\":443,\"protocol_str\":\"quic\"}],"
"\"quic_servers\":{"
"\"https://mail.google.com:80\":{"
"\"server_info\":\"quic_server_info1\"}"
"},"
"\"servers\":["
"{\"https://www.google.com:80\":{"
"\"alternative_service\":["
"{\"expiration\":\"13756212000000000\",\"port\":443,"
"\"protocol_str\":\"h2\"},"
"{\"expiration\":\"13758804000000000\",\"host\":\"www.google.com\","
"\"port\":1234,\"protocol_str\":\"h2\"}"
"]"
"}},"
"{\"https://mail.google.com:80\":{"
"\"alternative_service\":["
"{\"expiration\":\"9223372036854775807\",\"host\":\"foo.google.com\","
"\"port\":444,\"protocol_str\":\"h2\"}"
"],"
"\"network_stats\":{\"srtt\":42}"
"}}"
"],"
"\"supports_quic\":"
"{\"address\":\"127.0.0.1\",\"used_quic\":true},"
"\"version\":5"
"}");
ASSERT_TRUE(server_value);
base::DictionaryValue* server_dict;
ASSERT_TRUE(server_value->GetAsDictionary(&server_dict));
pref_delegate_->SetPrefs(*server_dict);
EXPECT_TRUE(MainThreadHasPendingTask());
// Run the cache update task but not the expiration task for
// |cached_broken_service|.
FastForwardBy(NextMainThreadPendingTaskDelay());
EXPECT_TRUE(MainThreadHasPendingTask());
//
// Verify alternative service info for https://www.google.com
//
AlternativeServiceInfoVector alternative_service_info_vector =
http_server_props_manager_->GetAlternativeServiceInfos(
url::SchemeHostPort("https", "www.google.com", 80));
ASSERT_EQ(2u, alternative_service_info_vector.size());
EXPECT_EQ(kProtoHTTP2,
alternative_service_info_vector[0].alternative_service().protocol);
EXPECT_EQ("www.google.com",
alternative_service_info_vector[0].alternative_service().host);
EXPECT_EQ(443, alternative_service_info_vector[0].alternative_service().port);
EXPECT_EQ(
"13756212000000000",
base::Int64ToString(
alternative_service_info_vector[0].expiration().ToInternalValue()));
EXPECT_EQ(kProtoHTTP2,
alternative_service_info_vector[1].alternative_service().protocol);
EXPECT_EQ("www.google.com",
alternative_service_info_vector[1].alternative_service().host);
EXPECT_EQ(1234,
alternative_service_info_vector[1].alternative_service().port);
EXPECT_EQ(
"13758804000000000",
base::Int64ToString(
alternative_service_info_vector[1].expiration().ToInternalValue()));
//
// Verify alternative service info for https://mail.google.com
//
alternative_service_info_vector =
http_server_props_manager_->GetAlternativeServiceInfos(
url::SchemeHostPort("https", "mail.google.com", 80));
ASSERT_EQ(1u, alternative_service_info_vector.size());
EXPECT_EQ(kProtoHTTP2,
alternative_service_info_vector[0].alternative_service().protocol);
EXPECT_EQ("foo.google.com",
alternative_service_info_vector[0].alternative_service().host);
EXPECT_EQ(444, alternative_service_info_vector[0].alternative_service().port);
EXPECT_EQ(
"9223372036854775807",
base::Int64ToString(
alternative_service_info_vector[0].expiration().ToInternalValue()));
//
// Verify broken alternative services.
//
AlternativeService prefs_broken_service(kProtoHTTP2, "www.google.com", 1234);
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
cached_broken_service));
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
cached_broken_service2));
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
prefs_broken_service));
// Verify brokenness expiration times.
// |cached_broken_service|'s expiration time should've been overwritten by the
// prefs to be approximately 1 day from now. |cached_broken_service2|'s
// expiration time should still be 5 minutes due to being marked broken.
// |prefs_broken_service|'s expiration time should be approximately 1 day from
// now which comes from the prefs.
FastForwardBy(base::TimeDelta::FromMinutes(4));
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
cached_broken_service));
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
cached_broken_service2));
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
prefs_broken_service));
FastForwardBy(base::TimeDelta::FromDays(1));
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
cached_broken_service));
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
cached_broken_service2));
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
prefs_broken_service));
// Now that |prefs_broken_service|'s brokenness has expired, it should've
// been removed from the alternative services info vectors of all servers.
alternative_service_info_vector =
http_server_props_manager_->GetAlternativeServiceInfos(
url::SchemeHostPort("https", "www.google.com", 80));
ASSERT_EQ(1u, alternative_service_info_vector.size());
//
// Verify recently broken alternative services.
//
// If an entry is already in cache, the broken count in the prefs should
// overwrite the one in the cache.
// |prefs_broken_service| should have broken-count 1 from prefs.
// |cached_recently_broken_service| should have broken-count 3 from prefs.
// |cached_broken_service| should have broken-count 2 from prefs.
// |cached_broken_service2| should have broken-count 1 from being marked
// broken.
EXPECT_TRUE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
prefs_broken_service));
EXPECT_TRUE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
cached_recently_broken_service));
EXPECT_TRUE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
cached_broken_service));
EXPECT_TRUE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
cached_broken_service2));
// Make sure |prefs_broken_service| has the right expiration delay when marked
// broken. Since |prefs_broken_service| had no broken_count specified in the
// prefs, a broken_count value of 1 should have been assumed by
// |http_server_props_manager_|.
http_server_props_manager_->MarkAlternativeServiceBroken(
prefs_broken_service);
EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates());
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardBy(base::TimeDelta::FromMinutes(10) -
base::TimeDelta::FromInternalValue(1));
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
prefs_broken_service));
FastForwardBy(base::TimeDelta::FromInternalValue(1));
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
prefs_broken_service));
// Make sure |cached_recently_broken_service| has the right expiration delay
// when marked broken.
http_server_props_manager_->MarkAlternativeServiceBroken(
cached_recently_broken_service);
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardBy(base::TimeDelta::FromMinutes(40) -
base::TimeDelta::FromInternalValue(1));
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
cached_recently_broken_service));
FastForwardBy(base::TimeDelta::FromInternalValue(1));
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
cached_recently_broken_service));
// Make sure |cached_broken_service| has the right expiration delay when
// marked broken.
http_server_props_manager_->MarkAlternativeServiceBroken(
cached_broken_service);
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardBy(base::TimeDelta::FromMinutes(20) -
base::TimeDelta::FromInternalValue(1));
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
cached_broken_service));
FastForwardBy(base::TimeDelta::FromInternalValue(1));
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
cached_broken_service));
// Make sure |cached_broken_service2| has the right expiration delay when
// marked broken.
http_server_props_manager_->MarkAlternativeServiceBroken(
cached_broken_service2);
EXPECT_TRUE(MainThreadHasPendingTask());
FastForwardBy(base::TimeDelta::FromMinutes(10) -
base::TimeDelta::FromInternalValue(1));
EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
cached_broken_service2));
FastForwardBy(base::TimeDelta::FromInternalValue(1));
EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
cached_broken_service2));
//
// Verify ServerNetworkStats.
//
const ServerNetworkStats* server_network_stats =
http_server_props_manager_->GetServerNetworkStats(
url::SchemeHostPort("https", "mail.google.com", 80));
EXPECT_TRUE(server_network_stats);
EXPECT_EQ(server_network_stats->srtt,
base::TimeDelta::FromInternalValue(42));
//
// Verify QUIC server info.
//
const std::string* quic_server_info =
http_server_props_manager_->GetQuicServerInfo(
quic::QuicServerId("mail.google.com", 80, false));
EXPECT_EQ("quic_server_info1", *quic_server_info);
//
// Verify supports QUIC.
//
IPAddress actual_address(127, 0, 0, 1);
EXPECT_TRUE(http_server_props_manager_->GetSupportsQuic(&actual_address));
EXPECT_EQ(4, pref_delegate_->GetAndClearNumPrefUpdates());
}
} // namespace net