// 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/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/optional.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/tick_clock.h"
#include "base/values.h"
#include "net/base/features.h"
#include "net/base/host_port_pair.h"
#include "net/base/ip_address.h"
#include "net/base/port_util.h"
#include "net/base/privacy_mode.h"
#include "net/http/http_server_properties.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h"
#include "url/gurl.h"
#include "url/scheme_host_port.h"

namespace net {

namespace {

// "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 at most 200 currently-broken alternative services to disk.
const int kMaxBrokenAlternativeServicesToPersist = 200;

const char kServerKey[] = "server";
const char kQuicServerIdKey[] = "server_id";
const char kNetworkIsolationKey[] = "isolation";
const char kVersionKey[] = "version";
const char kServersKey[] = "servers";
const char kSupportsSpdyKey[] = "supports_spdy";
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 kAdvertisedAlpnsKey[] = "advertised_alpns";
const char kNetworkStatsKey[] = "network_stats";
const char kSrttKey[] = "srtt";
const char kBrokenAlternativeServicesKey[] = "broken_alternative_services";
const char kBrokenUntilKey[] = "broken_until";
const char kBrokenCountKey[] = "broken_count";

// Utility method to return only those AlternativeServiceInfos that should be
// persisted to disk. In particular, removes expired and invalid alternative
// services. Also checks if an alternative service for the same canonical suffix
// has already been saved, and if so, returns an empty list.
AlternativeServiceInfoVector GetAlternativeServiceToPersist(
    const base::Optional<AlternativeServiceInfoVector>& alternative_services,
    const HttpServerProperties::ServerInfoMapKey& server_info_key,
    base::Time now,
    const HttpServerPropertiesManager::GetCannonicalSuffix&
        get_canonical_suffix,
    std::set<std::pair<std::string, NetworkIsolationKey>>*
        persisted_canonical_suffix_set) {
  if (!alternative_services)
    return AlternativeServiceInfoVector();
  // Separate out valid, non-expired AlternativeServiceInfo entries.
  AlternativeServiceInfoVector notbroken_alternative_service_info_vector;
  for (const auto& alternative_service_info : alternative_services.value()) {
    if (alternative_service_info.expiration() < now ||
        !IsAlternateProtocolValid(
            alternative_service_info.alternative_service().protocol)) {
      continue;
    }
    notbroken_alternative_service_info_vector.push_back(
        alternative_service_info);
  }
  if (notbroken_alternative_service_info_vector.empty())
    return notbroken_alternative_service_info_vector;
  const std::string* canonical_suffix =
      get_canonical_suffix.Run(server_info_key.server.host());
  if (canonical_suffix) {
    // Don't save if have already saved information associated with the same
    // canonical suffix.
    std::pair<std::string, NetworkIsolationKey> index(
        *canonical_suffix, server_info_key.network_isolation_key);
    if (persisted_canonical_suffix_set->find(index) !=
        persisted_canonical_suffix_set->end()) {
      return AlternativeServiceInfoVector();
    }
    persisted_canonical_suffix_set->emplace(std::move(index));
  }
  return notbroken_alternative_service_info_vector;
}

void AddAlternativeServiceFieldsToDictionaryValue(
    const AlternativeService& alternative_service,
    base::Value* dict) {
  DCHECK(dict->is_dict());
  dict->SetIntKey(kPortKey, alternative_service.port);
  if (!alternative_service.host.empty()) {
    dict->SetStringKey(kHostKey, alternative_service.host);
  }
  dict->SetStringKey(kProtocolKey,
                     NextProtoToString(alternative_service.protocol));
}

// Fails in the case of NetworkIsolationKeys that can't be persisted to disk,
// like unique origins.
bool TryAddBrokenAlternativeServiceFieldsToDictionaryValue(
    const BrokenAlternativeService& broken_alt_service,
    base::Value* dict) {
  DCHECK(dict->is_dict());
  base::Value network_isolation_key_value;
  if (!broken_alt_service.network_isolation_key.ToValue(
          &network_isolation_key_value)) {
    return false;
  }

  dict->SetKey(kNetworkIsolationKey, std::move(network_isolation_key_value));
  AddAlternativeServiceFieldsToDictionaryValue(
      broken_alt_service.alternative_service, dict);
  return true;
}

quic::QuicServerId QuicServerIdFromString(const std::string& str) {
  GURL url(str);
  if (!url.is_valid()) {
    return quic::QuicServerId();
  }
  HostPortPair host_port_pair = HostPortPair::FromURL(url);
  return quic::QuicServerId(host_port_pair.host(), host_port_pair.port(),
                            url.path_piece() == "/private"
                                ? PRIVACY_MODE_ENABLED
                                : PRIVACY_MODE_DISABLED);
}

std::string QuicServerIdToString(const quic::QuicServerId& server_id) {
  HostPortPair host_port_pair(server_id.host(), server_id.port());
  return "https://" + host_port_pair.ToString() +
         (server_id.privacy_mode_enabled() ? "/private" : "");
}

// Takes in a base::Value representing a dictionary, and whether
// NetworkIsolationKeys are enabled for HttpServerProperties, and extracts the
// NetworkIsolationKey stored with the |kNetworkIsolationKey| in the dictionary,
// and writes it to |out_network_isolation_key|. Returns false if unable to load
// a NetworkIsolationKey, or the NetworkIsolationKey is non-empty, but
// |use_network_isolation_key| is false.
bool GetNetworkIsolationKeyFromDict(
    const base::Value& dict,
    bool use_network_isolation_key,
    NetworkIsolationKey* out_network_isolation_key) {
  DCHECK(dict.is_dict());

  const base::Value* network_isolation_key_value =
      dict.FindKey(kNetworkIsolationKey);
  NetworkIsolationKey network_isolation_key;
  if (!network_isolation_key_value ||
      !NetworkIsolationKey::FromValue(*network_isolation_key_value,
                                      &network_isolation_key)) {
    return false;
  }

  // Fail if NetworkIsolationKeys are disabled, but the entry has a non-empty
  // NetworkIsolationKey.
  if (!use_network_isolation_key && !network_isolation_key.IsEmpty())
    return false;

  *out_network_isolation_key = std::move(network_isolation_key);
  return true;
}

}  // namespace

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

HttpServerPropertiesManager::HttpServerPropertiesManager(
    std::unique_ptr<HttpServerProperties::PrefDelegate> pref_delegate,
    OnPrefsLoadedCallback on_prefs_loaded_callback,
    size_t max_server_configs_stored_in_properties,
    NetLog* net_log,
    const base::TickClock* clock)
    : pref_delegate_(std::move(pref_delegate)),
      on_prefs_loaded_callback_(std::move(on_prefs_loaded_callback)),
      max_server_configs_stored_in_properties_(
          max_server_configs_stored_in_properties),
      clock_(clock),
      net_log_(
          NetLogWithSource::Make(net_log,
                                 NetLogSourceType::HTTP_SERVER_PROPERTIES)) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(pref_delegate_);
  DCHECK(on_prefs_loaded_callback_);
  DCHECK(clock_);

