// Copyright 2017 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/reporting/reporting_cache.h"

#include <algorithm>
#include <map>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#include "base/stl_util.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "net/log/net_log.h"
#include "net/reporting/reporting_client.h"
#include "net/reporting/reporting_context.h"
#include "net/reporting/reporting_report.h"
#include "url/gurl.h"

namespace net {

namespace {

// Returns the superdomain of a given domain, or the empty string if the given
// domain is just a single label. Note that this does not take into account
// anything like the Public Suffix List, so the superdomain may end up being a
// bare TLD.
//
// Examples:
//
// GetSuperdomain("assets.example.com") -> "example.com"
// GetSuperdomain("example.net") -> "net"
// GetSuperdomain("littlebox") -> ""
std::string GetSuperdomain(const std::string& domain) {
  size_t dot_pos = domain.find('.');
  if (dot_pos == std::string::npos)
    return "";

  return domain.substr(dot_pos + 1);
}

struct ClientMetadata {
  base::TimeTicks last_used;
  ReportingCache::ClientStatistics stats;
};

class ReportingCacheImpl : public ReportingCache {
 public:
  ReportingCacheImpl(ReportingContext* context) : context_(context) {
    DCHECK(context_);
  }

  ~ReportingCacheImpl() override {
    base::TimeTicks now = tick_clock()->NowTicks();

    // Mark all undoomed reports as erased at shutdown, and record outcomes of
    // all remaining reports (doomed or not).
    for (auto it = reports_.begin(); it != reports_.end(); ++it) {
      ReportingReport* report = it->second.get();
      if (!base::ContainsKey(doomed_reports_, report))
        report->outcome = ReportingReport::Outcome::ERASED_REPORTING_SHUT_DOWN;
      report->RecordOutcome(now);
    }

    reports_.clear();
  }

  void AddReport(const GURL& url,
                 const std::string& user_agent,
                 const std::string& group,
                 const std::string& type,
                 std::unique_ptr<const base::Value> body,
                 int depth,
                 base::TimeTicks queued,
                 int attempts) override {
    auto report = std::make_unique<ReportingReport>(
        url, user_agent, group, type, std::move(body), depth, queued, attempts);

    auto inserted =
        reports_.insert(std::make_pair(report.get(), std::move(report)));
    DCHECK(inserted.second);

    if (reports_.size() > context_->policy().max_report_count) {
      // There should be at most one extra report (the one added above).
      DCHECK_EQ(context_->policy().max_report_count + 1, reports_.size());
      const ReportingReport* to_evict = FindReportToEvict();
      DCHECK_NE(nullptr, to_evict);
      // The newly-added report isn't pending, so even if all other reports are
      // pending, the cache should have a report to evict.
      DCHECK(!base::ContainsKey(pending_reports_, to_evict));
      reports_[to_evict]->outcome = ReportingReport::Outcome::ERASED_EVICTED;
      RemoveReportInternal(to_evict);
    }

    context_->NotifyCacheUpdated();
  }

  void GetReports(
      std::vector<const ReportingReport*>* reports_out) const override {
    reports_out->clear();
    for (const auto& it : reports_) {
      if (!base::ContainsKey(doomed_reports_, it.first))
        reports_out->push_back(it.second.get());
    }
  }

  base::Value GetReportsAsValue() const override {
    // Sort the queued reports by origin and timestamp.
    std::vector<const ReportingReport*> sorted_reports;
    sorted_reports.reserve(reports_.size());
    for (const auto& it : reports_) {
      sorted_reports.push_back(it.second.get());
    }
    std::sort(
        sorted_reports.begin(), sorted_reports.end(),
        [](const ReportingReport* report1, const ReportingReport* report2) {
          if (report1->queued < report2->queued)
            return true;
          else if (report1->queued > report2->queued)
            return false;
          else
            return report1->url < report2->url;
        });

    std::vector<base::Value> report_list;
    for (const ReportingReport* report : sorted_reports) {
      base::Value report_dict(base::Value::Type::DICTIONARY);
#if defined(STARBOARD)
      report_dict.SetKey("url", base::Value(report->url.spec().c_str()));
      report_dict.SetKey("group", base::Value(report->group.c_str()));
      report_dict.SetKey("type", base::Value(report->type.c_str()));
#else
      report_dict.SetKey("url", base::Value(report->url.spec()));
      report_dict.SetKey("group", base::Value(report->group));
      report_dict.SetKey("type", base::Value(report->type));
#endif
      report_dict.SetKey("depth", base::Value(report->depth));
      report_dict.SetKey(
          "queued", base::Value(NetLog::TickCountToString(report->queued)));
      report_dict.SetKey("attempts", base::Value(report->attempts));
      if (report->body) {
        report_dict.SetKey("body", report->body->Clone());
      }
      if (base::ContainsKey(doomed_reports_, report)) {
        report_dict.SetKey("status", base::Value("doomed"));
      } else if (base::ContainsKey(pending_reports_, report)) {
        report_dict.SetKey("status", base::Value("pending"));
      } else {
        report_dict.SetKey("status", base::Value("queued"));
      }
      report_list.push_back(std::move(report_dict));
    }
    return base::Value(std::move(report_list));
  }

