// Copyright 2013 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 "content/browser/service_worker/service_worker_context_core.h"

#include <limits>
#include <set>
#include <utility>

#include "base/barrier_closure.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
#include "content/browser/service_worker/service_worker_context_observer.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_database_task_manager.h"
#include "content/browser/service_worker/service_worker_info.h"
#include "content/browser/service_worker/service_worker_job_coordinator.h"
#include "content/browser/service_worker/service_worker_process_manager.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
#include "content/browser/service_worker/service_worker_register_job.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_storage.h"
#include "content/common/service_worker/service_worker_utils.h"
#include "content/public/browser/browser_thread.h"
#include "ipc/ipc_message.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "url/gurl.h"

namespace content {
namespace {

void SuccessCollectorCallback(const base::Closure& done_closure,
                              bool* overall_success,
                              ServiceWorkerStatusCode status) {
  if (status != ServiceWorkerStatusCode::SERVICE_WORKER_OK) {
    *overall_success = false;
  }
  done_closure.Run();
}

void SuccessReportingCallback(
    const bool* success,
    const ServiceWorkerContextCore::UnregistrationCallback& callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  bool result = *success;
  callback.Run(result ? ServiceWorkerStatusCode::SERVICE_WORKER_OK
                      : ServiceWorkerStatusCode::SERVICE_WORKER_ERROR_FAILED);
}

bool IsSameOriginClientProviderHost(const GURL& origin,
                                    ServiceWorkerProviderHost* host) {
  return host->IsProviderForClient() &&
         host->document_url().GetOrigin() == origin;
}

bool IsSameOriginWindowProviderHost(const GURL& origin,
                                    ServiceWorkerProviderHost* host) {
  return host->provider_type() ==
             ServiceWorkerProviderType::SERVICE_WORKER_PROVIDER_FOR_WINDOW &&
         host->document_url().GetOrigin() == origin;
}

// Returns true if any of the frames specified by |frames| is a top-level frame.
// |frames| is a vector of (render process id, frame id) pairs.
bool FrameListContainsMainFrameOnUI(
    std::unique_ptr<std::vector<std::pair<int, int>>> frames) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);

  for (const auto& frame : *frames) {
    RenderFrameHostImpl* render_frame_host =
        RenderFrameHostImpl::FromID(frame.first, frame.second);
    if (!render_frame_host)
      continue;
    if (!render_frame_host->GetParent())
      return true;
  }
  return false;
}

class ClearAllServiceWorkersHelper
    : public base::RefCounted<ClearAllServiceWorkersHelper> {
 public:
  explicit ClearAllServiceWorkersHelper(const base::Closure& callback)
      : callback_(callback) {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
  }

  void OnResult(ServiceWorkerStatusCode) {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
    // We do nothing in this method. We use this class to wait for all callbacks
    // to be called using the refcount.
  }

  void DidGetAllRegistrations(
      const base::WeakPtr<ServiceWorkerContextCore>& context,
      ServiceWorkerStatusCode status,
      const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
    if (!context || status != SERVICE_WORKER_OK)
      return;
    // Make a copy of live versions map because StopWorker() removes the version
    // from it when we were starting up and don't have a process yet.
    const std::map<int64_t, ServiceWorkerVersion*> live_versions_copy =
        context->GetLiveVersions();
    for (const auto& version_itr : live_versions_copy) {
      ServiceWorkerVersion* version(version_itr.second);
      if (version->running_status() == ServiceWorkerVersion::STARTING ||
          version->running_status() == ServiceWorkerVersion::RUNNING) {
        version->StopWorker(
            base::Bind(&ClearAllServiceWorkersHelper::OnResult, this));
      }
    }
    for (const auto& registration_info : registrations) {
      context->UnregisterServiceWorker(
          registration_info.pattern,
          base::Bind(&ClearAllServiceWorkersHelper::OnResult, this));
    }
  }

 private:
  friend class base::RefCounted<ClearAllServiceWorkersHelper>;
  ~ClearAllServiceWorkersHelper() {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback_);
  }

  const base::Closure callback_;
  DISALLOW_COPY_AND_ASSIGN(ClearAllServiceWorkersHelper);
};

}  // namespace

