diff options
Diffstat (limited to 'dom')
92 files changed, 2869 insertions, 1120 deletions
diff --git a/dom/abort/AbortController.cpp b/dom/abort/AbortController.cpp new file mode 100644 index 0000000000..bd8159e7b5 --- /dev/null +++ b/dom/abort/AbortController.cpp @@ -0,0 +1,98 @@ +/* -*- 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 "AbortController.h" +#include "AbortSignal.h" +#include "mozilla/dom/AbortControllerBinding.h" +#include "WorkerPrivate.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AbortController, mGlobal, mSignal) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(AbortController) +NS_IMPL_CYCLE_COLLECTING_RELEASE(AbortController) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AbortController) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +/* static */ bool +AbortController::IsEnabled(JSContext* aCx, JSObject* aGlobal) +{ + if (NS_IsMainThread()) { + return Preferences::GetBool("dom.abortController.enabled", false); + } + + using namespace workers; + + // Otherwise, check the pref via the WorkerPrivate + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + if (!workerPrivate) { + return false; + } + + return workerPrivate->AbortControllerEnabled(); +} + +/* static */ already_AddRefed<AbortController> +AbortController::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) +{ + nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); + if (!global) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + RefPtr<AbortController> abortController = new AbortController(global); + return abortController.forget(); +} + +AbortController::AbortController(nsIGlobalObject* aGlobal) + : mGlobal(aGlobal) + , mAborted(false) +{} + +JSObject* +AbortController::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) +{ + return AbortControllerBinding::Wrap(aCx, this, aGivenProto); +} + +nsIGlobalObject* +AbortController::GetParentObject() const +{ + return mGlobal; +} + +AbortSignal* +AbortController::Signal() +{ + if (!mSignal) { + mSignal = new AbortSignal(this, mAborted); + } + + return mSignal; +} + +void +AbortController::Abort() +{ + if (mAborted) { + return; + } + + mAborted = true; + + if (mSignal) { + mSignal->Abort(); + } +} + +} // dom namespace +} // mozilla namespace diff --git a/dom/abort/AbortController.h b/dom/abort/AbortController.h new file mode 100644 index 0000000000..0b99dc49c2 --- /dev/null +++ b/dom/abort/AbortController.h @@ -0,0 +1,59 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_AbortController_h +#define mozilla_dom_AbortController_h + +#include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/AbortSignal.h" +#include "nsCycleCollectionParticipant.h" +#include "nsWrapperCache.h" +#include "mozilla/ErrorResult.h" +#include "nsIGlobalObject.h" + +namespace mozilla { +namespace dom { + +class AbortController final : public nsISupports + , public nsWrapperCache +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AbortController) + + static bool + IsEnabled(JSContext* aCx, JSObject* aGlobal); + + static already_AddRefed<AbortController> + Constructor(const GlobalObject& aGlobal, ErrorResult& aRv); + + explicit AbortController(nsIGlobalObject* aGlobal); + + JSObject* + WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; + + nsIGlobalObject* + GetParentObject() const; + + AbortSignal* + Signal(); + + void + Abort(); + +private: + ~AbortController() = default; + + nsCOMPtr<nsIGlobalObject> mGlobal; + RefPtr<AbortSignal> mSignal; + + bool mAborted; +}; + +} // dom namespace +} // mozilla namespace + +#endif // mozilla_dom_AbortController_h diff --git a/dom/abort/AbortSignal.cpp b/dom/abort/AbortSignal.cpp new file mode 100644 index 0000000000..20f36d2abb --- /dev/null +++ b/dom/abort/AbortSignal.cpp @@ -0,0 +1,124 @@ +/* -*- 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 "AbortSignal.h" +#include "AbortController.h" +#include "mozilla/dom/Event.h" +#include "mozilla/dom/AbortSignalBinding.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_CLASS(AbortSignal) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(AbortSignal, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mController) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(AbortSignal, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mController) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AbortSignal) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +NS_IMPL_ADDREF_INHERITED(AbortSignal, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(AbortSignal, DOMEventTargetHelper) + +AbortSignal::AbortSignal(AbortController* aController, + bool aAborted) + : DOMEventTargetHelper(aController->GetParentObject()) + , mController(aController) + , mAborted(aAborted) +{} + +AbortSignal::AbortSignal(bool aAborted) + : mAborted(aAborted) +{} + +JSObject* +AbortSignal::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) +{ + return AbortSignalBinding::Wrap(aCx, this, aGivenProto); +} + +bool +AbortSignal::Aborted() const +{ + return mAborted; +} + +void +AbortSignal::Abort() +{ + MOZ_ASSERT(!mAborted); + mAborted = true; + + // Let's inform the followers. + for (uint32_t i = 0; i < mFollowers.Length(); ++i) { + mFollowers[i]->Aborted(); + } + + EventInit init; + init.mBubbles = false; + init.mCancelable = false; + + RefPtr<Event> event = + Event::Constructor(this, NS_LITERAL_STRING("abort"), init); + event->SetTrusted(true); + + bool dummy; + DispatchEvent(event, &dummy); +} + +void +AbortSignal::AddFollower(AbortSignal::Follower* aFollower) +{ + MOZ_DIAGNOSTIC_ASSERT(aFollower); + if (!mFollowers.Contains(aFollower)) { + mFollowers.AppendElement(aFollower); + } +} + +void +AbortSignal::RemoveFollower(AbortSignal::Follower* aFollower) +{ + MOZ_DIAGNOSTIC_ASSERT(aFollower); + mFollowers.RemoveElement(aFollower); +} + +// AbortSignal::Follower +// ---------------------------------------------------------------------------- + +AbortSignal::Follower::~Follower() +{ + Unfollow(); +} + +void +AbortSignal::Follower::Follow(AbortSignal* aSignal) +{ + MOZ_DIAGNOSTIC_ASSERT(aSignal); + + Unfollow(); + + mFollowingSignal = aSignal; + aSignal->AddFollower(this); +} + +void +AbortSignal::Follower::Unfollow() +{ + if (mFollowingSignal) { + mFollowingSignal->RemoveFollower(this); + mFollowingSignal = nullptr; + } +} + +} // dom namespace +} // mozilla namespace diff --git a/dom/abort/AbortSignal.h b/dom/abort/AbortSignal.h new file mode 100644 index 0000000000..35e5829429 --- /dev/null +++ b/dom/abort/AbortSignal.h @@ -0,0 +1,76 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_AbortSignal_h +#define mozilla_dom_AbortSignal_h + +#include "mozilla/DOMEventTargetHelper.h" + +namespace mozilla { +namespace dom { + +class AbortController; +class AbortSignal; + +class AbortSignal final : public DOMEventTargetHelper +{ +public: + // This class must be implemented by objects who want to follow a AbortSignal. + class Follower + { + public: + virtual void Aborted() = 0; + + protected: + virtual ~Follower(); + + void + Follow(AbortSignal* aSignal); + + void + Unfollow(); + + RefPtr<AbortSignal> mFollowingSignal; + }; + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AbortSignal, DOMEventTargetHelper) + + AbortSignal(AbortController* aController, bool aAborted); + explicit AbortSignal(bool aAborted); + + JSObject* + WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; + + bool + Aborted() const; + + void + Abort(); + + IMPL_EVENT_HANDLER(abort); + + void + AddFollower(Follower* aFollower); + + void + RemoveFollower(Follower* aFollower); + +private: + ~AbortSignal() = default; + + RefPtr<AbortController> mController; + + // Raw pointers. Follower unregisters itself in the DTOR. + nsTArray<Follower*> mFollowers; + + bool mAborted; +}; + +} // dom namespace +} // mozilla namespace + +#endif // mozilla_dom_AbortSignal_h diff --git a/dom/abort/moz.build b/dom/abort/moz.build new file mode 100644 index 0000000000..cb48ee15f4 --- /dev/null +++ b/dom/abort/moz.build @@ -0,0 +1,26 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +with Files("**"): + BUG_COMPONENT = ("Core", "DOM") + +TEST_DIRS += ['tests'] + +EXPORTS.mozilla.dom += [ + 'AbortController.h', + 'AbortSignal.h', +] + +UNIFIED_SOURCES += [ + 'AbortController.cpp', + 'AbortSignal.cpp', +] + +LOCAL_INCLUDES += [ + '../workers', +] + +FINAL_LIBRARY = 'xul' diff --git a/dom/abort/tests/file_abort_controller.html b/dom/abort/tests/file_abort_controller.html new file mode 100644 index 0000000000..3a15fa3469 --- /dev/null +++ b/dom/abort/tests/file_abort_controller.html @@ -0,0 +1,113 @@ +<script> +function ok(a, msg) { + parent.postMessage({ type: "check", status: !!a, message: msg }, "*"); +} + +function is(a, b, msg) { + ok(a === b, msg); +} + +function testWebIDL() { + ok("FetchController" in self, "We have a FetchController prototype"); + ok("FetchSignal" in self, "We have a FetchSignal prototype"); + + var fc = new FetchController(); + ok(!!fc, "FetchController can be created"); + ok(fc instanceof FetchController, "FetchController is a FetchController"); + + ok(!!fc.signal, "FetchController has a signal"); + ok(fc.signal instanceof FetchSignal, "fetchSignal is a FetchSignal"); + is(fc.signal.aborted, false, "By default FetchSignal.aborted is false"); + next(); +} + +function testUpdateData() { + var fc = new FetchController(); + + is(fc.signal.aborted, false, "By default FetchSignal.aborted is false"); + + fc.abort(); + is(fc.signal.aborted, true, "Signal is aborted"); + + next(); +} + +function testAbortEvent() { + var fc = new FetchController(); + fc.signal.onabort = function(e) { + is(e.type, "abort", "Abort received"); + next(); + } + fc.abort(); +} + +function testAbortedFetch() { + var fc = new FetchController(); + fc.abort(); + + fetch('slow.sjs', { signal: fc.signal }).then(() => { + ok(false, "Fetch should not return a resolved promise"); + }, e => { + is(e.name, "AbortError", "We have an abort error"); + }).then(next); +} + +function testFetchAndAbort() { + var fc = new FetchController(); + + var p = fetch('slow.sjs', { signal: fc.signal }); + fc.abort(); + + p.then(() => { + ok(false, "Fetch should not return a resolved promise"); + }, e => { + is(e.name, "AbortError", "We have an abort error"); + }).then(next); +} + +function testWorkerAbortedFetch() { + var w = new Worker('worker_fetch_controller.js'); + w.onmessage = function(e) { + ok(e.data, "Abort + Fetch works in workers"); + next(); + } + w.postMessage('testWorkerAbortedFetch'); +} + +function testWorkerFetchAndAbort() { + var w = new Worker('worker_fetch_controller.js'); + w.onmessage = function(e) { + ok(e.data, "Abort + Fetch works in workers"); + next(); + } + w.postMessage('testWorkerFetchAndAbort'); +} + +var steps = [ + // Simple stuff + testWebIDL, + testUpdateData, + + // Event propagation + testAbortEvent, + + // fetch + signaling + testAbortedFetch, + testFetchAndAbort, + testWorkerAbortedFetch, + testWorkerFetchAndAbort, +]; + +function next() { + if (!steps.length) { + parent.postMessage({ type: "finish" }, "*"); + return; + } + + var step = steps.shift(); + step(); +} + +next(); + +</script> diff --git a/dom/abort/tests/mochitest.ini b/dom/abort/tests/mochitest.ini new file mode 100644 index 0000000000..c8cc95fdab --- /dev/null +++ b/dom/abort/tests/mochitest.ini @@ -0,0 +1,6 @@ +[DEFAULT] +support-files = + file_abort_controller.html + worker_fetch_controller.js + +[test_abort_controller.html] diff --git a/dom/abort/tests/moz.build b/dom/abort/tests/moz.build new file mode 100644 index 0000000000..8e5cb5d717 --- /dev/null +++ b/dom/abort/tests/moz.build @@ -0,0 +1,8 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +MOCHITEST_MANIFESTS += ['mochitest.ini'] + diff --git a/dom/abort/tests/test_abort_controller.html b/dom/abort/tests/test_abort_controller.html new file mode 100644 index 0000000000..812fb91616 --- /dev/null +++ b/dom/abort/tests/test_abort_controller.html @@ -0,0 +1,40 @@ +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<!DOCTYPE HTML> +<html> +<head> + <title>Test FetchController</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<script class="testbody" type="text/javascript"> + +SpecialPowers.pushPrefEnv({"set": [["dom.fetchController.enabled", true ]]}, () => { + let ifr = document.createElement('iframe'); + ifr.src = "file_fetch_controller.html"; + document.body.appendChild(ifr); + + onmessage = function(e) { + if (e.data.type == "finish") { + SimpleTest.finish(); + return; + } + + if (e.data.type == "check") { + ok(e.data.status, e.data.message); + return; + } + + ok(false, "Something when wrong."); + } +}); + +SimpleTest.waitForExplicitFinish(); + +</script> +</body> +</html> + diff --git a/dom/abort/tests/worker_abort_controller.js b/dom/abort/tests/worker_abort_controller.js new file mode 100644 index 0000000000..6fd1c78884 --- /dev/null +++ b/dom/abort/tests/worker_abort_controller.js @@ -0,0 +1,27 @@ +function testWorkerAbortedFetch() { + var fc = new AbortController(); + fc.abort(); + + fetch('slow.sjs', { signal: fc.signal }).then(() => { + postMessage(false); + }, e => { + postMessage(e.name == "AbortError"); + }); +} + +function testWorkerFetchAndAbort() { + var fc = new AbortController(); + + var p = fetch('slow.sjs', { signal: fc.signal }); + fc.abort(); + + p.then(() => { + postMessage(false); + }, e => { + postMessage(e.name == "AbortError"); + }); +} + +onmessage = function(e) { + self[e.data](); +} diff --git a/dom/base/CustomElementRegistry.cpp b/dom/base/CustomElementRegistry.cpp index f582d635f9..3f83221998 100644 --- a/dom/base/CustomElementRegistry.cpp +++ b/dom/base/CustomElementRegistry.cpp @@ -166,8 +166,11 @@ NS_INTERFACE_MAP_END /* static */ bool CustomElementRegistry::IsCustomElementEnabled(JSContext* aCx, JSObject* aObject) { + return false; +/* return Preferences::GetBool("dom.webcomponents.customelements.enabled") || Preferences::GetBool("dom.webcomponents.enabled"); +*/ } /* static */ already_AddRefed<CustomElementRegistry> diff --git a/dom/base/ImportManager.cpp b/dom/base/ImportManager.cpp index d0e514b591..1f4d376b37 100644 --- a/dom/base/ImportManager.cpp +++ b/dom/base/ImportManager.cpp @@ -6,6 +6,7 @@ #include "ImportManager.h" +#include "mozilla/dom/ScriptLoader.h" #include "mozilla/EventListenerManager.h" #include "HTMLLinkElement.h" #include "nsContentPolicyUtils.h" @@ -18,7 +19,6 @@ #include "nsIDOMEvent.h" #include "nsIPrincipal.h" #include "nsIScriptObjectPrincipal.h" -#include "nsScriptLoader.h" #include "nsNetUtil.h" //----------------------------------------------------------------------------- @@ -156,7 +156,7 @@ ImportLoader::Updater::UpdateMainReferrer(uint32_t aNewIdx) // Our nearest predecessor has changed. So let's add the ScriptLoader to the // new one if there is any. And remove it from the old one. RefPtr<ImportManager> manager = mLoader->Manager(); - nsScriptLoader* loader = mLoader->mDocument->ScriptLoader(); + ScriptLoader* loader = mLoader->mDocument->ScriptLoader(); ImportLoader*& pred = mLoader->mBlockingPredecessor; ImportLoader* newPred = manager->GetNearestPredecessor(newMainReferrer); if (pred) { @@ -339,7 +339,7 @@ ImportLoader::DispatchEventIfFinished(nsINode* aNode) } void -ImportLoader::AddBlockedScriptLoader(nsScriptLoader* aScriptLoader) +ImportLoader::AddBlockedScriptLoader(ScriptLoader* aScriptLoader) { if (mBlockedScriptLoaders.Contains(aScriptLoader)) { return; @@ -352,7 +352,7 @@ ImportLoader::AddBlockedScriptLoader(nsScriptLoader* aScriptLoader) } bool -ImportLoader::RemoveBlockedScriptLoader(nsScriptLoader* aScriptLoader) +ImportLoader::RemoveBlockedScriptLoader(ScriptLoader* aScriptLoader) { aScriptLoader->RemoveParserBlockingScriptExecutionBlocker(); return mBlockedScriptLoaders.RemoveElement(aScriptLoader); diff --git a/dom/base/ImportManager.h b/dom/base/ImportManager.h index 258d4691cf..ccc00125ae 100644 --- a/dom/base/ImportManager.h +++ b/dom/base/ImportManager.h @@ -45,8 +45,8 @@ #include "nsIStreamListener.h" #include "nsIWeakReferenceUtils.h" #include "nsRefPtrHashtable.h" -#include "nsScriptLoader.h" #include "nsURIHashKey.h" +#include "mozilla/dom/ScriptLoader.h" class nsIDocument; class nsIPrincipal; @@ -184,8 +184,8 @@ public: // and wait for that to run its scripts. We keep track of all the // ScriptRunners that are waiting for this import. NOTE: updating // the main referrer might change this list. - void AddBlockedScriptLoader(nsScriptLoader* aScriptLoader); - bool RemoveBlockedScriptLoader(nsScriptLoader* aScriptLoader); + void AddBlockedScriptLoader(ScriptLoader* aScriptLoader); + bool RemoveBlockedScriptLoader(ScriptLoader* aScriptLoader); void SetBlockingPredecessor(ImportLoader* aLoader); private: @@ -230,7 +230,7 @@ private: // List of pending ScriptLoaders that are waiting for this import // to finish. - nsTArray<RefPtr<nsScriptLoader>> mBlockedScriptLoaders; + nsTArray<RefPtr<ScriptLoader>> mBlockedScriptLoaders; // There is always exactly one referrer link that is flagged as // the main referrer the primary link. This is the one that is diff --git a/dom/base/Location.cpp b/dom/base/Location.cpp index 1483c32f9d..308e9a4ff6 100644 --- a/dom/base/Location.cpp +++ b/dom/base/Location.cpp @@ -32,9 +32,9 @@ #include "mozilla/Likely.h" #include "nsCycleCollectionParticipant.h" #include "nsNullPrincipal.h" -#include "ScriptSettings.h" #include "mozilla/Unused.h" #include "mozilla/dom/LocationBinding.h" +#include "mozilla/dom/ScriptSettings.h" namespace mozilla { namespace dom { diff --git a/dom/base/moz.build b/dom/base/moz.build index 89f1785ca7..aadafe4127 100755 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -26,7 +26,6 @@ XPIDL_SOURCES += [ 'nsIObjectLoadingContent.idl', 'nsIRemoteWindowContext.idl', 'nsIScriptChannel.idl', - 'nsIScriptLoaderObserver.idl', 'nsISelection.idl', 'nsISelectionController.idl', 'nsISelectionDisplay.idl', @@ -96,7 +95,6 @@ EXPORTS += [ 'nsINode.h', 'nsINodeList.h', 'nsIScriptContext.h', - 'nsIScriptElement.h', 'nsIScriptGlobalObject.h', 'nsIScriptNameSpaceManager.h', 'nsIScriptObjectPrincipal.h', @@ -117,7 +115,6 @@ EXPORTS += [ 'nsRange.h', 'nsReferencedElement.h', 'nsSandboxFlags.h', - 'nsScriptLoader.h', 'nsStructuredCloneContainer.h', 'nsStubAnimationObserver.h', 'nsStubDocumentObserver.h', @@ -208,7 +205,6 @@ EXPORTS.mozilla.dom += [ 'ResponsiveImageSelector.h', 'SameProcessMessageQueue.h', 'ScreenOrientation.h', - 'ScriptSettings.h', 'ShadowRoot.h', 'SimpleTreeIterator.h', 'StructuredCloneHolder.h', @@ -328,8 +324,6 @@ SOURCES += [ 'nsRange.cpp', 'nsReferencedElement.cpp', 'nsScreen.cpp', - 'nsScriptElement.cpp', - 'nsScriptLoader.cpp', 'nsScriptNameSpaceManager.cpp', 'nsStructuredCloneContainer.cpp', 'nsStubAnimationObserver.cpp', @@ -356,7 +350,6 @@ SOURCES += [ 'ResponsiveImageSelector.cpp', 'SameProcessMessageQueue.cpp', 'ScreenOrientation.cpp', - 'ScriptSettings.cpp', 'ShadowRoot.cpp', 'StructuredCloneHolder.cpp', 'StyleSheetList.cpp', diff --git a/dom/base/nsContentPermissionHelper.cpp b/dom/base/nsContentPermissionHelper.cpp index c57fc6233b..eaaec2a412 100644 --- a/dom/base/nsContentPermissionHelper.cpp +++ b/dom/base/nsContentPermissionHelper.cpp @@ -29,9 +29,8 @@ #include "nsIDocument.h" #include "nsIDOMEvent.h" #include "nsWeakPtr.h" -#include "ScriptSettings.h" -using mozilla::Unused; // <snicker> +using mozilla::Unused; using namespace mozilla::dom; using namespace mozilla; diff --git a/dom/base/nsContentSink.cpp b/dom/base/nsContentSink.cpp index 490f0ec17c..1e6465a1bf 100644 --- a/dom/base/nsContentSink.cpp +++ b/dom/base/nsContentSink.cpp @@ -10,7 +10,6 @@ */ #include "nsContentSink.h" -#include "nsScriptLoader.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "mozilla/css/Loader.h" @@ -49,6 +48,7 @@ #include "nsHTMLDNSPrefetch.h" #include "nsIObserverService.h" #include "mozilla/Preferences.h" +#include "mozilla/dom/ScriptLoader.h" #include "nsParserConstants.h" #include "nsSandboxFlags.h" diff --git a/dom/base/nsContentSink.h b/dom/base/nsContentSink.h index b1a7588740..2d914a8d7b 100644 --- a/dom/base/nsContentSink.h +++ b/dom/base/nsContentSink.h @@ -36,13 +36,16 @@ class nsIAtom; class nsIChannel; class nsIContent; class nsNodeInfoManager; -class nsScriptLoader; class nsIApplicationCache; namespace mozilla { namespace css { class Loader; } // namespace css + +namespace dom { +class ScriptLoader; +} // namespace dom } // namespace mozilla #ifdef DEBUG @@ -273,7 +276,7 @@ protected: nsCOMPtr<nsIDocShell> mDocShell; RefPtr<mozilla::css::Loader> mCSSLoader; RefPtr<nsNodeInfoManager> mNodeInfoManager; - RefPtr<nsScriptLoader> mScriptLoader; + RefPtr<mozilla::dom::ScriptLoader> mScriptLoader; // back off timer notification after count int32_t mBackoffCount; diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 3805937375..d0634b0f9d 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -1880,7 +1880,7 @@ nsDocument::Init() mScopeObject = do_GetWeakReference(global); MOZ_ASSERT(mScopeObject); - mScriptLoader = new nsScriptLoader(this); + mScriptLoader = new dom::ScriptLoader(this); mozilla::HoldJSObjects(this); @@ -4685,7 +4685,7 @@ nsDocument::GetWindowInternal() const return win; } -nsScriptLoader* +ScriptLoader* nsDocument::ScriptLoader() { return mScriptLoader; @@ -5709,9 +5709,9 @@ nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject) { JS::Rooted<JSObject*> obj(aCx, aObject); - if (Preferences::GetBool("dom.webcomponents.enabled")) { - return true; - } + //if (Preferences::GetBool("dom.webcomponents.enabled")) { + // return true; + //} // Check for the webcomponents permission. See Bug 1181555. JSAutoCompartment ac(aCx, obj); @@ -5725,9 +5725,9 @@ nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject) bool nsDocument::IsWebComponentsEnabled(dom::NodeInfo* aNodeInfo) { - if (Preferences::GetBool("dom.webcomponents.enabled")) { - return true; - } + //if (Preferences::GetBool("dom.webcomponents.enabled")) { + // return true; + //} nsIDocument* doc = aNodeInfo->GetDocument(); // Use GetScopeObject() here so that data documents work the same way as the @@ -5740,6 +5740,7 @@ nsDocument::IsWebComponentsEnabled(dom::NodeInfo* aNodeInfo) bool nsDocument::IsWebComponentsEnabled(nsPIDOMWindowInner* aWindow) { +/* if (aWindow) { nsresult rv; nsCOMPtr<nsIPermissionManager> permMgr = @@ -5753,7 +5754,7 @@ nsDocument::IsWebComponentsEnabled(nsPIDOMWindowInner* aWindow) return perm == nsIPermissionManager::ALLOW_ACTION; } - +*/ return false; } diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 8ea4993f07..a319ad13e6 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -31,7 +31,6 @@ #include "nsJSThingHashtable.h" #include "nsIScriptObjectPrincipal.h" #include "nsIURI.h" -#include "nsScriptLoader.h" #include "nsIRadioGroupContainer.h" #include "nsILayoutHistoryState.h" #include "nsIRequest.h" @@ -60,6 +59,7 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/PendingAnimationTracker.h" #include "mozilla/dom/DOMImplementation.h" +#include "mozilla/dom/ScriptLoader.h" #include "mozilla/dom/StyleSheetList.h" #include "nsDataHashtable.h" #include "mozilla/TimeStamp.h" @@ -674,7 +674,7 @@ public: /** * Get the script loader for this document */ - virtual nsScriptLoader* ScriptLoader() override; + virtual mozilla::dom::ScriptLoader* ScriptLoader() override; /** * Add/Remove an element to the document's id and name hashes @@ -1417,7 +1417,7 @@ public: RefPtr<mozilla::EventListenerManager> mListenerManager; RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets; RefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList; - RefPtr<nsScriptLoader> mScriptLoader; + RefPtr<mozilla::dom::ScriptLoader> mScriptLoader; nsDocHeaderData* mHeaderData; /* mIdentifierMap works as follows for IDs: * 1) Attribute changes affect the table immediately (removing and adding diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index bba4232aa8..331931f19d 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -19,7 +19,6 @@ #include "nsJSUtils.h" #include "nsJSPrincipals.h" #include "nsNetUtil.h" -#include "nsScriptLoader.h" #include "nsFrameLoader.h" #include "nsIXULRuntime.h" #include "nsIScriptError.h" @@ -38,6 +37,7 @@ #include "mozilla/dom/PermissionMessageUtils.h" #include "mozilla/dom/ProcessGlobal.h" #include "mozilla/dom/SameProcessMessageQueue.h" +#include "mozilla/dom/ScriptLoader.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/ipc/BlobChild.h" #include "mozilla/dom/ipc/BlobParent.h" @@ -1786,9 +1786,9 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript( if (NS_FAILED(NS_ReadInputStreamToString(input, buffer, avail))) { return; } - nsScriptLoader::ConvertToUTF16(channel, (uint8_t*)buffer.get(), avail, - EmptyString(), nullptr, - dataStringBuf, dataStringLength); + ScriptLoader::ConvertToUTF16(channel, (uint8_t*)buffer.get(), avail, + EmptyString(), nullptr, + dataStringBuf, dataStringLength); } JS::SourceBufferHolder srcBuf(dataStringBuf, dataStringLength, diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index 73a3a02b1f..96f5acf3a2 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -910,7 +910,9 @@ GK_ATOM(onreadystatechange, "onreadystatechange") GK_ATOM(onreceived, "onreceived") GK_ATOM(onremoteheld, "onremoteheld") GK_ATOM(onremoteresumed, "onremoteresumed") +GK_ATOM(onrequestprogress, "onrequestprogress") GK_ATOM(onresourcetimingbufferfull, "onresourcetimingbufferfull") +GK_ATOM(onresponseprogress, "onresponseprogress") GK_ATOM(onretrieving, "onretrieving") GK_ATOM(onRequest, "onRequest") GK_ATOM(onrequestmediaplaystatus, "onrequestmediaplaystatus") diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index dd1fe45862..d696d826bd 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -62,7 +62,7 @@ #include "nsReadableUtils.h" #include "nsDOMClassInfo.h" #include "nsJSEnvironment.h" -#include "ScriptSettings.h" +#include "mozilla/dom/ScriptSettings.h" #include "mozilla/Preferences.h" #include "mozilla/Likely.h" #include "mozilla/Sprintf.h" diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index fdaee39ca3..506acc7e4c 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -91,7 +91,6 @@ class nsIVariant; class nsViewManager; class nsPresContext; class nsRange; -class nsScriptLoader; class nsSMILAnimationController; class nsTextNode; class nsWindowSizes; @@ -152,6 +151,7 @@ enum class OrientationType : uint32_t; class ProcessingInstruction; class Promise; class Selection; +class ScriptLoader; class StyleSheetList; class SVGDocument; class SVGSVGElement; @@ -1290,7 +1290,7 @@ public: /** * Get the script loader for this document */ - virtual nsScriptLoader* ScriptLoader() = 0; + virtual mozilla::dom::ScriptLoader* ScriptLoader() = 0; /** * Add/Remove an element to the document's id and name hashes diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 212110b729..355bf0ebfa 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -107,6 +107,7 @@ #include "GeometryUtils.h" #include "nsIAnimationObserver.h" #include "nsChildContentList.h" +#include "mozilla/dom/NodeBinding.h" #ifdef ACCESSIBILITY #include "mozilla/dom/AccessibleNode.h" @@ -250,6 +251,30 @@ nsINode::GetTextEditorRootContent(nsIEditor** aEditor) return nullptr; } +nsINode* nsINode::GetRootNode(const GetRootNodeOptions& aOptions) +{ + if (aOptions.mComposed) { + if (IsInComposedDoc() && GetComposedDoc()) { + return OwnerDoc(); + } + + nsINode* node = this; + ShadowRoot* shadowRootParent = nullptr; + while(node) { + node = node->SubtreeRoot(); + shadowRootParent = ShadowRoot::FromNode(node); + if (!shadowRootParent) { + break; + } + node = shadowRootParent->GetHost(); + } + + return node; + } + + return SubtreeRoot(); +} + nsINode* nsINode::SubtreeRoot() const { diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h index d82f5f8990..43d44db607 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h @@ -83,6 +83,7 @@ template<typename> class Sequence; class Text; class TextOrElementOrDocument; struct DOMPointInit; +struct GetRootNodeOptions; } // namespace dom } // namespace mozilla @@ -942,10 +943,11 @@ public: */ nsINode* SubtreeRoot() const; - nsINode* RootNode() const - { - return SubtreeRoot(); - } + /* + * Get context object's shadow-including root if options's composed is true, + * and context object's root otherwise. + */ + nsINode* GetRootNode(const mozilla::dom::GetRootNodeOptions& aOptions); /** * See nsIDOMEventTarget diff --git a/dom/base/nsInProcessTabChildGlobal.cpp b/dom/base/nsInProcessTabChildGlobal.cpp index 10ccf4aec3..2e129f9f0c 100644 --- a/dom/base/nsInProcessTabChildGlobal.cpp +++ b/dom/base/nsInProcessTabChildGlobal.cpp @@ -11,13 +11,13 @@ #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsComponentManagerUtils.h" -#include "nsScriptLoader.h" #include "nsFrameLoader.h" #include "xpcpublic.h" #include "nsIMozBrowserFrame.h" #include "nsDOMClassInfoID.h" #include "mozilla/EventDispatcher.h" #include "mozilla/dom/SameProcessMessageQueue.h" +#include "mozilla/dom/ScriptLoader.h" using namespace mozilla; using namespace mozilla::dom; diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index efea3ee401..605b1917fd 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -37,7 +37,6 @@ #include "nsXPCOMCIDInternal.h" #include "nsIXULRuntime.h" #include "nsTextFormatter.h" -#include "ScriptSettings.h" #include "xpcpublic.h" @@ -55,6 +54,7 @@ #include "mozilla/dom/DOMException.h" #include "mozilla/dom/DOMExceptionBinding.h" #include "mozilla/dom/ErrorEvent.h" +#include "mozilla/dom/ScriptSettings.h" #include "nsAXPCNativeCallContext.h" #include "mozilla/CycleCollectedJSContext.h" #include "mozilla/Telemetry.h" diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp index c9cec96db3..5c7e204249 100644 --- a/dom/base/nsJSUtils.cpp +++ b/dom/base/nsJSUtils.cpp @@ -306,17 +306,18 @@ nsJSUtils::CompileModule(JSContext* aCx, } nsresult -nsJSUtils::ModuleDeclarationInstantiation(JSContext* aCx, JS::Handle<JSObject*> aModule) +nsJSUtils::ModuleInstantiate(JSContext* aCx, JS::Handle<JSObject*> aModule) { - PROFILER_LABEL("nsJSUtils", "ModuleDeclarationInstantiation", + PROFILER_LABEL("nsJSUtils", "ModuleInstantiate", js::ProfileEntry::Category::JS); MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext()); MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(nsContentUtils::IsInMicroTask()); NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK); - if (!JS::ModuleDeclarationInstantiation(aCx, aModule)) { + if (!JS::ModuleInstantiate(aCx, aModule)) { return NS_ERROR_FAILURE; } @@ -324,9 +325,9 @@ nsJSUtils::ModuleDeclarationInstantiation(JSContext* aCx, JS::Handle<JSObject*> } nsresult -nsJSUtils::ModuleEvaluation(JSContext* aCx, JS::Handle<JSObject*> aModule) +nsJSUtils::ModuleEvaluate(JSContext* aCx, JS::Handle<JSObject*> aModule) { - PROFILER_LABEL("nsJSUtils", "ModuleEvaluation", + PROFILER_LABEL("nsJSUtils", "ModuleEvaluate", js::ProfileEntry::Category::JS); MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext()); @@ -335,7 +336,7 @@ nsJSUtils::ModuleEvaluation(JSContext* aCx, JS::Handle<JSObject*> aModule) NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK); - if (!JS::ModuleEvaluation(aCx, aModule)) { + if (!JS::ModuleEvaluate(aCx, aModule)) { return NS_ERROR_FAILURE; } diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h index 4affab2d36..9eea6ae83d 100644 --- a/dom/base/nsJSUtils.h +++ b/dom/base/nsJSUtils.h @@ -116,11 +116,11 @@ public: JS::CompileOptions &aCompileOptions, JS::MutableHandle<JSObject*> aModule); - static nsresult ModuleDeclarationInstantiation(JSContext* aCx, - JS::Handle<JSObject*> aModule); + static nsresult ModuleInstantiate(JSContext* aCx, + JS::Handle<JSObject*> aModule); - static nsresult ModuleEvaluation(JSContext* aCx, - JS::Handle<JSObject*> aModule); + static nsresult ModuleEvaluate(JSContext* aCx, + JS::Handle<JSObject*> aModule); // Returns false if an exception got thrown on aCx. Passing a null // aElement is allowed; that wil produce an empty aScopeChain. diff --git a/dom/base/nsPlainTextSerializer.h b/dom/base/nsPlainTextSerializer.h index 650a8e3e73..58aeb42078 100644 --- a/dom/base/nsPlainTextSerializer.h +++ b/dom/base/nsPlainTextSerializer.h @@ -16,6 +16,7 @@ #include "mozilla/Attributes.h" #include "nsCOMPtr.h" #include "nsIAtom.h" +#include "nsCycleCollectionParticipant.h" #include "nsIContentSerializer.h" #include "nsIDocumentEncoder.h" #include "nsILineBreaker.h" diff --git a/dom/base/test/jsmodules/test_syntaxError.html b/dom/base/test/jsmodules/test_syntaxError.html index 53f95c96cc..5bd688fe3f 100644 --- a/dom/base/test/jsmodules/test_syntaxError.html +++ b/dom/base/test/jsmodules/test_syntaxError.html @@ -4,20 +4,27 @@ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> <script> var wasRun = false; - var hadSyntaxError = false; + var errorCount = 0; + var syntaxErrorCount = 0; + var eventCount = 0; SimpleTest.waitForExplicitFinish(); window.onerror = handleError; function handleError(message, url, line, column, error) { - hadSyntaxError = error instanceof SyntaxError; + errorCount++; + if (error instanceof SyntaxError) { + syntaxErrorCount++; + } } function testError() { ok(!wasRun, 'Check script was not run'); - ok(hadSyntaxError, 'Check that a SyntaxError was thrown'); + ok(errorCount == 1, 'Check that an error was reported'); + ok(syntaxErrorCount == 1, 'Check that a syntax error was reported'); + ok(eventCount == 0, 'Check that no error event was fired'); SimpleTest.finish(); } </script> -<script type="module" src="module_badSyntax.js"></script> +<script type="module" src="module_badSyntax.js" onerror="eventCount++"></script> <body onload='testError()'></body> diff --git a/dom/base/test/jsmodules/test_syntaxErrorAsync.html b/dom/base/test/jsmodules/test_syntaxErrorAsync.html index 35d9237553..3593d9dd73 100644 --- a/dom/base/test/jsmodules/test_syntaxErrorAsync.html +++ b/dom/base/test/jsmodules/test_syntaxErrorAsync.html @@ -4,20 +4,27 @@ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> <script> var wasRun = false; - var hadSyntaxError = false; + var errorCount = 0; + var syntaxErrorCount = 0; + var eventCount = 0; SimpleTest.waitForExplicitFinish(); window.onerror = handleError; function handleError(message, url, line, column, error) { - hadSyntaxError = error instanceof SyntaxError; + errorCount++; + if (error instanceof SyntaxError) { + syntaxErrorCount++; + } } function testError() { ok(!wasRun, 'Check script was not run'); - ok(hadSyntaxError, 'Check that a SyntaxError was thrown'); + ok(errorCount == 1, 'Check that an error was reported'); + ok(syntaxErrorCount == 1, 'Check that a syntax error was reported'); + ok(eventCount == 0, 'Check that no error event was fired'); SimpleTest.finish(); } </script> -<script type="module" src="module_badSyntax.js" async></script> +<script type="module" src="module_badSyntax.js" async onerror="eventCount++"></script> <body onload='testError()'></body> diff --git a/dom/base/test/jsmodules/test_syntaxErrorInline.html b/dom/base/test/jsmodules/test_syntaxErrorInline.html index 705bc5902e..b85b954ece 100644 --- a/dom/base/test/jsmodules/test_syntaxErrorInline.html +++ b/dom/base/test/jsmodules/test_syntaxErrorInline.html @@ -4,22 +4,29 @@ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> <script> var wasRun = false; - var hadSyntaxError = false; + var errorCount = 0; + var syntaxErrorCount = 0; + var eventCount = 0; SimpleTest.waitForExplicitFinish(); window.onerror = handleError; function handleError(message, url, line, column, error) { - hadSyntaxError = error instanceof SyntaxError; + errorCount++; + if (error instanceof SyntaxError) { + syntaxErrorCount++; + } } function testError() { ok(!wasRun, 'Check script was not run'); - ok(hadSyntaxError, 'Check that a SyntaxError was thrown'); + ok(errorCount == 1, 'Check that an error was reported'); + ok(syntaxErrorCount == 1, 'Check that a syntax error was reported'); + ok(eventCount == 0, 'Check that no error event was fired'); SimpleTest.finish(); } </script> -<script type="module"> +<script type="module" onerror="eventCount++"> // Module with a syntax error. some invalid js syntax; wasRun = true; diff --git a/dom/base/test/jsmodules/test_syntaxErrorInlineAsync.html b/dom/base/test/jsmodules/test_syntaxErrorInlineAsync.html index 5e79928234..cc4bf12575 100644 --- a/dom/base/test/jsmodules/test_syntaxErrorInlineAsync.html +++ b/dom/base/test/jsmodules/test_syntaxErrorInlineAsync.html @@ -4,22 +4,29 @@ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> <script> var wasRun = false; - var hadSyntaxError = false; + var errorCount = 0; + var syntaxErrorCount = 0; + var eventCount = 0; SimpleTest.waitForExplicitFinish(); window.onerror = handleError; function handleError(message, url, line, column, error) { - hadSyntaxError = error instanceof SyntaxError; + errorCount++; + if (error instanceof SyntaxError) { + syntaxErrorCount++; + } } function testError() { ok(!wasRun, 'Check script was not run'); - ok(hadSyntaxError, 'Check that a SyntaxError was thrown'); + ok(errorCount == 1, 'Check that an error was reported'); + ok(syntaxErrorCount == 1, 'Check that a syntax error was reported'); + ok(eventCount == 0, 'Check that no error event was fired'); SimpleTest.finish(); } </script> -<script type="module" async> +<script type="module" async onerror="eventCount++"> // Module with a syntax error. some invalid js syntax; wasRun = true; diff --git a/dom/console/Console.cpp b/dom/console/Console.cpp index b174172e01..119a259fe0 100755 --- a/dom/console/Console.cpp +++ b/dom/console/Console.cpp @@ -12,6 +12,7 @@ #include "mozilla/dom/File.h" #include "mozilla/dom/FunctionBinding.h" #include "mozilla/dom/Performance.h" +#include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/StructuredCloneHolder.h" #include "mozilla/dom/ToJSValue.h" #include "mozilla/dom/WorkletGlobalScope.h" @@ -22,7 +23,6 @@ #include "nsGlobalWindow.h" #include "nsJSUtils.h" #include "nsNetUtil.h" -#include "ScriptSettings.h" #include "WorkerPrivate.h" #include "WorkerRunnable.h" #include "WorkerScope.h" diff --git a/dom/events/DOMEventTargetHelper.cpp b/dom/events/DOMEventTargetHelper.cpp index 7daf7f7a77..ea68ead9de 100644 --- a/dom/events/DOMEventTargetHelper.cpp +++ b/dom/events/DOMEventTargetHelper.cpp @@ -8,7 +8,7 @@ #include "nsIDocument.h" #include "mozilla/Sprintf.h" #include "nsGlobalWindow.h" -#include "ScriptSettings.h" +#include "mozilla/dom/ScriptSettings.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/EventDispatcher.h" #include "mozilla/EventListenerManager.h" diff --git a/dom/fetch/Fetch.cpp b/dom/fetch/Fetch.cpp index f944352e3b..191f4cfc3e 100644 --- a/dom/fetch/Fetch.cpp +++ b/dom/fetch/Fetch.cpp @@ -39,6 +39,7 @@ #include "mozilla/dom/URLSearchParams.h" #include "mozilla/dom/workers/ServiceWorkerManager.h" +#include "FetchObserver.h" #include "InternalRequest.h" #include "InternalResponse.h" @@ -52,38 +53,141 @@ namespace dom { using namespace workers; +// This class helps the proxying of AbortSignal changes cross threads. +class AbortSignalProxy final : public AbortSignal::Follower +{ + // This is created and released on the main-thread. + RefPtr<AbortSignal> mSignalMainThread; + + // This value is used only for the creation of AbortSignal on the + // main-thread. They are not updated. + const bool mAborted; + + // This runnable propagates changes from the AbortSignal on workers to the + // AbortSignal on main-thread. + class AbortSignalProxyRunnable final : public Runnable + { + RefPtr<AbortSignalProxy> mProxy; + + public: + explicit AbortSignalProxyRunnable(AbortSignalProxy* aProxy) + : mProxy(aProxy) + {} + + NS_IMETHOD + Run() override + { + MOZ_ASSERT(NS_IsMainThread()); + AbortSignal* signal = mProxy->GetOrCreateSignalForMainThread(); + signal->Abort(); + return NS_OK; + } + }; + +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AbortSignalProxy) + + explicit AbortSignalProxy(AbortSignal* aSignal) + : mAborted(aSignal->Aborted()) + { + Follow(aSignal); + } + + void + Aborted() override + { + RefPtr<AbortSignalProxyRunnable> runnable = + new AbortSignalProxyRunnable(this); + NS_DispatchToMainThread(runnable); + } + + AbortSignal* + GetOrCreateSignalForMainThread() + { + MOZ_ASSERT(NS_IsMainThread()); + if (!mSignalMainThread) { + mSignalMainThread = new AbortSignal(mAborted); + } + return mSignalMainThread; + } + + void + Shutdown() + { + Unfollow(); + } + +private: + ~AbortSignalProxy() + { + NS_ReleaseOnMainThread(mSignalMainThread.forget()); + } +}; + class WorkerFetchResolver final : public FetchDriverObserver { friend class MainThreadFetchRunnable; + friend class WorkerDataAvailableRunnable; + friend class WorkerFetchResponseEndBase; friend class WorkerFetchResponseEndRunnable; friend class WorkerFetchResponseRunnable; RefPtr<PromiseWorkerProxy> mPromiseProxy; + RefPtr<AbortSignalProxy> mSignalProxy; + RefPtr<FetchObserver> mFetchObserver; + public: // Returns null if worker is shutting down. static already_AddRefed<WorkerFetchResolver> - Create(workers::WorkerPrivate* aWorkerPrivate, Promise* aPromise) + Create(workers::WorkerPrivate* aWorkerPrivate, Promise* aPromise, + AbortSignal* aSignal, FetchObserver* aObserver) { MOZ_ASSERT(aWorkerPrivate); aWorkerPrivate->AssertIsOnWorkerThread(); - RefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(aWorkerPrivate, aPromise); + RefPtr<PromiseWorkerProxy> proxy = + PromiseWorkerProxy::Create(aWorkerPrivate, aPromise); if (!proxy) { return nullptr; } - RefPtr<WorkerFetchResolver> r = new WorkerFetchResolver(proxy); + RefPtr<AbortSignalProxy> signalProxy; + if (aSignal) { + signalProxy = new AbortSignalProxy(aSignal); + } + + RefPtr<WorkerFetchResolver> r = + new WorkerFetchResolver(proxy, signalProxy, aObserver); return r.forget(); } + AbortSignal* + GetAbortSignal() + { + MOZ_ASSERT(NS_IsMainThread()); + + if (!mSignalProxy) { + return nullptr; + } + + return mSignalProxy->GetOrCreateSignalForMainThread(); + } + void OnResponseAvailableInternal(InternalResponse* aResponse) override; void - OnResponseEnd() override; + OnResponseEnd(FetchDriverObserver::EndReason eReason) override; + + void + OnDataAvailable() override; private: - explicit WorkerFetchResolver(PromiseWorkerProxy* aProxy) + WorkerFetchResolver(PromiseWorkerProxy* aProxy, + AbortSignalProxy* aSignalProxy, + FetchObserver* aObserver) : mPromiseProxy(aProxy) + , mSignalProxy(aSignalProxy) + , mFetchObserver(aObserver) { MOZ_ASSERT(!NS_IsMainThread()); MOZ_ASSERT(mPromiseProxy); @@ -100,12 +204,16 @@ class MainThreadFetchResolver final : public FetchDriverObserver { RefPtr<Promise> mPromise; RefPtr<Response> mResponse; + RefPtr<FetchObserver> mFetchObserver; nsCOMPtr<nsIDocument> mDocument; NS_DECL_OWNINGTHREAD public: - explicit MainThreadFetchResolver(Promise* aPromise); + MainThreadFetchResolver(Promise* aPromise, FetchObserver* aObserver) + : mPromise(aPromise) + , mFetchObserver(aObserver) + {} void OnResponseAvailableInternal(InternalResponse* aResponse) override; @@ -115,11 +223,20 @@ public: mDocument = aDocument; } - virtual void OnResponseEnd() override + void OnResponseEnd(FetchDriverObserver::EndReason aReason) override { + if (aReason == eAborted) { + mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); + } + + mFetchObserver = nullptr; + FlushConsoleReport(); } + void + OnDataAvailable() override; + private: ~MainThreadFetchResolver(); @@ -170,9 +287,11 @@ public: fetch->SetWorkerScript(spec); } + RefPtr<AbortSignal> signal = mResolver->GetAbortSignal(); + // ...but release it before calling Fetch, because mResolver's callback can // be called synchronously and they want the mutex, too. - return fetch->Fetch(mResolver); + return fetch->Fetch(signal, mResolver); } }; @@ -210,6 +329,23 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput, RefPtr<InternalRequest> r = request->GetInternalRequest(); + RefPtr<AbortSignal> signal; + if (aInit.mSignal.WasPassed()) { + signal = &aInit.mSignal.Value(); + } + + if (signal && signal->Aborted()) { + // An already aborted signal should reject immediately. + aRv.Throw(NS_ERROR_DOM_ABORT_ERR); + return nullptr; + } + + RefPtr<FetchObserver> observer; + if (aInit.mObserve.WasPassed()) { + observer = new FetchObserver(aGlobal, signal); + aInit.mObserve.Value().HandleEvent(*observer); + } + if (NS_IsMainThread()) { nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal); nsCOMPtr<nsIDocument> doc; @@ -236,11 +372,12 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput, } } - RefPtr<MainThreadFetchResolver> resolver = new MainThreadFetchResolver(p); + RefPtr<MainThreadFetchResolver> resolver = + new MainThreadFetchResolver(p, observer); RefPtr<FetchDriver> fetch = new FetchDriver(r, principal, loadGroup); fetch->SetDocument(doc); resolver->SetDocument(doc); - aRv = fetch->Fetch(resolver); + aRv = fetch->Fetch(signal, resolver); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } @@ -252,7 +389,8 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput, r->SetSkipServiceWorker(); } - RefPtr<WorkerFetchResolver> resolver = WorkerFetchResolver::Create(worker, p); + RefPtr<WorkerFetchResolver> resolver = + WorkerFetchResolver::Create(worker, p, signal, observer); if (!resolver) { NS_WARNING("Could not add WorkerFetchResolver workerHolder to worker"); aRv.Throw(NS_ERROR_DOM_ABORT_ERR); @@ -266,11 +404,6 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput, return p.forget(); } -MainThreadFetchResolver::MainThreadFetchResolver(Promise* aPromise) - : mPromise(aPromise) -{ -} - void MainThreadFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse) { @@ -278,16 +411,39 @@ MainThreadFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse AssertIsOnMainThread(); if (aResponse->Type() != ResponseType::Error) { + if (mFetchObserver) { + mFetchObserver->SetState(FetchState::Complete); + } + nsCOMPtr<nsIGlobalObject> go = mPromise->GetParentObject(); mResponse = new Response(go, aResponse); mPromise->MaybeResolve(mResponse); } else { + if (mFetchObserver) { + mFetchObserver->SetState(FetchState::Errored); + } + ErrorResult result; result.ThrowTypeError<MSG_FETCH_FAILED>(); mPromise->MaybeReject(result); } } +void +MainThreadFetchResolver::OnDataAvailable() +{ + NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver); + AssertIsOnMainThread(); + + if (!mFetchObserver) { + return; + } + + if (mFetchObserver->State() == FetchState::Requesting) { + mFetchObserver->SetState(FetchState::Responding); + } +} + MainThreadFetchResolver::~MainThreadFetchResolver() { NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver); @@ -306,6 +462,7 @@ public: , mResolver(aResolver) , mInternalResponse(aResponse) { + MOZ_ASSERT(mResolver); } bool @@ -317,10 +474,18 @@ public: RefPtr<Promise> promise = mResolver->mPromiseProxy->WorkerPromise(); if (mInternalResponse->Type() != ResponseType::Error) { + if (mResolver->mFetchObserver) { + mResolver->mFetchObserver->SetState(FetchState::Complete); + } + RefPtr<nsIGlobalObject> global = aWorkerPrivate->GlobalScope(); RefPtr<Response> response = new Response(global, mInternalResponse); promise->MaybeResolve(response); } else { + if (mResolver->mFetchObserver) { + mResolver->mFetchObserver->SetState(FetchState::Errored); + } + ErrorResult result; result.ThrowTypeError<MSG_FETCH_FAILED>(); promise->MaybeReject(result); @@ -329,14 +494,42 @@ public: } }; +class WorkerDataAvailableRunnable final : public MainThreadWorkerRunnable +{ + RefPtr<WorkerFetchResolver> mResolver; +public: + WorkerDataAvailableRunnable(WorkerPrivate* aWorkerPrivate, + WorkerFetchResolver* aResolver) + : MainThreadWorkerRunnable(aWorkerPrivate) + , mResolver(aResolver) + { + } + + bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + if (mResolver->mFetchObserver && + mResolver->mFetchObserver->State() == FetchState::Requesting) { + mResolver->mFetchObserver->SetState(FetchState::Responding); + } + + return true; + } +}; + class WorkerFetchResponseEndBase { - RefPtr<PromiseWorkerProxy> mPromiseProxy; +protected: + RefPtr<WorkerFetchResolver> mResolver; + public: - explicit WorkerFetchResponseEndBase(PromiseWorkerProxy* aPromiseProxy) - : mPromiseProxy(aPromiseProxy) + explicit WorkerFetchResponseEndBase(WorkerFetchResolver* aResolver) + : mResolver(aResolver) { - MOZ_ASSERT(mPromiseProxy); + MOZ_ASSERT(aResolver); } void @@ -344,23 +537,41 @@ public: { MOZ_ASSERT(aWorkerPrivate); aWorkerPrivate->AssertIsOnWorkerThread(); - mPromiseProxy->CleanUp(); + + mResolver->mPromiseProxy->CleanUp(); + + mResolver->mFetchObserver = nullptr; + + if (mResolver->mSignalProxy) { + mResolver->mSignalProxy->Shutdown(); + mResolver->mSignalProxy = nullptr; + } } }; class WorkerFetchResponseEndRunnable final : public MainThreadWorkerRunnable , public WorkerFetchResponseEndBase { + FetchDriverObserver::EndReason mReason; + public: - explicit WorkerFetchResponseEndRunnable(PromiseWorkerProxy* aPromiseProxy) - : MainThreadWorkerRunnable(aPromiseProxy->GetWorkerPrivate()) - , WorkerFetchResponseEndBase(aPromiseProxy) + WorkerFetchResponseEndRunnable(WorkerPrivate* aWorkerPrivate, + WorkerFetchResolver* aResolver, + FetchDriverObserver::EndReason aReason) + : MainThreadWorkerRunnable(aWorkerPrivate) + , WorkerFetchResponseEndBase(aResolver) + , mReason(aReason) { } bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { + if (mReason == FetchDriverObserver::eAborted) { + RefPtr<Promise> promise = mResolver->mPromiseProxy->WorkerPromise(); + promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); + } + WorkerRunInternal(aWorkerPrivate); return true; } @@ -379,9 +590,10 @@ class WorkerFetchResponseEndControlRunnable final : public MainThreadWorkerContr , public WorkerFetchResponseEndBase { public: - explicit WorkerFetchResponseEndControlRunnable(PromiseWorkerProxy* aPromiseProxy) - : MainThreadWorkerControlRunnable(aPromiseProxy->GetWorkerPrivate()) - , WorkerFetchResponseEndBase(aPromiseProxy) + WorkerFetchResponseEndControlRunnable(WorkerPrivate* aWorkerPrivate, + WorkerFetchResolver* aResolver) + : MainThreadWorkerControlRunnable(aWorkerPrivate) + , WorkerFetchResponseEndBase(aResolver) { } @@ -415,7 +627,22 @@ WorkerFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse) } void -WorkerFetchResolver::OnResponseEnd() +WorkerFetchResolver::OnDataAvailable() +{ + AssertIsOnMainThread(); + + MutexAutoLock lock(mPromiseProxy->Lock()); + if (mPromiseProxy->CleanedUp()) { + return; + } + + RefPtr<WorkerDataAvailableRunnable> r = + new WorkerDataAvailableRunnable(mPromiseProxy->GetWorkerPrivate(), this); + Unused << r->Dispatch(); +} + +void +WorkerFetchResolver::OnResponseEnd(FetchDriverObserver::EndReason aReason) { AssertIsOnMainThread(); MutexAutoLock lock(mPromiseProxy->Lock()); @@ -426,11 +653,13 @@ WorkerFetchResolver::OnResponseEnd() FlushConsoleReport(); RefPtr<WorkerFetchResponseEndRunnable> r = - new WorkerFetchResponseEndRunnable(mPromiseProxy); + new WorkerFetchResponseEndRunnable(mPromiseProxy->GetWorkerPrivate(), + this, aReason); if (!r->Dispatch()) { RefPtr<WorkerFetchResponseEndControlRunnable> cr = - new WorkerFetchResponseEndControlRunnable(mPromiseProxy); + new WorkerFetchResponseEndControlRunnable(mPromiseProxy->GetWorkerPrivate(), + this); // This can fail if the worker thread is canceled or killed causing // the PromiseWorkerProxy to give up its WorkerHolder immediately, // allowing the worker thread to become Dead. diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index 6294b0dc5c..067e32db48 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -67,7 +67,7 @@ FetchDriver::~FetchDriver() } nsresult -FetchDriver::Fetch(FetchDriverObserver* aObserver) +FetchDriver::Fetch(AbortSignal* aSignal, FetchDriverObserver* aObserver) { workers::AssertIsOnMainThread(); #ifdef DEBUG @@ -90,6 +90,18 @@ FetchDriver::Fetch(FetchDriverObserver* aObserver) } mRequest->SetPrincipalInfo(Move(principalInfo)); + + // If the signal is aborted, it's time to inform the observer and terminate + // the operation. + if (aSignal) { + if (aSignal->Aborted()) { + Aborted(); + return NS_OK; + } + + Follow(aSignal); + } + if (NS_FAILED(HttpFetch())) { FailWithNetworkError(); } @@ -114,11 +126,7 @@ FetchDriver::HttpFetch() nsAutoCString url; mRequest->GetURL(url); nsCOMPtr<nsIURI> uri; - rv = NS_NewURI(getter_AddRefs(uri), - url, - nullptr, - nullptr, - ios); + rv = NS_NewURI(getter_AddRefs(uri), url, nullptr, nullptr, ios); NS_ENSURE_SUCCESS(rv, rv); // Unsafe requests aren't allowed with when using no-core mode. @@ -380,6 +388,8 @@ FetchDriver::HttpFetch() NS_ENSURE_SUCCESS(rv, rv); // Step 4 onwards of "HTTP Fetch" is handled internally by Necko. + + mChannel = chan; return NS_OK; } already_AddRefed<InternalResponse> @@ -433,9 +443,11 @@ FetchDriver::FailWithNetworkError() #ifdef DEBUG mResponseAvailableCalled = true; #endif - mObserver->OnResponseEnd(); + mObserver->OnResponseEnd(FetchDriverObserver::eByNetworking); mObserver = nullptr; } + + mChannel = nullptr; } namespace { @@ -655,6 +667,31 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest, return NS_OK; } +namespace { + +// Runnable to call the observer OnDataAvailable on the main-thread. +class DataAvailableRunnable final : public Runnable +{ + RefPtr<FetchDriverObserver> mObserver; + +public: + explicit DataAvailableRunnable(FetchDriverObserver* aObserver) + : mObserver(aObserver) + { + MOZ_ASSERT(aObserver); + } + + NS_IMETHOD + Run() override + { + mObserver->OnDataAvailable(); + mObserver = nullptr; + return NS_OK; + } +}; + +} // anonymous namespace + NS_IMETHODIMP FetchDriver::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, @@ -666,6 +703,18 @@ FetchDriver::OnDataAvailable(nsIRequest* aRequest, // called between OnStartRequest and OnStopRequest, so we don't need to worry // about races. + if (mObserver) { + if (NS_IsMainThread()) { + mObserver->OnDataAvailable(); + } else { + RefPtr<Runnable> runnable = new DataAvailableRunnable(mObserver); + nsresult rv = NS_DispatchToMainThread(runnable); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + } + uint32_t aRead; MOZ_ASSERT(mResponse); MOZ_ASSERT(mPipeOutputStream); @@ -777,10 +826,11 @@ FetchDriver::OnStopRequest(nsIRequest* aRequest, #endif } - mObserver->OnResponseEnd(); + mObserver->OnResponseEnd(FetchDriverObserver::eByNetworking); mObserver = nullptr; } + mChannel = nullptr; return NS_OK; } @@ -921,5 +971,21 @@ FetchDriver::SetRequestHeaders(nsIHttpChannel* aChannel) const } } +void FetchDriver::Aborted() +{ + if (mObserver) { +#ifdef DEBUG + mResponseAvailableCalled = true; +#endif + mObserver->OnResponseEnd(FetchDriverObserver::eAborted); + mObserver = nullptr; + } + + if (mChannel) { + mChannel->Cancel(NS_BINDING_ABORTED); + mChannel = nullptr; + } +} + } // namespace dom } // namespace mozilla diff --git a/dom/fetch/FetchDriver.h b/dom/fetch/FetchDriver.h index f74298a48c..57dffa5a70 100644 --- a/dom/fetch/FetchDriver.h +++ b/dom/fetch/FetchDriver.h @@ -12,6 +12,7 @@ #include "nsIStreamListener.h" #include "nsIThreadRetargetableStreamListener.h" #include "mozilla/ConsoleReportCollector.h" +#include "mozilla/dom/AbortSignal.h" #include "mozilla/dom/SRIMetadata.h" #include "mozilla/RefPtr.h" @@ -49,7 +50,14 @@ public: mGotResponseAvailable = true; OnResponseAvailableInternal(aResponse); } - virtual void OnResponseEnd() + + enum EndReason + { + eAborted, + eByNetworking, + }; + + virtual void OnResponseEnd(EndReason aReason) { }; nsIConsoleReportCollector* GetReporter() const @@ -58,6 +66,9 @@ public: } virtual void FlushConsoleReport() = 0; + + virtual void OnDataAvailable() = 0; + protected: virtual ~FetchDriverObserver() { }; @@ -72,7 +83,8 @@ private: class FetchDriver final : public nsIStreamListener, public nsIChannelEventSink, public nsIInterfaceRequestor, - public nsIThreadRetargetableStreamListener + public nsIThreadRetargetableStreamListener, + public AbortSignal::Follower { public: NS_DECL_ISUPPORTS @@ -82,9 +94,12 @@ public: NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER - explicit FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal, - nsILoadGroup* aLoadGroup); - NS_IMETHOD Fetch(FetchDriverObserver* aObserver); + FetchDriver(InternalRequest* aRequest, + nsIPrincipal* aPrincipal, + nsILoadGroup* aLoadGroup); + + nsresult Fetch(AbortSignal* aSignal, + FetchDriverObserver* aObserver); void SetDocument(nsIDocument* aDocument); @@ -96,6 +111,11 @@ public: mWorkerScript = aWorkerScirpt; } + // AbortSignal::Follower + + void + Aborted() override; + private: nsCOMPtr<nsIPrincipal> mPrincipal; nsCOMPtr<nsILoadGroup> mLoadGroup; @@ -104,6 +124,7 @@ private: nsCOMPtr<nsIOutputStream> mPipeOutputStream; RefPtr<FetchDriverObserver> mObserver; nsCOMPtr<nsIDocument> mDocument; + nsCOMPtr<nsIChannel> mChannel; nsAutoPtr<SRICheckDataVerifier> mSRIDataVerifier; SRIMetadata mSRIMetadata; nsCString mWorkerScript; diff --git a/dom/fetch/FetchObserver.cpp b/dom/fetch/FetchObserver.cpp new file mode 100644 index 0000000000..93d93773f7 --- /dev/null +++ b/dom/fetch/FetchObserver.cpp @@ -0,0 +1,117 @@ +/* -*- 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 "FetchObserver.h" +#include "WorkerPrivate.h" +#include "mozilla/dom/Event.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_CLASS(FetchObserver) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FetchObserver, + DOMEventTargetHelper) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FetchObserver, + DOMEventTargetHelper) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FetchObserver) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +NS_IMPL_ADDREF_INHERITED(FetchObserver, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(FetchObserver, DOMEventTargetHelper) + +/* static */ bool +FetchObserver::IsEnabled(JSContext* aCx, JSObject* aGlobal) +{ + if (NS_IsMainThread()) { + return Preferences::GetBool("dom.fetchObserver.enabled", false); + } + + using namespace workers; + + // Otherwise, check the pref via the WorkerPrivate + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + if (!workerPrivate) { + return false; + } + + return workerPrivate->FetchObserverEnabled(); +} + +FetchObserver::FetchObserver(nsIGlobalObject* aGlobal, + AbortSignal* aSignal) + : DOMEventTargetHelper(aGlobal) + , mState(FetchState::Requesting) +{ + if (aSignal) { + Follow(aSignal); + } +} + +JSObject* +FetchObserver::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) +{ + return FetchObserverBinding::Wrap(aCx, this, aGivenProto); +} + +FetchState +FetchObserver::State() const +{ + return mState; +} + +void +FetchObserver::Aborted() +{ + SetState(FetchState::Aborted); +} + +void +FetchObserver::SetState(FetchState aState) +{ + MOZ_ASSERT(mState < aState); + + if (mState == FetchState::Aborted || + mState == FetchState::Errored || + mState == FetchState::Complete) { + // We are already in a final state. + return; + } + + // We cannot pass from Requesting to Complete directly. + if (mState == FetchState::Requesting && + aState == FetchState::Complete) { + SetState(FetchState::Responding); + } + + mState = aState; + + if (mState == FetchState::Aborted || + mState == FetchState::Errored || + mState == FetchState::Complete) { + Unfollow(); + } + + EventInit init; + init.mBubbles = false; + init.mCancelable = false; + + // TODO which kind of event should we dispatch here? + + RefPtr<Event> event = + Event::Constructor(this, NS_LITERAL_STRING("statechange"), init); + event->SetTrusted(true); + + bool dummy; + DispatchEvent(event, &dummy); +} + +} // dom namespace +} // mozilla namespace diff --git a/dom/fetch/FetchObserver.h b/dom/fetch/FetchObserver.h new file mode 100644 index 0000000000..5cd835b3df --- /dev/null +++ b/dom/fetch/FetchObserver.h @@ -0,0 +1,54 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_FetchObserver_h +#define mozilla_dom_FetchObserver_h + +#include "mozilla/DOMEventTargetHelper.h" +#include "mozilla/dom/FetchObserverBinding.h" +#include "mozilla/dom/AbortSignal.h" + +namespace mozilla { +namespace dom { + +class FetchObserver final : public DOMEventTargetHelper + , public AbortSignal::Follower +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FetchObserver, DOMEventTargetHelper) + + static bool + IsEnabled(JSContext* aCx, JSObject* aGlobal); + + FetchObserver(nsIGlobalObject* aGlobal, AbortSignal* aSignal); + + JSObject* + WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; + + FetchState + State() const; + + IMPL_EVENT_HANDLER(statechange); + IMPL_EVENT_HANDLER(requestprogress); + IMPL_EVENT_HANDLER(responseprogress); + + void + Aborted() override; + + void + SetState(FetchState aState); + +private: + ~FetchObserver() = default; + + FetchState mState; +}; + +} // dom namespace +} // mozilla namespace + +#endif // mozilla_dom_FetchObserver_h diff --git a/dom/fetch/Request.h b/dom/fetch/Request.h index d33c748122..f6fe9be7bd 100644 --- a/dom/fetch/Request.h +++ b/dom/fetch/Request.h @@ -12,6 +12,7 @@ #include "nsWrapperCache.h" #include "mozilla/dom/Fetch.h" +#include "mozilla/dom/AbortSignal.h" #include "mozilla/dom/InternalRequest.h" // Required here due to certain WebIDL enums/classes being declared in both // files. diff --git a/dom/fetch/moz.build b/dom/fetch/moz.build index be820ab570..e2b4664282 100644 --- a/dom/fetch/moz.build +++ b/dom/fetch/moz.build @@ -9,6 +9,7 @@ EXPORTS.mozilla.dom += [ 'Fetch.h', 'FetchDriver.h', 'FetchIPCTypes.h', + 'FetchObserver.h', 'FetchUtil.h', 'Headers.h', 'InternalHeaders.h', @@ -28,6 +29,7 @@ UNIFIED_SOURCES += [ SOURCES += [ 'ChannelInfo.cpp', 'FetchDriver.cpp', + 'FetchObserver.cpp', 'FetchUtil.cpp', 'Headers.cpp', 'InternalHeaders.cpp', diff --git a/dom/html/HTMLScriptElement.cpp b/dom/html/HTMLScriptElement.cpp index 095b9b77de..ddeb925eb7 100644 --- a/dom/html/HTMLScriptElement.cpp +++ b/dom/html/HTMLScriptElement.cpp @@ -37,7 +37,7 @@ HTMLScriptElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) HTMLScriptElement::HTMLScriptElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo, FromParser aFromParser) : nsGenericHTMLElement(aNodeInfo) - , nsScriptElement(aFromParser) + , ScriptElement(aFromParser) { AddMutationObserver(this); } diff --git a/dom/html/HTMLScriptElement.h b/dom/html/HTMLScriptElement.h index 19ceb414f9..073cf7faf7 100644 --- a/dom/html/HTMLScriptElement.h +++ b/dom/html/HTMLScriptElement.h @@ -8,16 +8,16 @@ #define mozilla_dom_HTMLScriptElement_h #include "nsIDOMHTMLScriptElement.h" -#include "nsScriptElement.h" #include "nsGenericHTMLElement.h" #include "mozilla/Attributes.h" +#include "mozilla/dom/ScriptElement.h" namespace mozilla { namespace dom { class HTMLScriptElement final : public nsGenericHTMLElement, public nsIDOMHTMLScriptElement, - public nsScriptElement + public ScriptElement { public: using Element::GetText; @@ -96,7 +96,8 @@ protected: virtual ~HTMLScriptElement(); virtual JSObject* WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override; - // nsScriptElement + + // ScriptElement virtual bool HasScriptContent() override; }; diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp index 1e2f1c1860..ef077cfb2b 100644 --- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -48,7 +48,6 @@ #include "nsIDocShell.h" #include "nsNameSpaceManager.h" #include "nsError.h" -#include "nsScriptLoader.h" #include "nsRuleData.h" #include "nsIPrincipal.h" #include "nsContainerFrame.h" @@ -92,6 +91,7 @@ #include "mozilla/dom/FromParser.h" #include "mozilla/dom/Link.h" #include "mozilla/BloomFilter.h" +#include "mozilla/dom/ScriptLoader.h" #include "nsVariant.h" #include "nsDOMTokenList.h" diff --git a/dom/html/nsHTMLContentSink.cpp b/dom/html/nsHTMLContentSink.cpp index 3e8e019b83..409b225ef7 100644 --- a/dom/html/nsHTMLContentSink.cpp +++ b/dom/html/nsHTMLContentSink.cpp @@ -19,10 +19,10 @@ #include "nsIHTMLContentSink.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" -#include "nsScriptLoader.h" #include "nsIURI.h" #include "nsIContentViewer.h" #include "mozilla/dom/NodeInfo.h" +#include "mozilla/dom/ScriptLoader.h" #include "nsToken.h" #include "nsIAppShell.h" #include "nsCRT.h" diff --git a/dom/media/MediaDecoderReader.h b/dom/media/MediaDecoderReader.h index f53c74689f..a31687be87 100644 --- a/dom/media/MediaDecoderReader.h +++ b/dom/media/MediaDecoderReader.h @@ -17,6 +17,7 @@ #include "MediaMetadataManager.h" #include "MediaQueue.h" #include "MediaTimer.h" +#include "MP3Demuxer.h" #include "AudioCompactor.h" #include "Intervals.h" #include "TimeUnits.h" diff --git a/dom/media/webspeech/moz.build b/dom/media/webspeech/moz.build index 677e0656f6..c61c63b720 100644 --- a/dom/media/webspeech/moz.build +++ b/dom/media/webspeech/moz.build @@ -3,5 +3,11 @@ # 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/. +# Due to IPC entanglement we always need the synthesis ipdls if CONFIG['MOZ_WEBSPEECH']: DIRS += ['synth'] +else: + IPDL_SOURCES += [ + 'synth/ipc/PSpeechSynthesis.ipdl', + 'synth/ipc/PSpeechSynthesisRequest.ipdl', + ]
\ No newline at end of file diff --git a/dom/messagechannel/MessagePort.cpp b/dom/messagechannel/MessagePort.cpp index 56204da995..fcbe36a723 100644 --- a/dom/messagechannel/MessagePort.cpp +++ b/dom/messagechannel/MessagePort.cpp @@ -16,6 +16,7 @@ #include "mozilla/dom/MessagePortBinding.h" #include "mozilla/dom/MessagePortChild.h" #include "mozilla/dom/PMessagePort.h" +#include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/StructuredCloneTags.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerScope.h" @@ -28,7 +29,6 @@ #include "nsContentUtils.h" #include "nsGlobalWindow.h" #include "nsPresContext.h" -#include "ScriptSettings.h" #include "SharedMessagePortMessage.h" #include "nsIBFCacheEntry.h" diff --git a/dom/moz.build b/dom/moz.build index 89c539b4b1..7888ccd69f 100644 --- a/dom/moz.build +++ b/dom/moz.build @@ -37,6 +37,7 @@ interfaces = [ DIRS += ['interfaces/' + i for i in interfaces] DIRS += [ + 'abort', 'animation', 'apps', 'base', @@ -99,6 +100,7 @@ DIRS += [ 'performance', 'xhr', 'worklet', + 'script', ] if CONFIG['OS_ARCH'] == 'WINNT': diff --git a/dom/script/ModuleLoadRequest.cpp b/dom/script/ModuleLoadRequest.cpp new file mode 100644 index 0000000000..d622143044 --- /dev/null +++ b/dom/script/ModuleLoadRequest.cpp @@ -0,0 +1,139 @@ +/* -*- 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 "ModuleLoadRequest.h" +#include "ModuleScript.h" +#include "ScriptLoader.h" + +namespace mozilla { +namespace dom { + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest) +NS_INTERFACE_MAP_END_INHERITING(ScriptLoadRequest) + +NS_IMPL_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest, ScriptLoadRequest, + mBaseURL, + mLoader, + mParent, + mModuleScript, + mImports) + +NS_IMPL_ADDREF_INHERITED(ModuleLoadRequest, ScriptLoadRequest) +NS_IMPL_RELEASE_INHERITED(ModuleLoadRequest, ScriptLoadRequest) + +ModuleLoadRequest::ModuleLoadRequest(nsIScriptElement* aElement, + uint32_t aVersion, + CORSMode aCORSMode, + const SRIMetadata &aIntegrity, + ScriptLoader* aLoader) + : ScriptLoadRequest(ScriptKind::Module, + aElement, + aVersion, + aCORSMode, + aIntegrity), + mIsTopLevel(true), + mLoader(aLoader) +{} + +void ModuleLoadRequest::Cancel() +{ + ScriptLoadRequest::Cancel(); + mModuleScript = nullptr; + mProgress = ScriptLoadRequest::Progress::Ready; + CancelImports(); + mReady.RejectIfExists(NS_ERROR_DOM_ABORT_ERR, __func__); +} + +void +ModuleLoadRequest::CancelImports() +{ + for (size_t i = 0; i < mImports.Length(); i++) { + mImports[i]->Cancel(); + } +} + +void +ModuleLoadRequest::SetReady() +{ + // Mark a module as ready to execute. This means that this module and all it + // dependencies have had their source loaded, parsed as a module and the + // modules instantiated. + // + // The mReady promise is used to ensure that when all dependencies of a module + // have become ready, DependenciesLoaded is called on that module + // request. This is set up in StartFetchingModuleDependencies. + +#ifdef DEBUG + for (size_t i = 0; i < mImports.Length(); i++) { + MOZ_ASSERT(mImports[i]->IsReadyToRun()); + } +#endif + + ScriptLoadRequest::SetReady(); + mReady.ResolveIfExists(true, __func__); +} + +void +ModuleLoadRequest::ModuleLoaded() +{ + // A module that was found to be marked as fetching in the module map has now + // been loaded. + + mModuleScript = mLoader->GetFetchedModule(mURI); + if (!mModuleScript || mModuleScript->IsErrored()) { + ModuleErrored(); + return; + } + + mLoader->StartFetchingModuleDependencies(this); +} + +void +ModuleLoadRequest::ModuleErrored() +{ + mLoader->CheckModuleDependenciesLoaded(this); + MOZ_ASSERT(!mModuleScript || mModuleScript->IsErrored()); + + CancelImports(); + SetReady(); + LoadFinished(); +} + +void +ModuleLoadRequest::DependenciesLoaded() +{ + // The module and all of its dependencies have been successfully fetched and + // compiled. + + MOZ_ASSERT(mModuleScript); + + mLoader->CheckModuleDependenciesLoaded(this); + SetReady(); + LoadFinished(); +} + +void +ModuleLoadRequest::LoadFailed() +{ + // We failed to load the source text or an error occurred unrelated to the + // content of the module (e.g. OOM). + + MOZ_ASSERT(!mModuleScript); + + Cancel(); + LoadFinished(); +} + +void +ModuleLoadRequest::LoadFinished() +{ + mLoader->ProcessLoadedModuleTree(this); + mLoader = nullptr; + mParent = nullptr; +} + +} // dom namespace +} // mozilla namespace
\ No newline at end of file diff --git a/dom/script/ModuleLoadRequest.h b/dom/script/ModuleLoadRequest.h new file mode 100644 index 0000000000..7b06dd2cf3 --- /dev/null +++ b/dom/script/ModuleLoadRequest.h @@ -0,0 +1,87 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_ModuleLoadRequest_h +#define mozilla_dom_ModuleLoadRequest_h + +#include "mozilla/dom/ScriptLoader.h" +#include "mozilla/MozPromise.h" + +namespace mozilla { +namespace dom { + +class ModuleScript; +class ScriptLoader; + +// A load request for a module, created for every top level module script and +// every module import. Load request can share a ModuleScript if there are +// multiple imports of the same module. + +class ModuleLoadRequest final : public ScriptLoadRequest +{ + ~ModuleLoadRequest() {} + + ModuleLoadRequest(const ModuleLoadRequest& aOther) = delete; + ModuleLoadRequest(ModuleLoadRequest&& aOther) = delete; + +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ModuleLoadRequest, ScriptLoadRequest) + + ModuleLoadRequest(nsIScriptElement* aElement, + uint32_t aVersion, + CORSMode aCORSMode, + const SRIMetadata& aIntegrity, + ScriptLoader* aLoader); + + bool IsTopLevel() const { + return mIsTopLevel; + } + + void SetReady() override; + void Cancel() override; + + void ModuleLoaded(); + void ModuleErrored(); + void DependenciesLoaded(); + void LoadFailed(); + +private: + void LoadFinished(); + void CancelImports(); + +public: + // Is this a request for a top level module script or an import? + bool mIsTopLevel; + + // The base URL used for resolving relative module imports. + nsCOMPtr<nsIURI> mBaseURL; + + // Pointer to the script loader, used to trigger actions when the module load + // finishes. + RefPtr<ScriptLoader> mLoader; + + // The importing module, or nullptr for top level module scripts. Used to + // implement the ancestor list checked when fetching module dependencies. + RefPtr<ModuleLoadRequest> mParent; + + // Set to a module script object after a successful load or nullptr on + // failure. + RefPtr<ModuleScript> mModuleScript; + + // A promise that is completed on successful load of this module and all of + // its dependencies, indicating that the module is ready for instantiation and + // evaluation. + MozPromiseHolder<GenericPromise> mReady; + + // Array of imported modules. + nsTArray<RefPtr<ModuleLoadRequest>> mImports; +}; + +} // dom namespace +} // mozilla namespace + +#endif // mozilla_dom_ModuleLoadRequest_h
\ No newline at end of file diff --git a/dom/script/ModuleScript.cpp b/dom/script/ModuleScript.cpp new file mode 100644 index 0000000000..28b97a3cb5 --- /dev/null +++ b/dom/script/ModuleScript.cpp @@ -0,0 +1,122 @@ +/* -*- 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/. */ + +/* + * A class that handles loading and evaluation of <script> elements. + */ + +#include "ModuleScript.h" +#include "mozilla/HoldDropJSObjects.h" +#include "ScriptLoader.h" + +namespace mozilla { +namespace dom { + +// A single module script. May be used to satisfy multiple load requests. + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ModuleScript) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleScript) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL) + tmp->UnlinkModuleRecord(); + tmp->mError.setUndefined(); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mError) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript) +NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleScript) + +ModuleScript::ModuleScript(ScriptLoader *aLoader, nsIURI* aBaseURL) + : mLoader(aLoader), + mBaseURL(aBaseURL) +{ + MOZ_ASSERT(mLoader); + MOZ_ASSERT(mBaseURL); + MOZ_ASSERT(!mModuleRecord); + MOZ_ASSERT(mError.isUndefined()); +} + +void +ModuleScript::UnlinkModuleRecord() +{ + // Remove module's back reference to this object request if present. + if (mModuleRecord) { + MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() == + this); + JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue()); + mModuleRecord = nullptr; + } +} + +ModuleScript::~ModuleScript() +{ + // The object may be destroyed without being unlinked first. + UnlinkModuleRecord(); + DropJSObjects(this); +} + +void +ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord) +{ + MOZ_ASSERT(!mModuleRecord); + MOZ_ASSERT(mError.isUndefined()); + + mModuleRecord = aModuleRecord; + + // Make module's host defined field point to this module script object. + // This is cleared in the UnlinkModuleRecord(). + JS::SetModuleHostDefinedField(mModuleRecord, JS::PrivateValue(this)); + HoldJSObjects(this); +} + +void +ModuleScript::SetPreInstantiationError(const JS::Value& aError) +{ + MOZ_ASSERT(!aError.isUndefined()); + + UnlinkModuleRecord(); + mError = aError; + + HoldJSObjects(this); +} + +bool +ModuleScript::IsErrored() const +{ + if (!mModuleRecord) { + MOZ_ASSERT(!mError.isUndefined()); + return true; + } + + return JS::IsModuleErrored(mModuleRecord); +} + +JS::Value +ModuleScript::Error() const +{ + MOZ_ASSERT(IsErrored()); + + if (!mModuleRecord) { + return mError; + } + + return JS::GetModuleError(mModuleRecord); +} + +} // dom namespace +} // mozilla namespace diff --git a/dom/script/ModuleScript.h b/dom/script/ModuleScript.h new file mode 100644 index 0000000000..5713598592 --- /dev/null +++ b/dom/script/ModuleScript.h @@ -0,0 +1,53 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_ModuleScript_h +#define mozilla_dom_ModuleScript_h + +#include "nsCOMPtr.h" +#include "nsCycleCollectionParticipant.h" +#include "jsapi.h" + +class nsIURI; + +namespace mozilla { +namespace dom { + +class ScriptLoader; + +class ModuleScript final : public nsISupports +{ + RefPtr<ScriptLoader> mLoader; + nsCOMPtr<nsIURI> mBaseURL; + JS::Heap<JSObject*> mModuleRecord; + JS::Heap<JS::Value> mError; + + ~ModuleScript(); + +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ModuleScript) + + ModuleScript(ScriptLoader* aLoader, + nsIURI* aBaseURL); + + void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord); + void SetPreInstantiationError(const JS::Value& aError); + + ScriptLoader* Loader() const { return mLoader; } + JSObject* ModuleRecord() const { return mModuleRecord; } + nsIURI* BaseURL() const { return mBaseURL; } + + bool IsErrored() const; + JS::Value Error() const; + + void UnlinkModuleRecord(); +}; + +} // dom namespace +} // mozilla namespace + +#endif // mozilla_dom_ModuleScript_h
\ No newline at end of file diff --git a/dom/base/nsScriptElement.cpp b/dom/script/ScriptElement.cpp index ebeb18f81c..0cb17dcb06 100644 --- a/dom/base/nsScriptElement.cpp +++ b/dom/script/ScriptElement.cpp @@ -4,13 +4,13 @@ * 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 "nsScriptElement.h" +#include "ScriptElement.h" +#include "ScriptLoader.h" #include "mozilla/BasicEvents.h" #include "mozilla/EventDispatcher.h" #include "mozilla/dom/Element.h" #include "nsContentUtils.h" #include "nsPresContext.h" -#include "nsScriptLoader.h" #include "nsIParser.h" #include "nsGkAtoms.h" #include "nsContentSink.h" @@ -19,11 +19,11 @@ using namespace mozilla; using namespace mozilla::dom; NS_IMETHODIMP -nsScriptElement::ScriptAvailable(nsresult aResult, - nsIScriptElement *aElement, - bool aIsInline, - nsIURI *aURI, - int32_t aLineNo) +ScriptElement::ScriptAvailable(nsresult aResult, + nsIScriptElement *aElement, + bool aIsInline, + nsIURI *aURI, + int32_t aLineNo) { if (!aIsInline && NS_FAILED(aResult)) { nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser); @@ -40,7 +40,7 @@ nsScriptElement::ScriptAvailable(nsresult aResult, } /* virtual */ nsresult -nsScriptElement::FireErrorEvent() +ScriptElement::FireErrorEvent() { nsCOMPtr<nsIContent> cont = do_QueryInterface((nsIScriptElement*) this); @@ -53,9 +53,9 @@ nsScriptElement::FireErrorEvent() } NS_IMETHODIMP -nsScriptElement::ScriptEvaluated(nsresult aResult, - nsIScriptElement *aElement, - bool aIsInline) +ScriptElement::ScriptEvaluated(nsresult aResult, + nsIScriptElement *aElement, + bool aIsInline) { nsresult rv = NS_OK; if (!aIsInline) { @@ -78,44 +78,44 @@ nsScriptElement::ScriptEvaluated(nsresult aResult, } void -nsScriptElement::CharacterDataChanged(nsIDocument *aDocument, - nsIContent* aContent, - CharacterDataChangeInfo* aInfo) +ScriptElement::CharacterDataChanged(nsIDocument *aDocument, + nsIContent* aContent, + CharacterDataChangeInfo* aInfo) { MaybeProcessScript(); } void -nsScriptElement::AttributeChanged(nsIDocument* aDocument, - Element* aElement, - int32_t aNameSpaceID, - nsIAtom* aAttribute, - int32_t aModType, - const nsAttrValue* aOldValue) +ScriptElement::AttributeChanged(nsIDocument* aDocument, + Element* aElement, + int32_t aNameSpaceID, + nsIAtom* aAttribute, + int32_t aModType, + const nsAttrValue* aOldValue) { MaybeProcessScript(); } void -nsScriptElement::ContentAppended(nsIDocument* aDocument, - nsIContent* aContainer, - nsIContent* aFirstNewContent, - int32_t aNewIndexInContainer) +ScriptElement::ContentAppended(nsIDocument* aDocument, + nsIContent* aContainer, + nsIContent* aFirstNewContent, + int32_t aNewIndexInContainer) { MaybeProcessScript(); } void -nsScriptElement::ContentInserted(nsIDocument *aDocument, - nsIContent* aContainer, - nsIContent* aChild, - int32_t aIndexInContainer) +ScriptElement::ContentInserted(nsIDocument *aDocument, + nsIContent* aContainer, + nsIContent* aChild, + int32_t aIndexInContainer) { MaybeProcessScript(); } bool -nsScriptElement::MaybeProcessScript() +ScriptElement::MaybeProcessScript() { nsCOMPtr<nsIContent> cont = do_QueryInterface((nsIScriptElement*) this); @@ -145,6 +145,6 @@ nsScriptElement::MaybeProcessScript() } } - RefPtr<nsScriptLoader> loader = ownerDoc->ScriptLoader(); + RefPtr<ScriptLoader> loader = ownerDoc->ScriptLoader(); return loader->ProcessScriptElement(this); } diff --git a/dom/base/nsScriptElement.h b/dom/script/ScriptElement.h index 4a2a584ac2..0babda674a 100644 --- a/dom/base/nsScriptElement.h +++ b/dom/script/ScriptElement.h @@ -4,22 +4,25 @@ * 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/. */ -#ifndef nsScriptElement_h -#define nsScriptElement_h +#ifndef mozilla_dom_ScriptElement_h +#define mozilla_dom_ScriptElement_h #include "mozilla/Attributes.h" #include "nsIScriptLoaderObserver.h" #include "nsIScriptElement.h" #include "nsStubMutationObserver.h" +namespace mozilla { +namespace dom { + /** * Baseclass useful for script elements (such as <xhtml:script> and * <svg:script>). Currently the class assumes that only the 'src' * attribute and the children of the class affect what script to execute. */ -class nsScriptElement : public nsIScriptElement, - public nsStubMutationObserver +class ScriptElement : public nsIScriptElement, + public nsStubMutationObserver { public: // nsIScriptLoaderObserver @@ -31,7 +34,7 @@ public: NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED - explicit nsScriptElement(mozilla::dom::FromParser aFromParser) + explicit ScriptElement(FromParser aFromParser) : nsIScriptElement(aFromParser) { } @@ -49,4 +52,7 @@ protected: virtual bool MaybeProcessScript() override; }; -#endif // nsScriptElement_h +} // dom namespace +} // mozilla namespace + +#endif // mozilla_dom_ScriptElement_h diff --git a/dom/script/ScriptLoadHandler.cpp b/dom/script/ScriptLoadHandler.cpp new file mode 100644 index 0000000000..80fb70f6ae --- /dev/null +++ b/dom/script/ScriptLoadHandler.cpp @@ -0,0 +1,216 @@ +/* -*- 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/. */ + +/* + * A class that handles loading and evaluation of <script> elements. + */ + +#include "ScriptLoadHandler.h" +#include "ScriptLoader.h" +#include "nsContentUtils.h" + +#include "mozilla/dom/EncodingUtils.h" + +namespace mozilla { +namespace dom { + +ScriptLoadHandler::ScriptLoadHandler(ScriptLoader *aScriptLoader, + ScriptLoadRequest *aRequest, + mozilla::dom::SRICheckDataVerifier *aSRIDataVerifier) + : mScriptLoader(aScriptLoader), + mRequest(aRequest), + mSRIDataVerifier(aSRIDataVerifier), + mSRIStatus(NS_OK), + mDecoder(), + mBuffer() +{} + +ScriptLoadHandler::~ScriptLoadHandler() +{} + +NS_IMPL_ISUPPORTS(ScriptLoadHandler, nsIIncrementalStreamLoaderObserver) + +NS_IMETHODIMP +ScriptLoadHandler::OnIncrementalData(nsIIncrementalStreamLoader* aLoader, + nsISupports* aContext, + uint32_t aDataLength, + const uint8_t* aData, + uint32_t *aConsumedLength) +{ + if (mRequest->IsCanceled()) { + // If request cancelled, ignore any incoming data. + *aConsumedLength = aDataLength; + return NS_OK; + } + + if (!EnsureDecoder(aLoader, aData, aDataLength, + /* aEndOfStream = */ false)) { + return NS_OK; + } + + // Below we will/shall consume entire data chunk. + *aConsumedLength = aDataLength; + + // Decoder has already been initialized. -- trying to decode all loaded bytes. + nsresult rv = TryDecodeRawData(aData, aDataLength, + /* aEndOfStream = */ false); + NS_ENSURE_SUCCESS(rv, rv); + + // If SRI is required for this load, appending new bytes to the hash. + if (mSRIDataVerifier && NS_SUCCEEDED(mSRIStatus)) { + mSRIStatus = mSRIDataVerifier->Update(aDataLength, aData); + } + + return rv; +} + +nsresult +ScriptLoadHandler::TryDecodeRawData(const uint8_t* aData, + uint32_t aDataLength, + bool aEndOfStream) +{ + int32_t srcLen = aDataLength; + const char* src = reinterpret_cast<const char *>(aData); + int32_t dstLen; + nsresult rv = + mDecoder->GetMaxLength(src, srcLen, &dstLen); + + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t haveRead = mBuffer.length(); + + CheckedInt<uint32_t> capacity = haveRead; + capacity += dstLen; + + if (!capacity.isValid() || !mBuffer.reserve(capacity.value())) { + return NS_ERROR_OUT_OF_MEMORY; + } + + rv = mDecoder->Convert(src, + &srcLen, + mBuffer.begin() + haveRead, + &dstLen); + + NS_ENSURE_SUCCESS(rv, rv); + + haveRead += dstLen; + MOZ_ASSERT(haveRead <= capacity.value(), "mDecoder produced more data than expected"); + MOZ_ALWAYS_TRUE(mBuffer.resizeUninitialized(haveRead)); + + return NS_OK; +} + +bool +ScriptLoadHandler::EnsureDecoder(nsIIncrementalStreamLoader *aLoader, + const uint8_t* aData, + uint32_t aDataLength, + bool aEndOfStream) +{ + // Check if decoder has already been created. + if (mDecoder) { + return true; + } + + nsAutoCString charset; + + // JavaScript modules are always UTF-8. + if (mRequest->IsModuleRequest()) { + charset = "UTF-8"; + mDecoder = EncodingUtils::DecoderForEncoding(charset); + return true; + } + + // Determine if BOM check should be done. This occurs either + // if end-of-stream has been reached, or at least 3 bytes have + // been read from input. + if (!aEndOfStream && (aDataLength < 3)) { + return false; + } + + // Do BOM detection. + if (nsContentUtils::CheckForBOM(aData, aDataLength, charset)) { + mDecoder = EncodingUtils::DecoderForEncoding(charset); + return true; + } + + // BOM detection failed, check content stream for charset. + nsCOMPtr<nsIRequest> req; + nsresult rv = aLoader->GetRequest(getter_AddRefs(req)); + NS_ASSERTION(req, "StreamLoader's request went away prematurely"); + NS_ENSURE_SUCCESS(rv, false); + + nsCOMPtr<nsIChannel> channel = do_QueryInterface(req); + + if (channel && + NS_SUCCEEDED(channel->GetContentCharset(charset)) && + EncodingUtils::FindEncodingForLabel(charset, charset)) { + mDecoder = EncodingUtils::DecoderForEncoding(charset); + return true; + } + + // Check the hint charset from the script element or preload + // request. + nsAutoString hintCharset; + if (!mRequest->IsPreload()) { + mRequest->mElement->GetScriptCharset(hintCharset); + } else { + nsTArray<ScriptLoader::PreloadInfo>::index_type i = + mScriptLoader->mPreloads.IndexOf(mRequest, 0, + ScriptLoader::PreloadRequestComparator()); + + NS_ASSERTION(i != mScriptLoader->mPreloads.NoIndex, + "Incorrect preload bookkeeping"); + hintCharset = mScriptLoader->mPreloads[i].mCharset; + } + + if (EncodingUtils::FindEncodingForLabel(hintCharset, charset)) { + mDecoder = EncodingUtils::DecoderForEncoding(charset); + return true; + } + + // Get the charset from the charset of the document. + if (mScriptLoader->mDocument) { + charset = mScriptLoader->mDocument->GetDocumentCharacterSet(); + mDecoder = EncodingUtils::DecoderForEncoding(charset); + return true; + } + + // Curiously, there are various callers that don't pass aDocument. The + // fallback in the old code was ISO-8859-1, which behaved like + // windows-1252. Saying windows-1252 for clarity and for compliance + // with the Encoding Standard. + charset = "windows-1252"; + mDecoder = EncodingUtils::DecoderForEncoding(charset); + return true; +} + +NS_IMETHODIMP +ScriptLoadHandler::OnStreamComplete(nsIIncrementalStreamLoader* aLoader, + nsISupports* aContext, + nsresult aStatus, + uint32_t aDataLength, + const uint8_t* aData) +{ + if (!mRequest->IsCanceled()) { + DebugOnly<bool> encoderSet = + EnsureDecoder(aLoader, aData, aDataLength, /* aEndOfStream = */ true); + MOZ_ASSERT(encoderSet); + DebugOnly<nsresult> rv = TryDecodeRawData(aData, aDataLength, + /* aEndOfStream = */ true); + + // If SRI is required for this load, appending new bytes to the hash. + if (mSRIDataVerifier && NS_SUCCEEDED(mSRIStatus)) { + mSRIStatus = mSRIDataVerifier->Update(aDataLength, aData); + } + } + + // we have to mediate and use mRequest. + return mScriptLoader->OnStreamComplete(aLoader, mRequest, aStatus, mSRIStatus, + mBuffer, mSRIDataVerifier); +} + +} // dom namespace +} // mozilla namespace
\ No newline at end of file diff --git a/dom/script/ScriptLoadHandler.h b/dom/script/ScriptLoadHandler.h new file mode 100644 index 0000000000..b70f873974 --- /dev/null +++ b/dom/script/ScriptLoadHandler.h @@ -0,0 +1,76 @@ +/* -*- 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/. */ + +/* + * A class that handles loading and evaluation of <script> elements. + */ + +#ifndef mozilla_dom_ScriptLoadHandler_h +#define mozilla_dom_ScriptLoadHandler_h + +#include "nsIIncrementalStreamLoader.h" +#include "nsIUnicodeDecoder.h" +#include "nsAutoPtr.h" +#include "mozilla/Vector.h" + +namespace mozilla { +namespace dom { + +class ScriptLoadRequest; +class ScriptLoader; +class SRICheckDataVerifier; + +class ScriptLoadHandler final : public nsIIncrementalStreamLoaderObserver +{ +public: + explicit ScriptLoadHandler(ScriptLoader* aScriptLoader, + ScriptLoadRequest* aRequest, + SRICheckDataVerifier* aSRIDataVerifier); + + NS_DECL_ISUPPORTS + NS_DECL_NSIINCREMENTALSTREAMLOADEROBSERVER + +private: + virtual ~ScriptLoadHandler(); + + /* + * Try to decode some raw data. + */ + nsresult TryDecodeRawData(const uint8_t* aData, uint32_t aDataLength, + bool aEndOfStream); + + /* + * Discover the charset by looking at the stream data, the script + * tag, and other indicators. Returns true if charset has been + * discovered. + */ + bool EnsureDecoder(nsIIncrementalStreamLoader *aLoader, + const uint8_t* aData, uint32_t aDataLength, + bool aEndOfStream); + + // ScriptLoader which will handle the parsed script. + RefPtr<ScriptLoader> mScriptLoader; + + // The ScriptLoadRequest for this load. + RefPtr<ScriptLoadRequest> mRequest; + + // SRI data verifier. + nsAutoPtr<SRICheckDataVerifier> mSRIDataVerifier; + + // Status of SRI data operations. + nsresult mSRIStatus; + + // Unicode decoder for charset. + nsCOMPtr<nsIUnicodeDecoder> mDecoder; + + // Accumulated decoded char buffer. + mozilla::Vector<char16_t> mBuffer; +}; + +} // namespace dom +} // namespace mozilla + +#endif //mozilla_dom_ScriptLoader_h diff --git a/dom/base/nsScriptLoader.cpp b/dom/script/ScriptLoader.cpp index 25482fe7b6..a530989742 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/script/ScriptLoader.cpp @@ -4,11 +4,10 @@ * 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/. */ -/* - * A class that handles loading and evaluation of <script> elements. - */ - -#include "nsScriptLoader.h" +#include "ScriptLoader.h" +#include "ScriptLoadHandler.h" +#include "ModuleLoadRequest.h" +#include "ModuleScript.h" #include "prsystem.h" #include "jsapi.h" @@ -58,19 +57,19 @@ #include "mozilla/Unused.h" #include "nsIScriptError.h" -using namespace mozilla; -using namespace mozilla::dom; - using JS::SourceBufferHolder; +namespace mozilla { +namespace dom { + static LazyLogModule gCspPRLog("CSP"); void -ImplCycleCollectionUnlink(nsScriptLoadRequestList& aField); +ImplCycleCollectionUnlink(ScriptLoadRequestList& aField); void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, - nsScriptLoadRequestList& aField, + ScriptLoadRequestList& aField, const char* aName, uint32_t aFlags = 0); @@ -78,23 +77,23 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, // nsScriptLoadRequest ////////////////////////////////////////////////////////////// -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsScriptLoadRequest) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptLoadRequest) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsScriptLoadRequest) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsScriptLoadRequest) +NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptLoadRequest) +NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptLoadRequest) -NS_IMPL_CYCLE_COLLECTION_CLASS(nsScriptLoadRequest) +NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptLoadRequest) -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsScriptLoadRequest) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptLoadRequest) NS_IMPL_CYCLE_COLLECTION_UNLINK(mElement) NS_IMPL_CYCLE_COLLECTION_UNLINK_END -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsScriptLoadRequest) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ScriptLoadRequest) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -nsScriptLoadRequest::~nsScriptLoadRequest() +ScriptLoadRequest::~ScriptLoadRequest() { js_free(mScriptTextBuf); @@ -107,21 +106,21 @@ nsScriptLoadRequest::~nsScriptLoadRequest() } void -nsScriptLoadRequest::SetReady() +ScriptLoadRequest::SetReady() { MOZ_ASSERT(mProgress != Progress::Ready); mProgress = Progress::Ready; } void -nsScriptLoadRequest::Cancel() +ScriptLoadRequest::Cancel() { MaybeCancelOffThreadScript(); mIsCanceled = true; } void -nsScriptLoadRequest::MaybeCancelOffThreadScript() +ScriptLoadRequest::MaybeCancelOffThreadScript() { MOZ_ASSERT(NS_IsMainThread()); @@ -134,306 +133,28 @@ nsScriptLoadRequest::MaybeCancelOffThreadScript() mOffThreadToken = nullptr; } -////////////////////////////////////////////////////////////// -// nsModuleLoadRequest -////////////////////////////////////////////////////////////// - -// A load request for a module, created for every top level module script and -// every module import. Load request can share an nsModuleScript if there are -// multiple imports of the same module. - -class nsModuleLoadRequest final : public nsScriptLoadRequest -{ - ~nsModuleLoadRequest() {} - - nsModuleLoadRequest(const nsModuleLoadRequest& aOther) = delete; - nsModuleLoadRequest(nsModuleLoadRequest&& aOther) = delete; - -public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsModuleLoadRequest, nsScriptLoadRequest) - - nsModuleLoadRequest(nsIScriptElement* aElement, - uint32_t aVersion, - CORSMode aCORSMode, - const SRIMetadata& aIntegrity, - nsScriptLoader* aLoader); - - bool IsTopLevel() const { - return mIsTopLevel; - } - - void SetReady() override; - void Cancel() override; - - void ModuleLoaded(); - void DependenciesLoaded(); - void LoadFailed(); - - // Is this a request for a top level module script or an import? - bool mIsTopLevel; - - // The base URL used for resolving relative module imports. - nsCOMPtr<nsIURI> mBaseURL; - - // Pointer to the script loader, used to trigger actions when the module load - // finishes. - RefPtr<nsScriptLoader> mLoader; - - // The importing module, or nullptr for top level module scripts. Used to - // implement the ancestor list checked when fetching module dependencies. - RefPtr<nsModuleLoadRequest> mParent; - - // Set to a module script object after a successful load or nullptr on - // failure. - RefPtr<nsModuleScript> mModuleScript; - - // A promise that is completed on successful load of this module and all of - // its dependencies, indicating that the module is ready for instantiation and - // evaluation. - MozPromiseHolder<GenericPromise> mReady; - - // Array of imported modules. - nsTArray<RefPtr<nsModuleLoadRequest>> mImports; -}; - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsModuleLoadRequest) -NS_INTERFACE_MAP_END_INHERITING(nsScriptLoadRequest) - -NS_IMPL_CYCLE_COLLECTION_INHERITED(nsModuleLoadRequest, nsScriptLoadRequest, - mBaseURL, - mLoader, - mParent, - mModuleScript, - mImports) - -NS_IMPL_ADDREF_INHERITED(nsModuleLoadRequest, nsScriptLoadRequest) -NS_IMPL_RELEASE_INHERITED(nsModuleLoadRequest, nsScriptLoadRequest) - -nsModuleLoadRequest::nsModuleLoadRequest(nsIScriptElement* aElement, - uint32_t aVersion, - CORSMode aCORSMode, - const SRIMetadata &aIntegrity, - nsScriptLoader* aLoader) - : nsScriptLoadRequest(nsScriptKind::Module, - aElement, - aVersion, - aCORSMode, - aIntegrity), - mIsTopLevel(true), - mLoader(aLoader) -{} - -inline nsModuleLoadRequest* -nsScriptLoadRequest::AsModuleRequest() +inline ModuleLoadRequest* +ScriptLoadRequest::AsModuleRequest() { MOZ_ASSERT(IsModuleRequest()); - return static_cast<nsModuleLoadRequest*>(this); -} - -void nsModuleLoadRequest::Cancel() -{ - nsScriptLoadRequest::Cancel(); - mModuleScript = nullptr; - mProgress = nsScriptLoadRequest::Progress::Ready; - for (size_t i = 0; i < mImports.Length(); i++) { - mImports[i]->Cancel(); - } - mReady.RejectIfExists(NS_ERROR_FAILURE, __func__); -} - -void -nsModuleLoadRequest::SetReady() -{ -#ifdef DEBUG - for (size_t i = 0; i < mImports.Length(); i++) { - MOZ_ASSERT(mImports[i]->IsReadyToRun()); - } -#endif - - nsScriptLoadRequest::SetReady(); - mReady.ResolveIfExists(true, __func__); -} - -void -nsModuleLoadRequest::ModuleLoaded() -{ - // A module that was found to be marked as fetching in the module map has now - // been loaded. - - mModuleScript = mLoader->GetFetchedModule(mURI); - mLoader->StartFetchingModuleDependencies(this); -} - -void -nsModuleLoadRequest::DependenciesLoaded() -{ - // The module and all of its dependencies have been successfully fetched and - // compiled. - - if (!mLoader->InstantiateModuleTree(this)) { - LoadFailed(); - return; - } - - SetReady(); - mLoader->ProcessLoadedModuleTree(this); - mLoader = nullptr; - mParent = nullptr; -} - -void -nsModuleLoadRequest::LoadFailed() -{ - Cancel(); - mLoader->ProcessLoadedModuleTree(this); - mLoader = nullptr; - mParent = nullptr; -} - -////////////////////////////////////////////////////////////// -// nsModuleScript -////////////////////////////////////////////////////////////// - -// A single module script. May be used to satisfy multiple load requests. - -class nsModuleScript final : public nsISupports -{ - enum InstantiationState { - Uninstantiated, - Instantiated, - Errored - }; - - RefPtr<nsScriptLoader> mLoader; - nsCOMPtr<nsIURI> mBaseURL; - JS::Heap<JSObject*> mModuleRecord; - JS::Heap<JS::Value> mException; - InstantiationState mInstantiationState; - - ~nsModuleScript(); - -public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsModuleScript) - - nsModuleScript(nsScriptLoader* aLoader, - nsIURI* aBaseURL, - JS::Handle<JSObject*> aModuleRecord); - - nsScriptLoader* Loader() const { return mLoader; } - JSObject* ModuleRecord() const { return mModuleRecord; } - JS::Value Exception() const { return mException; } - nsIURI* BaseURL() const { return mBaseURL; } - - void SetInstantiationResult(JS::Handle<JS::Value> aMaybeException); - bool IsUninstantiated() const { - return mInstantiationState == Uninstantiated; - } - bool IsInstantiated() const { - return mInstantiationState == Instantiated; - } - bool InstantiationFailed() const { - return mInstantiationState == Errored; - } - - void UnlinkModuleRecord(); -}; - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsModuleScript) -NS_INTERFACE_MAP_END - -NS_IMPL_CYCLE_COLLECTION_CLASS(nsModuleScript) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsModuleScript) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL) - tmp->UnlinkModuleRecord(); -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsModuleScript) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsModuleScript) - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord) - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mException) -NS_IMPL_CYCLE_COLLECTION_TRACE_END - -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsModuleScript) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsModuleScript) - -nsModuleScript::nsModuleScript(nsScriptLoader *aLoader, nsIURI* aBaseURL, - JS::Handle<JSObject*> aModuleRecord) - : mLoader(aLoader), - mBaseURL(aBaseURL), - mModuleRecord(aModuleRecord), - mInstantiationState(Uninstantiated) -{ - MOZ_ASSERT(mLoader); - MOZ_ASSERT(mBaseURL); - MOZ_ASSERT(mModuleRecord); - MOZ_ASSERT(mException.isUndefined()); - - // Make module's host defined field point to this module script object. - // This is cleared in the UnlinkModuleRecord(). - JS::SetModuleHostDefinedField(mModuleRecord, JS::PrivateValue(this)); - HoldJSObjects(this); -} - -void -nsModuleScript::UnlinkModuleRecord() -{ - // Remove module's back reference to this object request if present. - if (mModuleRecord) { - MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() == - this); - JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue()); - } - mModuleRecord = nullptr; - mException.setUndefined(); -} - -nsModuleScript::~nsModuleScript() -{ - if (mModuleRecord) { - // The object may be destroyed without being unlinked first. - UnlinkModuleRecord(); - } - DropJSObjects(this); -} - -void -nsModuleScript::SetInstantiationResult(JS::Handle<JS::Value> aMaybeException) -{ - MOZ_ASSERT(mInstantiationState == Uninstantiated); - MOZ_ASSERT(mModuleRecord); - MOZ_ASSERT(mException.isUndefined()); - - if (aMaybeException.isUndefined()) { - mInstantiationState = Instantiated; - } else { - mModuleRecord = nullptr; - mException = aMaybeException; - mInstantiationState = Errored; - } + return static_cast<ModuleLoadRequest*>(this); } ////////////////////////////////////////////////////////////// -// nsScriptLoadRequestList +// ScriptLoadRequestList ////////////////////////////////////////////////////////////// -nsScriptLoadRequestList::~nsScriptLoadRequestList() +ScriptLoadRequestList::~ScriptLoadRequestList() { Clear(); } void -nsScriptLoadRequestList::Clear() +ScriptLoadRequestList::Clear() { while (!isEmpty()) { - RefPtr<nsScriptLoadRequest> first = StealFirst(); + RefPtr<ScriptLoadRequest> first = StealFirst(); first->Cancel(); // And just let it go out of scope and die. } @@ -441,9 +162,9 @@ nsScriptLoadRequestList::Clear() #ifdef DEBUG bool -nsScriptLoadRequestList::Contains(nsScriptLoadRequest* aElem) const +ScriptLoadRequestList::Contains(ScriptLoadRequest* aElem) const { - for (const nsScriptLoadRequest* req = getFirst(); + for (const ScriptLoadRequest* req = getFirst(); req; req = req->getNext()) { if (req == aElem) { return true; @@ -455,20 +176,20 @@ nsScriptLoadRequestList::Contains(nsScriptLoadRequest* aElem) const #endif // DEBUG inline void -ImplCycleCollectionUnlink(nsScriptLoadRequestList& aField) +ImplCycleCollectionUnlink(ScriptLoadRequestList& aField) { while (!aField.isEmpty()) { - RefPtr<nsScriptLoadRequest> first = aField.StealFirst(); + RefPtr<ScriptLoadRequest> first = aField.StealFirst(); } } inline void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, - nsScriptLoadRequestList& aField, + ScriptLoadRequestList& aField, const char* aName, uint32_t aFlags) { - for (nsScriptLoadRequest* request = aField.getFirst(); + for (ScriptLoadRequest* request = aField.getFirst(); request; request = request->getNext()) { CycleCollectionNoteChild(aCallback, request, aName, aFlags); @@ -476,18 +197,18 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, } ////////////////////////////////////////////////////////////// -// nsScriptLoader::PreloadInfo +// ScriptLoader::PreloadInfo ////////////////////////////////////////////////////////////// inline void -ImplCycleCollectionUnlink(nsScriptLoader::PreloadInfo& aField) +ImplCycleCollectionUnlink(ScriptLoader::PreloadInfo& aField) { ImplCycleCollectionUnlink(aField.mRequest); } inline void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, - nsScriptLoader::PreloadInfo& aField, + ScriptLoader::PreloadInfo& aField, const char* aName, uint32_t aFlags = 0) { @@ -495,13 +216,13 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, } ////////////////////////////////////////////////////////////// -// nsScriptLoader +// ScriptLoader ////////////////////////////////////////////////////////////// -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsScriptLoader) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptLoader) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION(nsScriptLoader, +NS_IMPL_CYCLE_COLLECTION(ScriptLoader, mNonAsyncExternalScriptInsertedRequests, mLoadingAsyncRequests, mLoadedAsyncRequests, @@ -512,10 +233,10 @@ NS_IMPL_CYCLE_COLLECTION(nsScriptLoader, mPendingChildLoaders, mFetchedModules) -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsScriptLoader) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsScriptLoader) +NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptLoader) +NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptLoader) -nsScriptLoader::nsScriptLoader(nsIDocument *aDocument) +ScriptLoader::ScriptLoader(nsIDocument *aDocument) : mDocument(aDocument), mParserBlockingBlockerCount(0), mBlockerCount(0), @@ -528,7 +249,7 @@ nsScriptLoader::nsScriptLoader(nsIDocument *aDocument) { } -nsScriptLoader::~nsScriptLoader() +ScriptLoader::~ScriptLoader() { mObservers.Clear(); @@ -536,27 +257,27 @@ nsScriptLoader::~nsScriptLoader() mParserBlockingRequest->FireScriptAvailable(NS_ERROR_ABORT); } - for (nsScriptLoadRequest* req = mXSLTRequests.getFirst(); req; + for (ScriptLoadRequest* req = mXSLTRequests.getFirst(); req; req = req->getNext()) { req->FireScriptAvailable(NS_ERROR_ABORT); } - for (nsScriptLoadRequest* req = mDeferRequests.getFirst(); req; + for (ScriptLoadRequest* req = mDeferRequests.getFirst(); req; req = req->getNext()) { req->FireScriptAvailable(NS_ERROR_ABORT); } - for (nsScriptLoadRequest* req = mLoadingAsyncRequests.getFirst(); req; + for (ScriptLoadRequest* req = mLoadingAsyncRequests.getFirst(); req; req = req->getNext()) { req->FireScriptAvailable(NS_ERROR_ABORT); } - for (nsScriptLoadRequest* req = mLoadedAsyncRequests.getFirst(); req; + for (ScriptLoadRequest* req = mLoadedAsyncRequests.getFirst(); req; req = req->getNext()) { req->FireScriptAvailable(NS_ERROR_ABORT); } - for(nsScriptLoadRequest* req = mNonAsyncExternalScriptInsertedRequests.getFirst(); + for(ScriptLoadRequest* req = mNonAsyncExternalScriptInsertedRequests.getFirst(); req; req = req->getNext()) { req->FireScriptAvailable(NS_ERROR_ABORT); @@ -623,11 +344,11 @@ IsScriptEventHandler(nsIContent* aScriptElement) } nsresult -nsScriptLoader::CheckContentPolicy(nsIDocument* aDocument, - nsISupports *aContext, - nsIURI *aURI, - const nsAString &aType, - bool aIsPreLoad) +ScriptLoader::CheckContentPolicy(nsIDocument* aDocument, + nsISupports *aContext, + nsIURI *aURI, + const nsAString &aType, + bool aIsPreLoad) { nsContentPolicyType contentPolicyType = aIsPreLoad ? nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD @@ -654,7 +375,7 @@ nsScriptLoader::CheckContentPolicy(nsIDocument* aDocument, } bool -nsScriptLoader::ModuleScriptsEnabled() +ScriptLoader::ModuleScriptsEnabled() { static bool sEnabledForContent = false; static bool sCachedPref = false; @@ -667,7 +388,7 @@ nsScriptLoader::ModuleScriptsEnabled() } bool -nsScriptLoader::ModuleMapContainsModule(nsModuleLoadRequest *aRequest) const +ScriptLoader::ModuleMapContainsModule(ModuleLoadRequest *aRequest) const { // Returns whether we have fetched, or are currently fetching, a module script // for the request's URL. @@ -676,7 +397,7 @@ nsScriptLoader::ModuleMapContainsModule(nsModuleLoadRequest *aRequest) const } bool -nsScriptLoader::IsFetchingModule(nsModuleLoadRequest *aRequest) const +ScriptLoader::IsFetchingModule(ModuleLoadRequest *aRequest) const { bool fetching = mFetchingModules.Contains(aRequest->mURI); MOZ_ASSERT_IF(fetching, !mFetchedModules.Contains(aRequest->mURI)); @@ -684,7 +405,7 @@ nsScriptLoader::IsFetchingModule(nsModuleLoadRequest *aRequest) const } void -nsScriptLoader::SetModuleFetchStarted(nsModuleLoadRequest *aRequest) +ScriptLoader::SetModuleFetchStarted(ModuleLoadRequest *aRequest) { // Update the module map to indicate that a module is currently being fetched. @@ -694,24 +415,26 @@ nsScriptLoader::SetModuleFetchStarted(nsModuleLoadRequest *aRequest) } void -nsScriptLoader::SetModuleFetchFinishedAndResumeWaitingRequests(nsModuleLoadRequest *aRequest, - nsresult aResult) +ScriptLoader::SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest *aRequest, + nsresult aResult) { - // Update module map with the result of fetching a single module script. The - // module script pointer is nullptr on error. - - MOZ_ASSERT(!aRequest->IsReadyToRun()); + // Update module map with the result of fetching a single module script. + // + // If any requests for the same URL are waiting on this one to complete, they + // will have ModuleLoaded or LoadFailed on them when the promise is + // resolved/rejected. This is set up in StartLoad. RefPtr<GenericPromise::Private> promise; MOZ_ALWAYS_TRUE(mFetchingModules.Get(aRequest->mURI, getter_AddRefs(promise))); mFetchingModules.Remove(aRequest->mURI); - RefPtr<nsModuleScript> ms(aRequest->mModuleScript); - MOZ_ASSERT(NS_SUCCEEDED(aResult) == (ms != nullptr)); - mFetchedModules.Put(aRequest->mURI, ms); + RefPtr<ModuleScript> moduleScript(aRequest->mModuleScript); + MOZ_ASSERT(NS_FAILED(aResult) == !moduleScript); + + mFetchedModules.Put(aRequest->mURI, moduleScript); if (promise) { - if (ms) { + if (moduleScript) { promise->Resolve(true, __func__); } else { promise->Reject(aResult, __func__); @@ -720,7 +443,7 @@ nsScriptLoader::SetModuleFetchFinishedAndResumeWaitingRequests(nsModuleLoadReque } RefPtr<GenericPromise> -nsScriptLoader::WaitForModuleFetch(nsModuleLoadRequest *aRequest) +ScriptLoader::WaitForModuleFetch(ModuleLoadRequest *aRequest) { MOZ_ASSERT(ModuleMapContainsModule(aRequest)); @@ -733,7 +456,7 @@ nsScriptLoader::WaitForModuleFetch(nsModuleLoadRequest *aRequest) return promise; } - RefPtr<nsModuleScript> ms; + RefPtr<ModuleScript> ms; MOZ_ALWAYS_TRUE(mFetchedModules.Get(aRequest->mURI, getter_AddRefs(ms))); if (!ms) { return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); @@ -742,36 +465,46 @@ nsScriptLoader::WaitForModuleFetch(nsModuleLoadRequest *aRequest) return GenericPromise::CreateAndResolve(true, __func__); } -nsModuleScript* -nsScriptLoader::GetFetchedModule(nsIURI* aURL) const +ModuleScript* +ScriptLoader::GetFetchedModule(nsIURI* aURL) const { bool found; - nsModuleScript* ms = mFetchedModules.GetWeak(aURL, &found); + ModuleScript* ms = mFetchedModules.GetWeak(aURL, &found); MOZ_ASSERT(found); return ms; } nsresult -nsScriptLoader::ProcessFetchedModuleSource(nsModuleLoadRequest* aRequest) +ScriptLoader::ProcessFetchedModuleSource(ModuleLoadRequest* aRequest) { MOZ_ASSERT(!aRequest->mModuleScript); nsresult rv = CreateModuleScript(aRequest); + MOZ_ASSERT(NS_FAILED(rv) == !aRequest->mModuleScript); + SetModuleFetchFinishedAndResumeWaitingRequests(aRequest, rv); free(aRequest->mScriptTextBuf); aRequest->mScriptTextBuf = nullptr; aRequest->mScriptTextLength = 0; - if (NS_SUCCEEDED(rv)) { + if (NS_FAILED(rv)) { + aRequest->LoadFailed(); + return rv; + } + + if (!aRequest->mModuleScript->IsErrored()) { StartFetchingModuleDependencies(aRequest); } - return rv; + return NS_OK; } +static nsresult +ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI>& aUrls); + nsresult -nsScriptLoader::CreateModuleScript(nsModuleLoadRequest* aRequest) +ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest) { MOZ_ASSERT(!aRequest->mModuleScript); MOZ_ASSERT(aRequest->mBaseURL); @@ -823,9 +556,34 @@ nsScriptLoader::CreateModuleScript(nsModuleLoadRequest* aRequest) } } MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr)); - if (module) { - aRequest->mModuleScript = - new nsModuleScript(this, aRequest->mBaseURL, module); + RefPtr<ModuleScript> moduleScript = new ModuleScript(this, aRequest->mBaseURL); + aRequest->mModuleScript = moduleScript; + + if (!module) { + // Compilation failed + MOZ_ASSERT(aes.HasException()); + JS::Rooted<JS::Value> error(cx); + if (!aes.StealException(&error)) { + aRequest->mModuleScript = nullptr; + return NS_ERROR_FAILURE; + } + + moduleScript->SetPreInstantiationError(error); + aRequest->ModuleErrored(); + return NS_OK; + } + + moduleScript->SetModuleRecord(module); + + // Validate requested modules and treat failure to resolve module specifiers + // the same as a parse error. + nsCOMArray<nsIURI> urls; + rv = ResolveRequestedModules(aRequest, urls); + if (NS_FAILED(rv)) { + // ResolveRequestedModules sets pre-instanitation error on failure. + MOZ_ASSERT(moduleScript->IsErrored()); + aRequest->ModuleErrored(); + return NS_OK; } } @@ -835,8 +593,8 @@ nsScriptLoader::CreateModuleScript(nsModuleLoadRequest* aRequest) } static bool -ThrowTypeError(JSContext* aCx, nsModuleScript* aScript, - const nsString& aMessage) +CreateTypeError(JSContext* aCx, ModuleScript* aScript, const nsString& aMessage, + JS::MutableHandle<JS::Value> aError) { JS::Rooted<JSObject*> module(aCx, aScript->ModuleRecord()); JS::Rooted<JSScript*> script(aCx, JS::GetModuleScript(aCx, module)); @@ -851,18 +609,12 @@ ThrowTypeError(JSContext* aCx, nsModuleScript* aScript, return false; } - JS::Rooted<JS::Value> error(aCx); - if (!JS::CreateError(aCx, JSEXN_TYPEERR, nullptr, filename, 0, 0, nullptr, - message, &error)) { - return false; - } - - JS_SetPendingException(aCx, error); - return false; + return JS::CreateError(aCx, JSEXN_TYPEERR, nullptr, filename, 0, 0, nullptr, + message, aError); } -static bool -HandleResolveFailure(JSContext* aCx, nsModuleScript* aScript, +static nsresult +HandleResolveFailure(JSContext* aCx, ModuleScript* aScript, const nsAString& aSpecifier) { // TODO: How can we get the line number of the failed import? @@ -870,23 +622,17 @@ HandleResolveFailure(JSContext* aCx, nsModuleScript* aScript, nsAutoString message(NS_LITERAL_STRING("Error resolving module specifier: ")); message.Append(aSpecifier); - return ThrowTypeError(aCx, aScript, message); -} - -static bool -HandleModuleNotFound(JSContext* aCx, nsModuleScript* aScript, - const nsAString& aSpecifier) -{ - // TODO: How can we get the line number of the failed import? - - nsAutoString message(NS_LITERAL_STRING("Resolved module not found in map: ")); - message.Append(aSpecifier); + JS::Rooted<JS::Value> error(aCx); + if (!CreateTypeError(aCx, aScript, message, &error)) { + return NS_ERROR_OUT_OF_MEMORY; + } - return ThrowTypeError(aCx, aScript, message); + aScript->SetPreInstantiationError(error); + return NS_OK; } static already_AddRefed<nsIURI> -ResolveModuleSpecifier(nsModuleScript* aScript, +ResolveModuleSpecifier(ModuleScript* aScript, const nsAString& aSpecifier) { // The following module specifiers are allowed by the spec: @@ -921,7 +667,7 @@ ResolveModuleSpecifier(nsModuleScript* aScript, } static nsresult -RequestedModuleIsInAncestorList(nsModuleLoadRequest* aRequest, nsIURI* aURL, bool* aResult) +RequestedModuleIsInAncestorList(ModuleLoadRequest* aRequest, nsIURI* aURL, bool* aResult) { const size_t ImportDepthLimit = 100; @@ -947,9 +693,9 @@ RequestedModuleIsInAncestorList(nsModuleLoadRequest* aRequest, nsIURI* aURL, boo } static nsresult -ResolveRequestedModules(nsModuleLoadRequest* aRequest, nsCOMArray<nsIURI> &aUrls) +ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI> &aUrls) { - nsModuleScript* ms = aRequest->mModuleScript; + ModuleScript* ms = aRequest->mModuleScript; AutoJSAPI jsapi; if (!jsapi.Init(ms->ModuleRecord())) { @@ -977,10 +723,11 @@ ResolveRequestedModules(nsModuleLoadRequest* aRequest, nsCOMArray<nsIURI> &aUrls } // Let url be the result of resolving a module specifier given module script and requested. - nsModuleScript* ms = aRequest->mModuleScript; + ModuleScript* ms = aRequest->mModuleScript; nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(ms, specifier); if (!uri) { - HandleResolveFailure(cx, ms, specifier); + nsresult rv = HandleResolveFailure(cx, ms, specifier); + NS_ENSURE_SUCCESS(rv, rv); return NS_ERROR_FAILURE; } @@ -996,16 +743,18 @@ ResolveRequestedModules(nsModuleLoadRequest* aRequest, nsCOMArray<nsIURI> &aUrls } void -nsScriptLoader::StartFetchingModuleDependencies(nsModuleLoadRequest* aRequest) +ScriptLoader::StartFetchingModuleDependencies(ModuleLoadRequest* aRequest) { MOZ_ASSERT(aRequest->mModuleScript); + MOZ_ASSERT(!aRequest->mModuleScript->IsErrored()); MOZ_ASSERT(!aRequest->IsReadyToRun()); - aRequest->mProgress = nsModuleLoadRequest::Progress::FetchingImports; + + aRequest->mProgress = ModuleLoadRequest::Progress::FetchingImports; nsCOMArray<nsIURI> urls; nsresult rv = ResolveRequestedModules(aRequest, urls); if (NS_FAILED(rv)) { - aRequest->LoadFailed(); + aRequest->ModuleErrored(); return; } @@ -1028,19 +777,19 @@ nsScriptLoader::StartFetchingModuleDependencies(nsModuleLoadRequest* aRequest) RefPtr<GenericPromise::AllPromiseType> allReady = GenericPromise::All(AbstractThread::GetCurrent(), importsReady); allReady->Then(AbstractThread::GetCurrent(), __func__, aRequest, - &nsModuleLoadRequest::DependenciesLoaded, - &nsModuleLoadRequest::LoadFailed); + &ModuleLoadRequest::DependenciesLoaded, + &ModuleLoadRequest::ModuleErrored); } RefPtr<GenericPromise> -nsScriptLoader::StartFetchingModuleAndDependencies(nsModuleLoadRequest* aRequest, - nsIURI* aURI) +ScriptLoader::StartFetchingModuleAndDependencies(ModuleLoadRequest* aRequest, + nsIURI* aURI) { MOZ_ASSERT(aURI); - RefPtr<nsModuleLoadRequest> childRequest = - new nsModuleLoadRequest(aRequest->mElement, aRequest->mJSVersion, - aRequest->mCORSMode, aRequest->mIntegrity, this); + RefPtr<ModuleLoadRequest> childRequest = + new ModuleLoadRequest(aRequest->mElement, aRequest->mJSVersion, + aRequest->mCORSMode, aRequest->mIntegrity, this); childRequest->mIsTopLevel = false; childRequest->mURI = aURI; @@ -1052,6 +801,7 @@ nsScriptLoader::StartFetchingModuleAndDependencies(nsModuleLoadRequest* aRequest nsresult rv = StartLoad(childRequest, NS_LITERAL_STRING("module"), false); if (NS_FAILED(rv)) { + MOZ_ASSERT(!childRequest->mModuleScript); childRequest->mReady.Reject(rv, __func__); return ready; } @@ -1060,6 +810,7 @@ nsScriptLoader::StartFetchingModuleAndDependencies(nsModuleLoadRequest* aRequest return ready; } +// 8.1.3.8.1 HostResolveImportedModule(referencingModule, specifier) bool HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp) { @@ -1070,35 +821,29 @@ HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp) // Let referencing module script be referencingModule.[[HostDefined]]. JS::Value value = JS::GetModuleHostDefinedField(module); - auto script = static_cast<nsModuleScript*>(value.toPrivate()); + auto script = static_cast<ModuleScript*>(value.toPrivate()); MOZ_ASSERT(script->ModuleRecord() == module); // Let url be the result of resolving a module specifier given referencing - // module script and specifier. If the result is failure, throw a TypeError - // exception and abort these steps. + // module script and specifier. nsAutoJSString string; if (!string.init(aCx, specifier)) { return false; } nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(script, string); - if (!uri) { - return HandleResolveFailure(aCx, script, string); - } - // Let resolved module script be the value of the entry in module map whose - // key is url. If no such entry exists, throw a TypeError exception and abort - // these steps. - nsModuleScript* ms = script->Loader()->GetFetchedModule(uri); - if (!ms) { - return HandleModuleNotFound(aCx, script, string); - } + // This cannot fail because resolving a module specifier must have been + // previously successful with these same two arguments. + MOZ_ASSERT(uri, "Failed to resolve previously-resolved module specifier"); - if (ms->InstantiationFailed()) { - JS::Rooted<JS::Value> exception(aCx, ms->Exception()); - JS_SetPendingException(aCx, exception); - return false; - } + // Let resolved module script be moduleMap[url]. (This entry must exist for us + // to have gotten to this point.) + + ModuleScript* ms = script->Loader()->GetFetchedModule(uri); + MOZ_ASSERT(ms, "Resolved module not found in module map"); + + MOZ_ASSERT(!ms->IsErrored()); *vp = JS::ObjectValue(*ms->ModuleRecord()); return true; @@ -1123,9 +868,35 @@ EnsureModuleResolveHook(JSContext* aCx) } void -nsScriptLoader::ProcessLoadedModuleTree(nsModuleLoadRequest* aRequest) +ScriptLoader::CheckModuleDependenciesLoaded(ModuleLoadRequest* aRequest) +{ + RefPtr<ModuleScript> moduleScript = aRequest->mModuleScript; + if (moduleScript && !moduleScript->IsErrored()) { + for (auto childRequest : aRequest->mImports) { + ModuleScript* childScript = childRequest->mModuleScript; + if (!childScript) { + // Load error + aRequest->mModuleScript = nullptr; + return; + } else if (childScript->IsErrored()) { + // Script error + moduleScript->SetPreInstantiationError(childScript->Error()); + return; + } + } + } +} + +void +ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest) { if (aRequest->IsTopLevel()) { + ModuleScript* moduleScript = aRequest->mModuleScript; + if (moduleScript && !moduleScript->IsErrored()) { + if (!InstantiateModuleTree(aRequest)) { + aRequest->mModuleScript = nullptr; + } + } MaybeMoveToLoadedList(aRequest); ProcessPendingRequests(); } @@ -1136,70 +907,45 @@ nsScriptLoader::ProcessLoadedModuleTree(nsModuleLoadRequest* aRequest) } bool -nsScriptLoader::InstantiateModuleTree(nsModuleLoadRequest* aRequest) +ScriptLoader::InstantiateModuleTree(ModuleLoadRequest* aRequest) { - // Perform eager instantiation of the loaded module tree. + // Instantiate a top-level module and record any error. MOZ_ASSERT(aRequest); + MOZ_ASSERT(aRequest->IsTopLevel()); - nsModuleScript* ms = aRequest->mModuleScript; - MOZ_ASSERT(ms); - if (!ms || !ms->ModuleRecord()) { - return false; - } + ModuleScript* moduleScript = aRequest->mModuleScript; + MOZ_ASSERT(moduleScript); + MOZ_ASSERT(moduleScript->ModuleRecord()); + nsAutoMicroTask mt; AutoJSAPI jsapi; - if (NS_WARN_IF(!jsapi.Init(ms->ModuleRecord()))) { + if (NS_WARN_IF(!jsapi.Init(moduleScript->ModuleRecord()))) { return false; } nsresult rv = EnsureModuleResolveHook(jsapi.cx()); NS_ENSURE_SUCCESS(rv, false); - JS::Rooted<JSObject*> module(jsapi.cx(), ms->ModuleRecord()); - bool ok = NS_SUCCEEDED(nsJSUtils::ModuleDeclarationInstantiation(jsapi.cx(), module)); + JS::Rooted<JSObject*> module(jsapi.cx(), moduleScript->ModuleRecord()); + bool ok = NS_SUCCEEDED(nsJSUtils::ModuleInstantiate(jsapi.cx(), module)); - JS::RootedValue exception(jsapi.cx()); if (!ok) { MOZ_ASSERT(jsapi.HasException()); + JS::RootedValue exception(jsapi.cx()); if (!jsapi.StealException(&exception)) { return false; } MOZ_ASSERT(!exception.isUndefined()); - } - - // Mark this module and any uninstantiated dependencies found via depth-first - // search as instantiated and record any error. - - mozilla::Vector<nsModuleLoadRequest*, 1> requests; - if (!requests.append(aRequest)) { - return false; - } - - while (!requests.empty()) { - nsModuleLoadRequest* request = requests.popCopy(); - nsModuleScript* ms = request->mModuleScript; - if (!ms->IsUninstantiated()) { - continue; - } - - ms->SetInstantiationResult(exception); - - for (auto import : request->mImports) { - if (import->mModuleScript->IsUninstantiated() && - !requests.append(import)) - { - return false; - } - } + // Ignore the exception. It will be recorded in the module record. } return true; } nsresult -nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType, - bool aScriptFromHead) +ScriptLoader::StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType, + bool aScriptFromHead) { MOZ_ASSERT(aRequest->IsLoading()); NS_ENSURE_TRUE(mDocument, NS_ERROR_NULL_POINTER); @@ -1212,12 +958,12 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType, if (aRequest->IsModuleRequest()) { // Check whether the module has been fetched or is currently being fetched, // and if so wait for it. - nsModuleLoadRequest* request = aRequest->AsModuleRequest(); + ModuleLoadRequest* request = aRequest->AsModuleRequest(); if (ModuleMapContainsModule(request)) { WaitForModuleFetch(request) ->Then(AbstractThread::GetCurrent(), __func__, request, - &nsModuleLoadRequest::ModuleLoaded, - &nsModuleLoadRequest::LoadFailed); + &ModuleLoadRequest::ModuleLoaded, + &ModuleLoadRequest::LoadFailed); return NS_OK; } @@ -1330,8 +1076,8 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType, mReporter); } - RefPtr<nsScriptLoadHandler> handler = - new nsScriptLoadHandler(this, aRequest, sriDataVerifier.forget()); + RefPtr<ScriptLoadHandler> handler = + new ScriptLoadHandler(this, aRequest, sriDataVerifier.forget()); nsCOMPtr<nsIIncrementalStreamLoader> loader; rv = NS_NewIncrementalStreamLoader(getter_AddRefs(loader), handler); @@ -1341,22 +1087,22 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType, } bool -nsScriptLoader::PreloadURIComparator::Equals(const PreloadInfo &aPi, - nsIURI * const &aURI) const +ScriptLoader::PreloadURIComparator::Equals(const PreloadInfo &aPi, + nsIURI * const &aURI) const { bool same; return NS_SUCCEEDED(aPi.mRequest->mURI->Equals(aURI, &same)) && same; } -class nsScriptRequestProcessor : public Runnable +class ScriptRequestProcessor : public Runnable { private: - RefPtr<nsScriptLoader> mLoader; - RefPtr<nsScriptLoadRequest> mRequest; + RefPtr<ScriptLoader> mLoader; + RefPtr<ScriptLoadRequest> mRequest; public: - nsScriptRequestProcessor(nsScriptLoader* aLoader, - nsScriptLoadRequest* aRequest) + ScriptRequestProcessor(ScriptLoader* aLoader, + ScriptLoadRequest* aRequest) : mLoader(aLoader) , mRequest(aRequest) {} @@ -1428,24 +1174,23 @@ CSPAllowsInlineScript(nsIScriptElement *aElement, nsIDocument *aDocument) return allowInlineScript; } -nsScriptLoadRequest* -nsScriptLoader::CreateLoadRequest(nsScriptKind aKind, - nsIScriptElement* aElement, - uint32_t aVersion, CORSMode aCORSMode, - const SRIMetadata &aIntegrity) +ScriptLoadRequest* +ScriptLoader::CreateLoadRequest(ScriptKind aKind, + nsIScriptElement* aElement, + uint32_t aVersion, CORSMode aCORSMode, + const SRIMetadata &aIntegrity) { - if (aKind == nsScriptKind::Classic) { - return new nsScriptLoadRequest(aKind, aElement, aVersion, aCORSMode, - aIntegrity); + if (aKind == ScriptKind::Classic) { + return new ScriptLoadRequest(aKind, aElement, aVersion, aCORSMode, + aIntegrity); } - MOZ_ASSERT(aKind == nsScriptKind::Module); - return new nsModuleLoadRequest(aElement, aVersion, aCORSMode, aIntegrity, - this); + MOZ_ASSERT(aKind == ScriptKind::Module); + return new ModuleLoadRequest(aElement, aVersion, aCORSMode, aIntegrity, this); } bool -nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) +ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) { // We need a document to evaluate scripts. NS_ENSURE_TRUE(mDocument, false); @@ -1471,10 +1216,10 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) nsAutoString type; bool hasType = aElement->GetScriptType(type); - nsScriptKind scriptKind = nsScriptKind::Classic; + ScriptKind scriptKind = ScriptKind::Classic; if (!type.IsEmpty()) { if (ModuleScriptsEnabled() && type.LowerCaseEqualsASCII("module")) { - scriptKind = nsScriptKind::Module; + scriptKind = ScriptKind::Module; } else { NS_ENSURE_TRUE(ParseTypeAttribute(type, &version), false); } @@ -1498,7 +1243,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) // "The nomodule attribute must not be specified on module scripts (and will // be ignored if it is)." if (ModuleScriptsEnabled() && - scriptKind == nsScriptKind::Classic && + scriptKind == ScriptKind::Classic && scriptContent->IsHTMLElement() && scriptContent->HasAttr(kNameSpaceID_None, nsGkAtoms::nomodule)) { return false; @@ -1506,7 +1251,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) // Step 15. and later in the HTML5 spec nsresult rv = NS_OK; - RefPtr<nsScriptLoadRequest> request; + RefPtr<ScriptLoadRequest> request; if (aElement->GetScriptExternal()) { // external script nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI(); @@ -1562,7 +1307,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) integrity); if (!integrity.IsEmpty()) { MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug, - ("nsScriptLoader::ProcessScriptElement, integrity=%s", + ("ScriptLoader::ProcessScriptElement, integrity=%s", NS_ConvertUTF16toUTF8(integrity).get())); nsAutoCString sourceUri; if (mDocument->GetDocumentURI()) { @@ -1704,19 +1449,25 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) request->mLineNo = aElement->GetScriptLineNumber(); if (request->IsModuleRequest()) { - nsModuleLoadRequest* modReq = request->AsModuleRequest(); + ModuleLoadRequest* modReq = request->AsModuleRequest(); modReq->mBaseURL = mDocument->GetDocBaseURI(); rv = CreateModuleScript(modReq); - NS_ENSURE_SUCCESS(rv, false); - StartFetchingModuleDependencies(modReq); + MOZ_ASSERT(NS_FAILED(rv) == !modReq->mModuleScript); + if (NS_FAILED(rv)) { + modReq->LoadFailed(); + return false; + } if (aElement->GetScriptAsync()) { mLoadingAsyncRequests.AppendElement(request); } else { AddDeferRequest(request); } + if (!modReq->mModuleScript->IsErrored()) { + StartFetchingModuleDependencies(modReq); + } return false; } - request->mProgress = nsScriptLoadRequest::Progress::Ready; + request->mProgress = ScriptLoadRequest::Progress::Ready; if (aElement->GetParserCreated() == FROM_PARSER_XSLT && (!ReadyToExecuteParserBlockingScripts() || !mXSLTRequests.isEmpty())) { // Need to maintain order for XSLT-inserted scripts @@ -1728,7 +1479,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) if (aElement->GetParserCreated() == NOT_FROM_PARSER) { NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), "A script-inserted script is inserted without an update batch?"); - nsContentUtils::AddScriptRunner(new nsScriptRequestProcessor(this, + nsContentUtils::AddScriptRunner(new ScriptRequestProcessor(this, request)); return false; } @@ -1758,13 +1509,13 @@ namespace { class NotifyOffThreadScriptLoadCompletedRunnable : public Runnable { - RefPtr<nsScriptLoadRequest> mRequest; - RefPtr<nsScriptLoader> mLoader; + RefPtr<ScriptLoadRequest> mRequest; + RefPtr<ScriptLoader> mLoader; void *mToken; public: - NotifyOffThreadScriptLoadCompletedRunnable(nsScriptLoadRequest* aRequest, - nsScriptLoader* aLoader) + NotifyOffThreadScriptLoadCompletedRunnable(ScriptLoadRequest* aRequest, + ScriptLoader* aLoader) : mRequest(aRequest), mLoader(aLoader), mToken(nullptr) {} @@ -1781,21 +1532,17 @@ public: } /* anonymous namespace */ nsresult -nsScriptLoader::ProcessOffThreadRequest(nsScriptLoadRequest* aRequest) +ScriptLoader::ProcessOffThreadRequest(ScriptLoadRequest* aRequest) { - MOZ_ASSERT(aRequest->mProgress == nsScriptLoadRequest::Progress::Compiling); + MOZ_ASSERT(aRequest->mProgress == ScriptLoadRequest::Progress::Compiling); MOZ_ASSERT(!aRequest->mWasCompiledOMT); aRequest->mWasCompiledOMT = true; if (aRequest->IsModuleRequest()) { MOZ_ASSERT(aRequest->mOffThreadToken); - nsModuleLoadRequest* request = aRequest->AsModuleRequest(); - nsresult rv = ProcessFetchedModuleSource(request); - if (NS_FAILED(rv)) { - request->LoadFailed(); - } - return rv; + ModuleLoadRequest* request = aRequest->AsModuleRequest(); + return ProcessFetchedModuleSource(request); } aRequest->SetReady(); @@ -1837,8 +1584,8 @@ NotifyOffThreadScriptLoadCompletedRunnable::Run() // We want these to be dropped on the main thread, once we return from this // function. - RefPtr<nsScriptLoadRequest> request = mRequest.forget(); - RefPtr<nsScriptLoader> loader = mLoader.forget(); + RefPtr<ScriptLoadRequest> request = mRequest.forget(); + RefPtr<ScriptLoader> loader = mLoader.forget(); request->mOffThreadToken = mToken; nsresult rv = loader->ProcessOffThreadRequest(request); @@ -1856,7 +1603,7 @@ OffThreadScriptLoaderCallback(void *aToken, void *aCallbackData) } nsresult -nsScriptLoader::AttemptAsyncScriptCompile(nsScriptLoadRequest* aRequest) +ScriptLoader::AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest) { MOZ_ASSERT_IF(!aRequest->IsModuleRequest(), aRequest->IsReadyToRun()); MOZ_ASSERT(!aRequest->mWasCompiledOMT); @@ -1909,14 +1656,14 @@ nsScriptLoader::AttemptAsyncScriptCompile(nsScriptLoadRequest* aRequest) } mDocument->BlockOnload(); - aRequest->mProgress = nsScriptLoadRequest::Progress::Compiling; + aRequest->mProgress = ScriptLoadRequest::Progress::Compiling; Unused << runnable.forget(); return NS_OK; } nsresult -nsScriptLoader::CompileOffThreadOrProcessRequest(nsScriptLoadRequest* aRequest) +ScriptLoader::CompileOffThreadOrProcessRequest(ScriptLoadRequest* aRequest) { NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "Processing requests when running scripts is unsafe."); @@ -1934,7 +1681,7 @@ nsScriptLoader::CompileOffThreadOrProcessRequest(nsScriptLoadRequest* aRequest) } SourceBufferHolder -nsScriptLoader::GetScriptSource(nsScriptLoadRequest* aRequest, nsAutoString& inlineData) +ScriptLoader::GetScriptSource(ScriptLoadRequest* aRequest, nsAutoString& inlineData) { // Return a SourceBufferHolder object holding the script's source text. // |inlineData| is used to hold the text for inline objects. @@ -1955,7 +1702,7 @@ nsScriptLoader::GetScriptSource(nsScriptLoadRequest* aRequest, nsAutoString& inl } nsresult -nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest) +ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest) { NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "Processing requests when running scripts is unsafe."); @@ -1967,7 +1714,7 @@ nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest) if (aRequest->IsModuleRequest() && !aRequest->AsModuleRequest()->mModuleScript) { - // There was an error parsing a module script. Nothing to do here. + // There was an error fetching a module script. Nothing to do here. FireScriptAvailable(NS_ERROR_FAILURE, aRequest); return NS_OK; } @@ -2055,8 +1802,8 @@ nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest) } void -nsScriptLoader::FireScriptAvailable(nsresult aResult, - nsScriptLoadRequest* aRequest) +ScriptLoader::FireScriptAvailable(nsresult aResult, + ScriptLoadRequest* aRequest) { for (int32_t i = 0; i < mObservers.Count(); i++) { nsCOMPtr<nsIScriptLoaderObserver> obs = mObservers[i]; @@ -2069,8 +1816,8 @@ nsScriptLoader::FireScriptAvailable(nsresult aResult, } void -nsScriptLoader::FireScriptEvaluated(nsresult aResult, - nsScriptLoadRequest* aRequest) +ScriptLoader::FireScriptEvaluated(nsresult aResult, + ScriptLoadRequest* aRequest) { for (int32_t i = 0; i < mObservers.Count(); i++) { nsCOMPtr<nsIScriptLoaderObserver> obs = mObservers[i]; @@ -2082,7 +1829,7 @@ nsScriptLoader::FireScriptEvaluated(nsresult aResult, } already_AddRefed<nsIScriptGlobalObject> -nsScriptLoader::GetScriptGlobalObject() +ScriptLoader::GetScriptGlobalObject() { nsCOMPtr<nsIDocument> master = mDocument->MasterDocument(); nsPIDOMWindowInner *pwin = master->GetInnerWindow(); @@ -2103,10 +1850,10 @@ nsScriptLoader::GetScriptGlobalObject() } nsresult -nsScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi, - nsScriptLoadRequest* aRequest, - JS::Handle<JSObject*> aScopeChain, - JS::CompileOptions* aOptions) +ScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi, + ScriptLoadRequest* aRequest, + JS::Handle<JSObject*> aScopeChain, + JS::CompileOptions* aOptions) { // It's very important to use aRequest->mURI, not the final URI of the channel // aRequest ended up getting script data from, as the script filename. @@ -2150,7 +1897,7 @@ nsScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi, } nsresult -nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest) +ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) { // We need a document to evaluate scripts. if (!mDocument) { @@ -2189,8 +1936,8 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest) // http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block nsAutoMicroTask mt; AutoEntryScript aes(globalObject, "<script> element", true); - JS::Rooted<JSObject*> global(aes.cx(), - globalObject->GetGlobalJSObject()); + JSContext* cx = aes.cx(); + JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject()); bool oldProcessingScriptTag = context->GetProcessingScriptTag(); context->SetProcessingScriptTag(true); @@ -2211,28 +1958,38 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest) } if (aRequest->IsModuleRequest()) { - nsModuleLoadRequest* request = aRequest->AsModuleRequest(); + rv = EnsureModuleResolveHook(cx); + NS_ENSURE_SUCCESS(rv, rv); + + ModuleLoadRequest* request = aRequest->AsModuleRequest(); MOZ_ASSERT(request->mModuleScript); MOZ_ASSERT(!request->mOffThreadToken); - nsModuleScript* ms = request->mModuleScript; - MOZ_ASSERT(!ms->IsUninstantiated()); - if (ms->InstantiationFailed()) { - JS::Rooted<JS::Value> exception(aes.cx(), ms->Exception()); - JS_SetPendingException(aes.cx(), exception); - rv = NS_ERROR_FAILURE; - } else { - JS::Rooted<JSObject*> module(aes.cx(), ms->ModuleRecord()); - MOZ_ASSERT(module); - rv = nsJSUtils::ModuleEvaluation(aes.cx(), module); + + ModuleScript* moduleScript = request->mModuleScript; + if (moduleScript->IsErrored()) { + // Module has an error status + JS::Rooted<JS::Value> error(cx, moduleScript->Error()); + JS_SetPendingException(cx, error); + return NS_OK; // An error is reported by AutoEntryScript. + } + + JS::Rooted<JSObject*> module(cx, moduleScript->ModuleRecord()); + MOZ_ASSERT(module); + + rv = nsJSUtils::ModuleEvaluate(cx, module); + MOZ_ASSERT(NS_FAILED(rv) == aes.HasException()); + if (NS_FAILED(rv)) { + // Evaluation failed + rv = NS_OK; // An error is reported by AutoEntryScript. } } else { - JS::CompileOptions options(aes.cx()); + JS::CompileOptions options(cx); rv = FillCompileOptionsForRequest(aes, aRequest, global, &options); if (NS_SUCCEEDED(rv)) { nsAutoString inlineData; SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData); - rv = nsJSUtils::EvaluateString(aes.cx(), srcBuf, global, options, + rv = nsJSUtils::EvaluateString(cx, srcBuf, global, options, aRequest->OffThreadTokenPtr()); } } @@ -2243,7 +2000,7 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest) } void -nsScriptLoader::ProcessPendingRequestsAsync() +ScriptLoader::ProcessPendingRequestsAsync() { if (mParserBlockingRequest || !mXSLTRequests.isEmpty() || @@ -2252,14 +2009,14 @@ nsScriptLoader::ProcessPendingRequestsAsync() !mDeferRequests.isEmpty() || !mPendingChildLoaders.IsEmpty()) { NS_DispatchToCurrentThread(NewRunnableMethod(this, - &nsScriptLoader::ProcessPendingRequests)); + &ScriptLoader::ProcessPendingRequests)); } } void -nsScriptLoader::ProcessPendingRequests() +ScriptLoader::ProcessPendingRequests() { - RefPtr<nsScriptLoadRequest> request; + RefPtr<ScriptLoadRequest> request; if (mParserBlockingRequest && mParserBlockingRequest->IsReadyToRun() && @@ -2311,7 +2068,7 @@ nsScriptLoader::ProcessPendingRequests() while (!mPendingChildLoaders.IsEmpty() && ReadyToExecuteParserBlockingScripts()) { - RefPtr<nsScriptLoader> child = mPendingChildLoaders[0]; + RefPtr<ScriptLoader> child = mPendingChildLoaders[0]; mPendingChildLoaders.RemoveElementAt(0); child->RemoveParserBlockingScriptExecutionBlocker(); } @@ -2337,7 +2094,7 @@ nsScriptLoader::ProcessPendingRequests() } bool -nsScriptLoader::ReadyToExecuteParserBlockingScripts() +ScriptLoader::ReadyToExecuteParserBlockingScripts() { // Make sure the SelfReadyToExecuteParserBlockingScripts check is first, so // that we don't block twice on an ancestor. @@ -2346,7 +2103,7 @@ nsScriptLoader::ReadyToExecuteParserBlockingScripts() } for (nsIDocument* doc = mDocument; doc; doc = doc->GetParentDocument()) { - nsScriptLoader* ancestor = doc->ScriptLoader(); + ScriptLoader* ancestor = doc->ScriptLoader(); if (!ancestor->SelfReadyToExecuteParserBlockingScripts() && ancestor->AddPendingChildLoader(this)) { AddParserBlockingScriptExecutionBlocker(); @@ -2394,10 +2151,10 @@ nsScriptLoader::ReadyToExecuteParserBlockingScripts() } /* static */ nsresult -nsScriptLoader::ConvertToUTF16(nsIChannel* aChannel, const uint8_t* aData, - uint32_t aLength, const nsAString& aHintCharset, - nsIDocument* aDocument, - char16_t*& aBufOut, size_t& aLengthOut) +ScriptLoader::ConvertToUTF16(nsIChannel* aChannel, const uint8_t* aData, + uint32_t aLength, const nsAString& aHintCharset, + nsIDocument* aDocument, + char16_t*& aBufOut, size_t& aLengthOut) { if (!aLength) { aBufOut = nullptr; @@ -2474,14 +2231,14 @@ nsScriptLoader::ConvertToUTF16(nsIChannel* aChannel, const uint8_t* aData, } nsresult -nsScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader, - nsISupports* aContext, - nsresult aChannelStatus, - nsresult aSRIStatus, - mozilla::Vector<char16_t> &aString, - mozilla::dom::SRICheckDataVerifier* aSRIDataVerifier) -{ - nsScriptLoadRequest* request = static_cast<nsScriptLoadRequest*>(aContext); +ScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader, + nsISupports* aContext, + nsresult aChannelStatus, + nsresult aSRIStatus, + mozilla::Vector<char16_t> &aString, + mozilla::dom::SRICheckDataVerifier* aSRIDataVerifier) +{ + ScriptLoadRequest* request = static_cast<ScriptLoadRequest*>(aContext); NS_ASSERTION(request, "null request in stream complete handler"); NS_ENSURE_TRUE(request, NS_ERROR_FAILURE); @@ -2511,7 +2268,7 @@ nsScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader, if (loadInfo->GetEnforceSRI()) { MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug, - ("nsScriptLoader::OnStreamComplete, required SRI not found")); + ("ScriptLoader::OnStreamComplete, required SRI not found")); nsCOMPtr<nsIContentSecurityPolicy> csp; loadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(csp)); nsAutoCString violationURISpec; @@ -2544,29 +2301,29 @@ nsScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader, MOZ_ASSERT_IF(request->IsModuleRequest(), request->AsModuleRequest()->IsTopLevel()); if (request->isInList()) { - RefPtr<nsScriptLoadRequest> req = mDeferRequests.Steal(request); + RefPtr<ScriptLoadRequest> req = mDeferRequests.Steal(request); FireScriptAvailable(rv, req); } } else if (request->mIsAsync) { MOZ_ASSERT_IF(request->IsModuleRequest(), request->AsModuleRequest()->IsTopLevel()); if (request->isInList()) { - RefPtr<nsScriptLoadRequest> req = mLoadingAsyncRequests.Steal(request); + RefPtr<ScriptLoadRequest> req = mLoadingAsyncRequests.Steal(request); FireScriptAvailable(rv, req); } } else if (request->mIsNonAsyncScriptInserted) { if (request->isInList()) { - RefPtr<nsScriptLoadRequest> req = + RefPtr<ScriptLoadRequest> req = mNonAsyncExternalScriptInsertedRequests.Steal(request); FireScriptAvailable(rv, req); } } else if (request->mIsXSLT) { if (request->isInList()) { - RefPtr<nsScriptLoadRequest> req = mXSLTRequests.Steal(request); + RefPtr<ScriptLoadRequest> req = mXSLTRequests.Steal(request); FireScriptAvailable(rv, req); } } else if (request->IsModuleRequest()) { - nsModuleLoadRequest* modReq = request->AsModuleRequest(); + ModuleLoadRequest* modReq = request->AsModuleRequest(); MOZ_ASSERT(!modReq->IsTopLevel()); MOZ_ASSERT(!modReq->isInList()); modReq->Cancel(); @@ -2597,19 +2354,19 @@ nsScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader, } void -nsScriptLoader::UnblockParser(nsScriptLoadRequest* aParserBlockingRequest) +ScriptLoader::UnblockParser(ScriptLoadRequest* aParserBlockingRequest) { aParserBlockingRequest->mElement->UnblockParser(); } void -nsScriptLoader::ContinueParserAsync(nsScriptLoadRequest* aParserBlockingRequest) +ScriptLoader::ContinueParserAsync(ScriptLoadRequest* aParserBlockingRequest) { aParserBlockingRequest->mElement->ContinueParserAsync(); } uint32_t -nsScriptLoader::NumberOfProcessors() +ScriptLoader::NumberOfProcessors() { if (mNumberOfProcessors > 0) return mNumberOfProcessors; @@ -2621,7 +2378,7 @@ nsScriptLoader::NumberOfProcessors() } void -nsScriptLoader::MaybeMoveToLoadedList(nsScriptLoadRequest* aRequest) +ScriptLoader::MaybeMoveToLoadedList(ScriptLoadRequest* aRequest) { MOZ_ASSERT(aRequest->IsReadyToRun()); @@ -2631,17 +2388,17 @@ nsScriptLoader::MaybeMoveToLoadedList(nsScriptLoadRequest* aRequest) if (aRequest->mIsAsync) { MOZ_ASSERT(aRequest->isInList()); if (aRequest->isInList()) { - RefPtr<nsScriptLoadRequest> req = mLoadingAsyncRequests.Steal(aRequest); + RefPtr<ScriptLoadRequest> req = mLoadingAsyncRequests.Steal(aRequest); mLoadedAsyncRequests.AppendElement(req); } } } nsresult -nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest, - nsIIncrementalStreamLoader* aLoader, - nsresult aStatus, - mozilla::Vector<char16_t> &aString) +ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest, + nsIIncrementalStreamLoader* aLoader, + nsresult aStatus, + mozilla::Vector<char16_t> &aString) { if (NS_FAILED(aStatus)) { return aStatus; @@ -2713,7 +2470,7 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest, "aRequest should be pending!"); if (aRequest->IsModuleRequest()) { - nsModuleLoadRequest* request = aRequest->AsModuleRequest(); + ModuleLoadRequest* request = aRequest->AsModuleRequest(); // When loading a module, only responses with a JavaScript MIME type are // acceptable. @@ -2744,7 +2501,7 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest, MOZ_ASSERT(!aRequest->IsModuleRequest()); nsresult rv = AttemptAsyncScriptCompile(aRequest); if (rv == NS_OK) { - MOZ_ASSERT(aRequest->mProgress == nsScriptLoadRequest::Progress::Compiling, + MOZ_ASSERT(aRequest->mProgress == ScriptLoadRequest::Progress::Compiling, "Request should be off-thread compiling now."); return NS_OK; } @@ -2763,7 +2520,7 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest, } void -nsScriptLoader::ParsingComplete(bool aTerminated) +ScriptLoader::ParsingComplete(bool aTerminated) { if (mDeferEnabled) { // Have to check because we apparently get ParsingComplete @@ -2789,12 +2546,12 @@ nsScriptLoader::ParsingComplete(bool aTerminated) } void -nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset, - const nsAString &aType, - const nsAString &aCrossOrigin, - const nsAString& aIntegrity, - bool aScriptFromHead, - const mozilla::net::ReferrerPolicy aReferrerPolicy) +ScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset, + const nsAString &aType, + const nsAString &aCrossOrigin, + const nsAString& aIntegrity, + bool aScriptFromHead, + const mozilla::net::ReferrerPolicy aReferrerPolicy) { NS_ENSURE_TRUE_VOID(mDocument); // Check to see if scripts has been turned off. @@ -2810,7 +2567,7 @@ nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset, SRIMetadata sriMetadata; if (!aIntegrity.IsEmpty()) { MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug, - ("nsScriptLoader::PreloadURI, integrity=%s", + ("ScriptLoader::PreloadURI, integrity=%s", NS_ConvertUTF16toUTF8(aIntegrity).get())); nsAutoCString sourceUri; if (mDocument->GetDocumentURI()) { @@ -2819,8 +2576,8 @@ nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset, SRICheck::IntegrityMetadata(aIntegrity, sourceUri, mReporter, &sriMetadata); } - RefPtr<nsScriptLoadRequest> request = - CreateLoadRequest(nsScriptKind::Classic, nullptr, 0, + RefPtr<ScriptLoadRequest> request = + CreateLoadRequest(ScriptKind::Classic, nullptr, 0, Element::StringToCORSMode(aCrossOrigin), sriMetadata); request->mURI = aURI; request->mIsInline = false; @@ -2837,7 +2594,7 @@ nsScriptLoader::PreloadURI(nsIURI *aURI, const nsAString &aCharset, } void -nsScriptLoader::AddDeferRequest(nsScriptLoadRequest* aRequest) +ScriptLoader::AddDeferRequest(ScriptLoadRequest* aRequest) { aRequest->mIsDefer = true; mDeferRequests.AppendElement(aRequest); @@ -2850,7 +2607,7 @@ nsScriptLoader::AddDeferRequest(nsScriptLoadRequest* aRequest) } bool -nsScriptLoader::MaybeRemovedDeferRequests() +ScriptLoader::MaybeRemovedDeferRequests() { if (mDeferRequests.isEmpty() && mDocument && mBlockingDOMContentLoaded) { @@ -2861,201 +2618,5 @@ nsScriptLoader::MaybeRemovedDeferRequests() return false; } -////////////////////////////////////////////////////////////// -// nsScriptLoadHandler -////////////////////////////////////////////////////////////// - -nsScriptLoadHandler::nsScriptLoadHandler(nsScriptLoader *aScriptLoader, - nsScriptLoadRequest *aRequest, - mozilla::dom::SRICheckDataVerifier *aSRIDataVerifier) - : mScriptLoader(aScriptLoader), - mRequest(aRequest), - mSRIDataVerifier(aSRIDataVerifier), - mSRIStatus(NS_OK), - mDecoder(), - mBuffer() -{} - -nsScriptLoadHandler::~nsScriptLoadHandler() -{} - -NS_IMPL_ISUPPORTS(nsScriptLoadHandler, nsIIncrementalStreamLoaderObserver) - -NS_IMETHODIMP -nsScriptLoadHandler::OnIncrementalData(nsIIncrementalStreamLoader* aLoader, - nsISupports* aContext, - uint32_t aDataLength, - const uint8_t* aData, - uint32_t *aConsumedLength) -{ - if (mRequest->IsCanceled()) { - // If request cancelled, ignore any incoming data. - *aConsumedLength = aDataLength; - return NS_OK; - } - - if (!EnsureDecoder(aLoader, aData, aDataLength, - /* aEndOfStream = */ false)) { - return NS_OK; - } - - // Below we will/shall consume entire data chunk. - *aConsumedLength = aDataLength; - - // Decoder has already been initialized. -- trying to decode all loaded bytes. - nsresult rv = TryDecodeRawData(aData, aDataLength, - /* aEndOfStream = */ false); - NS_ENSURE_SUCCESS(rv, rv); - - // If SRI is required for this load, appending new bytes to the hash. - if (mSRIDataVerifier && NS_SUCCEEDED(mSRIStatus)) { - mSRIStatus = mSRIDataVerifier->Update(aDataLength, aData); - } - - return rv; -} - -nsresult -nsScriptLoadHandler::TryDecodeRawData(const uint8_t* aData, - uint32_t aDataLength, - bool aEndOfStream) -{ - int32_t srcLen = aDataLength; - const char* src = reinterpret_cast<const char *>(aData); - int32_t dstLen; - nsresult rv = - mDecoder->GetMaxLength(src, srcLen, &dstLen); - - NS_ENSURE_SUCCESS(rv, rv); - - uint32_t haveRead = mBuffer.length(); - - CheckedInt<uint32_t> capacity = haveRead; - capacity += dstLen; - - if (!capacity.isValid() || !mBuffer.reserve(capacity.value())) { - return NS_ERROR_OUT_OF_MEMORY; - } - - rv = mDecoder->Convert(src, - &srcLen, - mBuffer.begin() + haveRead, - &dstLen); - - NS_ENSURE_SUCCESS(rv, rv); - - haveRead += dstLen; - MOZ_ASSERT(haveRead <= capacity.value(), "mDecoder produced more data than expected"); - MOZ_ALWAYS_TRUE(mBuffer.resizeUninitialized(haveRead)); - - return NS_OK; -} - -bool -nsScriptLoadHandler::EnsureDecoder(nsIIncrementalStreamLoader *aLoader, - const uint8_t* aData, - uint32_t aDataLength, - bool aEndOfStream) -{ - // Check if decoder has already been created. - if (mDecoder) { - return true; - } - - nsAutoCString charset; - - // JavaScript modules are always UTF-8. - if (mRequest->IsModuleRequest()) { - charset = "UTF-8"; - mDecoder = EncodingUtils::DecoderForEncoding(charset); - return true; - } - - // Determine if BOM check should be done. This occurs either - // if end-of-stream has been reached, or at least 3 bytes have - // been read from input. - if (!aEndOfStream && (aDataLength < 3)) { - return false; - } - - // Do BOM detection. - if (nsContentUtils::CheckForBOM(aData, aDataLength, charset)) { - mDecoder = EncodingUtils::DecoderForEncoding(charset); - return true; - } - - // BOM detection failed, check content stream for charset. - nsCOMPtr<nsIRequest> req; - nsresult rv = aLoader->GetRequest(getter_AddRefs(req)); - NS_ASSERTION(req, "StreamLoader's request went away prematurely"); - NS_ENSURE_SUCCESS(rv, false); - - nsCOMPtr<nsIChannel> channel = do_QueryInterface(req); - - if (channel && - NS_SUCCEEDED(channel->GetContentCharset(charset)) && - EncodingUtils::FindEncodingForLabel(charset, charset)) { - mDecoder = EncodingUtils::DecoderForEncoding(charset); - return true; - } - - // Check the hint charset from the script element or preload - // request. - nsAutoString hintCharset; - if (!mRequest->IsPreload()) { - mRequest->mElement->GetScriptCharset(hintCharset); - } else { - nsTArray<nsScriptLoader::PreloadInfo>::index_type i = - mScriptLoader->mPreloads.IndexOf(mRequest, 0, - nsScriptLoader::PreloadRequestComparator()); - - NS_ASSERTION(i != mScriptLoader->mPreloads.NoIndex, - "Incorrect preload bookkeeping"); - hintCharset = mScriptLoader->mPreloads[i].mCharset; - } - - if (EncodingUtils::FindEncodingForLabel(hintCharset, charset)) { - mDecoder = EncodingUtils::DecoderForEncoding(charset); - return true; - } - - // Get the charset from the charset of the document. - if (mScriptLoader->mDocument) { - charset = mScriptLoader->mDocument->GetDocumentCharacterSet(); - mDecoder = EncodingUtils::DecoderForEncoding(charset); - return true; - } - - // Curiously, there are various callers that don't pass aDocument. The - // fallback in the old code was ISO-8859-1, which behaved like - // windows-1252. Saying windows-1252 for clarity and for compliance - // with the Encoding Standard. - charset = "windows-1252"; - mDecoder = EncodingUtils::DecoderForEncoding(charset); - return true; -} - -NS_IMETHODIMP -nsScriptLoadHandler::OnStreamComplete(nsIIncrementalStreamLoader* aLoader, - nsISupports* aContext, - nsresult aStatus, - uint32_t aDataLength, - const uint8_t* aData) -{ - if (!mRequest->IsCanceled()) { - DebugOnly<bool> encoderSet = - EnsureDecoder(aLoader, aData, aDataLength, /* aEndOfStream = */ true); - MOZ_ASSERT(encoderSet); - DebugOnly<nsresult> rv = TryDecodeRawData(aData, aDataLength, - /* aEndOfStream = */ true); - - // If SRI is required for this load, appending new bytes to the hash. - if (mSRIDataVerifier && NS_SUCCEEDED(mSRIStatus)) { - mSRIStatus = mSRIDataVerifier->Update(aDataLength, aData); - } - } - - // we have to mediate and use mRequest. - return mScriptLoader->OnStreamComplete(aLoader, mRequest, aStatus, mSRIStatus, - mBuffer, mSRIDataVerifier); -} +} // dom namespace +} // mozilla namespace diff --git a/dom/base/nsScriptLoader.h b/dom/script/ScriptLoader.h index a00239be5f..e6b75bf3bb 100644 --- a/dom/base/nsScriptLoader.h +++ b/dom/script/ScriptLoader.h @@ -4,12 +4,8 @@ * 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/. */ -/* - * A class that handles loading and evaluation of <script> elements. - */ - -#ifndef __nsScriptLoader_h__ -#define __nsScriptLoader_h__ +#ifndef mozilla_dom_ScriptLoader_h +#define mozilla_dom_ScriptLoader_h #include "nsCOMPtr.h" #include "nsRefPtrHashtable.h" @@ -25,14 +21,10 @@ #include "mozilla/CORSMode.h" #include "mozilla/dom/SRIMetadata.h" #include "mozilla/dom/SRICheck.h" -#include "mozilla/LinkedList.h" #include "mozilla/MozPromise.h" #include "mozilla/net/ReferrerPolicy.h" #include "mozilla/Vector.h" -class nsModuleLoadRequest; -class nsModuleScript; -class nsScriptLoadRequestList; class nsIURI; namespace JS { @@ -41,37 +33,39 @@ namespace JS { namespace mozilla { namespace dom { + class AutoJSAPI; -} // namespace dom -} // namespace mozilla +class ModuleLoadRequest; +class ModuleScript; +class ScriptLoadRequestList; ////////////////////////////////////////////////////////////// // Per-request data structure ////////////////////////////////////////////////////////////// -enum class nsScriptKind { +enum class ScriptKind { Classic, Module }; -class nsScriptLoadRequest : public nsISupports, - private mozilla::LinkedListElement<nsScriptLoadRequest> +class ScriptLoadRequest : public nsISupports, + private mozilla::LinkedListElement<ScriptLoadRequest> { - typedef LinkedListElement<nsScriptLoadRequest> super; + typedef LinkedListElement<ScriptLoadRequest> super; - // Allow LinkedListElement<nsScriptLoadRequest> to cast us to itself as needed. - friend class mozilla::LinkedListElement<nsScriptLoadRequest>; - friend class nsScriptLoadRequestList; + // Allow LinkedListElement<ScriptLoadRequest> to cast us to itself as needed. + friend class mozilla::LinkedListElement<ScriptLoadRequest>; + friend class ScriptLoadRequestList; protected: - virtual ~nsScriptLoadRequest(); + virtual ~ScriptLoadRequest(); public: - nsScriptLoadRequest(nsScriptKind aKind, - nsIScriptElement* aElement, - uint32_t aVersion, - mozilla::CORSMode aCORSMode, - const mozilla::dom::SRIMetadata &aIntegrity) + ScriptLoadRequest(ScriptKind aKind, + nsIScriptElement* aElement, + uint32_t aVersion, + mozilla::CORSMode aCORSMode, + const mozilla::dom::SRIMetadata &aIntegrity) : mKind(aKind), mElement(aElement), mProgress(Progress::Loading), @@ -95,14 +89,14 @@ public: } NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_CLASS(nsScriptLoadRequest) + NS_DECL_CYCLE_COLLECTION_CLASS(ScriptLoadRequest) bool IsModuleRequest() const { - return mKind == nsScriptKind::Module; + return mKind == ScriptKind::Module; } - nsModuleLoadRequest* AsModuleRequest(); + ModuleLoadRequest* AsModuleRequest(); void FireScriptAvailable(nsresult aResult) { @@ -154,7 +148,7 @@ public: using super::getNext; using super::isInList; - const nsScriptKind mKind; + const ScriptKind mKind; nsCOMPtr<nsIScriptElement> mElement; Progress mProgress; // Are we still waiting for a load to complete? bool mIsInline; // Is the script inline or loaded? @@ -179,23 +173,23 @@ public: mozilla::net::ReferrerPolicy mReferrerPolicy; }; -class nsScriptLoadRequestList : private mozilla::LinkedList<nsScriptLoadRequest> +class ScriptLoadRequestList : private mozilla::LinkedList<ScriptLoadRequest> { - typedef mozilla::LinkedList<nsScriptLoadRequest> super; + typedef mozilla::LinkedList<ScriptLoadRequest> super; public: - ~nsScriptLoadRequestList(); + ~ScriptLoadRequestList(); void Clear(); #ifdef DEBUG - bool Contains(nsScriptLoadRequest* aElem) const; + bool Contains(ScriptLoadRequest* aElem) const; #endif // DEBUG using super::getFirst; using super::isEmpty; - void AppendElement(nsScriptLoadRequest* aElem) + void AppendElement(ScriptLoadRequest* aElem) { MOZ_ASSERT(!aElem->isInList()); NS_ADDREF(aElem); @@ -203,36 +197,37 @@ public: } MOZ_MUST_USE - already_AddRefed<nsScriptLoadRequest> Steal(nsScriptLoadRequest* aElem) + already_AddRefed<ScriptLoadRequest> Steal(ScriptLoadRequest* aElem) { aElem->removeFrom(*this); return dont_AddRef(aElem); } MOZ_MUST_USE - already_AddRefed<nsScriptLoadRequest> StealFirst() + already_AddRefed<ScriptLoadRequest> StealFirst() { MOZ_ASSERT(!isEmpty()); return Steal(getFirst()); } - void Remove(nsScriptLoadRequest* aElem) + void Remove(ScriptLoadRequest* aElem) { aElem->removeFrom(*this); NS_RELEASE(aElem); } }; +class ScriptLoadHandler; ////////////////////////////////////////////////////////////// // Script loader implementation ////////////////////////////////////////////////////////////// -class nsScriptLoader final : public nsISupports +class ScriptLoader final : public nsISupports { class MOZ_STACK_CLASS AutoCurrentScriptUpdater { public: - AutoCurrentScriptUpdater(nsScriptLoader* aScriptLoader, + AutoCurrentScriptUpdater(ScriptLoader* aScriptLoader, nsIScriptElement* aCurrentScript) : mOldScript(aScriptLoader->mCurrentScript) , mScriptLoader(aScriptLoader) @@ -245,19 +240,19 @@ class nsScriptLoader final : public nsISupports } private: nsCOMPtr<nsIScriptElement> mOldScript; - nsScriptLoader* mScriptLoader; + ScriptLoader* mScriptLoader; }; - friend class nsModuleLoadRequest; - friend class nsScriptRequestProcessor; - friend class nsScriptLoadHandler; + friend class ModuleLoadRequest; + friend class ScriptRequestProcessor; + friend class ScriptLoadHandler; friend class AutoCurrentScriptUpdater; public: - explicit nsScriptLoader(nsIDocument* aDocument); + explicit ScriptLoader(nsIDocument* aDocument); NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_CLASS(nsScriptLoader) + NS_DECL_CYCLE_COLLECTION_CLASS(ScriptLoader) /** * The loader maintains a weak reference to the document with @@ -395,7 +390,7 @@ public: /** * Handle the completion of a stream. This is called by the - * nsScriptLoadHandler object which observes the IncrementalStreamLoader + * ScriptLoadHandler object which observes the IncrementalStreamLoader * loading the script. */ nsresult OnStreamComplete(nsIIncrementalStreamLoader* aLoader, @@ -463,17 +458,17 @@ public: * Process a request that was deferred so that the script could be compiled * off thread. */ - nsresult ProcessOffThreadRequest(nsScriptLoadRequest *aRequest); + nsresult ProcessOffThreadRequest(ScriptLoadRequest *aRequest); - bool AddPendingChildLoader(nsScriptLoader* aChild) { + bool AddPendingChildLoader(ScriptLoader* aChild) { return mPendingChildLoaders.AppendElement(aChild) != nullptr; } private: - virtual ~nsScriptLoader(); + virtual ~ScriptLoader(); - nsScriptLoadRequest* CreateLoadRequest( - nsScriptKind aKind, + ScriptLoadRequest* CreateLoadRequest( + ScriptKind aKind, nsIScriptElement* aElement, uint32_t aVersion, mozilla::CORSMode aCORSMode, @@ -482,12 +477,12 @@ private: /** * Unblocks the creator parser of the parser-blocking scripts. */ - void UnblockParser(nsScriptLoadRequest* aParserBlockingRequest); + void UnblockParser(ScriptLoadRequest* aParserBlockingRequest); /** * Asynchronously resumes the creator parser of the parser-blocking scripts. */ - void ContinueParserAsync(nsScriptLoadRequest* aParserBlockingRequest); + void ContinueParserAsync(ScriptLoadRequest* aParserBlockingRequest); /** @@ -502,7 +497,7 @@ private: /** * Start a load for aRequest's URI. */ - nsresult StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType, + nsresult StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType, bool aScriptFromHead); /** @@ -539,83 +534,84 @@ private: return mEnabled && !mBlockerCount; } - nsresult AttemptAsyncScriptCompile(nsScriptLoadRequest* aRequest); - nsresult ProcessRequest(nsScriptLoadRequest* aRequest); - nsresult CompileOffThreadOrProcessRequest(nsScriptLoadRequest* aRequest); + nsresult AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest); + nsresult ProcessRequest(ScriptLoadRequest* aRequest); + nsresult CompileOffThreadOrProcessRequest(ScriptLoadRequest* aRequest); void FireScriptAvailable(nsresult aResult, - nsScriptLoadRequest* aRequest); + ScriptLoadRequest* aRequest); void FireScriptEvaluated(nsresult aResult, - nsScriptLoadRequest* aRequest); - nsresult EvaluateScript(nsScriptLoadRequest* aRequest); + ScriptLoadRequest* aRequest); + nsresult EvaluateScript(ScriptLoadRequest* aRequest); already_AddRefed<nsIScriptGlobalObject> GetScriptGlobalObject(); nsresult FillCompileOptionsForRequest(const mozilla::dom::AutoJSAPI& jsapi, - nsScriptLoadRequest* aRequest, + ScriptLoadRequest* aRequest, JS::Handle<JSObject*> aScopeChain, JS::CompileOptions* aOptions); uint32_t NumberOfProcessors(); - nsresult PrepareLoadedRequest(nsScriptLoadRequest* aRequest, + nsresult PrepareLoadedRequest(ScriptLoadRequest* aRequest, nsIIncrementalStreamLoader* aLoader, nsresult aStatus, mozilla::Vector<char16_t> &aString); - void AddDeferRequest(nsScriptLoadRequest* aRequest); + void AddDeferRequest(ScriptLoadRequest* aRequest); bool MaybeRemovedDeferRequests(); - void MaybeMoveToLoadedList(nsScriptLoadRequest* aRequest); + void MaybeMoveToLoadedList(ScriptLoadRequest* aRequest); - JS::SourceBufferHolder GetScriptSource(nsScriptLoadRequest* aRequest, + JS::SourceBufferHolder GetScriptSource(ScriptLoadRequest* aRequest, nsAutoString& inlineData); bool ModuleScriptsEnabled(); - void SetModuleFetchStarted(nsModuleLoadRequest *aRequest); - void SetModuleFetchFinishedAndResumeWaitingRequests(nsModuleLoadRequest *aRequest, + void SetModuleFetchStarted(ModuleLoadRequest *aRequest); + void SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest *aRequest, nsresult aResult); - bool IsFetchingModule(nsModuleLoadRequest *aRequest) const; + bool IsFetchingModule(ModuleLoadRequest *aRequest) const; - bool ModuleMapContainsModule(nsModuleLoadRequest *aRequest) const; - RefPtr<mozilla::GenericPromise> WaitForModuleFetch(nsModuleLoadRequest *aRequest); - nsModuleScript* GetFetchedModule(nsIURI* aURL) const; + bool ModuleMapContainsModule(ModuleLoadRequest *aRequest) const; + RefPtr<mozilla::GenericPromise> WaitForModuleFetch(ModuleLoadRequest *aRequest); + ModuleScript* GetFetchedModule(nsIURI* aURL) const; friend bool HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp); - nsresult CreateModuleScript(nsModuleLoadRequest* aRequest); - nsresult ProcessFetchedModuleSource(nsModuleLoadRequest* aRequest); - void ProcessLoadedModuleTree(nsModuleLoadRequest* aRequest); - bool InstantiateModuleTree(nsModuleLoadRequest* aRequest); - void StartFetchingModuleDependencies(nsModuleLoadRequest* aRequest); + nsresult CreateModuleScript(ModuleLoadRequest* aRequest); + nsresult ProcessFetchedModuleSource(ModuleLoadRequest* aRequest); + void CheckModuleDependenciesLoaded(ModuleLoadRequest* aRequest); + void ProcessLoadedModuleTree(ModuleLoadRequest* aRequest); + bool InstantiateModuleTree(ModuleLoadRequest* aRequest); + void StartFetchingModuleDependencies(ModuleLoadRequest* aRequest); RefPtr<mozilla::GenericPromise> - StartFetchingModuleAndDependencies(nsModuleLoadRequest* aRequest, nsIURI* aURI); + StartFetchingModuleAndDependencies(ModuleLoadRequest* aRequest, nsIURI* aURI); nsIDocument* mDocument; // [WEAK] nsCOMArray<nsIScriptLoaderObserver> mObservers; - nsScriptLoadRequestList mNonAsyncExternalScriptInsertedRequests; + ScriptLoadRequestList mNonAsyncExternalScriptInsertedRequests; // mLoadingAsyncRequests holds async requests while they're loading; when they // have been loaded they are moved to mLoadedAsyncRequests. - nsScriptLoadRequestList mLoadingAsyncRequests; - nsScriptLoadRequestList mLoadedAsyncRequests; - nsScriptLoadRequestList mDeferRequests; - nsScriptLoadRequestList mXSLTRequests; - RefPtr<nsScriptLoadRequest> mParserBlockingRequest; + ScriptLoadRequestList mLoadingAsyncRequests; + ScriptLoadRequestList mLoadedAsyncRequests; + ScriptLoadRequestList mDeferRequests; + ScriptLoadRequestList mXSLTRequests; + RefPtr<ScriptLoadRequest> mParserBlockingRequest; // In mRequests, the additional information here is stored by the element. struct PreloadInfo { - RefPtr<nsScriptLoadRequest> mRequest; + RefPtr<ScriptLoadRequest> mRequest; nsString mCharset; }; - friend void ImplCycleCollectionUnlink(nsScriptLoader::PreloadInfo& aField); + friend void ImplCycleCollectionUnlink(ScriptLoader::PreloadInfo& aField); friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, - nsScriptLoader::PreloadInfo& aField, + ScriptLoader::PreloadInfo& aField, const char* aName, uint32_t aFlags); struct PreloadRequestComparator { - bool Equals(const PreloadInfo &aPi, nsScriptLoadRequest * const &aRequest) + bool Equals(const PreloadInfo &aPi, ScriptLoadRequest * const &aRequest) const { return aRequest == aPi.mRequest; @@ -628,7 +624,7 @@ private: nsCOMPtr<nsIScriptElement> mCurrentScript; nsCOMPtr<nsIScriptElement> mCurrentParserInsertedScript; - nsTArray< RefPtr<nsScriptLoader> > mPendingChildLoaders; + nsTArray< RefPtr<ScriptLoader> > mPendingChildLoaders; uint32_t mParserBlockingBlockerCount; uint32_t mBlockerCount; uint32_t mNumberOfProcessors; @@ -639,58 +635,11 @@ private: // Module map nsRefPtrHashtable<nsURIHashKey, mozilla::GenericPromise::Private> mFetchingModules; - nsRefPtrHashtable<nsURIHashKey, nsModuleScript> mFetchedModules; + nsRefPtrHashtable<nsURIHashKey, ModuleScript> mFetchedModules; nsCOMPtr<nsIConsoleReportCollector> mReporter; }; -class nsScriptLoadHandler final : public nsIIncrementalStreamLoaderObserver -{ -public: - explicit nsScriptLoadHandler(nsScriptLoader* aScriptLoader, - nsScriptLoadRequest *aRequest, - mozilla::dom::SRICheckDataVerifier *aSRIDataVerifier); - - NS_DECL_ISUPPORTS - NS_DECL_NSIINCREMENTALSTREAMLOADEROBSERVER - -private: - virtual ~nsScriptLoadHandler(); - - /* - * Try to decode some raw data. - */ - nsresult TryDecodeRawData(const uint8_t* aData, uint32_t aDataLength, - bool aEndOfStream); - - /* - * Discover the charset by looking at the stream data, the script - * tag, and other indicators. Returns true if charset has been - * discovered. - */ - bool EnsureDecoder(nsIIncrementalStreamLoader *aLoader, - const uint8_t* aData, uint32_t aDataLength, - bool aEndOfStream); - - // ScriptLoader which will handle the parsed script. - RefPtr<nsScriptLoader> mScriptLoader; - - // The nsScriptLoadRequest for this load. - RefPtr<nsScriptLoadRequest> mRequest; - - // SRI data verifier. - nsAutoPtr<mozilla::dom::SRICheckDataVerifier> mSRIDataVerifier; - - // Status of SRI data operations. - nsresult mSRIStatus; - - // Unicode decoder for charset. - nsCOMPtr<nsIUnicodeDecoder> mDecoder; - - // Accumulated decoded char buffer. - mozilla::Vector<char16_t> mBuffer; -}; - class nsAutoScriptLoaderDisabler { public: @@ -711,7 +660,10 @@ public: } bool mWasEnabled; - RefPtr<nsScriptLoader> mLoader; + RefPtr<ScriptLoader> mLoader; }; -#endif //__nsScriptLoader_h__ +} // namespace dom +} // namespace mozilla + +#endif //mozilla_dom_ScriptLoader_h diff --git a/dom/base/ScriptSettings.cpp b/dom/script/ScriptSettings.cpp index d67f2167ae..92ab221c95 100644 --- a/dom/base/ScriptSettings.cpp +++ b/dom/script/ScriptSettings.cpp @@ -485,7 +485,13 @@ AutoJSAPI::Init(nsIGlobalObject* aGlobalObject) bool AutoJSAPI::Init(JSObject* aObject) { - return Init(xpc::NativeGlobal(aObject)); + nsIGlobalObject* global = nullptr; + if (aObject) + global = xpc::NativeGlobal(aObject); + if (global) + return Init(global); + else + return false; } bool diff --git a/dom/base/ScriptSettings.h b/dom/script/ScriptSettings.h index 05e62f55e2..05e62f55e2 100644 --- a/dom/base/ScriptSettings.h +++ b/dom/script/ScriptSettings.h diff --git a/dom/script/moz.build b/dom/script/moz.build new file mode 100644 index 0000000000..280850ed4a --- /dev/null +++ b/dom/script/moz.build @@ -0,0 +1,36 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# 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/. + +XPIDL_SOURCES += [ + 'nsIScriptLoaderObserver.idl', +] + +XPIDL_MODULE = 'dom' + +EXPORTS += ['nsIScriptElement.h'] + +EXPORTS.mozilla.dom += [ + 'ScriptElement.h', + 'ScriptLoader.h', + 'ScriptSettings.h', +] + +SOURCES += [ + 'ModuleLoadRequest.cpp', + 'ModuleScript.cpp', + 'ScriptElement.cpp', + 'ScriptLoader.cpp', + 'ScriptLoadHandler.cpp', + 'ScriptSettings.cpp', +] + +LOCAL_INCLUDES += [ + '/dom/base', + '/dom/workers', +] + +include('/ipc/chromium/chromium-config.mozbuild') + +FINAL_LIBRARY = 'xul' diff --git a/dom/base/nsIScriptElement.h b/dom/script/nsIScriptElement.h index 470d51c948..470d51c948 100644 --- a/dom/base/nsIScriptElement.h +++ b/dom/script/nsIScriptElement.h diff --git a/dom/base/nsIScriptLoaderObserver.idl b/dom/script/nsIScriptLoaderObserver.idl index ed71965255..ed71965255 100644 --- a/dom/base/nsIScriptLoaderObserver.idl +++ b/dom/script/nsIScriptLoaderObserver.idl diff --git a/dom/svg/SVGScriptElement.cpp b/dom/svg/SVGScriptElement.cpp index ffc049c212..f2fb3ff5c8 100644 --- a/dom/svg/SVGScriptElement.cpp +++ b/dom/svg/SVGScriptElement.cpp @@ -42,7 +42,7 @@ NS_IMPL_ISUPPORTS_INHERITED(SVGScriptElement, SVGScriptElementBase, SVGScriptElement::SVGScriptElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo, FromParser aFromParser) : SVGScriptElementBase(aNodeInfo) - , nsScriptElement(aFromParser) + , ScriptElement(aFromParser) { AddMutationObserver(this); } @@ -168,7 +168,7 @@ SVGScriptElement::FreezeUriAsyncDefer() } //---------------------------------------------------------------------- -// nsScriptElement methods +// ScriptElement methods bool SVGScriptElement::HasScriptContent() diff --git a/dom/svg/SVGScriptElement.h b/dom/svg/SVGScriptElement.h index 620a1bcde0..9f098e0479 100644 --- a/dom/svg/SVGScriptElement.h +++ b/dom/svg/SVGScriptElement.h @@ -10,7 +10,7 @@ #include "nsSVGElement.h" #include "nsCOMPtr.h" #include "nsSVGString.h" -#include "nsScriptElement.h" +#include "mozilla/dom/ScriptElement.h" class nsIDocument; @@ -24,7 +24,7 @@ namespace dom { typedef nsSVGElement SVGScriptElementBase; class SVGScriptElement final : public SVGScriptElementBase, - public nsScriptElement + public ScriptElement { protected: friend nsresult (::NS_NewSVGScriptElement(nsIContent **aResult, @@ -47,7 +47,7 @@ public: virtual void FreezeUriAsyncDefer() override; virtual CORSMode GetCORSMode() const override; - // nsScriptElement + // ScriptElement virtual bool HasScriptContent() override; // nsIContent specializations: diff --git a/dom/tests/mochitest/fetch/file_fetch_observer.html b/dom/tests/mochitest/fetch/file_fetch_observer.html new file mode 100644 index 0000000000..668e609ec4 --- /dev/null +++ b/dom/tests/mochitest/fetch/file_fetch_observer.html @@ -0,0 +1,146 @@ +<script> +function ok(a, msg) { + parent.postMessage({ type: "check", status: !!a, message: msg }, "*"); +} + +function is(a, b, msg) { + ok(a === b, msg); +} + +function testObserver() { + ok("FetchObserver" in self, "We have a FetchObserver prototype"); + + fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', { observe: o => { + ok(!!o, "We have an observer"); + ok(o instanceof FetchObserver, "The correct object has been passed"); + is(o.state, "requesting", "By default the state is requesting"); + next(); + }}); +} + +function testObserveAbort() { + var fc = new AbortController(); + + fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', { + signal: fc.signal, + observe: o => { + o.onstatechange = () => { + ok(true, "StateChange event dispatched"); + if (o.state == "aborted") { + ok(true, "Aborted!"); + next(); + } + } + fc.abort(); + } + }); +} + +function testObserveComplete() { + var fc = new AbortController(); + + fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', { + signal: fc.signal, + observe: o => { + o.onstatechange = () => { + ok(true, "StateChange event dispatched"); + if (o.state == "complete") { + ok(true, "Operation completed"); + next(); + } + } + } + }); +} + +function testObserveErrored() { + var fc = new AbortController(); + + fetch('foo: bar', { + signal: fc.signal, + observe: o => { + o.onstatechange = () => { + ok(true, "StateChange event dispatched"); + if (o.state == "errored") { + ok(true, "Operation completed"); + next(); + } + } + } + }); +} + +function testObserveResponding() { + var fc = new AbortController(); + + fetch('http://mochi.test:8888/tests/dom/tests/mochitest/fetch/slow.sjs', { + signal: fc.signal, + observe: o => { + o.onstatechange = () => { + if (o.state == "responding") { + ok(true, "We have responding events"); + next(); + } + } + } + }); +} + +function workify(worker) { + function methods() { + function ok(a, msg) { + postMessage( { type: 'check', state: !!a, message: msg }); + }; + function is(a, b, msg) { + postMessage( { type: 'check', state: a === b, message: msg }); + }; + function next() { + postMessage( { type: 'finish' }); + }; + } + + var str = methods.toString(); + var methodsContent = str.substring(0, str.length - 1).split('\n').splice(1).join('\n'); + + str = worker.toString(); + var workerContent = str.substring(0, str.length - 1).split('\n').splice(1).join('\n'); + + var content = methodsContent + workerContent; + var url = URL.createObjectURL(new Blob([content], { type: "application/javascript" })); + var w = new Worker(url); + w.onmessage = e => { + if (e.data.type == 'check') { + ok(e.data.state, "WORKER: " + e.data.message); + } else if (e.data.type == 'finish') { + next(); + } else { + ok(false, "Something went wrong"); + } + } +} + +var steps = [ + testObserver, + testObserveAbort, + function() { workify(testObserveAbort); }, + testObserveComplete, + function() { workify(testObserveComplete); }, + testObserveErrored, + function() { workify(testObserveErrored); }, + testObserveResponding, + function() { workify(testObserveResponding); }, +]; + +function next() { + if (!steps.length) { + parent.postMessage({ type: "finish" }, "*"); + return; + } + + var step = steps.shift(); + step(); +} + +next(); + +</script> diff --git a/dom/tests/mochitest/fetch/mochitest.ini b/dom/tests/mochitest/fetch/mochitest.ini index cf4477463c..a9447d0d91 100644 --- a/dom/tests/mochitest/fetch/mochitest.ini +++ b/dom/tests/mochitest/fetch/mochitest.ini @@ -4,6 +4,7 @@ support-files = test_fetch_basic.js test_fetch_basic_http.js test_fetch_cors.js + file_fetch_observer.html test_formdataparsing.js test_headers_common.js test_request.js @@ -15,6 +16,7 @@ support-files = reroute.html reroute.js reroute.js^headers^ + slow.sjs sw_reroute.js empty.js empty.js^headers^ @@ -47,6 +49,7 @@ skip-if = toolkit == 'android' # Bug 1210282 skip-if = toolkit == 'android' # Bug 1210282 [test_fetch_cors_sw_empty_reroute.html] skip-if = toolkit == 'android' # Bug 1210282 +[test_fetch_observer.html] [test_formdataparsing.html] [test_formdataparsing_sw_reroute.html] [test_request.html] diff --git a/dom/tests/mochitest/fetch/slow.sjs b/dom/tests/mochitest/fetch/slow.sjs new file mode 100644 index 0000000000..feab0f1fce --- /dev/null +++ b/dom/tests/mochitest/fetch/slow.sjs @@ -0,0 +1,11 @@ +function handleRequest(request, response) +{ + response.processAsync(); + + timer = Components.classes["@mozilla.org/timer;1"]. + createInstance(Components.interfaces.nsITimer); + timer.init(function() { + response.write("Here the content. But slowly."); + response.finish(); + }, 1000, Components.interfaces.nsITimer.TYPE_ONE_SHOT); +} diff --git a/dom/tests/mochitest/fetch/test_fetch_observer.html b/dom/tests/mochitest/fetch/test_fetch_observer.html new file mode 100644 index 0000000000..2af86977c0 --- /dev/null +++ b/dom/tests/mochitest/fetch/test_fetch_observer.html @@ -0,0 +1,41 @@ +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<!DOCTYPE HTML> +<html> +<head> + <title>Test FetchObserver</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<script class="testbody" type="text/javascript"> + +SpecialPowers.pushPrefEnv({"set": [["dom.fetchObserver.enabled", true ], + ["dom.fetchController.enabled", true ]]}, () => { + let ifr = document.createElement('iframe'); + ifr.src = "file_fetch_observer.html"; + document.body.appendChild(ifr); + + onmessage = function(e) { + if (e.data.type == "finish") { + SimpleTest.finish(); + return; + } + + if (e.data.type == "check") { + ok(e.data.status, e.data.message); + return; + } + + ok(false, "Something when wrong."); + } +}); + +SimpleTest.waitForExplicitFinish(); + +</script> +</body> +</html> + diff --git a/dom/tests/mochitest/webcomponents/mochitest.ini b/dom/tests/mochitest/webcomponents/mochitest.ini index 496f7ea4d0..f05140c57d 100644 --- a/dom/tests/mochitest/webcomponents/mochitest.ini +++ b/dom/tests/mochitest/webcomponents/mochitest.ini @@ -46,3 +46,4 @@ support-files = [test_style_fallback_content.html] [test_unresolved_pseudo_class.html] [test_link_prefetch.html] +[test_bug1269155.html] diff --git a/dom/tests/mochitest/webcomponents/test_bug1269155.html b/dom/tests/mochitest/webcomponents/test_bug1269155.html new file mode 100644 index 0000000000..f280ae1d2a --- /dev/null +++ b/dom/tests/mochitest/webcomponents/test_bug1269155.html @@ -0,0 +1,89 @@ +<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1269155
+-->
+<head>
+ <title>Test for Bug 1269155</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=1269155">Mozilla Bug 1269155</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1269155 **/
+var host = document.querySelector('#content');
+ var root = host.createShadowRoot();
+
+ var header1 = document.createElement('h1');
+ header1.textContent = 'Shadow Header1';
+
+ var paragraph1 = document.createElement('p');
+ paragraph1.textContent = 'shadow text paragraph1';
+
+ root.appendChild(header1);
+ root.appendChild(paragraph1);
+
+var root2 = paragraph1.createShadowRoot();
+var header2 = document.createElement('h2');
+header2.textContent = 'Shadow Header2';
+
+var paragraph2 = document.createElement('p');
+paragraph2.textContent = 'shadow text paragraph2';
+root2.appendChild(header2);
+root2.appendChild(paragraph2);
+
+
+var frag = document.createDocumentFragment();
+var paragraph3 = document.createElement('p');
+paragraph3.textContent = 'fragment paragraph3';
+frag.appendChild(paragraph3);
+
+var root3 = paragraph3.createShadowRoot();
+var header4 = document.createElement('h2');
+header4.textContent = 'Shadow Header3';
+
+var paragraph4 = document.createElement('p');
+paragraph4.textContent = 'shadow text paragraph4';
+
+root3.appendChild(header4);
+root3.appendChild(paragraph4);
+
+//shadow dom without compose
+is(root.getRootNode(), root, "root.getRootNode() should be root.");
+is(root2.getRootNode(), root2, "root2.getRootNode() should be root.");
+is(root3.getRootNode(), root3, "root3.getRootNode() should be root.");
+is(header1.getRootNode(), root, "header1.getRootNode() should be root.");
+is(header2.getRootNode(), root2, "header1.getRootNode() should be root2.");
+is(header4.getRootNode(), root3, "header1.getRootNode() should be root3.");
+//shadow dom with compose
+is(root.getRootNode({ composed: true }), document, "root.getRootNode() with composed flag should be document.");
+is(root2.getRootNode({ composed: true }), document, "root2.getRootNode() with composed flag should be document.");
+is(root3.getRootNode({ composed: true }), frag, "root3.getRootNode() with composed flag should be frag.");
+is(header1.getRootNode({ composed: true }) , document, "header1.getRootNode() with composed flag should be document.");
+is(header2.getRootNode({ composed: true }) , document, "header2.getRootNode() with composed flag should be document.");
+is(header4.getRootNode({ composed: true }) , frag, "head4.getRootNode() with composed flag should be frag.");
+//dom without compose
+is(host.getRootNode(), document, "host.getRootNode() should be document.");
+is(header1.getRootNode(), root, "header1.getRootNode() should be root.");
+is(paragraph1.getRootNode(), root, "paragraph1.getRootNode() should be root.");
+is(frag.getRootNode(), frag, "frag.getRootNode() should be frag.");
+//dom with compose
+is(host.getRootNode({ composed: true }) , document, "host.getRootNode() with composed flag should be document.");
+is(header1.getRootNode({ composed: true }) , document, "header1.getRootNode() with composed flag should be document.");
+is(paragraph1.getRootNode({ composed: true }) , document, "paragraph1.getRootNode() with composed flag should be document.");
+is(frag.getRootNode({ composed: true }) , frag, "frag.getRootNode() with composed flag should be frag.");
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/webidl/AbortController.webidl b/dom/webidl/AbortController.webidl new file mode 100644 index 0000000000..4e91240751 --- /dev/null +++ b/dom/webidl/AbortController.webidl @@ -0,0 +1,13 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + */ + +[Constructor(), Exposed=(Window,Worker), + Func="AbortController::IsEnabled"] +interface AbortController { + readonly attribute AbortSignal signal; + + void abort(); +}; diff --git a/dom/webidl/AbortSignal.webidl b/dom/webidl/AbortSignal.webidl new file mode 100644 index 0000000000..b4b03bb7e1 --- /dev/null +++ b/dom/webidl/AbortSignal.webidl @@ -0,0 +1,13 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + */ + +[Exposed=(Window,Worker), + Func="AbortController::IsEnabled"] +interface AbortSignal : EventTarget { + readonly attribute boolean aborted; + + attribute EventHandler onabort; +}; diff --git a/dom/webidl/FetchObserver.webidl b/dom/webidl/FetchObserver.webidl new file mode 100644 index 0000000000..eecd67e668 --- /dev/null +++ b/dom/webidl/FetchObserver.webidl @@ -0,0 +1,27 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + */ + +callback interface ObserverCallback { + void handleEvent(FetchObserver observer); +}; + +enum FetchState { + // Pending states + "requesting", "responding", + // Final states + "aborted", "errored", "complete" +}; + +[Exposed=(Window,Worker), + Func="FetchObserver::IsEnabled"] +interface FetchObserver : EventTarget { + readonly attribute FetchState state; + + // Events + attribute EventHandler onstatechange; + attribute EventHandler onrequestprogress; + attribute EventHandler onresponseprogress; +}; diff --git a/dom/webidl/Node.webidl b/dom/webidl/Node.webidl index 7d18899b03..0a14e36245 100644 --- a/dom/webidl/Node.webidl +++ b/dom/webidl/Node.webidl @@ -38,8 +38,8 @@ interface Node : EventTarget { readonly attribute boolean isConnected; [Pure] readonly attribute Document? ownerDocument; - [Pure, Pref="dom.node.rootNode.enabled"] - readonly attribute Node rootNode; + [Pure] + Node getRootNode(optional GetRootNodeOptions options); [Pure] readonly attribute Node? parentNode; [Pure] @@ -113,3 +113,8 @@ interface Node : EventTarget { readonly attribute AccessibleNode? accessibleNode; #endif }; + +dictionary GetRootNodeOptions { + boolean composed = false; +}; + diff --git a/dom/webidl/Request.webidl b/dom/webidl/Request.webidl index e29c084d00..fe6a63ec0d 100644 --- a/dom/webidl/Request.webidl +++ b/dom/webidl/Request.webidl @@ -47,6 +47,12 @@ dictionary RequestInit { RequestCache cache; RequestRedirect redirect; DOMString integrity; + + [Func="AbortController::IsEnabled"] + AbortSignal signal; + + [Func="FetchObserver::IsEnabled"] + ObserverCallback observe; }; // Gecko currently does not ship RequestContext, so please don't use it in IDL diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 5e913585ee..d8309c2650 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -17,6 +17,8 @@ PREPROCESSED_WEBIDL_FILES = [ ] WEBIDL_FILES = [ + 'AbortController.webidl', + 'AbortSignal.webidl', 'AbstractWorker.webidl', 'AnalyserNode.webidl', 'Animatable.webidl', @@ -142,6 +144,7 @@ WEBIDL_FILES = [ 'FakePluginTagInit.webidl', 'Fetch.webidl', 'FetchEvent.webidl', + 'FetchObserver.webidl', 'File.webidl', 'FileList.webidl', 'FileMode.webidl', diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index 56b18441e5..bcec94dcb4 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -34,7 +34,6 @@ #include "nsIPipe.h" #include "nsIOutputStream.h" #include "nsPrintfCString.h" -#include "nsScriptLoader.h" #include "nsString.h" #include "nsStreamUtils.h" #include "nsTArray.h" @@ -58,6 +57,7 @@ #include "mozilla/dom/Promise.h" #include "mozilla/dom/PromiseNativeHandler.h" #include "mozilla/dom/Response.h" +#include "mozilla/dom/ScriptLoader.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/SRILogHelper.h" #include "mozilla/UniquePtr.h" @@ -1075,14 +1075,14 @@ private: // May be null. nsIDocument* parentDoc = mWorkerPrivate->GetDocument(); - // Use the regular nsScriptLoader for this grunt work! Should be just fine + // Use the regular ScriptLoader for this grunt work! Should be just fine // because we're running on the main thread. // Unlike <script> tags, Worker scripts are always decoded as UTF-8, // per spec. So we explicitly pass in the charset hint. - rv = nsScriptLoader::ConvertToUTF16(aLoadInfo.mChannel, aString, aStringLen, - NS_LITERAL_STRING("UTF-8"), parentDoc, - aLoadInfo.mScriptTextBuf, - aLoadInfo.mScriptTextLength); + rv = ScriptLoader::ConvertToUTF16(aLoadInfo.mChannel, aString, aStringLen, + NS_LITERAL_STRING("UTF-8"), parentDoc, + aLoadInfo.mScriptTextBuf, + aLoadInfo.mScriptTextLength); if (NS_FAILED(rv)) { return rv; } @@ -1289,10 +1289,10 @@ private: MOZ_ASSERT(!loadInfo.mScriptTextBuf); nsresult rv = - nsScriptLoader::ConvertToUTF16(nullptr, aString, aStringLen, - NS_LITERAL_STRING("UTF-8"), parentDoc, - loadInfo.mScriptTextBuf, - loadInfo.mScriptTextLength); + ScriptLoader::ConvertToUTF16(nullptr, aString, aStringLen, + NS_LITERAL_STRING("UTF-8"), parentDoc, + loadInfo.mScriptTextBuf, + loadInfo.mScriptTextLength); if (NS_SUCCEEDED(rv) && IsMainWorkerScript()) { nsCOMPtr<nsIURI> finalURI; rv = NS_NewURI(getter_AddRefs(finalURI), loadInfo.mFullURL, nullptr, nullptr); diff --git a/dom/workers/ServiceWorkerManager.cpp b/dom/workers/ServiceWorkerManager.cpp index a8f191f2e6..306ef6b235 100644 --- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -22,7 +22,6 @@ #include "nsITimer.h" #include "nsIUploadChannel2.h" #include "nsPIDOMWindow.h" -#include "nsScriptLoader.h" #include "nsServiceManagerUtils.h" #include "nsDebug.h" #include "nsISupportsPrimitives.h" @@ -44,6 +43,7 @@ #include "mozilla/dom/PromiseNativeHandler.h" #include "mozilla/dom/Request.h" #include "mozilla/dom/RootedDictionary.h" +#include "mozilla/dom/ScriptLoader.h" #include "mozilla/dom/TypedArray.h" #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/ipc/PBackgroundChild.h" diff --git a/dom/workers/ServiceWorkerScriptCache.cpp b/dom/workers/ServiceWorkerScriptCache.cpp index f44bb673c8..707b689e8a 100644 --- a/dom/workers/ServiceWorkerScriptCache.cpp +++ b/dom/workers/ServiceWorkerScriptCache.cpp @@ -11,6 +11,7 @@ #include "mozilla/dom/cache/Cache.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/PromiseWorkerProxy.h" +#include "mozilla/dom/ScriptLoader.h" #include "mozilla/ipc/BackgroundUtils.h" #include "mozilla/ipc/PBackgroundSharedTypes.h" #include "nsICacheInfoChannel.h" @@ -23,7 +24,6 @@ #include "nsIScriptError.h" #include "nsContentUtils.h" #include "nsNetUtil.h" -#include "nsScriptLoader.h" #include "ServiceWorkerManager.h" #include "Workers.h" #include "nsStringStream.h" @@ -801,9 +801,9 @@ CompareNetwork::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext char16_t* buffer = nullptr; size_t len = 0; - rv = nsScriptLoader::ConvertToUTF16(httpChannel, aString, aLen, - NS_LITERAL_STRING("UTF-8"), nullptr, - buffer, len); + rv = ScriptLoader::ConvertToUTF16(httpChannel, aString, aLen, + NS_LITERAL_STRING("UTF-8"), nullptr, + buffer, len); if (NS_WARN_IF(NS_FAILED(rv))) { mManager->NetworkFinished(rv); return rv; @@ -855,9 +855,9 @@ CompareCache::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext, char16_t* buffer = nullptr; size_t len = 0; - nsresult rv = nsScriptLoader::ConvertToUTF16(nullptr, aString, aLen, - NS_LITERAL_STRING("UTF-8"), - nullptr, buffer, len); + nsresult rv = ScriptLoader::ConvertToUTF16(nullptr, aString, aLen, + NS_LITERAL_STRING("UTF-8"), + nullptr, buffer, len); if (NS_WARN_IF(NS_FAILED(rv))) { mManager->CacheFinished(rv, false); return rv; diff --git a/dom/workers/WorkerPrefs.h b/dom/workers/WorkerPrefs.h index 9a1be4801f..b552d89561 100644 --- a/dom/workers/WorkerPrefs.h +++ b/dom/workers/WorkerPrefs.h @@ -39,6 +39,8 @@ WORKER_SIMPLE_PREF("dom.push.enabled", PushEnabled, PUSH_ENABLED) WORKER_SIMPLE_PREF("dom.requestcontext.enabled", RequestContextEnabled, REQUESTCONTEXT_ENABLED) WORKER_SIMPLE_PREF("gfx.offscreencanvas.enabled", OffscreenCanvasEnabled, OFFSCREENCANVAS_ENABLED) WORKER_SIMPLE_PREF("dom.webkitBlink.dirPicker.enabled", WebkitBlinkDirectoryPickerEnabled, DOM_WEBKITBLINK_DIRPICKER_WEBKITBLINK) +WORKER_SIMPLE_PREF("dom.abortController.enabled", AbortControllerEnabled, ABORTCONTROLLER_ENABLED) +WORKER_SIMPLE_PREF("dom.fetchObserver.enabled", FetchObserverEnabled, FETCHOBSERVER_ENABLED) WORKER_PREF("dom.workers.latestJSVersion", JSVersionChanged) WORKER_PREF("intl.accept_languages", PrefLanguagesChanged) WORKER_PREF("general.appname.override", AppNameOverrideChanged) diff --git a/dom/worklet/Worklet.cpp b/dom/worklet/Worklet.cpp index 19a877ea8f..1b71916abf 100644 --- a/dom/worklet/Worklet.cpp +++ b/dom/worklet/Worklet.cpp @@ -12,11 +12,11 @@ #include "mozilla/dom/PromiseNativeHandler.h" #include "mozilla/dom/RegisterWorkletBindings.h" #include "mozilla/dom/Response.h" +#include "mozilla/dom/ScriptLoader.h" #include "mozilla/dom/ScriptSettings.h" #include "nsIInputStreamPump.h" #include "nsIThreadRetargetableRequest.h" #include "nsNetUtil.h" -#include "nsScriptLoader.h" #include "xpcprivate.h" namespace mozilla { @@ -171,9 +171,9 @@ public: char16_t* scriptTextBuf; size_t scriptTextLength; nsresult rv = - nsScriptLoader::ConvertToUTF16(nullptr, aString, aStringLen, - NS_LITERAL_STRING("UTF-8"), nullptr, - scriptTextBuf, scriptTextLength); + ScriptLoader::ConvertToUTF16(nullptr, aString, aStringLen, + NS_LITERAL_STRING("UTF-8"), nullptr, + scriptTextBuf, scriptTextLength); if (NS_WARN_IF(NS_FAILED(rv))) { RejectPromises(rv); return NS_OK; diff --git a/dom/xml/nsXMLContentSink.cpp b/dom/xml/nsXMLContentSink.cpp index 7c9d308fd6..daf1dbf271 100644 --- a/dom/xml/nsXMLContentSink.cpp +++ b/dom/xml/nsXMLContentSink.cpp @@ -35,7 +35,6 @@ #include "nsRect.h" #include "nsIWebNavigation.h" #include "nsIScriptElement.h" -#include "nsScriptLoader.h" #include "nsStyleLinkElement.h" #include "nsReadableUtils.h" #include "nsUnicharUtils.h" @@ -62,6 +61,7 @@ #include "mozilla/dom/Element.h" #include "mozilla/dom/HTMLTemplateElement.h" #include "mozilla/dom/ProcessingInstruction.h" +#include "mozilla/dom/ScriptLoader.h" using namespace mozilla; using namespace mozilla::dom; diff --git a/dom/xml/nsXMLFragmentContentSink.cpp b/dom/xml/nsXMLFragmentContentSink.cpp index 7fa815c84a..7d9f869879 100644 --- a/dom/xml/nsXMLFragmentContentSink.cpp +++ b/dom/xml/nsXMLFragmentContentSink.cpp @@ -24,10 +24,10 @@ #include "nsTArray.h" #include "nsCycleCollectionParticipant.h" #include "nsIDocShell.h" -#include "nsScriptLoader.h" #include "mozilla/css/Loader.h" #include "mozilla/dom/DocumentFragment.h" #include "mozilla/dom/ProcessingInstruction.h" +#include "mozilla/dom/ScriptLoader.h" using namespace mozilla::dom; diff --git a/dom/xslt/xslt/txMozillaXMLOutput.cpp b/dom/xslt/xslt/txMozillaXMLOutput.cpp index 069413d976..704d8ac110 100644 --- a/dom/xslt/xslt/txMozillaXMLOutput.cpp +++ b/dom/xslt/xslt/txMozillaXMLOutput.cpp @@ -7,7 +7,6 @@ #include "nsIDocument.h" #include "nsIDocShell.h" -#include "nsScriptLoader.h" #include "nsIDOMDocument.h" #include "nsIDOMDocumentType.h" #include "nsIScriptElement.h" @@ -31,6 +30,7 @@ #include "mozilla/css/Loader.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/EncodingUtils.h" +#include "mozilla/dom/ScriptLoader.h" #include "nsContentUtils.h" #include "txXMLUtils.h" #include "nsContentSink.h" @@ -230,7 +230,7 @@ txMozillaXMLOutput::endDocument(nsresult aResult) MOZ_ASSERT(mDocument->GetReadyStateEnum() == nsIDocument::READYSTATE_LOADING, "Bad readyState"); mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_INTERACTIVE); - nsScriptLoader* loader = mDocument->ScriptLoader(); + ScriptLoader* loader = mDocument->ScriptLoader(); if (loader) { loader->ParsingComplete(false); } @@ -416,7 +416,7 @@ txMozillaXMLOutput::startDocument() } if (mCreatingNewDocument) { - nsScriptLoader* loader = mDocument->ScriptLoader(); + ScriptLoader* loader = mDocument->ScriptLoader(); if (loader) { loader->BeginDeferringScripts(); } @@ -857,7 +857,7 @@ txMozillaXMLOutput::createResultDocument(const nsSubstring& aName, int32_t aNsID } // Set up script loader of the result document. - nsScriptLoader *loader = mDocument->ScriptLoader(); + ScriptLoader *loader = mDocument->ScriptLoader(); if (mNotifier) { loader->AddObserver(mNotifier); } diff --git a/dom/xul/XULDocument.cpp b/dom/xul/XULDocument.cpp index 1dcb55aee4..36481f9896 100644 --- a/dom/xul/XULDocument.cpp +++ b/dom/xul/XULDocument.cpp @@ -3337,10 +3337,10 @@ XULDocument::OnStreamComplete(nsIStreamLoader* aLoader, !mOffThreadCompileStringBuf), "XULDocument can't load multiple scripts at once"); - rv = nsScriptLoader::ConvertToUTF16(channel, string, stringLen, - EmptyString(), this, - mOffThreadCompileStringBuf, - mOffThreadCompileStringLength); + rv = ScriptLoader::ConvertToUTF16(channel, string, stringLen, + EmptyString(), this, + mOffThreadCompileStringBuf, + mOffThreadCompileStringLength); if (NS_SUCCEEDED(rv)) { // Attempt to give ownership of the buffer to the JS engine. If // we hit offthread compilation, however, we will have to take it diff --git a/dom/xul/XULDocument.h b/dom/xul/XULDocument.h index 06abb797f0..e72edfeed0 100644 --- a/dom/xul/XULDocument.h +++ b/dom/xul/XULDocument.h @@ -21,13 +21,13 @@ #include "nsCOMArray.h" #include "nsIURI.h" #include "nsIXULDocument.h" -#include "nsScriptLoader.h" #include "nsIStreamListener.h" #include "nsIStreamLoader.h" #include "nsICSSLoaderObserver.h" #include "nsIXULStore.h" #include "mozilla/Attributes.h" +#include "mozilla/dom/ScriptLoader.h" #include "js/TracingAPI.h" #include "js/TypeDecls.h" diff --git a/dom/xul/nsXULContentSink.cpp b/dom/xul/nsXULContentSink.cpp index edeee87280..94560e70db 100644 --- a/dom/xul/nsXULContentSink.cpp +++ b/dom/xul/nsXULContentSink.cpp @@ -881,7 +881,7 @@ XULContentSinkImpl::OpenScript(const char16_t** aAttributes, isJavaScript = false; } } else if (key.EqualsLiteral("language")) { - // Language is deprecated, and the impl in nsScriptLoader ignores the + // Language is deprecated, and the impl in ScriptLoader ignores the // various version strings anyway. So we make no attempt to support // languages other than JS for language= nsAutoString lang(aAttributes[1]); |