  pref_delegate_->WaitForPrefLoad(
      base::BindOnce(&HttpServerPropertiesManager::OnHttpServerPropertiesLoaded,
                     pref_load_weak_ptr_factory_.GetWeakPtr()));
  net_log_.BeginEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_INITIALIZATION);
}

HttpServerPropertiesManager::~HttpServerPropertiesManager() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}

void HttpServerPropertiesManager::ReadPrefs(
    std::unique_ptr<HttpServerProperties::ServerInfoMap>* server_info_map,
    IPAddress* last_local_address_when_quic_worked,
    std::unique_ptr<HttpServerProperties::QuicServerInfoMap>*
        quic_server_info_map,
    std::unique_ptr<BrokenAlternativeServiceList>*
        broken_alternative_service_list,
    std::unique_ptr<RecentlyBrokenAlternativeServices>*
        recently_broken_alternative_services) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  net_log_.EndEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_INITIALIZATION);

  const base::Value* http_server_properties_dict =
      pref_delegate_->GetServerProperties();
  // If there are no preferences set, do nothing.
  if (!http_server_properties_dict || !http_server_properties_dict->is_dict())
    return;

  net_log_.AddEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_UPDATE_CACHE,
                    [&] { return http_server_properties_dict->Clone(); });
  base::Optional<int> maybe_version_number =
      http_server_properties_dict->FindIntKey(kVersionKey);
  if (!maybe_version_number.has_value() ||
      *maybe_version_number != kVersionNumber) {
    DVLOG(1) << "Missing or unsupported. Clearing all properties. "
             << maybe_version_number.value_or(kMissingVersion);
    return;
  }

  // For Version 5, data is 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" : {...}},
  //          ...
  //      ], ...
  // },
  const base::Value* servers_list =
      http_server_properties_dict->FindListKey(kServersKey);
  if (!servers_list) {
    DVLOG(1) << "Malformed http_server_properties for servers list.";
    return;
  }

  ReadLastLocalAddressWhenQuicWorked(*http_server_properties_dict,
                                     last_local_address_when_quic_worked);

  *server_info_map = std::make_unique<HttpServerProperties::ServerInfoMap>();
  *quic_server_info_map =
      std::make_unique<HttpServerProperties::QuicServerInfoMap>(
          max_server_configs_stored_in_properties_);

  bool use_network_isolation_key = base::FeatureList::IsEnabled(
      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);

  // Iterate servers list in reverse MRU order so that entries are inserted
  // into |spdy_servers_map|, |alternative_service_map|, and
  // |server_network_stats_map| from oldest to newest.
  for (auto it = servers_list->GetList().end();
       it != servers_list->GetList().begin();) {
    --it;
    if (!it->is_dict()) {
      DVLOG(1) << "Malformed http_server_properties for servers dictionary.";
      continue;
    }
    AddServerData(*it, server_info_map->get(), use_network_isolation_key);
  }

  AddToQuicServerInfoMap(*http_server_properties_dict,
                         use_network_isolation_key,
                         quic_server_info_map->get());

  // Read list containing broken and recently-broken alternative services, if
  // it exists.
  const base::Value* broken_alt_svc_list =
      http_server_properties_dict->FindListKey(kBrokenAlternativeServicesKey);
  if (broken_alt_svc_list) {
    *broken_alternative_service_list =
        std::make_unique<BrokenAlternativeServiceList>();
    *recently_broken_alternative_services =
        std::make_unique<RecentlyBrokenAlternativeServices>(
            kMaxRecentlyBrokenAlternativeServiceEntries);

    // Iterate list in reverse-MRU order
    for (auto it = broken_alt_svc_list->GetList().end();
         it != broken_alt_svc_list->GetList().begin();) {
      --it;
      if (!it->is_dict()) {
        DVLOG(1) << "Malformed broken alterantive service entry.";
        continue;
      }
      AddToBrokenAlternativeServices(
          *it, use_network_isolation_key,
          broken_alternative_service_list->get(),
          recently_broken_alternative_services->get());
    }
  }

  // Set the properties loaded from prefs on |http_server_properties_impl_|.

  // TODO(mmenke): Rename this once more information is stored in this map.
  UMA_HISTOGRAM_COUNTS_1M("Net.HttpServerProperties.CountOfServers",
                          (*server_info_map)->size());

  UMA_HISTOGRAM_COUNTS_1000("Net.CountOfQuicServerInfos",
                            (*quic_server_info_map)->size());

  if (*recently_broken_alternative_services) {
    DCHECK(*broken_alternative_service_list);

    UMA_HISTOGRAM_COUNTS_1000("Net.CountOfBrokenAlternativeServices",
                              (*broken_alternative_service_list)->size());
    UMA_HISTOGRAM_COUNTS_1000("Net.CountOfRecentlyBrokenAlternativeServices",
                              (*recently_broken_alternative_services)->size());
  }
}