const base::FilePath::CharType
    ServiceWorkerContextCore::kServiceWorkerDirectory[] =
        FILE_PATH_LITERAL("Service Worker");

ServiceWorkerContextCore::ProviderHostIterator::~ProviderHostIterator() {}

ServiceWorkerProviderHost*
ServiceWorkerContextCore::ProviderHostIterator::GetProviderHost() {
  DCHECK(!IsAtEnd());
  return provider_host_iterator_->GetCurrentValue();
}

void ServiceWorkerContextCore::ProviderHostIterator::Advance() {
  DCHECK(!IsAtEnd());
  DCHECK(!provider_host_iterator_->IsAtEnd());
  DCHECK(!process_iterator_->IsAtEnd());

  // Advance the inner iterator. If an element is reached, we're done.
  provider_host_iterator_->Advance();
  if (ForwardUntilMatchingProviderHost())
    return;

  // Advance the outer iterator until an element is reached, or end is hit.
  while (true) {
    process_iterator_->Advance();
    if (process_iterator_->IsAtEnd())
      return;
    ProviderMap* provider_map = process_iterator_->GetCurrentValue();
    provider_host_iterator_.reset(new ProviderMap::iterator(provider_map));
    if (ForwardUntilMatchingProviderHost())
      return;
  }
}

bool ServiceWorkerContextCore::ProviderHostIterator::IsAtEnd() {
  return process_iterator_->IsAtEnd() &&
         (!provider_host_iterator_ || provider_host_iterator_->IsAtEnd());
}

ServiceWorkerContextCore::ProviderHostIterator::ProviderHostIterator(
    ProcessToProviderMap* map,
    const ProviderHostPredicate& predicate)
    : map_(map), predicate_(predicate) {
  DCHECK(map);
  Initialize();
}

void ServiceWorkerContextCore::ProviderHostIterator::Initialize() {
  process_iterator_.reset(new ProcessToProviderMap::iterator(map_));
  // Advance to the first element.
  while (!process_iterator_->IsAtEnd()) {
    ProviderMap* provider_map = process_iterator_->GetCurrentValue();
    provider_host_iterator_.reset(new ProviderMap::iterator(provider_map));
    if (ForwardUntilMatchingProviderHost())
      return;
    process_iterator_->Advance();
  }
}

bool ServiceWorkerContextCore::ProviderHostIterator::
    ForwardUntilMatchingProviderHost() {
  while (!provider_host_iterator_->IsAtEnd()) {
    if (predicate_.is_null() || predicate_.Run(GetProviderHost()))
      return true;
    provider_host_iterator_->Advance();
  }
  return false;
}

ServiceWorkerContextCore::ServiceWorkerContextCore(
    const base::FilePath& path,
    std::unique_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager,
    const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
    storage::QuotaManagerProxy* quota_manager_proxy,
    storage::SpecialStoragePolicy* special_storage_policy,
    base::ObserverListThreadSafe<ServiceWorkerContextObserver>* observer_list,
    ServiceWorkerContextWrapper* wrapper)
    : wrapper_(wrapper),
      providers_(new ProcessToProviderMap),
      provider_by_uuid_(new ProviderByClientUUIDMap),
      force_update_on_page_load_(false),
      next_handle_id_(0),
      next_registration_handle_id_(0),
      was_service_worker_registered_(false),
      observer_list_(observer_list),
      weak_factory_(this) {
  // These get a WeakPtr from weak_factory_, so must be set after weak_factory_
  // is initialized.
  storage_ = ServiceWorkerStorage::Create(
      path, AsWeakPtr(), std::move(database_task_manager), disk_cache_thread,
      quota_manager_proxy, special_storage_policy);
  embedded_worker_registry_ = EmbeddedWorkerRegistry::Create(AsWeakPtr());
  job_coordinator_.reset(new ServiceWorkerJobCoordinator(AsWeakPtr()));
}

