910e62b5创建于 1月15日历史提交
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/domain_reliability/context_manager.h"

#include <utility>

#include "base/functional/callback_helpers.h"
#include "components/domain_reliability/google_configs.h"
#include "net/base/url_util.h"

namespace domain_reliability {

DomainReliabilityContextManager::DomainReliabilityContextManager(
    const MockableTime* time,
    const std::string& upload_reporter_string,
    DomainReliabilityContext::UploadAllowedCallback upload_allowed_callback,
    DomainReliabilityDispatcher* dispatcher)
    : time_(time),
      upload_reporter_string_(upload_reporter_string),
      upload_allowed_callback_(upload_allowed_callback),
      dispatcher_(dispatcher) {
  DCHECK(time_);
  DCHECK(dispatcher_);
}

DomainReliabilityContextManager::~DomainReliabilityContextManager() = default;

void DomainReliabilityContextManager::RouteBeacon(
    std::unique_ptr<DomainReliabilityBeacon> beacon) {
  const std::string& beacon_host = beacon->url.GetHost();

  // An exact match for the host always takes priority.
  DomainReliabilityContext* context_to_use = GetContext(beacon_host);
  if (context_to_use) {
    context_to_use->OnBeacon(std::move(beacon));
    return;
  }

  DomainReliabilityContext* superdomain_context =
      GetSuperdomainContext(beacon_host);

  // Try to get a Google config which may match the host itself, or the host's
  // parent domain.
  std::unique_ptr<const DomainReliabilityConfig> google_config =
      MaybeGetGoogleConfig(beacon_host);

  if (!google_config) {
    if (superdomain_context)
      superdomain_context->OnBeacon(std::move(beacon));
    return;
  }

  context_to_use = superdomain_context;
  bool google_config_is_exact = (google_config->origin.host() == beacon_host);

  // An exact match takes priority over an existing superdomain context, if any
  // exists.
  if (google_config_is_exact || !context_to_use)
    context_to_use = AddContextForConfig(std::move(google_config));

  context_to_use->OnBeacon(std::move(beacon));
}

void DomainReliabilityContextManager::ClearBeacons(
    const base::RepeatingCallback<bool(const url::Origin&)>& origin_filter) {
  for (auto& context_entry : contexts_) {
    if (origin_filter.is_null() ||
        origin_filter.Run(context_entry.second->config().origin)) {
      context_entry.second->ClearBeacons();
    }
  }
}

DomainReliabilityContext* DomainReliabilityContextManager::AddContextForConfig(
    std::unique_ptr<const DomainReliabilityConfig> config) {
  const std::string& key = config->origin.host();
  auto pair = contexts_.insert(
      std::make_pair(key, CreateContextForConfig(std::move(config))));

  // Insertion should have succeeded (the key should not have already existed).
  DCHECK(pair.second);
  return pair.first->second.get();
}

void DomainReliabilityContextManager::RemoveContexts(
    const base::RepeatingCallback<bool(const url::Origin&)>& origin_filter) {
  if (origin_filter.is_null()) {
    contexts_.clear();
    return;
  }

  for (auto it = contexts_.begin(); it != contexts_.end();) {
    if (origin_filter.Run(it->second->config().origin)) {
      it = contexts_.erase(it);
      continue;
    }
    ++it;
  }
}

DomainReliabilityContext* DomainReliabilityContextManager::GetContext(
    const std::string& host) const {
  ContextMap::const_iterator context_it = contexts_.find(host);
  if (context_it == contexts_.end())
    return nullptr;
  return context_it->second.get();
}

DomainReliabilityContext*
DomainReliabilityContextManager::GetSuperdomainContext(
    const std::string& host) const {
  // TODO(juliatuttle): Make sure parent is not in PSL before using.
  std::string parent_host = net::GetSuperdomain(host);
  if (parent_host.empty())
    return nullptr;

  DomainReliabilityContext* context = GetContext(parent_host);
  if (context && context->config().include_subdomains)
    return context;

  return nullptr;
}

void DomainReliabilityContextManager::OnNetworkChanged(base::TimeTicks now) {
  last_network_change_time_ = now;
}

void DomainReliabilityContextManager::SetUploader(
    DomainReliabilityUploader* uploader) {
  DCHECK(!uploader_);
  DCHECK(uploader);
  uploader_ = uploader;
}

std::unique_ptr<DomainReliabilityContext>
DomainReliabilityContextManager::CreateContextForConfig(
    std::unique_ptr<const DomainReliabilityConfig> config) const {
  DCHECK(config);
  DCHECK(config->IsValid());
  DCHECK(uploader_);

  return std::make_unique<DomainReliabilityContext>(
      time_, DomainReliabilityScheduler::Params::GetFromFieldTrialsOrDefaults(),
      upload_reporter_string_, &last_network_change_time_,
      upload_allowed_callback_, dispatcher_, uploader_, std::move(config));
}

}  // namespace domain_reliability