void HttpServerPropertiesManager::AddToBrokenAlternativeServices(
    const base::Value& broken_alt_svc_entry_dict,
    bool use_network_isolation_key,
    BrokenAlternativeServiceList* broken_alternative_service_list,
    RecentlyBrokenAlternativeServices* recently_broken_alternative_services) {
  AlternativeService alt_service;
  if (!ParseAlternativeServiceDict(broken_alt_svc_entry_dict, false,
                                   "broken alternative services",
                                   &alt_service)) {
    return;
  }

  NetworkIsolationKey network_isolation_key;
  if (!GetNetworkIsolationKeyFromDict(broken_alt_svc_entry_dict,
                                      use_network_isolation_key,
                                      &network_isolation_key)) {
    return;
  }

  // Each entry must contain either broken-count and/or broken-until fields.
  bool contains_broken_count_or_broken_until = false;

  // Read broken-count and add an entry for |alt_service| into
  // |recently_broken_alternative_services|.
  if (broken_alt_svc_entry_dict.FindKey(kBrokenCountKey)) {
    base::Optional<int> broken_count =
        broken_alt_svc_entry_dict.FindIntKey(kBrokenCountKey);
    if (!broken_count.has_value()) {
      DVLOG(1) << "Recently broken alternative service has malformed "
               << "broken-count.";
      return;
    }
    if (broken_count.value() < 0) {
      DVLOG(1) << "Broken alternative service has negative broken-count.";
      return;
    }
    recently_broken_alternative_services->Put(
        BrokenAlternativeService(alt_service, network_isolation_key,
                                 use_network_isolation_key),
        broken_count.value());
    contains_broken_count_or_broken_until = true;
  }

  // Read broken-until and add an entry for |alt_service| in
  // |broken_alternative_service_list|.
  if (broken_alt_svc_entry_dict.FindKey(kBrokenUntilKey)) {
    const std::string* expiration_string =
        broken_alt_svc_entry_dict.FindStringKey(kBrokenUntilKey);
    int64_t expiration_int64;
    if (!expiration_string ||
        !base::StringToInt64(*expiration_string, &expiration_int64)) {
      DVLOG(1) << "Broken alternative service has malformed broken-until "
               << "string.";
      return;
    }

    time_t expiration_time_t = static_cast<time_t>(expiration_int64);
    // Convert expiration from time_t to Time to TimeTicks
    base::TimeTicks expiration_time_ticks =
        clock_->NowTicks() +
        (base::Time::FromTimeT(expiration_time_t) - base::Time::Now());
    broken_alternative_service_list->push_back(std::make_pair(
        BrokenAlternativeService(alt_service, network_isolation_key,
                                 use_network_isolation_key),
        expiration_time_ticks));
    contains_broken_count_or_broken_until = true;
  }

  if (!contains_broken_count_or_broken_until) {
    DVLOG(1) << "Broken alternative service has neither broken-count nor "
             << "broken-until specified.";
  }
}

