// 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/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.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/base/port_util.h"
#include "url/gurl.h"

namespace net {

namespace {

// Time to wait before starting an update the http_server_properties_impl_ cache
// from preferences. Scheduling another update during this period will reset the
// timer.
const int64_t kUpdateCacheDelayMs = 1000;

// Time to wait before starting an update the preferences from the
// http_server_properties_impl_ cache. Scheduling another update during this
// period will reset the timer.
const int64_t kUpdatePrefsDelayMs = 60000;

// "version" 0 indicates, http_server_properties doesn't have "version"
// property.
const int kMissingVersion = 0;

// The version number of persisted http_server_properties.
const int kVersionNumber = 5;

// Persist 200 MRU AlternateProtocolHostPortPairs.
const int kMaxAlternateProtocolHostsToPersist = 200;

// Persist 200 MRU SpdySettingsHostPortPairs.
const int kMaxSpdySettingsHostsToPersist = 200;

// Persist 300 MRU SupportsSpdyServerHostPortPairs.
const int kMaxSupportsSpdyServerHostsToPersist = 300;

// Persist 200 ServerNetworkStats.
const int kMaxServerNetworkStatsHostsToPersist = 200;

const char kVersionKey[] = "version";
const char kServersKey[] = "servers";
const char kSupportsSpdyKey[] = "supports_spdy";
const char kSettingsKey[] = "settings";
const char kSupportsQuicKey[] = "supports_quic";
const char kQuicServers[] = "quic_servers";
const char kServerInfoKey[] = "server_info";
const char kUsedQuicKey[] = "used_quic";
const char kAddressKey[] = "address";
const char kAlternativeServiceKey[] = "alternative_service";
const char kProtocolKey[] = "protocol_str";
const char kHostKey[] = "host";
const char kPortKey[] = "port";
const char kExpirationKey[] = "expiration";
const char kNetworkStatsKey[] = "network_stats";
const char kSrttKey[] = "srtt";

}  // namespace

////////////////////////////////////////////////////////////////////////////////
//  HttpServerPropertiesManager

HttpServerPropertiesManager::PrefDelegate::~PrefDelegate() {}

HttpServerPropertiesManager::HttpServerPropertiesManager(
    PrefDelegate* pref_delegate,
    scoped_refptr<base::SequencedTaskRunner> network_task_runner)
    : pref_task_runner_(base::ThreadTaskRunnerHandle::Get()),
      pref_delegate_(pref_delegate),
      setting_prefs_(false),
      network_task_runner_(network_task_runner) {
  DCHECK(pref_delegate_);
  pref_weak_ptr_factory_.reset(
      new base::WeakPtrFactory<HttpServerPropertiesManager>(this));
  pref_weak_ptr_ = pref_weak_ptr_factory_->GetWeakPtr();
  pref_cache_update_timer_.reset(new base::OneShotTimer);
  pref_delegate_->StartListeningForUpdates(
      base::Bind(&HttpServerPropertiesManager::OnHttpServerPropertiesChanged,
                 base::Unretained(this)));
}

HttpServerPropertiesManager::~HttpServerPropertiesManager() {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  network_weak_ptr_factory_.reset();
}

void HttpServerPropertiesManager::InitializeOnNetworkThread() {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  network_weak_ptr_factory_.reset(
      new base::WeakPtrFactory<HttpServerPropertiesManager>(this));
  http_server_properties_impl_.reset(new HttpServerPropertiesImpl());

  network_prefs_update_timer_.reset(new base::OneShotTimer);

  pref_task_runner_->PostTask(
      FROM_HERE,
      base::Bind(&HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread,
                 pref_weak_ptr_));
}

void HttpServerPropertiesManager::ShutdownOnPrefThread() {
  DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
  // Cancel any pending updates, and stop listening for pref change updates.
  pref_cache_update_timer_->Stop();
  pref_weak_ptr_factory_.reset();
  pref_delegate_->StopListeningForUpdates();
}

// static
void HttpServerPropertiesManager::SetVersion(
    base::DictionaryValue* http_server_properties_dict,
    int version_number) {
  if (version_number < 0)
    version_number = kVersionNumber;
  DCHECK_LE(version_number, kVersionNumber);
  if (version_number <= kVersionNumber)
    http_server_properties_dict->SetInteger(kVersionKey, version_number);
}

// This is required for conformance with the HttpServerProperties interface.
base::WeakPtr<HttpServerProperties> HttpServerPropertiesManager::GetWeakPtr() {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return network_weak_ptr_factory_->GetWeakPtr();
}

void HttpServerPropertiesManager::Clear() {
  Clear(base::Closure());
}

void HttpServerPropertiesManager::Clear(const base::Closure& completion) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());

  http_server_properties_impl_->Clear();
  UpdatePrefsFromCacheOnNetworkThread(completion);
}

bool HttpServerPropertiesManager::SupportsRequestPriority(
    const url::SchemeHostPort& server) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->SupportsRequestPriority(server);
}

bool HttpServerPropertiesManager::GetSupportsSpdy(
    const url::SchemeHostPort& server) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->GetSupportsSpdy(server);
}

void HttpServerPropertiesManager::SetSupportsSpdy(
    const url::SchemeHostPort& server,
    bool support_spdy) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());

  bool old_support_spdy = http_server_properties_impl_->GetSupportsSpdy(server);
  http_server_properties_impl_->SetSupportsSpdy(server, support_spdy);
  bool new_support_spdy = http_server_properties_impl_->GetSupportsSpdy(server);
  if (old_support_spdy != new_support_spdy)
    ScheduleUpdatePrefsOnNetworkThread(SUPPORTS_SPDY);
}

bool HttpServerPropertiesManager::RequiresHTTP11(const HostPortPair& server) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->RequiresHTTP11(server);
}

