blob: 037b04bd12915bf97fe3e857d7abe8c25ca7c9aa [file] [log] [blame]
// 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.
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_CORE_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_CORE_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/id_map.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list_threadsafe.h"
#include "content/browser/service_worker/service_worker_info.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_registration_status.h"
#include "content/browser/service_worker/service_worker_storage.h"
#include "content/common/content_export.h"
#include "content/common/worker_url_loader_factory_provider.mojom.h"
#include "content/public/browser/service_worker_context.h"
class GURL;
namespace base {
class FilePath;
class SingleThreadTaskRunner;
}
namespace storage {
class BlobStorageContext;
class QuotaManagerProxy;
class SpecialStoragePolicy;
}
namespace content {
class EmbeddedWorkerRegistry;
class ServiceWorkerContextCoreObserver;
class ServiceWorkerContextWrapper;
class ServiceWorkerDatabaseTaskManager;
class ServiceWorkerDispatcherHost;
class ServiceWorkerJobCoordinator;
class ServiceWorkerNavigationHandleCore;
class ServiceWorkerProviderHost;
class ServiceWorkerRegistration;
class ServiceWorkerStorage;
class URLLoaderFactoryGetter;
// This class manages data associated with service workers.
// The class is single threaded and should only be used on the IO thread.
// In chromium, there is one instance per storagepartition. This class
// is the root of the containment hierarchy for service worker data
// associated with a particular partition.
class CONTENT_EXPORT ServiceWorkerContextCore
: NON_EXPORTED_BASE(public ServiceWorkerVersion::Listener) {
public:
using BoolCallback = base::Callback<void(bool)>;
using StatusCallback = base::Callback<void(ServiceWorkerStatusCode status)>;
using RegistrationCallback =
base::Callback<void(ServiceWorkerStatusCode status,
const std::string& status_message,
int64_t registration_id)>;
using UpdateCallback = base::Callback<void(ServiceWorkerStatusCode status,
const std::string& status_message,
int64_t registration_id)>;
using UnregistrationCallback =
base::Callback<void(ServiceWorkerStatusCode status)>;
using ProviderMap = IDMap<std::unique_ptr<ServiceWorkerProviderHost>>;
using ProcessToProviderMap = IDMap<std::unique_ptr<ProviderMap>>;
using ProviderByClientUUIDMap =
std::map<std::string, ServiceWorkerProviderHost*>;
// Directory for ServiceWorkerStorage and ServiceWorkerCacheManager.
static const base::FilePath::CharType kServiceWorkerDirectory[];
// Iterates over ServiceWorkerProviderHost objects in a ProcessToProviderMap.
class CONTENT_EXPORT ProviderHostIterator {
public:
~ProviderHostIterator();
ServiceWorkerProviderHost* GetProviderHost();
void Advance();
bool IsAtEnd();
private:
friend class ServiceWorkerContextCore;
using ProviderHostPredicate =
base::Callback<bool(ServiceWorkerProviderHost*)>;
ProviderHostIterator(ProcessToProviderMap* map,
const ProviderHostPredicate& predicate);
void Initialize();
bool ForwardUntilMatchingProviderHost();
ProcessToProviderMap* map_;
ProviderHostPredicate predicate_;
std::unique_ptr<ProcessToProviderMap::iterator> process_iterator_;
std::unique_ptr<ProviderMap::iterator> provider_host_iterator_;
DISALLOW_COPY_AND_ASSIGN(ProviderHostIterator);
};
// This is owned by the StoragePartition, which will supply it with
// the local path on disk. Given an empty |user_data_directory|,
// nothing will be stored on disk. |observer_list| is created in
// ServiceWorkerContextWrapper. When Notify() of |observer_list| is called in
// ServiceWorkerContextCore, the methods of ServiceWorkerContextCoreObserver
// will be called on the thread which called AddObserver() of |observer_list|.
// |blob_context| and |url_loader_factory_getter| are used only
// when IsServicificationEnabled is true.
ServiceWorkerContextCore(
const base::FilePath& user_data_directory,
std::unique_ptr<ServiceWorkerDatabaseTaskManager>
database_task_runner_manager,
const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
storage::QuotaManagerProxy* quota_manager_proxy,
storage::SpecialStoragePolicy* special_storage_policy,
base::WeakPtr<storage::BlobStorageContext> blob_context,
URLLoaderFactoryGetter* url_loader_factory_getter,
base::ObserverListThreadSafe<ServiceWorkerContextCoreObserver>*
observer_list,
ServiceWorkerContextWrapper* wrapper);
ServiceWorkerContextCore(
ServiceWorkerContextCore* old_context,
ServiceWorkerContextWrapper* wrapper);
~ServiceWorkerContextCore() override;
void OnStorageWiped();
// ServiceWorkerVersion::Listener overrides.
void OnRunningStateChanged(ServiceWorkerVersion* version) override;
void OnVersionStateChanged(ServiceWorkerVersion* version) override;
void OnDevToolsRoutingIdChanged(ServiceWorkerVersion* version) override;
void OnMainScriptHttpResponseInfoSet(ServiceWorkerVersion* version) override;
void OnErrorReported(ServiceWorkerVersion* version,
const base::string16& error_message,
int line_number,
int column_number,
const GURL& source_url) override;
void OnReportConsoleMessage(ServiceWorkerVersion* version,
int source_identifier,
int message_level,
const base::string16& message,
int line_number,
const GURL& source_url) override;
void OnControlleeAdded(ServiceWorkerVersion* version,
ServiceWorkerProviderHost* provider_host) override;
void OnControlleeRemoved(ServiceWorkerVersion* version,
ServiceWorkerProviderHost* provider_host) override;
ServiceWorkerContextWrapper* wrapper() const { return wrapper_; }
ServiceWorkerStorage* storage() { return storage_.get(); }
ServiceWorkerProcessManager* process_manager();
EmbeddedWorkerRegistry* embedded_worker_registry() {
return embedded_worker_registry_.get();
}
ServiceWorkerJobCoordinator* job_coordinator() {
return job_coordinator_.get();
}
// Maintains DispatcherHosts to exchange service worker related messages
// through them. The DispatcherHosts are not owned by this class.
void AddDispatcherHost(int process_id,
ServiceWorkerDispatcherHost* dispatcher_host);
ServiceWorkerDispatcherHost* GetDispatcherHost(int process_id);
void RemoveDispatcherHost(int process_id);
// The context class owns the set of ProviderHosts.
void AddProviderHost(
std::unique_ptr<ServiceWorkerProviderHost> provider_host);
ServiceWorkerProviderHost* GetProviderHost(int process_id, int provider_id);
void RemoveProviderHost(int process_id, int provider_id);
void RemoveAllProviderHostsForProcess(int process_id);
std::unique_ptr<ProviderHostIterator> GetProviderHostIterator();
// Returns a ProviderHost iterator for all ServiceWorker clients for
// the |origin|. This only returns ProviderHosts that are of CONTROLLEE
// and belong to the |origin|.
std::unique_ptr<ProviderHostIterator> GetClientProviderHostIterator(
const GURL& origin);
// Runs the callback with true if there is a ProviderHost for |origin| of type
// SERVICE_WORKER_PROVIDER_FOR_WINDOW which is a main (top-level) frame.
void HasMainFrameProviderHost(const GURL& origin,
const BoolCallback& callback) const;
// Maintains a map from Client UUID to ProviderHost.
// (Note: instead of maintaining 2 maps we might be able to uniformly use
// UUID instead of process_id+provider_id elsewhere. For now I'm leaving
// these as provider_id is deeply wired everywhere)
void RegisterProviderHostByClientID(const std::string& client_uuid,
ServiceWorkerProviderHost* provider_host);
void UnregisterProviderHostByClientID(const std::string& client_uuid);
ServiceWorkerProviderHost* GetProviderHostByClientID(
const std::string& client_uuid);
// Non-null |provider_host| must be given if this is called from a document.
void RegisterServiceWorker(const GURL& script_url,
const ServiceWorkerRegistrationOptions& options,
ServiceWorkerProviderHost* provider_host,
const RegistrationCallback& callback);
void UnregisterServiceWorker(const GURL& pattern,
const UnregistrationCallback& callback);
// Callback is called issued after all unregistrations occur. The Status
// is populated as SERVICE_WORKER_OK if all succeed, or SERVICE_WORKER_FAILED
// if any did not succeed.
void UnregisterServiceWorkers(const GURL& origin,
const UnregistrationCallback& callback);
// Updates the service worker. If |force_bypass_cache| is true or 24 hours
// have passed since the last update, bypasses the browser cache.
void UpdateServiceWorker(ServiceWorkerRegistration* registration,
bool force_bypass_cache);
void UpdateServiceWorker(ServiceWorkerRegistration* registration,
bool force_bypass_cache,
bool skip_script_comparison,
ServiceWorkerProviderHost* provider_host,
const UpdateCallback& callback);
// Used in DevTools to update the service worker registrations without
// consulting the browser cache while loading the controlled page. The
// loading is delayed until the update completes and the new worker is
// activated. The new worker skips the waiting state and immediately
// becomes active after installed.
bool force_update_on_page_load() { return force_update_on_page_load_; }
void set_force_update_on_page_load(bool force_update_on_page_load) {
force_update_on_page_load_ = force_update_on_page_load;
}
// This class maintains collections of live instances, this class
// does not own these object or influence their lifetime.
ServiceWorkerRegistration* GetLiveRegistration(int64_t registration_id);
void AddLiveRegistration(ServiceWorkerRegistration* registration);
void RemoveLiveRegistration(int64_t registration_id);
const std::map<int64_t, ServiceWorkerRegistration*>& GetLiveRegistrations()
const {
return live_registrations_;
}
ServiceWorkerVersion* GetLiveVersion(int64_t version_id);
void AddLiveVersion(ServiceWorkerVersion* version);
void RemoveLiveVersion(int64_t registration_id);
const std::map<int64_t, ServiceWorkerVersion*>& GetLiveVersions() const {
return live_versions_;
}
// PlzNavigate
// Methods to manage the map keeping track of all
// ServiceWorkerNavigationHandleCores registered for ongoing navigations.
void AddNavigationHandleCore(int service_worker_provider_id,
ServiceWorkerNavigationHandleCore* handle);
void RemoveNavigationHandleCore(int service_worker_provider_id);
ServiceWorkerNavigationHandleCore* GetNavigationHandleCore(
int service_worker_provider_id);
std::vector<ServiceWorkerRegistrationInfo> GetAllLiveRegistrationInfo();
std::vector<ServiceWorkerVersionInfo> GetAllLiveVersionInfo();
// ProtectVersion holds a reference to |version| until UnprotectVersion is
// called.
void ProtectVersion(const scoped_refptr<ServiceWorkerVersion>& version);
void UnprotectVersion(int64_t version_id);
// Returns new context-local unique ID.
int GetNewServiceWorkerHandleId();
int GetNewRegistrationHandleId();
void ScheduleDeleteAndStartOver() const;
// Deletes all files on disk and restarts the system. This leaves the system
// in a disabled state until it's done.
void DeleteAndStartOver(const StatusCallback& callback);
// Methods to support cross site navigations.
std::unique_ptr<ServiceWorkerProviderHost> TransferProviderHostOut(
int process_id,
int provider_id);
void TransferProviderHostIn(
int new_process_id,
int new_host_id,
std::unique_ptr<ServiceWorkerProviderHost> provider_host);
void ClearAllServiceWorkersForTest(const base::Closure& callback);
// Determines if there is a ServiceWorker registration that matches |url|, and
// if |other_url| falls inside the scope of the same registration. See
// ServiceWorkerContext::CheckHasServiceWorker for more details.
void CheckHasServiceWorker(
const GURL& url,
const GURL& other_url,
const ServiceWorkerContext::CheckHasServiceWorkerCallback callback);
void UpdateVersionFailureCount(int64_t version_id,
ServiceWorkerStatusCode status);
// Returns the count of consecutive start worker failures for the given
// version. The count resets to zero when the worker successfully starts.
int GetVersionFailureCount(int64_t version_id);
// Binds the ServiceWorkerWorkerClient of a dedicated (or shared) worker to
// the parent frame's ServiceWorkerProviderHost. (This is used only when
// off-main-thread-fetch is enabled.)
void BindWorkerFetchContext(
int render_process_id,
int service_worker_provider_id,
mojom::ServiceWorkerWorkerClientAssociatedPtrInfo client_ptr_info);
base::WeakPtr<storage::BlobStorageContext> blob_storage_context() {
return blob_storage_context_;
}
URLLoaderFactoryGetter* loader_factory_getter() {
return loader_factory_getter_.get();
}
base::WeakPtr<ServiceWorkerContextCore> AsWeakPtr() {
return weak_factory_.GetWeakPtr();
}
private:
friend class ServiceWorkerContextCoreTest;
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextCoreTest, FailureInfo);
typedef std::map<int64_t, ServiceWorkerRegistration*> RegistrationsMap;
typedef std::map<int64_t, ServiceWorkerVersion*> VersionMap;
struct FailureInfo {
int count;
ServiceWorkerStatusCode last_failure;
};
ProviderMap* GetProviderMapForProcess(int process_id) {
return providers_->Lookup(process_id);
}
void RegistrationComplete(const GURL& pattern,
const RegistrationCallback& callback,
ServiceWorkerStatusCode status,
const std::string& status_message,
ServiceWorkerRegistration* registration);
void UpdateComplete(const UpdateCallback& callback,
ServiceWorkerStatusCode status,
const std::string& status_message,
ServiceWorkerRegistration* registration);
void UnregistrationComplete(const GURL& pattern,
const UnregistrationCallback& callback,
int64_t registration_id,
ServiceWorkerStatusCode status);
void DidGetAllRegistrationsForUnregisterForOrigin(
const UnregistrationCallback& result,
const GURL& origin,
ServiceWorkerStatusCode status,
const std::vector<ServiceWorkerRegistrationInfo>& registrations);
void DidFindRegistrationForCheckHasServiceWorker(
const GURL& other_url,
const ServiceWorkerContext::CheckHasServiceWorkerCallback callback,
ServiceWorkerStatusCode status,
scoped_refptr<ServiceWorkerRegistration> registration);
void OnRegistrationFinishedForCheckHasServiceWorker(
const ServiceWorkerContext::CheckHasServiceWorkerCallback callback,
scoped_refptr<ServiceWorkerRegistration> registration);
// It's safe to store a raw pointer instead of a scoped_refptr to |wrapper_|
// because the Wrapper::Shutdown call that hops threads to destroy |this| uses
// Bind() to hold a reference to |wrapper_| until |this| is fully destroyed.
ServiceWorkerContextWrapper* wrapper_;
std::map<int /* process_id */, ServiceWorkerDispatcherHost*>
dispatcher_hosts_;
std::unique_ptr<ProcessToProviderMap> providers_;
std::unique_ptr<ProviderByClientUUIDMap> provider_by_uuid_;
std::unique_ptr<ServiceWorkerStorage> storage_;
scoped_refptr<EmbeddedWorkerRegistry> embedded_worker_registry_;
std::unique_ptr<ServiceWorkerJobCoordinator> job_coordinator_;
std::map<int64_t, ServiceWorkerRegistration*> live_registrations_;
std::map<int64_t, ServiceWorkerVersion*> live_versions_;
std::map<int64_t, scoped_refptr<ServiceWorkerVersion>> protected_versions_;
std::map<int64_t /* version_id */, FailureInfo> failure_counts_;
// PlzNavigate
// Map of ServiceWorkerNavigationHandleCores used for navigation requests.
std::map<int, ServiceWorkerNavigationHandleCore*>
navigation_handle_cores_map_;
// IsServicificationEnabled
base::WeakPtr<storage::BlobStorageContext> blob_storage_context_;
scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter_;
bool force_update_on_page_load_;
int next_handle_id_;
int next_registration_handle_id_;
// Set in RegisterServiceWorker(), cleared in ClearAllServiceWorkersForTest().
// This is used to avoid unnecessary disk read operation in tests. This value
// is false if Chrome was relaunched after service workers were registered.
bool was_service_worker_registered_;
scoped_refptr<base::ObserverListThreadSafe<ServiceWorkerContextCoreObserver>>
observer_list_;
base::WeakPtrFactory<ServiceWorkerContextCore> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContextCore);
};
} // namespace content
#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_CORE_H_