void HttpServerPropertiesManager::AddServerData(
    const base::Value& server_dict,
    HttpServerProperties::ServerInfoMap* server_info_map,
    bool use_network_isolation_key) {
  // Get server's scheme/host/pair.
  const std::string* server_str = server_dict.FindStringKey(kServerKey);
  NetworkIsolationKey network_isolation_key;
  // Can't load entry if server name missing, or if the network isolation key is
  // missing or invalid.
  if (!server_str ||
      !GetNetworkIsolationKeyFromDict(server_dict, use_network_isolation_key,
                                      &network_isolation_key)) {
    return;
  }

  url::SchemeHostPort spdy_server((GURL(*server_str)));
  if (spdy_server.host().empty()) {
    DVLOG(1) << "Malformed http_server_properties for server: " << server_str;
    return;
  }

  HttpServerProperties::ServerInfo server_info;

  server_info.supports_spdy = server_dict.FindBoolKey(kSupportsSpdyKey);

  if (ParseAlternativeServiceInfo(spdy_server, server_dict, &server_info))
    ParseNetworkStats(spdy_server, server_dict, &server_info);

  if (!server_info.empty()) {
    server_info_map->Put(HttpServerProperties::ServerInfoMapKey(
                             std::move(spdy_server), network_isolation_key,
                             use_network_isolation_key),
                         std::move(server_info));
  }
}

bool HttpServerPropertiesManager::ParseAlternativeServiceDict(
    const base::Value& dict,
    bool host_optional,
    const std::string& parsing_under,
    AlternativeService* alternative_service) {
  // Protocol is mandatory.
  const std::string* protocol_str = dict.FindStringKey(kProtocolKey);
  if (!protocol_str) {
    DVLOG(1) << "Malformed alternative service protocol string under: "
             << parsing_under;
    return false;
  }
  NextProto protocol = NextProtoFromString(*protocol_str);
  if (!IsAlternateProtocolValid(protocol)) {
    DVLOG(1) << "Invalid alternative service protocol string \"" << protocol_str
             << "\" under: " << parsing_under;
    return false;
  }
  alternative_service->protocol = protocol;

  // If host is optional, it defaults to "".
  std::string host = "";
  const std::string* hostp = nullptr;
  if (dict.FindKey(kHostKey)) {
    hostp = dict.FindStringKey(kHostKey);
    if (!hostp) {
      DVLOG(1) << "Malformed alternative service host string under: "
               << parsing_under;
      return false;
    }
    host = *hostp;
  } else if (!host_optional) {
    DVLOG(1) << "alternative service missing host string under: "
             << parsing_under;
    return false;
  }
  alternative_service->host = host;

  // Port is mandatory.
  base::Optional<int> maybe_port = dict.FindIntKey(kPortKey);
  if (!maybe_port.has_value() || !IsPortValid(maybe_port.value())) {
    DVLOG(1) << "Malformed alternative service port under: " << parsing_under;
    return false;
  }
  alternative_service->port = static_cast<uint32_t>(maybe_port.value());

  return true;
}

