forked from mirrors/gecko-dev
		
	 01d4cafbb1
			
		
	
	
		01d4cafbb1
		
	
	
	
	
		
			
			Firstly we need to find a usable ScriptLoader for code in the content script sandbox, for that we use the normal ScriptLoader associated with DOMWindow wrapped by the sandbox. Secondly we need to execute the module in the global of the sandbox instead of the "ScriptGlobal" the ScriptLoader is actually associated with. The main behavior change here comes from using xpc::NativeGlobal in HostImportModuleDynamically and passing that global around inside ScriptFetchOptions. To ensure that content-scripts and the webpage don't share imported modules, the module map (mFetchingModules and mFetchedModules) now uses a complex key of <URI, Global>. The Global is a nullptr for normal imports from a webpage. Differential Revision: https://phabricator.services.mozilla.com/D107076
		
			
				
	
	
		
			218 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "ModuleLoadRequest.h"
 | |
| 
 | |
| #include "mozilla/HoldDropJSObjects.h"
 | |
| 
 | |
| #include "LoadedScript.h"
 | |
| #include "ScriptLoader.h"
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace dom {
 | |
| 
 | |
| #undef LOG
 | |
| #define LOG(args) \
 | |
|   MOZ_LOG(ScriptLoader::gScriptLoaderLog, mozilla::LogLevel::Debug, args)
 | |
| 
 | |
| NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ModuleLoadRequest)
 | |
| NS_INTERFACE_MAP_END_INHERITING(ScriptLoadRequest)
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_MULTI_ZONE_JSHOLDER_CLASS(ModuleLoadRequest)
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ModuleLoadRequest,
 | |
|                                                 ScriptLoadRequest)
 | |
|   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader, mModuleScript, mImports)
 | |
|   tmp->ClearDynamicImport();
 | |
| NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ModuleLoadRequest,
 | |
|                                                   ScriptLoadRequest)
 | |
|   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader, mModuleScript, mImports)
 | |
| NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ModuleLoadRequest,
 | |
|                                                ScriptLoadRequest)
 | |
|   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicReferencingPrivate)
 | |
|   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicSpecifier)
 | |
|   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDynamicPromise)
 | |
| NS_IMPL_CYCLE_COLLECTION_TRACE_END
 | |
| 
 | |
| NS_IMPL_ADDREF_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
 | |
| NS_IMPL_RELEASE_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
 | |
| 
 | |
