blob: fc8809b08b0c62720a83d8cc2c540d7375600566 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/service_worker/service_worker_host.h"
#include <utility>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "content/browser/broadcast_channel/broadcast_channel_provider.h"
#include "content/browser/broadcast_channel/broadcast_channel_service.h"
#include "content/browser/buckets/bucket_manager.h"
#include "content/browser/code_cache/generated_code_cache_context.h"
#include "content/browser/renderer_host/code_cache_host_impl.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/service_worker/service_worker_consts.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_version.h"
#include "content/browser/webtransport/web_transport_connector_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/child_process_host.h"
#include "content/public/common/origin_util.h"
#include "mojo/public/cpp/bindings/message.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/messaging/message_port_channel.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom.h"
namespace content {
ServiceWorkerHost::ServiceWorkerHost(
mojo::PendingAssociatedReceiver<blink::mojom::ServiceWorkerContainerHost>
host_receiver,
ServiceWorkerVersion* version,
base::WeakPtr<ServiceWorkerContextCore> context)
: version_(version),
broker_(this),
container_host_(std::make_unique<content::ServiceWorkerContainerHost>(
std::move(context))),
host_receiver_(container_host_.get(), std::move(host_receiver)) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(version_);
container_host_->set_service_worker_host(this);
container_host_->UpdateUrls(
version_->script_url(),
url::Origin::Create(version_->key().top_level_site().GetURL()),
version_->key());
}
ServiceWorkerHost::~ServiceWorkerHost() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Explicitly destroy the ServiceWorkerContainerHost to release
// ServiceWorkerObjectHosts and ServiceWorkerRegistrationObjectHosts owned by
// that. Otherwise, this destructor can trigger their Mojo connection error
// handlers, which would call back into halfway destroyed |this|. This is
// because they are associated with the ServiceWorker interface, which can be
// destroyed while in this destructor (|version_|'s |event_dispatcher_|).
// See https://crbug.com/854993.
container_host_.reset();
}
void ServiceWorkerHost::CompleteStartWorkerPreparation(
int process_id,
mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker> broker_receiver,
mojo::PendingRemote<service_manager::mojom::InterfaceProvider>
interface_provider_remote) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_EQ(ChildProcessHost::kInvalidUniqueID, worker_process_id_);
DCHECK_NE(ChildProcessHost::kInvalidUniqueID, process_id);
worker_process_id_ = process_id;
broker_receiver_.Bind(std::move(broker_receiver));
remote_interfaces_.Bind(std::move(interface_provider_remote));
}
void ServiceWorkerHost::CreateWebTransportConnector(
mojo::PendingReceiver<blink::mojom::WebTransportConnector> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
mojo::MakeSelfOwnedReceiver(
std::make_unique<WebTransportConnectorImpl>(
worker_process_id_, /*frame=*/nullptr, version_->key().origin(),
GetNetworkIsolationKey()),
std::move(receiver));
}
void ServiceWorkerHost::BindCacheStorage(
mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
version_->embedded_worker()->BindCacheStorage(std::move(receiver));
}
#if !BUILDFLAG(IS_ANDROID)
void ServiceWorkerHost::BindHidService(
mojo::PendingReceiver<blink::mojom::HidService> receiver) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
version_->embedded_worker()->BindHidService(version_->key().origin(),
std::move(receiver));
}
#endif
net::NetworkIsolationKey ServiceWorkerHost::GetNetworkIsolationKey() const {
// TODO(https://crbug.com/1147281): This is the NetworkIsolationKey of a
// top-level browsing context, which shouldn't be use for ServiceWorkers used
// in iframes.
return net::NetworkIsolationKey::ToDoUseTopFrameOriginAsWell(
version_->key().origin());
}
const base::UnguessableToken& ServiceWorkerHost::GetReportingSource() const {
return version_->reporting_source();
}
StoragePartition* ServiceWorkerHost::GetStoragePartition() const {
// It is possible that the RenderProcessHost is gone but we receive a request
// before we had the opportunity to Detach because the disconnect handler
// wasn't run yet. In such cases it is is safe to ignore these messages since
// we are about to stop the service worker.
auto* process =
RenderProcessHost::FromID(version_->embedded_worker()->process_id());
if (process == nullptr)
return nullptr;
return process->GetStoragePartition();
}
void ServiceWorkerHost::CreateCodeCacheHost(
mojo::PendingReceiver<blink::mojom::CodeCacheHost> receiver) {
auto embedded_worker_status = version_->embedded_worker()->status();
// Due to IPC races it is possible that we receive code cache host requests
// when the worker is stopping. For ex:
// 1) Browser starts trying to stop, sends the Stop() IPC.
// 2) Renderer sends a CreateCodeCacheHost() IPC.
// 3) Renderer gets the Stop() IPC and realize it should try to stop the
// worker.
// Given the worker is stopping it is safe to ignore these messages.
if (embedded_worker_status == EmbeddedWorkerStatus::STOPPING)
return;
// Create a new CodeCacheHostImpl and bind it to the given receiver.
StoragePartition* storage_partition = GetStoragePartition();
if (!storage_partition) {
return;
}
if (!code_cache_host_receivers_) {
code_cache_host_receivers_ =
std::make_unique<CodeCacheHostImpl::ReceiverSet>(
storage_partition->GetGeneratedCodeCacheContext());
}
code_cache_host_receivers_->Add(version_->embedded_worker()->process_id(),
GetNetworkIsolationKey(),
std::move(receiver));
}
void ServiceWorkerHost::CreateBroadcastChannelProvider(
mojo::PendingReceiver<blink::mojom::BroadcastChannelProvider> receiver) {
auto* storage_partition_impl =
static_cast<StoragePartitionImpl*>(GetStoragePartition());
if (!storage_partition_impl) {
return;
}
auto* broadcast_channel_service =
storage_partition_impl->GetBroadcastChannelService();
broadcast_channel_service->AddReceiver(
std::make_unique<BroadcastChannelProvider>(broadcast_channel_service,
version()->key()),
std::move(receiver));
}
void ServiceWorkerHost::CreateBucketManagerHost(
mojo::PendingReceiver<blink::mojom::BucketManagerHost> receiver) {
static_cast<StoragePartitionImpl*>(GetStoragePartition())
->GetBucketManager()
->BindReceiver(GetWeakPtr(), std::move(receiver),
mojo::GetBadMessageCallback());
}
base::WeakPtr<ServiceWorkerHost> ServiceWorkerHost::GetWeakPtr() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return weak_factory_.GetWeakPtr();
}
void ServiceWorkerHost::ReportNoBinderForInterface(const std::string& error) {
broker_receiver_.ReportBadMessage(error + " for the service worker scope");
}
blink::StorageKey ServiceWorkerHost::GetBucketStorageKey() {
return version_->key();
}
blink::mojom::PermissionStatus ServiceWorkerHost::GetPermissionStatus(
blink::PermissionType permission_type) {
auto* process =
RenderProcessHost::FromID(version_->embedded_worker()->process_id());
if (!process)
return blink::mojom::PermissionStatus::DENIED;
return process->GetBrowserContext()
->GetPermissionController()
->GetPermissionStatusForWorker(permission_type, process,
GetBucketStorageKey().origin());
}
void ServiceWorkerHost::BindCacheStorageForBucket(
const storage::BucketInfo& bucket,
mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) {
// TODO(estade): pass the bucket in order to support non-default buckets.
version_->embedded_worker()->BindCacheStorage(std::move(receiver));
}
} // namespace content