forked from mirrors/gecko-dev
		
	 f53affe1cb
			
		
	
	
		f53affe1cb
		
	
	
	
	
		
			
			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)
		
			
				
	
	
		
			1123 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1123 lines
		
	
	
	
		
			36 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 "jsfriendapi.h"
 | |
| #include "mozilla/EventListenerManager.h"
 | |
| #include "mozilla/dom/BindingDeclarations.h"
 | |
| #include "mozilla/dom/Clients.h"
 | |
| #include "mozilla/dom/ClientState.h"
 | |
| #include "mozilla/dom/Console.h"
 | |
| #include "mozilla/dom/CSPEvalChecker.h"
 | |
| #include "mozilla/dom/DebuggerNotification.h"
 | |
| #include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h"
 | |
| #include "mozilla/dom/Fetch.h"
 | |
| #include "mozilla/dom/FunctionBinding.h"
 | |
| #include "mozilla/dom/IDBFactory.h"
 | |
| #include "mozilla/dom/ImageBitmap.h"
 | |
| #include "mozilla/dom/ImageBitmapBinding.h"
 | |
| #include "mozilla/dom/Performance.h"
 | |
| #include "mozilla/dom/Promise.h"
 | |
| #include "mozilla/dom/PromiseWorkerProxy.h"
 | |
| #include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
 | |
| #include "mozilla/dom/SharedWorkerGlobalScopeBinding.h"
 | |
| #include "mozilla/dom/SimpleGlobalObject.h"
 | |
| #include "mozilla/dom/TimeoutHandler.h"
 | |
| #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
 | |
| #include "mozilla/dom/WorkerGlobalScopeBinding.h"
 | |
| #include "mozilla/dom/WorkerLocation.h"
 | |
| #include "mozilla/dom/WorkerNavigator.h"
 | |
| #include "mozilla/dom/cache/CacheStorage.h"
 | |
| #include "mozilla/StorageAccess.h"
 | |
| #include "nsContentUtils.h"
 | |
| #include "nsJSUtils.h"
 | |
| #include "nsServiceManagerUtils.h"
 | |
| 
 | |
| #include "mozilla/dom/Document.h"
 | |
| #include "nsIServiceWorkerManager.h"
 | |
| #include "nsIScriptError.h"
 | |
| 
 | |
| #ifdef ANDROID
 | |
| #  include <android/log.h>
 | |
| #endif
 | |
| 
 | |
| #include "Crypto.h"
 | |
| #include "Principal.h"
 | |
| #include "RuntimeService.h"
 | |
| #include "ScriptLoader.h"
 | |
| #include "WorkerPrivate.h"
 | |
| #include "WorkerRunnable.h"
 | |
| #include "mozilla/dom/ServiceWorkerManager.h"
 | |
| #include "mozilla/dom/ServiceWorkerRegistration.h"
 | |
| 
 | |
| #ifdef XP_WIN
 | |
| #  undef PostMessage
 | |
| #endif
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace dom {
 | |
| 
 | |
| using mozilla::dom::cache::CacheStorage;
 | |
| using mozilla::ipc::PrincipalInfo;
 | |
| 
 | |
| class WorkerScriptTimeoutHandler final : public ScriptTimeoutHandler {
 | |
|  public:
 | |
|   NS_DECL_ISUPPORTS_INHERITED
 | |
|   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WorkerScriptTimeoutHandler,
 | |
|                                            ScriptTimeoutHandler)
 | |
| 
 | |
|   WorkerScriptTimeoutHandler(JSContext* aCx, nsIGlobalObject* aGlobal,
 | |
|                              const nsAString& aExpression)
 | |
|       : ScriptTimeoutHandler(aCx, aGlobal, aExpression) {}
 | |
| 
 | |
|   MOZ_CAN_RUN_SCRIPT virtual bool Call(const char* aExecutionReason) override;
 | |
| 
 | |
|  private:
 | |
|   virtual ~WorkerScriptTimeoutHandler() {}
 | |
| };
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_INHERITED(WorkerScriptTimeoutHandler,
 | |
|                                    ScriptTimeoutHandler)
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerScriptTimeoutHandler)
 | |
| NS_INTERFACE_MAP_END_INHERITING(ScriptTimeoutHandler)
 | |
| 
 | |
| NS_IMPL_ADDREF_INHERITED(WorkerScriptTimeoutHandler, ScriptTimeoutHandler)
 | |
| NS_IMPL_RELEASE_INHERITED(WorkerScriptTimeoutHandler, ScriptTimeoutHandler)
 | |
| 
 | |
| bool WorkerScriptTimeoutHandler::Call(const char* aExecutionReason) {
 | |
|   nsAutoMicroTask mt;
 | |
|   AutoEntryScript aes(mGlobal, aExecutionReason, false);
 | |
| 
 | |
|   JSContext* cx = aes.cx();
 | |
|   JS::CompileOptions options(cx);
 | |
|   options.setFileAndLine(mFileName.get(), mLineNo).setNoScriptRval(true);
 | |
| 
 | |
|   JS::Rooted<JS::Value> unused(cx);
 | |
|   JS::SourceText<char16_t> srcBuf;
 | |
|   if (!srcBuf.init(cx, mExpr.BeginReading(), mExpr.Length(),
 | |
|                    JS::SourceOwnership::Borrowed) ||
 | |
|       !JS::Evaluate(cx, options, srcBuf, &unused)) {
 | |
|     if (!JS_IsExceptionPending(cx)) {
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| };
 | |
| 
 | |
| WorkerGlobalScope::WorkerGlobalScope(WorkerPrivate* aWorkerPrivate)
 | |
|     : mSerialEventTarget(aWorkerPrivate->HybridEventTarget()),
 | |
|       mWindowInteractionsAllowed(0),
 | |
|       mWorkerPrivate(aWorkerPrivate) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   // We should always have an event target when the global is created.
 | |
|   MOZ_DIAGNOSTIC_ASSERT(mSerialEventTarget);
 | |
| 
 | |
|   // In workers, each DETH must have an owner. Because the global scope doesn't
 | |
|   // have one, let's set it as owner of itself.
 | |
|   BindToOwner(static_cast<nsIGlobalObject*>(this));
 | |
| }
 | |
| 
 | |
| 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(mCrypto)
 | |
|   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)
 | |
