Bug 1438945 - Part 9: RemoteWorker in SharedWorkerManager. r=asuth

--HG--
extra : rebase_source : 07a23a3f76ef06d76a456ba785186018e6fb77f1
This commit is contained in:
Andrea Marchesini 2018-11-19 15:18:33 -08:00
Родитель 7c7e94be60
Коммит c292b31a93
30 изменённых файлов: 1565 добавлений и 539 удалений

Просмотреть файл

@ -33,10 +33,10 @@
#include "mozilla/dom/MutableBlobStreamListener.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseWorkerProxy.h"
#include "mozilla/dom/RemoteWorkerChild.h"
#include "mozilla/dom/Request.h"
#include "mozilla/dom/Response.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/SharedWorkerManager.h"
#include "mozilla/dom/URLSearchParams.h"
#include "mozilla/Telemetry.h"
@ -907,7 +907,7 @@ WorkerFetchResolver::FlushConsoleReport()
if (worker->IsSharedWorker()) {
// Flush to shared worker
worker->GetSharedWorkerManager()->FlushReportsToActorsOnMainThread(mReporter);
worker->GetRemoteWorkerController()->FlushReportsOnMainThread(mReporter);
return;
}

Просмотреть файл

@ -47,9 +47,9 @@
#include "mozilla/dom/MessageChannel.h"
#include "mozilla/dom/MessageEventBinding.h"
#include "mozilla/dom/PerformanceService.h"
#include "mozilla/dom/RemoteWorkerChild.h"
#include "mozilla/dom/WorkerBinding.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/SharedWorkerManager.h"
#include "mozilla/dom/IndexedDatabaseManager.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/DebugOnly.h"
@ -1533,7 +1533,7 @@ RuntimeService::UnregisterWorker(WorkerPrivate* aWorkerPrivate)
if (aWorkerPrivate->IsSharedWorker()) {
AssertIsOnMainThread();
aWorkerPrivate->GetSharedWorkerManager()->CloseActorsOnMainThread();
aWorkerPrivate->GetRemoteWorkerController()->CloseWorkerOnMainThread();
}
if (parent) {

Просмотреть файл

@ -9,8 +9,7 @@
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/dom/ErrorEvent.h"
#include "mozilla/dom/ErrorEventBinding.h"
#include "mozilla/dom/PSharedWorker.h"
#include "mozilla/dom/SharedWorkerManager.h"
#include "mozilla/dom/RemoteWorkerChild.h"
#include "mozilla/dom/ServiceWorkerManager.h"
#include "mozilla/dom/SimpleGlobalObject.h"
#include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
@ -203,9 +202,9 @@ private:
MOZ_ASSERT(!aWorkerPrivate->IsParentWindowPaused());
if (aWorkerPrivate->IsSharedWorker()) {
aWorkerPrivate->GetSharedWorkerManager()
->BroadcastErrorToActorsOnMainThread(&mReport,
/* isErrorEvent */ true);
aWorkerPrivate->GetRemoteWorkerController()
->ErrorPropagationOnMainThread(&mReport,
/* isErrorEvent */ true);
return true;
}
@ -294,8 +293,8 @@ private:
MOZ_ASSERT(!aWorkerPrivate->IsParentWindowPaused());
if (aWorkerPrivate->IsSharedWorker()) {
aWorkerPrivate->GetSharedWorkerManager()
->BroadcastErrorToActorsOnMainThread(nullptr, false);
aWorkerPrivate->GetRemoteWorkerController()
->ErrorPropagationOnMainThread(nullptr, false);
return true;
}

Просмотреть файл

@ -30,7 +30,7 @@
#include "mozilla/dom/Performance.h"
#include "mozilla/dom/PerformanceStorageWorker.h"
#include "mozilla/dom/PromiseDebugging.h"
#include "mozilla/dom/SharedWorkerManager.h"
#include "mozilla/dom/RemoteWorkerChild.h"
#include "mozilla/dom/WorkerBinding.h"
#include "mozilla/ThreadEventQueue.h"
#include "mozilla/ThrottledEventQueue.h"
@ -1888,7 +1888,7 @@ WorkerPrivate::ModifyBusyCount(bool aIncrease)
{
AssertIsOnParentThread();
NS_ASSERTION(aIncrease || mBusyCount, "Mismatched busy count mods!");
MOZ_ASSERT(aIncrease || mBusyCount, "Mismatched busy count mods!");
if (aIncrease) {
mBusyCount++;
@ -4907,7 +4907,7 @@ WorkerPrivate::EndCTypesCall()
bool
WorkerPrivate::ConnectMessagePort(JSContext* aCx,
MessagePortIdentifier& aIdentifier)
const MessagePortIdentifier& aIdentifier)
{
AssertIsOnWorkerThread();
@ -5075,21 +5075,21 @@ WorkerPrivate::GetPerformanceStorage()
}
void
WorkerPrivate::SetSharedWorkerManager(SharedWorkerManager* aManager)
WorkerPrivate::SetRemoteWorkerController(RemoteWorkerChild* aController)
{
AssertIsOnMainThread();
MOZ_ASSERT(aManager);
MOZ_ASSERT(!mSharedWorkerManager);
MOZ_ASSERT(aController);
MOZ_ASSERT(!mRemoteWorkerController);
mSharedWorkerManager = aManager;
mRemoteWorkerController = aController;
}
SharedWorkerManager*
WorkerPrivate::GetSharedWorkerManager()
RemoteWorkerChild*
WorkerPrivate::GetRemoteWorkerController()
{
AssertIsOnMainThread();
MOZ_ASSERT(mSharedWorkerManager);
return mSharedWorkerManager;
MOZ_ASSERT(mRemoteWorkerController);
return mRemoteWorkerController;
}
NS_IMPL_ADDREF(WorkerPrivate::EventTarget)

Просмотреть файл

@ -44,7 +44,7 @@ class Function;
class MessagePort;
class MessagePortIdentifier;
class PerformanceStorage;
class SharedWorkerManager;
class RemoteWorkerChild;
class WorkerControlRunnable;
class WorkerCSPEventListener;
class WorkerDebugger;
@ -461,7 +461,7 @@ public:
}
bool
ConnectMessagePort(JSContext* aCx, MessagePortIdentifier& aIdentifier);
ConnectMessagePort(JSContext* aCx, const MessagePortIdentifier& aIdentifier);
WorkerGlobalScope*
GetOrCreateGlobalScope(JSContext* aCx);
@ -1079,11 +1079,11 @@ public:
mLoadingWorkerScript = aLoadingWorkerScript;
}
SharedWorkerManager*
GetSharedWorkerManager();
RemoteWorkerChild*
GetRemoteWorkerController();
void
SetSharedWorkerManager(SharedWorkerManager* aWorkerManager);
SetRemoteWorkerController(RemoteWorkerChild* aController);
// We can assume that an nsPIDOMWindow will be available for Freeze, Thaw
// as these are only used for globals going in and out of the bfcache.
@ -1393,7 +1393,7 @@ private:
nsTArray<RefPtr<WorkerRunnable>> mPreStartRunnables;
// Only touched on the parent thread. This is set only if IsSharedWorker().
RefPtr<SharedWorkerManager> mSharedWorkerManager;
RefPtr<RemoteWorkerChild> mRemoteWorkerController;
JS::UniqueChars mDefaultLocale; // nulled during worker JSContext init
TimeStamp mKillTime;

Просмотреть файл

@ -4,9 +4,53 @@
include protocol PBackground;
include DOMTypes;
include RemoteWorkerTypes;
namespace mozilla {
namespace dom {
struct RemoteWorkerSuspendOp
{};
struct RemoteWorkerResumeOp
{};
struct RemoteWorkerFreezeOp
{};
struct RemoteWorkerThawOp
{};
struct RemoteWorkerTerminateOp
{};
struct RemoteWorkerPortIdentifierOp
{
MessagePortIdentifier portIdentifier;
};
struct RemoteWorkerAddWindowIDOp
{
uint64_t windowID;
};
struct RemoteWorkerRemoveWindowIDOp
{
uint64_t windowID;
};
union RemoteWorkerOp {
RemoteWorkerSuspendOp;
RemoteWorkerResumeOp;
RemoteWorkerFreezeOp;
RemoteWorkerThawOp;
RemoteWorkerTerminateOp;
RemoteWorkerPortIdentifierOp;
RemoteWorkerAddWindowIDOp;
RemoteWorkerRemoveWindowIDOp;
};
// This protocol is used to make a remote worker controllable from the parent
// process. The parent process will receive operations from the
// PRemoteWorkerController protocol.
@ -15,9 +59,16 @@ protocol PRemoteWorker
manager PBackground;
parent:
async Created(bool aStatus);
async Error(ErrorValue aValue);
async Close();
child:
async __delete__();
async Created(bool aStatus);
async ExecOp(RemoteWorkerOp op);
};
} // namespace dom

Просмотреть файл

