forked from mirrors/gecko-dev
This only changes the behaviour when called with a TaskQueue or other type using SerialEventTargetGuard on the stack. They are being switched over as the existing GetCurrentEventTarget method is being removed, as it is somewhat confusing, and poorly documented. Callers which need to get the current thread even when on a threadpool or behind a TaskQueue were switched to GetCurrentEventTarget in the previous part. Differential Revision: https://phabricator.services.mozilla.com/D166607
260 lines
8.5 KiB
C++
260 lines
8.5 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "SharedWorkerService.h"
|
|
#include "mozilla/dom/MessagePort.h"
|
|
#include "mozilla/dom/RemoteWorkerTypes.h"
|
|
#include "mozilla/dom/SharedWorkerManager.h"
|
|
#include "mozilla/ipc/BackgroundParent.h"
|
|
#include "mozilla/ipc/URIUtils.h"
|
|
#include "mozilla/BasePrincipal.h"
|
|
#include "mozilla/ClearOnShutdown.h"
|
|
#include "mozilla/SchedulerGroup.h"
|
|
#include "mozilla/StaticMutex.h"
|
|
#include "nsIPrincipal.h"
|
|
#include "nsProxyRelease.h"
|
|
|
|
namespace mozilla {
|
|
|
|
using namespace ipc;
|
|
|
|
namespace dom {
|
|
|
|
namespace {
|
|
|
|
StaticMutex sSharedWorkerMutex;
|
|
|
|
StaticRefPtr<SharedWorkerService> sSharedWorkerService;
|
|
|
|
class GetOrCreateWorkerManagerRunnable final : public Runnable {
|
|
public:
|
|
GetOrCreateWorkerManagerRunnable(SharedWorkerService* aService,
|
|
SharedWorkerParent* aActor,
|
|
const RemoteWorkerData& aData,
|
|
uint64_t aWindowID,
|
|
const MessagePortIdentifier& aPortIdentifier)
|
|
: Runnable("GetOrCreateWorkerManagerRunnable"),
|
|
mBackgroundEventTarget(GetCurrentSerialEventTarget()),
|
|
mService(aService),
|
|
mActor(aActor),
|
|
mData(aData),
|
|
mWindowID(aWindowID),
|
|
mPortIdentifier(aPortIdentifier) {}
|
|
|
|
NS_IMETHOD
|
|
Run() {
|
|
mService->GetOrCreateWorkerManagerOnMainThread(
|
|
mBackgroundEventTarget, mActor, mData, mWindowID, mPortIdentifier);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
|
|
RefPtr<SharedWorkerService> mService;
|
|
RefPtr<SharedWorkerParent> mActor;
|
|
RemoteWorkerData mData;
|
|
uint64_t mWindowID;
|
|
UniqueMessagePortId mPortIdentifier;
|
|
};
|
|
|
|
class WorkerManagerCreatedRunnable final : public Runnable {
|
|
public:
|
|
WorkerManagerCreatedRunnable(
|
|
already_AddRefed<SharedWorkerManagerWrapper> aManagerWrapper,
|
|
SharedWorkerParent* aActor, const RemoteWorkerData& aData,
|
|
uint64_t aWindowID, UniqueMessagePortId& aPortIdentifier)
|
|
: Runnable("WorkerManagerCreatedRunnable"),
|
|
mManagerWrapper(aManagerWrapper),
|
|
mActor(aActor),
|
|
mData(aData),
|
|
mWindowID(aWindowID),
|
|
mPortIdentifier(std::move(aPortIdentifier)) {}
|
|
|
|
NS_IMETHOD
|
|
Run() {
|
|
AssertIsOnBackgroundThread();
|
|
|
|
if (NS_WARN_IF(!mManagerWrapper->Manager()->MaybeCreateRemoteWorker(
|
|
mData, mWindowID, mPortIdentifier, mActor->OtherPid()))) {
|
|
mActor->ErrorPropagation(NS_ERROR_FAILURE);
|
|
return NS_OK;
|
|
}
|
|
|
|
mManagerWrapper->Manager()->AddActor(mActor);
|
|
mActor->ManagerCreated(mManagerWrapper.forget());
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
RefPtr<SharedWorkerManagerWrapper> mManagerWrapper;
|
|
RefPtr<SharedWorkerParent> mActor;
|
|
RemoteWorkerData mData;
|
|
uint64_t mWindowID;
|
|
UniqueMessagePortId mPortIdentifier;
|
|
};
|
|
|
|
class ErrorPropagationRunnable final : public Runnable {
|
|
public:
|
|
ErrorPropagationRunnable(SharedWorkerParent* aActor, nsresult aError)
|
|
: Runnable("ErrorPropagationRunnable"), mActor(aActor), mError(aError) {}
|
|
|
|
NS_IMETHOD
|
|
Run() {
|
|
AssertIsOnBackgroundThread();
|
|
mActor->ErrorPropagation(mError);
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
RefPtr<SharedWorkerParent> mActor;
|
|
nsresult mError;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
/* static */
|
|
already_AddRefed<SharedWorkerService> SharedWorkerService::GetOrCreate() {
|
|
AssertIsOnBackgroundThread();
|
|
|
|
StaticMutexAutoLock lock(sSharedWorkerMutex);
|
|
|
|
if (!sSharedWorkerService) {
|
|
sSharedWorkerService = new SharedWorkerService();
|
|
// ClearOnShutdown can only be called on main thread
|
|
nsresult rv = SchedulerGroup::Dispatch(
|
|
TaskCategory::Other,
|
|
NS_NewRunnableFunction("RegisterSharedWorkerServiceClearOnShutdown",
|
|
[]() {
|
|
StaticMutexAutoLock lock(sSharedWorkerMutex);
|
|
MOZ_ASSERT(sSharedWorkerService);
|
|
ClearOnShutdown(&sSharedWorkerService);
|
|
}));
|
|
Unused << NS_WARN_IF(NS_FAILED(rv));
|
|
}
|
|
|
|
RefPtr<SharedWorkerService> instance = sSharedWorkerService;
|
|
return instance.forget();
|
|
}
|
|
|
|
/* static */
|
|
SharedWorkerService* SharedWorkerService::Get() {
|
|
StaticMutexAutoLock lock(sSharedWorkerMutex);
|
|
|
|
MOZ_ASSERT(sSharedWorkerService);
|
|
return sSharedWorkerService;
|
|
}
|
|
|
|
void SharedWorkerService::GetOrCreateWorkerManager(
|
|
SharedWorkerParent* aActor, const RemoteWorkerData& aData,
|
|
uint64_t aWindowID, const MessagePortIdentifier& aPortIdentifier) {
|
|
AssertIsOnBackgroundThread();
|
|
|
|
// The real check happens on main-thread.
|
|
RefPtr<GetOrCreateWorkerManagerRunnable> r =
|
|
new GetOrCreateWorkerManagerRunnable(this, aActor, aData, aWindowID,
|
|
aPortIdentifier);
|
|
|
|
nsresult rv = SchedulerGroup::Dispatch(TaskCategory::Other, r.forget());
|
|
Unused << NS_WARN_IF(NS_FAILED(rv));
|
|
}
|
|
|
|
void SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(
|
|
nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor,
|
|
const RemoteWorkerData& aData, uint64_t aWindowID,
|
|
UniqueMessagePortId& aPortIdentifier) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(aBackgroundEventTarget);
|
|
MOZ_ASSERT(aActor);
|
|
|
|
auto partitionedPrincipalOrErr =
|
|
PrincipalInfoToPrincipal(aData.partitionedPrincipalInfo());
|
|
if (NS_WARN_IF(partitionedPrincipalOrErr.isErr())) {
|
|
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
|
|
partitionedPrincipalOrErr.unwrapErr());
|
|
return;
|
|
}
|
|
|
|
auto loadingPrincipalOrErr =
|
|
PrincipalInfoToPrincipal(aData.loadingPrincipalInfo());
|
|
if (NS_WARN_IF(loadingPrincipalOrErr.isErr())) {
|
|
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
|
|
loadingPrincipalOrErr.unwrapErr());
|
|
return;
|
|
}
|
|
|
|
RefPtr<SharedWorkerManagerHolder> managerHolder;
|
|
|
|
nsCOMPtr<nsIPrincipal> loadingPrincipal = loadingPrincipalOrErr.unwrap();
|
|
nsCOMPtr<nsIPrincipal> partitionedPrincipal =
|
|
partitionedPrincipalOrErr.unwrap();
|
|
|
|
nsCOMPtr<nsIPrincipal> effectiveStoragePrincipal = partitionedPrincipal;
|
|
if (aData.useRegularPrincipal()) {
|
|
effectiveStoragePrincipal = loadingPrincipal;
|
|
}
|
|
|
|
// Let's see if there is already a SharedWorker to share.
|
|
nsCOMPtr<nsIURI> resolvedScriptURL =
|
|
DeserializeURI(aData.resolvedScriptURL());
|
|
for (SharedWorkerManager* workerManager : mWorkerManagers) {
|
|
managerHolder = workerManager->MatchOnMainThread(
|
|
this, aData.domain(), resolvedScriptURL, aData.name(), loadingPrincipal,
|
|
BasePrincipal::Cast(effectiveStoragePrincipal)->OriginAttributesRef());
|
|
if (managerHolder) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Let's create a new one.
|
|
if (!managerHolder) {
|
|
managerHolder = SharedWorkerManager::Create(
|
|
this, aBackgroundEventTarget, aData, loadingPrincipal,
|
|
BasePrincipal::Cast(effectiveStoragePrincipal)->OriginAttributesRef());
|
|
|
|
mWorkerManagers.AppendElement(managerHolder->Manager());
|
|
} else {
|
|
// We are attaching the actor to an existing one.
|
|
if (managerHolder->Manager()->IsSecureContext() !=
|
|
aData.isSecureContext()) {
|
|
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
|
|
NS_ERROR_DOM_SECURITY_ERR);
|
|
return;
|
|
}
|
|
}
|
|
|
|
RefPtr<SharedWorkerManagerWrapper> wrapper =
|
|
new SharedWorkerManagerWrapper(managerHolder.forget());
|
|
|
|
RefPtr<WorkerManagerCreatedRunnable> r = new WorkerManagerCreatedRunnable(
|
|
wrapper.forget(), aActor, aData, aWindowID, aPortIdentifier);
|
|
aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
|
|
}
|
|
|
|
void SharedWorkerService::ErrorPropagationOnMainThread(
|
|
nsIEventTarget* aBackgroundEventTarget, SharedWorkerParent* aActor,
|
|
nsresult aError) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(aBackgroundEventTarget);
|
|
MOZ_ASSERT(aActor);
|
|
MOZ_ASSERT(NS_FAILED(aError));
|
|
|
|
RefPtr<ErrorPropagationRunnable> r =
|
|
new ErrorPropagationRunnable(aActor, aError);
|
|
aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
|
|
}
|
|
|
|
void SharedWorkerService::RemoveWorkerManagerOnMainThread(
|
|
SharedWorkerManager* aManager) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(aManager);
|
|
MOZ_ASSERT(mWorkerManagers.Contains(aManager));
|
|
|
|
mWorkerManagers.RemoveElement(aManager);
|
|
}
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|