  void GetNonpendingReports(
      std::vector<const ReportingReport*>* reports_out) const override {
    reports_out->clear();
    for (const auto& it : reports_) {
      if (!base::ContainsKey(pending_reports_, it.first) &&
          !base::ContainsKey(doomed_reports_, it.first)) {
        reports_out->push_back(it.second.get());
      }
    }
  }

  void SetReportsPending(
      const std::vector<const ReportingReport*>& reports) override {
    for (const ReportingReport* report : reports) {
      auto inserted = pending_reports_.insert(report);
      DCHECK(inserted.second);
    }
  }

  void ClearReportsPending(
      const std::vector<const ReportingReport*>& reports) override {
    std::vector<const ReportingReport*> reports_to_remove;

    for (const ReportingReport* report : reports) {
      size_t erased = pending_reports_.erase(report);
      DCHECK_EQ(1u, erased);
      if (base::ContainsKey(doomed_reports_, report)) {
        reports_to_remove.push_back(report);
        doomed_reports_.erase(report);
      }
    }

    for (const ReportingReport* report : reports_to_remove)
      RemoveReportInternal(report);
  }

  void IncrementReportsAttempts(
      const std::vector<const ReportingReport*>& reports) override {
    for (const ReportingReport* report : reports) {
      DCHECK(base::ContainsKey(reports_, report));
      reports_[report]->attempts++;
    }

    context_->NotifyCacheUpdated();
  }

  void IncrementEndpointDeliveries(const url::Origin& origin,
                                   const GURL& endpoint,
                                   int reports_delivered,
                                   bool successful) override {
    const ReportingClient* client =
        GetClientByOriginAndEndpoint(origin, endpoint);
    if (client) {
      auto& metadata = client_metadata_[client];
      metadata.stats.attempted_uploads++;
      metadata.stats.attempted_reports += reports_delivered;
      if (successful) {
        metadata.stats.successful_uploads++;
        metadata.stats.successful_reports += reports_delivered;
      }
    }
  }

  void RemoveReports(const std::vector<const ReportingReport*>& reports,
                     ReportingReport::Outcome outcome) override {
    for (const ReportingReport* report : reports) {
      reports_[report]->outcome = outcome;
      if (base::ContainsKey(pending_reports_, report)) {
        doomed_reports_.insert(report);
      } else {
        DCHECK(!base::ContainsKey(doomed_reports_, report));
        RemoveReportInternal(report);
      }
    }

    context_->NotifyCacheUpdated();
  }

  void RemoveAllReports(ReportingReport::Outcome outcome) override {
    std::vector<const ReportingReport*> reports_to_remove;
    for (auto it = reports_.begin(); it != reports_.end(); ++it) {
      ReportingReport* report = it->second.get();
      report->outcome = outcome;
      if (!base::ContainsKey(pending_reports_, report))
        reports_to_remove.push_back(report);
      else
        doomed_reports_.insert(report);
    }

    for (const ReportingReport* report : reports_to_remove)
      RemoveReportInternal(report);

    context_->NotifyCacheUpdated();
  }