bool HttpServerPropertiesManager::ParseAlternativeServiceInfoDictOfServer(
    const base::Value& dict,
    const std::string& server_str,
    AlternativeServiceInfo* alternative_service_info) {
  AlternativeService alternative_service;
  if (!ParseAlternativeServiceDict(dict, true, "server " + server_str,
                                   &alternative_service)) {
    return false;
  }
  alternative_service_info->set_alternative_service(alternative_service);

  // Expiration is optional, defaults to one day.
  if (!dict.FindKey(kExpirationKey)) {
    alternative_service_info->set_expiration(base::Time::Now() +
                                             base::TimeDelta::FromDays(1));
  } else {
    const std::string* expiration_string = dict.FindStringKey(kExpirationKey);
    if (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->set_expiration(
          base::Time::FromInternalValue(expiration_int64));
    } else {
      DVLOG(1) << "Malformed alternative service expiration for server: "
               << server_str;
      return false;
    }
  }

  // Advertised versions list is optional.
  if (dict.FindKey(kAdvertisedAlpnsKey)) {
    const base::Value* versions_list = dict.FindListKey(kAdvertisedAlpnsKey);
    if (!versions_list) {
      DVLOG(1) << "Malformed alternative service advertised versions list for "
               << "server: " << server_str;
      return false;
    }
    quic::ParsedQuicVersionVector advertised_versions;
    for (const auto& value : versions_list->GetList()) {
      std::string version_string;
      if (!value.GetAsString(&version_string)) {
        DVLOG(1) << "Malformed alternative service version for server: "
                 << server_str;
        return false;
      }
      quic::ParsedQuicVersion version =
          quic::ParseQuicVersionString(version_string);
      if (version != quic::ParsedQuicVersion::Unsupported()) {
        advertised_versions.push_back(version);
      }
    }
    alternative_service_info->set_advertised_versions(advertised_versions);
  }

  return true;
}

