// Copyright (c) 2012 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_impl.h"

#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"

namespace net {

namespace {

const uint64 kBrokenAlternativeProtocolDelaySecs = 300;

}  // namespace

HttpServerPropertiesImpl::HttpServerPropertiesImpl()
    : spdy_servers_map_(SpdyServerHostPortMap::NO_AUTO_EVICT),
      alternative_service_map_(AlternativeServiceMap::NO_AUTO_EVICT),
      spdy_settings_map_(SpdySettingsMap::NO_AUTO_EVICT),
      server_network_stats_map_(ServerNetworkStatsMap::NO_AUTO_EVICT),
      alternative_service_probability_threshold_(1.0),
      weak_ptr_factory_(this) {
  canonical_suffixes_.push_back(".c.youtube.com");
  canonical_suffixes_.push_back(".googlevideo.com");
  canonical_suffixes_.push_back(".googleusercontent.com");
}

HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
}

void HttpServerPropertiesImpl::InitializeSpdyServers(
    std::vector<std::string>* spdy_servers,
    bool support_spdy) {
  DCHECK(CalledOnValidThread());
  if (!spdy_servers)
    return;
  // Add the entries from persisted data.
  for (std::vector<std::string>::reverse_iterator it = spdy_servers->rbegin();
       it != spdy_servers->rend(); ++it) {
    spdy_servers_map_.Put(*it, support_spdy);
  }
}

void HttpServerPropertiesImpl::InitializeAlternativeServiceServers(
    AlternativeServiceMap* alternative_service_map) {
  // Keep all the broken ones since those don't get persisted.
  for (AlternativeServiceMap::iterator it = alternative_service_map_.begin();
       it != alternative_service_map_.end();) {
    if (IsAlternativeServiceBroken(it->second.alternative_service)) {
      ++it;
    } else {
      it = alternative_service_map_.Erase(it);
    }
  }

  // Add the entries from persisted data.
  for (AlternativeServiceMap::reverse_iterator it =
           alternative_service_map->rbegin();
       it != alternative_service_map->rend(); ++it) {
    alternative_service_map_.Put(it->first, it->second);
  }

  // Attempt to find canonical servers.
  uint16 canonical_ports[] = { 80, 443 };
  for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
    std::string canonical_suffix = canonical_suffixes_[i];
    for (size_t j = 0; j < arraysize(canonical_ports); ++j) {
      HostPortPair canonical_host(canonical_suffix, canonical_ports[j]);
      // If we already have a valid canonical server, we're done.
      if (ContainsKey(canonical_host_to_origin_map_, canonical_host) &&
          (alternative_service_map_.Peek(
               canonical_host_to_origin_map_[canonical_host]) !=
           alternative_service_map_.end())) {
        continue;
      }
      // Now attempt to find a server which matches this origin and set it as
      // canonical.
      for (AlternativeServiceMap::const_iterator it =
               alternative_service_map_.begin();
           it != alternative_service_map_.end(); ++it) {
        if (base::EndsWith(it->first.host(), canonical_suffixes_[i],
                           base::CompareCase::SENSITIVE)) {
          canonical_host_to_origin_map_[canonical_host] = it->first;
          break;
        }
      }
    }
  }
}

void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
    SpdySettingsMap* spdy_settings_map) {
  for (SpdySettingsMap::reverse_iterator it = spdy_settings_map->rbegin();
       it != spdy_settings_map->rend(); ++it) {
    spdy_settings_map_.Put(it->first, it->second);
  }
}

void HttpServerPropertiesImpl::InitializeSupportsQuic(
    IPAddressNumber* last_address) {
  if (last_address)
    last_quic_address_ = *last_address;
}

void HttpServerPropertiesImpl::InitializeServerNetworkStats(
    ServerNetworkStatsMap* server_network_stats_map) {
  for (ServerNetworkStatsMap::reverse_iterator it =
           server_network_stats_map->rbegin();
       it != server_network_stats_map->rend(); ++it) {
    server_network_stats_map_.Put(it->first, it->second);
  }
}

