gecko-dev/dom/workers/sharedworkers/SharedWorker.cpp
Tim Huang 04d44bae12 Bug 1616570 - Part 1: Rename CookieSettings to CookieJarSettings. r=Ehsan
Given that we are going to add ContentBlockingAllowList in
CookieSettings, so CookieSettings will be responsible for more stuff than the
cookie behavior and cookie permission. We should use a proper name to
reflect the purpose of it. The name 'CookieSettings' is misleading that
this is only for cookie related stuff. So, we decide to rename
'CookieSettins' to 'CookieJarSettings' which serves better meaning here.

Differential Revision: https://phabricator.services.mozilla.com/D63935

--HG--
rename : netwerk/cookie/CookieSettings.cpp => netwerk/cookie/CookieJarSettings.cpp
rename : netwerk/cookie/nsICookieSettings.idl => netwerk/cookie/nsICookieJarSettings.idl
extra : moz-landing-system : lando
2020-03-04 08:59:08 +00:00

378 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()->CookieJarSettings())) {
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;
}
UniqueMessagePortId 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());
}
nsID agentClusterId = nsContentUtils::GenerateUUID();
RemoteWorkerData remoteWorkerData(
nsString(aScriptURL), baseURL, resolvedScriptURL, name,
loadingPrincipalInfo, principalInfo, storagePrincipalInfo,
loadInfo.mDomain, isSecureContext, ipcClientInfo, loadInfo.mReferrerInfo,
storageAllowed, void_t() /* OptionalServiceWorkerData */, agentClusterId);
PSharedWorkerChild* pActor = actorChild->SendPSharedWorkerConstructor(
remoteWorkerData, loadInfo.mWindowID, portIdentifier.release());
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();
}