bool HttpServerPropertiesManager::ParseAlternativeServiceInfo(
    const url::SchemeHostPort& server,
    const base::Value& server_pref_dict,
    HttpServerProperties::ServerInfo* server_info) {
  DCHECK(!server_info->alternative_services.has_value());
  const base::Value* alternative_service_list =
      server_pref_dict.FindListKey(kAlternativeServiceKey);
  if (!alternative_service_list) {
    return true;
  }
  if (server.scheme() != "https") {
    return false;
  }

  AlternativeServiceInfoVector alternative_service_info_vector;
  for (const auto& alternative_service_list_item :
       alternative_service_list->GetList()) {
    if (!alternative_service_list_item.is_dict())
      return false;
    AlternativeServiceInfo alternative_service_info;
    if (!ParseAlternativeServiceInfoDictOfServer(alternative_service_list_item,
                                                 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;
  }

  server_info->alternative_services = alternative_service_info_vector;
  return true;
}

void HttpServerPropertiesManager::ReadLastLocalAddressWhenQuicWorked(
    const base::Value& http_server_properties_dict,
    IPAddress* last_local_address_when_quic_worked) {
  const base::Value* supports_quic_dict =
      http_server_properties_dict.FindDictKey(kSupportsQuicKey);
  if (!supports_quic_dict) {
    return;
  }
  const base::Value* used_quic = supports_quic_dict->FindKey(kUsedQuicKey);
  if (!used_quic || !used_quic->is_bool()) {
    DVLOG(1) << "Malformed SupportsQuic";
    return;
  }
  if (!used_quic->GetBool())
    return;

  const std::string* address = supports_quic_dict->FindStringKey(kAddressKey);
  if (!address ||
      !last_local_address_when_quic_worked->AssignFromIPLiteral(*address)) {
    DVLOG(1) << "Malformed SupportsQuic";
  }
}

void HttpServerPropertiesManager::ParseNetworkStats(
    const url::SchemeHostPort& server,
    const base::Value& server_pref_dict,
    HttpServerProperties::ServerInfo* server_info) {
  DCHECK(!server_info->server_network_stats.has_value());
  const base::Value* server_network_stats_dict =
      server_pref_dict.FindDictKey(kNetworkStatsKey);
  if (!server_network_stats_dict) {
    return;
  }
  base::Optional<int> maybe_srtt =
      server_network_stats_dict->FindIntKey(kSrttKey);
  if (!maybe_srtt.has_value()) {
    DVLOG(1) << "Malformed ServerNetworkStats for server: "
             << server.Serialize();
    return;
  }
  ServerNetworkStats server_network_stats;
  server_network_stats.srtt =
      base::TimeDelta::FromMicroseconds(maybe_srtt.value());
  // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
  // bandwidth_estimate.
  server_info->server_network_stats = server_network_stats;
}

void HttpServerPropertiesManager::AddToQuicServerInfoMap(
    const base::Value& http_server_properties_dict,
    bool use_network_isolation_key,
    HttpServerProperties::QuicServerInfoMap* quic_server_info_map) {
  const base::Value* quic_server_info_list =
      http_server_properties_dict.FindListKey(kQuicServers);
  if (!quic_server_info_list) {
    DVLOG(1) << "Malformed http_server_properties for quic_servers.";
    return;
  }

  for (const auto& quic_server_info_value : quic_server_info_list->GetList()) {
    if (!quic_server_info_value.is_dict())
      continue;

    const std::string* quic_server_id_str =
        quic_server_info_value.FindStringKey(kQuicServerIdKey);
    if (!quic_server_id_str || quic_server_id_str->empty())
      continue;

    quic::QuicServerId quic_server_id =
        QuicServerIdFromString(*quic_server_id_str);
    if (quic_server_id.host().empty()) {
      DVLOG(1) << "Malformed http_server_properties for quic server: "
               << quic_server_id_str;
      continue;
    }

    NetworkIsolationKey network_isolation_key;
    if (!GetNetworkIsolationKeyFromDict(quic_server_info_value,
                                        use_network_isolation_key,
                                        &network_isolation_key)) {
      DVLOG(1) << "Malformed http_server_properties quic server dict: "
               << *quic_server_id_str;
      continue;
    }

    const std::string* quic_server_info =
        quic_server_info_value.FindStringKey(kServerInfoKey);
    if (!quic_server_info) {
      DVLOG(1) << "Malformed http_server_properties quic server info: "
               << *quic_server_id_str;
      continue;
    }
    quic_server_info_map->Put(
        HttpServerProperties::QuicServerInfoMapKey(
            quic_server_id, network_isolation_key, use_network_isolation_key),
        *quic_server_info);
  }
}

void HttpServerPropertiesManager::WriteToPrefs(
    const HttpServerProperties::ServerInfoMap& server_info_map,
    const GetCannonicalSuffix& get_canonical_suffix,
    const IPAddress& last_local_address_when_quic_worked,
    const HttpServerProperties::QuicServerInfoMap& quic_server_info_map,
    const BrokenAlternativeServiceList& broken_alternative_service_list,
    const RecentlyBrokenAlternativeServices&
        recently_broken_alternative_services,
    base::OnceClosure callback) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  // If loading prefs hasn't completed, don't call it, since this will overwrite
  // existing prefs.
  on_prefs_loaded_callback_.Reset();

  std::set<std::pair<std::string, NetworkIsolationKey>>
      persisted_canonical_suffix_set;
  const base::Time now = base::Time::Now();
  base::Value http_server_properties_dict(base::Value::Type::DICTIONARY);

  // Convert |server_info_map| to a dictionary Value and add it to
  // |http_server_properties_dict|.
  base::Value servers_list(base::Value::Type::LIST);
  for (auto map_it = server_info_map.rbegin(); map_it != server_info_map.rend();
       ++map_it) {
    const HttpServerProperties::ServerInfoMapKey key = map_it->first;
    const HttpServerProperties::ServerInfo& server_info = map_it->second;

    // If can't convert the NetworkIsolationKey to a value, don't save to disk.
    // Generally happens because the key is for a unique origin.
    base::Value network_isolation_key_value;
    if (!key.network_isolation_key.ToValue(&network_isolation_key_value))
      continue;

    base::Value server_dict(base::Value::Type::DICTIONARY);

    bool supports_spdy = server_info.supports_spdy.value_or(false);
    if (supports_spdy)
      server_dict.SetBoolKey(kSupportsSpdyKey, supports_spdy);

    AlternativeServiceInfoVector alternative_services =
        GetAlternativeServiceToPersist(server_info.alternative_services, key,
                                       now, get_canonical_suffix,
                                       &persisted_canonical_suffix_set);
    if (!alternative_services.empty())
      SaveAlternativeServiceToServerPrefs(alternative_services, &server_dict);

    if (server_info.server_network_stats) {
      SaveNetworkStatsToServerPrefs(*server_info.server_network_stats,
                                    &server_dict);
    }

    // Don't add empty entries. This can happen if, for example, all alternative
    // services are empty, or |supports_spdy| is set to false, and all other
    // fields are not set.
    if (server_dict.DictEmpty())
      continue;
    server_dict.SetStringKey(kServerKey, key.server.Serialize());
    server_dict.SetKey(kNetworkIsolationKey,
                       std::move(network_isolation_key_value));
    servers_list.Append(std::move(server_dict));
  }
  http_server_properties_dict.SetKey(kServersKey, std::move(servers_list));

  http_server_properties_dict.SetIntKey(kVersionKey, kVersionNumber);

  SaveLastLocalAddressWhenQuicWorkedToPrefs(last_local_address_when_quic_worked,
                                            &http_server_properties_dict);

  SaveQuicServerInfoMapToServerPrefs(quic_server_info_map,
                                     &http_server_properties_dict);

  SaveBrokenAlternativeServicesToPrefs(
      broken_alternative_service_list, kMaxBrokenAlternativeServicesToPersist,
      recently_broken_alternative_services, &http_server_properties_dict);

  pref_delegate_->SetServerProperties(http_server_properties_dict,
                                      std::move(callback));

  net_log_.AddEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_UPDATE_PREFS,
                    [&] { return http_server_properties_dict.Clone(); });
}