void HttpServerPropertiesImpl::GetSpdyServerList(
    base::ListValue* spdy_server_list,
    size_t max_size) const {
  DCHECK(CalledOnValidThread());
  DCHECK(spdy_server_list);
  spdy_server_list->Clear();
  size_t count = 0;
  // Get the list of servers (host/port) that support SPDY.
  for (SpdyServerHostPortMap::const_iterator it = spdy_servers_map_.begin();
       it != spdy_servers_map_.end() && count < max_size; ++it) {
    const std::string spdy_server_host_port = it->first;
    if (it->second) {
      spdy_server_list->Append(new base::StringValue(spdy_server_host_port));
      ++count;
    }
  }
}

base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() {
  return weak_ptr_factory_.GetWeakPtr();
}

void HttpServerPropertiesImpl::Clear() {
  DCHECK(CalledOnValidThread());
  spdy_servers_map_.Clear();
  alternative_service_map_.Clear();
  canonical_host_to_origin_map_.clear();
  spdy_settings_map_.Clear();
  last_quic_address_.clear();
  server_network_stats_map_.Clear();
}

bool HttpServerPropertiesImpl::SupportsRequestPriority(
    const HostPortPair& host_port_pair) {
  DCHECK(CalledOnValidThread());
  if (host_port_pair.host().empty())
    return false;

  SpdyServerHostPortMap::iterator spdy_host_port =
      spdy_servers_map_.Get(host_port_pair.ToString());
  if (spdy_host_port != spdy_servers_map_.end() && spdy_host_port->second)
    return true;

  const AlternativeService alternative_service =
      GetAlternativeService(host_port_pair);
  return alternative_service.protocol == QUIC;
}

void HttpServerPropertiesImpl::SetSupportsSpdy(
    const HostPortPair& host_port_pair,
    bool support_spdy) {
  DCHECK(CalledOnValidThread());
  if (host_port_pair.host().empty())
    return;

  SpdyServerHostPortMap::iterator spdy_host_port =
      spdy_servers_map_.Get(host_port_pair.ToString());
  if ((spdy_host_port != spdy_servers_map_.end()) &&
      (spdy_host_port->second == support_spdy)) {
    return;
  }
  // Cache the data.
  spdy_servers_map_.Put(host_port_pair.ToString(), support_spdy);
}

bool HttpServerPropertiesImpl::RequiresHTTP11(
    const HostPortPair& host_port_pair) {
  DCHECK(CalledOnValidThread());
  if (host_port_pair.host().empty())
    return false;

  return (http11_servers_.find(host_port_pair) != http11_servers_.end());
}

void HttpServerPropertiesImpl::SetHTTP11Required(
    const HostPortPair& host_port_pair) {
  DCHECK(CalledOnValidThread());
  if (host_port_pair.host().empty())
    return;

  http11_servers_.insert(host_port_pair);
}

void HttpServerPropertiesImpl::MaybeForceHTTP11(const HostPortPair& server,
                                                SSLConfig* ssl_config) {
  if (RequiresHTTP11(server)) {
    ForceHTTP11(ssl_config);
  }
}

std::string HttpServerPropertiesImpl::GetCanonicalSuffix(
    const std::string& host) {
  // If this host ends with a canonical suffix, then return the canonical
  // suffix.
  for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
    std::string canonical_suffix = canonical_suffixes_[i];
    if (base::EndsWith(host, canonical_suffixes_[i],
                       base::CompareCase::SENSITIVE)) {
      return canonical_suffix;
    }
  }
  return std::string();
}