  void SetClient(const url::Origin& origin,
                 const GURL& endpoint,
                 ReportingClient::Subdomains subdomains,
                 const std::string& group,
                 base::TimeTicks expires,
                 int priority,
                 int weight) override {
    DCHECK(endpoint.SchemeIsCryptographic());

    base::TimeTicks last_used = tick_clock()->NowTicks();

    const ReportingClient* old_client =
        GetClientByOriginAndEndpoint(origin, endpoint);
    if (old_client) {
      last_used = client_metadata_[old_client].last_used;
      RemoveClient(old_client);
    }

    AddClient(
        std::make_unique<ReportingClient>(origin, endpoint, subdomains, group,
                                          expires, priority, weight),
        last_used);

    if (client_metadata_.size() > context_->policy().max_client_count) {
      // There should only ever be one extra client, added above.
      DCHECK_EQ(context_->policy().max_client_count + 1,
                client_metadata_.size());
      // And that shouldn't happen if it was replaced, not added.
      DCHECK(!old_client);
      const ReportingClient* to_evict =
          FindClientToEvict(tick_clock()->NowTicks());
      DCHECK(to_evict);
      RemoveClient(to_evict);
    }

    context_->NotifyCacheUpdated();
  }

  void MarkClientUsed(const ReportingClient* client) override {
    DCHECK(client);
    client_metadata_[client].last_used = tick_clock()->NowTicks();
  }

  void GetClients(
      std::vector<const ReportingClient*>* clients_out) const override {
    clients_out->clear();
    for (const auto& it : clients_)
      for (const auto& endpoint_and_client : it.second)
        clients_out->push_back(endpoint_and_client.second.get());
  }

  base::Value GetClientsAsValue() const override {
    std::map<const url::Origin,
             std::map<const std::string, std::vector<const ReportingClient*>>>
        clients_by_origin_and_group;
    for (const auto& it : clients_) {
      const url::Origin& origin = it.first;
      for (const auto& endpoint_and_client : it.second) {
        const ReportingClient* client = endpoint_and_client.second.get();
        clients_by_origin_and_group[origin][client->group].push_back(client);
      }
    }

    std::vector<base::Value> origin_list;
    for (const auto& it : clients_by_origin_and_group) {
      const url::Origin& origin = it.first;
      base::Value origin_dict(base::Value::Type::DICTIONARY);
      origin_dict.SetKey("origin", base::Value(origin.Serialize()));
      std::vector<base::Value> group_list;
      for (const auto& group_and_clients : it.second) {
        const std::string& group = group_and_clients.first;
        const std::vector<const ReportingClient*>& clients =
            group_and_clients.second;
        base::Value group_dict(base::Value::Type::DICTIONARY);
#if defined(STARBOARD)
        group_dict.SetKey("name", base::Value(group.c_str()));
#else
        group_dict.SetKey("name", base::Value(group));
#endif
        std::vector<base::Value> endpoint_list;
        for (const ReportingClient* client : clients) {
          base::Value endpoint_dict(base::Value::Type::DICTIONARY);
          // Reporting defines the group as a whole to have an expiration time
          // and subdomains flag, not the individual endpoints within the group.
          group_dict.SetKey(
              "expires",
#if defined(STARBOARD)
              base::Value(NetLog::TickCountToString(client->expires).c_str()));
#else
              base::Value(NetLog::TickCountToString(client->expires)));
#endif
          group_dict.SetKey("includeSubdomains",
                            base::Value(client->subdomains ==
                                        ReportingClient::Subdomains::INCLUDE));
          endpoint_dict.SetKey("url", base::Value(client->endpoint.spec()));
          endpoint_dict.SetKey("priority", base::Value(client->priority));
          endpoint_dict.SetKey("weight", base::Value(client->weight));
          auto metadata_it = client_metadata_.find(client);
          if (metadata_it != client_metadata_.end()) {
            const ClientStatistics& stats = metadata_it->second.stats;
            base::Value successful_dict(base::Value::Type::DICTIONARY);
            successful_dict.SetKey("uploads",
                                   base::Value(stats.successful_uploads));
            successful_dict.SetKey("reports",
                                   base::Value(stats.successful_reports));
            endpoint_dict.SetKey("successful", std::move(successful_dict));
            base::Value failed_dict(base::Value::Type::DICTIONARY);
            failed_dict.SetKey("uploads",
                               base::Value(stats.attempted_uploads -
                                           stats.successful_uploads));
            failed_dict.SetKey("reports",
                               base::Value(stats.attempted_reports -
                                           stats.successful_reports));
            endpoint_dict.SetKey("failed", std::move(failed_dict));
          }
          endpoint_list.push_back(std::move(endpoint_dict));
        }
        group_dict.SetKey("endpoints", base::Value(std::move(endpoint_list)));
        group_list.push_back(std::move(group_dict));
      }
      origin_dict.SetKey("groups", base::Value(std::move(group_list)));
      origin_list.push_back(std::move(origin_dict));
    }
    return base::Value(std::move(origin_list));
  }