void HttpServerPropertiesManager::SaveAlternativeServiceToServerPrefs(
    const AlternativeServiceInfoVector& alternative_service_info_vector,
    base::Value* server_pref_dict) {
  if (alternative_service_info_vector.empty()) {
    return;
  }
  base::Value alternative_service_list(base::Value::Type::LIST);
  for (const AlternativeServiceInfo& alternative_service_info :
       alternative_service_info_vector) {
    const AlternativeService& alternative_service =
        alternative_service_info.alternative_service();
    DCHECK(IsAlternateProtocolValid(alternative_service.protocol));
    base::Value alternative_service_dict(base::Value::Type::DICTIONARY);
    AddAlternativeServiceFieldsToDictionaryValue(alternative_service,
                                                 &alternative_service_dict);
    // JSON cannot store int64_t, so expiration is converted to a string.
    alternative_service_dict.SetStringKey(
        kExpirationKey,
        base::NumberToString(
            alternative_service_info.expiration().ToInternalValue()));
    base::Value advertised_versions_list(base::Value::Type::LIST);
    for (const auto& version : alternative_service_info.advertised_versions()) {
      advertised_versions_list.Append(quic::AlpnForVersion(version));
    }
    alternative_service_dict.SetKey(kAdvertisedAlpnsKey,
                                    std::move(advertised_versions_list));
    alternative_service_list.Append(std::move(alternative_service_dict));
  }
  if (alternative_service_list.GetList().size() == 0)
    return;
  server_pref_dict->SetKey(kAlternativeServiceKey,
                           std::move(alternative_service_list));
}

void HttpServerPropertiesManager::SaveLastLocalAddressWhenQuicWorkedToPrefs(
    const IPAddress& last_local_address_when_quic_worked,
    base::Value* http_server_properties_dict) {
  if (!last_local_address_when_quic_worked.IsValid())
    return;

  base::Value supports_quic_dict(base::Value::Type::DICTIONARY);
  supports_quic_dict.SetBoolKey(kUsedQuicKey, true);
  supports_quic_dict.SetStringKey(
      kAddressKey, last_local_address_when_quic_worked.ToString());
  http_server_properties_dict->SetKey(kSupportsQuicKey,
                                      std::move(supports_quic_dict));
}

void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
    const ServerNetworkStats& server_network_stats,
    base::Value* server_pref_dict) {
  base::Value server_network_stats_dict(base::Value::Type::DICTIONARY);
  // Becasue JSON doesn't support int64_t, persist int64_t as a string.
  server_network_stats_dict.SetIntKey(
      kSrttKey, static_cast<int>(server_network_stats.srtt.InMicroseconds()));
  // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
  // bandwidth_estimate.
  server_pref_dict->SetKey(kNetworkStatsKey,
                           std::move(server_network_stats_dict));
}

void HttpServerPropertiesManager::SaveQuicServerInfoMapToServerPrefs(
    const HttpServerProperties::QuicServerInfoMap& quic_server_info_map,
    base::Value* http_server_properties_dict) {
  if (quic_server_info_map.empty())
    return;
  base::Value quic_servers_list(base::Value::Type::LIST);
  for (auto it = quic_server_info_map.rbegin();
       it != quic_server_info_map.rend(); ++it) {
    const HttpServerProperties::QuicServerInfoMapKey& key = it->first;

    base::Value network_isolation_key_value;
    // Don't save entries with ephemeral NIKs.
    if (!key.network_isolation_key.ToValue(&network_isolation_key_value))
      continue;

    base::Value quic_server_pref_dict(base::Value::Type::DICTIONARY);
    quic_server_pref_dict.SetStringKey(kQuicServerIdKey,
                                       QuicServerIdToString(key.server_id));
    quic_server_pref_dict.SetKey(kNetworkIsolationKey,
                                 std::move(network_isolation_key_value));
    quic_server_pref_dict.SetStringKey(kServerInfoKey, it->second);

    quic_servers_list.Append(std::move(quic_server_pref_dict));
  }
  http_server_properties_dict->SetKey(kQuicServers,
                                      std::move(quic_servers_list));
}

