blob: 802d5c476de9b0defae71d7e921e6ea8c3600bc5 [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_WORKER_HOST_SHARED_WORKER_HOST_H_
#define CONTENT_BROWSER_WORKER_HOST_SHARED_WORKER_HOST_H_
#include <list>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/supports_user_data.h"
#include "base/unguessable_token.h"
#include "content/browser/browser_interface_broker_impl.h"
#include "content/browser/buckets/bucket_context.h"
#include "content/browser/renderer_host/code_cache_host_impl.h"
#include "content/browser/renderer_host/policy_container_host.h"
#include "content/common/content_export.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_process_host_observer.h"
#include "content/public/browser/shared_worker_instance.h"
#include "media/mojo/mojom/video_decode_perf_history.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/unique_receiver_set.h"
#include "net/base/network_isolation_key.h"
#include "services/device/public/cpp/compute_pressure/buildflags.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/cpp/cross_origin_embedder_policy.h"
#include "services/network/public/mojom/url_loader_factory.mojom-forward.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/blob/blob_url_store.mojom-forward.h"
#include "third_party/blink/public/mojom/broadcastchannel/broadcast_channel.mojom.h"
#include "third_party/blink/public/mojom/buckets/bucket_manager_host.mojom.h"
#include "third_party/blink/public/mojom/devtools/devtools_agent.mojom.h"
#include "third_party/blink/public/mojom/loader/code_cache.mojom.h"
#include "third_party/blink/public/mojom/loader/fetch_client_settings_object.mojom-forward.h"
#include "third_party/blink/public/mojom/payments/payment_app.mojom-forward.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_provider.mojom.h"
#include "third_party/blink/public/mojom/webtransport/web_transport_connector.mojom.h"
#include "third_party/blink/public/mojom/worker/shared_worker.mojom.h"
#include "third_party/blink/public/mojom/worker/shared_worker_client.mojom.h"
#include "third_party/blink/public/mojom/worker/shared_worker_factory.mojom.h"
#include "third_party/blink/public/mojom/worker/shared_worker_host.mojom.h"
#include "third_party/blink/public/mojom/worker/worker_main_script_load_params.mojom.h"
#if BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
#include "content/browser/compute_pressure/pressure_service_for_shared_worker.h"
#include "third_party/blink/public/mojom/compute_pressure/web_pressure_manager.mojom.h"
#endif // BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
class GURL;
namespace blink {
class MessagePortChannel;
class StorageKey;
} // namespace blink
namespace content {
class ContentBrowserClient;
class CrossOriginEmbedderPolicyReporter;
class ServiceWorkerMainResourceHandle;
class SharedWorkerContentSettingsProxyImpl;
class SharedWorkerServiceImpl;
class SiteInstanceImpl;
struct WorkerScriptFetcherResult;
// SharedWorkerHost is the browser-side host of a single shared worker running
// in the renderer. This class is owned by the SharedWorkerServiceImpl of the
// current BrowserContext.
class CONTENT_EXPORT SharedWorkerHost : public blink::mojom::SharedWorkerHost,
public RenderProcessHostObserver,
public BucketContext,
public base::SupportsUserData {
public:
SharedWorkerHost(
SharedWorkerServiceImpl* service,
const SharedWorkerInstance& instance,
scoped_refptr<SiteInstanceImpl> site_instance,
std::vector<network::mojom::ContentSecurityPolicyPtr>
content_security_policies,
scoped_refptr<PolicyContainerHost> creator_policy_container_host);
SharedWorkerHost(const SharedWorkerHost&) = delete;
SharedWorkerHost& operator=(const SharedWorkerHost&) = delete;
~SharedWorkerHost() override;
// Returns the RenderProcessHost where this shared worker lives.
// SharedWorkerHost can't outlive the RenderProcessHost so this can't be null.
RenderProcessHost* GetProcessHost() const;
// Starts the SharedWorker in the renderer process.
//
// |outside_fetch_client_settings_object| is used for loading the shared
// worker main script by the browser process, sent to the renderer process,
// and then used to load the script.
//
// |client| is used to determine the IP address space of the worker if the
// script is fetched from a URL with a special scheme known only to the
// embedder.
//
// `result` contains the worker main script fetch result.
void Start(mojo::PendingRemote<blink::mojom::SharedWorkerFactory> factory,
blink::mojom::FetchClientSettingsObjectPtr
outside_fetch_client_settings_object,
ContentBrowserClient* client,
WorkerScriptFetcherResult result);
void AllowFileSystem(const GURL& url,
base::OnceCallback<void(bool)> callback);
void AllowIndexedDB(const GURL& url, base::OnceCallback<void(bool)> callback);
void AllowCacheStorage(const GURL& url,
base::OnceCallback<void(bool)> callback);
void AllowWebLocks(const GURL& url, base::OnceCallback<void(bool)> callback);
void CreateWebTransportConnector(
mojo::PendingReceiver<blink::mojom::WebTransportConnector> receiver);
void BindCacheStorage(
mojo::PendingReceiver<blink::mojom::CacheStorage> receiver);
void CreateBroadcastChannelProvider(
mojo::PendingReceiver<blink::mojom::BroadcastChannelProvider> receiver);
void CreateBlobUrlStoreProvider(
mojo::PendingReceiver<blink::mojom::BlobURLStore> receiver);
void CreateBucketManagerHost(
mojo::PendingReceiver<blink::mojom::BucketManagerHost> receiver);
#if BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
void BindPressureService(
mojo::PendingReceiver<blink::mojom::WebPressureManager> receiver);
#endif // BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
// Causes this instance to be deleted, which will terminate the worker. May
// be done based on a UI action.
void Destruct();
void AddClient(mojo::PendingRemote<blink::mojom::SharedWorkerClient> client,
GlobalRenderFrameHostId client_render_frame_host_id,
const blink::MessagePortChannel& port,
ukm::SourceId client_ukm_source_id);
void SetServiceWorkerHandle(
std::unique_ptr<ServiceWorkerMainResourceHandle> service_worker_handle);
// Removes all clients whose RenderFrameHost has been destroyed before the
// shared worker was started.
void PruneNonExistentClients();
// Returns true if this worker is connected to at least one client.
bool HasClients() const;
// Returns the frame ids of this worker's clients.
std::vector<GlobalRenderFrameHostId> GetRenderFrameIDsForWorker();
SiteInstanceImpl* site_instance() { return site_instance_.get(); }
bool started() const { return started_; }
const GURL& final_response_url() const { return final_response_url_; }
const blink::SharedWorkerToken& token() const { return token_; }
const SharedWorkerInstance& instance() const { return instance_; }
const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy()
const {
return worker_client_security_state_->cross_origin_embedder_policy;
}
const network::mojom::ClientSecurityStatePtr& client_security_state() const {
return worker_client_security_state_;
}
const std::vector<network::mojom::ContentSecurityPolicyPtr>&
content_security_policies() const {
return content_security_policies_;
}
#if BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
PressureServiceForSharedWorker* pressure_service() {
return pressure_service_.get();
}
#endif // BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
// Exposed so that tests can swap the implementation and intercept calls.
mojo::Receiver<blink::mojom::BrowserInterfaceBroker>&
browser_interface_broker_receiver_for_testing() {
return broker_receiver_;
}
ukm::SourceId ukm_source_id() const { return ukm_source_id_; }
const base::UnguessableToken& GetDevToolsToken() const;
// Signals the remote worker to terminate and returns the mojo::Remote
// instance so the caller can be notified when the connection is lost. Should
// be called right before deleting this instance.
mojo::Remote<blink::mojom::SharedWorker> TerminateRemoteWorkerForTesting();
base::WeakPtr<SharedWorkerHost> AsWeakPtr();
net::NetworkIsolationKey GetNetworkIsolationKey() const;
net::NetworkAnonymizationKey GetNetworkAnonymizationKey() const;
const blink::StorageKey& GetStorageKey() const;
const base::UnguessableToken& GetReportingSource() const {
return reporting_source_;
}
void ReportNoBinderForInterface(const std::string& error);
void CreateCodeCacheHost(
mojo::PendingReceiver<blink::mojom::CodeCacheHost> receiver);
// Creates a network factory params for subresource requests from this worker.
network::mojom::URLLoaderFactoryParamsPtr
CreateNetworkFactoryParamsForSubresources();
// BucketContext:
blink::StorageKey GetBucketStorageKey() override;
blink::mojom::PermissionStatus GetPermissionStatus(
blink::PermissionType permission_type) override;
void BindCacheStorageForBucket(
const storage::BucketInfo& bucket,
mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) override;
void GetSandboxedFileSystemForBucket(
const storage::BucketInfo& bucket,
const std::vector<std::string>& directory_path_components,
blink::mojom::BucketHost::GetDirectoryCallback callback) override;
storage::BucketClientInfo GetBucketClientInfo() const override;
private:
friend class SharedWorkerHostTest;
class ScopedDevToolsHandle;
class ScopedProcessHostRef;
// Contains information about a client connecting to this shared worker.
struct ClientInfo {
ClientInfo(mojo::Remote<blink::mojom::SharedWorkerClient> client,
int connection_request_id,
GlobalRenderFrameHostId render_frame_host_id);
~ClientInfo();
mojo::Remote<blink::mojom::SharedWorkerClient> client;
const int connection_request_id;
const GlobalRenderFrameHostId render_frame_host_id;
};
using ClientList = std::list<ClientInfo>;
// Returns true if the COEP policy of the worker and the creator are
// compatible.
bool CheckCrossOriginEmbedderPolicy(
network::CrossOriginEmbedderPolicy creator_cross_origin_embedder_policy,
network::CrossOriginEmbedderPolicy worker_cross_origin_embedder_policy);
// blink::mojom::SharedWorkerHost methods:
void OnConnected(int connection_request_id) override;
void OnContextClosed() override;
void OnReadyForInspection(
mojo::PendingRemote<blink::mojom::DevToolsAgent>,
mojo::PendingReceiver<blink::mojom::DevToolsAgentHost>) override;
void OnScriptLoadFailed(const std::string& error_message) override;
void OnFeatureUsed(blink::mojom::WebFeature feature) override;
// RenderProcessHostObserver methods:
void RenderProcessHostDestroyed(RenderProcessHost* host) override;
void AllowFileSystemResponse(base::OnceCallback<void(bool)> callback,
bool allowed);
void OnClientConnectionLost();
void OnWorkerConnectionLost();
void BindCacheStorageInternal(
mojo::PendingReceiver<blink::mojom::CacheStorage> receiver,
const storage::BucketLocator& bucket_locator);
// Creates a network factory for subresource requests from this worker. The
// network factory is meant to be passed to the renderer.
mojo::PendingRemote<network::mojom::URLLoaderFactory>
CreateNetworkFactoryForSubresources(bool* bypass_redirect_checks);
mojo::Receiver<blink::mojom::SharedWorkerHost> receiver_{this};
// |service_| owns |this|.
const raw_ptr<SharedWorkerServiceImpl> service_;
// An identifier for this worker that is unique across all workers. This is
// generated by this object in the browser process.
const blink::SharedWorkerToken token_;
// This holds information used to match a shared worker connection request to
// this shared worker.
SharedWorkerInstance instance_;
ClientList clients_;
std::vector<network::mojom::ContentSecurityPolicyPtr>
content_security_policies_;
mojo::PendingReceiver<blink::mojom::SharedWorker> worker_receiver_;
mojo::Remote<blink::mojom::SharedWorker> worker_;
// A SiteInstance whose process the shared worker runs in.
const scoped_refptr<SiteInstanceImpl> site_instance_;
// Keep alive the renderer process that will be hosting the shared worker.
std::unique_ptr<ScopedProcessHostRef> scoped_process_host_ref_;
int next_connection_request_id_;
std::unique_ptr<ScopedDevToolsHandle> devtools_handle_;
// This is the set of features that this worker has used.
std::set<blink::mojom::WebFeature> used_features_;
std::unique_ptr<SharedWorkerContentSettingsProxyImpl> content_settings_;
#if BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
std::unique_ptr<PressureServiceForSharedWorker> pressure_service_;
#endif // BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
// This is kept alive during the lifetime of the shared worker, since it's
// associated with Mojo interfaces (ServiceWorkerContainer and
// URLLoaderFactory) that are needed to stay alive while the worker is
// starting or running.
mojo::Remote<blink::mojom::SharedWorkerFactory> factory_;
BrowserInterfaceBrokerImpl<SharedWorkerHost, const url::Origin&> broker_{
this};
mojo::Receiver<blink::mojom::BrowserInterfaceBroker> broker_receiver_{
&broker_};
std::unique_ptr<ServiceWorkerMainResourceHandle> service_worker_handle_;
// CodeCacheHost processes requests to fetch / write generated code for
// JavaScript / WebAssembly resources.
CodeCacheHostImpl::ReceiverSet code_cache_host_receivers_;
// Indicates if Start() was invoked on this instance.
bool started_ = false;
GURL final_response_url_;
const ukm::SourceId ukm_source_id_;
const base::UnguessableToken reporting_source_;
// Set at construction time and should not change afterwards.
const scoped_refptr<PolicyContainerHost> creator_policy_container_host_;
// The worker's own client security state, applied to subresource fetches.
// This is nullptr until it is computed in `DidStartScriptLoad()`.
network::mojom::ClientSecurityStatePtr worker_client_security_state_;
std::unique_ptr<CrossOriginEmbedderPolicyReporter> coep_reporter_;
base::WeakPtrFactory<SharedWorkerHost> weak_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_WORKER_HOST_SHARED_WORKER_HOST_H_