ServiceWorkerContextCore::ServiceWorkerContextCore(
    ServiceWorkerContextCore* old_context,
    ServiceWorkerContextWrapper* wrapper)
    : wrapper_(wrapper),
      providers_(old_context->providers_.release()),
      provider_by_uuid_(old_context->provider_by_uuid_.release()),
      next_handle_id_(old_context->next_handle_id_),
      next_registration_handle_id_(old_context->next_registration_handle_id_),
      was_service_worker_registered_(
          old_context->was_service_worker_registered_),
      observer_list_(old_context->observer_list_),
      weak_factory_(this) {
  // These get a WeakPtr from weak_factory_, so must be set after weak_factory_
  // is initialized.
  storage_ = ServiceWorkerStorage::Create(AsWeakPtr(), old_context->storage());
  embedded_worker_registry_ = EmbeddedWorkerRegistry::Create(
      AsWeakPtr(),
      old_context->embedded_worker_registry());
  job_coordinator_.reset(new ServiceWorkerJobCoordinator(AsWeakPtr()));
}

ServiceWorkerContextCore::~ServiceWorkerContextCore() {
  DCHECK(storage_);
  for (VersionMap::iterator it = live_versions_.begin();
       it != live_versions_.end();
       ++it) {
    it->second->RemoveListener(this);
  }
  weak_factory_.InvalidateWeakPtrs();
}

ServiceWorkerProviderHost* ServiceWorkerContextCore::GetProviderHost(
    int process_id, int provider_id) {
  ProviderMap* map = GetProviderMapForProcess(process_id);
  if (!map)
    return NULL;
  return map->Lookup(provider_id);
}

void ServiceWorkerContextCore::AddProviderHost(
    std::unique_ptr<ServiceWorkerProviderHost> host) {
  ServiceWorkerProviderHost* host_ptr = host.release();   // we take ownership
  ProviderMap* map = GetProviderMapForProcess(host_ptr->process_id());
  if (!map) {
    map = new ProviderMap;
    providers_->AddWithID(map, host_ptr->process_id());
  }
  map->AddWithID(host_ptr, host_ptr->provider_id());
}

void ServiceWorkerContextCore::RemoveProviderHost(
    int process_id, int provider_id) {
  ProviderMap* map = GetProviderMapForProcess(process_id);
  DCHECK(map);
  map->Remove(provider_id);
}

void ServiceWorkerContextCore::RemoveAllProviderHostsForProcess(
    int process_id) {
  if (providers_->Lookup(process_id))
    providers_->Remove(process_id);
}

std::unique_ptr<ServiceWorkerContextCore::ProviderHostIterator>
ServiceWorkerContextCore::GetProviderHostIterator() {
  return base::WrapUnique(new ProviderHostIterator(
      providers_.get(), ProviderHostIterator::ProviderHostPredicate()));
}

std::unique_ptr<ServiceWorkerContextCore::ProviderHostIterator>
ServiceWorkerContextCore::GetClientProviderHostIterator(const GURL& origin) {
  return base::WrapUnique(new ProviderHostIterator(
      providers_.get(), base::Bind(IsSameOriginClientProviderHost, origin)));
}