  void GetClientsForOriginAndGroup(
      const url::Origin& origin,
      const std::string& group,
      std::vector<const ReportingClient*>* clients_out) const override {
    clients_out->clear();

    const auto it = clients_.find(origin);
    if (it != clients_.end()) {
      for (const auto& endpoint_and_client : it->second) {
        if (endpoint_and_client.second->group == group)
          clients_out->push_back(endpoint_and_client.second.get());
      }
    }

    // If no clients were found, try successive superdomain suffixes until a
    // client with include_subdomains is found or there are no more domain
    // components left.
    std::string domain = origin.host();
    while (clients_out->empty() && !domain.empty()) {
      GetWildcardClientsForDomainAndGroup(domain, group, clients_out);
      domain = GetSuperdomain(domain);
    }
  }

  // TODO(juliatuttle): Unittests.
  void GetEndpointsForOrigin(const url::Origin& origin,
                             std::vector<GURL>* endpoints_out) const override {
    endpoints_out->clear();

    const auto it = clients_.find(origin);
    if (it == clients_.end())
      return;

    for (const auto& endpoint_and_client : it->second)
      endpoints_out->push_back(endpoint_and_client.first);
  }

  void RemoveClients(
      const std::vector<const ReportingClient*>& clients_to_remove) override {
    for (const ReportingClient* client : clients_to_remove)
      RemoveClient(client);

    context_->NotifyCacheUpdated();
  }

  void RemoveClientForOriginAndEndpoint(const url::Origin& origin,
                                        const GURL& endpoint) override {
    const ReportingClient* client =
        GetClientByOriginAndEndpoint(origin, endpoint);
    RemoveClient(client);

    context_->NotifyCacheUpdated();
  }

  void RemoveClientsForEndpoint(const GURL& endpoint) override {
    std::vector<const ReportingClient*> clients_to_remove;

    for (auto& origin_and_endpoints : clients_)
      if (base::ContainsKey(origin_and_endpoints.second, endpoint))
        clients_to_remove.push_back(
            origin_and_endpoints.second[endpoint].get());

    for (const ReportingClient* client : clients_to_remove)
      RemoveClient(client);

    if (!clients_to_remove.empty())
      context_->NotifyCacheUpdated();
  }

  void RemoveAllClients() override {
    clients_.clear();
    wildcard_clients_.clear();
    client_metadata_.clear();

    context_->NotifyCacheUpdated();
  }

  ClientStatistics GetStatisticsForOriginAndEndpoint(
      const url::Origin& origin,
      const GURL& endpoint) const override {
    const ReportingClient* client =
        GetClientByOriginAndEndpoint(origin, endpoint);
    auto it = client_metadata_.find(client);
    if (it == client_metadata_.end()) {
      return ClientStatistics();
    }
    return it->second.stats;
  }

  size_t GetFullReportCountForTesting() const override {
    return reports_.size();
  }

  bool IsReportPendingForTesting(const ReportingReport* report) const override {
    return base::ContainsKey(pending_reports_, report);
  }

  bool IsReportDoomedForTesting(const ReportingReport* report) const override {
    return base::ContainsKey(doomed_reports_, report);
  }

 private:
  void RemoveReportInternal(const ReportingReport* report) {
    reports_[report]->RecordOutcome(tick_clock()->NowTicks());
    size_t erased = reports_.erase(report);
    DCHECK_EQ(1u, erased);
  }

  const ReportingReport* FindReportToEvict() const {
    const ReportingReport* earliest_queued = nullptr;

    for (const auto& it : reports_) {
      const ReportingReport* report = it.first;
      if (base::ContainsKey(pending_reports_, report))
        continue;
      if (!earliest_queued || report->queued < earliest_queued->queued) {
        earliest_queued = report;
      }
    }

    return earliest_queued;
  }

  void AddClient(std::unique_ptr<ReportingClient> client,
                 base::TimeTicks last_used) {
    DCHECK(client);

    url::Origin origin = client->origin;
    GURL endpoint = client->endpoint;

    auto inserted_metadata = client_metadata_.insert(
        std::make_pair(client.get(), ClientMetadata{last_used}));
    DCHECK(inserted_metadata.second);

    if (client->subdomains == ReportingClient::Subdomains::INCLUDE) {
      const std::string& domain = origin.host();
      auto inserted_wildcard_client =
          wildcard_clients_[domain].insert(client.get());
      DCHECK(inserted_wildcard_client.second);
    }

    auto inserted_client =
        clients_[origin].insert(std::make_pair(endpoint, std::move(client)));
    DCHECK(inserted_client.second);
  }