AlternativeService HttpServerPropertiesImpl::GetAlternativeService(
    const HostPortPair& origin) {
  AlternativeServiceMap::const_iterator it =
      alternative_service_map_.Get(origin);
  if (it != alternative_service_map_.end()) {
    if (it->second.probability < alternative_service_probability_threshold_) {
      return AlternativeService();
    }
    AlternativeService alternative_service(it->second.alternative_service);
    if (alternative_service.host.empty()) {
      alternative_service.host = origin.host();
    }
    return alternative_service;
  }

  CanonicalHostMap::const_iterator canonical = GetCanonicalHost(origin);
  if (canonical == canonical_host_to_origin_map_.end()) {
    return AlternativeService();
  }
  it = alternative_service_map_.Get(canonical->second);
  if (it == alternative_service_map_.end()) {
    return AlternativeService();
  }
  if (it->second.probability < alternative_service_probability_threshold_) {
    return AlternativeService();
  }
  AlternativeService alternative_service(it->second.alternative_service);
  if (alternative_service.host.empty()) {
    alternative_service.host = canonical->second.host();
  }
  if (IsAlternativeServiceBroken(alternative_service)) {
    RemoveCanonicalHost(canonical->second);
    return AlternativeService();
  }
  // Empty hostname: if alternative service for with hostname of canonical host
  // is not broken, then return alternative service with hostname of origin.
  if (it->second.alternative_service.host.empty()) {
    alternative_service.host = origin.host();
  }
  return alternative_service;
}

void HttpServerPropertiesImpl::SetAlternativeService(
    const HostPortPair& origin,
    const AlternativeService& alternative_service,
    double alternative_probability) {
  AlternativeService complete_alternative_service(alternative_service);
  if (complete_alternative_service.host.empty()) {
    complete_alternative_service.host = origin.host();
  }
  if (IsAlternativeServiceBroken(complete_alternative_service)) {
    DVLOG(1) << "Ignore alternative service since it is known to be broken.";
    return;
  }

  const AlternativeServiceInfo alternative_service_info(
      alternative_service, alternative_probability);
  AlternativeServiceMap::const_iterator it =
      GetAlternateProtocolIterator(origin);
  if (it != alternative_service_map_.end()) {
    const AlternativeServiceInfo existing_alternative_service_info = it->second;
    if (existing_alternative_service_info != alternative_service_info) {
      LOG(WARNING) << "Changing the alternative service for: "
                   << origin.ToString() << " from "
                   << existing_alternative_service_info.ToString() << " to "
                   << alternative_service_info.ToString() << ".";
    }
  } else {
    if (alternative_probability >= alternative_service_probability_threshold_) {
      // TODO(rch): Consider the case where multiple requests are started
      // before the first completes. In this case, only one of the jobs
      // would reach this code, whereas all of them should should have.
      HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING);
    }
  }

  alternative_service_map_.Put(origin, alternative_service_info);

  // If this host ends with a canonical suffix, then set it as the
  // canonical host.
  for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
    std::string canonical_suffix = canonical_suffixes_[i];
    if (base::EndsWith(origin.host(), canonical_suffixes_[i],
                       base::CompareCase::SENSITIVE)) {
      HostPortPair canonical_host(canonical_suffix, origin.port());
      canonical_host_to_origin_map_[canonical_host] = origin;
      break;
    }
  }
}

void HttpServerPropertiesImpl::MarkAlternativeServiceBroken(
    const AlternativeService& alternative_service) {
  if (alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL) {
    LOG(DFATAL) << "Trying to mark unknown alternate protocol broken.";
    return;
  }
  int count = ++recently_broken_alternative_services_[alternative_service];
  base::TimeDelta delay =
      base::TimeDelta::FromSeconds(kBrokenAlternativeProtocolDelaySecs);
  base::TimeTicks when = base::TimeTicks::Now() + delay * (1 << (count - 1));
  auto result = broken_alternative_services_.insert(
      std::make_pair(alternative_service, when));
  // Return if alternative service is already in expiration queue.
  if (!result.second) {
    return;
  }

  // If this is the only entry in the list, schedule an expiration task.
  // Otherwise it will be rescheduled automatically when the pending task runs.
  if (broken_alternative_services_.size() == 1) {
    ScheduleBrokenAlternateProtocolMappingsExpiration();
  }
}

void HttpServerPropertiesImpl::MarkAlternativeServiceRecentlyBroken(
    const AlternativeService& alternative_service) {
  if (!ContainsKey(recently_broken_alternative_services_, alternative_service))
    recently_broken_alternative_services_[alternative_service] = 1;
}