void ServiceWorkerContextCore::HasMainFrameProviderHost(
    const GURL& origin,
    const BoolCallback& callback) const {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  ProviderHostIterator provider_host_iterator(
      providers_.get(), base::Bind(IsSameOriginWindowProviderHost, origin));

  if (provider_host_iterator.IsAtEnd()) {
    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
                                                  base::Bind(callback, false));
    return;
  }

  std::unique_ptr<std::vector<std::pair<int, int>>> render_frames(
      new std::vector<std::pair<int, int>>());

  while (!provider_host_iterator.IsAtEnd()) {
    ServiceWorkerProviderHost* provider_host =
        provider_host_iterator.GetProviderHost();
    render_frames->push_back(
        std::make_pair(provider_host->process_id(), provider_host->frame_id()));
    provider_host_iterator.Advance();
  }

  BrowserThread::PostTaskAndReplyWithResult(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&FrameListContainsMainFrameOnUI,
                 base::Passed(std::move(render_frames))),
      callback);
}

void ServiceWorkerContextCore::RegisterProviderHostByClientID(
    const std::string& client_uuid,
    ServiceWorkerProviderHost* provider_host) {
  DCHECK(!ContainsKey(*provider_by_uuid_, client_uuid));
  (*provider_by_uuid_)[client_uuid] = provider_host;
}

void ServiceWorkerContextCore::UnregisterProviderHostByClientID(
    const std::string& client_uuid) {
  DCHECK(ContainsKey(*provider_by_uuid_, client_uuid));
  provider_by_uuid_->erase(client_uuid);
}

ServiceWorkerProviderHost* ServiceWorkerContextCore::GetProviderHostByClientID(
    const std::string& client_uuid) {
  auto found = provider_by_uuid_->find(client_uuid);
  if (found == provider_by_uuid_->end())
    return nullptr;
  return found->second;
}

void ServiceWorkerContextCore::RegisterServiceWorker(
    const GURL& pattern,
    const GURL& script_url,
    ServiceWorkerProviderHost* provider_host,
    const RegistrationCallback& callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  was_service_worker_registered_ = true;
  job_coordinator_->Register(
      pattern,
      script_url,
      provider_host,
      base::Bind(&ServiceWorkerContextCore::RegistrationComplete,
                 AsWeakPtr(),
                 pattern,
                 callback));
}

void ServiceWorkerContextCore::UpdateServiceWorker(
    ServiceWorkerRegistration* registration,
    bool force_bypass_cache) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  job_coordinator_->Update(registration, force_bypass_cache);
}

void ServiceWorkerContextCore::UpdateServiceWorker(
    ServiceWorkerRegistration* registration,
    bool force_bypass_cache,
    bool skip_script_comparison,
    ServiceWorkerProviderHost* provider_host,
    const UpdateCallback& callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  job_coordinator_->Update(registration, force_bypass_cache,
                           skip_script_comparison, provider_host,
                           base::Bind(&ServiceWorkerContextCore::UpdateComplete,
                                      AsWeakPtr(), callback));
}

void ServiceWorkerContextCore::UnregisterServiceWorker(
    const GURL& pattern,
    const UnregistrationCallback& callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  job_coordinator_->Unregister(
      pattern,
      base::Bind(&ServiceWorkerContextCore::UnregistrationComplete,
                 AsWeakPtr(),
                 pattern,
                 callback));
}

void ServiceWorkerContextCore::UnregisterServiceWorkers(
    const GURL& origin,
    const UnregistrationCallback& callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  storage()->GetAllRegistrationsInfos(base::Bind(
      &ServiceWorkerContextCore::DidGetAllRegistrationsForUnregisterForOrigin,
      AsWeakPtr(), callback, origin));
}

void ServiceWorkerContextCore::DidGetAllRegistrationsForUnregisterForOrigin(
    const UnregistrationCallback& result,
    const GURL& origin,
    ServiceWorkerStatusCode status,
    const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
  if (status != SERVICE_WORKER_OK) {
    result.Run(status);
    return;
  }
  std::set<GURL> scopes;
  for (const auto& registration_info : registrations) {
    if (origin == registration_info.pattern.GetOrigin()) {
      scopes.insert(registration_info.pattern);
    }
  }
  bool* overall_success = new bool(true);
  base::Closure barrier = base::BarrierClosure(
      scopes.size(),
      base::Bind(
          &SuccessReportingCallback, base::Owned(overall_success), result));

  for (const GURL& scope : scopes) {
    UnregisterServiceWorker(
        scope, base::Bind(&SuccessCollectorCallback, barrier, overall_success));
  }
}