|   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDebuggerNotificationManager)
 | |
|   tmp->TraverseHostObjectURIs(cb);
 | |
|   tmp->mWorkerPrivate->TraverseTimeouts(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(mCrypto)
 | |
|   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)
 | |
|   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDebuggerNotificationManager)
 | |
|   tmp->UnlinkHostObjectURIs();
 | |
|   tmp->mWorkerPrivate->UnlinkTimeouts();
 | |
| NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerGlobalScope,
 | |
|                                                DOMEventTargetHelper)
 | |
|   tmp->mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 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!");
 | |
| }
 | |
| 
 | |
| void WorkerGlobalScope::NoteTerminating() {
 | |
|   DisconnectEventTargetObjects();
 | |
|   StartDying();
 | |
| }
 | |
| 
 | |
| already_AddRefed<Console> WorkerGlobalScope::GetConsole(ErrorResult& aRv) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   if (!mConsole) {
 | |
|     mConsole = Console::Create(mWorkerPrivate->GetJSContext(), nullptr, aRv);
 | |
|     if (NS_WARN_IF(aRv.Failed())) {
 | |
|       return nullptr;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   RefPtr<Console> console = mConsole;
 | |
|   return console.forget();
 | |
| }
 | |
| 
 | |
| Crypto* WorkerGlobalScope::GetCrypto(ErrorResult& aError) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   if (!mCrypto) {
 | |
|     mCrypto = new Crypto(this);
 | |
|   }
 | |
| 
 | |
|   return mCrypto;
 | |
| }
 | |
| 
 | |
| already_AddRefed<CacheStorage> WorkerGlobalScope::GetCaches(ErrorResult& aRv) {
 | |
|   if (!mCacheStorage) {
 | |
|     MOZ_ASSERT(mWorkerPrivate);
 | |
|     mCacheStorage = CacheStorage::CreateOnWorker(cache::DEFAULT_NAMESPACE, this,
 | |
|                                                  mWorkerPrivate, aRv);
 | |
|   }
 | |
| 
 | |
|   RefPtr<CacheStorage> ref = mCacheStorage;
 | |
|   return ref.forget();
 | |
| }
 | |
| 
 | |
| bool WorkerGlobalScope::IsSecureContext() const {
 | |
|   bool globalSecure = JS::GetIsSecureContext(
 | |
|       js::GetNonCCWObjectRealm(GetWrapperPreserveColor()));
 | |
|   MOZ_ASSERT(globalSecure == mWorkerPrivate->IsSecureContext());
 | |
|   return globalSecure;
 | |
| }
 | |
| 
 | |
| already_AddRefed<WorkerLocation> WorkerGlobalScope::Location() {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   if (!mLocation) {
 | |
|     WorkerPrivate::LocationInfo& info = mWorkerPrivate->GetLocationInfo();
 | |
| 
 | |
|     mLocation = WorkerLocation::Create(info);
 | |
|     MOZ_ASSERT(mLocation);
 | |
|   }
 | |
| 
 | |
|   RefPtr<WorkerLocation> location = mLocation;
 | |
|   return location.forget();
 | |
| }
 | |
| 
 | |
| already_AddRefed<WorkerNavigator> WorkerGlobalScope::Navigator() {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   if (!mNavigator) {
 | |
|     mNavigator = WorkerNavigator::Create(mWorkerPrivate->OnLine());
 | |
|     MOZ_ASSERT(mNavigator);
 | |
|   }
 | |
| 
 | |
|   RefPtr<WorkerNavigator> navigator = mNavigator;
 | |
|   return navigator.forget();
 | |
| }
 | |
| 
 | |
| already_AddRefed<WorkerNavigator> WorkerGlobalScope::GetExistingNavigator()
 | |
|     const {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   RefPtr<WorkerNavigator> navigator = mNavigator;
 | |
|   return navigator.forget();
 | |
| }
 | |
| 
 | |
| 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();
 | |
| 
 | |
|   UniquePtr<SerializedStackHolder> stack;
 | |
|   if (mWorkerPrivate->IsWatchedByDevtools()) {
 | |
|     stack = GetCurrentStackForNetMonitor(aCx);
 | |
|   }
 | |
| 
 | |
|   workerinternals::Load(mWorkerPrivate, std::move(stack), aScriptURLs,
 | |
|                         WorkerScript, aRv);
 | |
| }
 | |
| 
 | |
| int32_t WorkerGlobalScope::SetTimeout(JSContext* aCx, Function& aHandler,
 | |
|                                       const int32_t aTimeout,
 | |
|                                       const Sequence<JS::Value>& aArguments,
 | |
|                                       ErrorResult& aRv) {
 | |
|   return SetTimeoutOrInterval(aCx, aHandler, aTimeout, aArguments, false, aRv);
 | |
| }
 | |
| 
 | |
| int32_t WorkerGlobalScope::SetTimeout(JSContext* aCx, const nsAString& aHandler,
 | |
|                                       const int32_t aTimeout,
 | |
|                                       const Sequence<JS::Value>& /* unused */,
 | |
|                                       ErrorResult& aRv) {
 | |
|   return SetTimeoutOrInterval(aCx, aHandler, aTimeout, false, aRv);
 | |
| }
 | |