@ -5,14 +5,739 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "RemoteWorkerChild.h"
#include "RemoteWorkerService.h"
#include "mozilla/dom/IndexedDatabaseManager.h"
#include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/RemoteWorkerTypes.h"
#include "mozilla/dom/ServiceWorkerInterceptController.h"
#include "mozilla/dom/workerinternals/ScriptLoader.h"
#include "mozilla/dom/WorkerError.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRef.h"
#include "mozilla/dom/WorkerRunnable.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "nsIConsoleReportCollector.h"
#include "nsIPrincipal.h"
#include "nsNetUtil.h"
#include "nsProxyRelease.h"
namespace mozilla {
using namespace ipc;
namespace dom {
RemoteWorkerChild::RemoteWorkerChild()
{}
using workerinternals::ChannelFromScriptURLMainThread;
RemoteWorkerChild::~RemoteWorkerChild() = default;
namespace {
nsresult
PopulateContentSecurityPolicy(nsIContentSecurityPolicy* aCSP,
const nsTArray<ContentSecurityPolicy>& aPolicies)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aCSP);
MOZ_ASSERT(!aPolicies.IsEmpty());
for (const ContentSecurityPolicy& policy : aPolicies) {
nsresult rv = aCSP->AppendPolicy(policy.policy(),
policy.reportOnlyFlag(),
policy.deliveredViaMetaTagFlag());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
return NS_OK;
}
nsresult
PopulatePrincipalContentSecurityPolicy(nsIPrincipal* aPrincipal,
const nsTArray<ContentSecurityPolicy>& aPolicies,
const nsTArray<ContentSecurityPolicy>& aPreloadPolicies)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPrincipal);
if (!aPolicies.IsEmpty()) {
nsCOMPtr<nsIContentSecurityPolicy> csp;
aPrincipal->EnsureCSP(nullptr, getter_AddRefs(csp));
nsresult rv = PopulateContentSecurityPolicy(csp, aPolicies);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
if (!aPreloadPolicies.IsEmpty()) {
nsCOMPtr<nsIContentSecurityPolicy> preloadCsp;
aPrincipal->EnsurePreloadCSP(nullptr, getter_AddRefs(preloadCsp));
nsresult rv = PopulateContentSecurityPolicy(preloadCsp, aPreloadPolicies);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
return NS_OK;
}
class SharedWorkerInterfaceRequestor final : public nsIInterfaceRequestor
{
public:
NS_DECL_ISUPPORTS
SharedWorkerInterfaceRequestor()
: mSWController(new ServiceWorkerInterceptController())
{}
NS_IMETHOD
GetInterface(const nsIID& aIID, void** aSink) override
{
MOZ_ASSERT(NS_IsMainThread());
if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController))) {
// If asked for the network intercept controller, ask the outer requestor,
// which could be the docshell.
RefPtr<ServiceWorkerInterceptController> swController = mSWController;
swController.forget(aSink);
return NS_OK;
}
return NS_NOINTERFACE;
}
private:
~SharedWorkerInterfaceRequestor() = default;
RefPtr<ServiceWorkerInterceptController> mSWController;
};
NS_IMPL_ADDREF(SharedWorkerInterfaceRequestor)
NS_IMPL_RELEASE(SharedWorkerInterfaceRequestor)
NS_IMPL_QUERY_INTERFACE(SharedWorkerInterfaceRequestor, nsIInterfaceRequestor)
// Normal runnable because AddPortIdentifier() is going to exec JS code.
class MessagePortIdentifierRunnable final : public WorkerRunnable
{
public:
MessagePortIdentifierRunnable(WorkerPrivate* aWorkerPrivate,
RemoteWorkerChild* aActor,
const MessagePortIdentifier& aPortIdentifier)
: WorkerRunnable(aWorkerPrivate)
, mActor(aActor)
, mPortIdentifier(aPortIdentifier)
{}
private:
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
mActor->AddPortIdentifier(aCx, aWorkerPrivate, mPortIdentifier);
return true;
}
nsresult
Cancel() override
{
MessagePort::ForceClose(mPortIdentifier);
return WorkerRunnable::Cancel();
}
virtual bool
PreDispatch(WorkerPrivate* aWorkerPrivate) override
{
// Silence bad assertions.
return true;
}
virtual void
PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
{
// Silence bad assertions.
}
bool
PreRun(WorkerPrivate* aWorkerPrivate) override
{
// Silence bad assertions.
return true;
}
void
PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
bool aRunResult) override
{
// Silence bad assertions.
return;
}
RefPtr<RemoteWorkerChild> mActor;
MessagePortIdentifier mPortIdentifier;
};
} // anonymous
class RemoteWorkerChild::InitializeWorkerRunnable final : public WorkerRunnable
{
public:
InitializeWorkerRunnable(WorkerPrivate* aWorkerPrivate,
RemoteWorkerChild* aActor)
: WorkerRunnable(aWorkerPrivate)
, mActor(aActor)
{}
private:
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
mActor->InitializeOnWorker(aWorkerPrivate);
return true;
}
nsresult
Cancel() override
{
mActor->CreationFailedOnAnyThread();
mActor->ShutdownOnWorker();
return WorkerRunnable::Cancel();
}
RefPtr<RemoteWorkerChild> mActor;
};
RemoteWorkerChild::RemoteWorkerChild()
: mIPCActive(true)
, mWorkerState(ePending)
{
MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
}
RemoteWorkerChild::~RemoteWorkerChild()
{
nsCOMPtr<nsIEventTarget> target =
SystemGroup::EventTargetFor(TaskCategory::Other);
NS_ProxyRelease("RemoteWorkerChild::mWorkerPrivate",
target, mWorkerPrivate.forget());
}
void
RemoteWorkerChild::ActorDestroy(ActorDestroyReason aWhy)
{
mIPCActive = false;
mPendingOps.Clear();
}
void
RemoteWorkerChild::ExecWorker(const RemoteWorkerData& aData)
{
MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
MOZ_ASSERT(mIPCActive);
RefPtr<RemoteWorkerChild> self = this;
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("RemoteWorkerChild::ExecWorker",
[self, aData]() {
nsresult rv = self->ExecWorkerOnMainThread(aData);
if (NS_WARN_IF(NS_FAILED(rv))) {
self->CreationFailedOnAnyThread();
}
});
nsCOMPtr<nsIEventTarget> target =
SystemGroup::EventTargetFor(TaskCategory::Other);
target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
nsresult
RemoteWorkerChild::ExecWorkerOnMainThread(const RemoteWorkerData& aData)
{
MOZ_ASSERT(NS_IsMainThread());
// Ensure that the IndexedDatabaseManager is initialized
Unused << NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate());
nsresult rv = NS_OK;
nsCOMPtr<nsIPrincipal> principal =
PrincipalInfoToPrincipal(aData.principalInfo(), &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = PopulatePrincipalContentSecurityPolicy(principal,
aData.principalCsp(),
aData.principalPreloadCsp());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIPrincipal> loadingPrincipal =
PrincipalInfoToPrincipal(aData.loadingPrincipalInfo(), &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = PopulatePrincipalContentSecurityPolicy(loadingPrincipal,
aData.loadingPrincipalCsp(),
aData.loadingPrincipalPreloadCsp());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
WorkerLoadInfo info;
rv = NS_NewURI(getter_AddRefs(info.mBaseURI), aData.baseScriptURL(),
nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = NS_NewURI(getter_AddRefs(info.mResolvedScriptURI),
aData.resolvedScriptURL(), nullptr, info.mBaseURI);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
info.mPrincipalInfo = new PrincipalInfo(aData.principalInfo());
info.mDomain = aData.domain();
info.mPrincipal = principal;
info.mLoadingPrincipal = loadingPrincipal;
nsContentUtils::StorageAccess access =
nsContentUtils::StorageAllowedForPrincipal(info.mPrincipal);
info.mStorageAllowed =
access > nsContentUtils::StorageAccess::ePrivateBrowsing;
info.mOriginAttributes =
BasePrincipal::Cast(principal)->OriginAttributesRef();
// Default CSP permissions for now. These will be overrided if necessary
// based on the script CSP headers during load in ScriptLoader.
info.mEvalAllowed = true;
info.mReportCSPViolations = false;
info.mSecureContext = aData.isSecureContext()
? WorkerLoadInfo::eSecureContext : WorkerLoadInfo::eInsecureContext;
WorkerPrivate::OverrideLoadInfoLoadGroup(info, info.mLoadingPrincipal);
RefPtr<SharedWorkerInterfaceRequestor> requestor =
new SharedWorkerInterfaceRequestor();
info.mInterfaceRequestor->SetOuterRequestor(requestor);
rv = info.SetPrincipalOnMainThread(info.mPrincipal, info.mLoadGroup);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
Maybe<ClientInfo> clientInfo;
if (aData.clientInfo().type() == OptionalIPCClientInfo::TIPCClientInfo) {
clientInfo.emplace(ClientInfo(aData.clientInfo().get_IPCClientInfo()));
}
// Top level workers' main script use the document charset for the script
// uri encoding.
rv = ChannelFromScriptURLMainThread(info.mLoadingPrincipal,
info.mBaseURI,
nullptr /* parent document */,
info.mLoadGroup,
aData.originalScriptURL(),
clientInfo,
aData.isSharedWorker()
? nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER
: nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER,
false /* default encoding */,
getter_AddRefs(info.mChannel));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
AutoJSAPI jsapi;
jsapi.Init();
ErrorResult error;
mWorkerPrivate = WorkerPrivate::Constructor(jsapi.cx(),
aData.originalScriptURL(),
false,
aData.isSharedWorker()
? WorkerTypeShared
: WorkerTypeService,
aData.name(),
VoidCString(),
&info, error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
RefPtr<InitializeWorkerRunnable> runnable =
new InitializeWorkerRunnable(mWorkerPrivate, this);
if (NS_WARN_IF(!runnable->Dispatch())) {
return NS_ERROR_FAILURE;
}
mWorkerPrivate->SetRemoteWorkerController(this);
return NS_OK;
}
void
RemoteWorkerChild::InitializeOnWorker(WorkerPrivate* aWorkerPrivate)
{
MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread();
RefPtr<RemoteWorkerChild> self = this;
mWorkerRef = WeakWorkerRef::Create(mWorkerPrivate, [self]() {
self->ShutdownOnWorker();
});
if (NS_WARN_IF(!mWorkerRef)) {
CreationFailedOnAnyThread();
ShutdownOnWorker();
return;
}
CreationSucceededOnAnyThread();
}
void
RemoteWorkerChild::ShutdownOnWorker()
{
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
// This will release the worker.
mWorkerRef = nullptr;
nsCOMPtr<nsIEventTarget> target =
SystemGroup::EventTargetFor(TaskCategory::Other);
NS_ProxyRelease("RemoteWorkerChild::mWorkerPrivate",
target, mWorkerPrivate.forget());
RefPtr<RemoteWorkerChild> self = this;
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("RemoteWorkerChild::ShutdownOnWorker",
[self]() {
self->WorkerTerminated();
});
RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
void
RemoteWorkerChild::WorkerTerminated()
{
MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
mWorkerState = eTerminated;
mPendingOps.Clear();
if (!mIPCActive) {
return;
}
Unused << SendClose();
mIPCActive = false;
}
void
RemoteWorkerChild::ErrorPropagationDispatch(nsresult aError)
{
MOZ_ASSERT(NS_FAILED(aError));
RefPtr<RemoteWorkerChild> self = this;
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("RemoteWorkerChild::ErrorPropagationDispatch",
[self, aError]() {
self->ErrorPropagation(aError);
});
RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
void
RemoteWorkerChild::ErrorPropagationOnMainThread(const WorkerErrorReport* aReport,
bool aIsErrorEvent)
{
MOZ_ASSERT(NS_IsMainThread());
ErrorValue value;
if (aIsErrorEvent) {
nsTArray<ErrorDataNote> notes;
for (size_t i = 0, len = aReport->mNotes.Length(); i < len; i++) {
const WorkerErrorNote& note = aReport->mNotes.ElementAt(i);
notes.AppendElement(ErrorDataNote(note.mLineNumber, note.mColumnNumber,
note.mMessage, note.mFilename));
}
ErrorData data(aReport->mLineNumber,
aReport->mColumnNumber,
aReport->mFlags,
aReport->mMessage,
aReport->mFilename,
aReport->mLine,
notes);
value = data;
} else {
value = void_t();
}
RefPtr<RemoteWorkerChild> self = this;
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("RemoteWorkerChild::ErrorPropagationOnMainThread",
[self, value]() {
self->ErrorPropagation(value);
});
RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
void
RemoteWorkerChild::ErrorPropagation(const ErrorValue& aValue)
{
MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
if (!mIPCActive) {
return;
}
Unused << SendError(aValue);
}
void
RemoteWorkerChild::CloseWorkerOnMainThread()
{
MOZ_ASSERT(NS_IsMainThread());
if (mWorkerState == ePending) {
mWorkerState = ePendingTerminated;
// Already released.
return;
}
// The holder will be notified by this.
if (mWorkerState == eRunning) {
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->Cancel();
}
}
void
RemoteWorkerChild::FlushReportsOnMainThread(nsIConsoleReportCollector* aReporter)
{
MOZ_ASSERT(NS_IsMainThread());
bool reportErrorToBrowserConsole = true;
// Flush the reports.
for (uint32_t i = 0, len = mWindowIDs.Length(); i < len; ++i) {
aReporter->FlushReportsToConsole(mWindowIDs[i],
nsIConsoleReportCollector::ReportAction::Save);
reportErrorToBrowserConsole = false;
}
// Finally report to browser console if there is no any window.
if (reportErrorToBrowserConsole) {
aReporter->FlushReportsToConsole(0);
return;
}
aReporter->ClearConsoleReports();
}
IPCResult
RemoteWorkerChild::RecvExecOp(const RemoteWorkerOp& aOp)
{
if (!mIPCActive) {
return IPC_OK();
}
// The worker is not ready yet.
if (mWorkerState == ePending) {
mPendingOps.AppendElement(aOp);
return IPC_OK();
}
if (mWorkerState == eTerminated || mWorkerState == ePendingTerminated) {
// No op.
return IPC_OK();
}
MOZ_ASSERT(mWorkerState == eRunning);
// Main-thread operations
if (aOp.type() == RemoteWorkerOp::TRemoteWorkerSuspendOp ||
aOp.type() == RemoteWorkerOp::TRemoteWorkerResumeOp ||
aOp.type() == RemoteWorkerOp::TRemoteWorkerFreezeOp ||
aOp.type() == RemoteWorkerOp::TRemoteWorkerThawOp ||
aOp.type() == RemoteWorkerOp::TRemoteWorkerTerminateOp ||
aOp.type() == RemoteWorkerOp::TRemoteWorkerAddWindowIDOp ||
aOp.type() == RemoteWorkerOp::TRemoteWorkerRemoveWindowIDOp) {
RefPtr<RemoteWorkerChild> self = this;
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("RemoteWorkerChild::RecvExecOp",
[self, aOp]() {
self->RecvExecOpOnMainThread(aOp);
});
nsCOMPtr<nsIEventTarget> target =
SystemGroup::EventTargetFor(TaskCategory::Other);
target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
return IPC_OK();
}
if (aOp.type() == RemoteWorkerOp::TRemoteWorkerPortIdentifierOp) {
const RemoteWorkerPortIdentifierOp& op =
aOp.get_RemoteWorkerPortIdentifierOp();
RefPtr<MessagePortIdentifierRunnable> runnable =
new MessagePortIdentifierRunnable(mWorkerPrivate, this,
op.portIdentifier());
if (NS_WARN_IF(!runnable->Dispatch())) {
ErrorPropagation(NS_ERROR_FAILURE);
}
return IPC_OK();
}
MOZ_CRASH("Unknown operation.");
return IPC_OK();
}
void
RemoteWorkerChild::RecvExecOpOnMainThread(const RemoteWorkerOp& aOp)
{
MOZ_ASSERT(NS_IsMainThread());
if (aOp.type() == RemoteWorkerOp::TRemoteWorkerSuspendOp) {
if (mWorkerPrivate) {
mWorkerPrivate->ParentWindowPaused();
}
return;
}
if (aOp.type() == RemoteWorkerOp::TRemoteWorkerResumeOp) {
if (mWorkerPrivate) {
mWorkerPrivate->ParentWindowResumed();
}
return;
}
if (aOp.type() == RemoteWorkerOp::TRemoteWorkerFreezeOp) {
if (mWorkerPrivate) {
mWorkerPrivate->Freeze(nullptr);
}
return;
}
if (aOp.type() == RemoteWorkerOp::TRemoteWorkerThawOp) {
if (mWorkerPrivate) {
mWorkerPrivate->Thaw(nullptr);
}
return;
}
if (aOp.type() == RemoteWorkerOp::TRemoteWorkerTerminateOp) {
CloseWorkerOnMainThread();
return;
}
if (aOp.type() == RemoteWorkerOp::TRemoteWorkerAddWindowIDOp) {
mWindowIDs.AppendElement(aOp.get_RemoteWorkerAddWindowIDOp().windowID());
return;
}
if (aOp.type() == RemoteWorkerOp::TRemoteWorkerRemoveWindowIDOp) {
mWindowIDs.RemoveElement(aOp.get_RemoteWorkerRemoveWindowIDOp().windowID());
return;
}
MOZ_CRASH("No other operations should be scheduled on main-thread.");
}
void
RemoteWorkerChild::AddPortIdentifier(JSContext* aCx,
WorkerPrivate* aWorkerPrivate,
const MessagePortIdentifier& aPortIdentifier)
{
if (NS_WARN_IF(!aWorkerPrivate->ConnectMessagePort(aCx, aPortIdentifier))) {
ErrorPropagationDispatch(NS_ERROR_FAILURE);
}
}
void
RemoteWorkerChild::CreationSucceededOnAnyThread()
{
RefPtr<RemoteWorkerChild> self = this;
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("RemoteWorkerChild::CreationSucceededOnAnyThread",
[self]() {
self->CreationSucceeded();
});
RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
void
RemoteWorkerChild::CreationSucceeded()
{
MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
// The worker is created but we need to terminate it already.
if (mWorkerState == ePendingTerminated) {
RefPtr<RemoteWorkerChild> self = this;
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("RemoteWorkerChild::CreationSucceeded",
[self]() {
self->CloseWorkerOnMainThread();
});
nsCOMPtr<nsIEventTarget> target =
SystemGroup::EventTargetFor(TaskCategory::Other);
target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
return;
}
mWorkerState = eRunning;
if (!mIPCActive) {
return;
}
for (const RemoteWorkerOp& op : mPendingOps) {
RecvExecOp(op);
}
mPendingOps.Clear();
Unused << SendCreated(true);
}
void
RemoteWorkerChild::CreationFailedOnAnyThread()
{
RefPtr<RemoteWorkerChild> self = this;
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("RemoteWorkerChild::CreationFailedOnAnyThread",
[self]() {
self->CreationFailed();
});
RemoteWorkerService::Thread()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
void
RemoteWorkerChild::CreationFailed()
{
MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread());
mWorkerState = eTerminated;
mPendingOps.Clear();
if (!mIPCActive) {
return;
}
Unused << SendCreated(false);
}
} // dom namespace
} // mozilla namespace

Просмотреть файл

@ -8,15 +8,117 @@
#define mozilla_dom_RemoteWorkerChild_h
#include "mozilla/dom/PRemoteWorkerChild.h"
#include "mozilla/UniquePtr.h"
#include "nsISupportsImpl.h"
class nsIConsoleReportCollector;
namespace mozilla {
namespace dom {
class RemoteWorkerData;
class WeakWorkerRef;
class WorkerErrorReport;
class WorkerPrivate;
class OptionalMessagePortIdentifier;
class RemoteWorkerChild final : public PRemoteWorkerChild
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteWorkerChild)
RemoteWorkerChild();
void
ExecWorker(const RemoteWorkerData& aData);
void
InitializeOnWorker(WorkerPrivate* aWorkerPrivate);
void
ShutdownOnWorker();
void
AddPortIdentifier(JSContext* aCx,
WorkerPrivate* aWorkerPrivate,
const MessagePortIdentifier& aPortIdentifier);
void
ErrorPropagationOnMainThread(const WorkerErrorReport* aReport,
bool aIsErrorEvent);
void
CloseWorkerOnMainThread();
void
FlushReportsOnMainThread(nsIConsoleReportCollector* aReporter);
private:
class InitializeWorkerRunnable;
~RemoteWorkerChild();
void
ActorDestroy(ActorDestroyReason aWhy) override;
mozilla::ipc::IPCResult
RecvExecOp(const RemoteWorkerOp& aOp) override;
void
RecvExecOpOnMainThread(const RemoteWorkerOp& aOp);
nsresult
ExecWorkerOnMainThread(const RemoteWorkerData& aData);
void
ErrorPropagation(const ErrorValue& aValue);
void
ErrorPropagationDispatch(nsresult aError);
void
CreationSucceededOnAnyThread();
void
CreationSucceeded();
void
CreationFailedOnAnyThread();
void
CreationFailed();
void
WorkerTerminated();
// Touched on main-thread only.
nsTArray<uint64_t> mWindowIDs;
RefPtr<WorkerPrivate> mWorkerPrivate;
RefPtr<WeakWorkerRef> mWorkerRef;
bool mIPCActive;
enum WorkerState
{
// CreationSucceeded/CreationFailed not called yet.
ePending,
// The worker is not created yet, but we want to terminate as soon as
// possible.
ePendingTerminated,
// Worker up and running.
eRunning,
// Worker terminated.
eTerminated,
};
// Touched only on the owning thread (PBackground).
WorkerState mWorkerState;
// Touched only on the owning thread (PBackground).
nsTArray<RemoteWorkerOp> mPendingOps;
};
} // dom namespace

Просмотреть файл

@ -4,9 +4,12 @@
* 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 "mozilla/dom/MessagePort.h"
#include "mozilla/dom/MessagePortParent.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "RemoteWorkerController.h"
#include "RemoteWorkerManager.h"
#include "RemoteWorkerParent.h"
namespace mozilla {
@ -15,20 +18,17 @@ using namespace ipc;
namespace dom {
/* static */ already_AddRefed<RemoteWorkerController>
RemoteWorkerController::Create()
RemoteWorkerController::Create(const RemoteWorkerData& aData)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
RefPtr<RemoteWorkerController> controller = new RemoteWorkerController();
// This will be populated, eventually.
RemoteWorkerData data;
RefPtr<RemoteWorkerManager> manager = RemoteWorkerManager::GetOrCreate();
MOZ_ASSERT(manager);
manager->Launch(controller, data);
manager->Launch(controller, aData);
return controller.forget();
}
@ -62,10 +62,11 @@ RemoteWorkerController::CreationFailed()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(mActor);
MOZ_ASSERT(mState == ePending || mState == eTerminated);
mState = eTerminated;
mActor = nullptr;
// TODO: maybe notification?
Shutdown();
}
void
@ -73,11 +74,260 @@ RemoteWorkerController::CreationSucceeded()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(mActor);
MOZ_ASSERT(mState == ePending || mState == eTerminated);
if (mState == eTerminated) {
MOZ_ASSERT(!mActor);
MOZ_ASSERT(mPendingOps.IsEmpty());
// Nothing to do.
return;
}
MOZ_ASSERT(mActor);
mState = eReady;
// TODO: flush the pending op queue.
// TODO: maybe notification?
for (UniquePtr<Op>& op : mPendingOps) {
switch (op->mType) {
case Op::eTerminate:
Terminate();
break;
case Op::eSuspend:
Suspend();
break;
case Op::eResume:
Resume();
break;
case Op::eFreeze:
Freeze();
break;
case Op::eThaw:
Thaw();
break;
case Op::ePortIdentifier:
AddPortIdentifier(op->mPortIdentifier);
break;
case Op::eAddWindowID:
AddWindowID(op->mWindowID);
break;
case Op::eRemoveWindowID:
RemoveWindowID(op->mWindowID);
break;
default:
MOZ_CRASH("Unknown op.");
}
op->Completed();
}
mPendingOps.Clear();
}
void
RemoteWorkerController::ErrorPropagation(const ErrorValue& aValue)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
// TODO: error propagation
}
void
RemoteWorkerController::WorkerTerminated()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(mState == eReady);
// TODO: worker terminated
Shutdown();
}
void
RemoteWorkerController::Shutdown()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(mState == ePending || mState == eReady);
mState = eTerminated;
mPendingOps.Clear();
if (mActor) {
mActor->SetController(nullptr);
Unused << mActor->SendExecOp(RemoteWorkerTerminateOp());
mActor = nullptr;
}
}
void
RemoteWorkerController::AddWindowID(uint64_t aWindowID)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(aWindowID);
if (mState == ePending) {
mPendingOps.AppendElement(new Op(Op::eAddWindowID, aWindowID));
return;
}
if (mState == eTerminated) {
return;
}
MOZ_ASSERT(mState == eReady);
Unused << mActor->SendExecOp(RemoteWorkerAddWindowIDOp(aWindowID));
}
void
RemoteWorkerController::RemoveWindowID(uint64_t aWindowID)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(aWindowID);
if (mState == ePending) {
mPendingOps.AppendElement(new Op(Op::eRemoveWindowID, aWindowID));
return;
}
if (mState == eTerminated) {
return;
}
MOZ_ASSERT(mState == eReady);
Unused << mActor->SendExecOp(RemoteWorkerRemoveWindowIDOp(aWindowID));
}
void
RemoteWorkerController::AddPortIdentifier(const MessagePortIdentifier& aPortIdentifier)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
if (mState == ePending) {
mPendingOps.AppendElement(new Op(aPortIdentifier));
return;
}
if (mState == eTerminated) {
return;
}
MOZ_ASSERT(mState == eReady);
Unused << mActor->SendExecOp(RemoteWorkerPortIdentifierOp(aPortIdentifier));
}
void
RemoteWorkerController::Terminate()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
if (mState == eTerminated) {
return;
}
Shutdown();
}
void
RemoteWorkerController::Suspend()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
if (mState == ePending) {
mPendingOps.AppendElement(new Op(Op::eSuspend));
return;
}
if (mState == eTerminated) {
return;
}
MOZ_ASSERT(mState == eReady);
Unused << mActor->SendExecOp(RemoteWorkerSuspendOp());
}
void
RemoteWorkerController::Resume()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
if (mState == ePending) {
mPendingOps.AppendElement(new Op(Op::eResume));
return;
}
if (mState == eTerminated) {
return;
}
MOZ_ASSERT(mState == eReady);
Unused << mActor->SendExecOp(RemoteWorkerResumeOp());
}
void
RemoteWorkerController::Freeze()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
if (mState == ePending) {
mPendingOps.AppendElement(new Op(Op::eFreeze));
return;
}
if (mState == eTerminated) {
return;
}
MOZ_ASSERT(mState == eReady);
Unused << mActor->SendExecOp(RemoteWorkerFreezeOp());
}
void
RemoteWorkerController::Thaw()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
if (mState == ePending) {
mPendingOps.AppendElement(new Op(Op::eThaw));
return;
}
if (mState == eTerminated) {
return;
}
MOZ_ASSERT(mState == eReady);
Unused << mActor->SendExecOp(RemoteWorkerThawOp());
}
RemoteWorkerController::Op::~Op()
{
MOZ_COUNT_DTOR(Op);
// We don't want to leak the port if the operation has not been processed.
if (!mCompleted && mType == ePortIdentifier) {
MessagePortParent::ForceClose(mPortIdentifier.uuid(),
mPortIdentifier.destinationUuid(),
mPortIdentifier.sequenceId());
}
}
} // dom namespace