void ServiceWorkerContextCore::RegistrationComplete(
    const GURL& pattern,
    const ServiceWorkerContextCore::RegistrationCallback& callback,
    ServiceWorkerStatusCode status,
    const std::string& status_message,
    ServiceWorkerRegistration* registration) {
  if (status != SERVICE_WORKER_OK) {
    DCHECK(!registration);
    callback.Run(status, status_message, kInvalidServiceWorkerRegistrationId);
    return;
  }

  DCHECK(registration);
  callback.Run(status, status_message, registration->id());
  // TODO(falken): At this point the registration promise is resolved, but we
  // haven't persisted anything to storage yet. So we should either call
  // OnRegistrationStored somewhere else or change its name.
  if (observer_list_.get()) {
    observer_list_->Notify(FROM_HERE,
                           &ServiceWorkerContextObserver::OnRegistrationStored,
                           registration->id(), pattern);
  }
}

void ServiceWorkerContextCore::UpdateComplete(
    const ServiceWorkerContextCore::UpdateCallback& callback,
    ServiceWorkerStatusCode status,
    const std::string& status_message,
    ServiceWorkerRegistration* registration) {
  if (status != SERVICE_WORKER_OK) {
    DCHECK(!registration);
    callback.Run(status, status_message, kInvalidServiceWorkerRegistrationId);
    return;
  }

  DCHECK(registration);
  callback.Run(status, status_message, registration->id());
}

void ServiceWorkerContextCore::UnregistrationComplete(
    const GURL& pattern,
    const ServiceWorkerContextCore::UnregistrationCallback& callback,
    int64_t registration_id,
    ServiceWorkerStatusCode status) {
  callback.Run(status);
  if (status == SERVICE_WORKER_OK && observer_list_.get()) {
    observer_list_->Notify(FROM_HERE,
                           &ServiceWorkerContextObserver::OnRegistrationDeleted,
                           registration_id, pattern);
  }
}

ServiceWorkerRegistration* ServiceWorkerContextCore::GetLiveRegistration(
    int64_t id) {
  RegistrationsMap::iterator it = live_registrations_.find(id);
  return (it != live_registrations_.end()) ? it->second : NULL;
}

void ServiceWorkerContextCore::AddLiveRegistration(
    ServiceWorkerRegistration* registration) {
  DCHECK(!GetLiveRegistration(registration->id()));
  live_registrations_[registration->id()] = registration;
  if (observer_list_.get()) {
    observer_list_->Notify(FROM_HERE,
                           &ServiceWorkerContextObserver::OnNewLiveRegistration,
                           registration->id(), registration->pattern());
  }
}

void ServiceWorkerContextCore::RemoveLiveRegistration(int64_t id) {
  live_registrations_.erase(id);
}

ServiceWorkerVersion* ServiceWorkerContextCore::GetLiveVersion(int64_t id) {
  VersionMap::iterator it = live_versions_.find(id);
  return (it != live_versions_.end()) ? it->second : NULL;
}

// PlzNavigate
void ServiceWorkerContextCore::AddNavigationHandleCore(
    int service_worker_provider_id,
    ServiceWorkerNavigationHandleCore* handle) {
  auto result = navigation_handle_cores_map_.insert(
      std::pair<int, ServiceWorkerNavigationHandleCore*>(
          service_worker_provider_id, handle));
  DCHECK(result.second)
      << "Inserting a duplicate ServiceWorkerNavigationHandleCore";
}

// PlzNavigate
void ServiceWorkerContextCore::RemoveNavigationHandleCore(
    int service_worker_provider_id) {
  navigation_handle_cores_map_.erase(service_worker_provider_id);
}