bool HttpServerPropertiesImpl::IsAlternativeServiceBroken(
    const AlternativeService& alternative_service) const {
  // Empty host means use host of origin, callers are supposed to substitute.
  DCHECK(!alternative_service.host.empty());
  return ContainsKey(broken_alternative_services_, alternative_service);
}

bool HttpServerPropertiesImpl::WasAlternativeServiceRecentlyBroken(
    const AlternativeService& alternative_service) {
  if (alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
    return false;
  return ContainsKey(recently_broken_alternative_services_,
                     alternative_service);
}

void HttpServerPropertiesImpl::ConfirmAlternativeService(
    const AlternativeService& alternative_service) {
  if (alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
    return;
  broken_alternative_services_.erase(alternative_service);
  recently_broken_alternative_services_.erase(alternative_service);
}

void HttpServerPropertiesImpl::ClearAlternativeService(
    const HostPortPair& origin) {
  RemoveCanonicalHost(origin);

  AlternativeServiceMap::iterator it = alternative_service_map_.Peek(origin);
  if (it == alternative_service_map_.end()) {
    return;
  }
  AlternativeService alternative_service(it->second.alternative_service);
  if (alternative_service.host.empty()) {
    alternative_service.host = origin.host();
  }
  alternative_service_map_.Erase(it);

  // The following is temporary to keep the existing semantics, which is that if
  // there is a broken alternative service in the mapping, then this method
  // leaves it in a non-broken, but recently broken state.
  //
  // TODO(bnc):
  //  1. Verify and document the class invariant that no broken alternative
  //     service can be in the mapping.
  //  2. Remove the rest of this method as it will be moot.
  broken_alternative_services_.erase(alternative_service);
}

const AlternativeServiceMap& HttpServerPropertiesImpl::alternative_service_map()
    const {
  return alternative_service_map_;
}

base::Value* HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue()
    const {
  base::ListValue* dict_list = new base::ListValue();
  for (const auto& alternative_service_map_item : alternative_service_map_) {
    const HostPortPair& host_port_pair = alternative_service_map_item.first;
    const AlternativeServiceInfo& alternative_service_info =
        alternative_service_map_item.second;
    std::string alternative_service_string(alternative_service_info.ToString());
    AlternativeService alternative_service(
        alternative_service_info.alternative_service);
    if (alternative_service.host.empty()) {
      alternative_service.host = host_port_pair.host();
    }
    if (IsAlternativeServiceBroken(alternative_service)) {
      alternative_service_string.append(" (broken)");
    }

    base::DictionaryValue* dict = new base::DictionaryValue();
    dict->SetString("host_port_pair", host_port_pair.ToString());
    dict->SetString("alternative_service", alternative_service_string);
    dict_list->Append(dict);
  }
  return dict_list;
}

const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings(
    const HostPortPair& host_port_pair) {
  SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
  if (it == spdy_settings_map_.end()) {
    CR_DEFINE_STATIC_LOCAL(SettingsMap, kEmptySettingsMap, ());
    return kEmptySettingsMap;
  }
  return it->second;
}

bool HttpServerPropertiesImpl::SetSpdySetting(
    const HostPortPair& host_port_pair,
    SpdySettingsIds id,
    SpdySettingsFlags flags,
    uint32 value) {
  if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST))
      return false;

  SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
  SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
  if (it == spdy_settings_map_.end()) {
    SettingsMap settings_map;
    settings_map[id] = flags_and_value;
    spdy_settings_map_.Put(host_port_pair, settings_map);
  } else {
    SettingsMap& settings_map = it->second;
    settings_map[id] = flags_and_value;
  }
  return true;
}

void HttpServerPropertiesImpl::ClearSpdySettings(
    const HostPortPair& host_port_pair) {
  SpdySettingsMap::iterator it = spdy_settings_map_.Peek(host_port_pair);
  if (it != spdy_settings_map_.end())
    spdy_settings_map_.Erase(it);
}

void HttpServerPropertiesImpl::ClearAllSpdySettings() {
  spdy_settings_map_.Clear();
}

const SpdySettingsMap&
HttpServerPropertiesImpl::spdy_settings_map() const {
  return spdy_settings_map_;
}