| 
 | |
| void WorkerGlobalScope::ClearTimeout(int32_t aHandle) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearTimeout);
 | |
| 
 | |
|   mWorkerPrivate->ClearTimeout(aHandle);
 | |
| }
 | |
| 
 | |
| int32_t WorkerGlobalScope::SetInterval(JSContext* aCx, Function& aHandler,
 | |
|                                        const int32_t aTimeout,
 | |
|                                        const Sequence<JS::Value>& aArguments,
 | |
|                                        ErrorResult& aRv) {
 | |
|   return SetTimeoutOrInterval(aCx, aHandler, aTimeout, aArguments, true, aRv);
 | |
| }
 | |
| 
 | |
| int32_t WorkerGlobalScope::SetInterval(JSContext* aCx,
 | |
|                                        const nsAString& aHandler,
 | |
|                                        const int32_t aTimeout,
 | |
|                                        const Sequence<JS::Value>& /* unused */,
 | |
|                                        ErrorResult& aRv) {
 | |
|   return SetTimeoutOrInterval(aCx, aHandler, aTimeout, true, aRv);
 | |
| }
 | |
| 
 | |
| void WorkerGlobalScope::ClearInterval(int32_t aHandle) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearInterval);
 | |
| 
 | |
|   mWorkerPrivate->ClearTimeout(aHandle);
 | |
| }
 | |
| 
 | |
| int32_t WorkerGlobalScope::SetTimeoutOrInterval(
 | |
|     JSContext* aCx, Function& aHandler, const int32_t aTimeout,
 | |
|     const Sequence<JS::Value>& aArguments, bool aIsInterval, ErrorResult& aRv) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   DebuggerNotificationDispatch(
 | |
|       this, aIsInterval ? DebuggerNotificationType::SetInterval
 | |
|                         : DebuggerNotificationType::SetTimeout);
 | |
| 
 | |
|   nsTArray<JS::Heap<JS::Value>> args;
 | |
|   if (!args.AppendElements(aArguments, fallible)) {
 | |
|     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   RefPtr<TimeoutHandler> handler =
 | |
|       new CallbackTimeoutHandler(aCx, this, &aHandler, std::move(args));
 | |
| 
 | |
|   return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, aIsInterval, aRv);
 | |
| }
 | |
| 
 | |
| int32_t WorkerGlobalScope::SetTimeoutOrInterval(JSContext* aCx,
 | |
|                                                 const nsAString& aHandler,
 | |
|                                                 const int32_t aTimeout,
 | |
|                                                 bool aIsInterval,
 | |
|                                                 ErrorResult& aRv) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   DebuggerNotificationDispatch(
 | |
|       this, aIsInterval ? DebuggerNotificationType::SetInterval
 | |
|                         : DebuggerNotificationType::SetTimeout);
 | |
| 
 | |
|   bool allowEval = false;
 | |
|   aRv =
 | |
|       CSPEvalChecker::CheckForWorker(aCx, mWorkerPrivate, aHandler, &allowEval);
 | |
|   if (NS_WARN_IF(aRv.Failed()) || !allowEval) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   RefPtr<TimeoutHandler> handler =
 | |
|       new WorkerScriptTimeoutHandler(aCx, this, aHandler);
 | |
| 
 | |
|   return mWorkerPrivate->SetTimeout(aCx, handler, aTimeout, aIsInterval, aRv);
 | |
| }
 | |
| 
 | |
| void WorkerGlobalScope::GetOrigin(nsAString& aOrigin) const {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   aOrigin = mWorkerPrivate->Origin();
 | |
| }
 | |
| 
 | |
| 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 (!nsJSUtils::DumpEnabled()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   NS_ConvertUTF16toUTF8 str(aString.Value());
 | |
| 
 | |
|   MOZ_LOG(nsContentUtils::DOMDumpLog(), LogLevel::Debug,
 | |
|           ("[Worker.Dump] %s", str.get()));
 | |
| #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 = Performance::CreateForWorker(mWorkerPrivate);
 | |
|   }
 | |
| 
 | |
|   return mPerformance;
 | |
| }
 | |
| 
 | |
| bool WorkerGlobalScope::IsInAutomation(JSContext* aCx, JSObject* /* unused */) {
 | |
|   return GetWorkerPrivateFromContext(aCx)->IsInAutomation();
 | |
| }
 | |
| 
 | |