void HttpServerPropertiesManager::SetHTTP11Required(
    const HostPortPair& server) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());

  http_server_properties_impl_->SetHTTP11Required(server);
  ScheduleUpdatePrefsOnNetworkThread(HTTP_11_REQUIRED);
}

void HttpServerPropertiesManager::MaybeForceHTTP11(const HostPortPair& server,
                                                   SSLConfig* ssl_config) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  http_server_properties_impl_->MaybeForceHTTP11(server, ssl_config);
}

AlternativeServiceVector HttpServerPropertiesManager::GetAlternativeServices(
    const url::SchemeHostPort& origin) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->GetAlternativeServices(origin);
}

bool HttpServerPropertiesManager::SetAlternativeService(
    const url::SchemeHostPort& origin,
    const AlternativeService& alternative_service,
    base::Time expiration) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  const bool changed = http_server_properties_impl_->SetAlternativeService(
      origin, alternative_service, expiration);
  if (changed) {
    ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICES);
  }
  return changed;
}

bool HttpServerPropertiesManager::SetAlternativeServices(
    const url::SchemeHostPort& origin,
    const AlternativeServiceInfoVector& alternative_service_info_vector) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  const bool changed = http_server_properties_impl_->SetAlternativeServices(
      origin, alternative_service_info_vector);
  if (changed) {
    ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICES);
  }
  return changed;
}

void HttpServerPropertiesManager::MarkAlternativeServiceBroken(
    const AlternativeService& alternative_service) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  http_server_properties_impl_->MarkAlternativeServiceBroken(
      alternative_service);
  ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_BROKEN);
}

void HttpServerPropertiesManager::MarkAlternativeServiceRecentlyBroken(
    const AlternativeService& alternative_service) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  http_server_properties_impl_->MarkAlternativeServiceRecentlyBroken(
      alternative_service);
  ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_RECENTLY_BROKEN);
}

bool HttpServerPropertiesManager::IsAlternativeServiceBroken(
    const AlternativeService& alternative_service) const {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->IsAlternativeServiceBroken(
      alternative_service);
}

bool HttpServerPropertiesManager::WasAlternativeServiceRecentlyBroken(
    const AlternativeService& alternative_service) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->WasAlternativeServiceRecentlyBroken(
      alternative_service);
}

void HttpServerPropertiesManager::ConfirmAlternativeService(
    const AlternativeService& alternative_service) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  bool old_value = http_server_properties_impl_->IsAlternativeServiceBroken(
      alternative_service);
  http_server_properties_impl_->ConfirmAlternativeService(alternative_service);
  bool new_value = http_server_properties_impl_->IsAlternativeServiceBroken(
      alternative_service);
  // For persisting, we only care about the value returned by
  // IsAlternativeServiceBroken. If that value changes, then call persist.
  if (old_value != new_value)
    ScheduleUpdatePrefsOnNetworkThread(CONFIRM_ALTERNATIVE_SERVICE);
}

void HttpServerPropertiesManager::ClearAlternativeServices(
    const url::SchemeHostPort& origin) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  const AlternativeServiceMap& map =
      http_server_properties_impl_->alternative_service_map();
  size_t old_size = map.size();
  http_server_properties_impl_->ClearAlternativeServices(origin);
  size_t new_size = map.size();
  // Persist only if we have deleted an entry.
  if (old_size != new_size)
    ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALTERNATIVE_SERVICE);
}

const AlternativeServiceMap&
HttpServerPropertiesManager::alternative_service_map() const {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->alternative_service_map();
}

std::unique_ptr<base::Value>
HttpServerPropertiesManager::GetAlternativeServiceInfoAsValue() const {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->GetAlternativeServiceInfoAsValue();
}

const SettingsMap& HttpServerPropertiesManager::GetSpdySettings(
    const url::SchemeHostPort& server) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->GetSpdySettings(server);
}

bool HttpServerPropertiesManager::SetSpdySetting(
    const url::SchemeHostPort& server,
    SpdySettingsIds id,
    SpdySettingsFlags flags,
    uint32_t value) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  bool persist =
      http_server_properties_impl_->SetSpdySetting(server, id, flags, value);
  if (persist)
    ScheduleUpdatePrefsOnNetworkThread(SET_SPDY_SETTING);
  return persist;
}

void HttpServerPropertiesManager::ClearSpdySettings(
    const url::SchemeHostPort& server) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  http_server_properties_impl_->ClearSpdySettings(server);
  ScheduleUpdatePrefsOnNetworkThread(CLEAR_SPDY_SETTINGS);
}

void HttpServerPropertiesManager::ClearAllSpdySettings() {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  http_server_properties_impl_->ClearAllSpdySettings();
  ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALL_SPDY_SETTINGS);
}

const SpdySettingsMap& HttpServerPropertiesManager::spdy_settings_map()
    const {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->spdy_settings_map();
}

bool HttpServerPropertiesManager::GetSupportsQuic(
    IPAddress* last_address) const {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->GetSupportsQuic(last_address);
}

void HttpServerPropertiesManager::SetSupportsQuic(bool used_quic,
                                                  const IPAddress& address) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  IPAddress old_last_quic_addr;
  http_server_properties_impl_->GetSupportsQuic(&old_last_quic_addr);
  http_server_properties_impl_->SetSupportsQuic(used_quic, address);
  IPAddress new_last_quic_addr;
  http_server_properties_impl_->GetSupportsQuic(&new_last_quic_addr);
  if (old_last_quic_addr != new_last_quic_addr)
    ScheduleUpdatePrefsOnNetworkThread(SET_SUPPORTS_QUIC);
}

void HttpServerPropertiesManager::SetServerNetworkStats(
    const url::SchemeHostPort& server,
    ServerNetworkStats stats) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  ServerNetworkStats old_stats;
  const ServerNetworkStats* old_stats_ptr =
      http_server_properties_impl_->GetServerNetworkStats(server);
  if (http_server_properties_impl_->GetServerNetworkStats(server))
    old_stats = *old_stats_ptr;
  http_server_properties_impl_->SetServerNetworkStats(server, stats);
  ServerNetworkStats new_stats =
      *(http_server_properties_impl_->GetServerNetworkStats(server));
  if (old_stats != new_stats)
    ScheduleUpdatePrefsOnNetworkThread(SET_SERVER_NETWORK_STATS);
}