bool HttpServerPropertiesImpl::GetSupportsQuic(
    IPAddressNumber* last_address) const {
  if (last_quic_address_.empty())
    return false;

  *last_address = last_quic_address_;
  return true;
}

void HttpServerPropertiesImpl::SetSupportsQuic(bool used_quic,
                                               const IPAddressNumber& address) {
  if (!used_quic) {
    last_quic_address_.clear();
  } else {
    last_quic_address_ = address;
  }
}

void HttpServerPropertiesImpl::SetServerNetworkStats(
    const HostPortPair& host_port_pair,
    ServerNetworkStats stats) {
  server_network_stats_map_.Put(host_port_pair, stats);
}

const ServerNetworkStats* HttpServerPropertiesImpl::GetServerNetworkStats(
    const HostPortPair& host_port_pair) {
  ServerNetworkStatsMap::iterator it =
      server_network_stats_map_.Get(host_port_pair);
  if (it == server_network_stats_map_.end()) {
    return NULL;
  }
  return &it->second;
}

const ServerNetworkStatsMap&
HttpServerPropertiesImpl::server_network_stats_map() const {
  return server_network_stats_map_;
}

void HttpServerPropertiesImpl::SetAlternativeServiceProbabilityThreshold(
    double threshold) {
  alternative_service_probability_threshold_ = threshold;
}

AlternativeServiceMap::const_iterator
HttpServerPropertiesImpl::GetAlternateProtocolIterator(
    const HostPortPair& server) {
  AlternativeServiceMap::const_iterator it =
      alternative_service_map_.Get(server);
  if (it != alternative_service_map_.end())
    return it;

  CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
  if (canonical == canonical_host_to_origin_map_.end()) {
    return alternative_service_map_.end();
  }

  const HostPortPair canonical_host_port = canonical->second;
  it = alternative_service_map_.Get(canonical_host_port);
  if (it == alternative_service_map_.end()) {
    return alternative_service_map_.end();
  }

  const AlternativeService alternative_service(
      it->second.alternative_service.protocol, canonical_host_port.host(),
      it->second.alternative_service.port);
  if (!IsAlternativeServiceBroken(alternative_service)) {
    return it;
  }

  RemoveCanonicalHost(canonical_host_port);
  return alternative_service_map_.end();
}

HttpServerPropertiesImpl::CanonicalHostMap::const_iterator
HttpServerPropertiesImpl::GetCanonicalHost(HostPortPair server) const {
  for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
    std::string canonical_suffix = canonical_suffixes_[i];
    if (base::EndsWith(server.host(), canonical_suffixes_[i],
                       base::CompareCase::SENSITIVE)) {
      HostPortPair canonical_host(canonical_suffix, server.port());
      return canonical_host_to_origin_map_.find(canonical_host);
    }
  }

  return canonical_host_to_origin_map_.end();
}

void HttpServerPropertiesImpl::RemoveCanonicalHost(
    const HostPortPair& server) {
  CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
  if (canonical == canonical_host_to_origin_map_.end())
    return;

  if (!canonical->second.Equals(server))
    return;

  canonical_host_to_origin_map_.erase(canonical->first);
}

void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
  base::TimeTicks now = base::TimeTicks::Now();
  while (!broken_alternative_services_.empty()) {
    BrokenAlternativeServices::iterator it =
        broken_alternative_services_.begin();
    if (now < it->second) {
      break;
    }

    const AlternativeService alternative_service = it->first;
    broken_alternative_services_.erase(it);
    // TODO(bnc): Make sure broken alternative services are not in the mapping.
    ClearAlternativeService(
        HostPortPair(alternative_service.host, alternative_service.port));
  }
  ScheduleBrokenAlternateProtocolMappingsExpiration();
}

void
HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
  if (broken_alternative_services_.empty()) {
    return;
  }
  base::TimeTicks now = base::TimeTicks::Now();
  base::TimeTicks when = broken_alternative_services_.front().second;
  base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
  base::MessageLoop::current()->PostDelayedTask(
      FROM_HERE,
      base::Bind(
          &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
          weak_ptr_factory_.GetWeakPtr()),
      delay);
}

}  // namespace net