| void WorkerGlobalScope::GetJSTestingFunctions(
 | |
|     JSContext* aCx, JS::MutableHandle<JSObject*> aFunctions, ErrorResult& aRv) {
 | |
|   JSObject* obj = js::GetTestingFunctions(aCx);
 | |
|   if (!obj) {
 | |
|     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   aFunctions.set(obj);
 | |
| }
 | |
| 
 | |
| already_AddRefed<Promise> WorkerGlobalScope::Fetch(
 | |
|     const RequestOrUSVString& aInput, const RequestInit& aInit,
 | |
|     CallerType aCallerType, ErrorResult& aRv) {
 | |
|   return FetchRequest(this, aInput, aInit, aCallerType, aRv);
 | |
| }
 | |
| 
 | |
| already_AddRefed<IDBFactory> WorkerGlobalScope::GetIndexedDB(
 | |
|     ErrorResult& aErrorResult) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   RefPtr<IDBFactory> indexedDB = mIndexedDB;
 | |
| 
 | |
|   if (!indexedDB) {
 | |
|     StorageAccess access = mWorkerPrivate->StorageAccess();
 | |
| 
 | |
|     if (access == StorageAccess::eDeny) {
 | |
|       NS_WARNING("IndexedDB is not allowed in this worker!");
 | |
|       aErrorResult = NS_ERROR_DOM_SECURITY_ERR;
 | |
|       return nullptr;
 | |
|     }
 | |
| 
 | |
|     if (ShouldPartitionStorage(access) &&
 | |
|         !StoragePartitioningEnabled(access, mWorkerPrivate->CookieSettings())) {
 | |
|       NS_WARNING("IndexedDB is not allowed in this worker!");
 | |
|       aErrorResult = NS_ERROR_DOM_SECURITY_ERR;
 | |
|       return nullptr;
 | |
|     }
 | |
| 
 | |
|     const PrincipalInfo& principalInfo =
 | |
|         mWorkerPrivate->GetEffectiveStoragePrincipalInfo();
 | |
| 
 | |
|     nsresult rv = IDBFactory::CreateForWorker(this, 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(
 | |
|     JSContext* aCx, const ImageBitmapSource& aImage, ErrorResult& aRv) {
 | |
|   return ImageBitmap::Create(this, aImage, Nothing(), aRv);
 | |
| }
 | |
| 
 | |
| already_AddRefed<Promise> WorkerGlobalScope::CreateImageBitmap(
 | |
|     JSContext* aCx, 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);
 | |
| }
 | |
| 
 | |
| nsresult WorkerGlobalScope::Dispatch(
 | |
|     TaskCategory aCategory, already_AddRefed<nsIRunnable>&& aRunnable) {
 | |
|   return EventTargetFor(aCategory)->Dispatch(std::move(aRunnable),
 | |
|                                              NS_DISPATCH_NORMAL);
 | |
| }
 | |
| 
 | |
| nsISerialEventTarget* WorkerGlobalScope::EventTargetFor(
 | |
|     TaskCategory aCategory) const {
 | |
|   return mSerialEventTarget;
 | |
| }
 | |
| 
 | |
| AbstractThread* WorkerGlobalScope::AbstractMainThreadFor(
 | |
|     TaskCategory aCategory) {
 | |
|   MOZ_CRASH("AbstractMainThreadFor not supported for workers.");
 | |
| }
 | |
| 
 | |
| mozilla::dom::DebuggerNotificationManager*
 | |
| WorkerGlobalScope::GetOrCreateDebuggerNotificationManager() {
 | |
|   if (!mDebuggerNotificationManager) {
 | |
|     mDebuggerNotificationManager = new DebuggerNotificationManager(this);
 | |
|   }
 | |
| 
 | |
|   return mDebuggerNotificationManager;
 | |
| }
 | |
| 
 | |
| mozilla::dom::DebuggerNotificationManager*
 | |
| WorkerGlobalScope::GetExistingDebuggerNotificationManager() {
 | |
|   return mDebuggerNotificationManager;
 | |
| }
 | |
| 
 | |
| Maybe<ClientInfo> WorkerGlobalScope::GetClientInfo() const {
 | |
|   return mWorkerPrivate->GetClientInfo();
 | |
| }
 | |
| 
 | |
| Maybe<ClientState> WorkerGlobalScope::GetClientState() const {
 | |
|   Maybe<ClientState> state;
 | |
|   state.emplace(mWorkerPrivate->GetClientState());
 | |
|   return state;
 | |
| }
 | |
| 
 | |
| Maybe<ServiceWorkerDescriptor> WorkerGlobalScope::GetController() const {
 | |
|   return mWorkerPrivate->GetController();
 | |
| }
 | |
| 
 | |
| RefPtr<mozilla::dom::ServiceWorkerRegistration>
 | |
| WorkerGlobalScope::GetServiceWorkerRegistration(
 | |
|     const ServiceWorkerRegistrationDescriptor& aDescriptor) const {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   RefPtr<ServiceWorkerRegistration> ref;
 | |
|   ForEachEventTargetObject([&](DOMEventTargetHelper* aTarget, bool* aDoneOut) {
 | |
|     RefPtr<ServiceWorkerRegistration> swr = do_QueryObject(aTarget);
 | |
|     if (!swr || !swr->MatchesDescriptor(aDescriptor)) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     ref = swr.forget();
 | |
|     *aDoneOut = true;
 | |
|   });
 | |
|   return ref.forget();
 | |
| }
 | |
| 
 | |
| RefPtr<ServiceWorkerRegistration>
 | |
| WorkerGlobalScope::GetOrCreateServiceWorkerRegistration(
 | |
|     const ServiceWorkerRegistrationDescriptor& aDescriptor) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   RefPtr<ServiceWorkerRegistration> ref =
 | |
|       GetServiceWorkerRegistration(aDescriptor);
 | |
|   if (!ref) {
 | |
|     ref = ServiceWorkerRegistration::CreateForWorker(mWorkerPrivate, this,
 | |
|                                                      aDescriptor);
 | |
|   }
 | |
|   return ref.forget();
 | |
| }
 | |
| 
 | |
| void WorkerGlobalScope::FirstPartyStorageAccessGranted() {
 | |
|   // Reset the IndexedDB factory.
 | |
|   mIndexedDB = nullptr;
 | |
| 
 | |
|   // Reset DOM Cache
 | |
|   mCacheStorage = nullptr;
 | |
| }
 | |
| 
 | |
| DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(
 | |
|     WorkerPrivate* aWorkerPrivate, const nsString& aName)
 | |
|     : WorkerGlobalScope(aWorkerPrivate), mName(aName) {}
 | |
| 
 | |
| bool DedicatedWorkerGlobalScope::WrapGlobalObject(
 | |
|     JSContext* aCx, JS::MutableHandle<JSObject*> aReflector) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   MOZ_ASSERT(!mWorkerPrivate->IsSharedWorker());
 | |
| 
 | |
|   JS::RealmOptions options;
 | |
|   mWorkerPrivate->CopyJSRealmOptions(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 && xpc::ShouldDiscardSystemSource();
 | |
|   const bool extraWarnings =
 | |
|       usesSystemPrincipal && xpc::ExtraWarningsForSystemJS();
 | |
| 
 | |
|   JS::RealmBehaviors& behaviors = options.behaviors();
 | |
|   behaviors.setDiscardSource(discardSource)
 | |
|       .extraWarningsOverride()
 | |
|       .set(extraWarnings);
 | |
| 
 | |
|   xpc::SetPrefableRealmOptions(options);
 | |
| 
 | |
|   return DedicatedWorkerGlobalScope_Binding::Wrap(
 | |
|       aCx, this, this, options, GetWorkerPrincipal(), true, aReflector);
 | |
| }
 | |
| 
 | |
| void DedicatedWorkerGlobalScope::PostMessage(
 | |
|     JSContext* aCx, JS::Handle<JS::Value> aMessage,
 | |
|     const Sequence<JSObject*>& aTransferable, ErrorResult& aRv) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   mWorkerPrivate->PostMessageToParent(aCx, aMessage, aTransferable, aRv);
 | |
| }
 | |