Просмотреть файл

@ -78,6 +78,8 @@ namespace dom {
* In case there were pending operations, they are now executed.
*/
class ErrorValue;
class MessagePortIdentifier;
class RemoteWorkerManager;
class RemoteWorkerParent;
@ -90,7 +92,31 @@ public:
NS_INLINE_DECL_REFCOUNTING(RemoteWorkerController)
static already_AddRefed<RemoteWorkerController>
Create(); // TODO parameters?
Create(const RemoteWorkerData& aData);
void
AddWindowID(uint64_t aWindowID);
void
RemoveWindowID(uint64_t aWindowID);
void
AddPortIdentifier(const MessagePortIdentifier& aPortIdentifier);
void
Terminate();
void
Suspend();
void
Resume();
void
Freeze();
void
Thaw();
private:
RemoteWorkerController();
@ -99,6 +125,15 @@ private:
void
SetWorkerActor(RemoteWorkerParent* aActor);
void
ErrorPropagation(const ErrorValue& aValue);
void
WorkerTerminated();
void
Shutdown();
void
CreationFailed();
@ -112,6 +147,55 @@ private:
} mState;
RefPtr<RemoteWorkerParent> mActor;
struct Op {
enum Type {
eTerminate,
eSuspend,
eResume,
eFreeze,
eThaw,
ePortIdentifier,
eAddWindowID,
eRemoveWindowID,
};
explicit Op(Type aType, uint64_t aWindowID = 0)
: mType(aType)
, mWindowID(aWindowID)
, mCompleted(false)
{
MOZ_COUNT_CTOR(Op);
}
explicit Op(const MessagePortIdentifier& aPortIdentifier)
: mType(ePortIdentifier)
, mPortIdentifier(aPortIdentifier)
, mCompleted(false)
{
MOZ_COUNT_CTOR(Op);
}
// This object cannot be copied.
Op(Op const&) = delete;
Op& operator=(Op const&) = delete;
~Op();
void
Completed()
{
mCompleted = true;
}
Type mType;
MessagePortIdentifier mPortIdentifier;
uint64_t mWindowID;
bool mCompleted;
};
nsTArray<UniquePtr<Op>> mPendingOps;
};
} // dom namespace