  void RemoveClient(const ReportingClient* client) {
    DCHECK(client);

    url::Origin origin = client->origin;
    GURL endpoint = client->endpoint;

    if (client->subdomains == ReportingClient::Subdomains::INCLUDE) {
      const std::string& domain = origin.host();
      size_t erased_wildcard_client = wildcard_clients_[domain].erase(client);
      DCHECK_EQ(1u, erased_wildcard_client);
      if (wildcard_clients_[domain].empty()) {
        size_t erased_wildcard_domain = wildcard_clients_.erase(domain);
        DCHECK_EQ(1u, erased_wildcard_domain);
      }
    }

    size_t erased_metadata = client_metadata_.erase(client);
    DCHECK_EQ(1u, erased_metadata);

    size_t erased_endpoint = clients_[origin].erase(endpoint);
    DCHECK_EQ(1u, erased_endpoint);
    if (clients_[origin].empty()) {
      size_t erased_origin = clients_.erase(origin);
      DCHECK_EQ(1u, erased_origin);
    }
  }

  const ReportingClient* GetClientByOriginAndEndpoint(
      const url::Origin& origin,
      const GURL& endpoint) const {
    const auto& origin_it = clients_.find(origin);
    if (origin_it == clients_.end())
      return nullptr;

    const auto& endpoint_it = origin_it->second.find(endpoint);
    if (endpoint_it == origin_it->second.end())
      return nullptr;

    return endpoint_it->second.get();
  }

  void GetWildcardClientsForDomainAndGroup(
      const std::string& domain,
      const std::string& group,
      std::vector<const ReportingClient*>* clients_out) const {
    clients_out->clear();

    auto it = wildcard_clients_.find(domain);
    if (it == wildcard_clients_.end())
      return;

    for (const ReportingClient* client : it->second) {
      DCHECK_EQ(ReportingClient::Subdomains::INCLUDE, client->subdomains);
      if (client->group == group)
        clients_out->push_back(client);
    }
  }

  const ReportingClient* FindClientToEvict(base::TimeTicks now) const {
    DCHECK(!client_metadata_.empty());

    const ReportingClient* earliest_used = nullptr;
    base::TimeTicks earliest_used_last_used;
    const ReportingClient* earliest_expired = nullptr;

    for (const auto& it : client_metadata_) {
      const ReportingClient* client = it.first;
      base::TimeTicks client_last_used = it.second.last_used;
      if (earliest_used == nullptr ||
          client_last_used < earliest_used_last_used) {
        earliest_used = client;
        earliest_used_last_used = client_last_used;
      }
      if (earliest_expired == nullptr ||
          client->expires < earliest_expired->expires) {
        earliest_expired = client;
      }
    }

    // If there are expired clients, return the earliest-expired.
    if (earliest_expired->expires < now)
      return earliest_expired;
    else
      return earliest_used;
  }

  const base::TickClock* tick_clock() { return context_->tick_clock(); }

  ReportingContext* context_;

  // Owns all reports, keyed by const raw pointer for easier lookup.
  std::unordered_map<const ReportingReport*, std::unique_ptr<ReportingReport>>
      reports_;

  // Reports that have been marked pending (in use elsewhere and should not be
  // deleted until no longer pending).
  std::unordered_set<const ReportingReport*> pending_reports_;

  // Reports that have been marked doomed (would have been deleted, but were
  // pending when the deletion was requested).
  std::unordered_set<const ReportingReport*> doomed_reports_;

  // Owns all clients, keyed by origin, then endpoint URL.
  // (These would be unordered_map, but neither url::Origin nor GURL has a hash
  // function implemented.)
  std::map<url::Origin, std::map<GURL, std::unique_ptr<ReportingClient>>>
      clients_;

  // References but does not own all clients with include_subdomains set, keyed
  // by domain name.
  std::unordered_map<std::string, std::unordered_set<const ReportingClient*>>
      wildcard_clients_;

  // The time that each client has last been used.
  std::unordered_map<const ReportingClient*, ClientMetadata> client_metadata_;
};

}  // namespace

// static
std::unique_ptr<ReportingCache> ReportingCache::Create(
    ReportingContext* context) {
  return std::make_unique<ReportingCacheImpl>(context);
}

ReportingCache::~ReportingCache() = default;

}  // namespace net