| 
 | |
| void DedicatedWorkerGlobalScope::PostMessage(JSContext* aCx,
 | |
|                                              JS::Handle<JS::Value> aMessage,
 | |
|                                              const PostMessageOptions& aOptions,
 | |
|                                              ErrorResult& aRv) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   mWorkerPrivate->PostMessageToParent(aCx, aMessage, aOptions.mTransfer, aRv);
 | |
| }
 | |
| 
 | |
| void DedicatedWorkerGlobalScope::Close() {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   mWorkerPrivate->CloseInternal();
 | |
| }
 | |
| 
 | |
| SharedWorkerGlobalScope::SharedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate,
 | |
|                                                  const nsString& aName)
 | |
|     : WorkerGlobalScope(aWorkerPrivate), mName(aName) {}
 | |
| 
 | |
| bool SharedWorkerGlobalScope::WrapGlobalObject(
 | |
|     JSContext* aCx, JS::MutableHandle<JSObject*> aReflector) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   MOZ_ASSERT(mWorkerPrivate->IsSharedWorker());
 | |
| 
 | |
|   JS::RealmOptions options;
 | |
|   mWorkerPrivate->CopyJSRealmOptions(options);
 | |
| 
 | |
|   return SharedWorkerGlobalScope_Binding::Wrap(
 | |
|       aCx, this, this, options, GetWorkerPrincipal(), true, aReflector);
 | |
| }
 | |
| 
 | |
| void SharedWorkerGlobalScope::Close() {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   mWorkerPrivate->CloseInternal();
 | |
| }
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope,
 | |
|                                    mClients, mRegistration)
 | |
| NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerGlobalScope)
 | |
| NS_INTERFACE_MAP_END_INHERITING(WorkerGlobalScope)
 | |
| 
 | |
| NS_IMPL_ADDREF_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope)
 | |
| NS_IMPL_RELEASE_INHERITED(ServiceWorkerGlobalScope, WorkerGlobalScope)
 | |
| 
 | |
| ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(
 | |
|     WorkerPrivate* aWorkerPrivate,
 | |
|     const ServiceWorkerRegistrationDescriptor& aRegistrationDescriptor)
 | |
|     : WorkerGlobalScope(aWorkerPrivate),
 | |
|       mScope(NS_ConvertUTF8toUTF16(aRegistrationDescriptor.Scope()))
 | |
| 
 | |
|       // Eagerly create the registration because we will need to receive updates
 | |
|       // about the state of the registration.  We can't wait until first access
 | |
|       // to start receiving these.
 | |
|       ,
 | |
|       mRegistration(
 | |
|           GetOrCreateServiceWorkerRegistration(aRegistrationDescriptor)) {}
 | |
| 
 | |
| ServiceWorkerGlobalScope::~ServiceWorkerGlobalScope() {}
 | |
| 
 | |
| bool ServiceWorkerGlobalScope::WrapGlobalObject(
 | |
|     JSContext* aCx, JS::MutableHandle<JSObject*> aReflector) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
 | |
| 
 | |
|   JS::RealmOptions options;
 | |
|   mWorkerPrivate->CopyJSRealmOptions(options);
 | |
| 
 | |
|   return ServiceWorkerGlobalScope_Binding::Wrap(
 | |
|       aCx, this, this, options, GetWorkerPrincipal(), true, aReflector);
 | |
| }
 | |
| 
 | |
| already_AddRefed<Clients> ServiceWorkerGlobalScope::GetClients() {
 | |
|   if (!mClients) {
 | |
|     mClients = new Clients(this);
 | |
|   }
 | |
| 
 | |
|   RefPtr<Clients> ref = mClients;
 | |
|   return ref.forget();
 | |
| }
 | |
| 
 | |
| ServiceWorkerRegistration* ServiceWorkerGlobalScope::Registration() {
 | |
|   return mRegistration;
 | |
| }
 | |
| 
 | |