// PlzNavigate
ServiceWorkerNavigationHandleCore*
ServiceWorkerContextCore::GetNavigationHandleCore(
    int service_worker_provider_id) {
  auto result = navigation_handle_cores_map_.find(service_worker_provider_id);
  if (result == navigation_handle_cores_map_.end())
    return nullptr;
  return result->second;
}

void ServiceWorkerContextCore::AddLiveVersion(ServiceWorkerVersion* version) {
  // TODO(horo): If we will see crashes here, we have to find the root cause of
  // the version ID conflict. Otherwise change CHECK to DCHECK.
  CHECK(!GetLiveVersion(version->version_id()));
  live_versions_[version->version_id()] = version;
  version->AddListener(this);
  if (observer_list_.get()) {
    observer_list_->Notify(FROM_HERE,
                           &ServiceWorkerContextObserver::OnNewLiveVersion,
                           version->version_id(), version->registration_id(),
                           version->script_url());
  }
}

void ServiceWorkerContextCore::RemoveLiveVersion(int64_t id) {
  live_versions_.erase(id);
}

std::vector<ServiceWorkerRegistrationInfo>
ServiceWorkerContextCore::GetAllLiveRegistrationInfo() {
  std::vector<ServiceWorkerRegistrationInfo> infos;
  for (std::map<int64_t, ServiceWorkerRegistration*>::const_iterator iter =
           live_registrations_.begin();
       iter != live_registrations_.end(); ++iter) {
    infos.push_back(iter->second->GetInfo());
  }
  return infos;
}

std::vector<ServiceWorkerVersionInfo>
ServiceWorkerContextCore::GetAllLiveVersionInfo() {
  std::vector<ServiceWorkerVersionInfo> infos;
  for (std::map<int64_t, ServiceWorkerVersion*>::const_iterator iter =
           live_versions_.begin();
       iter != live_versions_.end(); ++iter) {
    infos.push_back(iter->second->GetInfo());
  }
  return infos;
}

void ServiceWorkerContextCore::ProtectVersion(
    const scoped_refptr<ServiceWorkerVersion>& version) {
  DCHECK(protected_versions_.find(version->version_id()) ==
         protected_versions_.end());
  protected_versions_[version->version_id()] = version;
}

void ServiceWorkerContextCore::UnprotectVersion(int64_t version_id) {
  DCHECK(protected_versions_.find(version_id) != protected_versions_.end());
  protected_versions_.erase(version_id);
}

int ServiceWorkerContextCore::GetNewServiceWorkerHandleId() {
  return next_handle_id_++;
}

int ServiceWorkerContextCore::GetNewRegistrationHandleId() {
  return next_registration_handle_id_++;
}

void ServiceWorkerContextCore::ScheduleDeleteAndStartOver() const {
  storage_->Disable();
  base::ThreadTaskRunnerHandle::Get()->PostTask(
      FROM_HERE,
      base::Bind(&ServiceWorkerContextWrapper::DeleteAndStartOver, wrapper_));
}

void ServiceWorkerContextCore::DeleteAndStartOver(
    const StatusCallback& callback) {
  job_coordinator_->AbortAll();
  storage_->DeleteAndStartOver(callback);
}

std::unique_ptr<ServiceWorkerProviderHost>
ServiceWorkerContextCore::TransferProviderHostOut(int process_id,
                                                  int provider_id) {
  ProviderMap* map = GetProviderMapForProcess(process_id);
  ServiceWorkerProviderHost* transferee = map->Lookup(provider_id);
  ServiceWorkerProviderHost* replacement =
      new ServiceWorkerProviderHost(process_id,
                                    transferee->frame_id(),
                                    provider_id,
                                    transferee->provider_type(),
                                    AsWeakPtr(),
                                    transferee->dispatcher_host());
  map->Replace(provider_id, replacement);
  transferee->PrepareForCrossSiteTransfer();
  return base::WrapUnique(transferee);
}

