blob: dd11b86e4fca551a710f0e6b26ec5cc37d4709ad [file] [log] [blame]
// Copyright 2017 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/worker_host/dedicated_worker_host.h"
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "content/browser/appcache/appcache_navigation_handle.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h"
#include "content/browser/loader/content_security_notifier.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/service_worker/service_worker_container_host.h"
#include "content/browser/service_worker/service_worker_main_resource_handle.h"
#include "content/browser/service_worker/service_worker_object_host.h"
#include "content/browser/storage_partition_impl.h"
#include "content/browser/url_loader_factory_params_helper.h"
#include "content/browser/websockets/websocket_connector_impl.h"
#include "content/browser/webtransport/web_transport_connector_impl.h"
#include "content/browser/worker_host/dedicated_worker_host_factory_impl.h"
#include "content/browser/worker_host/dedicated_worker_service_impl.h"
#include "content/browser/worker_host/worker_script_fetch_initiator.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/idle_manager.h"
#include "content/public/browser/service_worker_context.h"
#include "content/public/common/content_client.h"
#include "content/public/common/network_service_util.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "net/base/isolation_info.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/fetch_api.mojom.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/service_worker/service_worker_scope_match.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/loader/fetch_client_settings_object.mojom.h"
namespace content {
DedicatedWorkerHost::DedicatedWorkerHost(
DedicatedWorkerServiceImpl* service,
const blink::DedicatedWorkerToken& token,
RenderProcessHost* worker_process_host,
base::Optional<GlobalFrameRoutingId> creator_render_frame_host_id,
base::Optional<blink::DedicatedWorkerToken> creator_worker_token,
GlobalFrameRoutingId ancestor_render_frame_host_id,
const url::Origin& creator_origin,
const net::IsolationInfo& isolation_info,
const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy,
base::WeakPtr<CrossOriginEmbedderPolicyReporter> creator_coep_reporter,
base::WeakPtr<CrossOriginEmbedderPolicyReporter> ancestor_coep_reporter,
mojo::PendingReceiver<blink::mojom::DedicatedWorkerHost> host)
: service_(service),
token_(token),
worker_process_host_(worker_process_host),
creator_render_frame_host_id_(creator_render_frame_host_id),
creator_worker_token_(creator_worker_token),
ancestor_render_frame_host_id_(ancestor_render_frame_host_id),
creator_origin_(creator_origin),
// TODO(https://crbug.com/1058759): Calculate the worker origin based on
// the worker script URL.
worker_origin_(creator_origin),
isolation_info_(isolation_info),
creator_cross_origin_embedder_policy_(cross_origin_embedder_policy),
host_receiver_(this, std::move(host)),
creator_coep_reporter_(std::move(creator_coep_reporter)),
ancestor_coep_reporter_(std::move(ancestor_coep_reporter)) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(worker_process_host_);
DCHECK(worker_process_host_->IsInitializedAndNotDead());
DCHECK((creator_render_frame_host_id_ && !creator_worker_token_) ||
(!creator_render_frame_host_id_ && creator_worker_token_));
scoped_process_host_observation_.Observe(worker_process_host_);
if (!base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker)) {
// This is a workaround to make the worker's COEP have a value when
// PlzDedicatedWorker is disabled. When the feature is enabled, The value is
// initialized in DedicatedWorkerHost::DidStartScriptLoad().
worker_cross_origin_embedder_policy_ =
creator_cross_origin_embedder_policy_;
}
service_->NotifyWorkerCreated(this);
}
DedicatedWorkerHost::~DedicatedWorkerHost() {
service_->NotifyBeforeWorkerDestroyed(token_, ancestor_render_frame_host_id_);
}
void DedicatedWorkerHost::BindBrowserInterfaceBrokerReceiver(
mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(receiver.is_valid());
broker_receiver_.Bind(std::move(receiver));
broker_receiver_.set_disconnect_handler(base::BindOnce(
&DedicatedWorkerHost::OnMojoDisconnect, base::Unretained(this)));
}
void DedicatedWorkerHost::CreateContentSecurityNotifier(
mojo::PendingReceiver<blink::mojom::ContentSecurityNotifier> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto* ancestor_render_frame_host =
RenderFrameHostImpl::FromID(ancestor_render_frame_host_id_);
if (!ancestor_render_frame_host) {
// The ancestor frame may have already been closed. In that case, the worker
// will soon be terminated too, so abort the connection.
return;
}
mojo::MakeSelfOwnedReceiver(
std::make_unique<ContentSecurityNotifier>(ancestor_render_frame_host_id_),
std::move(receiver));
}
void DedicatedWorkerHost::OnMojoDisconnect() {
delete this;
}
void DedicatedWorkerHost::RenderProcessExited(
RenderProcessHost* render_process_host,
const ChildProcessTerminationInfo& info) {
DCHECK_EQ(worker_process_host_, render_process_host);
delete this;
}
void DedicatedWorkerHost::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) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker));
DCHECK(!client_);
DCHECK(client);
client_ = std::move(client);
auto* storage_partition_impl = static_cast<StoragePartitionImpl*>(
worker_process_host_->GetStoragePartition());
// Get nearest ancestor render frame host in order to determine the
// top-frame origin to use for the network isolation key.
RenderFrameHostImpl* nearest_ancestor_render_frame_host =
RenderFrameHostImpl::FromID(ancestor_render_frame_host_id_);
if (!nearest_ancestor_render_frame_host) {
client_->OnScriptLoadStartFailed();
return;
}
scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory;
if (script_url.SchemeIsBlob()) {
if (!blob_url_token) {
mojo::ReportBadMessage("DWH_NO_BLOB_URL_TOKEN");
return;
}
blob_url_loader_factory =
ChromeBlobStorageContext::URLLoaderFactoryForToken(
storage_partition_impl, std::move(blob_url_token));
} else if (blob_url_token) {
mojo::ReportBadMessage("DWH_NOT_BLOB_URL");
return;
}
// If this is a nested worker, there is no creator frame.
RenderFrameHostImpl* creator_render_frame_host = nullptr;
if (creator_render_frame_host_id_) {
creator_render_frame_host =
RenderFrameHostImpl::FromID(creator_render_frame_host_id_.value());
if (!creator_render_frame_host) {
client_->OnScriptLoadStartFailed();
return;
}
}
// A dedicated worker depends on its nearest ancestor's appcache host.
AppCacheHost* appcache_host = nullptr;
const AppCacheNavigationHandle* appcache_handle =
nearest_ancestor_render_frame_host->GetAppCacheNavigationHandle();
if (appcache_handle) {
auto* appcache_service = storage_partition_impl->GetAppCacheService();
if (appcache_service) {
appcache_host =
appcache_service->GetHost(appcache_handle->appcache_host_id());
}
}
// Set if the subresource loader factories support file URLs so that we can
// recreate the factories after Network Service crashes.
// TODO(nhiroki): Currently this flag is calculated based on the request
// initiator origin to keep consistency with WorkerScriptFetchInitiator, but
// probably this should be calculated based on the worker origin as the
// factories be used for subresource loading on the worker.
file_url_support_ = creator_origin_.scheme() == url::kFileScheme;
service_worker_handle_ = std::make_unique<ServiceWorkerMainResourceHandle>(
storage_partition_impl->GetServiceWorkerContext(), base::DoNothing());
// For blob URL workers, inherit the controller from the worker's parent.
// See https://w3c.github.io/ServiceWorker/#control-and-use-worker-client
if (script_url.SchemeIsBlob()) {
if (creator_render_frame_host_id_) {
// The creator of this worker is a frame.
base::WeakPtr<ServiceWorkerContainerHost> creator_container_host =
RenderFrameHostImpl::FromID(creator_render_frame_host_id_.value())
->GetLastCommittedServiceWorkerHost();
service_worker_handle_->set_parent_container_host(creator_container_host);
} else {
// The creator of this worker is a dedicated worker.
DCHECK(creator_worker_token_);
DedicatedWorkerHost* creator_worker =
service_->GetDedicatedWorkerHostFromToken(
creator_worker_token_.value());
if (!creator_worker) {
client_->OnScriptLoadStartFailed();
return;
}
base::WeakPtr<ServiceWorkerContainerHost> creator_container_host =
creator_worker->service_worker_handle()->container_host();
service_worker_handle_->set_parent_container_host(creator_container_host);
}
}
// Get a storage domain.
auto partition_domain =
nearest_ancestor_render_frame_host->GetSiteInstance()->GetPartitionDomain(
storage_partition_impl);
WorkerScriptFetchInitiator::Start(
worker_process_host_->GetID(), token_, script_url,
creator_render_frame_host,
nearest_ancestor_render_frame_host->ComputeSiteForCookies(),
creator_origin_,
nearest_ancestor_render_frame_host->GetIsolationInfoForSubresources(),
credentials_mode, std::move(outside_fetch_client_settings_object),
network::mojom::RequestDestination::kWorker,
storage_partition_impl->GetServiceWorkerContext(),
service_worker_handle_.get(),
appcache_host ? appcache_host->GetWeakPtr() : nullptr,
std::move(blob_url_loader_factory), nullptr, storage_partition_impl,
partition_domain,
// TODO(crbug.com/1138622): Propagate dedicated worker ukm::SourceId here.
ukm::kInvalidSourceId,
// TODO(crbug.com/1143102): pass DevToolsAgentHostImpl for the worker.
nullptr, base::UnguessableToken(),
base::BindOnce(&DedicatedWorkerHost::DidStartScriptLoad,
weak_factory_.GetWeakPtr()));
}
void DedicatedWorkerHost::ReportNoBinderForInterface(const std::string& error) {
broker_receiver_.ReportBadMessage(error + " for the dedicated worker scope");
}
void DedicatedWorkerHost::DidStartScriptLoad(
bool success,
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
subresource_loader_factories,
blink::mojom::WorkerMainScriptLoadParamsPtr main_script_load_params,
blink::mojom::ControllerServiceWorkerInfoPtr controller,
base::WeakPtr<ServiceWorkerObjectHost>
controller_service_worker_object_host,
const GURL& final_response_url) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker));
if (!success) {
client_->OnScriptLoadStartFailed();
return;
}
// TODO(https://crbug.com/986188): Check if the main script's final response
// URL is committable.
final_response_url_ = final_response_url;
service_->NotifyWorkerFinalResponseURLDetermined(token_, final_response_url);
// TODO(cammie): Change this approach when we support shared workers
// creating dedicated workers, as there might be no ancestor frame.
RenderFrameHostImpl* ancestor_render_frame_host =
RenderFrameHostImpl::FromID(ancestor_render_frame_host_id_);
if (!ancestor_render_frame_host) {
client_->OnScriptLoadStartFailed();
return;
}
// https://html.spec.whatwg.org/C/#run-a-worker
worker_cross_origin_embedder_policy_ = network::CrossOriginEmbedderPolicy();
if (final_response_url.SchemeIsBlob() ||
final_response_url.SchemeIs(url::kAboutScheme) ||
final_response_url.SchemeIs(url::kDataScheme)) {
// > 14.5 If response's url's scheme is a local scheme, then set worker
// global scope's embedder policy to owner's embedder policy.
worker_cross_origin_embedder_policy_ =
creator_cross_origin_embedder_policy_;
} else if (main_script_load_params->response_head->parsed_headers) {
// > 14.6 Otherwise, set worker global scope's embedder policy to the result
// of obtaining an embedder policy from response.
worker_cross_origin_embedder_policy_ =
main_script_load_params->response_head->parsed_headers
->cross_origin_embedder_policy;
}
// Create a COEP reporter with worker's policy.
coep_reporter_ = std::make_unique<CrossOriginEmbedderPolicyReporter>(
worker_process_host_->GetStoragePartition(), final_response_url,
worker_cross_origin_embedder_policy_->reporting_endpoint,
worker_cross_origin_embedder_policy_->report_only_reporting_endpoint,
isolation_info_.network_isolation_key());
// TODO(crbug.com/1197041): Bind the receiver of ReportingObserver to the
// worker in the renderer process.
// > 14.8 If the result of checking a global object's embedder policy with
// worker global scope, owner, and response is false, then set response to a
// network error.
if (!CheckCrossOriginEmbedderPolicy(creator_cross_origin_embedder_policy_,
cross_origin_embedder_policy())) {
client_->OnScriptLoadStartFailed();
return;
}
// Start observing Network Service crash when it's running out-of-process.
if (IsOutOfProcessNetworkService()) {
ObserveNetworkServiceCrash(static_cast<StoragePartitionImpl*>(
worker_process_host_->GetStoragePartition()));
}
// Set up the default network loader factory.
bool bypass_redirect_checks = false;
mojo::PendingRemote<network::mojom::URLLoaderFactory>
url_loader_factory_remote = CreateNetworkFactoryForSubresources(
ancestor_render_frame_host, &bypass_redirect_checks);
DCHECK(url_loader_factory_remote);
subresource_loader_factories->pending_default_factory() =
std::move(url_loader_factory_remote);
subresource_loader_factories->set_bypass_redirect_checks(
bypass_redirect_checks);
// Prepare the controller service worker info to pass to the renderer.
// |object_info| can be nullptr when the service worker context or the
// service worker version is gone during dedicated worker startup.
mojo::PendingAssociatedRemote<blink::mojom::ServiceWorkerObject>
service_worker_remote_object;
blink::mojom::ServiceWorkerState service_worker_state;
if (controller && controller->object_info) {
controller->object_info->receiver =
service_worker_remote_object.InitWithNewEndpointAndPassReceiver();
service_worker_state = controller->object_info->state;
}
client_->OnScriptLoadStarted(
service_worker_handle_->TakeContainerInfo(),
std::move(main_script_load_params),
std::move(subresource_loader_factories),
subresource_loader_updater_.BindNewPipeAndPassReceiver(),
std::move(controller));
// |service_worker_remote_object| is an associated remote, so calls can't be
// made on it until its receiver is sent. Now that the receiver was sent, it
// can be used, so add it to ServiceWorkerObjectHost.
if (service_worker_remote_object) {
RunOrPostTaskOnThread(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(
&ServiceWorkerObjectHost::AddRemoteObjectPtrAndUpdateState,
controller_service_worker_object_host,
std::move(service_worker_remote_object), service_worker_state));
}
}
mojo::PendingRemote<network::mojom::URLLoaderFactory>
DedicatedWorkerHost::CreateNetworkFactoryForSubresources(
RenderFrameHostImpl* ancestor_render_frame_host,
bool* bypass_redirect_checks) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(ancestor_render_frame_host);
DCHECK(bypass_redirect_checks);
mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_default_factory;
mojo::PendingReceiver<network::mojom::URLLoaderFactory>
default_factory_receiver =
pending_default_factory.InitWithNewPipeAndPassReceiver();
mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
coep_reporter;
if (GetWorkerCoepReporter()) {
GetWorkerCoepReporter()->Clone(
coep_reporter.InitWithNewPipeAndPassReceiver());
}
network::mojom::URLLoaderFactoryParamsPtr factory_params =
URLLoaderFactoryParamsHelper::CreateForFrame(
ancestor_render_frame_host, worker_origin_, isolation_info_,
ancestor_render_frame_host->BuildClientSecurityState(),
std::move(coep_reporter), worker_process_host_,
ancestor_render_frame_host->IsFeatureEnabled(
blink::mojom::PermissionsPolicyFeature::kTrustTokenRedemption)
? network::mojom::TrustTokenRedemptionPolicy::kPotentiallyPermit
: network::mojom::TrustTokenRedemptionPolicy::kForbid,
"DedicatedWorkerHost::CreateNetworkFactoryForSubresources");
GetContentClient()->browser()->WillCreateURLLoaderFactory(
worker_process_host_->GetBrowserContext(),
/*frame=*/nullptr, worker_process_host_->GetID(),
ContentBrowserClient::URLLoaderFactoryType::kWorkerSubResource,
worker_origin_, /*navigation_id=*/base::nullopt,
ukm::SourceIdObj::FromInt64(
ancestor_render_frame_host->GetPageUkmSourceId()),
&default_factory_receiver, &factory_params->header_client,
bypass_redirect_checks,
/*disable_secure_dns=*/nullptr, &factory_params->factory_override);
// TODO(nhiroki): Call devtools_instrumentation::WillCreateURLLoaderFactory()
// here.
worker_process_host_->CreateURLLoaderFactory(
std::move(default_factory_receiver), std::move(factory_params));
return pending_default_factory;
}
// The implementation of the following algorithm:
// https://html.spec.whatwg.org/C/#check-a-global-object's-embedder-policy
bool DedicatedWorkerHost::CheckCrossOriginEmbedderPolicy(
network::CrossOriginEmbedderPolicy creator_cross_origin_embedder_policy,
network::CrossOriginEmbedderPolicy worker_cross_origin_embedder_policy) {
DCHECK(base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker));
DCHECK(final_response_url_);
if (!creator_coep_reporter_)
return false;
// > 4. If ownerPolicy's report-only value is "require-corp" or
// "credentialless" and policy's value is "unsafe-none", then queue a
// cross-origin embedder policy inheritance violation with response, "worker
// initialization", owner's policy's report only reporting endpoint,
// "reporting", and owner.
if (network::CompatibleWithCrossOriginIsolated(
creator_cross_origin_embedder_policy.report_only_value) &&
!network::CompatibleWithCrossOriginIsolated(
worker_cross_origin_embedder_policy)) {
creator_coep_reporter_->QueueWorkerInitializationReport(
final_response_url_.value(),
/*report_only=*/true);
}
// > 5. If ownerPolicy's value is "unsafe-none" or policy's value is
// "require-corp" or "credentialless", then return true.
if (!network::CompatibleWithCrossOriginIsolated(
creator_cross_origin_embedder_policy) ||
network::CompatibleWithCrossOriginIsolated(
worker_cross_origin_embedder_policy)) {
return true;
}
// > 6. Queue a cross-origin embedder policy inheritance violation with
// response, "worker initialization", owner's policy's reporting endpoint,
// "enforce", and owner.
creator_coep_reporter_->QueueWorkerInitializationReport(
final_response_url_.value(),
/*report_only=*/false);
// > 7. Return false.
return false;
}
void DedicatedWorkerHost::CreateWebUsbService(
mojo::PendingReceiver<blink::mojom::WebUsbService> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderFrameHostImpl* ancestor_render_frame_host =
RenderFrameHostImpl::FromID(ancestor_render_frame_host_id_);
// The ancestor frame may have already been closed. In that case, the worker
// will soon be terminated too, so abort the connection.
if (!ancestor_render_frame_host)
return;
ancestor_render_frame_host->CreateWebUsbService(std::move(receiver));
}
void DedicatedWorkerHost::CreateWebSocketConnector(
mojo::PendingReceiver<blink::mojom::WebSocketConnector> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderFrameHostImpl* ancestor_render_frame_host =
RenderFrameHostImpl::FromID(ancestor_render_frame_host_id_);
if (!ancestor_render_frame_host) {
// The ancestor frame may have already been closed. In that case, the worker
// will soon be terminated too, so abort the connection.
receiver.ResetWithReason(0, "The parent frame has already been gone.");
return;
}
mojo::MakeSelfOwnedReceiver(
std::make_unique<WebSocketConnectorImpl>(
ancestor_render_frame_host_id_.child_id,
ancestor_render_frame_host_id_.frame_routing_id, worker_origin_,
ancestor_render_frame_host->GetIsolationInfoForSubresources()),
std::move(receiver));
}
void DedicatedWorkerHost::CreateWebTransportConnector(
mojo::PendingReceiver<blink::mojom::WebTransportConnector> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
mojo::MakeSelfOwnedReceiver(
std::make_unique<WebTransportConnectorImpl>(
worker_process_host_->GetID(), /*frame=*/nullptr, worker_origin_,
isolation_info_.network_isolation_key()),
std::move(receiver));
}
void DedicatedWorkerHost::CreateWakeLockService(
mojo::PendingReceiver<blink::mojom::WakeLockService> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Unconditionally disallow wake locks from workers until
// WakeLockPermissionContext has been updated to no longer force the
// permission to "denied" and WakeLockServiceImpl checks permissions on
// every request.
return;
}
void DedicatedWorkerHost::BindCacheStorage(
mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
coep_reporter;
if (GetWorkerCoepReporter()) {
GetWorkerCoepReporter()->Clone(
coep_reporter.InitWithNewPipeAndPassReceiver());
}
worker_process_host_->BindCacheStorage(cross_origin_embedder_policy(),
std::move(coep_reporter),
worker_origin_, std::move(receiver));
}
void DedicatedWorkerHost::CreateNestedDedicatedWorker(
mojo::PendingReceiver<blink::mojom::DedicatedWorkerHostFactory> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// For the non-PlzDedicatedWorker case, use ancestor's COEP reporter as a
// `creator_coep_reporter` to keep the current behavior, but it's not aligned
// with the spec.
base::WeakPtr<CrossOriginEmbedderPolicyReporter> creator_coep_reporter =
GetWorkerCoepReporter();
mojo::MakeSelfOwnedReceiver(
std::make_unique<DedicatedWorkerHostFactoryImpl>(
worker_process_host_->GetID(),
/*creator_render_frame_host_id_=*/base::nullopt,
/*creator_worker_token=*/token_, ancestor_render_frame_host_id_,
worker_origin_, isolation_info_, cross_origin_embedder_policy(),
creator_coep_reporter, ancestor_coep_reporter_),
std::move(receiver));
}
void DedicatedWorkerHost::CreateIdleManager(
mojo::PendingReceiver<blink::mojom::IdleManager> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderFrameHostImpl* ancestor_render_frame_host =
RenderFrameHostImpl::FromID(ancestor_render_frame_host_id_);
if (!ancestor_render_frame_host) {
// The ancestor frame may have already been closed. In that case, the worker
// will soon be terminated too, so abort the connection.
return;
}
ancestor_render_frame_host->BindIdleManager(std::move(receiver));
}
void DedicatedWorkerHost::BindWebOTPServiceReceiver(
mojo::PendingReceiver<blink::mojom::WebOTPService> receiver) {
RenderFrameHostImpl* ancestor_render_frame_host =
RenderFrameHostImpl::FromID(ancestor_render_frame_host_id_);
if (!ancestor_render_frame_host) {
// The ancestor frame may have already been closed. In that case, the worker
// will soon be terminated too, so abort the connection.
return;
}
ancestor_render_frame_host->BindWebOTPServiceReceiver(std::move(receiver));
}
#if !defined(OS_ANDROID)
void DedicatedWorkerHost::BindSerialService(
mojo::PendingReceiver<blink::mojom::SerialService> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderFrameHostImpl* ancestor_render_frame_host =
RenderFrameHostImpl::FromID(ancestor_render_frame_host_id_);
if (!ancestor_render_frame_host) {
// The ancestor frame may have already been closed. In that case, the worker
// will soon be terminated too, so abort the connection.
return;
}
ancestor_render_frame_host->BindSerialService(std::move(receiver));
}
#endif
void DedicatedWorkerHost::ObserveNetworkServiceCrash(
StoragePartitionImpl* storage_partition_impl) {
auto params = network::mojom::URLLoaderFactoryParams::New();
params->process_id = worker_process_host_->GetID();
params->debug_tag = "DedicatedWorkerHost::ObserveNetworkServiceCrash";
network_service_connection_error_handler_holder_.reset();
storage_partition_impl->GetNetworkContext()->CreateURLLoaderFactory(
network_service_connection_error_handler_holder_
.BindNewPipeAndPassReceiver(),
std::move(params));
network_service_connection_error_handler_holder_.set_disconnect_handler(
base::BindOnce(&DedicatedWorkerHost::UpdateSubresourceLoaderFactories,
weak_factory_.GetWeakPtr()));
}
void DedicatedWorkerHost::UpdateSubresourceLoaderFactories() {
DCHECK(IsOutOfProcessNetworkService());
DCHECK(subresource_loader_updater_.is_bound());
DCHECK(network_service_connection_error_handler_holder_);
DCHECK(!network_service_connection_error_handler_holder_.is_connected());
auto* storage_partition_impl = static_cast<StoragePartitionImpl*>(
worker_process_host_->GetStoragePartition());
RenderFrameHostImpl* ancestor_render_frame_host =
RenderFrameHostImpl::FromID(ancestor_render_frame_host_id_);
if (!ancestor_render_frame_host)
return;
// Get a storage domain.
auto partition_domain =
ancestor_render_frame_host->GetSiteInstance()->GetPartitionDomain(
storage_partition_impl);
// Start observing Network Service crash again.
ObserveNetworkServiceCrash(storage_partition_impl);
// If this is a nested worker, there is no creator frame and
// |creator_render_frame_host| will be null.
RenderFrameHostImpl* creator_render_frame_host =
creator_render_frame_host_id_
? RenderFrameHostImpl::FromID(creator_render_frame_host_id_.value())
: nullptr;
// Recreate the default URLLoaderFactory. This doesn't support
// AppCache-specific factory.
std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
subresource_loader_factories =
WorkerScriptFetchInitiator::CreateFactoryBundle(
WorkerScriptFetchInitiator::LoaderType::kSubResource,
worker_process_host_->GetID(), storage_partition_impl,
partition_domain, file_url_support_,
/*filesystem_url_support=*/true, creator_render_frame_host);
bool bypass_redirect_checks = false;
subresource_loader_factories->pending_default_factory() =
CreateNetworkFactoryForSubresources(ancestor_render_frame_host,
&bypass_redirect_checks);
subresource_loader_factories->set_bypass_redirect_checks(
bypass_redirect_checks);
subresource_loader_updater_->UpdateSubresourceLoaderFactories(
std::move(subresource_loader_factories));
}
void DedicatedWorkerHost::MaybeCountWebFeature(const GURL& script_url) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker));
RenderFrameHostImpl* ancestor_render_frame_host =
RenderFrameHostImpl::FromID(ancestor_render_frame_host_id_);
if (!ancestor_render_frame_host)
return;
base::WeakPtr<ServiceWorkerContainerHost> container_host =
ancestor_render_frame_host->GetLastCommittedServiceWorkerHost();
if (!container_host)
return;
// Count the number of dedicated workers that are controlled by the service
// worker that is inherited from a controlled document, and will not be
// controlled after PlzDedicatedWorker is enabled.
if (container_host->controller_registration() &&
!blink::ServiceWorkerScopeMatches(
container_host->controller_registration()->scope(), script_url)) {
container_host->CountFeature(
blink::mojom::WebFeature::kWorkerControlledByServiceWorkerOutOfScope);
// Count the number of dedicated workers that will not be controlled by the
// service worker with a fetch event handler. This better measures the risk
// of site breakage by PlzDedicatedWorker.
if (container_host->controller()) {
DCHECK_NE(container_host->controller()->fetch_handler_existence(),
ServiceWorkerVersion::FetchHandlerExistence::UNKNOWN);
if (container_host->controller()->fetch_handler_existence() ==
ServiceWorkerVersion::FetchHandlerExistence::EXISTS)
container_host->CountFeature(
blink::mojom::WebFeature::
kWorkerControlledByServiceWorkerWithFetchEventHandlerOutOfScope);
}
}
}
base::WeakPtr<CrossOriginEmbedderPolicyReporter>
DedicatedWorkerHost::GetWorkerCoepReporter() {
if (base::FeatureList::IsEnabled(blink::features::kPlzDedicatedWorker)) {
DCHECK(coep_reporter_);
return coep_reporter_->GetWeakPtr();
}
// For the non-PlzDedicatedWorker case, use ancestor's COEP reporter to keep
// the current behavior, but it's not aligned with the spec.
// `ancestor_coep_reporter_` is possible to be nullptr, which means the
// ancestor render frame has already been closed or navigated and this worker
// will also be terminated soon.
return ancestor_coep_reporter_;
}
} // namespace content