| EventHandlerNonNull* ServiceWorkerGlobalScope::GetOnfetch() {
 | |
|   MOZ_ASSERT(mWorkerPrivate);
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   return GetEventHandler(nsGkAtoms::onfetch);
 | |
| }
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| class ReportFetchListenerWarningRunnable final : public Runnable {
 | |
|   const nsCString mScope;
 | |
|   nsCString mSourceSpec;
 | |
|   uint32_t mLine;
 | |
|   uint32_t mColumn;
 | |
| 
 | |
|  public:
 | |
|   explicit ReportFetchListenerWarningRunnable(const nsString& aScope)
 | |
|       : mozilla::Runnable("ReportFetchListenerWarningRunnable"),
 | |
|         mScope(NS_ConvertUTF16toUTF8(aScope)) {
 | |
|     WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
 | |
|     MOZ_ASSERT(workerPrivate);
 | |
|     JSContext* cx = workerPrivate->GetJSContext();
 | |
|     MOZ_ASSERT(cx);
 | |
| 
 | |
|     nsJSUtils::GetCallingLocation(cx, mSourceSpec, &mLine, &mColumn);
 | |
|   }
 | |
| 
 | |
|   NS_IMETHOD
 | |
|   Run() override {
 | |
|     AssertIsOnMainThread();
 | |
| 
 | |
|     ServiceWorkerManager::LocalizeAndReportToAllClients(
 | |
|         mScope, "ServiceWorkerNoFetchHandler", nsTArray<nsString>{},
 | |
|         nsIScriptError::warningFlag, NS_ConvertUTF8toUTF16(mSourceSpec),
 | |
|         EmptyString(), mLine, mColumn);
 | |
| 
 | |
|     return NS_OK;
 | |
|   }
 | |
| };
 | |
| 
 | |
| }  // anonymous namespace
 | |
| 
 | |
| void ServiceWorkerGlobalScope::SetOnfetch(
 | |
|     mozilla::dom::EventHandlerNonNull* aCallback) {
 | |
|   MOZ_ASSERT(mWorkerPrivate);
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   if (aCallback) {
 | |
|     if (mWorkerPrivate->WorkerScriptExecutedSuccessfully()) {
 | |
|       RefPtr<Runnable> r = new ReportFetchListenerWarningRunnable(mScope);
 | |
|       mWorkerPrivate->DispatchToMainThreadForMessaging(r.forget());
 | |
|     }
 | |
|     mWorkerPrivate->SetFetchHandlerWasAdded();
 | |
|   }
 | |
|   SetEventHandler(nsGkAtoms::onfetch, aCallback);
 | |
| }
 | |
| 
 | |
| void ServiceWorkerGlobalScope::EventListenerAdded(nsAtom* aType) {
 | |
|   MOZ_ASSERT(mWorkerPrivate);
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   if (aType != nsGkAtoms::onfetch) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (mWorkerPrivate->WorkerScriptExecutedSuccessfully()) {
 | |
|     RefPtr<Runnable> r = new ReportFetchListenerWarningRunnable(mScope);
 | |
|     mWorkerPrivate->DispatchToMainThreadForMessaging(r.forget());
 | |
|   }
 | |
| 
 | |
|   mWorkerPrivate->SetFetchHandlerWasAdded();
 | |
| }
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| class SkipWaitingResultRunnable final : public WorkerRunnable {
 | |
|   RefPtr<PromiseWorkerProxy> mPromiseProxy;
 | |
| 
 | |
|  public:
 | |
|   SkipWaitingResultRunnable(WorkerPrivate* aWorkerPrivate,
 | |
|                             PromiseWorkerProxy* aPromiseProxy)
 | |
|       : WorkerRunnable(aWorkerPrivate), mPromiseProxy(aPromiseProxy) {
 | |
|     AssertIsOnMainThread();
 | |
|   }
 | |
| 
 | |
|   virtual bool WorkerRun(JSContext* aCx,
 | |
|                          WorkerPrivate* aWorkerPrivate) override {
 | |
|     MOZ_ASSERT(aWorkerPrivate);
 | |
|     aWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|     RefPtr<Promise> promise = mPromiseProxy->WorkerPromise();
 | |
|     promise->MaybeResolveWithUndefined();
 | |
| 
 | |
|     // Release the reference on the worker thread.
 | |
|     mPromiseProxy->CleanUp();
 | |
| 
 | |
|     return true;
 | |
|   }
 | |
| };
 | |
| 
 | |
| class WorkerScopeSkipWaitingRunnable final : public Runnable {
 | |
|   RefPtr<PromiseWorkerProxy> mPromiseProxy;
 | |
|   nsCString mScope;
 | |
| 
 | |
|  public:
 | |
|   WorkerScopeSkipWaitingRunnable(PromiseWorkerProxy* aPromiseProxy,
 | |
|                                  const nsCString& aScope)
 | |
|       : mozilla::Runnable("WorkerScopeSkipWaitingRunnable"),
 | |
|         mPromiseProxy(aPromiseProxy),
 | |
|         mScope(aScope) {
 | |
|     MOZ_ASSERT(aPromiseProxy);
 | |
|   }
 | |
| 
 | |
|   NS_IMETHOD
 | |
|   Run() override {
 | |
|     AssertIsOnMainThread();
 | |
| 
 | |
|     MutexAutoLock lock(mPromiseProxy->Lock());
 | |
|     if (mPromiseProxy->CleanedUp()) {
 | |
|       return NS_OK;
 | |
|     }
 | |
| 
 | |
|     WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
 | |
|     MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
 | |
| 
 | |
|     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
 | |
|     if (swm) {
 | |
|       swm->SetSkipWaitingFlag(workerPrivate->GetPrincipal(), mScope,
 | |
|                               workerPrivate->ServiceWorkerID());
 | |
|     }
 | |
| 
 | |
|     RefPtr<SkipWaitingResultRunnable> runnable =
 | |
|         new SkipWaitingResultRunnable(workerPrivate, mPromiseProxy);
 | |
| 
 | |
|     if (!runnable->Dispatch()) {
 | |
|       NS_WARNING("Failed to dispatch SkipWaitingResultRunnable to the worker.");
 | |
|     }
 | |
|     return NS_OK;
 | |
|   }
 | |
| };
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| already_AddRefed<Promise> ServiceWorkerGlobalScope::SkipWaiting(
 | |
|     ErrorResult& aRv) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   MOZ_ASSERT(mWorkerPrivate->IsServiceWorker());
 | |