const ServerNetworkStats* HttpServerPropertiesManager::GetServerNetworkStats(
    const url::SchemeHostPort& server) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->GetServerNetworkStats(server);
}

const ServerNetworkStatsMap&
HttpServerPropertiesManager::server_network_stats_map() const {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->server_network_stats_map();
}

bool HttpServerPropertiesManager::SetQuicServerInfo(
    const QuicServerId& server_id,
    const std::string& server_info) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  bool changed =
      http_server_properties_impl_->SetQuicServerInfo(server_id, server_info);
  if (changed)
    ScheduleUpdatePrefsOnNetworkThread(SET_QUIC_SERVER_INFO);
  return changed;
}

const std::string* HttpServerPropertiesManager::GetQuicServerInfo(
    const QuicServerId& server_id) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->GetQuicServerInfo(server_id);
}

const QuicServerInfoMap& HttpServerPropertiesManager::quic_server_info_map()
    const {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->quic_server_info_map();
}

size_t HttpServerPropertiesManager::max_server_configs_stored_in_properties()
    const {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_
      ->max_server_configs_stored_in_properties();
}

void HttpServerPropertiesManager::SetMaxServerConfigsStoredInProperties(
    size_t max_server_configs_stored_in_properties) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  return http_server_properties_impl_->SetMaxServerConfigsStoredInProperties(
      max_server_configs_stored_in_properties);
}

//
// Update the HttpServerPropertiesImpl's cache with data from preferences.
//
void HttpServerPropertiesManager::ScheduleUpdateCacheOnPrefThread() {
  DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
  // Cancel pending updates, if any.
  pref_cache_update_timer_->Stop();
  StartCacheUpdateTimerOnPrefThread(
      base::TimeDelta::FromMilliseconds(kUpdateCacheDelayMs));
}

void HttpServerPropertiesManager::StartCacheUpdateTimerOnPrefThread(
    base::TimeDelta delay) {
  DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
  pref_cache_update_timer_->Start(
      FROM_HERE,
      delay,
      this,
      &HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread);
}

void HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread() {
  // The preferences can only be read on the pref thread.
  DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());

  if (!pref_delegate_->HasServerProperties())
    return;

  bool detected_corrupted_prefs = false;
  const base::DictionaryValue& http_server_properties_dict =
      pref_delegate_->GetServerProperties();

  int version = kMissingVersion;
  if (!http_server_properties_dict.GetIntegerWithoutPathExpansion(kVersionKey,
                                                                  &version)) {
    DVLOG(1) << "Missing version. Clearing all properties.";
    return;
  }

  const base::DictionaryValue* servers_dict = nullptr;
  const base::ListValue* servers_list = nullptr;
  if (version < 4) {
    // The properties for a given server is in
    // http_server_properties_dict["servers"][server].
    // Before Version 4, server data was stored in the following format in
    // alphabetical order.
    //
    //   "http_server_properties": {
    //      "servers": {
    //         "0-edge-chat.facebook.com:443" : {...},
    //         "0.client-channel.google.com:443" : {...},
    //         "yt3.ggpht.com:80" : {...},
    //         ...
    //      }, ...
    // },
    if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion(
            kServersKey, &servers_dict)) {
      DVLOG(1) << "Malformed http_server_properties for servers.";
      return;
    }
  } else {
    // For Version 4, data was stored in the following format.
    // |servers| are saved in MRU order.
    //
    // "http_server_properties": {
    //      "servers": [
    //          {"yt3.ggpht.com:443" : {...}},
    //          {"0.client-channel.google.com:443" : {...}},
    //          {"0-edge-chat.facebook.com:80" : {...}},
    //          ...
    //      ], ...
    // },
    // For Version 5, data was stored in the following format.
    // |servers| are saved in MRU order. |servers| are in the format flattened
    // representation of (scheme/host/port) where port might be ignored if is
    // default with scheme.
    //
    // "http_server_properties": {
    //      "servers": [
    //          {"https://yt3.ggpht.com" : {...}},
    //          {"http://0.client-channel.google.com:443" : {...}},
    //          {"http://0-edge-chat.facebook.com" : {...}},
    //          ...
    //      ], ...
    // },
    if (!http_server_properties_dict.GetListWithoutPathExpansion(
            kServersKey, &servers_list)) {
      DVLOG(1) << "Malformed http_server_properties for servers list.";
      return;
    }
  }

  IPAddress* addr = new IPAddress;
  ReadSupportsQuic(http_server_properties_dict, addr);

  // String is "scheme://host:port" tuple of spdy server.
  std::unique_ptr<ServerList> spdy_servers(new ServerList);
  std::unique_ptr<SpdySettingsMap> spdy_settings_map(
      new SpdySettingsMap(kMaxSpdySettingsHostsToPersist));
  std::unique_ptr<AlternativeServiceMap> alternative_service_map(
      new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist));
  std::unique_ptr<ServerNetworkStatsMap> server_network_stats_map(
      new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist));
  std::unique_ptr<QuicServerInfoMap> quic_server_info_map(
      new QuicServerInfoMap(QuicServerInfoMap::NO_AUTO_EVICT));

  if (version < 4) {
    if (!AddServersData(*servers_dict, spdy_servers.get(),
                        spdy_settings_map.get(), alternative_service_map.get(),
                        server_network_stats_map.get(), version)) {
      detected_corrupted_prefs = true;
    }
  } else {
    for (base::ListValue::const_iterator it = servers_list->begin();
         it != servers_list->end(); ++it) {
      if (!(*it)->GetAsDictionary(&servers_dict)) {
        DVLOG(1) << "Malformed http_server_properties for servers dictionary.";
        detected_corrupted_prefs = true;
        continue;
      }
      if (!AddServersData(*servers_dict, spdy_servers.get(),
                          spdy_settings_map.get(),
                          alternative_service_map.get(),
                          server_network_stats_map.get(), version)) {
        detected_corrupted_prefs = true;
      }
    }
  }

  if (!AddToQuicServerInfoMap(http_server_properties_dict,
                              quic_server_info_map.get())) {
    detected_corrupted_prefs = true;
  }

  network_task_runner_->PostTask(
      FROM_HERE,
      base::Bind(
          &HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread,
          base::Unretained(this), base::Owned(spdy_servers.release()),
          base::Owned(spdy_settings_map.release()),
          base::Owned(alternative_service_map.release()), base::Owned(addr),
          base::Owned(server_network_stats_map.release()),
          base::Owned(quic_server_info_map.release()),
          detected_corrupted_prefs));
}