Просмотреть файл

@ -7,6 +7,7 @@
#include "RemoteWorkerParent.h"
#include "RemoteWorkerController.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/Unused.h"
namespace mozilla {
@ -54,6 +55,33 @@ RemoteWorkerParent::RecvCreated(const bool& aStatus)
return IPC_OK();
}
IPCResult
RemoteWorkerParent::RecvError(const ErrorValue& aValue)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
if (mController) {
mController->ErrorPropagation(aValue);
}
return IPC_OK();
}
IPCResult
RemoteWorkerParent::RecvClose()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
if (mController) {
mController->WorkerTerminated();
}
Unused << Send__delete__(this);
return IPC_OK();
}
void
RemoteWorkerParent::SetController(RemoteWorkerController* aController)
{

Просмотреть файл

@ -30,6 +30,12 @@ private:
void
ActorDestroy(mozilla::ipc::IProtocol::ActorDestroyReason) override;
mozilla::ipc::IPCResult
RecvError(const ErrorValue& aValue) override;
mozilla::ipc::IPCResult
RecvClose() override;
mozilla::ipc::IPCResult
RecvCreated(const bool& aStatus) override;

Просмотреть файл

@ -69,6 +69,15 @@ RemoteWorkerService::Initialize()
sRemoteWorkerService = service;
}
/* static */ nsIThread*
RemoteWorkerService::Thread()
{
StaticMutexAutoLock lock(sRemoteWorkerServiceMutex);
MOZ_ASSERT(sRemoteWorkerService);
MOZ_ASSERT(sRemoteWorkerService->mThread);
return sRemoteWorkerService->mThread;
}
nsresult
RemoteWorkerService::InitializeOnMainThread()
{

Просмотреть файл

@ -27,6 +27,9 @@ public:
static void
Initialize();
static nsIThread*
Thread();
private:
RemoteWorkerService();
~RemoteWorkerService();

Просмотреть файл

@ -2,11 +2,73 @@
* 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 ClientIPCTypes;
include PBackgroundSharedTypes;
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
namespace mozilla {
namespace dom {
struct ContentSecurityPolicy
{
nsString policy;
bool reportOnlyFlag;
bool deliveredViaMetaTagFlag;
};
struct RemoteWorkerData
{
nsString originalScriptURL;
nsCString baseScriptURL;
nsCString resolvedScriptURL;
nsString name;
PrincipalInfo loadingPrincipalInfo;
ContentSecurityPolicy[] loadingPrincipalCsp;
ContentSecurityPolicy[] loadingPrincipalPreloadCsp;
PrincipalInfo principalInfo;
ContentSecurityPolicy[] principalCsp;
ContentSecurityPolicy[] principalPreloadCsp;
nsCString domain;
bool isSecureContext;
OptionalIPCClientInfo clientInfo;
bool isSharedWorker;
};
// ErrorData/ErrorDataNote correspond to WorkerErrorReport/WorkerErrorNote
// which in turn correspond to JSErrorReport/JSErrorNotes which allows JS to
// report complicated errors such as redeclarations that involve multiple
// distinct lines. For more generic error-propagation IPC structures, see bug
// 1357463 on making ErrorResult usable over IPC.
struct ErrorDataNote {
uint32_t lineNumber;
uint32_t columnNumber;
nsString message;
nsString filename;
};
struct ErrorData {
uint32_t lineNumber;
uint32_t columnNumber;
uint32_t flags;
nsString message;
nsString filename;
nsString line;
ErrorDataNote[] notes;
};
union ErrorValue {
nsresult;
ErrorData;
void_t;
};
} // namespace dom

Просмотреть файл

@ -4,7 +4,7 @@
include protocol PBackground;
include SharedWorkerTypes;
include RemoteWorkerTypes;
namespace mozilla {
namespace dom {

Просмотреть файл

@ -14,6 +14,7 @@
#include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/nsCSPUtils.h"
#include "mozilla/dom/PMessagePort.h"
#include "mozilla/dom/RemoteWorkerTypes.h"
#include "mozilla/dom/SharedWorkerBinding.h"
#include "mozilla/dom/SharedWorkerChild.h"
#include "mozilla/dom/WorkerBinding.h"
@ -247,24 +248,25 @@ SharedWorker::Constructor(const GlobalObject& aGlobal,
ipcClientInfo = void_t();
}
SharedWorkerLoadInfo sharedWorkerLoadInfo(nsString(aScriptURL),
baseURL,
resolvedScriptURL,
name,
loadingPrincipalInfo,
loadingPrincipalCSP,
loadingPrincipalPreloadCSP,
principalInfo,
principalCSP,
principalPreloadCSP,
loadInfo.mDomain,
isSecureContext,
loadInfo.mWindowID,
ipcClientInfo,
portIdentifier);
RemoteWorkerData remoteWorkerData(nsString(aScriptURL),
baseURL,
resolvedScriptURL,
name,
loadingPrincipalInfo,
loadingPrincipalCSP,
loadingPrincipalPreloadCSP,
principalInfo,
principalCSP,
principalPreloadCSP,
loadInfo.mDomain,
isSecureContext,
ipcClientInfo,
true /* sharedWorker */);
PSharedWorkerChild* pActor =
actorChild->SendPSharedWorkerConstructor(sharedWorkerLoadInfo);
actorChild->SendPSharedWorkerConstructor(remoteWorkerData,
loadInfo.mWindowID,
portIdentifier);
RefPtr<SharedWorkerChild> actor = static_cast<SharedWorkerChild*>(pActor);
MOZ_ASSERT(actor);

Просмотреть файл

@ -7,103 +7,28 @@
#include "SharedWorkerManager.h"
#include "SharedWorkerParent.h"
#include "SharedWorkerService.h"
#include "mozilla/dom/IndexedDatabaseManager.h"
#include "mozilla/dom/PSharedWorker.h"
#include "mozilla/dom/ServiceWorkerInterceptController.h"
#include "mozilla/dom/WorkerError.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRunnable.h"
#include "mozilla/dom/workerinternals/ScriptLoader.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/dom/RemoteWorkerController.h"
#include "nsIConsoleReportCollector.h"
#include "nsINetworkInterceptController.h"
#include "nsIPrincipal.h"
#include "nsNetUtil.h"
#include "nsProxyRelease.h"
namespace mozilla {
namespace dom {
using workerinternals::ChannelFromScriptURLMainThread;
namespace {
class MessagePortRunnable final : public WorkerRunnable
{
MessagePortIdentifier mPortIdentifier;
public:
MessagePortRunnable(WorkerPrivate* aWorkerPrivate,
const MessagePortIdentifier& aPortIdentifier)
: WorkerRunnable(aWorkerPrivate)
, mPortIdentifier(aPortIdentifier)
{}
private:
~MessagePortRunnable() = default;
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
return aWorkerPrivate->ConnectMessagePort(aCx, mPortIdentifier);
}
nsresult
Cancel() override
{
MessagePort::ForceClose(mPortIdentifier);
return WorkerRunnable::Cancel();
}
};
class SharedWorkerInterfaceRequestor final : public nsIInterfaceRequestor
{
public:
NS_DECL_ISUPPORTS
SharedWorkerInterfaceRequestor()
: mSWController(new ServiceWorkerInterceptController())
{}
NS_IMETHOD
GetInterface(const nsIID& aIID, void** aSink) override
{
MOZ_ASSERT(NS_IsMainThread());
if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController))) {
// If asked for the network intercept controller, ask the outer requestor,
// which could be the docshell.
RefPtr<ServiceWorkerInterceptController> swController = mSWController;
swController.forget(aSink);
return NS_OK;
}
return NS_NOINTERFACE;
}
private:
~SharedWorkerInterfaceRequestor() = default;
RefPtr<ServiceWorkerInterceptController> mSWController;
};
NS_IMPL_ADDREF(SharedWorkerInterfaceRequestor)
NS_IMPL_RELEASE(SharedWorkerInterfaceRequestor)
NS_IMPL_QUERY_INTERFACE(SharedWorkerInterfaceRequestor, nsIInterfaceRequestor)
} // anonymous
SharedWorkerManager::SharedWorkerManager(nsIEventTarget* aPBackgroundEventTarget,
const SharedWorkerLoadInfo& aInfo,
nsIPrincipal* aPrincipal,
const RemoteWorkerData& aData,
nsIPrincipal* aLoadingPrincipal)
: mPBackgroundEventTarget(aPBackgroundEventTarget)
, mInfo(aInfo)
, mPrincipal(aPrincipal)
, mLoadingPrincipal(aLoadingPrincipal)
, mDomain(aData.domain())
, mResolvedScriptURL(aData.resolvedScriptURL())
, mName(aData.name())
, mIsSecureContext(aData.isSecureContext())
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aLoadingPrincipal);
}
@ -112,124 +37,32 @@ SharedWorkerManager::~SharedWorkerManager()
nsCOMPtr<nsIEventTarget> target =
SystemGroup::EventTargetFor(TaskCategory::Other);
NS_ProxyRelease("SharedWorkerManager::mPrincipal",
target, mPrincipal.forget());
NS_ProxyRelease("SharedWorkerManager::mLoadingPrincipal",
target, mLoadingPrincipal.forget());
NS_ProxyRelease("SharedWorkerManager::mWorkerPrivate",
target, mWorkerPrivate.forget());
NS_ProxyRelease("SharedWorkerManager::mRemoteWorkerController",
mPBackgroundEventTarget, mRemoteWorkerController.forget());
}
nsresult
SharedWorkerManager::CreateWorkerOnMainThread()
bool
SharedWorkerManager::MaybeCreateRemoteWorker(const RemoteWorkerData& aData,
uint64_t aWindowID,
const MessagePortIdentifier& aPortIdentifier)
{
MOZ_ASSERT(NS_IsMainThread());
AssertIsOnBackgroundThread();
// Ensure that the IndexedDatabaseManager is initialized
Unused << NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate());
WorkerLoadInfo info;
nsresult rv = NS_NewURI(getter_AddRefs(info.mBaseURI),
mInfo.baseScriptURL(),
nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
if (!mRemoteWorkerController) {
mRemoteWorkerController = RemoteWorkerController::Create(aData);
if (NS_WARN_IF(!mRemoteWorkerController)) {
return false;
}
}
rv = NS_NewURI(getter_AddRefs(info.mResolvedScriptURI),
mInfo.resolvedScriptURL(), nullptr, info.mBaseURI);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
if (aWindowID) {
mRemoteWorkerController->AddWindowID(aWindowID);
}
info.mPrincipalInfo = new PrincipalInfo();
rv = PrincipalToPrincipalInfo(mPrincipal, info.mPrincipalInfo);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
info.mResolvedScriptURI = info.mBaseURI;
info.mDomain = mInfo.domain();
info.mPrincipal = mPrincipal;
info.mLoadingPrincipal = mLoadingPrincipal;
nsContentUtils::StorageAccess access =
nsContentUtils::StorageAllowedForPrincipal(info.mPrincipal);
info.mStorageAllowed =
access > nsContentUtils::StorageAccess::ePrivateBrowsing;
info.mOriginAttributes =
BasePrincipal::Cast(mPrincipal)->OriginAttributesRef();
// Default CSP permissions for now. These will be overrided if necessary
// based on the script CSP headers during load in ScriptLoader.
info.mEvalAllowed = true;
info.mReportCSPViolations = false;
info.mSecureContext = mInfo.isSecureContext()
? WorkerLoadInfo::eSecureContext : WorkerLoadInfo::eInsecureContext;
WorkerPrivate::OverrideLoadInfoLoadGroup(info, info.mLoadingPrincipal);
RefPtr<SharedWorkerInterfaceRequestor> requestor =
new SharedWorkerInterfaceRequestor();
info.mInterfaceRequestor->SetOuterRequestor(requestor);
rv = info.SetPrincipalOnMainThread(info.mPrincipal, info.mLoadGroup);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
Maybe<ClientInfo> clientInfo;
if (mInfo.clientInfo().type() == OptionalIPCClientInfo::TIPCClientInfo) {
clientInfo.emplace(ClientInfo(mInfo.clientInfo().get_IPCClientInfo()));
}
// Top level workers' main script use the document charset for the script
// uri encoding.
rv = ChannelFromScriptURLMainThread(info.mLoadingPrincipal,
info.mBaseURI,
nullptr /* parent document */,
info.mLoadGroup,
mInfo.originalScriptURL(),
clientInfo,
nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER,
false /* default encoding */,
getter_AddRefs(info.mChannel));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
AutoJSAPI jsapi;
jsapi.Init();
ErrorResult error;
mWorkerPrivate = WorkerPrivate::Constructor(jsapi.cx(),
mInfo.originalScriptURL(),
false,
WorkerTypeShared,
mInfo.name(),
VoidCString(),
&info, error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
mWorkerPrivate->SetSharedWorkerManager(this);
return NS_OK;
}
nsresult
SharedWorkerManager::ConnectPortOnMainThread(const MessagePortIdentifier& aPortIdentifier)
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<MessagePortRunnable> runnable =
new MessagePortRunnable(mWorkerPrivate, aPortIdentifier);
if (NS_WARN_IF(!runnable->Dispatch())) {
return NS_ERROR_FAILURE;
}
return NS_OK;
mRemoteWorkerController->AddPortIdentifier(aPortIdentifier);
return true;
}
bool
@ -239,9 +72,9 @@ SharedWorkerManager::MatchOnMainThread(const nsACString& aDomain,
nsIPrincipal* aLoadingPrincipal) const
{
MOZ_ASSERT(NS_IsMainThread());
return aDomain == mInfo.domain() &&
aScriptURL == mInfo.resolvedScriptURL() &&
aName == mInfo.name() &&
return aDomain == mDomain &&
aScriptURL == mResolvedScriptURL &&
aName == mName &&
// We want to be sure that the window's principal subsumes the
// SharedWorker's loading principal and vice versa.
mLoadingPrincipal->Subsumes(aLoadingPrincipal) &&
@ -255,7 +88,21 @@ SharedWorkerManager::AddActor(SharedWorkerParent* aParent)
MOZ_ASSERT(aParent);
MOZ_ASSERT(!mActors.Contains(aParent));
uint32_t frozen = 0;
for (SharedWorkerParent* actor : mActors) {
if (actor->IsFrozen()) {
++frozen;
}
}
bool hadActors = !mActors.IsEmpty();
mActors.AppendElement(aParent);
if (hadActors && frozen == mActors.Length() - 1) {
mRemoteWorkerController->Thaw();
}
}
void
@ -265,6 +112,11 @@ SharedWorkerManager::RemoveActor(SharedWorkerParent* aParent)
MOZ_ASSERT(aParent);
MOZ_ASSERT(mActors.Contains(aParent));
uint64_t windowID = aParent->WindowID();
if (windowID) {
mRemoteWorkerController->RemoveWindowID(windowID);
}
mActors.RemoveElement(aParent);
if (!mActors.IsEmpty()) {
@ -273,16 +125,8 @@ SharedWorkerManager::RemoveActor(SharedWorkerParent* aParent)
// Time to go.
RefPtr<SharedWorkerManager> self = this;
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("SharedWorkerManager::RemoveActor",
[self]() {
self->CloseOnMainThread();
});
nsCOMPtr<nsIEventTarget> target =
SystemGroup::EventTargetFor(TaskCategory::Other);
target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
mRemoteWorkerController->Terminate();
mRemoteWorkerController = nullptr;
// SharedWorkerService exists because it is kept alive by SharedWorkerParent.
SharedWorkerService::Get()->RemoveWorkerManager(this);
@ -292,6 +136,7 @@ void
SharedWorkerManager::UpdateSuspend()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mRemoteWorkerController);
uint32_t suspended = 0;
@ -305,26 +150,18 @@ SharedWorkerManager::UpdateSuspend()
return;
}
RefPtr<SharedWorkerManager> self = this;
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("SharedWorkerManager::UpdateSuspend",
[self, suspended]() {
if (suspended) {
self->SuspendOnMainThread();
} else {
self->ResumeOnMainThread();
}
});
nsCOMPtr<nsIEventTarget> target =
SystemGroup::EventTargetFor(TaskCategory::Other);
target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
if (suspended) {
mRemoteWorkerController->Suspend();
} else {
mRemoteWorkerController->Resume();
}
}
void
SharedWorkerManager::UpdateFrozen()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mRemoteWorkerController);
uint32_t frozen = 0;
@ -338,94 +175,20 @@ SharedWorkerManager::UpdateFrozen()
return;
}
RefPtr<SharedWorkerManager> self = this;
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("SharedWorkerManager::UpdateFrozen",
[self, frozen]() {
if (frozen) {
self->FreezeOnMainThread();
} else {
self->ThawOnMainThread();
}
});
nsCOMPtr<nsIEventTarget> target =
SystemGroup::EventTargetFor(TaskCategory::Other);
target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
if (frozen) {
mRemoteWorkerController->Freeze();
} else {
mRemoteWorkerController->Thaw();
}
}
bool
SharedWorkerManager::IsSecureContext() const
{
return mInfo.isSecureContext();
}
void
SharedWorkerManager::FreezeOnMainThread()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mWorkerPrivate || mWorkerPrivate->IsFrozen()) {
// Already released.
return;
}
mWorkerPrivate->Freeze(nullptr);
}
void
SharedWorkerManager::ThawOnMainThread()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mWorkerPrivate || !mWorkerPrivate->IsFrozen()) {
// Already released.
return;
}
mWorkerPrivate->Thaw(nullptr);
}
void
SharedWorkerManager::SuspendOnMainThread()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mWorkerPrivate) {
// Already released.
return;
}
mWorkerPrivate->ParentWindowPaused();
}
void
SharedWorkerManager::ResumeOnMainThread()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mWorkerPrivate) {
// Already released.
return;
}
mWorkerPrivate->ParentWindowResumed();
}
void
SharedWorkerManager::CloseOnMainThread()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mWorkerPrivate) {
// Already released.
return;
}
mWorkerPrivate->Cancel();
mWorkerPrivate = nullptr;
return mIsSecureContext;
}
/* TODO
void
SharedWorkerManager::BroadcastErrorToActorsOnMainThread(const WorkerErrorReport* aReport,
bool aIsErrorEvent)
@ -530,6 +293,7 @@ SharedWorkerManager::FlushReportsToActorsOnMainThread(nsIConsoleReportCollector*
aReporter->ClearConsoleReports();
}
*/
} // dom namespace
} // mozilla namespace

