| // 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_ |