bool HttpServerPropertiesManager::AddServersData(
    const base::DictionaryValue& servers_dict,
    ServerList* spdy_servers,
    SpdySettingsMap* spdy_settings_map,
    AlternativeServiceMap* alternative_service_map,
    ServerNetworkStatsMap* network_stats_map,
    int version) {
  for (base::DictionaryValue::Iterator it(servers_dict); !it.IsAtEnd();
       it.Advance()) {
    // Get server's scheme/host/pair.
    const std::string& server_str = it.key();
    std::string spdy_server_url = server_str;
    if (version < 5) {
      // For old version disk data, always use HTTPS as the scheme.
      spdy_server_url.insert(0, "https://");
    }
    url::SchemeHostPort spdy_server((GURL(spdy_server_url)));
    if (spdy_server.host().empty()) {
      DVLOG(1) << "Malformed http_server_properties for server: " << server_str;
      return false;
    }

    const base::DictionaryValue* server_pref_dict = nullptr;
    if (!it.value().GetAsDictionary(&server_pref_dict)) {
      DVLOG(1) << "Malformed http_server_properties server: " << server_str;
      return false;
    }

    // Get if server supports Spdy.
    bool supports_spdy = false;
    if ((server_pref_dict->GetBoolean(kSupportsSpdyKey, &supports_spdy)) &&
        supports_spdy) {
      spdy_servers->push_back(spdy_server.Serialize());
    }

    AddToSpdySettingsMap(spdy_server, *server_pref_dict, spdy_settings_map);
    if (!AddToAlternativeServiceMap(spdy_server, *server_pref_dict,
                                    alternative_service_map) ||
        !AddToNetworkStatsMap(spdy_server, *server_pref_dict,
                              network_stats_map)) {
      return false;
    }
  }
  return true;
}

void HttpServerPropertiesManager::AddToSpdySettingsMap(
    const url::SchemeHostPort& server,
    const base::DictionaryValue& server_pref_dict,
    SpdySettingsMap* spdy_settings_map) {
  // Get SpdySettings.
  DCHECK(spdy_settings_map->Peek(server) == spdy_settings_map->end());
  const base::DictionaryValue* spdy_settings_dict = nullptr;
  if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
          kSettingsKey, &spdy_settings_dict)) {
    return;
  }
  SettingsMap settings_map;
  for (base::DictionaryValue::Iterator dict_it(*spdy_settings_dict);
       !dict_it.IsAtEnd(); dict_it.Advance()) {
    const std::string& id_str = dict_it.key();
    int id = 0;
    if (!base::StringToInt(id_str, &id)) {
      DVLOG(1) << "Malformed id in SpdySettings for server: "
               << server.Serialize();
      NOTREACHED();
      continue;
    }
    int value = 0;
    if (!dict_it.value().GetAsInteger(&value)) {
      DVLOG(1) << "Malformed value in SpdySettings for server: "
               << server.Serialize();
      NOTREACHED();
      continue;
    }
    SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
    settings_map[static_cast<SpdySettingsIds>(id)] = flags_and_value;
  }
  spdy_settings_map->Put(server, settings_map);
}

bool HttpServerPropertiesManager::ParseAlternativeServiceDict(
    const base::DictionaryValue& alternative_service_dict,
    const std::string& server_str,
    AlternativeServiceInfo* alternative_service_info) {
  // Protocol is mandatory.
  std::string protocol_str;
  if (!alternative_service_dict.GetStringWithoutPathExpansion(kProtocolKey,
                                                              &protocol_str)) {
    DVLOG(1) << "Malformed alternative service protocol string for server: "
             << server_str;
    return false;
  }
  AlternateProtocol protocol = AlternateProtocolFromString(protocol_str);
  if (!IsAlternateProtocolValid(protocol)) {
    DVLOG(1) << "Invalid alternative service protocol string for server: "
             << server_str;
    return false;
  }
  alternative_service_info->alternative_service.protocol = protocol;

  // Host is optional, defaults to "".
  alternative_service_info->alternative_service.host.clear();
  if (alternative_service_dict.HasKey(kHostKey) &&
      !alternative_service_dict.GetStringWithoutPathExpansion(
          kHostKey, &(alternative_service_info->alternative_service.host))) {
    DVLOG(1) << "Malformed alternative service host string for server: "
             << server_str;
    return false;
  }

  // Port is mandatory.
  int port = 0;
  if (!alternative_service_dict.GetInteger(kPortKey, &port) ||
      !IsPortValid(port)) {
    DVLOG(1) << "Malformed alternative service port for server: " << server_str;
    return false;
  }
  alternative_service_info->alternative_service.port =
      static_cast<uint32_t>(port);

  // Expiration is optional, defaults to one day.
  base::Time expiration;
  if (!alternative_service_dict.HasKey(kExpirationKey)) {
    alternative_service_info->expiration =
        base::Time::Now() + base::TimeDelta::FromDays(1);
    return true;
  }

  std::string expiration_string;
  if (alternative_service_dict.GetStringWithoutPathExpansion(
          kExpirationKey, &expiration_string)) {
    int64_t expiration_int64 = 0;
    if (!base::StringToInt64(expiration_string, &expiration_int64)) {
      DVLOG(1) << "Malformed alternative service expiration for server: "
               << server_str;
      return false;
    }
    alternative_service_info->expiration =
        base::Time::FromInternalValue(expiration_int64);
    return true;
  }

  DVLOG(1) << "Malformed alternative service expiration for server: "
           << server_str;
  return false;
}