Просмотреть файл

@ -7,21 +7,18 @@
#ifndef mozilla_dom_SharedWorkerManager_h
#define mozilla_dom_SharedWorkerManager_h
#include "mozilla/dom/SharedWorkerTypes.h"
#include "nsISupportsImpl.h"
#include "nsTArray.h"
class nsIConsoleReportCollector;
class nsIPrincipal;
namespace mozilla {
namespace dom {
class ErrorValue;
class SharedWorkerLoadInfo;
class MessagePortIdentifier;
class RemoteWorkerData;
class RemoteWorkerController;
class SharedWorkerParent;
class WorkerErrorReport;
class WorkerPrivate;
class SharedWorkerManager final
{
@ -31,49 +28,22 @@ public:
// Called on main-thread thread methods
SharedWorkerManager(nsIEventTarget* aPBackgroundEventTarget,
const SharedWorkerLoadInfo& aInfo,
nsIPrincipal* aPrincipal,
const RemoteWorkerData& aData,
nsIPrincipal* aLoadingPrincipal);
nsresult
CreateWorkerOnMainThread();
nsresult
ConnectPortOnMainThread(const MessagePortIdentifier& aPortIdentifier);
bool
MatchOnMainThread(const nsACString& aDomain,
const nsACString& aScriptURL,
const nsAString& aName,
nsIPrincipal* aLoadingPrincipal) const;
void
CloseOnMainThread();
void
FreezeOnMainThread();
void
ThawOnMainThread();
void
SuspendOnMainThread();
void
ResumeOnMainThread();
void
BroadcastErrorToActorsOnMainThread(const WorkerErrorReport* aReport,
bool aIsErrorEvent);
void
CloseActorsOnMainThread();
void
FlushReportsToActorsOnMainThread(nsIConsoleReportCollector* aReporter);
// Called on PBackground thread methods
bool
MaybeCreateRemoteWorker(const RemoteWorkerData& aData,
uint64_t aWindowID,
const MessagePortIdentifier& aPortIdentifier);
void
AddActor(SharedWorkerParent* aParent);
@ -89,27 +59,21 @@ public:
bool
IsSecureContext() const;
void
CloseActors();
void
BroadcastErrorToActors(const ErrorValue& aValue);
private:
~SharedWorkerManager();
nsCOMPtr<nsIEventTarget> mPBackgroundEventTarget;
SharedWorkerLoadInfo mInfo;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
nsCString mDomain;
nsCString mResolvedScriptURL;
nsString mName;
bool mIsSecureContext;
// Raw pointers because SharedWorkerParent unregisters itself in ActorDestroy().
nsTArray<SharedWorkerParent*> mActors;
// With this patch, SharedWorker are executed on the parent process.
// This is going to change in the following parts.
RefPtr<WorkerPrivate> mWorkerPrivate;
RefPtr<RemoteWorkerController> mRemoteWorkerController;
};
} // dom namespace

Просмотреть файл

@ -7,6 +7,7 @@
#include "SharedWorkerParent.h"
#include "SharedWorkerManager.h"
#include "SharedWorkerService.h"
#include "mozilla/dom/RemoteWorkerTypes.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/Unused.h"
@ -20,7 +21,6 @@ namespace dom {
SharedWorkerParent::SharedWorkerParent()
: mBackgroundEventTarget(GetCurrentThreadEventTarget())
, mStatus(eInit)
, mWindowID(0)
, mSuspended(false)
, mFrozen(false)
{
@ -41,7 +41,9 @@ SharedWorkerParent::ActorDestroy(IProtocol::ActorDestroyReason aReason)
}
void
SharedWorkerParent::Initialize(const SharedWorkerLoadInfo& aInfo)
SharedWorkerParent::Initialize(const RemoteWorkerData& aData,
uint64_t aWindowID,
const MessagePortIdentifier& aPortIdentifier)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mStatus == eInit);
@ -50,11 +52,10 @@ SharedWorkerParent::Initialize(const SharedWorkerLoadInfo& aInfo)
mService = SharedWorkerService::GetOrCreate();
MOZ_ASSERT(mService);
// This is the only information we currently care.
mWindowID = aInfo.windowID();
mWindowID = aWindowID;
mStatus = ePending;
mService->GetOrCreateWorkerManager(this, aInfo);
mService->GetOrCreateWorkerManager(this, aData, aWindowID, aPortIdentifier);
}
IPCResult