| 
 | |
|   RefPtr<Promise> promise = Promise::Create(this, aRv);
 | |
|   if (NS_WARN_IF(aRv.Failed())) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   RefPtr<PromiseWorkerProxy> promiseProxy =
 | |
|       PromiseWorkerProxy::Create(mWorkerPrivate, promise);
 | |
|   if (!promiseProxy) {
 | |
|     promise->MaybeResolveWithUndefined();
 | |
|     return promise.forget();
 | |
|   }
 | |
| 
 | |
|   RefPtr<WorkerScopeSkipWaitingRunnable> runnable =
 | |
|       new WorkerScopeSkipWaitingRunnable(promiseProxy,
 | |
|                                          NS_ConvertUTF16toUTF8(mScope));
 | |
| 
 | |
|   MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(runnable.forget()));
 | |
|   return promise.forget();
 | |
| }
 | |
| 
 | |
| WorkerDebuggerGlobalScope::WorkerDebuggerGlobalScope(
 | |
|     WorkerPrivate* aWorkerPrivate)
 | |
|     : mWorkerPrivate(aWorkerPrivate),
 | |
|       mSerialEventTarget(aWorkerPrivate->HybridEventTarget()) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   // We should always have an event target when the global is created.
 | |
|   MOZ_DIAGNOSTIC_ASSERT(mSerialEventTarget);
 | |
| 
 | |
|   // In workers, each DETH must have an owner. Because the global scope doesn't
 | |
|   // have an owner, let's set it as owner of itself.
 | |
|   BindToOwner(static_cast<nsIGlobalObject*>(this));
 | |
| }
 | |
| 
 | |
| WorkerDebuggerGlobalScope::~WorkerDebuggerGlobalScope() {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| }
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerDebuggerGlobalScope)
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerDebuggerGlobalScope,
 | |
|                                                   DOMEventTargetHelper)
 | |
|   tmp->mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
 | |
| NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerDebuggerGlobalScope,
 | |
|                                                 DOMEventTargetHelper)
 | |
|   tmp->mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
 | |
| NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerDebuggerGlobalScope,
 | |
|                                                DOMEventTargetHelper)
 | |
|   tmp->mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| NS_IMPL_CYCLE_COLLECTION_TRACE_END
 | |
| 
 | |
| 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::RealmOptions options;
 | |
|   mWorkerPrivate->CopyJSRealmOptions(options);
 | |
| 
 | |
|   return WorkerDebuggerGlobalScope_Binding::Wrap(
 | |
|       aCx, this, this, options, GetWorkerPrincipal(), true, aReflector);
 | |
| }
 | |
| 
 | |
