fune/dom/workers/sharedworkers/SharedWorker.cpp
Narcis Beleuzu f53affe1cb Backed out 22 changesets (bug 1231213) for build bustages on RemoteWorkerChild.cpp . CLOSED TREE
Backed out changeset 6f25a7e73fe2 (bug 1231213)
Backed out changeset 5e88c3855fb6 (bug 1231213)
Backed out changeset a78d7b3e44af (bug 1231213)
Backed out changeset eb7f3a9b0a42 (bug 1231213)
Backed out changeset 87575a180ad5 (bug 1231213)
Backed out changeset 4e8369314e87 (bug 1231213)
Backed out changeset 039c34bc043c (bug 1231213)
Backed out changeset 0528ab68d94e (bug 1231213)
Backed out changeset 670e7d61d95c (bug 1231213)
Backed out changeset d61b9d65bd0a (bug 1231213)
Backed out changeset 9042ea694d40 (bug 1231213)
Backed out changeset bc0607e0d50b (bug 1231213)
Backed out changeset 196ee18781cb (bug 1231213)
Backed out changeset 4b588dec466b (bug 1231213)
Backed out changeset be6031a6fca7 (bug 1231213)
Backed out changeset 12e04c22f52f (bug 1231213)
Backed out changeset fd146f327f2d (bug 1231213)
Backed out changeset f2af7b66f50d (bug 1231213)
Backed out changeset 71d93fc98d3f (bug 1231213)
Backed out changeset 280271806864 (bug 1231213)
Backed out changeset ca4e828345a2 (bug 1231213)
Backed out changeset e41b984510ad (bug 1231213)
2019-08-13 07:47:05 +03:00