void HttpServerPropertiesManager::SaveBrokenAlternativeServicesToPrefs(
    const BrokenAlternativeServiceList& broken_alternative_service_list,
    size_t max_broken_alternative_services,
    const RecentlyBrokenAlternativeServices&
        recently_broken_alternative_services,
    base::Value* http_server_properties_dict) {
  if (broken_alternative_service_list.empty() &&
      recently_broken_alternative_services.empty()) {
    return;
  }

  // JSON list will be in MRU order according to
  // |recently_broken_alternative_services|.
  base::Value json_list(base::Value::Type::LIST);

  // Maps recently-broken alternative services to the index where it's stored
  // in |json_list|.
  std::map<BrokenAlternativeService, size_t> json_list_index_map;

  if (!recently_broken_alternative_services.empty()) {
    for (auto it = recently_broken_alternative_services.rbegin();
         it != recently_broken_alternative_services.rend(); ++it) {
      const BrokenAlternativeService& broken_alt_service = it->first;
      int broken_count = it->second;

      base::Value entry_dict(base::Value::Type::DICTIONARY);
      if (!TryAddBrokenAlternativeServiceFieldsToDictionaryValue(
              broken_alt_service, &entry_dict)) {
        continue;
      }
      entry_dict.SetKey(kBrokenCountKey, base::Value(broken_count));
      json_list_index_map[broken_alt_service] = json_list.GetList().size();
      json_list.Append(std::move(entry_dict));
    }
  }

  if (!broken_alternative_service_list.empty()) {
    // Add expiration time info from |broken_alternative_service_list| to
    // the JSON list.
    size_t count = 0;
    for (auto it = broken_alternative_service_list.begin();
         it != broken_alternative_service_list.end() &&
         count < max_broken_alternative_services;
         ++it, ++count) {
      const BrokenAlternativeService& broken_alt_service = it->first;
      base::TimeTicks expiration_time_ticks = it->second;
      // Convert expiration from TimeTicks to Time to time_t
      time_t expiration_time_t =
          (base::Time::Now() + (expiration_time_ticks - clock_->NowTicks()))
              .ToTimeT();
      int64_t expiration_int64 = static_cast<int64_t>(expiration_time_t);

      auto index_map_it = json_list_index_map.find(broken_alt_service);
      if (index_map_it != json_list_index_map.end()) {
        size_t json_list_index = index_map_it->second;
        base::Value& entry_dict = json_list.GetList()[json_list_index];
        DCHECK(entry_dict.is_dict());
        DCHECK(!entry_dict.FindKey(kBrokenUntilKey));
        entry_dict.SetKey(kBrokenUntilKey,
                          base::Value(base::NumberToString(expiration_int64)));
      } else {
        base::Value entry_dict(base::Value::Type::DICTIONARY);
        if (!TryAddBrokenAlternativeServiceFieldsToDictionaryValue(
                broken_alt_service, &entry_dict)) {
          continue;
        }
        entry_dict.SetKey(kBrokenUntilKey,
                          base::Value(base::NumberToString(expiration_int64)));
        json_list.Append(std::move(entry_dict));
      }
    }
  }

  // This can happen if all the entries are for NetworkIsolationKeys for opaque
  // origins, which isn't exactly common, but can theoretically happen.
  if (json_list.GetList().empty())
    return;

  http_server_properties_dict->SetKey(kBrokenAlternativeServicesKey,
                                      std::move(json_list));
}

void HttpServerPropertiesManager::OnHttpServerPropertiesLoaded() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  // If prefs have already been written, nothing to do.
  if (!on_prefs_loaded_callback_)
    return;

  std::unique_ptr<HttpServerProperties::ServerInfoMap> server_info_map;
  IPAddress last_local_address_when_quic_worked;
  std::unique_ptr<HttpServerProperties::QuicServerInfoMap> quic_server_info_map;
  std::unique_ptr<BrokenAlternativeServiceList> broken_alternative_service_list;
  std::unique_ptr<RecentlyBrokenAlternativeServices>
      recently_broken_alternative_services;

  ReadPrefs(&server_info_map, &last_local_address_when_quic_worked,
            &quic_server_info_map, &broken_alternative_service_list,
            &recently_broken_alternative_services);

  std::move(on_prefs_loaded_callback_)
      .Run(std::move(server_info_map), last_local_address_when_quic_worked,
           std::move(quic_server_info_map),
           std::move(broken_alternative_service_list),
           std::move(recently_broken_alternative_services));
}

}  // namespace net