| void WorkerDebuggerGlobalScope::GetGlobal(JSContext* aCx,
 | |
|                                           JS::MutableHandle<JSObject*> aGlobal,
 | |
|                                           ErrorResult& aRv) {
 | |
|   WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
 | |
|   if (!scope) {
 | |
|     aRv.Throw(NS_ERROR_FAILURE);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   aGlobal.set(scope->GetWrapper());
 | |
| }
 | |
| 
 | |
| void WorkerDebuggerGlobalScope::CreateSandbox(
 | |
|     JSContext* aCx, const nsAString& aName, JS::Handle<JSObject*> aPrototype,
 | |
|     JS::MutableHandle<JSObject*> aResult, ErrorResult& aRv) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   aResult.set(nullptr);
 | |
| 
 | |
|   JS::Rooted<JS::Value> protoVal(aCx);
 | |
|   protoVal.setObjectOrNull(aPrototype);
 | |
|   JS::Rooted<JSObject*> sandbox(
 | |
|       aCx,
 | |
|       SimpleGlobalObject::Create(
 | |
|           SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox, protoVal));
 | |
| 
 | |
|   if (!sandbox) {
 | |
|     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!JS_WrapObject(aCx, &sandbox)) {
 | |
|     aRv.NoteJSContextException(aCx);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   aResult.set(sandbox);
 | |
| }
 | |
| 
 | |
| void WorkerDebuggerGlobalScope::LoadSubScript(
 | |
|     JSContext* aCx, const nsAString& aURL,
 | |
|     const Optional<JS::Handle<JSObject*>>& aSandbox, ErrorResult& aRv) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   Maybe<JSAutoRealm> ar;
 | |
|   if (aSandbox.WasPassed()) {
 | |
|     // We only care about worker debugger sandbox objects here, so
 | |
|     // CheckedUnwrapStatic is fine.
 | |
|     JS::Rooted<JSObject*> sandbox(aCx,
 | |
|                                   js::CheckedUnwrapStatic(aSandbox.Value()));
 | |
|     if (!sandbox || !IsWorkerDebuggerSandbox(sandbox)) {
 | |
|       aRv.Throw(NS_ERROR_INVALID_ARG);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     ar.emplace(aCx, sandbox);
 | |
|   }
 | |
| 
 | |
|   nsTArray<nsString> urls;
 | |
|   urls.AppendElement(aURL);
 | |
|   workerinternals::Load(mWorkerPrivate, nullptr, urls, DebuggerScript, aRv);
 | |
| }
 | |
| 
 | |
| void WorkerDebuggerGlobalScope::EnterEventLoop() {
 | |
|   // We're on the worker thread here, and WorkerPrivate's refcounting is
 | |
|   // non-threadsafe: you can only do it on the parent thread.  What that
 | |
|   // means in practice is that we're relying on it being kept alive while
 | |
|   // we run.  Hopefully.
 | |
|   MOZ_KnownLive(mWorkerPrivate)->EnterDebuggerEventLoop();
 | |
| }
 | |
| 
 | |
| void WorkerDebuggerGlobalScope::LeaveEventLoop() {
 | |
|   mWorkerPrivate->LeaveDebuggerEventLoop();
 | |
| }
 | |
| 
 | |
| void WorkerDebuggerGlobalScope::PostMessage(const nsAString& aMessage) {
 | |
|   mWorkerPrivate->PostMessageToDebugger(aMessage);
 | |
| }
 | |
| 
 | |
| void WorkerDebuggerGlobalScope::SetImmediate(Function& aHandler,
 | |
|                                              ErrorResult& aRv) {
 | |
|   mWorkerPrivate->SetDebuggerImmediate(aHandler, aRv);
 | |
| }
 | |
| 
 | |
| void WorkerDebuggerGlobalScope::ReportError(JSContext* aCx,
 | |
|                                             const nsAString& aMessage) {
 | |
|   JS::AutoFilename chars;
 | |
|   uint32_t lineno = 0;
 | |
|   JS::DescribeScriptedCaller(aCx, &chars, &lineno);
 | |
|   nsString filename(NS_ConvertUTF8toUTF16(chars.get()));
 | |
|   mWorkerPrivate->ReportErrorToDebugger(filename, lineno, aMessage);
 | |
| }
 | |
| 
 | |
| void WorkerDebuggerGlobalScope::RetrieveConsoleEvents(
 | |
|     JSContext* aCx, nsTArray<JS::Value>& aEvents, ErrorResult& aRv) {
 | |
|   WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
 | |
|   if (!scope) {
 | |
|     aRv.Throw(NS_ERROR_FAILURE);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   RefPtr<Console> console = scope->GetConsole(aRv);
 | |
|   if (NS_WARN_IF(aRv.Failed())) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   console->RetrieveConsoleEvents(aCx, aEvents, aRv);
 | |
| }
 | |
| 
 | |
| void WorkerDebuggerGlobalScope::SetConsoleEventHandler(JSContext* aCx,
 | |
|                                                        AnyCallback* aHandler,
 | |
|                                                        ErrorResult& aRv) {
 | |
|   WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
 | |
|   if (!scope) {
 | |
|     aRv.Throw(NS_ERROR_FAILURE);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   RefPtr<Console> console = scope->GetConsole(aRv);
 | |
|   if (NS_WARN_IF(aRv.Failed())) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   console->SetConsoleEventHandler(aHandler);
 | |
| }
 | |
| 
 | |
| already_AddRefed<Console> WorkerDebuggerGlobalScope::GetConsole(
 | |
|     ErrorResult& aRv) {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
| 
 | |
|   // Debugger console has its own console object.
 | |
|   if (!mConsole) {
 | |
|     mConsole = Console::Create(mWorkerPrivate->GetJSContext(), nullptr, aRv);
 | |
|     if (NS_WARN_IF(aRv.Failed())) {
 | |
|       return nullptr;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   RefPtr<Console> console = mConsole;
 | |
|   return console.forget();
 | |
| }
 | |
| 
 | |
| void WorkerDebuggerGlobalScope::Dump(JSContext* aCx,
 | |
|                                      const Optional<nsAString>& aString) const {
 | |
|   WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
 | |
|   if (scope) {
 | |
|     scope->Dump(aString);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void WorkerDebuggerGlobalScope::Atob(const nsAString& aAtob, nsAString& aOutput,
 | |
|                                      ErrorResult& aRv) const {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   aRv = nsContentUtils::Atob(aAtob, aOutput);
 | |
| }
 | |
| 
 | |
| void WorkerDebuggerGlobalScope::Btoa(const nsAString& aBtoa, nsAString& aOutput,
 | |
|                                      ErrorResult& aRv) const {
 | |
|   mWorkerPrivate->AssertIsOnWorkerThread();
 | |
|   aRv = nsContentUtils::Btoa(aBtoa, aOutput);
 | |
| }
 | |
| 
 | |
| nsresult WorkerDebuggerGlobalScope::Dispatch(
 | |
|     TaskCategory aCategory, already_AddRefed<nsIRunnable>&& aRunnable) {
 | |
|   return EventTargetFor(aCategory)->Dispatch(std::move(aRunnable),
 | |
|                                              NS_DISPATCH_NORMAL);
 | |
| }
 | |
| 
 | |
| nsISerialEventTarget* WorkerDebuggerGlobalScope::EventTargetFor(
 | |
|     TaskCategory aCategory) const {
 | |
|   return mSerialEventTarget;
 | |
| }
 | |
| 
 | |
| AbstractThread* WorkerDebuggerGlobalScope::AbstractMainThreadFor(
 | |
|     TaskCategory aCategory) {
 | |
|   MOZ_CRASH("AbstractMainThreadFor not supported for workers.");
 | |
| }
 | |
| 
 | |
| bool IsWorkerGlobal(JSObject* object) {
 | |
|   return IS_INSTANCE_OF(WorkerGlobalScope, object);
 | |
| }
 | |
| 
 | |
| bool IsWorkerDebuggerGlobal(JSObject* object) {
 | |
|   return IS_INSTANCE_OF(WorkerDebuggerGlobalScope, object);
 | |
| }
 | |
| 
 | |
| bool IsWorkerDebuggerSandbox(JSObject* object) {
 | |
|   return SimpleGlobalObject::SimpleGlobalType(object) ==
 | |
|          SimpleGlobalObject::GlobalType::WorkerDebuggerSandbox;
 | |
| }
 | |
| 
 | |
| }  // namespace dom
 | |
| }  // namespace mozilla
 |