bool HttpServerPropertiesManager::AddToAlternativeServiceMap(
    const url::SchemeHostPort& server,
    const base::DictionaryValue& server_pref_dict,
    AlternativeServiceMap* alternative_service_map) {
  DCHECK(alternative_service_map->Peek(server) ==
         alternative_service_map->end());
  const base::ListValue* alternative_service_list;
  if (!server_pref_dict.GetListWithoutPathExpansion(
          kAlternativeServiceKey, &alternative_service_list)) {
    return true;
  }

  AlternativeServiceInfoVector alternative_service_info_vector;
  for (const auto& alternative_service_list_item : *alternative_service_list) {
    const base::DictionaryValue* alternative_service_dict;
    if (!alternative_service_list_item->GetAsDictionary(
            &alternative_service_dict))
      return false;
    AlternativeServiceInfo alternative_service_info;
    if (!ParseAlternativeServiceDict(*alternative_service_dict,
                                     server.Serialize(),
                                     &alternative_service_info)) {
      return false;
    }
    if (base::Time::Now() < alternative_service_info.expiration) {
      alternative_service_info_vector.push_back(alternative_service_info);
    }
  }

  if (alternative_service_info_vector.empty()) {
    return false;
  }

  alternative_service_map->Put(server, alternative_service_info_vector);
  return true;
}

bool HttpServerPropertiesManager::ReadSupportsQuic(
    const base::DictionaryValue& http_server_properties_dict,
    IPAddress* last_quic_address) {
  const base::DictionaryValue* supports_quic_dict = nullptr;
  if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion(
          kSupportsQuicKey, &supports_quic_dict)) {
    return true;
  }
  bool used_quic = false;
  if (!supports_quic_dict->GetBooleanWithoutPathExpansion(kUsedQuicKey,
                                                          &used_quic)) {
    DVLOG(1) << "Malformed SupportsQuic";
    return false;
  }
  if (!used_quic)
    return false;

  std::string address;
  if (!supports_quic_dict->GetStringWithoutPathExpansion(kAddressKey,
                                                         &address) ||
      !last_quic_address->AssignFromIPLiteral(address)) {
    DVLOG(1) << "Malformed SupportsQuic";
    return false;
  }
  return true;
}

bool HttpServerPropertiesManager::AddToNetworkStatsMap(
    const url::SchemeHostPort& server,
    const base::DictionaryValue& server_pref_dict,
    ServerNetworkStatsMap* network_stats_map) {
  DCHECK(network_stats_map->Peek(server) == network_stats_map->end());
  const base::DictionaryValue* server_network_stats_dict = nullptr;
  if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
          kNetworkStatsKey, &server_network_stats_dict)) {
    return true;
  }
  int srtt;
  if (!server_network_stats_dict->GetIntegerWithoutPathExpansion(kSrttKey,
                                                                 &srtt)) {
    DVLOG(1) << "Malformed ServerNetworkStats for server: "
             << server.Serialize();
    return false;
  }
  ServerNetworkStats server_network_stats;
  server_network_stats.srtt = base::TimeDelta::FromInternalValue(srtt);
  // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
  // bandwidth_estimate.
  network_stats_map->Put(server, server_network_stats);
  return true;
}

bool HttpServerPropertiesManager::AddToQuicServerInfoMap(
    const base::DictionaryValue& http_server_properties_dict,
    QuicServerInfoMap* quic_server_info_map) {
  const base::DictionaryValue* quic_servers_dict = nullptr;
  if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion(
          kQuicServers, &quic_servers_dict)) {
    DVLOG(1) << "Malformed http_server_properties for quic_servers.";
    return true;
  }

  bool detected_corrupted_prefs = false;
  for (base::DictionaryValue::Iterator it(*quic_servers_dict); !it.IsAtEnd();
       it.Advance()) {
    // Get quic_server_id.
    const std::string& quic_server_id_str = it.key();
    QuicServerId quic_server_id = QuicServerId::FromString(quic_server_id_str);
    if (quic_server_id.host().empty()) {
      DVLOG(1) << "Malformed http_server_properties for quic server: "
               << quic_server_id_str;
      detected_corrupted_prefs = true;
      continue;
    }

    const base::DictionaryValue* quic_server_pref_dict = nullptr;
    if (!it.value().GetAsDictionary(&quic_server_pref_dict)) {
      DVLOG(1) << "Malformed http_server_properties quic server dict: "
               << quic_server_id_str;
      detected_corrupted_prefs = true;
      continue;
    }

    std::string quic_server_info;
    if (!quic_server_pref_dict->GetStringWithoutPathExpansion(
            kServerInfoKey, &quic_server_info)) {
      DVLOG(1) << "Malformed http_server_properties quic server info: "
               << quic_server_id_str;
      detected_corrupted_prefs = true;
      continue;
    }
    quic_server_info_map->Put(quic_server_id, quic_server_info);
  }
  return !detected_corrupted_prefs;
}

void HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread(
    ServerList* spdy_servers,
    SpdySettingsMap* spdy_settings_map,
    AlternativeServiceMap* alternative_service_map,
    IPAddress* last_quic_address,
    ServerNetworkStatsMap* server_network_stats_map,
    QuicServerInfoMap* quic_server_info_map,
    bool detected_corrupted_prefs) {
  // Preferences have the master data because admins might have pushed new
  // preferences. Update the cached data with new data from preferences.
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());

  UMA_HISTOGRAM_COUNTS("Net.CountOfSpdyServers", spdy_servers->size());
  http_server_properties_impl_->InitializeSpdyServers(spdy_servers, true);

  // Update the cached data and use the new spdy_settings from preferences.
  UMA_HISTOGRAM_COUNTS("Net.CountOfSpdySettings", spdy_settings_map->size());
  http_server_properties_impl_->InitializeSpdySettingsServers(
      spdy_settings_map);

  // Update the cached data and use the new alternative service list from
  // preferences.
  UMA_HISTOGRAM_COUNTS("Net.CountOfAlternateProtocolServers",
                       alternative_service_map->size());
  http_server_properties_impl_->InitializeAlternativeServiceServers(
      alternative_service_map);

  http_server_properties_impl_->InitializeSupportsQuic(last_quic_address);

  http_server_properties_impl_->InitializeServerNetworkStats(
      server_network_stats_map);

  http_server_properties_impl_->InitializeQuicServerInfoMap(
      quic_server_info_map);

  // Update the prefs with what we have read (delete all corrupted prefs).
  if (detected_corrupted_prefs)
    ScheduleUpdatePrefsOnNetworkThread(DETECTED_CORRUPTED_PREFS);
}

//
// Update Preferences with data from the cached data.
//
void HttpServerPropertiesManager::ScheduleUpdatePrefsOnNetworkThread(
    Location location) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  // Cancel pending updates, if any.
  network_prefs_update_timer_->Stop();
  StartPrefsUpdateTimerOnNetworkThread(
      base::TimeDelta::FromMilliseconds(kUpdatePrefsDelayMs));
  // TODO(rtenneti): Delete the following histogram after collecting some data.
  UMA_HISTOGRAM_ENUMERATION("Net.HttpServerProperties.UpdatePrefs", location,
                            HttpServerPropertiesManager::NUM_LOCATIONS);
}

void HttpServerPropertiesManager::StartPrefsUpdateTimerOnNetworkThread(
    base::TimeDelta delay) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
  // This is overridden in tests to post the task without the delay.
  network_prefs_update_timer_->Start(
      FROM_HERE,
      delay,
      this,
      &HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread);
}

// This is required so we can set this as the callback for a timer.
void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread() {
  UpdatePrefsFromCacheOnNetworkThread(base::Closure());
}

void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread(
    const base::Closure& completion) {
  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());

  // It is in MRU order.
  base::ListValue* spdy_server_list = new base::ListValue;
  http_server_properties_impl_->GetSpdyServerList(
      spdy_server_list, kMaxSupportsSpdyServerHostsToPersist);

  SpdySettingsMap* spdy_settings_map =
      new SpdySettingsMap(kMaxSpdySettingsHostsToPersist);
  const SpdySettingsMap& main_map =
      http_server_properties_impl_->spdy_settings_map();
  int count = 0;
  // Maintain MRU order.
  for (SpdySettingsMap::const_reverse_iterator it = main_map.rbegin();
       it != main_map.rend() && count < kMaxSpdySettingsHostsToPersist;
       ++it, ++count) {
    spdy_settings_map->Put(it->first, it->second);
  }

  AlternativeServiceMap* alternative_service_map =
      new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist);
  const AlternativeServiceMap& map =
      http_server_properties_impl_->alternative_service_map();
  UMA_HISTOGRAM_COUNTS("Net.CountOfAlternateProtocolServers.Memory",
                       map.size());
  count = 0;
  typedef std::map<std::string, bool> CanonicalHostPersistedMap;
  CanonicalHostPersistedMap persisted_map;
  // Maintain MRU order.
  for (AlternativeServiceMap::const_reverse_iterator it = map.rbegin();
       it != map.rend() && count < kMaxAlternateProtocolHostsToPersist; ++it) {
    const url::SchemeHostPort& server = it->first;
    AlternativeServiceInfoVector notbroken_alternative_service_info_vector;
    for (const AlternativeServiceInfo& alternative_service_info : it->second) {
      // Do not persist expired entries.
      if (alternative_service_info.expiration < base::Time::Now()) {
        continue;
      }
      AlternativeService alternative_service(
          alternative_service_info.alternative_service);
      if (!IsAlternateProtocolValid(alternative_service.protocol)) {
        continue;
      }
      if (alternative_service.host.empty()) {
        alternative_service.host = server.host();
      }
      if (IsAlternativeServiceBroken(alternative_service)) {
        continue;
      }
      notbroken_alternative_service_info_vector.push_back(
          alternative_service_info);
    }
    if (notbroken_alternative_service_info_vector.empty()) {
      continue;
    }
    std::string canonical_suffix =
        http_server_properties_impl_->GetCanonicalSuffix(server.host());
    if (!canonical_suffix.empty()) {
      if (persisted_map.find(canonical_suffix) != persisted_map.end())
        continue;
      persisted_map[canonical_suffix] = true;
    }
    alternative_service_map->Put(server,
                                 notbroken_alternative_service_info_vector);
    ++count;
  }

  ServerNetworkStatsMap* server_network_stats_map =
      new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist);
  const ServerNetworkStatsMap& network_stats_map =
      http_server_properties_impl_->server_network_stats_map();
  count = 0;
  for (ServerNetworkStatsMap::const_reverse_iterator
           it = network_stats_map.rbegin();
       it != network_stats_map.rend() &&
       count < kMaxServerNetworkStatsHostsToPersist;
       ++it, ++count) {
    server_network_stats_map->Put(it->first, it->second);
  }

  QuicServerInfoMap* quic_server_info_map = nullptr;
  const QuicServerInfoMap& main_quic_server_info_map =
      http_server_properties_impl_->quic_server_info_map();
  if (main_quic_server_info_map.size() > 0) {
    quic_server_info_map =
        new QuicServerInfoMap(max_server_configs_stored_in_properties());
    for (const std::pair<const QuicServerId, std::string>& entry :
         main_quic_server_info_map) {
      quic_server_info_map->Put(entry.first, entry.second);
    }
  }

  IPAddress* last_quic_addr = new IPAddress;
  http_server_properties_impl_->GetSupportsQuic(last_quic_addr);
  // Update the preferences on the pref thread.
  pref_task_runner_->PostTask(
      FROM_HERE,
      base::Bind(
          &HttpServerPropertiesManager::UpdatePrefsOnPrefThread, pref_weak_ptr_,
          base::Owned(spdy_server_list), base::Owned(spdy_settings_map),
          base::Owned(alternative_service_map), base::Owned(last_quic_addr),
          base::Owned(server_network_stats_map),
          base::Owned(quic_server_info_map), completion));
}