Просмотреть файл

@ -14,7 +14,8 @@
namespace mozilla {
namespace dom {
class SharedWorkerLoadInfo;
class MessagePortIdentifier;
class RemoteWorkerData;
class SharedWorkerManager;
class SharedWorkerService;
@ -26,7 +27,9 @@ public:
SharedWorkerParent();
void
Initialize(const SharedWorkerLoadInfo& aInfo);
Initialize(const RemoteWorkerData& aData,
uint64_t aWindowID,
const MessagePortIdentifier& aPortIdentifier);
void
ManagerCreated(SharedWorkerManager* aWorkerManager);

Просмотреть файл

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SharedWorkerService.h"
#include "mozilla/dom/RemoteWorkerTypes.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/SystemGroup.h"
@ -75,11 +76,15 @@ class GetOrCreateWorkerManagerRunnable final : public Runnable
{
public:
GetOrCreateWorkerManagerRunnable(SharedWorkerParent* aActor,
const SharedWorkerLoadInfo& aInfo)
const RemoteWorkerData& aData,
uint64_t aWindowID,
const MessagePortIdentifier& aPortIdentifier)
: Runnable("GetOrCreateWorkerManagerRunnable")
, mBackgroundEventTarget(GetCurrentThreadEventTarget())
, mActor(aActor)
, mInfo(aInfo)
, mData(aData)
, mWindowID(aWindowID)
, mPortIdentifier(aPortIdentifier)
{}
NS_IMETHOD
@ -90,7 +95,8 @@ public:
MOZ_ASSERT(service);
service->GetOrCreateWorkerManagerOnMainThread(mBackgroundEventTarget,
mActor, mInfo);
mActor, mData, mWindowID,
mPortIdentifier);
return NS_OK;
}
@ -98,7 +104,9 @@ public:
private:
nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
RefPtr<SharedWorkerParent> mActor;
SharedWorkerLoadInfo mInfo;
RemoteWorkerData mData;
uint64_t mWindowID;
MessagePortIdentifier mPortIdentifier;
};
class RemoveWorkerManagerRunnable final : public Runnable
@ -130,16 +138,29 @@ class WorkerManagerCreatedRunnable final : public Runnable
{
public:
WorkerManagerCreatedRunnable(SharedWorkerManager* aManager,
SharedWorkerParent* aActor)
SharedWorkerParent* aActor,
const RemoteWorkerData& aData,
uint64_t aWindowID,
const MessagePortIdentifier& aPortIdentifier)
: Runnable("WorkerManagerCreatedRunnable")
, mManager(aManager)
, mActor(aActor)
, mData(aData)
, mWindowID(aWindowID)
, mPortIdentifier(aPortIdentifier)
{}
NS_IMETHOD
Run()
{
AssertIsOnBackgroundThread();
if (NS_WARN_IF(!mManager->MaybeCreateRemoteWorker(mData, mWindowID,
mPortIdentifier))) {
mActor->ErrorPropagation(NS_ERROR_FAILURE);
return NS_OK;
}
mManager->AddActor(mActor);
mActor->ManagerCreated(mManager);
return NS_OK;
@ -148,6 +169,9 @@ public:
private:
RefPtr<SharedWorkerManager> mManager;
RefPtr<SharedWorkerParent> mActor;
RemoteWorkerData mData;
uint64_t mWindowID;
MessagePortIdentifier mPortIdentifier;
};
class ErrorPropagationRunnable final : public Runnable
@ -218,13 +242,16 @@ SharedWorkerService::~SharedWorkerService()
void
SharedWorkerService::GetOrCreateWorkerManager(SharedWorkerParent* aActor,
const SharedWorkerLoadInfo& aInfo)
const RemoteWorkerData& aData,
uint64_t aWindowID,
const MessagePortIdentifier& aPortIdentifier)
{
AssertIsOnBackgroundThread();
// The real check happens on main-thread.
RefPtr<GetOrCreateWorkerManagerRunnable> r =
new GetOrCreateWorkerManagerRunnable(aActor, aInfo);
new GetOrCreateWorkerManagerRunnable(aActor, aData, aWindowID,
aPortIdentifier);
nsCOMPtr<nsIEventTarget> target = SystemGroup::EventTargetFor(TaskCategory::Other);
nsresult rv = target->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
@ -234,7 +261,9 @@ SharedWorkerService::GetOrCreateWorkerManager(SharedWorkerParent* aActor,
void
SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(nsIEventTarget* aBackgroundEventTarget,
SharedWorkerParent* aActor,
const SharedWorkerLoadInfo& aInfo)
const RemoteWorkerData& aData,
uint64_t aWindowID,
const MessagePortIdentifier& aPortIdentifier)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aBackgroundEventTarget);
@ -244,30 +273,30 @@ SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(nsIEventTarget* aBackg
nsresult rv = NS_OK;
nsCOMPtr<nsIPrincipal> principal =
PrincipalInfoToPrincipal(aInfo.principalInfo(), &rv);
PrincipalInfoToPrincipal(aData.principalInfo(), &rv);
if (NS_WARN_IF(!principal)) {
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
return;
}
rv = PopulatePrincipalContentSecurityPolicy(principal,
aInfo.principalCsp(),
aInfo.principalPreloadCsp());
aData.principalCsp(),
aData.principalPreloadCsp());
if (NS_WARN_IF(NS_FAILED(rv))) {
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
return;
}
nsCOMPtr<nsIPrincipal> loadingPrincipal =
PrincipalInfoToPrincipal(aInfo.loadingPrincipalInfo(), &rv);
PrincipalInfoToPrincipal(aData.loadingPrincipalInfo(), &rv);
if (NS_WARN_IF(!loadingPrincipal)) {
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
return;
}
rv = PopulatePrincipalContentSecurityPolicy(loadingPrincipal,
aInfo.loadingPrincipalCsp(),
aInfo.loadingPrincipalPreloadCsp());
aData.loadingPrincipalCsp(),
aData.loadingPrincipalPreloadCsp());
if (NS_WARN_IF(NS_FAILED(rv))) {
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
return;
@ -275,9 +304,9 @@ SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(nsIEventTarget* aBackg
// Let's see if there is already a SharedWorker to share.
for (SharedWorkerManager* workerManager : mWorkerManagers) {
if (workerManager->MatchOnMainThread(aInfo.domain(),
aInfo.resolvedScriptURL(),
aInfo.name(), loadingPrincipal)) {
if (workerManager->MatchOnMainThread(aData.domain(),
aData.resolvedScriptURL(),
aData.name(), loadingPrincipal)) {
manager = workerManager;
break;
}
@ -285,33 +314,22 @@ SharedWorkerService::GetOrCreateWorkerManagerOnMainThread(nsIEventTarget* aBackg
// Let's create a new one.
if (!manager) {
manager = new SharedWorkerManager(aBackgroundEventTarget, aInfo,
principal, loadingPrincipal);
rv = manager->CreateWorkerOnMainThread();
if (NS_WARN_IF(NS_FAILED(rv))) {
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor, rv);
return;
}
manager = new SharedWorkerManager(aBackgroundEventTarget, aData,
loadingPrincipal);
mWorkerManagers.AppendElement(manager);
} else {
// We are attaching the actor to an existing one.
if (manager->IsSecureContext() != aInfo.isSecureContext()) {
if (manager->IsSecureContext() != aData.isSecureContext()) {
ErrorPropagationOnMainThread(aBackgroundEventTarget, aActor,
NS_ERROR_DOM_SECURITY_ERR);
return;
}
}
// If the SharedWorker(Manager) already existed and was frozen, the existence
// of a new, un-frozen actor should trigger the thawing of the SharedWorker.
manager->ThawOnMainThread();
manager->ConnectPortOnMainThread(aInfo.portIdentifier());
RefPtr<WorkerManagerCreatedRunnable> r =
new WorkerManagerCreatedRunnable(manager, aActor);
new WorkerManagerCreatedRunnable(manager, aActor, aData, aWindowID,
aPortIdentifier);
aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}

Просмотреть файл

@ -18,6 +18,8 @@ class PrincipalInfo;
namespace dom {
class MessagePortIdentifier;
class RemoteWorkerData;
class SharedWorkerManager;
class SharedWorkerParent;
@ -38,12 +40,16 @@ public:
// PBackground method only.
void
GetOrCreateWorkerManager(SharedWorkerParent* aActor,
const SharedWorkerLoadInfo& aInfo);
const RemoteWorkerData& aData,
uint64_t aWindowID,
const MessagePortIdentifier& aPortIdentifier);
void
GetOrCreateWorkerManagerOnMainThread(nsIEventTarget* aBackgroundEventTarget,
SharedWorkerParent* aActor,
const SharedWorkerLoadInfo& aInfo);
const RemoteWorkerData& aData,
uint64_t aWindowID,
const MessagePortIdentifier& aPortIdentifier);
// PBackground method only.
void

Просмотреть файл

@ -1,78 +0,0 @@
/* 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 ClientIPCTypes;
include DOMTypes;
include PBackgroundSharedTypes;
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
namespace mozilla {
namespace dom {
struct ContentSecurityPolicy
{
nsString policy;
bool reportOnlyFlag;
bool deliveredViaMetaTagFlag;
};
struct SharedWorkerLoadInfo
{
nsString originalScriptURL;
nsCString baseScriptURL;
nsCString resolvedScriptURL;
nsString name;
PrincipalInfo loadingPrincipalInfo;
ContentSecurityPolicy[] loadingPrincipalCsp;
ContentSecurityPolicy[] loadingPrincipalPreloadCsp;
PrincipalInfo principalInfo;
ContentSecurityPolicy[] principalCsp;
ContentSecurityPolicy[] principalPreloadCsp;
nsCString domain;
bool isSecureContext;
uint64_t windowID;
OptionalIPCClientInfo clientInfo;
MessagePortIdentifier portIdentifier;
};
// ErrorData/ErrorDataNote correspond to WorkerErrorReport/WorkerErrorNote
// which in turn correspond to JSErrorReport/JSErrorNotes which allows JS to
// report complicated errors such as redeclarations that involve multiple
// distinct lines. For more generic error-propagation IPC structures, see bug
// 1357463 on making ErrorResult usable over IPC.
struct ErrorDataNote {
uint32_t lineNumber;
uint32_t columnNumber;
nsString message;
nsString filename;
};
struct ErrorData {
uint32_t lineNumber;
uint32_t columnNumber;
uint32_t flags;
nsString message;
nsString filename;
nsString line;
ErrorDataNote[] notes;
};
union ErrorValue {
nsresult;
ErrorData;
void_t;
};
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -21,7 +21,6 @@ UNIFIED_SOURCES += [
IPDL_SOURCES += [
'PSharedWorker.ipdl',
'SharedWorkerTypes.ipdlh',
]
include('/ipc/chromium/chromium-config.mozbuild')

Просмотреть файл

@ -294,13 +294,24 @@ BackgroundChildImpl::DeallocPPendingIPCBlobChild(PPendingIPCBlobChild* aActor)
dom::PRemoteWorkerChild*
BackgroundChildImpl::AllocPRemoteWorkerChild(const RemoteWorkerData& aData)
{
return new dom::RemoteWorkerChild();
RefPtr<dom::RemoteWorkerChild> agent = new dom::RemoteWorkerChild();
return agent.forget().take();
}
IPCResult
BackgroundChildImpl::RecvPRemoteWorkerConstructor(PRemoteWorkerChild* aActor,
const RemoteWorkerData& aData)
{
dom::RemoteWorkerChild* actor = static_cast<dom::RemoteWorkerChild*>(aActor);
actor->ExecWorker(aData);
return IPC_OK();
}
bool
BackgroundChildImpl::DeallocPRemoteWorkerChild(dom::PRemoteWorkerChild* aActor)
{
delete aActor;
RefPtr<dom::RemoteWorkerChild> actor =
dont_AddRef(static_cast<dom::RemoteWorkerChild*>(aActor));
return true;
}
@ -321,7 +332,9 @@ BackgroundChildImpl::DeallocPRemoteWorkerServiceChild(dom::PRemoteWorkerServiceC
}
dom::PSharedWorkerChild*
BackgroundChildImpl::AllocPSharedWorkerChild(const dom::SharedWorkerLoadInfo& aInfo)
BackgroundChildImpl::AllocPSharedWorkerChild(const dom::RemoteWorkerData& aData,
const uint64_t& aWindowID,
const dom::MessagePortIdentifier& aPortIdentifier)
{
RefPtr<dom::SharedWorkerChild> agent = new dom::SharedWorkerChild();
return agent.forget().take();

Просмотреть файл

@ -117,6 +117,10 @@ protected:
virtual mozilla::dom::PRemoteWorkerChild*
AllocPRemoteWorkerChild(const RemoteWorkerData& aData) override;
virtual mozilla::ipc::IPCResult
RecvPRemoteWorkerConstructor(PRemoteWorkerChild* aActor,
const RemoteWorkerData& aData) override;
virtual bool
DeallocPRemoteWorkerChild(mozilla::dom::PRemoteWorkerChild* aActor) override;
@ -127,7 +131,9 @@ protected:
DeallocPRemoteWorkerServiceChild(mozilla::dom::PRemoteWorkerServiceChild* aActor) override;
virtual mozilla::dom::PSharedWorkerChild*
AllocPSharedWorkerChild(const mozilla::dom::SharedWorkerLoadInfo& aInfo) override;
AllocPSharedWorkerChild(const mozilla::dom::RemoteWorkerData& aData,
const uint64_t& aWindowID,
const mozilla::dom::MessagePortIdentifier& aPortIdentifier) override;
virtual bool
DeallocPSharedWorkerChild(mozilla::dom::PSharedWorkerChild* aActor) override;

Просмотреть файл

@ -427,7 +427,9 @@ BackgroundParentImpl::DeallocPRemoteWorkerServiceParent(mozilla::dom::PRemoteWor
}
mozilla::dom::PSharedWorkerParent*
BackgroundParentImpl::AllocPSharedWorkerParent(const mozilla::dom::SharedWorkerLoadInfo& aInfo)
BackgroundParentImpl::AllocPSharedWorkerParent(const mozilla::dom::RemoteWorkerData& aData,
const uint64_t& aWindowID,
const mozilla::dom::MessagePortIdentifier& aPortIdentifier)
{
RefPtr<dom::SharedWorkerParent> agent =
new mozilla::dom::SharedWorkerParent();
@ -436,11 +438,13 @@ BackgroundParentImpl::AllocPSharedWorkerParent(const mozilla::dom::SharedWorkerL
IPCResult
BackgroundParentImpl::RecvPSharedWorkerConstructor(PSharedWorkerParent* aActor,
const mozilla::dom::SharedWorkerLoadInfo& aInfo)
const mozilla::dom::RemoteWorkerData& aData,
const uint64_t& aWindowID,
const mozilla::dom::MessagePortIdentifier& aPortIdentifier)
{
mozilla::dom::SharedWorkerParent* actor =
static_cast<mozilla::dom::SharedWorkerParent*>(aActor);
actor->Initialize(aInfo);
actor->Initialize(aData, aWindowID, aPortIdentifier);
return IPC_OK();
}

Просмотреть файл

@ -149,11 +149,15 @@ protected:
DeallocPRemoteWorkerServiceParent(PRemoteWorkerServiceParent* aActor) override;
virtual mozilla::dom::PSharedWorkerParent*
AllocPSharedWorkerParent(const mozilla::dom::SharedWorkerLoadInfo& aInfo) override;
AllocPSharedWorkerParent(const mozilla::dom::RemoteWorkerData& aData,
const uint64_t& aWindowID,
const mozilla::dom::MessagePortIdentifier& aPortIdentifier) override;
virtual mozilla::ipc::IPCResult
RecvPSharedWorkerConstructor(PSharedWorkerParent* aActor,
const mozilla::dom::SharedWorkerLoadInfo& aInfo) override;
const mozilla::dom::RemoteWorkerData& aData,
const uint64_t& aWindowID,
const mozilla::dom::MessagePortIdentifier& aPortIdentifier) override;
virtual bool
DeallocPSharedWorkerParent(PSharedWorkerParent* aActor) override;

Просмотреть файл

@ -49,7 +49,6 @@ include PBackgroundIDBSharedTypes;
include PFileSystemParams;
include ProtocolTypes;
include RemoteWorkerTypes;
include SharedWorkerTypes;
include MIDITypes;
include "mozilla/dom/cache/IPCUtils.h";
@ -161,7 +160,9 @@ parent:
async PWebAuthnTransaction();
async PSharedWorker(SharedWorkerLoadInfo loadInfo);
async PSharedWorker(RemoteWorkerData data,
uint64_t windowID,
MessagePortIdentifier portIdentifier);
async PTemporaryIPCBlob();