mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
1c269b0ef9
Backed out changeset e892727a373a (bug 1206168) Backed out changeset 6c93d1044b7e (bug 1054756) Backed out changeset 105433ce195b (bug 1054756) Backed out changeset 13128a88f2b9 (bug 1054756) Backed out changeset c250abf4fd17 (bug 1054756) Backed out changeset fc9fef646a97 (bug 1054756) Backed out changeset c8897f109a08 (bug 1177318)
963 lines
27 KiB
C++
963 lines
27 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 "WorkerScope.h"
|
|
|
|
#include "jsapi.h"
|
|
#include "mozilla/EventListenerManager.h"
|
|
#include "mozilla/dom/BindingDeclarations.h"
|
|
#include "mozilla/dom/Console.h"
|
|
#include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h"
|
|
#include "mozilla/dom/Fetch.h"
|
|
#include "mozilla/dom/FunctionBinding.h"
|
|
#include "mozilla/dom/ImageBitmap.h"
|
|
#include "mozilla/dom/Promise.h"
|
|
#include "mozilla/dom/PromiseWorkerProxy.h"
|
|
#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
|
|
#include "mozilla/dom/SharedWorkerGlobalScopeBinding.h"
|
|
#include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
|
|
#include "mozilla/dom/WorkerGlobalScopeBinding.h"
|
|
#include "mozilla/dom/cache/CacheStorage.h"
|
|
#include "mozilla/dom/indexedDB/IDBFactory.h"
|
|
#include "mozilla/Services.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
|
|
#include "nsIDocument.h"
|
|
#include "nsIServiceWorkerManager.h"
|
|
|
|
#ifdef ANDROID
|
|
#include <android/log.h>
|
|
#endif
|
|
|
|
#include "Location.h"
|
|
#include "Navigator.h"
|
|
#include "Principal.h"
|
|
#include "RuntimeService.h"
|
|
#include "ScriptLoader.h"
|
|
#include "WorkerPrivate.h"
|
|
#include "WorkerRunnable.h"
|
|
#include "Performance.h"
|
|
#include "ServiceWorkerClients.h"
|
|
#include "ServiceWorkerManager.h"
|
|
#include "ServiceWorkerRegistration.h"
|
|
|
|
#ifdef XP_WIN
|
|
#undef PostMessage
|
|
#endif
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::dom;
|
|
USING_WORKERS_NAMESPACE
|
|
|
|
using mozilla::dom::cache::CacheStorage;
|
|
using mozilla::dom::indexedDB::IDBFactory;
|
|
using mozilla::ipc::PrincipalInfo;
|
|
|
|
BEGIN_WORKERS_NAMESPACE
|
|
|
|
WorkerGlobalScope::WorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
|
|
: mWindowInteractionsAllowed(0)
|
|
, mWorkerPrivate(aWorkerPrivate)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
}
|
|
|
|
WorkerGlobalScope::~WorkerGlobalScope()
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerGlobalScope)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerGlobalScope,
|
|
DOMEventTargetHelper)
|
|
tmp->mWorkerPrivate->AssertIsOnWorkerThread();
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage)
|
|
tmp->TraverseHostObjectURIs(cb);
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope,
|
|
DOMEventTargetHelper)
|
|
tmp->mWorkerPrivate->AssertIsOnWorkerThread();
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)
|
|
tmp->UnlinkHostObjectURIs();
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerGlobalScope,
|
|
DOMEventTargetHelper)
|
|
tmp->mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
tmp->mWorkerPrivate->TraceTimeouts(aCallbacks, aClosure);
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
|
|
|
NS_IMPL_ADDREF_INHERITED(WorkerGlobalScope, DOMEventTargetHelper)
|
|
NS_IMPL_RELEASE_INHERITED(WorkerGlobalScope, DOMEventTargetHelper)
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerGlobalScope)
|
|
NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
|
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
|
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
|
|
|
JSObject*
|
|
WorkerGlobalScope::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|
{
|
|
MOZ_CRASH("We should never get here!");
|
|
}
|
|
|
|
Console*
|
|
WorkerGlobalScope::GetConsole()
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
if (!mConsole) {
|
|
mConsole = new Console(nullptr);
|
|
}
|
|
|
|
return mConsole;
|
|
}
|
|
|
|
already_AddRefed<CacheStorage>
|
|
WorkerGlobalScope::GetCaches(ErrorResult& aRv)
|
|
{
|
|
if (!mCacheStorage) {
|
|
MOZ_ASSERT(mWorkerPrivate);
|
|
mCacheStorage = CacheStorage::CreateOnWorker(cache::DEFAULT_NAMESPACE, this,
|
|
mWorkerPrivate, aRv);
|
|
}
|
|
|
|
nsRefPtr<CacheStorage> ref = mCacheStorage;
|
|
return ref.forget();
|
|
}
|
|
|
|
already_AddRefed<WorkerLocation>
|
|
WorkerGlobalScope::Location()
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
if (!mLocation) {
|
|
WorkerPrivate::LocationInfo& info = mWorkerPrivate->GetLocationInfo();
|
|
|
|
mLocation = WorkerLocation::Create(info);
|
|
MOZ_ASSERT(mLocation);
|
|
}
|
|
|
|
nsRefPtr<WorkerLocation> location = mLocation;
|
|
return location.forget();
|
|
}
|
|
|
|
already_AddRefed<WorkerNavigator>
|
|
WorkerGlobalScope::Navigator()
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
if (!mNavigator) {
|
|
mNavigator = WorkerNavigator::Create(mWorkerPrivate->OnLine());
|
|
MOZ_ASSERT(mNavigator);
|
|
}
|
|
|
|
nsRefPtr<WorkerNavigator> navigator = mNavigator;
|
|
return navigator.forget();
|
|
}
|
|
|
|
already_AddRefed<WorkerNavigator>
|
|
WorkerGlobalScope::GetExistingNavigator() const
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
nsRefPtr<WorkerNavigator> navigator = mNavigator;
|
|
return navigator.forget();
|
|
}
|
|
|
|
void
|
|
WorkerGlobalScope::Close(JSContext* aCx, ErrorResult& aRv)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
if (mWorkerPrivate->IsServiceWorker()) {
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
|
} else {
|
|
mWorkerPrivate->CloseInternal(aCx);
|
|
}
|
|
}
|
|
|
|
OnErrorEventHandlerNonNull*
|
|
WorkerGlobalScope::GetOnerror()
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
EventListenerManager* elm = GetExistingListenerManager();
|
|
return elm ? elm->GetOnErrorEventHandler() : nullptr;
|
|
}
|
|
|
|
void
|
|
WorkerGlobalScope::SetOnerror(OnErrorEventHandlerNonNull* aHandler)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
EventListenerManager* elm = GetOrCreateListenerManager();
|
|
if (elm) {
|
|
elm->SetEventHandler(aHandler);
|
|
}
|
|
}
|
|
|
|
void
|
|
WorkerGlobalScope::ImportScripts(JSContext* aCx,
|
|
const Sequence<nsString>& aScriptURLs,
|
|
ErrorResult& aRv)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
scriptloader::Load(aCx, mWorkerPrivate, aScriptURLs, WorkerScript, aRv);
|
|
}
|
|
|
|
int32_t
|
|
WorkerGlobalScope::SetTimeout(JSContext* aCx,
|
|
Function& aHandler,
|
|
const int32_t aTimeout,
|
|
const Sequence<JS::Value>& aArguments,
|
|
ErrorResult& aRv)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
return mWorkerPrivate->SetTimeout(aCx, &aHandler, EmptyString(), aTimeout,
|
|
aArguments, false, aRv);
|
|
}
|
|
|
|
int32_t
|
|
WorkerGlobalScope::SetTimeout(JSContext* /* unused */,
|
|
const nsAString& aHandler,
|
|
const int32_t aTimeout,
|
|
const Sequence<JS::Value>& /* unused */,
|
|
ErrorResult& aRv)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
Sequence<JS::Value> dummy;
|
|
return mWorkerPrivate->SetTimeout(GetCurrentThreadJSContext(), nullptr,
|
|
aHandler, aTimeout, dummy, false, aRv);
|
|
}
|
|
|
|
void
|
|
WorkerGlobalScope::ClearTimeout(int32_t aHandle, ErrorResult& aRv)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
mWorkerPrivate->ClearTimeout(aHandle);
|
|
}
|
|
|
|
int32_t
|
|
WorkerGlobalScope::SetInterval(JSContext* aCx,
|
|
Function& aHandler,
|
|
const Optional<int32_t>& aTimeout,
|
|
const Sequence<JS::Value>& aArguments,
|
|
ErrorResult& aRv)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
bool isInterval = aTimeout.WasPassed();
|
|
int32_t timeout = aTimeout.WasPassed() ? aTimeout.Value() : 0;
|
|
|
|
return mWorkerPrivate->SetTimeout(aCx, &aHandler, EmptyString(), timeout,
|
|
aArguments, isInterval, aRv);
|
|
}
|
|
|
|
int32_t
|
|
WorkerGlobalScope::SetInterval(JSContext* /* unused */,
|
|
const nsAString& aHandler,
|
|
const Optional<int32_t>& aTimeout,
|
|
const Sequence<JS::Value>& /* unused */,
|
|
ErrorResult& aRv)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
Sequence<JS::Value> dummy;
|
|
|
|
bool isInterval = aTimeout.WasPassed();
|
|
int32_t timeout = aTimeout.WasPassed() ? aTimeout.Value() : 0;
|
|
|
|
return mWorkerPrivate->SetTimeout(GetCurrentThreadJSContext(), nullptr,
|
|
aHandler, timeout, dummy, isInterval, aRv);
|
|
}
|
|
|
|
void
|
|
WorkerGlobalScope::ClearInterval(int32_t aHandle, ErrorResult& aRv)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
mWorkerPrivate->ClearTimeout(aHandle);
|
|
}
|
|
|
|
void
|
|
WorkerGlobalScope::Atob(const nsAString& aAtob, nsAString& aOutput, ErrorResult& aRv) const
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
aRv = nsContentUtils::Atob(aAtob, aOutput);
|
|
}
|
|
|
|
void
|
|
WorkerGlobalScope::Btoa(const nsAString& aBtoa, nsAString& aOutput, ErrorResult& aRv) const
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
aRv = nsContentUtils::Btoa(aBtoa, aOutput);
|
|
}
|
|
|
|
void
|
|
WorkerGlobalScope::Dump(const Optional<nsAString>& aString) const
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
if (!aString.WasPassed()) {
|
|
return;
|
|
}
|
|
|
|
if (!mWorkerPrivate->DumpEnabled()) {
|
|
return;
|
|
}
|
|
|
|
NS_ConvertUTF16toUTF8 str(aString.Value());
|
|
|
|
#ifdef ANDROID
|
|
__android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", str.get());
|
|
#endif
|
|
fputs(str.get(), stdout);
|
|
fflush(stdout);
|
|
}
|
|
|
|
Performance*
|
|
WorkerGlobalScope::GetPerformance()
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
if (!mPerformance) {
|
|
mPerformance = new Performance(mWorkerPrivate);
|
|
}
|
|
|
|
return mPerformance;
|
|
}
|
|
|
|
already_AddRefed<Promise>
|
|
WorkerGlobalScope::Fetch(const RequestOrUSVString& aInput,
|
|
const RequestInit& aInit, ErrorResult& aRv)
|
|
{
|
|
return FetchRequest(this, aInput, aInit, aRv);
|
|
}
|
|
|
|
already_AddRefed<IDBFactory>
|
|
WorkerGlobalScope::GetIndexedDB(ErrorResult& aErrorResult)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
nsRefPtr<IDBFactory> indexedDB = mIndexedDB;
|
|
|
|
if (!indexedDB) {
|
|
if (!mWorkerPrivate->IsStorageAllowed()) {
|
|
NS_WARNING("IndexedDB is not allowed in this worker!");
|
|
aErrorResult = NS_ERROR_DOM_SECURITY_ERR;
|
|
return nullptr;
|
|
}
|
|
|
|
JSContext* cx = mWorkerPrivate->GetJSContext();
|
|
MOZ_ASSERT(cx);
|
|
|
|
JS::Rooted<JSObject*> owningObject(cx, GetGlobalJSObject());
|
|
MOZ_ASSERT(owningObject);
|
|
|
|
const PrincipalInfo& principalInfo = mWorkerPrivate->GetPrincipalInfo();
|
|
|
|
nsresult rv =
|
|
IDBFactory::CreateForWorker(cx,
|
|
owningObject,
|
|
principalInfo,
|
|
mWorkerPrivate->WindowID(),
|
|
getter_AddRefs(indexedDB));
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
aErrorResult = rv;
|
|
return nullptr;
|
|
}
|
|
|
|
mIndexedDB = indexedDB;
|
|
}
|
|
|
|
return indexedDB.forget();
|
|
}
|
|
|
|
already_AddRefed<Promise>
|
|
WorkerGlobalScope::CreateImageBitmap(const ImageBitmapSource& aImage,
|
|
ErrorResult& aRv)
|
|
{
|
|
return ImageBitmap::Create(this, aImage, Nothing(), aRv);
|
|
}
|
|
|
|
already_AddRefed<Promise>
|
|
WorkerGlobalScope::CreateImageBitmap(const ImageBitmapSource& aImage,
|
|
int32_t aSx, int32_t aSy, int32_t aSw, int32_t aSh,
|
|
ErrorResult& aRv)
|
|
{
|
|
return ImageBitmap::Create(this, aImage, Some(gfx::IntRect(aSx, aSy, aSw, aSh)), aRv);
|
|
}
|
|
|
|
DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
|
|
: WorkerGlobalScope(aWorkerPrivate)
|
|
{
|
|
}
|
|
|
|
bool
|
|
DedicatedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx,
|
|
JS::MutableHandle<JSObject*> aReflector)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
MOZ_ASSERT(!mWorkerPrivate->IsSharedWorker());
|
|
|
|
JS::CompartmentOptions options;
|
|
mWorkerPrivate->CopyJSCompartmentOptions(options);
|
|
|
|
const bool usesSystemPrincipal = mWorkerPrivate->UsesSystemPrincipal();
|
|
|
|
// Note that xpc::ShouldDiscardSystemSource() and
|
|
// xpc::ExtraWarningsForSystemJS() read prefs that are cached on the main
|
|
// thread. This is benignly racey.
|
|
const bool discardSource = (usesSystemPrincipal ||
|
|
mWorkerPrivate->IsInPrivilegedApp()) &&
|
|
xpc::ShouldDiscardSystemSource();
|
|
const bool extraWarnings = usesSystemPrincipal &&
|
|
xpc::ExtraWarningsForSystemJS();
|
|
|
|
options.setDiscardSource(discardSource)
|
|
.extraWarningsOverride().set(extraWarnings);
|
|
|
|
return DedicatedWorkerGlobalScopeBinding_workers::Wrap(aCx, this, this,
|
|
options,
|
|
GetWorkerPrincipal(),
|
|
true, aReflector);
|
|
}
|
|
|
|
void
|
|
DedicatedWorkerGlobalScope::PostMessage(JSContext* aCx,
|
|
JS::Handle<JS::Value> aMessage,
|
|
const Optional<Sequence<JS::Value>>& aTransferable,
|
|
ErrorResult& aRv)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
mWorkerPrivate->PostMessageToParent(aCx, aMessage, aTransferable, aRv);
|
|
}
|
|
|
|
SharedWorkerGlobalScope::SharedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate,
|
|
const nsCString& aName)
|
|
: WorkerGlobalScope(aWorkerPrivate), mName(aName)
|
|
{
|
|
}
|
|
|
|
bool
|
|
SharedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx,
|
|
JS::MutableHandle<JSObject*> aReflector)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
MOZ_ASSERT(mWorkerPrivate->IsSharedWorker());
|
|
|
|
JS::CompartmentOptions options;
|
|
mWorkerPrivate->CopyJSCompartmentOptions(options);
|
|
|
|
return SharedWorkerGlobalScopeBinding_workers::Wrap(aCx, this, this, options,
|
|
GetWorkerPrincipal(),
|
|
true, aReflector);
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope,
|
|
mClients, mRegistration)
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorkerGlobalScope)
|
|
NS_INTERFACE_MAP_END_INHERITING(WorkerGlobalScope)
|
|
|
|
NS_IMPL_ADDREF_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope)
|
|
NS_IMPL_RELEASE_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope)
|
|
|
|
ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(WorkerPrivate* aWorkerPrivate,
|
|
const nsACString& aScope)
|
|
: WorkerGlobalScope(aWorkerPrivate),
|
|
mScope(NS_ConvertUTF8toUTF16(aScope))
|
|
{
|
|
}
|
|
|
|
ServiceWorkerGlobalScope::~ServiceWorkerGlobalScope()
|
|
{
|
|
}
|
|
|
|
bool
|
|
ServiceWorkerGlobalScope::WrapGlobalObject(JSContext* aCx,
|
|
JS::MutableHandle<JSObject*> aReflector)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
|
|
|
|
JS::CompartmentOptions options;
|
|
mWorkerPrivate->CopyJSCompartmentOptions(options);
|
|
|
|
return ServiceWorkerGlobalScopeBinding_workers::Wrap(aCx, this, this, options,
|
|
GetWorkerPrincipal(),
|
|
true, aReflector);
|
|
}
|
|
|
|
ServiceWorkerClients*
|
|
ServiceWorkerGlobalScope::Clients()
|
|
{
|
|
if (!mClients) {
|
|
mClients = new ServiceWorkerClients(this);
|
|
}
|
|
|
|
return mClients;
|
|
}
|
|
|
|
ServiceWorkerRegistrationWorkerThread*
|
|
ServiceWorkerGlobalScope::Registration()
|
|
{
|
|
if (!mRegistration) {
|
|
mRegistration =
|
|
new ServiceWorkerRegistrationWorkerThread(mWorkerPrivate, mScope);
|
|
}
|
|
|
|
return mRegistration;
|
|
}
|
|
|
|
namespace {
|
|
|
|
class SkipWaitingResultRunnable final : public WorkerRunnable
|
|
{
|
|
nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
|
|
|
|
public:
|
|
SkipWaitingResultRunnable(WorkerPrivate* aWorkerPrivate,
|
|
PromiseWorkerProxy* aPromiseProxy)
|
|
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
|
|
, mPromiseProxy(aPromiseProxy)
|
|
{
|
|
AssertIsOnMainThread();
|
|
}
|
|
|
|
virtual bool
|
|
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
|
{
|
|
MOZ_ASSERT(aWorkerPrivate);
|
|
aWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
nsRefPtr<Promise> promise = mPromiseProxy->WorkerPromise();
|
|
promise->MaybeResolve(JS::UndefinedHandleValue);
|
|
|
|
// Release the reference on the worker thread.
|
|
mPromiseProxy->CleanUp(aCx);
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
class WorkerScopeSkipWaitingRunnable final : public nsRunnable
|
|
{
|
|
nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
|
|
nsCString mScope;
|
|
|
|
public:
|
|
WorkerScopeSkipWaitingRunnable(PromiseWorkerProxy* aPromiseProxy,
|
|
const nsCString& aScope)
|
|
: mPromiseProxy(aPromiseProxy)
|
|
, mScope(aScope)
|
|
{
|
|
MOZ_ASSERT(aPromiseProxy);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
Run() override
|
|
{
|
|
AssertIsOnMainThread();
|
|
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
|
MOZ_ASSERT(swm);
|
|
|
|
MutexAutoLock lock(mPromiseProxy->Lock());
|
|
if (mPromiseProxy->CleanedUp()) {
|
|
return NS_OK;
|
|
}
|
|
|
|
WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
|
|
swm->SetSkipWaitingFlag(workerPrivate->GetPrincipal(), mScope,
|
|
workerPrivate->ServiceWorkerID());
|
|
|
|
nsRefPtr<SkipWaitingResultRunnable> runnable =
|
|
new SkipWaitingResultRunnable(workerPrivate, mPromiseProxy);
|
|
|
|
AutoJSAPI jsapi;
|
|
jsapi.Init();
|
|
runnable->Dispatch(jsapi.cx());
|
|
return NS_OK;
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
already_AddRefed<Promise>
|
|
ServiceWorkerGlobalScope::SkipWaiting(ErrorResult& aRv)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
|
|
|
|
nsRefPtr<Promise> promise = Promise::Create(this, aRv);
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
return nullptr;
|
|
}
|
|
|
|
nsRefPtr<PromiseWorkerProxy> promiseProxy =
|
|
PromiseWorkerProxy::Create(mWorkerPrivate, promise);
|
|
if (!promiseProxy) {
|
|
promise->MaybeResolve(JS::UndefinedHandleValue);
|
|
return promise.forget();
|
|
}
|
|
|
|
nsRefPtr<WorkerScopeSkipWaitingRunnable> runnable =
|
|
new WorkerScopeSkipWaitingRunnable(promiseProxy,
|
|
NS_ConvertUTF16toUTF8(mScope));
|
|
|
|
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
|
return promise.forget();
|
|
}
|
|
|
|
// static
|
|
bool
|
|
ServiceWorkerGlobalScope::InterceptionEnabled(JSContext* aCx, JSObject* aObj)
|
|
{
|
|
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
|
MOZ_ASSERT(worker);
|
|
worker->AssertIsOnWorkerThread();
|
|
return worker->InterceptionEnabled();
|
|
}
|
|
|
|
WorkerDebuggerGlobalScope::WorkerDebuggerGlobalScope(
|
|
WorkerPrivate* aWorkerPrivate)
|
|
: mWorkerPrivate(aWorkerPrivate)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
}
|
|
|
|
WorkerDebuggerGlobalScope::~WorkerDebuggerGlobalScope()
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
}
|
|
|
|
NS_IMPL_ADDREF_INHERITED(WorkerDebuggerGlobalScope, DOMEventTargetHelper)
|
|
NS_IMPL_RELEASE_INHERITED(WorkerDebuggerGlobalScope, DOMEventTargetHelper)
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerDebuggerGlobalScope)
|
|
NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
|
|
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
|
|
|
bool
|
|
WorkerDebuggerGlobalScope::WrapGlobalObject(JSContext* aCx,
|
|
JS::MutableHandle<JSObject*> aReflector)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
JS::CompartmentOptions options;
|
|
mWorkerPrivate->CopyJSCompartmentOptions(options);
|
|
|
|
return WorkerDebuggerGlobalScopeBinding::Wrap(aCx, this, this, options,
|
|
GetWorkerPrincipal(), true,
|
|
aReflector);
|
|
}
|
|
|
|
void
|
|
WorkerDebuggerGlobalScope::GetGlobal(JSContext* aCx,
|
|
JS::MutableHandle<JSObject*> aGlobal)
|
|
{
|
|
aGlobal.set(mWorkerPrivate->GetOrCreateGlobalScope(aCx)->GetWrapper());
|
|
}
|
|
|
|
class WorkerDebuggerSandboxPrivate : public nsIGlobalObject,
|
|
public nsWrapperCache
|
|
{
|
|
public:
|
|
explicit WorkerDebuggerSandboxPrivate(JSObject *global)
|
|
{
|
|
SetWrapper(global);
|
|
}
|
|
|
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(WorkerDebuggerSandboxPrivate,
|
|
nsIGlobalObject)
|
|
|
|
virtual JSObject *GetGlobalJSObject() override
|
|
{
|
|
return GetWrapper();
|
|
}
|
|
|
|
virtual JSObject* WrapObject(JSContext* cx,
|
|
JS::Handle<JSObject*> aGivenProto) override
|
|
{
|
|
MOZ_CRASH("WorkerDebuggerSandboxPrivate doesn't use DOM bindings!");
|
|
}
|
|
|
|
private:
|
|
virtual ~WorkerDebuggerSandboxPrivate()
|
|
{
|
|
ClearWrapper();
|
|
}
|
|
};
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerDebuggerSandboxPrivate)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WorkerDebuggerSandboxPrivate)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
|
tmp->UnlinkHostObjectURIs();
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WorkerDebuggerSandboxPrivate)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
|
tmp->TraverseHostObjectURIs(cb);
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(WorkerDebuggerSandboxPrivate)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(WorkerDebuggerSandboxPrivate)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(WorkerDebuggerSandboxPrivate)
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerDebuggerSandboxPrivate)
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
|
NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
static bool
|
|
workerdebuggersandbox_enumerate(JSContext *cx, JS::Handle<JSObject *> obj)
|
|
{
|
|
return JS_EnumerateStandardClasses(cx, obj);
|
|
}
|
|
|
|
static bool
|
|
workerdebuggersandbox_resolve(JSContext *cx, JS::Handle<JSObject *> obj,
|
|
JS::Handle<jsid> id, bool *resolvedp)
|
|
{
|
|
return JS_ResolveStandardClass(cx, obj, id, resolvedp);
|
|
}
|
|
|
|
static bool
|
|
workerdebuggersandbox_convert(JSContext *cx, JS::Handle<JSObject *> obj,
|
|
JSType type, JS::MutableHandle<JS::Value> vp)
|
|
{
|
|
if (type == JSTYPE_OBJECT) {
|
|
vp.setObject(*obj);
|
|
return true;
|
|
}
|
|
|
|
return JS::OrdinaryToPrimitive(cx, obj, type, vp);
|
|
}
|
|
|
|
static void
|
|
workerdebuggersandbox_finalize(js::FreeOp *fop, JSObject *obj)
|
|
{
|
|
nsIGlobalObject *globalObject =
|
|
static_cast<nsIGlobalObject *>(JS_GetPrivate(obj));
|
|
NS_RELEASE(globalObject);
|
|
}
|
|
|
|
static void
|
|
workerdebuggersandbox_moved(JSObject *obj, const JSObject *old)
|
|
{
|
|
}
|
|
|
|
const js::Class workerdebuggersandbox_class = {
|
|
"workerdebuggersandbox",
|
|
JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS,
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
workerdebuggersandbox_enumerate,
|
|
workerdebuggersandbox_resolve,
|
|
nullptr, /* mayResolve */
|
|
workerdebuggersandbox_convert,
|
|
workerdebuggersandbox_finalize,
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
JS_GlobalObjectTraceHook,
|
|
JS_NULL_CLASS_SPEC, {
|
|
nullptr,
|
|
nullptr,
|
|
false,
|
|
nullptr,
|
|
workerdebuggersandbox_moved
|
|
}, JS_NULL_OBJECT_OPS
|
|
};
|
|
|
|
void
|
|
WorkerDebuggerGlobalScope::CreateSandbox(JSContext* aCx, const nsAString& aName,
|
|
JS::Handle<JSObject*> aPrototype,
|
|
JS::MutableHandle<JSObject*> aResult)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
JS::CompartmentOptions options;
|
|
options.setInvisibleToDebugger(true);
|
|
|
|
JS::Rooted<JSObject*> sandbox(aCx,
|
|
JS_NewGlobalObject(aCx, js::Jsvalify(&workerdebuggersandbox_class), nullptr,
|
|
JS::DontFireOnNewGlobalHook, options));
|
|
if (!sandbox) {
|
|
JS_ReportError(aCx, "Can't create sandbox!");
|
|
aResult.set(nullptr);
|
|
return;
|
|
}
|
|
|
|
{
|
|
JSAutoCompartment ac(aCx, sandbox);
|
|
|
|
JS::Rooted<JSObject*> prototype(aCx, aPrototype);
|
|
if (!JS_WrapObject(aCx, &prototype)) {
|
|
JS_ReportError(aCx, "Can't wrap sandbox prototype!");
|
|
aResult.set(nullptr);
|
|
return;
|
|
}
|
|
|
|
if (!JS_SetPrototype(aCx, sandbox, prototype)) {
|
|
JS_ReportError(aCx, "Can't set sandbox prototype!");
|
|
aResult.set(nullptr);
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsIGlobalObject> globalObject =
|
|
new WorkerDebuggerSandboxPrivate(sandbox);
|
|
|
|
// Pass on ownership of globalObject to |sandbox|.
|
|
JS_SetPrivate(sandbox, globalObject.forget().take());
|
|
}
|
|
|
|
JS_FireOnNewGlobalObject(aCx, sandbox);
|
|
|
|
if (!JS_WrapObject(aCx, &sandbox)) {
|
|
JS_ReportError(aCx, "Can't wrap sandbox!");
|
|
aResult.set(nullptr);
|
|
return;
|
|
}
|
|
|
|
aResult.set(sandbox);
|
|
}
|
|
|
|
void
|
|
WorkerDebuggerGlobalScope::LoadSubScript(JSContext* aCx,
|
|
const nsAString& aURL,
|
|
const Optional<JS::Handle<JSObject*>>& aSandbox,
|
|
ErrorResult& aRv)
|
|
{
|
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
|
|
|
Maybe<JSAutoCompartment> ac;
|
|
if (aSandbox.WasPassed()) {
|
|
JS::Rooted<JSObject*> sandbox(aCx, js::CheckedUnwrap(aSandbox.Value()));
|
|
if (!IsDebuggerSandbox(sandbox)) {
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
return;
|
|
}
|
|
|
|
ac.emplace(aCx, sandbox);
|
|
}
|
|
|
|
nsTArray<nsString> urls;
|
|
urls.AppendElement(aURL);
|
|
scriptloader::Load(aCx, mWorkerPrivate, urls, DebuggerScript, aRv);
|
|
}
|
|
|
|
void
|
|
WorkerDebuggerGlobalScope::EnterEventLoop()
|
|
{
|
|
mWorkerPrivate->EnterDebuggerEventLoop();
|
|
}
|
|
|
|
void
|
|
WorkerDebuggerGlobalScope::LeaveEventLoop()
|
|
{
|
|
mWorkerPrivate->LeaveDebuggerEventLoop();
|
|
}
|
|
|
|
void
|
|
WorkerDebuggerGlobalScope::PostMessage(const nsAString& aMessage)
|
|
{
|
|
mWorkerPrivate->PostMessageToDebugger(aMessage);
|
|
}
|
|
|
|
void
|
|
WorkerDebuggerGlobalScope::SetImmediate(JSContext* aCx, Function& aHandler,
|
|
ErrorResult& aRv)
|
|
{
|
|
mWorkerPrivate->SetDebuggerImmediate(aCx, aHandler, aRv);
|
|
}
|
|
|
|
void
|
|
WorkerDebuggerGlobalScope::ReportError(JSContext* aCx,
|
|
const nsAString& aMessage)
|
|
{
|
|
JS::AutoFilename afn;
|
|
uint32_t lineno = 0;
|
|
JS::DescribeScriptedCaller(aCx, &afn, &lineno);
|
|
nsString filename(NS_ConvertUTF8toUTF16(afn.get()));
|
|
mWorkerPrivate->ReportErrorToDebugger(filename, lineno, aMessage);
|
|
}
|
|
|
|
void
|
|
WorkerDebuggerGlobalScope::Dump(JSContext* aCx,
|
|
const Optional<nsAString>& aString) const
|
|
{
|
|
return mWorkerPrivate->GetOrCreateGlobalScope(aCx)->Dump(aString);
|
|
}
|
|
|
|
nsIGlobalObject*
|
|
GetGlobalObjectForGlobal(JSObject* global)
|
|
{
|
|
nsIGlobalObject* globalObject = nullptr;
|
|
UNWRAP_WORKER_OBJECT(WorkerGlobalScope, global, globalObject);
|
|
|
|
if (!globalObject) {
|
|
UNWRAP_OBJECT(WorkerDebuggerGlobalScope, global, globalObject);
|
|
|
|
if (!globalObject) {
|
|
MOZ_ASSERT(IsDebuggerSandbox(global));
|
|
globalObject = static_cast<nsIGlobalObject *>(JS_GetPrivate(global));
|
|
|
|
MOZ_ASSERT(globalObject);
|
|
}
|
|
}
|
|
|
|
return globalObject;
|
|
}
|
|
|
|
bool
|
|
IsWorkerGlobal(JSObject* object)
|
|
{
|
|
nsIGlobalObject* globalObject = nullptr;
|
|
return NS_SUCCEEDED(UNWRAP_WORKER_OBJECT(WorkerGlobalScope, object,
|
|
globalObject)) && !!globalObject;
|
|
}
|
|
|
|
bool
|
|
IsDebuggerGlobal(JSObject* object)
|
|
{
|
|
nsIGlobalObject* globalObject = nullptr;
|
|
return NS_SUCCEEDED(UNWRAP_OBJECT(WorkerDebuggerGlobalScope, object,
|
|
globalObject)) && !!globalObject;
|
|
}
|
|
|
|
bool
|
|
IsDebuggerSandbox(JSObject* object)
|
|
{
|
|
return js::GetObjectClass(object) == &workerdebuggersandbox_class;
|
|
}
|
|
|
|
bool
|
|
GetterOnlyJSNative(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
|
|
{
|
|
JS_ReportErrorNumber(aCx, js::GetErrorMessage, nullptr, JSMSG_GETTER_ONLY);
|
|
return false;
|
|
}
|
|
|
|
END_WORKERS_NAMESPACE
|