void ServiceWorkerContextCore::TransferProviderHostIn(
    int new_process_id,
    int new_provider_id,
    std::unique_ptr<ServiceWorkerProviderHost> transferee) {
  ProviderMap* map = GetProviderMapForProcess(new_process_id);
  ServiceWorkerProviderHost* temp = map->Lookup(new_provider_id);
  if (!temp)
    return;

  DCHECK(temp->document_url().is_empty());
  transferee->CompleteCrossSiteTransfer(new_process_id,
                                        temp->frame_id(),
                                        new_provider_id,
                                        temp->provider_type(),
                                        temp->dispatcher_host());
  map->Replace(new_provider_id, transferee.release());
  delete temp;
}

void ServiceWorkerContextCore::ClearAllServiceWorkersForTest(
    const base::Closure& callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  // |callback| will be called in the destructor of |helper| on the UI thread.
  scoped_refptr<ClearAllServiceWorkersHelper> helper(
      new ClearAllServiceWorkersHelper(callback));
  if (!was_service_worker_registered_)
    return;
  was_service_worker_registered_ = false;
  storage()->GetAllRegistrationsInfos(
      base::Bind(&ClearAllServiceWorkersHelper::DidGetAllRegistrations, helper,
                 AsWeakPtr()));
}

void ServiceWorkerContextCore::CheckHasServiceWorker(
    const GURL& url,
    const GURL& other_url,
    const ServiceWorkerContext::CheckHasServiceWorkerCallback callback) {
  storage()->FindRegistrationForDocument(
      url, base::Bind(&ServiceWorkerContextCore::
                          DidFindRegistrationForCheckHasServiceWorker,
                      AsWeakPtr(), other_url, callback));
}

void ServiceWorkerContextCore::UpdateVersionFailureCount(
    int64_t version_id,
    ServiceWorkerStatusCode status) {
  // Don't count these, they aren't start worker failures.
  if (status == SERVICE_WORKER_ERROR_DISALLOWED)
    return;

  auto it = failure_counts_.find(version_id);
  if (it != failure_counts_.end()) {
    ServiceWorkerMetrics::RecordStartStatusAfterFailure(it->second.count,
                                                        status);
  }

  if (status == SERVICE_WORKER_OK) {
    if (it != failure_counts_.end())
      failure_counts_.erase(it);
    return;
  }

  if (it != failure_counts_.end()) {
    FailureInfo& info = it->second;
    DCHECK_GT(info.count, 0);
    if (info.count < std::numeric_limits<int>::max()) {
      ++info.count;
      info.last_failure = status;
    }
  } else {
    FailureInfo info;
    info.count = 1;
    info.last_failure = status;
    failure_counts_[version_id] = info;
  }
}

int ServiceWorkerContextCore::GetVersionFailureCount(int64_t version_id) {
  auto it = failure_counts_.find(version_id);
  if (it == failure_counts_.end())
    return 0;
  return it->second.count;
}

void ServiceWorkerContextCore::OnRunningStateChanged(
    ServiceWorkerVersion* version) {
  if (!observer_list_)
    return;
  observer_list_->Notify(FROM_HERE,
                         &ServiceWorkerContextObserver::OnRunningStateChanged,
                         version->version_id(), version->running_status());
}

void ServiceWorkerContextCore::OnVersionStateChanged(
    ServiceWorkerVersion* version) {
  if (!observer_list_)
    return;
  observer_list_->Notify(FROM_HERE,
                         &ServiceWorkerContextObserver::OnVersionStateChanged,
                         version->version_id(), version->status());
}

