blob: 1f5932c2374c68cce8d2e6f1fad0469bdcfc5f04 [file] [log] [blame]
// Copyright 2017 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_DEDICATED_WORKER_HOST_H_
#define CONTENT_BROWSER_WORKER_HOST_DEDICATED_WORKER_HOST_H_
#include <memory>
#include <optional>
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "base/supports_user_data.h"
#include "build/build_config.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/security/dip/document_isolation_policy_reporter.h"
#include "content/common/content_export.h"
#include "content/public/browser/dedicated_worker_creator.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 "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/isolation_info.h"
#include "net/storage_access_api/status.h"
#include "services/device/public/cpp/compute_pressure/buildflags.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
#include "services/network/public/mojom/client_security_state.mojom.h"
#include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
#include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
#include "third_party/blink/public/common/storage_key/storage_key.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/frame/back_forward_cache_controller.mojom.h"
#include "third_party/blink/public/mojom/idle/idle_manager.mojom-forward.h"
#include "third_party/blink/public/mojom/loader/code_cache.mojom.h"
#include "third_party/blink/public/mojom/loader/content_security_notifier.mojom.h"
#include "third_party/blink/public/mojom/serial/serial.mojom-forward.h"
#include "third_party/blink/public/mojom/usb/web_usb_service.mojom-forward.h"
#include "third_party/blink/public/mojom/wake_lock/wake_lock.mojom-forward.h"
#include "third_party/blink/public/mojom/websockets/websocket_connector.mojom-forward.h"
#include "third_party/blink/public/mojom/webtransport/web_transport_connector.mojom-forward.h"
#include "third_party/blink/public/mojom/worker/dedicated_worker_host.mojom.h"
#include "third_party/blink/public/mojom/worker/dedicated_worker_host_factory.mojom.h"
#include "third_party/blink/public/mojom/worker/subresource_loader_updater.mojom.h"
#include "url/origin.h"
#if !BUILDFLAG(IS_ANDROID)
#include "third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom-forward.h"
#include "third_party/blink/public/mojom/hid/hid.mojom-forward.h"
#endif
#if BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
#include "content/browser/compute_pressure/pressure_service_for_dedicated_worker.h"
#include "third_party/blink/public/mojom/compute_pressure/web_pressure_manager.mojom.h"
#endif // BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
namespace network {
struct CrossOriginEmbedderPolicy;
} // namespace network
namespace content {
class CrossOriginEmbedderPolicyReporter;
class DedicatedWorkerServiceImpl;
class ServiceWorkerClient;
class ServiceWorkerMainResourceHandle;
class StoragePartitionImpl;
struct WorkerScriptFetcherResult;
// A host for a single dedicated worker. It deletes itself upon Mojo
// disconnection from the worker in the renderer or when the RenderProcessHost
// of the worker is destroyed. This lives on the UI thread.
// TODO(crbug.com/40807127): Align this class's lifetime with the associated
// frame.
class CONTENT_EXPORT DedicatedWorkerHost final
: public blink::mojom::DedicatedWorkerHost,
public blink::mojom::BackForwardCacheControllerHost,
public RenderProcessHostObserver,
public BucketContext,
public base::SupportsUserData {
public:
// Creates a new browser-side host for a single dedicated worker.
//
// See the class-level comment for lifetime considerations.
//
// - `service` must not be nullptr and must outlive this instance.
// - `worker_process_host` must not be nullptr and must outlive this instance.
// It must be initialized and not be dead - see
// `RenderProcessHost::IsInitializedAndNotDead()`.
// - Exactly one of `creator_render_frame_host_id` or `creator_worker_token`
// must be specified.
// - `creator_client_security_state` specifies the client security state of
// the creator frame or worker. It must not be nullptr.
DedicatedWorkerHost(
DedicatedWorkerServiceImpl* service,
const blink::DedicatedWorkerToken& token,
RenderProcessHost* worker_process_host,
DedicatedWorkerCreator creator,
GlobalRenderFrameHostId ancestor_render_frame_host_id,
const blink::StorageKey& creator_storage_key,
const url::Origin& renderer_origin,
const net::IsolationInfo& isolation_info,
network::mojom::ClientSecurityStatePtr creator_client_security_state,
base::WeakPtr<CrossOriginEmbedderPolicyReporter> creator_coep_reporter,
mojo::PendingReceiver<blink::mojom::DedicatedWorkerHost> host,
net::StorageAccessApiStatus storage_access_api_status);
DedicatedWorkerHost(const DedicatedWorkerHost&) = delete;
DedicatedWorkerHost& operator=(const DedicatedWorkerHost&) = delete;
~DedicatedWorkerHost() final;
void BindBrowserInterfaceBrokerReceiver(
mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker> receiver);
const blink::DedicatedWorkerToken& GetToken() const { return token_; }
RenderProcessHost* GetProcessHost() const { return worker_process_host_; }
const blink::StorageKey& GetStorageKey() const { return storage_key_; }
const GlobalRenderFrameHostId& GetAncestorRenderFrameHostId() const {
return ancestor_render_frame_host_id_;
}
DedicatedWorkerCreator GetCreator() const { return creator_; }
const std::optional<GURL>& GetFinalResponseURL() const {
return final_response_url_;
}
void CreateContentSecurityNotifier(
mojo::PendingReceiver<blink::mojom::ContentSecurityNotifier> receiver);
void CreateIdleManager(
mojo::PendingReceiver<blink::mojom::IdleManager> receiver);
void CreateNestedDedicatedWorker(
mojo::PendingReceiver<blink::mojom::DedicatedWorkerHostFactory> receiver);
#if !BUILDFLAG(IS_ANDROID)
void CreateDirectSocketsService(
mojo::PendingReceiver<blink::mojom::DirectSocketsService> receiver);
#endif
void CreateWebUsbService(
mojo::PendingReceiver<blink::mojom::WebUsbService> receiver);
void CreateWebSocketConnector(
mojo::PendingReceiver<blink::mojom::WebSocketConnector> receiver);
void CreateWebTransportConnector(
mojo::PendingReceiver<blink::mojom::WebTransportConnector> receiver);
void CreateWakeLockService(
mojo::PendingReceiver<blink::mojom::WakeLockService> receiver);
void BindCacheStorage(
mojo::PendingReceiver<blink::mojom::CacheStorage> receiver);
void BindCacheStorageInternal(
mojo::PendingReceiver<blink::mojom::CacheStorage> receiver,
const storage::BucketLocator& bucket_locator);
void CreateCodeCacheHost(
mojo::PendingReceiver<blink::mojom::CodeCacheHost> receiver);
void CreateBroadcastChannelProvider(
mojo::PendingReceiver<blink::mojom::BroadcastChannelProvider> receiver);
bool WasStorageAccessGranted();
void CreateBlobUrlStoreProvider(
mojo::PendingReceiver<blink::mojom::BlobURLStore> receiver);
void CreateBucketManagerHost(
mojo::PendingReceiver<blink::mojom::BucketManagerHost> receiver);
void GetFileSystemAccessManager(
mojo::PendingReceiver<blink::mojom::FileSystemAccessManager> receiver);
#if BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
void BindPressureService(
mojo::PendingReceiver<blink::mojom::WebPressureManager> receiver);
#endif // BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
void BindSerialService(
mojo::PendingReceiver<blink::mojom::SerialService> receiver);
#if !BUILDFLAG(IS_ANDROID)
void BindHidService(mojo::PendingReceiver<blink::mojom::HidService> receiver);
#endif
void StartScriptLoad(
const GURL& script_url,
network::mojom::CredentialsMode credentials_mode,
blink::mojom::FetchClientSettingsObjectPtr
outside_fetch_client_settings_object,
mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token,
mojo::Remote<blink::mojom::DedicatedWorkerHostFactoryClient> client,
net::StorageAccessApiStatus storage_access_api_status);
void ReportNoBinderForInterface(const std::string& error);
const net::NetworkIsolationKey& GetNetworkIsolationKey() const {
return isolation_info_.network_isolation_key();
}
const net::NetworkAnonymizationKey& GetNetworkAnonymizationKey() const {
return isolation_info_.network_anonymization_key();
}
const base::UnguessableToken& GetReportingSource() const {
return reporting_source_;
}
// Returns the client security state applied to subresource fetches.
// May return nullptr before the script is loaded.
const network::mojom::ClientSecurityState* client_security_state() const {
return worker_client_security_state_.get();
}
const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy()
const {
DCHECK(worker_client_security_state_);
return worker_client_security_state_->cross_origin_embedder_policy;
}
ServiceWorkerMainResourceHandle* service_worker_handle() {
return service_worker_handle_.get();
}
#if BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
PressureServiceForDedicatedWorker* 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_;
}
// blink::mojom::BackForwardCacheControllerHost:
void EvictFromBackForwardCache(
blink::mojom::RendererEvictionReason reason,
blink::mojom::ScriptSourceLocationPtr source) override;
using BackForwardCacheBlockingDetails =
std::vector<blink::mojom::BlockingDetailsPtr>;
void DidChangeBackForwardCacheDisablingFeatures(
BackForwardCacheBlockingDetails details) override;
// 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::FileSystemAccessManager::GetSandboxedFileSystemCallback
callback) override;
storage::BucketClientInfo GetBucketClientInfo() const override;
// Returns the features set that disable back-forward cache.
blink::scheduler::WebSchedulerTrackedFeatures
GetBackForwardCacheDisablingFeatures() const;
const BackForwardCacheBlockingDetails& GetBackForwardCacheBlockingDetails()
const;
// This is called when out-of-process Network Service crashes,
// or when DevTools updates its network interception.
void UpdateSubresourceLoaderFactories();
base::WeakPtr<ServiceWorkerClient> GetServiceWorkerClient();
mojo::PendingRemote<blink::mojom::BackForwardCacheControllerHost>
BindAndPassRemoteForBackForwardCacheControllerHost();
base::WeakPtr<DedicatedWorkerHost> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
private:
// RenderProcessHostObserver:
void RenderProcessExited(RenderProcessHost* render_process_host,
const ChildProcessTerminationInfo& info) override;
void InProcessRendererExiting(RenderProcessHost* host) override;
void RenderProcessHostDestroyed(RenderProcessHost* host) override;
// Called from `WorkerScriptFetcher`. Continues starting the dedicated worker
// in the renderer process.
void DidStartScriptLoad(std::optional<WorkerScriptFetcherResult> result);
void ScriptLoadStartFailed(const network::URLLoaderCompletionStatus& status);
// Sets up the observer of network service crash.
void ObserveNetworkServiceCrash(StoragePartitionImpl* storage_partition_impl);
// 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(
RenderFrameHostImpl* ancestor_render_frame_host,
bool* bypass_redirect_checks);
void OnNetworkServiceCrash();
void OnMojoDisconnect();
// Returns whether creator and worker's COEP values are compatible.
bool CheckCOEP();
base::WeakPtr<CrossOriginEmbedderPolicyReporter> GetWorkerCoepReporter();
// This outlives `this` as follows:
// - StoragePartitionImpl owns DedicatedWorkerServiceImpl until its dtor.
// - StoragePartitionImpl outlives RenderProcessHostImpl.
// - RenderProcessHostImpl outlives DedicatedWorkerHost.
// As the conclusion of the above, DedicatedWorkerServiceImpl outlives
// DedicatedWorkerHost.
const raw_ptr<DedicatedWorkerServiceImpl> service_;
// The renderer generated ID of this worker, unique across all processes.
const blink::DedicatedWorkerToken token_;
// The RenderProcessHost that hosts this worker. This outlives `this`.
const raw_ptr<RenderProcessHost> worker_process_host_;
base::ScopedObservation<RenderProcessHost, RenderProcessHostObserver>
scoped_process_host_observation_{this};
// The creator of this worker. Holds a GlobalRenderFrameHostId if this worker
// was created by a frame, or holds a blink::DedicatedWorkerToken if this
// worker is nested.
const DedicatedWorkerCreator creator_;
// The ID of the frame that owns this worker, either directly, or (in the case
// of nested workers) indirectly via a tree of dedicated workers.
const GlobalRenderFrameHostId ancestor_render_frame_host_id_;
// The origin of the frame or dedicated worker that starts this worker.
const url::Origin creator_origin_;
// The origin used by this dedicated worker on the renderer side. This will
// almost always be the same as `storage_key_`'s origin, except in the case of
// data: URL workers, as described in the linked bug.
// TODO(crbug.com/40051700): Make the storage key's origin always match this,
// so that we can stop tracking this separately.
const url::Origin renderer_origin_;
// The storage key of this worker. This is used for storage partitioning and
// for retrieving the origin of this worker
// (https://html.spec.whatwg.org/C/#concept-settings-object-origin).
const blink::StorageKey storage_key_;
// The IsolationInfo associated with this worker. Same as that of the
// frame or the worker that created this worker.
const net::IsolationInfo isolation_info_;
const base::UnguessableToken reporting_source_;
// The client security state of the creator execution context. Never nullptr.
// Copied at construction time.
//
// TODO(crbug.com/40054797): Consider removing this member once the
// creator always outlives this instance. In that case, we could copy the
// creator's client security state lazily instead of eagerly.
const network::mojom::ClientSecurityStatePtr creator_client_security_state_;
// The client security state of this worker, used for subresource fetches. It
// is nullptr until the script's response head is loaded, at which point it is
// calculated based on the response info. If the response is loaded from a URL
// with a local scheme, then the worker inherits its creator's client security
// state.
network::mojom::ClientSecurityStatePtr worker_client_security_state_;
// This is kept alive during the lifetime of the dedicated 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::DedicatedWorkerHostFactoryClient> client_;
std::unique_ptr<ServiceWorkerMainResourceHandle> service_worker_handle_;
#if BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
std::unique_ptr<PressureServiceForDedicatedWorker> pressure_service_;
#endif // BUILDFLAG(ENABLE_COMPUTE_PRESSURE)
// Script request URL used, only for DevTools and tracing. Only set after
// `StartScriptLoad()`.
GURL script_request_url_;
// BrowserInterfaceBroker implementation through which this
// DedicatedWorkerHost exposes worker-scoped Mojo services to the
// corresponding worker in the renderer.
//
// The interfaces that can be requested from this broker are defined in the
// content/browser/browser_interface_binders.cc file, in the functions which
// take a `DedicatedWorkerHost*` parameter.
BrowserInterfaceBrokerImpl<DedicatedWorkerHost, const url::Origin&> broker_{
this};
mojo::Receiver<blink::mojom::BrowserInterfaceBroker> broker_receiver_{
&broker_};
mojo::Receiver<blink::mojom::DedicatedWorkerHost> host_receiver_;
mojo::Receiver<blink::mojom::BackForwardCacheControllerHost>
back_forward_cache_controller_host_receiver_{this};
// Indicates if subresource loaders of this worker support file URLs.
bool file_url_support_ = false;
// For observing Network Service connection errors only.
mojo::Remote<network::mojom::URLLoaderFactory>
network_service_connection_error_handler_holder_;
mojo::Remote<blink::mojom::SubresourceLoaderUpdater>
subresource_loader_updater_;
// `coep_reporter_` is valid after DidStartScriptLoad() and remains non-null
// for the lifetime of `this`.
std::unique_ptr<CrossOriginEmbedderPolicyReporter> coep_reporter_;
// TODO(crbug.com/40054797): Remove `creator_coep_reporter_` after this
// class's lifetime is aligned with the associated frame.
base::WeakPtr<CrossOriginEmbedderPolicyReporter> creator_coep_reporter_;
// This is valid after DidStartScriptLoad() and remains non-null for the
// lifetime of `this`.
std::unique_ptr<DocumentIsolationPolicyReporter> dip_reporter_;
// Will be set once the worker script started loading.
std::optional<GURL> final_response_url_;
// CodeCacheHost processes requests to fetch / write generated code for
// JavaScript / WebAssembly resources.
CodeCacheHostImpl::ReceiverSet code_cache_host_receivers_;
BackForwardCacheBlockingDetails bfcache_blocking_details_;
// This tracks whether the document that created this dedicated worker had
// been granted storage access when the dedicated worker was created, which
// also grants storage access to the dedicated worker.
net::StorageAccessApiStatus storage_access_api_status_;
base::WeakPtrFactory<DedicatedWorkerHost> weak_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_WORKER_HOST_DEDICATED_WORKER_HOST_H_