// A local or temporary data structure to hold |supports_spdy|, SpdySettings,
// AlternativeServiceInfoVector, and SupportsQuic preferences for a server. This
// is used only in UpdatePrefsOnPrefThread.
struct ServerPref {
  ServerPref()
      : supports_spdy(false),
        settings_map(nullptr),
        alternative_service_info_vector(nullptr),
        supports_quic(nullptr),
        server_network_stats(nullptr) {}
  ServerPref(
      bool supports_spdy,
      const SettingsMap* settings_map,
      const AlternativeServiceInfoVector* alternative_service_info_vector,
      const SupportsQuic* supports_quic,
      const ServerNetworkStats* server_network_stats)
      : supports_spdy(supports_spdy),
        settings_map(settings_map),
        alternative_service_info_vector(alternative_service_info_vector),
        supports_quic(supports_quic),
        server_network_stats(server_network_stats) {}
  bool supports_spdy;
  const SettingsMap* settings_map;
  const AlternativeServiceInfoVector* alternative_service_info_vector;
  const SupportsQuic* supports_quic;
  const ServerNetworkStats* server_network_stats;
};

// All maps and lists are in MRU order.
void HttpServerPropertiesManager::UpdatePrefsOnPrefThread(
    base::ListValue* spdy_server_list,
    SpdySettingsMap* spdy_settings_map,
    AlternativeServiceMap* alternative_service_map,
    IPAddress* last_quic_address,
    ServerNetworkStatsMap* server_network_stats_map,
    QuicServerInfoMap* quic_server_info_map,
    const base::Closure& completion) {
  typedef base::MRUCache<url::SchemeHostPort, ServerPref> ServerPrefMap;
  ServerPrefMap server_pref_map(ServerPrefMap::NO_AUTO_EVICT);

  DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());

  // Add servers that support spdy to server_pref_map in the MRU order.
  for (size_t index = spdy_server_list->GetSize(); index > 0; --index) {
    std::string server_str;
    if (spdy_server_list->GetString(index - 1, &server_str)) {
      url::SchemeHostPort server((GURL(server_str)));
      ServerPrefMap::iterator it = server_pref_map.Get(server);
      if (it == server_pref_map.end()) {
        ServerPref server_pref;
        server_pref.supports_spdy = true;
        server_pref_map.Put(server, server_pref);
      } else {
        it->second.supports_spdy = true;
      }
    }
  }

  // Add servers that have SpdySettings to server_pref_map in the MRU order.
  for (SpdySettingsMap::reverse_iterator map_it = spdy_settings_map->rbegin();
       map_it != spdy_settings_map->rend(); ++map_it) {
    const url::SchemeHostPort server = map_it->first;
    ServerPrefMap::iterator it = server_pref_map.Get(server);
    if (it == server_pref_map.end()) {
      ServerPref server_pref;
      server_pref.settings_map = &map_it->second;
      server_pref_map.Put(server, server_pref);
    } else {
      it->second.settings_map = &map_it->second;
    }
  }

  // Add alternative services to server_pref_map in the MRU order.
  for (AlternativeServiceMap::const_reverse_iterator map_it =
           alternative_service_map->rbegin();
       map_it != alternative_service_map->rend(); ++map_it) {
    const url::SchemeHostPort server = map_it->first;
    ServerPrefMap::iterator it = server_pref_map.Get(server);
    if (it == server_pref_map.end()) {
      ServerPref server_pref;
      server_pref.alternative_service_info_vector = &map_it->second;
      server_pref_map.Put(server, server_pref);
    } else {
      it->second.alternative_service_info_vector = &map_it->second;
    }
  }

  // Add ServerNetworkStats servers to server_pref_map in the MRU order.
  for (ServerNetworkStatsMap::const_reverse_iterator map_it =
           server_network_stats_map->rbegin();
       map_it != server_network_stats_map->rend(); ++map_it) {
    const url::SchemeHostPort server = map_it->first;
    ServerPrefMap::iterator it = server_pref_map.Get(server);
    if (it == server_pref_map.end()) {
      ServerPref server_pref;
      server_pref.server_network_stats = &map_it->second;
      server_pref_map.Put(server, server_pref);
    } else {
      it->second.server_network_stats = &map_it->second;
    }
  }

  // Persist properties to the prefs in the MRU order.
  base::DictionaryValue http_server_properties_dict;
  base::ListValue* servers_list = new base::ListValue;
  for (ServerPrefMap::const_reverse_iterator map_it = server_pref_map.rbegin();
       map_it != server_pref_map.rend(); ++map_it) {
    const url::SchemeHostPort server = map_it->first;
    const ServerPref& server_pref = map_it->second;

    base::DictionaryValue* servers_dict = new base::DictionaryValue;
    base::DictionaryValue* server_pref_dict = new base::DictionaryValue;

    // Save supports_spdy.
    if (server_pref.supports_spdy)
      server_pref_dict->SetBoolean(kSupportsSpdyKey, server_pref.supports_spdy);
    SaveSpdySettingsToServerPrefs(server_pref.settings_map, server_pref_dict);
    SaveAlternativeServiceToServerPrefs(
        server_pref.alternative_service_info_vector, server_pref_dict);
    SaveNetworkStatsToServerPrefs(server_pref.server_network_stats,
                                  server_pref_dict);

    servers_dict->SetWithoutPathExpansion(server.Serialize(), server_pref_dict);
    bool value = servers_list->AppendIfNotPresent(servers_dict);
    DCHECK(value);  // Should never happen.
  }

  http_server_properties_dict.SetWithoutPathExpansion(kServersKey,
                                                      servers_list);
  SetVersion(&http_server_properties_dict, kVersionNumber);

  SaveSupportsQuicToPrefs(last_quic_address, &http_server_properties_dict);

  SaveQuicServerInfoMapToServerPrefs(quic_server_info_map,
                                     &http_server_properties_dict);

  setting_prefs_ = true;
  pref_delegate_->SetServerProperties(http_server_properties_dict);
  setting_prefs_ = false;

  // Note that |completion| will be fired after we have written everything to
  // the Preferences, but likely before these changes are serialized to disk.
  // This is not a problem though, as JSONPrefStore guarantees that this will
  // happen, pretty soon, and even in the case we shut down immediately.
  if (!completion.is_null())
    completion.Run();
}