376 lines
11 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SharedWorker.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/dom/ClientInfo.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/MessageChannel.h"
#include "mozilla/dom/MessagePort.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"
#include "mozilla/dom/WorkerLoadInfo.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/StorageAccess.h"
#include "nsContentUtils.h"
#include "nsGlobalWindowInner.h"
#include "nsPIDOMWindow.h"
#ifdef XP_WIN
# undef PostMessage
#endif
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::ipc;
SharedWorker::SharedWorker(nsPIDOMWindowInner* aWindow,
SharedWorkerChild* aActor, MessagePort* aMessagePort)
: DOMEventTargetHelper(aWindow),
mWindow(aWindow),
mActor(aActor),
mMessagePort(aMessagePort),
mFrozen(false) {
AssertIsOnMainThread();
MOZ_ASSERT(aActor);
MOZ_ASSERT(aMessagePort);
}
SharedWorker::~SharedWorker() {
AssertIsOnMainThread();
Close();
}
// static
already_AddRefed<SharedWorker> SharedWorker::Constructor(
const GlobalObject& aGlobal, const nsAString& aScriptURL,
const StringOrWorkerOptions& aOptions, ErrorResult& aRv) {
AssertIsOnMainThread();
nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(aGlobal.GetAsSupports());
MOZ_ASSERT(window);
auto storageAllowed = StorageAllowedForWindow(window);
if (storageAllowed == StorageAccess::eDeny) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
if (ShouldPartitionStorage(storageAllowed) &&
!StoragePartitioningEnabled(storageAllowed,
window->GetExtantDoc()->CookieSettings())) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
// Assert that the principal private browsing state matches the
// StorageAccess value.
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
if (storageAllowed == StorageAccess::ePrivateBrowsing) {
nsCOMPtr<Document> doc = window->GetExtantDoc();
nsCOMPtr<nsIPrincipal> principal = doc ? doc->NodePrincipal() : nullptr;
uint32_t privateBrowsingId = 0;
if (principal) {
MOZ_ALWAYS_SUCCEEDS(principal->GetPrivateBrowsingId(&privateBrowsingId));
}
MOZ_DIAGNOSTIC_ASSERT(privateBrowsingId != 0);
}
#endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
nsAutoString name;
if (aOptions.IsString()) {
name = aOptions.GetAsString();
} else {
MOZ_ASSERT(aOptions.IsWorkerOptions());
name = aOptions.GetAsWorkerOptions().mName;
}
JSContext* cx = aGlobal.Context();
WorkerLoadInfo loadInfo;
aRv = WorkerPrivate::GetLoadInfo(cx, window, nullptr, aScriptURL, false,
WorkerPrivate::OverrideLoadGroup,
WorkerTypeShared, &loadInfo);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
PrincipalInfo principalInfo;
aRv = PrincipalToPrincipalInfo(loadInfo.mPrincipal, &principalInfo);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
PrincipalInfo loadingPrincipalInfo;
aRv = PrincipalToPrincipalInfo(loadInfo.mLoadingPrincipal,
&loadingPrincipalInfo);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
// Here, the StoragePrincipal is always equal to the SharedWorker's principal
// because the channel is not opened yet, and, because of this, it's not
// classified. We need to force the correct originAttributes.
if (ShouldPartitionStorage(storageAllowed)) {
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(window);
if (!sop) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsIPrincipal* windowPrincipal = sop->GetPrincipal();
if (!windowPrincipal) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsIPrincipal* windowStoragePrincipal = sop->GetEffectiveStoragePrincipal();
if (!windowStoragePrincipal) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
if (!windowPrincipal->Equals(windowStoragePrincipal)) {
loadInfo.mStoragePrincipal =
BasePrincipal::Cast(loadInfo.mPrincipal)
->CloneForcingOriginAttributes(
BasePrincipal::Cast(windowStoragePrincipal)
->OriginAttributesRef());
}
}
PrincipalInfo storagePrincipalInfo;
if (loadInfo.mPrincipal->Equals(loadInfo.mStoragePrincipal)) {
storagePrincipalInfo = principalInfo;
} else {
aRv = PrincipalToPrincipalInfo(loadInfo.mStoragePrincipal,
&storagePrincipalInfo);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
}
// We don't actually care about this MessageChannel, but we use it to 'steal'
// its 2 connected ports.
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(window);
RefPtr<MessageChannel> channel = MessageChannel::Constructor(global, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
MessagePortIdentifier portIdentifier;
channel->Port1()->CloneAndDisentangle(portIdentifier);
URIParams resolvedScriptURL;
SerializeURI(loadInfo.mResolvedScriptURI, resolvedScriptURL);
URIParams baseURL;
SerializeURI(loadInfo.mBaseURI, baseURL);
// Register this component to PBackground.
PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
bool isSecureContext = JS::GetIsSecureContext(js::GetContextRealm(cx));
Maybe<IPCClientInfo> ipcClientInfo;
Maybe<ClientInfo> clientInfo = window->GetClientInfo();
if (clientInfo.isSome()) {
ipcClientInfo.emplace(clientInfo.value().ToIPC());
}
RemoteWorkerData remoteWorkerData(
nsString(aScriptURL), baseURL, resolvedScriptURL, name,
loadingPrincipalInfo, principalInfo, storagePrincipalInfo,
loadInfo.mDomain, isSecureContext, ipcClientInfo, loadInfo.mReferrerInfo,
storageAllowed, true /* sharedWorker */);
PSharedWorkerChild* pActor = actorChild->SendPSharedWorkerConstructor(
remoteWorkerData, loadInfo.mWindowID, portIdentifier);
RefPtr<SharedWorkerChild> actor = static_cast<SharedWorkerChild*>(pActor);
MOZ_ASSERT(actor);
RefPtr<SharedWorker> sharedWorker =
new SharedWorker(window, actor, channel->Port2());
// Let's inform the window about this SharedWorker.
nsGlobalWindowInner::Cast(window)->StoreSharedWorker(sharedWorker);
actor->SetParent(sharedWorker);
return sharedWorker.forget();
}
MessagePort* SharedWorker::Port() {
AssertIsOnMainThread();
return mMessagePort;
}
void SharedWorker::Freeze() {
AssertIsOnMainThread();
MOZ_ASSERT(!IsFrozen());
if (mFrozen) {
return;
}
mFrozen = true;
if (mActor) {
mActor->SendFreeze();
}
}
void SharedWorker::Thaw() {
AssertIsOnMainThread();
MOZ_ASSERT(IsFrozen());
if (!mFrozen) {
return;
}
mFrozen = false;
if (mActor) {
mActor->SendThaw();
}
if (!mFrozenEvents.IsEmpty()) {
nsTArray<RefPtr<Event>> events;
mFrozenEvents.SwapElements(events);
for (uint32_t index = 0; index < events.Length(); index++) {
RefPtr<Event>& event = events[index];
MOZ_ASSERT(event);
RefPtr<EventTarget> target = event->GetTarget();
ErrorResult rv;
target->DispatchEvent(*event, rv);
if (rv.Failed()) {
NS_WARNING("Failed to dispatch event!");
}
}
}
}
void SharedWorker::QueueEvent(Event* aEvent) {
AssertIsOnMainThread();
MOZ_ASSERT(aEvent);
MOZ_ASSERT(IsFrozen());
mFrozenEvents.AppendElement(aEvent);
}
void SharedWorker::Close() {
AssertIsOnMainThread();
if (mWindow) {
nsGlobalWindowInner::Cast(mWindow)->ForgetSharedWorker(this);
mWindow = nullptr;
}
if (mActor) {
mActor->SendClose();
mActor->SetParent(nullptr);
mActor = nullptr;
}
if (mMessagePort) {
mMessagePort->Close();
}
}
void SharedWorker::Suspend() {
if (mActor) {
mActor->SendSuspend();
}
}
void SharedWorker::Resume() {
if (mActor) {
mActor->SendResume();
}
}
void SharedWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv) {
AssertIsOnMainThread();
MOZ_ASSERT(mMessagePort);
mMessagePort->PostMessage(aCx, aMessage, aTransferable, aRv);
}
NS_IMPL_ADDREF_INHERITED(SharedWorker, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(SharedWorker, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SharedWorker)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_CLASS(SharedWorker)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SharedWorker,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagePort)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrozenEvents)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SharedWorker,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagePort)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrozenEvents)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
JSObject* SharedWorker::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
AssertIsOnMainThread();
return SharedWorker_Binding::Wrap(aCx, this, aGivenProto);
}
void SharedWorker::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
AssertIsOnMainThread();
if (IsFrozen()) {
RefPtr<Event> event = aVisitor.mDOMEvent;
if (!event) {
event = EventDispatcher::CreateEvent(aVisitor.mEvent->mOriginalTarget,
aVisitor.mPresContext,
aVisitor.mEvent, EmptyString());
}
QueueEvent(event);
aVisitor.mCanHandle = false;
aVisitor.SetParentTarget(nullptr, false);
return;
}
DOMEventTargetHelper::GetEventTargetParent(aVisitor);
}
void SharedWorker::ErrorPropagation(nsresult aError) {
AssertIsOnMainThread();
MOZ_ASSERT(mActor);
MOZ_ASSERT(NS_FAILED(aError));
RefPtr<AsyncEventDispatcher> errorEvent = new AsyncEventDispatcher(
this, NS_LITERAL_STRING("error"), CanBubble::eNo);
errorEvent->PostDOMEvent();
Close();
}