| static VisitedURLSet* NewVisitedSetForTopLevelImport(nsIURI* aURI) {
 | |
|   auto set = new VisitedURLSet();
 | |
|   set->PutEntry(aURI);
 | |
|   return set;
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| ModuleLoadRequest* ModuleLoadRequest::CreateTopLevel(
 | |
|     nsIURI* aURI, ScriptFetchOptions* aFetchOptions,
 | |
|     const SRIMetadata& aIntegrity, nsIURI* aReferrer, ScriptLoader* aLoader) {
 | |
|   return new ModuleLoadRequest(aURI, aFetchOptions, aIntegrity, aReferrer,
 | |
|                                true,  /* is top level */
 | |
|                                false, /* is dynamic import */
 | |
|                                aLoader, NewVisitedSetForTopLevelImport(aURI));
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| ModuleLoadRequest* ModuleLoadRequest::CreateStaticImport(
 | |
|     nsIURI* aURI, ModuleLoadRequest* aParent) {
 | |
|   auto request =
 | |
|       new ModuleLoadRequest(aURI, aParent->mFetchOptions, SRIMetadata(),
 | |
|                             aParent->mURI, false, /* is top level */
 | |
|                             false,                /* is dynamic import */
 | |
|                             aParent->mLoader, aParent->mVisitedSet);
 | |
| 
 | |
|   request->mIsInline = false;
 | |
|   request->mScriptMode = aParent->mScriptMode;
 | |
| 
 | |
|   return request;
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| ModuleLoadRequest* ModuleLoadRequest::CreateDynamicImport(
 | |
|     nsIURI* aURI, ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL,
 | |
|     ScriptLoader* aLoader, JS::Handle<JS::Value> aReferencingPrivate,
 | |
|     JS::Handle<JSString*> aSpecifier, JS::Handle<JSObject*> aPromise) {
 | |
|   MOZ_ASSERT(aSpecifier);
 | |
|   MOZ_ASSERT(aPromise);
 | |
| 
 | |
|   auto request = new ModuleLoadRequest(
 | |
|       aURI, aFetchOptions, SRIMetadata(), aBaseURL, true, /* is top level */
 | |
|       true, /* is dynamic import */
 | |
|       aLoader, NewVisitedSetForTopLevelImport(aURI));
 | |
| 
 | |
|   request->mIsInline = false;
 | |
|   request->mScriptMode = ScriptMode::eAsync;
 | |
|   request->mDynamicReferencingPrivate = aReferencingPrivate;
 | |
|   request->mDynamicSpecifier = aSpecifier;
 | |
|   request->mDynamicPromise = aPromise;
 | |
| 
 | |
|   HoldJSObjects(request);
 | |
| 
 | |
|   return request;
 | |
| }
 | |
| 
 | |
| ModuleLoadRequest::ModuleLoadRequest(
 | |
|     nsIURI* aURI, ScriptFetchOptions* aFetchOptions,
 | |
|     const SRIMetadata& aIntegrity, nsIURI* aReferrer, bool aIsTopLevel,
 | |
|     bool aIsDynamicImport, ScriptLoader* aLoader, VisitedURLSet* aVisitedSet)
 | |
|     : ScriptLoadRequest(ScriptKind::eModule, aURI, aFetchOptions, aIntegrity,
 | |
|                         aReferrer),
 | |
|       mIsTopLevel(aIsTopLevel),
 | |
|       mIsDynamicImport(aIsDynamicImport),
 | |
|       mLoader(aLoader),
 | |
|       mVisitedSet(aVisitedSet) {}
 | |
| 
 | |
| void ModuleLoadRequest::Cancel() {
 | |
|   ScriptLoadRequest::Cancel();
 | |
|   mModuleScript = nullptr;
 | |
|   mProgress = ScriptLoadRequest::Progress::eReady;
 | |
|   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.
 | |
| 
 | |
|   LOG(("ScriptLoadRequest (%p): Module loaded", this));
 | |
| 
 | |
|   mModuleScript = mLoader->GetFetchedModule(mURI, GetWebExtGlobal());
 | |
|   if (!mModuleScript || mModuleScript->HasParseError()) {
 | |
|     ModuleErrored();
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   mLoader->StartFetchingModuleDependencies(this);
 | |
| }
 | |
| 
 | |
| void ModuleLoadRequest::ModuleErrored() {
 | |
|   if (IsCanceled()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   LOG(("ScriptLoadRequest (%p): Module errored", this));
 | |
| 
 | |
|   mLoader->CheckModuleDependenciesLoaded(this);
 | |
|   MOZ_ASSERT(!mModuleScript || mModuleScript->HasParseError());
 | |
| 
 | |
|   CancelImports();
 | |
|   SetReady();
 | |
|   LoadFinished();
 | |
| }
 | |
| 
 | |
| void ModuleLoadRequest::DependenciesLoaded() {
 | |
|   if (IsCanceled()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // The module and all of its dependencies have been successfully fetched and
 | |
|   // compiled.
 | |
| 
 | |
|   LOG(("ScriptLoadRequest (%p): Module dependencies loaded", this));
 | |
| 
 | |
|   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).
 | |
| 
 | |
|   LOG(("ScriptLoadRequest (%p): Module load failed", this));
 | |
| 
 | |
|   MOZ_ASSERT(!mModuleScript);
 | |
| 
 | |
|   Cancel();
 | |
|   LoadFinished();
 | |
| }
 | |
| 
 | |
| void ModuleLoadRequest::LoadFinished() {
 | |
|   mLoader->ProcessLoadedModuleTree(this);
 | |
| 
 | |
|   mLoader = nullptr;
 | |
| }
 | |
| 
 | |
| void ModuleLoadRequest::ClearDynamicImport() {
 | |
|   mDynamicReferencingPrivate = JS::UndefinedValue();
 | |
|   mDynamicSpecifier = nullptr;
 | |
|   mDynamicPromise = nullptr;
 | |
| }
 | |
| 
 | |
| }  // namespace dom
 | |
| }  // namespace mozilla
 |