void HttpServerPropertiesManager::SaveSpdySettingsToServerPrefs(
    const SettingsMap* settings_map,
    base::DictionaryValue* server_pref_dict) {
  if (!settings_map) {
    return;
  }
  base::DictionaryValue* spdy_settings_dict = new base::DictionaryValue;
  for (SettingsMap::const_iterator it = settings_map->begin();
       it != settings_map->end(); ++it) {
    SpdySettingsIds id = it->first;
    uint32_t value = it->second.second;
    std::string key = base::StringPrintf("%u", id);
    spdy_settings_dict->SetInteger(key, value);
  }
  server_pref_dict->SetWithoutPathExpansion(kSettingsKey, spdy_settings_dict);
}

void HttpServerPropertiesManager::SaveAlternativeServiceToServerPrefs(
    const AlternativeServiceInfoVector* alternative_service_info_vector,
    base::DictionaryValue* server_pref_dict) {
  if (!alternative_service_info_vector ||
      alternative_service_info_vector->empty()) {
    return;
  }
  std::unique_ptr<base::ListValue> alternative_service_list(
      new base::ListValue);
  for (const AlternativeServiceInfo& alternative_service_info :
       *alternative_service_info_vector) {
    const AlternativeService alternative_service =
        alternative_service_info.alternative_service;
    DCHECK(IsAlternateProtocolValid(alternative_service.protocol));
    std::unique_ptr<base::DictionaryValue> alternative_service_dict(
        new base::DictionaryValue);
    alternative_service_dict->SetInteger(kPortKey, alternative_service.port);
    if (!alternative_service.host.empty()) {
      alternative_service_dict->SetString(kHostKey, alternative_service.host);
    }
    alternative_service_dict->SetString(
        kProtocolKey, AlternateProtocolToString(alternative_service.protocol));
    // JSON cannot store int64_t, so expiration is converted to a string.
    alternative_service_dict->SetString(
        kExpirationKey,
        base::Int64ToString(
            alternative_service_info.expiration.ToInternalValue()));
    alternative_service_list->Append(std::move(alternative_service_dict));
  }
  if (alternative_service_list->GetSize() == 0)
    return;
  server_pref_dict->SetWithoutPathExpansion(kAlternativeServiceKey,
                                            alternative_service_list.release());
}

void HttpServerPropertiesManager::SaveSupportsQuicToPrefs(
    const IPAddress* last_quic_address,
    base::DictionaryValue* http_server_properties_dict) {
  if (!last_quic_address || !last_quic_address->IsValid())
    return;

  base::DictionaryValue* supports_quic_dict = new base::DictionaryValue;
  supports_quic_dict->SetBoolean(kUsedQuicKey, true);
  supports_quic_dict->SetString(kAddressKey, last_quic_address->ToString());
  http_server_properties_dict->SetWithoutPathExpansion(kSupportsQuicKey,
                                                       supports_quic_dict);
}

void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
    const ServerNetworkStats* server_network_stats,
    base::DictionaryValue* server_pref_dict) {
  if (!server_network_stats)
    return;

  base::DictionaryValue* server_network_stats_dict = new base::DictionaryValue;
  // Becasue JSON doesn't support int64_t, persist int64_t as a string.
  server_network_stats_dict->SetInteger(
      kSrttKey, static_cast<int>(server_network_stats->srtt.ToInternalValue()));
  // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
  // bandwidth_estimate.
  server_pref_dict->SetWithoutPathExpansion(kNetworkStatsKey,
                                            server_network_stats_dict);
}

void HttpServerPropertiesManager::SaveQuicServerInfoMapToServerPrefs(
    QuicServerInfoMap* quic_server_info_map,
    base::DictionaryValue* http_server_properties_dict) {
  if (!quic_server_info_map)
    return;

  base::DictionaryValue* quic_servers_dict = new base::DictionaryValue;
  for (const std::pair<QuicServerId, std::string>& entry :
       *quic_server_info_map) {
    const QuicServerId& server_id = entry.first;
    base::DictionaryValue* quic_server_pref_dict = new base::DictionaryValue;
    quic_server_pref_dict->SetStringWithoutPathExpansion(kServerInfoKey,
                                                         entry.second);
    quic_servers_dict->SetWithoutPathExpansion(server_id.ToString(),
                                               quic_server_pref_dict);
  }
  http_server_properties_dict->SetWithoutPathExpansion(kQuicServers,
                                                       quic_servers_dict);
}

void HttpServerPropertiesManager::OnHttpServerPropertiesChanged() {
  DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
  if (!setting_prefs_)
    ScheduleUpdateCacheOnPrefThread();
}

}  // namespace net
