diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp index d0660c9338d1..4d9e711f5815 100644 --- a/dom/fetch/Fetch.cpp +++ b/dom/fetch/Fetch.cpp @@ -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; } diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index d1d3c7c8503c..64c97ba4ec89 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -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) { diff --git a/dom/workers/WorkerError.cpp b/dom/workers/WorkerError.cpp index 856d9932e884..12fbf4b78ed4 100644 --- a/dom/workers/WorkerError.cpp +++ b/dom/workers/WorkerError.cpp @@ -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; } diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 83012a93b97f..20c25888899e 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -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) diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index f38dead92145..ec1a9cf416de 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -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> mPreStartRunnables; // Only touched on the parent thread. This is set only if IsSharedWorker(). - RefPtr mSharedWorkerManager; + RefPtr mRemoteWorkerController; JS::UniqueChars mDefaultLocale; // nulled during worker JSContext init TimeStamp mKillTime; diff --git a/dom/workers/remoteworkers/PRemoteWorker.ipdl b/dom/workers/remoteworkers/PRemoteWorker.ipdl index dfbd2b43ddd7..19450334ba62 100644 --- a/dom/workers/remoteworkers/PRemoteWorker.ipdl +++ b/dom/workers/remoteworkers/PRemoteWorker.ipdl @@ -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 diff --git a/dom/workers/remoteworkers/RemoteWorkerChild.cpp b/dom/workers/remoteworkers/RemoteWorkerChild.cpp index 30d77678a21d..3164b4eb8538 100644 --- a/dom/workers/remoteworkers/RemoteWorkerChild.cpp +++ b/dom/workers/remoteworkers/RemoteWorkerChild.cpp @@ -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& 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& aPolicies, + const nsTArray& aPreloadPolicies) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aPrincipal); + + if (!aPolicies.IsEmpty()) { + nsCOMPtr 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 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 swController = mSWController; + swController.forget(aSink); + return NS_OK; + } + + return NS_NOINTERFACE; + } + +private: + ~SharedWorkerInterfaceRequestor() = default; + + RefPtr 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 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 mActor; +}; + +RemoteWorkerChild::RemoteWorkerChild() + : mIPCActive(true) + , mWorkerState(ePending) +{ + MOZ_ASSERT(RemoteWorkerService::Thread()->IsOnCurrentThread()); +} + +RemoteWorkerChild::~RemoteWorkerChild() +{ + nsCOMPtr 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 self = this; + nsCOMPtr r = + NS_NewRunnableFunction("RemoteWorkerChild::ExecWorker", + [self, aData]() { + nsresult rv = self->ExecWorkerOnMainThread(aData); + if (NS_WARN_IF(NS_FAILED(rv))) { + self->CreationFailedOnAnyThread(); + } + }); + + nsCOMPtr 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 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 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 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; + 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 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 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 target = + SystemGroup::EventTargetFor(TaskCategory::Other); + + NS_ProxyRelease("RemoteWorkerChild::mWorkerPrivate", + target, mWorkerPrivate.forget()); + + RefPtr self = this; + nsCOMPtr 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 self = this; + nsCOMPtr 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 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 self = this; + nsCOMPtr 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 self = this; + nsCOMPtr r = + NS_NewRunnableFunction("RemoteWorkerChild::RecvExecOp", + [self, aOp]() { + self->RecvExecOpOnMainThread(aOp); + }); + + nsCOMPtr 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 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 self = this; + nsCOMPtr 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 self = this; + nsCOMPtr r = + NS_NewRunnableFunction("RemoteWorkerChild::CreationSucceeded", + [self]() { + self->CloseWorkerOnMainThread(); + }); + + nsCOMPtr 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 self = this; + nsCOMPtr 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 diff --git a/dom/workers/remoteworkers/RemoteWorkerChild.h b/dom/workers/remoteworkers/RemoteWorkerChild.h index b315145ea991..a6c9754ef3ca 100644 --- a/dom/workers/remoteworkers/RemoteWorkerChild.h +++ b/dom/workers/remoteworkers/RemoteWorkerChild.h @@ -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 mWindowIDs; + + RefPtr mWorkerPrivate; + RefPtr 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 mPendingOps; }; } // dom namespace diff --git a/dom/workers/remoteworkers/RemoteWorkerController.cpp b/dom/workers/remoteworkers/RemoteWorkerController.cpp index 01ef2a88889e..5bb359359807 100644 --- a/dom/workers/remoteworkers/RemoteWorkerController.cpp +++ b/dom/workers/remoteworkers/RemoteWorkerController.cpp @@ -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::Create() +RemoteWorkerController::Create(const RemoteWorkerData& aData) { AssertIsOnBackgroundThread(); MOZ_ASSERT(XRE_IsParentProcess()); RefPtr controller = new RemoteWorkerController(); - // This will be populated, eventually. - RemoteWorkerData data; - RefPtr 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 : 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 diff --git a/dom/workers/remoteworkers/RemoteWorkerController.h b/dom/workers/remoteworkers/RemoteWorkerController.h index 156db401fdbd..008aa1acc366 100644 --- a/dom/workers/remoteworkers/RemoteWorkerController.h +++ b/dom/workers/remoteworkers/RemoteWorkerController.h @@ -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 - 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 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> mPendingOps; }; } // dom namespace diff --git a/dom/workers/remoteworkers/RemoteWorkerParent.cpp b/dom/workers/remoteworkers/RemoteWorkerParent.cpp index d242c02a302b..6fcbe11088fe 100644 --- a/dom/workers/remoteworkers/RemoteWorkerParent.cpp +++ b/dom/workers/remoteworkers/RemoteWorkerParent.cpp @@ -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) { diff --git a/dom/workers/remoteworkers/RemoteWorkerParent.h b/dom/workers/remoteworkers/RemoteWorkerParent.h index d0164a11965f..3608e067f7cc 100644 --- a/dom/workers/remoteworkers/RemoteWorkerParent.h +++ b/dom/workers/remoteworkers/RemoteWorkerParent.h @@ -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; diff --git a/dom/workers/remoteworkers/RemoteWorkerService.cpp b/dom/workers/remoteworkers/RemoteWorkerService.cpp index 4c9206937bf8..f61b2b7cc274 100644 --- a/dom/workers/remoteworkers/RemoteWorkerService.cpp +++ b/dom/workers/remoteworkers/RemoteWorkerService.cpp @@ -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() { diff --git a/dom/workers/remoteworkers/RemoteWorkerService.h b/dom/workers/remoteworkers/RemoteWorkerService.h index 19a0396edb2b..3c03099dc11f 100644 --- a/dom/workers/remoteworkers/RemoteWorkerService.h +++ b/dom/workers/remoteworkers/RemoteWorkerService.h @@ -27,6 +27,9 @@ public: static void Initialize(); + static nsIThread* + Thread(); + private: RemoteWorkerService(); ~RemoteWorkerService(); diff --git a/dom/workers/remoteworkers/RemoteWorkerTypes.ipdlh b/dom/workers/remoteworkers/RemoteWorkerTypes.ipdlh index 1d4c0557d422..afeee1d6c1ed 100644 --- a/dom/workers/remoteworkers/RemoteWorkerTypes.ipdlh +++ b/dom/workers/remoteworkers/RemoteWorkerTypes.ipdlh @@ -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 diff --git a/dom/workers/sharedworkers/PSharedWorker.ipdl b/dom/workers/sharedworkers/PSharedWorker.ipdl index e3991addaf46..31c34e1b94dc 100644 --- a/dom/workers/sharedworkers/PSharedWorker.ipdl +++ b/dom/workers/sharedworkers/PSharedWorker.ipdl @@ -4,7 +4,7 @@ include protocol PBackground; -include SharedWorkerTypes; +include RemoteWorkerTypes; namespace mozilla { namespace dom { diff --git a/dom/workers/sharedworkers/SharedWorker.cpp b/dom/workers/sharedworkers/SharedWorker.cpp index 1a6050e15e10..c12526034582 100644 --- a/dom/workers/sharedworkers/SharedWorker.cpp +++ b/dom/workers/sharedworkers/SharedWorker.cpp @@ -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 actor = static_cast(pActor); MOZ_ASSERT(actor); diff --git a/dom/workers/sharedworkers/SharedWorkerManager.cpp b/dom/workers/sharedworkers/SharedWorkerManager.cpp index e7dde081ea31..eccb222552af 100644 --- a/dom/workers/sharedworkers/SharedWorkerManager.cpp +++ b/dom/workers/sharedworkers/SharedWorkerManager.cpp @@ -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 swController = mSWController; - swController.forget(aSink); - return NS_OK; - } - - return NS_NOINTERFACE; - } - -private: - ~SharedWorkerInterfaceRequestor() = default; - - RefPtr 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 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 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; - 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 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 self = this; - nsCOMPtr r = - NS_NewRunnableFunction("SharedWorkerManager::RemoveActor", - [self]() { - self->CloseOnMainThread(); - }); - - nsCOMPtr 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 self = this; - nsCOMPtr r = - NS_NewRunnableFunction("SharedWorkerManager::UpdateSuspend", - [self, suspended]() { - if (suspended) { - self->SuspendOnMainThread(); - } else { - self->ResumeOnMainThread(); - } - }); - - nsCOMPtr 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 self = this; - nsCOMPtr r = - NS_NewRunnableFunction("SharedWorkerManager::UpdateFrozen", - [self, frozen]() { - if (frozen) { - self->FreezeOnMainThread(); - } else { - self->ThawOnMainThread(); - } - }); - - nsCOMPtr 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 diff --git a/dom/workers/sharedworkers/SharedWorkerManager.h b/dom/workers/sharedworkers/SharedWorkerManager.h index d8bc84a5a011..81bf897d41f3 100644 --- a/dom/workers/sharedworkers/SharedWorkerManager.h +++ b/dom/workers/sharedworkers/SharedWorkerManager.h @@ -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 mPBackgroundEventTarget; - SharedWorkerLoadInfo mInfo; - nsCOMPtr mPrincipal; nsCOMPtr mLoadingPrincipal; + nsCString mDomain; + nsCString mResolvedScriptURL; + nsString mName; + bool mIsSecureContext; // Raw pointers because SharedWorkerParent unregisters itself in ActorDestroy(). nsTArray mActors; - // With this patch, SharedWorker are executed on the parent process. - // This is going to change in the following parts. - RefPtr mWorkerPrivate; + RefPtr mRemoteWorkerController; }; } // dom namespace diff --git a/dom/workers/sharedworkers/SharedWorkerParent.cpp b/dom/workers/sharedworkers/SharedWorkerParent.cpp index ff369328da7d..929bd2ecffc9 100644 --- a/dom/workers/sharedworkers/SharedWorkerParent.cpp +++ b/dom/workers/sharedworkers/SharedWorkerParent.cpp @@ -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 diff --git a/dom/workers/sharedworkers/SharedWorkerParent.h b/dom/workers/sharedworkers/SharedWorkerParent.h index 517c75d786a0..57689f6431c0 100644 --- a/dom/workers/sharedworkers/SharedWorkerParent.h +++ b/dom/workers/sharedworkers/SharedWorkerParent.h @@ -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); diff --git a/dom/workers/sharedworkers/SharedWorkerService.cpp b/dom/workers/sharedworkers/SharedWorkerService.cpp index d6b4a4270ac7..1eb4d85a9bed 100644 --- a/dom/workers/sharedworkers/SharedWorkerService.cpp +++ b/dom/workers/sharedworkers/SharedWorkerService.cpp @@ -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 mBackgroundEventTarget; RefPtr 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 mManager; RefPtr 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 r = - new GetOrCreateWorkerManagerRunnable(aActor, aInfo); + new GetOrCreateWorkerManagerRunnable(aActor, aData, aWindowID, + aPortIdentifier); nsCOMPtr 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 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 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 r = - new WorkerManagerCreatedRunnable(manager, aActor); + new WorkerManagerCreatedRunnable(manager, aActor, aData, aWindowID, + aPortIdentifier); aBackgroundEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL); } diff --git a/dom/workers/sharedworkers/SharedWorkerService.h b/dom/workers/sharedworkers/SharedWorkerService.h index 8cb3699d3c20..0c9ef4cf0045 100644 --- a/dom/workers/sharedworkers/SharedWorkerService.h +++ b/dom/workers/sharedworkers/SharedWorkerService.h @@ -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 diff --git a/dom/workers/sharedworkers/SharedWorkerTypes.ipdlh b/dom/workers/sharedworkers/SharedWorkerTypes.ipdlh deleted file mode 100644 index 8982dd488217..000000000000 --- a/dom/workers/sharedworkers/SharedWorkerTypes.ipdlh +++ /dev/null @@ -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 diff --git a/dom/workers/sharedworkers/moz.build b/dom/workers/sharedworkers/moz.build index 9908ddcacc92..95d3a71e7252 100644 --- a/dom/workers/sharedworkers/moz.build +++ b/dom/workers/sharedworkers/moz.build @@ -21,7 +21,6 @@ UNIFIED_SOURCES += [ IPDL_SOURCES += [ 'PSharedWorker.ipdl', - 'SharedWorkerTypes.ipdlh', ] include('/ipc/chromium/chromium-config.mozbuild') diff --git a/ipc/glue/BackgroundChildImpl.cpp b/ipc/glue/BackgroundChildImpl.cpp index ccb77e150274..d284323c3b7e 100644 --- a/ipc/glue/BackgroundChildImpl.cpp +++ b/ipc/glue/BackgroundChildImpl.cpp @@ -294,13 +294,24 @@ BackgroundChildImpl::DeallocPPendingIPCBlobChild(PPendingIPCBlobChild* aActor) dom::PRemoteWorkerChild* BackgroundChildImpl::AllocPRemoteWorkerChild(const RemoteWorkerData& aData) { - return new dom::RemoteWorkerChild(); + RefPtr agent = new dom::RemoteWorkerChild(); + return agent.forget().take(); +} + +IPCResult +BackgroundChildImpl::RecvPRemoteWorkerConstructor(PRemoteWorkerChild* aActor, + const RemoteWorkerData& aData) +{ + dom::RemoteWorkerChild* actor = static_cast(aActor); + actor->ExecWorker(aData); + return IPC_OK(); } bool BackgroundChildImpl::DeallocPRemoteWorkerChild(dom::PRemoteWorkerChild* aActor) { - delete aActor; + RefPtr actor = + dont_AddRef(static_cast(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 agent = new dom::SharedWorkerChild(); return agent.forget().take(); diff --git a/ipc/glue/BackgroundChildImpl.h b/ipc/glue/BackgroundChildImpl.h index 20422b69ee91..c0320f9afe46 100644 --- a/ipc/glue/BackgroundChildImpl.h +++ b/ipc/glue/BackgroundChildImpl.h @@ -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; diff --git a/ipc/glue/BackgroundParentImpl.cpp b/ipc/glue/BackgroundParentImpl.cpp index 6fe358093625..b17b30aec9b2 100644 --- a/ipc/glue/BackgroundParentImpl.cpp +++ b/ipc/glue/BackgroundParentImpl.cpp @@ -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 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(aActor); - actor->Initialize(aInfo); + actor->Initialize(aData, aWindowID, aPortIdentifier); return IPC_OK(); } diff --git a/ipc/glue/BackgroundParentImpl.h b/ipc/glue/BackgroundParentImpl.h index f6b5a1684992..64a1ba40737c 100644 --- a/ipc/glue/BackgroundParentImpl.h +++ b/ipc/glue/BackgroundParentImpl.h @@ -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; diff --git a/ipc/glue/PBackground.ipdl b/ipc/glue/PBackground.ipdl index 9e9bb060e251..7b6d4304de7f 100644 --- a/ipc/glue/PBackground.ipdl +++ b/ipc/glue/PBackground.ipdl @@ -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();