void ServiceWorkerContextCore::OnMainScriptHttpResponseInfoSet(
    ServiceWorkerVersion* version) {
  if (!observer_list_)
    return;
  const net::HttpResponseInfo* info = version->GetMainScriptHttpResponseInfo();
  DCHECK(info);
  base::Time lastModified;
  if (info->headers)
    info->headers->GetLastModifiedValue(&lastModified);
  observer_list_->Notify(
      FROM_HERE, &ServiceWorkerContextObserver::OnMainScriptHttpResponseInfoSet,
      version->version_id(), info->response_time, lastModified);
}

void ServiceWorkerContextCore::OnErrorReported(
    ServiceWorkerVersion* version,
    const base::string16& error_message,
    int line_number,
    int column_number,
    const GURL& source_url) {
  if (!observer_list_)
    return;
  observer_list_->Notify(
      FROM_HERE, &ServiceWorkerContextObserver::OnErrorReported,
      version->version_id(), version->embedded_worker()->process_id(),
      version->embedded_worker()->thread_id(),
      ServiceWorkerContextObserver::ErrorInfo(error_message, line_number,
                                              column_number, source_url));
}

void ServiceWorkerContextCore::OnReportConsoleMessage(
    ServiceWorkerVersion* version,
    int source_identifier,
    int message_level,
    const base::string16& message,
    int line_number,
    const GURL& source_url) {
  if (!observer_list_)
    return;
  observer_list_->Notify(
      FROM_HERE, &ServiceWorkerContextObserver::OnReportConsoleMessage,
      version->version_id(), version->embedded_worker()->process_id(),
      version->embedded_worker()->thread_id(),
      ServiceWorkerContextObserver::ConsoleMessage(
          source_identifier, message_level, message, line_number, source_url));
}

void ServiceWorkerContextCore::OnControlleeAdded(
    ServiceWorkerVersion* version,
    ServiceWorkerProviderHost* provider_host) {
  if (!observer_list_)
    return;
  observer_list_->Notify(FROM_HERE,
                         &ServiceWorkerContextObserver::OnControlleeAdded,
                         version->version_id(), provider_host->client_uuid(),
                         provider_host->process_id(), provider_host->route_id(),
                         provider_host->provider_type());
}

void ServiceWorkerContextCore::OnControlleeRemoved(
    ServiceWorkerVersion* version,
    ServiceWorkerProviderHost* provider_host) {
  if (!observer_list_)
    return;
  observer_list_->Notify(FROM_HERE,
                         &ServiceWorkerContextObserver::OnControlleeRemoved,
                         version->version_id(), provider_host->client_uuid());
}

ServiceWorkerProcessManager* ServiceWorkerContextCore::process_manager() {
  return wrapper_->process_manager();
}

void ServiceWorkerContextCore::DidFindRegistrationForCheckHasServiceWorker(
    const GURL& other_url,
    const ServiceWorkerContext::CheckHasServiceWorkerCallback callback,
    ServiceWorkerStatusCode status,
    const scoped_refptr<ServiceWorkerRegistration>& registration) {
  if (status != SERVICE_WORKER_OK) {
    callback.Run(false);
    return;
  }

  if (!ServiceWorkerUtils::ScopeMatches(registration->pattern(), other_url)) {
    callback.Run(false);
    return;
  }

  if (registration->is_uninstalling() || registration->is_uninstalled()) {
    callback.Run(false);
    return;
  }

  if (!registration->active_version() && !registration->waiting_version()) {
    registration->RegisterRegistrationFinishedCallback(
        base::Bind(&ServiceWorkerContextCore::
                       OnRegistrationFinishedForCheckHasServiceWorker,
                   AsWeakPtr(), callback, registration));
    return;
  }

  callback.Run(true);
}

void ServiceWorkerContextCore::OnRegistrationFinishedForCheckHasServiceWorker(
    const ServiceWorkerContext::CheckHasServiceWorkerCallback callback,
    const scoped_refptr<ServiceWorkerRegistration>& registration) {
  callback.Run(registration->active_version() ||
               registration->waiting_version());
}

}  // namespace content
