Changeset 208788 in webkit


Ignore:
Timestamp:
Nov 16, 2016 3:39:43 AM (7 years ago)
Author:
Yusuke Suzuki
Message:

[ES6] Integrate ES6 Modules into WebCore
https://bugs.webkit.org/show_bug.cgi?id=148897

Reviewed by Ryosuke Niwa.

Source/WebCore:

This patch introduces ES6 Modules into WebCore. We integrate JSC's JSModuleLoader into WebCore.
JSC constructs the module loader pipeline by the chains of the promises. To handle this,
the following components are added.

  1. CachedModuleScript

CachedModuleScript wraps the promise based JSModuleLoader pipeline and offers
similar APIs to CachedScript. ScriptElement and PendingScript interact with
CachedModuleScript when the script tag is the module tag instead of CachedScript.
ScriptElement and PendingScript will receive the notification from
CachedModuleScript by implementing CachedModuleScriptClient.

  1. ScriptModuleLoader

This is the module loader instantiated per document. It manages fetching and
offers the callbacks for the JSC's JSModuleLoader implementation. ScriptModuleLoader
will fetch the resource by creating CachedModuleScriptLoader per resource. ScriptModuleLoader
will receive the notification by implementing CachedModuleScriptLoaderClient. When the
resource is fetched, the module loader will drive the promise resolve/reject chain.

  1. CachedModuleScriptLoader

This fetches the resource by using CachedScript. Using CachedScript means that it
automatically reports the resource to the inspector. CachedModuleScriptLoader notify to
ScriptModuleLoader when the resource is fetched.

One tricky point is that the fetch requests issued from one module-graph should share the same
nonce, crossorigin attributes etc.

Here, we wrote the module graph like A -> B (A depends on B).

<script tag> -> A -> B -> C -> D

When fetching A, B, C, and D modules, we need to set the same nonce, crossorigin etc. configuration
derived from the original script tag. So per module-graph information should be shared throughout
the module loader pipeline. To do so, JSC's module loader implementation can take the value called
initiator. Since the loader will propagate & share this initiator throughout the pipeline,
we can transfer and share some metadata. Currently, we pass the JSWrapper of the script tag as the
initiator. Each fetch request is created by using this initiator script element.

More integration into the inspector should be done in the subsequent patch.

  • CMakeLists.txt:
  • WebCore.xcodeproj/project.pbxproj:
  • bindings/js/CachedModuleScript.cpp: Added.

CachedModuleScript offers similar interface to CachedScript to make ScriptElement things easier. It encapsulates the
detail of the JSC JSModuleLoader that this module loader is driven by the chain of the promises. CachedModuleScript's
callbacks are called from the promise's handlers configured in ScriptController::loadModuleScript.
(WebCore::CachedModuleScript::create):
(WebCore::CachedModuleScript::CachedModuleScript):
(WebCore::CachedModuleScript::load):
(WebCore::CachedModuleScript::notifyLoadCompleted):
(WebCore::CachedModuleScript::notifyLoadFailed):
(WebCore::CachedModuleScript::notifyLoadWasCanceled):
(WebCore::CachedModuleScript::notifyClientFinished):
(WebCore::CachedModuleScript::addClient):
(WebCore::CachedModuleScript::removeClient):

  • bindings/js/CachedModuleScript.h: Added.

(WebCore::CachedModuleScript::moduleKey):
(WebCore::CachedModuleScript::error):
(WebCore::CachedModuleScript::wasCanceled):
(WebCore::CachedModuleScript::isLoaded):
(WebCore::CachedModuleScript::nonce):
(WebCore::CachedModuleScript::crossOriginMode):
Save nonce and crossorigin attributes when we start ScriptElement::prepareScript.

  • bindings/js/CachedModuleScriptClient.h: Copied from Source/WebCore/dom/LoadableScript.h.

(WebCore::CachedModuleScriptClient::~CachedModuleScriptClient):

  • bindings/js/CachedModuleScriptLoader.cpp: Added.

CachedModuleScriptLoader is responsible to fetching the resource for the module script. It uses propagated initiator
to create the request. This initiator is the JS wrapper of the script element issuing this fetching request. The name
initiator is derived from the request.setInitiator(). Once the resource is fetched, the fetcher will notify to the
client. Currently, ScriptModuleLoader implements this client interface.
(WebCore::CachedModuleScriptLoader::create):
(WebCore::CachedModuleScriptLoader::CachedModuleScriptLoader):
(WebCore::CachedModuleScriptLoader::~CachedModuleScriptLoader):
(WebCore::CachedModuleScriptLoader::load):
Create the request. We call ScriptElement::requestCachedScript to initiate a new fetching request. At that time,
nonce and crossorigin (and charset) attributes of this element are applied to the new request.
(WebCore::CachedModuleScriptLoader::notifyFinished):

  • bindings/js/CachedModuleScriptLoader.h: Copied from Source/WebCore/bindings/js/ScriptModuleLoader.h.
  • bindings/js/CachedModuleScriptLoaderClient.h: Copied from Source/WebCore/dom/LoadableScript.h.

(WebCore::CachedModuleScriptLoaderClient::~CachedModuleScriptLoaderClient):

  • bindings/js/CachedScriptSourceProvider.h:

(WebCore::CachedScriptSourceProvider::create):
(WebCore::CachedScriptSourceProvider::CachedScriptSourceProvider):
(WebCore::makeSource):

  • bindings/js/JSBindingsAllInOne.cpp:
  • bindings/js/JSDOMBinding.cpp:

(WebCore::retrieveErrorMessage):
(WebCore::reportException):

  • bindings/js/JSDOMBinding.h:
  • bindings/js/JSMainThreadExecState.h:

(WebCore::JSMainThreadExecState::loadModule):
(WebCore::JSMainThreadExecState::linkAndEvaluateModule):

  • bindings/js/ScriptController.cpp:

(WebCore::ScriptController::evaluateInWorld):
(WebCore::ScriptController::loadModuleScriptInWorld):
(WebCore::ScriptController::loadModuleScript):
This just performs loading and not executing the module graph. Once the module graph is loaded, it is notified to
the given CachedModuleScript.
(WebCore::ScriptController::linkAndEvaluateModuleScriptInWorld):
(WebCore::ScriptController::linkAndEvaluateModuleScript):
This executes the linking and evaluation of the already instantiated module graph. After loading the module graph,
we call this function for the module to evaluate it. This is called from ScriptElement::executeModuleScript.
(WebCore::ScriptController::evaluateModule):
Every time we evaluate the module, the ScriptModuleLoader::evaluate hook is called. So the loader calls this function
to actually evaluate the module.
(WebCore::jsValueToModuleKey):
(WebCore::ScriptController::setupModuleScriptHandlers):
The JSC's module loader is driven by the chain of the promise. So here, we convert this to CachedModuleScript /
CachedModuleScriptClient style and encapsulate the details. This encapsulation makes CachedModuleScript similar
to CachedScript and it makes things simple in the rest of WebCore. If the propagated error is already reported
to the inspector, we receive moduleLoaderAlreadyReportedErrorSymbol as the error value. So at that case, we
don't report it twice. If the rejection is caused due to the canceled fetching, moduleLoaderFetchingIsCanceledSymbol
appears as the error value. In that case, we will call CachedModuleScript::notifyLoadWasCanceled.
(WebCore::ScriptController::executeScript):

  • bindings/js/ScriptController.h:

(WebCore::ScriptController::moduleLoaderAlreadyReportedErrorSymbol):
(WebCore::ScriptController::moduleLoaderFetchingIsCanceledSymbol):

  • bindings/js/ScriptModuleLoader.cpp:

We use DeferredWrapper to resolve promises used for the module pipeline. Thus, once the active DOM objects are
suspended, the module loader propagation stops.
(WebCore::ScriptModuleLoader::~ScriptModuleLoader):
Clear the clients of the fetchers issued from this loader.
(WebCore::isRootModule):
(WebCore::ScriptModuleLoader::resolve):
Resolve the module specifier (that is written in import from "XXX") to the unique module key. We use URL
string as module key. The edge case is that the module is inlined one. In that case, we don't have any URL
for that. Instead of URL, we use symbol at that time.
(WebCore::ScriptModuleLoader::fetch):
Start fetching for the requested module. It returns the promise that is resolved when the fetching is done.
The loader creates the fetcher, and the fetcher start loading the resource. Once the fetcher loads the resource,
it notify to the loader through CachedModuleScriptLoaderClient interface. Since we pass the original script
element as the initiator here, the fetcher can use this initiator to create the request. While the result of
CachedResource has 3 variations (loaded, canceled, error occurred), Promise only tells us whether it is resolved
or rejected. When CachedModuleScript gets the result from the promise chain, it needs to know which the result is.
To transfer the canceled information, we reject the promise with the special symbol moduleLoaderAlreadyReportedErrorSymbol.
This offers the way to distinguish the canceled error from the other errors.
(WebCore::ScriptModuleLoader::evaluate):
This is the hook function that is called when JSC's JSModuleLoader attempts to execute each module.
(WebCore::ScriptModuleLoader::notifyFinished):
This function is called when the fetcher completes. We will resolve the promise with the result of the fetching.
The module loader pipeline is constructed as a chain of promises.
Rejecting a promise when some error occurs is important because the execution flow of
the promise chain is driven by "rejected" or "fulfilled" events.
If the promise is not rejected while error occurs, reject handler won't be executed
and all the subsequent promise chain will wait the result forever.
As a result, even if the error is already reported to the inspector elsewhere,
it should be propagated in the pipeline. For example, the error of loading
CachedResource is already reported to the inspector by the loader. But we still need
to reject the promise to propagate this error to the script element.
At that time, we don't want to report the same error twice. When we propagate the error
that is already reported to the inspector, we throw moduleLoaderAlreadyReportedErrorSymbol
symbol instead. By comparing the thrown error with this symbol, we can distinguish errors raised
when checking syntax of a module script from errors reported already.
In the reject handler of the promise, we only report a error that is not this symbol.
And mime type checking is done here since the module script always require this check.

  • bindings/js/ScriptModuleLoader.h:

(WebCore::ScriptModuleLoader::document): Deleted.

  • bindings/js/ScriptSourceCode.h:

(WebCore::ScriptSourceCode::ScriptSourceCode):

  • dom/CurrentScriptIncrementer.h:

(WebCore::CurrentScriptIncrementer::CurrentScriptIncrementer):

  • dom/LoadableClassicScript.cpp:

(WebCore::LoadableClassicScript::error):
(WebCore::LoadableClassicScript::execute):
(WebCore::LoadableClassicScript::wasErrored): Deleted.

  • dom/LoadableClassicScript.h:
  • dom/LoadableModuleScript.cpp: Copied from Source/WebCore/dom/LoadableScript.h.

This is the derived class from LoadableScript. It is used for the script module graphs.
(WebCore::LoadableModuleScript::create):
(WebCore::LoadableModuleScript::LoadableModuleScript):
(WebCore::LoadableModuleScript::~LoadableModuleScript):
(WebCore::LoadableModuleScript::isLoaded):
(WebCore::LoadableModuleScript::error):
(WebCore::LoadableModuleScript::wasCanceled):
(WebCore::LoadableModuleScript::notifyFinished):
(WebCore::LoadableModuleScript::execute):

  • dom/LoadableModuleScript.h: Copied from Source/WebCore/dom/LoadableScript.h.

(isType):

  • dom/LoadableScript.h:

(WebCore::LoadableScript::isModuleScript):
(WebCore::LoadableScript::isModuleGraph): Deleted.

  • dom/PendingScript.cpp:

(WebCore::PendingScript::error):
(WebCore::PendingScript::wasErrored): Deleted.

  • dom/PendingScript.h:
  • dom/ScriptElement.cpp:

(WebCore::ScriptElement::ScriptElement):
(WebCore::ScriptElement::determineScriptType):
(WebCore::ScriptElement::prepareScript):
prepareScript is aligned to whatwg spec: the last sequence to setup flags has one-on-one correspondence to
the spec now. And prepareScript recognizes the type="module" case and call the requestModuleScript to setup
the CachedModuleScript.
(WebCore::ScriptElement::requestClassicScript):
(WebCore::ScriptElement::requestModuleScript):
We use the nonce and crossorigin attributes at the time of preparing the script tag. To do so, we store the
above values in CachedModuleScript.
Since inlined module scripts does not have "src" attribute, it is also affected by Content Security Policy's
inline script rules.
(WebCore::ScriptElement::requestScriptWithCacheForModuleScript):
The module loader will construct the fetching request by calling this function. This should be here since we
would like to set this Element to the initiator of the request. And nonce and crossorigin attributes of this
script tag will be used.
(WebCore::ScriptElement::requestScriptWithCache):
(WebCore::ScriptElement::executeScript):
(WebCore::ScriptElement::executeModuleScript):
The entry point to execute the module graph. Since the module graph is beyond the multiple CachedScript code,
we have the different entry point from ScriptElement::executeScript.
(WebCore::ScriptElement::executeScriptAndDispatchEvent):
(WebCore::ScriptElement::executeScriptForScriptRunner):

  • dom/ScriptElement.h:

(WebCore::ScriptElement::scriptType):

  • html/parser/CSSPreloadScanner.cpp:

(WebCore::CSSPreloadScanner::emitRule):

  • html/parser/HTMLPreloadScanner.cpp:

(WebCore::TokenPreloadScanner::StartTagScanner::createPreloadRequest):
According to the spec, the module tag ignores the "charset" attribute as the same to the worker's
importScript. But WebKit supports the "charset" for importScript intentionally. So to be consistent,
even for the module tags, we handle the "charset" attribute. We explicitly note about it in the preloader.
(WebCore::TokenPreloadScanner::StartTagScanner::processAttribute):

  • html/parser/HTMLResourcePreloader.cpp:

(WebCore::PreloadRequest::resourceRequest):

  • html/parser/HTMLResourcePreloader.h:

(WebCore::PreloadRequest::PreloadRequest):

  • html/parser/HTMLScriptRunner.h:
  • loader/cache/CachedResourceRequest.cpp:

(WebCore::CachedResourceRequest::setAsPotentiallyCrossOrigin):

  • xml/parser/XMLDocumentParser.cpp:

(WebCore::XMLDocumentParser::notifyFinished):

LayoutTests:

  • TestExpectations:
  • http/tests/misc/module-absolute-url-expected.txt: Added.
  • http/tests/misc/module-absolute-url.html: Added.
  • http/tests/misc/module-script-async-expected.txt: Added.
  • http/tests/misc/module-script-async.html: Added.
  • http/tests/misc/resources/module-absolute-url.js: Added.
  • http/tests/misc/resources/module-absolute-url2.js: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-allowed-expected.txt: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-allowed.html: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-and-scripthash-expected.txt: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-and-scripthash.html: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-basic-blocked-expected.txt: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-basic-blocked.html: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-blocked-expected.txt: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-blocked.html: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-ignore-unsafeinline-expected.txt: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-ignore-unsafeinline.html: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-in-enforced-policy-and-not-in-report-only-expected.txt: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-in-enforced-policy-and-not-in-report-only.html: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-in-one-enforced-policy-neither-in-another-enforced-policy-nor-report-policy-expected.txt: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-in-one-enforced-policy-neither-in-another-enforced-policy-nor-report-policy.html: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-invalidnonce-expected.txt: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-invalidnonce.html: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-multiple-policies-expected.txt: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-multiple-policies.html: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-redirect-expected.txt: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-redirect-same-origin-expected.txt: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-redirect-same-origin.html: Added.
  • http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-redirect.html: Added.
  • http/tests/security/contentSecurityPolicy/1.1/resources/module-scriptnonce-in-enforced-policy-and-not-in-report-only.php: Added.
  • http/tests/security/contentSecurityPolicy/1.1/resources/module-scriptnonce-in-one-enforced-policy-neither-in-another-enforced-policy-nor-report-policy.php: Added.
  • http/tests/security/contentSecurityPolicy/module-eval-blocked-expected.txt: Added.
  • http/tests/security/contentSecurityPolicy/module-eval-blocked-in-external-script-expected.txt: Added.
  • http/tests/security/contentSecurityPolicy/module-eval-blocked-in-external-script.html: Added.
  • http/tests/security/contentSecurityPolicy/module-eval-blocked.html: Added.
  • http/tests/security/contentSecurityPolicy/resources/echo-module-script-src.pl: Added.
  • http/tests/security/contentSecurityPolicy/resources/multiple-iframe-module-test.js: Added.

(testPreescapedPolicy):
(testExperimentalPolicy):
(test):
(iframe.onload):
(testImpl):
(finishTesting):

  • http/tests/security/module-correct-mime-types-expected.txt: Added.
  • http/tests/security/module-correct-mime-types.html: Added.
  • http/tests/security/module-crossorigin-error-event-information-expected.txt: Added.
  • http/tests/security/module-crossorigin-error-event-information.html: Added.
  • http/tests/security/module-crossorigin-loads-correctly-credentials-expected.txt: Added.
  • http/tests/security/module-crossorigin-loads-correctly-credentials.html: Added.
  • http/tests/security/module-crossorigin-loads-omit-expected.txt: Added.
  • http/tests/security/module-crossorigin-loads-omit.html: Added.
  • http/tests/security/module-crossorigin-loads-same-origin-expected.txt: Added.
  • http/tests/security/module-crossorigin-loads-same-origin.html: Added.
  • http/tests/security/module-crossorigin-onerror-information-expected.txt: Added.
  • http/tests/security/module-crossorigin-onerror-information.html: Added.
  • http/tests/security/module-incorrect-mime-types-expected.txt: Added.
  • http/tests/security/module-incorrect-mime-types.html: Added.
  • http/tests/security/module-no-mime-type-expected.txt: Added.
  • http/tests/security/module-no-mime-type.html: Added.
  • http/tests/security/resources/cors-script.php:
  • http/tests/security/resources/module-local-script.js: Added.
  • js/dom/modules/module-and-dom-content-loaded-expected.txt: Added.
  • js/dom/modules/module-and-dom-content-loaded.html: Added.
  • js/dom/modules/module-and-window-load-expected.txt: Added.
  • js/dom/modules/module-and-window-load.html: Added.
  • js/dom/modules/module-async-and-window-load-expected.txt: Added.
  • js/dom/modules/module-async-and-window-load.html: Added.
  • js/dom/modules/module-document-write-expected.txt: Added.
  • js/dom/modules/module-document-write-src-expected.txt: Added.
  • js/dom/modules/module-document-write-src.html: Added.
  • js/dom/modules/module-document-write.html: Added.
  • js/dom/modules/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror-expected.txt: Added.
  • js/dom/modules/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.html: Added.
  • js/dom/modules/module-execution-error-should-be-propagated-to-onerror-expected.txt: Added.
  • js/dom/modules/module-execution-error-should-be-propagated-to-onerror.html: Added.
  • js/dom/modules/module-execution-order-inline-expected.txt: Added.
  • js/dom/modules/module-execution-order-inline.html: Added.
  • js/dom/modules/module-execution-order-mixed-expected.txt: Added.
  • js/dom/modules/module-execution-order-mixed-with-classic-scripts-expected.txt: Added.
  • js/dom/modules/module-execution-order-mixed-with-classic-scripts.html: Added.
  • js/dom/modules/module-execution-order-mixed.html: Added.
  • js/dom/modules/module-incorrect-relative-specifier-expected.txt: Added.
  • js/dom/modules/module-incorrect-relative-specifier.html: Added.
  • js/dom/modules/module-incorrect-tag-expected.txt: Added.
  • js/dom/modules/module-incorrect-tag.html: Added.
  • js/dom/modules/module-inline-current-script-expected.txt: Added.
  • js/dom/modules/module-inline-current-script.html: Added.
  • js/dom/modules/module-inline-dynamic-expected.txt: Added.
  • js/dom/modules/module-inline-dynamic.html: Added.
  • js/dom/modules/module-inline-simple-expected.txt: Added.
  • js/dom/modules/module-inline-simple.html: Added.
  • js/dom/modules/module-load-event-expected.txt: Added.
  • js/dom/modules/module-load-event-with-src-expected.txt: Added.
  • js/dom/modules/module-load-event-with-src.html: Added.
  • js/dom/modules/module-load-event.html: Added.
  • js/dom/modules/module-load-same-module-from-different-entry-point-dynamic-expected.txt: Added.
  • js/dom/modules/module-load-same-module-from-different-entry-point-dynamic.html: Added.
  • js/dom/modules/module-load-same-module-from-different-entry-point-expected.txt: Added.
  • js/dom/modules/module-load-same-module-from-different-entry-point.html: Added.
  • js/dom/modules/module-not-found-error-event-expected.txt: Added.
  • js/dom/modules/module-not-found-error-event-with-src-and-import-expected.txt: Added.
  • js/dom/modules/module-not-found-error-event-with-src-and-import.html: Added.
  • js/dom/modules/module-not-found-error-event-with-src-expected.txt: Added.
  • js/dom/modules/module-not-found-error-event-with-src.html: Added.
  • js/dom/modules/module-not-found-error-event.html: Added.
  • js/dom/modules/module-src-current-script-expected.txt: Added.
  • js/dom/modules/module-src-current-script.html: Added.
  • js/dom/modules/module-src-dynamic-expected.txt: Added.
  • js/dom/modules/module-src-dynamic.html: Added.
  • js/dom/modules/module-src-simple-expected.txt: Added.
  • js/dom/modules/module-src-simple.html: Added.
  • js/dom/modules/module-type-case-insensitive-expected.txt: Added.
  • js/dom/modules/module-type-case-insensitive.html: Added.
  • js/dom/modules/module-will-fire-beforeload-expected.txt: Added.
  • js/dom/modules/module-will-fire-beforeload.html: Added.
  • js/dom/modules/script-tests/module-document-write-src.js: Added.
  • js/dom/modules/script-tests/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror-throw.js: Added.
  • js/dom/modules/script-tests/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.js: Added.
  • js/dom/modules/script-tests/module-execution-order-mixed-2.js: Added.
  • js/dom/modules/script-tests/module-execution-order-mixed-cappuccino.js: Added.
  • js/dom/modules/script-tests/module-execution-order-mixed-cocoa.js: Added.
  • js/dom/modules/script-tests/module-execution-order-mixed-matcha.js: Added.
  • js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-2.js: Added.
  • js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-cappuccino.js: Added.
  • js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-cocoa.js: Added.
  • js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-matcha.js: Added.
  • js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts.js: Added.
  • js/dom/modules/script-tests/module-execution-order-mixed.js: Added.
  • js/dom/modules/script-tests/module-inline-dynamic.js: Added.

(export.default.Cocoa.prototype.taste):
(export.default.Cocoa):

  • js/dom/modules/script-tests/module-inline-simple.js: Added.

(export.default.Cocoa.prototype.taste):
(export.default.Cocoa):

  • js/dom/modules/script-tests/module-load-event-with-src.js: Added.
  • js/dom/modules/script-tests/module-load-same-module-from-different-entry-point.js: Added.
  • js/dom/modules/script-tests/module-not-found-error-event-with-src-and-import.js: Added.
  • js/dom/modules/script-tests/module-src-current-script.js: Added.
  • js/dom/modules/script-tests/module-src-dynamic-cocoa.js: Added.

(Cocoa.prototype.taste):
(Cocoa):

  • js/dom/modules/script-tests/module-src-dynamic.js: Added.
  • js/dom/modules/script-tests/module-src-simple-cocoa.js: Added.

(Cocoa.prototype.taste):
(Cocoa):

  • js/dom/modules/script-tests/module-src-simple.js: Added.
  • js/dom/modules/script-tests/module-will-fire-beforeload.js: Added.
Location:
trunk
Files:
136 added
31 edited
5 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r208779 r208788  
     12016-11-16  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [ES6] Integrate ES6 Modules into WebCore
     4        https://bugs.webkit.org/show_bug.cgi?id=148897
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        * TestExpectations:
     9        * http/tests/misc/module-absolute-url-expected.txt: Added.
     10        * http/tests/misc/module-absolute-url.html: Added.
     11        * http/tests/misc/module-script-async-expected.txt: Added.
     12        * http/tests/misc/module-script-async.html: Added.
     13        * http/tests/misc/resources/module-absolute-url.js: Added.
     14        * http/tests/misc/resources/module-absolute-url2.js: Added.
     15        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-allowed-expected.txt: Added.
     16        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-allowed.html: Added.
     17        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-and-scripthash-expected.txt: Added.
     18        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-and-scripthash.html: Added.
     19        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-basic-blocked-expected.txt: Added.
     20        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-basic-blocked.html: Added.
     21        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-blocked-expected.txt: Added.
     22        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-blocked.html: Added.
     23        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-ignore-unsafeinline-expected.txt: Added.
     24        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-ignore-unsafeinline.html: Added.
     25        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-in-enforced-policy-and-not-in-report-only-expected.txt: Added.
     26        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-in-enforced-policy-and-not-in-report-only.html: Added.
     27        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-in-one-enforced-policy-neither-in-another-enforced-policy-nor-report-policy-expected.txt: Added.
     28        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-in-one-enforced-policy-neither-in-another-enforced-policy-nor-report-policy.html: Added.
     29        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-invalidnonce-expected.txt: Added.
     30        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-invalidnonce.html: Added.
     31        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-multiple-policies-expected.txt: Added.
     32        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-multiple-policies.html: Added.
     33        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-redirect-expected.txt: Added.
     34        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-redirect-same-origin-expected.txt: Added.
     35        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-redirect-same-origin.html: Added.
     36        * http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-redirect.html: Added.
     37        * http/tests/security/contentSecurityPolicy/1.1/resources/module-scriptnonce-in-enforced-policy-and-not-in-report-only.php: Added.
     38        * http/tests/security/contentSecurityPolicy/1.1/resources/module-scriptnonce-in-one-enforced-policy-neither-in-another-enforced-policy-nor-report-policy.php: Added.
     39        * http/tests/security/contentSecurityPolicy/module-eval-blocked-expected.txt: Added.
     40        * http/tests/security/contentSecurityPolicy/module-eval-blocked-in-external-script-expected.txt: Added.
     41        * http/tests/security/contentSecurityPolicy/module-eval-blocked-in-external-script.html: Added.
     42        * http/tests/security/contentSecurityPolicy/module-eval-blocked.html: Added.
     43        * http/tests/security/contentSecurityPolicy/resources/echo-module-script-src.pl: Added.
     44        * http/tests/security/contentSecurityPolicy/resources/multiple-iframe-module-test.js: Added.
     45        (testPreescapedPolicy):
     46        (testExperimentalPolicy):
     47        (test):
     48        (iframe.onload):
     49        (testImpl):
     50        (finishTesting):
     51        * http/tests/security/module-correct-mime-types-expected.txt: Added.
     52        * http/tests/security/module-correct-mime-types.html: Added.
     53        * http/tests/security/module-crossorigin-error-event-information-expected.txt: Added.
     54        * http/tests/security/module-crossorigin-error-event-information.html: Added.
     55        * http/tests/security/module-crossorigin-loads-correctly-credentials-expected.txt: Added.
     56        * http/tests/security/module-crossorigin-loads-correctly-credentials.html: Added.
     57        * http/tests/security/module-crossorigin-loads-omit-expected.txt: Added.
     58        * http/tests/security/module-crossorigin-loads-omit.html: Added.
     59        * http/tests/security/module-crossorigin-loads-same-origin-expected.txt: Added.
     60        * http/tests/security/module-crossorigin-loads-same-origin.html: Added.
     61        * http/tests/security/module-crossorigin-onerror-information-expected.txt: Added.
     62        * http/tests/security/module-crossorigin-onerror-information.html: Added.
     63        * http/tests/security/module-incorrect-mime-types-expected.txt: Added.
     64        * http/tests/security/module-incorrect-mime-types.html: Added.
     65        * http/tests/security/module-no-mime-type-expected.txt: Added.
     66        * http/tests/security/module-no-mime-type.html: Added.
     67        * http/tests/security/resources/cors-script.php:
     68        * http/tests/security/resources/module-local-script.js: Added.
     69        * js/dom/modules/module-and-dom-content-loaded-expected.txt: Added.
     70        * js/dom/modules/module-and-dom-content-loaded.html: Added.
     71        * js/dom/modules/module-and-window-load-expected.txt: Added.
     72        * js/dom/modules/module-and-window-load.html: Added.
     73        * js/dom/modules/module-async-and-window-load-expected.txt: Added.
     74        * js/dom/modules/module-async-and-window-load.html: Added.
     75        * js/dom/modules/module-document-write-expected.txt: Added.
     76        * js/dom/modules/module-document-write-src-expected.txt: Added.
     77        * js/dom/modules/module-document-write-src.html: Added.
     78        * js/dom/modules/module-document-write.html: Added.
     79        * js/dom/modules/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror-expected.txt: Added.
     80        * js/dom/modules/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.html: Added.
     81        * js/dom/modules/module-execution-error-should-be-propagated-to-onerror-expected.txt: Added.
     82        * js/dom/modules/module-execution-error-should-be-propagated-to-onerror.html: Added.
     83        * js/dom/modules/module-execution-order-inline-expected.txt: Added.
     84        * js/dom/modules/module-execution-order-inline.html: Added.
     85        * js/dom/modules/module-execution-order-mixed-expected.txt: Added.
     86        * js/dom/modules/module-execution-order-mixed-with-classic-scripts-expected.txt: Added.
     87        * js/dom/modules/module-execution-order-mixed-with-classic-scripts.html: Added.
     88        * js/dom/modules/module-execution-order-mixed.html: Added.
     89        * js/dom/modules/module-incorrect-relative-specifier-expected.txt: Added.
     90        * js/dom/modules/module-incorrect-relative-specifier.html: Added.
     91        * js/dom/modules/module-incorrect-tag-expected.txt: Added.
     92        * js/dom/modules/module-incorrect-tag.html: Added.
     93        * js/dom/modules/module-inline-current-script-expected.txt: Added.
     94        * js/dom/modules/module-inline-current-script.html: Added.
     95        * js/dom/modules/module-inline-dynamic-expected.txt: Added.
     96        * js/dom/modules/module-inline-dynamic.html: Added.
     97        * js/dom/modules/module-inline-simple-expected.txt: Added.
     98        * js/dom/modules/module-inline-simple.html: Added.
     99        * js/dom/modules/module-load-event-expected.txt: Added.
     100        * js/dom/modules/module-load-event-with-src-expected.txt: Added.
     101        * js/dom/modules/module-load-event-with-src.html: Added.
     102        * js/dom/modules/module-load-event.html: Added.
     103        * js/dom/modules/module-load-same-module-from-different-entry-point-dynamic-expected.txt: Added.
     104        * js/dom/modules/module-load-same-module-from-different-entry-point-dynamic.html: Added.
     105        * js/dom/modules/module-load-same-module-from-different-entry-point-expected.txt: Added.
     106        * js/dom/modules/module-load-same-module-from-different-entry-point.html: Added.
     107        * js/dom/modules/module-not-found-error-event-expected.txt: Added.
     108        * js/dom/modules/module-not-found-error-event-with-src-and-import-expected.txt: Added.
     109        * js/dom/modules/module-not-found-error-event-with-src-and-import.html: Added.
     110        * js/dom/modules/module-not-found-error-event-with-src-expected.txt: Added.
     111        * js/dom/modules/module-not-found-error-event-with-src.html: Added.
     112        * js/dom/modules/module-not-found-error-event.html: Added.
     113        * js/dom/modules/module-src-current-script-expected.txt: Added.
     114        * js/dom/modules/module-src-current-script.html: Added.
     115        * js/dom/modules/module-src-dynamic-expected.txt: Added.
     116        * js/dom/modules/module-src-dynamic.html: Added.
     117        * js/dom/modules/module-src-simple-expected.txt: Added.
     118        * js/dom/modules/module-src-simple.html: Added.
     119        * js/dom/modules/module-type-case-insensitive-expected.txt: Added.
     120        * js/dom/modules/module-type-case-insensitive.html: Added.
     121        * js/dom/modules/module-will-fire-beforeload-expected.txt: Added.
     122        * js/dom/modules/module-will-fire-beforeload.html: Added.
     123        * js/dom/modules/script-tests/module-document-write-src.js: Added.
     124        * js/dom/modules/script-tests/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror-throw.js: Added.
     125        * js/dom/modules/script-tests/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.js: Added.
     126        * js/dom/modules/script-tests/module-execution-order-mixed-2.js: Added.
     127        * js/dom/modules/script-tests/module-execution-order-mixed-cappuccino.js: Added.
     128        * js/dom/modules/script-tests/module-execution-order-mixed-cocoa.js: Added.
     129        * js/dom/modules/script-tests/module-execution-order-mixed-matcha.js: Added.
     130        * js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-2.js: Added.
     131        * js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-cappuccino.js: Added.
     132        * js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-cocoa.js: Added.
     133        * js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-matcha.js: Added.
     134        * js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts.js: Added.
     135        * js/dom/modules/script-tests/module-execution-order-mixed.js: Added.
     136        * js/dom/modules/script-tests/module-inline-dynamic.js: Added.
     137        (export.default.Cocoa.prototype.taste):
     138        (export.default.Cocoa):
     139        * js/dom/modules/script-tests/module-inline-simple.js: Added.
     140        (export.default.Cocoa.prototype.taste):
     141        (export.default.Cocoa):
     142        * js/dom/modules/script-tests/module-load-event-with-src.js: Added.
     143        * js/dom/modules/script-tests/module-load-same-module-from-different-entry-point.js: Added.
     144        * js/dom/modules/script-tests/module-not-found-error-event-with-src-and-import.js: Added.
     145        * js/dom/modules/script-tests/module-src-current-script.js: Added.
     146        * js/dom/modules/script-tests/module-src-dynamic-cocoa.js: Added.
     147        (Cocoa.prototype.taste):
     148        (Cocoa):
     149        * js/dom/modules/script-tests/module-src-dynamic.js: Added.
     150        * js/dom/modules/script-tests/module-src-simple-cocoa.js: Added.
     151        (Cocoa.prototype.taste):
     152        (Cocoa):
     153        * js/dom/modules/script-tests/module-src-simple.js: Added.
     154        * js/dom/modules/script-tests/module-will-fire-beforeload.js: Added.
     155
    11562016-11-15  Joseph Pecoraro  <pecoraro@apple.com>
    2157
  • trunk/LayoutTests/TestExpectations

    r208771 r208788  
    985985webkit.org/b/164080 http/tests/websocket/tests/hybi/closed-when-entering-page-cache.html [ Pass Failure ]
    986986webkit.org/b/164080 http/tests/websocket/tests/hybi/stop-on-resume-in-error-handler.html [ Pass Failure ]
     987
     988# ES6 Modules are not yet enabled by default: ENABLE(ES6_MODULES)
     989http/tests/misc/module-absolute-url.html [ Skip ]
     990http/tests/misc/module-script-async.html [ Skip ]
     991http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-allowed.html [ Skip ]
     992http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-and-scripthash.html [ Skip ]
     993http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-basic-blocked.html [ Skip ]
     994http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-blocked.html [ Skip ]
     995http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-ignore-unsafeinline.html [ Skip ]
     996http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-in-enforced-policy-and-not-in-report-only.html [ Skip ]
     997http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-in-one-enforced-policy-neither-in-another-enforced-policy-nor-report-policy.html [ Skip ]
     998http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-invalidnonce.html [ Skip ]
     999http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-multiple-policies.html [ Skip ]
     1000http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-redirect-same-origin.html [ Skip ]
     1001http/tests/security/contentSecurityPolicy/1.1/module-scriptnonce-redirect.html [ Skip ]
     1002http/tests/security/contentSecurityPolicy/module-eval-blocked-in-external-script.html [ Skip ]
     1003http/tests/security/contentSecurityPolicy/module-eval-blocked.html [ Skip ]
     1004http/tests/security/module-correct-mime-types.html [ Skip ]
     1005http/tests/security/module-crossorigin-loads-correctly-credentials.html [ Skip ]
     1006http/tests/security/module-crossorigin-loads-omit.html [ Skip ]
     1007http/tests/security/module-crossorigin-loads-same-origin.html [ Skip ]
     1008http/tests/security/module-incorrect-mime-types.html [ Skip ]
     1009http/tests/security/module-no-mime-type.html [ Skip ]
     1010js/dom/modules/module-and-dom-content-loaded.html [ Skip ]
     1011js/dom/modules/module-and-window-load.html [ Skip ]
     1012js/dom/modules/module-async-and-window-load.html [ Skip ]
     1013js/dom/modules/module-document-write-src.html [ Skip ]
     1014js/dom/modules/module-document-write.html [ Skip ]
     1015js/dom/modules/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.html [ Skip ]
     1016js/dom/modules/module-execution-error-should-be-propagated-to-onerror.html [ Skip ]
     1017js/dom/modules/module-execution-order-inline.html [ Skip ]
     1018js/dom/modules/module-execution-order-mixed-with-classic-scripts.html [ Skip ]
     1019js/dom/modules/module-execution-order-mixed.html [ Skip ]
     1020js/dom/modules/module-incorrect-relative-specifier.html [ Skip ]
     1021js/dom/modules/module-incorrect-tag.html [ Skip ]
     1022js/dom/modules/module-inline-current-script.html [ Skip ]
     1023js/dom/modules/module-inline-dynamic.html [ Skip ]
     1024js/dom/modules/module-inline-simple.html [ Skip ]
     1025js/dom/modules/module-load-event-with-src.html [ Skip ]
     1026js/dom/modules/module-load-event.html [ Skip ]
     1027js/dom/modules/module-load-same-module-from-different-entry-point-dynamic.html [ Skip ]
     1028js/dom/modules/module-load-same-module-from-different-entry-point.html [ Skip ]
     1029js/dom/modules/module-not-found-error-event-with-src-and-import.html [ Skip ]
     1030js/dom/modules/module-not-found-error-event-with-src.html [ Skip ]
     1031js/dom/modules/module-not-found-error-event.html [ Skip ]
     1032js/dom/modules/module-src-current-script.html [ Skip ]
     1033js/dom/modules/module-src-dynamic.html [ Skip ]
     1034js/dom/modules/module-src-simple.html [ Skip ]
     1035js/dom/modules/module-type-case-insensitive.html [ Skip ]
     1036js/dom/modules/module-will-fire-beforeload.html [ Skip ]
     1037webkit.org/b/164539 http/tests/security/module-crossorigin-error-event-information.html [ Failure ]
     1038webkit.org/b/164539 http/tests/security/module-crossorigin-onerror-information.html [ Failure ]
  • trunk/LayoutTests/http/tests/security/resources/cors-script.php

    • Property svn:executable set to *
    r205854 r208788  
    33header("Content-Type: application/javascript");
    44
    5 if (strtolower($_GET["credentials"]) == "true") {
    6     header("Access-Control-Allow-Credentials: true");
     5if (isset($_GET["credentials"])) {
     6    if (strtolower($_GET["credentials"]) == "true") {
     7        header("Access-Control-Allow-Credentials: true");
     8    } else {
     9        header("Access-Control-Allow-Credentials: false");
     10    }
    711}
    812
  • trunk/Source/WebCore/CMakeLists.txt

    r208705 r208788  
    10691069
    10701070    bindings/js/ArrayValue.cpp
     1071    bindings/js/CachedModuleScript.cpp
     1072    bindings/js/CachedModuleScriptLoader.cpp
    10711073    bindings/js/CallbackFunction.cpp
    10721074    bindings/js/DOMWrapperWorld.cpp
     
    14661468    dom/LiveNodeList.cpp
    14671469    dom/LoadableClassicScript.cpp
     1470    dom/LoadableModuleScript.cpp
    14681471    dom/LoadableScript.cpp
    14691472    dom/MessageChannel.cpp
  • trunk/Source/WebCore/ChangeLog

    r208786 r208788  
     12016-11-16  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [ES6] Integrate ES6 Modules into WebCore
     4        https://bugs.webkit.org/show_bug.cgi?id=148897
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        This patch introduces ES6 Modules into WebCore. We integrate JSC's JSModuleLoader into WebCore.
     9        JSC constructs the module loader pipeline by the chains of the promises. To handle this,
     10        the following components are added.
     11
     12            1. CachedModuleScript
     13
     14                CachedModuleScript wraps the promise based JSModuleLoader pipeline and offers
     15                similar APIs to CachedScript. ScriptElement and PendingScript interact with
     16                CachedModuleScript when the script tag is the module tag instead of CachedScript.
     17                ScriptElement and PendingScript will receive the notification from
     18                CachedModuleScript by implementing CachedModuleScriptClient.
     19
     20            2. ScriptModuleLoader
     21
     22                This is the module loader instantiated per document. It manages fetching and
     23                offers the callbacks for the JSC's JSModuleLoader implementation. ScriptModuleLoader
     24                will fetch the resource by creating CachedModuleScriptLoader per resource. ScriptModuleLoader
     25                will receive the notification by implementing CachedModuleScriptLoaderClient. When the
     26                resource is fetched, the module loader will drive the promise resolve/reject chain.
     27
     28            3. CachedModuleScriptLoader
     29
     30                This fetches the resource by using CachedScript. Using CachedScript means that it
     31                automatically reports the resource to the inspector. CachedModuleScriptLoader notify to
     32                ScriptModuleLoader when the resource is fetched.
     33
     34        One tricky point is that the fetch requests issued from one module-graph should share the same
     35        nonce, crossorigin attributes etc.
     36
     37            Here, we wrote the module graph like `A -> B (A depends on B)`.
     38
     39            <script tag> -> A -> B -> C -> D
     40
     41        When fetching A, B, C, and D modules, we need to set the same nonce, crossorigin etc. configuration
     42        derived from the original script tag. So per module-graph information should be shared throughout
     43        the module loader pipeline. To do so, JSC's module loader implementation can take the value called
     44        `initiator`. Since the loader will propagate & share this `initiator` throughout the pipeline,
     45        we can transfer and share some metadata. Currently, we pass the JSWrapper of the script tag as the
     46        initiator. Each fetch request is created by using this initiator script element.
     47
     48        More integration into the inspector should be done in the subsequent patch.
     49
     50        * CMakeLists.txt:
     51        * WebCore.xcodeproj/project.pbxproj:
     52        * bindings/js/CachedModuleScript.cpp: Added.
     53        CachedModuleScript offers similar interface to CachedScript to make ScriptElement things easier. It encapsulates the
     54        detail of the JSC JSModuleLoader that this module loader is driven by the chain of the promises. CachedModuleScript's
     55        callbacks are called from the promise's handlers configured in ScriptController::loadModuleScript.
     56        (WebCore::CachedModuleScript::create):
     57        (WebCore::CachedModuleScript::CachedModuleScript):
     58        (WebCore::CachedModuleScript::load):
     59        (WebCore::CachedModuleScript::notifyLoadCompleted):
     60        (WebCore::CachedModuleScript::notifyLoadFailed):
     61        (WebCore::CachedModuleScript::notifyLoadWasCanceled):
     62        (WebCore::CachedModuleScript::notifyClientFinished):
     63        (WebCore::CachedModuleScript::addClient):
     64        (WebCore::CachedModuleScript::removeClient):
     65        * bindings/js/CachedModuleScript.h: Added.
     66        (WebCore::CachedModuleScript::moduleKey):
     67        (WebCore::CachedModuleScript::error):
     68        (WebCore::CachedModuleScript::wasCanceled):
     69        (WebCore::CachedModuleScript::isLoaded):
     70        (WebCore::CachedModuleScript::nonce):
     71        (WebCore::CachedModuleScript::crossOriginMode):
     72        Save nonce and crossorigin attributes when we start ScriptElement::prepareScript.
     73        * bindings/js/CachedModuleScriptClient.h: Copied from Source/WebCore/dom/LoadableScript.h.
     74        (WebCore::CachedModuleScriptClient::~CachedModuleScriptClient):
     75        * bindings/js/CachedModuleScriptLoader.cpp: Added.
     76        CachedModuleScriptLoader is responsible to fetching the resource for the module script. It uses propagated `initiator`
     77        to create the request. This initiator is the JS wrapper of the script element issuing this fetching request. The name
     78        `initiator` is derived from the request.setInitiator(). Once the resource is fetched, the fetcher will notify to the
     79        client. Currently, ScriptModuleLoader implements this client interface.
     80        (WebCore::CachedModuleScriptLoader::create):
     81        (WebCore::CachedModuleScriptLoader::CachedModuleScriptLoader):
     82        (WebCore::CachedModuleScriptLoader::~CachedModuleScriptLoader):
     83        (WebCore::CachedModuleScriptLoader::load):
     84        Create the request. We call ScriptElement::requestCachedScript to initiate a new fetching request. At that time,
     85        nonce and crossorigin (and charset) attributes of this element are applied to the new request.
     86        (WebCore::CachedModuleScriptLoader::notifyFinished):
     87        * bindings/js/CachedModuleScriptLoader.h: Copied from Source/WebCore/bindings/js/ScriptModuleLoader.h.
     88        * bindings/js/CachedModuleScriptLoaderClient.h: Copied from Source/WebCore/dom/LoadableScript.h.
     89        (WebCore::CachedModuleScriptLoaderClient::~CachedModuleScriptLoaderClient):
     90        * bindings/js/CachedScriptSourceProvider.h:
     91        (WebCore::CachedScriptSourceProvider::create):
     92        (WebCore::CachedScriptSourceProvider::CachedScriptSourceProvider):
     93        (WebCore::makeSource):
     94        * bindings/js/JSBindingsAllInOne.cpp:
     95        * bindings/js/JSDOMBinding.cpp:
     96        (WebCore::retrieveErrorMessage):
     97        (WebCore::reportException):
     98        * bindings/js/JSDOMBinding.h:
     99        * bindings/js/JSMainThreadExecState.h:
     100        (WebCore::JSMainThreadExecState::loadModule):
     101        (WebCore::JSMainThreadExecState::linkAndEvaluateModule):
     102        * bindings/js/ScriptController.cpp:
     103        (WebCore::ScriptController::evaluateInWorld):
     104        (WebCore::ScriptController::loadModuleScriptInWorld):
     105        (WebCore::ScriptController::loadModuleScript):
     106        This just performs loading and not executing the module graph. Once the module graph is loaded, it is notified to
     107        the given CachedModuleScript.
     108        (WebCore::ScriptController::linkAndEvaluateModuleScriptInWorld):
     109        (WebCore::ScriptController::linkAndEvaluateModuleScript):
     110        This executes the linking and evaluation of the already instantiated module graph. After loading the module graph,
     111        we call this function for the module to evaluate it. This is called from ScriptElement::executeModuleScript.
     112        (WebCore::ScriptController::evaluateModule):
     113        Every time we evaluate the module, the ScriptModuleLoader::evaluate hook is called. So the loader calls this function
     114        to actually evaluate the module.
     115        (WebCore::jsValueToModuleKey):
     116        (WebCore::ScriptController::setupModuleScriptHandlers):
     117        The JSC's module loader is driven by the chain of the promise. So here, we convert this to CachedModuleScript /
     118        CachedModuleScriptClient style and encapsulate the details. This encapsulation makes CachedModuleScript similar
     119        to CachedScript and it makes things simple in the rest of WebCore. If the propagated error is already reported
     120        to the inspector, we receive moduleLoaderAlreadyReportedErrorSymbol as the error value. So at that case, we
     121        don't report it twice. If the rejection is caused due to the canceled fetching, moduleLoaderFetchingIsCanceledSymbol
     122        appears as the error value. In that case, we will call CachedModuleScript::notifyLoadWasCanceled.
     123        (WebCore::ScriptController::executeScript):
     124        * bindings/js/ScriptController.h:
     125        (WebCore::ScriptController::moduleLoaderAlreadyReportedErrorSymbol):
     126        (WebCore::ScriptController::moduleLoaderFetchingIsCanceledSymbol):
     127        * bindings/js/ScriptModuleLoader.cpp:
     128        We use DeferredWrapper to resolve promises used for the module pipeline. Thus, once the active DOM objects are
     129        suspended, the module loader propagation stops.
     130        (WebCore::ScriptModuleLoader::~ScriptModuleLoader):
     131        Clear the clients of the fetchers issued from this loader.
     132        (WebCore::isRootModule):
     133        (WebCore::ScriptModuleLoader::resolve):
     134        Resolve the module specifier (that is written in `import from "XXX"`) to the unique module key. We use URL
     135        string as module key. The edge case is that the module is inlined one. In that case, we don't have any URL
     136        for that. Instead of URL, we use symbol at that time.
     137        (WebCore::ScriptModuleLoader::fetch):
     138        Start fetching for the requested module. It returns the promise that is resolved when the fetching is done.
     139        The loader creates the fetcher, and the fetcher start loading the resource. Once the fetcher loads the resource,
     140        it notify to the loader through CachedModuleScriptLoaderClient interface. Since we pass the original script
     141        element as the `initiator` here, the fetcher can use this initiator to create the request. While the result of
     142        CachedResource has 3 variations (loaded, canceled, error occurred), Promise only tells us whether it is resolved
     143        or rejected. When CachedModuleScript gets the result from the promise chain, it needs to know which the result is.
     144        To transfer the canceled information, we reject the promise with the special symbol `moduleLoaderAlreadyReportedErrorSymbol`.
     145        This offers the way to distinguish the canceled error from the other errors.
     146        (WebCore::ScriptModuleLoader::evaluate):
     147        This is the hook function that is called when JSC's JSModuleLoader attempts to execute each module.
     148        (WebCore::ScriptModuleLoader::notifyFinished):
     149        This function is called when the fetcher completes. We will resolve the promise with the result of the fetching.
     150        The module loader pipeline is constructed as a chain of promises.
     151        Rejecting a promise when some error occurs is important because the execution flow of
     152        the promise chain is driven by "rejected" or "fulfilled" events.
     153        If the promise is not rejected while error occurs, reject handler won't be executed
     154        and all the subsequent promise chain will wait the result forever.
     155        As a result, even if the error is already reported to the inspector elsewhere,
     156        it should be propagated in the pipeline. For example, the error of loading
     157        CachedResource is already reported to the inspector by the loader. But we still need
     158        to reject the promise to propagate this error to the script element.
     159        At that time, we don't want to report the same error twice. When we propagate the error
     160        that is already reported to the inspector, we throw moduleLoaderAlreadyReportedErrorSymbol
     161        symbol instead. By comparing the thrown error with this symbol, we can distinguish errors raised
     162        when checking syntax of a module script from errors reported already.
     163        In the reject handler of the promise, we only report a error that is not this symbol.
     164        And mime type checking is done here since the module script always require this check.
     165        * bindings/js/ScriptModuleLoader.h:
     166        (WebCore::ScriptModuleLoader::document): Deleted.
     167        * bindings/js/ScriptSourceCode.h:
     168        (WebCore::ScriptSourceCode::ScriptSourceCode):
     169        * dom/CurrentScriptIncrementer.h:
     170        (WebCore::CurrentScriptIncrementer::CurrentScriptIncrementer):
     171        * dom/LoadableClassicScript.cpp:
     172        (WebCore::LoadableClassicScript::error):
     173        (WebCore::LoadableClassicScript::execute):
     174        (WebCore::LoadableClassicScript::wasErrored): Deleted.
     175        * dom/LoadableClassicScript.h:
     176        * dom/LoadableModuleScript.cpp: Copied from Source/WebCore/dom/LoadableScript.h.
     177        This is the derived class from LoadableScript. It is used for the script module graphs.
     178        (WebCore::LoadableModuleScript::create):
     179        (WebCore::LoadableModuleScript::LoadableModuleScript):
     180        (WebCore::LoadableModuleScript::~LoadableModuleScript):
     181        (WebCore::LoadableModuleScript::isLoaded):
     182        (WebCore::LoadableModuleScript::error):
     183        (WebCore::LoadableModuleScript::wasCanceled):
     184        (WebCore::LoadableModuleScript::notifyFinished):
     185        (WebCore::LoadableModuleScript::execute):
     186        * dom/LoadableModuleScript.h: Copied from Source/WebCore/dom/LoadableScript.h.
     187        (isType):
     188        * dom/LoadableScript.h:
     189        (WebCore::LoadableScript::isModuleScript):
     190        (WebCore::LoadableScript::isModuleGraph): Deleted.
     191        * dom/PendingScript.cpp:
     192        (WebCore::PendingScript::error):
     193        (WebCore::PendingScript::wasErrored): Deleted.
     194        * dom/PendingScript.h:
     195        * dom/ScriptElement.cpp:
     196        (WebCore::ScriptElement::ScriptElement):
     197        (WebCore::ScriptElement::determineScriptType):
     198        (WebCore::ScriptElement::prepareScript):
     199        prepareScript is aligned to whatwg spec: the last sequence to setup flags has one-on-one correspondence to
     200        the spec now. And prepareScript recognizes the type="module" case and call the requestModuleScript to setup
     201        the CachedModuleScript.
     202        (WebCore::ScriptElement::requestClassicScript):
     203        (WebCore::ScriptElement::requestModuleScript):
     204        We use the nonce and crossorigin attributes at the time of preparing the script tag. To do so, we store the
     205        above values in CachedModuleScript.
     206        Since inlined module scripts does not have "src" attribute, it is also affected by Content Security Policy's
     207        inline script rules.
     208        (WebCore::ScriptElement::requestScriptWithCacheForModuleScript):
     209        The module loader will construct the fetching request by calling this function. This should be here since we
     210        would like to set this Element to the initiator of the request. And nonce and crossorigin attributes of this
     211        script tag will be used.
     212        (WebCore::ScriptElement::requestScriptWithCache):
     213        (WebCore::ScriptElement::executeScript):
     214        (WebCore::ScriptElement::executeModuleScript):
     215        The entry point to execute the module graph. Since the module graph is beyond the multiple CachedScript code,
     216        we have the different entry point from ScriptElement::executeScript.
     217        (WebCore::ScriptElement::executeScriptAndDispatchEvent):
     218        (WebCore::ScriptElement::executeScriptForScriptRunner):
     219        * dom/ScriptElement.h:
     220        (WebCore::ScriptElement::scriptType):
     221        * html/parser/CSSPreloadScanner.cpp:
     222        (WebCore::CSSPreloadScanner::emitRule):
     223        * html/parser/HTMLPreloadScanner.cpp:
     224        (WebCore::TokenPreloadScanner::StartTagScanner::createPreloadRequest):
     225        According to the spec, the module tag ignores the "charset" attribute as the same to the worker's
     226        importScript. But WebKit supports the "charset" for importScript intentionally. So to be consistent,
     227        even for the module tags, we handle the "charset" attribute. We explicitly note about it in the preloader.
     228        (WebCore::TokenPreloadScanner::StartTagScanner::processAttribute):
     229        * html/parser/HTMLResourcePreloader.cpp:
     230        (WebCore::PreloadRequest::resourceRequest):
     231        * html/parser/HTMLResourcePreloader.h:
     232        (WebCore::PreloadRequest::PreloadRequest):
     233        * html/parser/HTMLScriptRunner.h:
     234        * loader/cache/CachedResourceRequest.cpp:
     235        (WebCore::CachedResourceRequest::setAsPotentiallyCrossOrigin):
     236        * xml/parser/XMLDocumentParser.cpp:
     237        (WebCore::XMLDocumentParser::notifyFinished):
     238
    12392016-11-15  Alejandro G. Castro  <alex@igalia.com>
    2240
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r208705 r208788  
    62596259                E1FF8F6C180DB5BE00132674 /* CryptoAlgorithmRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1FF8F6A180DB5BE00132674 /* CryptoAlgorithmRegistry.cpp */; };
    62606260                E1FF8F6D180DB5BE00132674 /* CryptoAlgorithmRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = E1FF8F6B180DB5BE00132674 /* CryptoAlgorithmRegistry.h */; };
     6261                E307DECC1D81E4B300141CAF /* CachedModuleScript.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E307DEC91D81E46E00141CAF /* CachedModuleScript.cpp */; };
     6262                E307DECD1D81E4B600141CAF /* CachedModuleScript.h in Headers */ = {isa = PBXBuildFile; fileRef = E307DECA1D81E46E00141CAF /* CachedModuleScript.h */; settings = {ATTRIBUTES = (Private, ); }; };
     6263                E307DECE1D81E4BA00141CAF /* CachedModuleScriptClient.h in Headers */ = {isa = PBXBuildFile; fileRef = E307DECB1D81E49500141CAF /* CachedModuleScriptClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
     6264                E307DECF1D81E4C300141CAF /* CachedModuleScriptLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E307DEC61D81E44800141CAF /* CachedModuleScriptLoader.cpp */; };
     6265                E307DED01D81E4C700141CAF /* CachedModuleScriptLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = E307DEC71D81E44800141CAF /* CachedModuleScriptLoader.h */; settings = {ATTRIBUTES = (Private, ); }; };
     6266                E307DED11D81E4CB00141CAF /* CachedModuleScriptLoaderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = E307DEC81D81E44800141CAF /* CachedModuleScriptLoaderClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
     6267                E307DED41D81E4F000141CAF /* LoadableModuleScript.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E307DED21D81E4ED00141CAF /* LoadableModuleScript.cpp */; };
     6268                E307DED51D81E4F200141CAF /* LoadableModuleScript.h in Headers */ = {isa = PBXBuildFile; fileRef = E307DED31D81E4ED00141CAF /* LoadableModuleScript.h */; settings = {ATTRIBUTES = (Private, ); }; };
    62616269                E3150EA61DA7219000194012 /* JSNodeDOMJIT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3AFA9641DA6E908002861BD /* JSNodeDOMJIT.cpp */; };
    62626270                E3150EA71DA7219300194012 /* DOMJITHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = E3150EA51DA7218D00194012 /* DOMJITHelpers.h */; };
     
    1420214210                E1FF8F6A180DB5BE00132674 /* CryptoAlgorithmRegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmRegistry.cpp; sourceTree = "<group>"; };
    1420314211                E1FF8F6B180DB5BE00132674 /* CryptoAlgorithmRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmRegistry.h; sourceTree = "<group>"; };
     14212                E307DEC61D81E44800141CAF /* CachedModuleScriptLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CachedModuleScriptLoader.cpp; sourceTree = "<group>"; };
     14213                E307DEC71D81E44800141CAF /* CachedModuleScriptLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedModuleScriptLoader.h; sourceTree = "<group>"; };
     14214                E307DEC81D81E44800141CAF /* CachedModuleScriptLoaderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedModuleScriptLoaderClient.h; sourceTree = "<group>"; };
     14215                E307DEC91D81E46E00141CAF /* CachedModuleScript.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CachedModuleScript.cpp; sourceTree = "<group>"; };
     14216                E307DECA1D81E46E00141CAF /* CachedModuleScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedModuleScript.h; sourceTree = "<group>"; };
     14217                E307DECB1D81E49500141CAF /* CachedModuleScriptClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedModuleScriptClient.h; sourceTree = "<group>"; };
     14218                E307DED21D81E4ED00141CAF /* LoadableModuleScript.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LoadableModuleScript.cpp; sourceTree = "<group>"; };
     14219                E307DED31D81E4ED00141CAF /* LoadableModuleScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadableModuleScript.h; sourceTree = "<group>"; };
    1420414220                E3150EA51DA7218D00194012 /* DOMJITHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITHelpers.h; sourceTree = "<group>"; };
    1420514221                E334825E1DC93AA0009C9544 /* DOMJITAbstractHeapRepository.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITAbstractHeapRepository.h; sourceTree = "<group>"; };
     
    2178221798                                49B3760B15C6C6840059131D /* ArrayValue.h */,
    2178321799                                2DFA488E1DB541C200362B99 /* BufferSource.h */,
     21800                                E307DEC61D81E44800141CAF /* CachedModuleScriptLoader.cpp */,
     21801                                E307DEC71D81E44800141CAF /* CachedModuleScriptLoader.h */,
     21802                                E307DEC81D81E44800141CAF /* CachedModuleScriptLoaderClient.h */,
    2178421803                                BCD533630ED6848900887468 /* CachedScriptSourceProvider.h */,
    2178521804                                93F8B3060A300FEA00F61AB8 /* CodeGeneratorJS.pm */,
     
    2186221881                                E38838941BAD145F00D62EE3 /* ScriptModuleLoader.cpp */,
    2186321882                                E38838951BAD145F00D62EE3 /* ScriptModuleLoader.h */,
     21883                                E307DEC91D81E46E00141CAF /* CachedModuleScript.cpp */,
     21884                                E307DECA1D81E46E00141CAF /* CachedModuleScript.h */,
     21885                                E307DECB1D81E49500141CAF /* CachedModuleScriptClient.h */,
    2186421886                                934CC1090EDB223900A658F2 /* ScriptSourceCode.h */,
    2186521887                                4127D5360F8AAB1D00E424F5 /* ScriptState.cpp */,
     
    2400424026                                E3B2F0E91D7F3D3C00B0C9D1 /* LoadableScript.cpp */,
    2400524027                                E3B2F0E71D7F35EC00B0C9D1 /* LoadableScript.h */,
     24028                                E307DED21D81E4ED00141CAF /* LoadableModuleScript.cpp */,
     24029                                E307DED31D81E4ED00141CAF /* LoadableModuleScript.h */,
    2400624030                                E3B2F0E81D7F35EC00B0C9D1 /* LoadableScriptClient.h */,
    2400724031                                BC9A6144146859D9006057FD /* make_dom_exceptions.pl */,
     
    2491124935                                7C3A91E61C963B8800D1A7E3 /* ClipboardAccessPolicy.h in Headers */,
    2491224936                                85031B400A44EFC700F992E0 /* ClipboardEvent.h in Headers */,
     24937                                E307DED01D81E4C700141CAF /* CachedModuleScriptLoader.h in Headers */,
    2491324938                                FB92DF4B15FED08700994433 /* ClipPathOperation.h in Headers */,
    2491424939                                580371621A66F00A00BAF519 /* ClipRect.h in Headers */,
     
    2572525750                                510A58FA1BACC7F200C19282 /* IDBRequestData.h in Headers */,
    2572625751                                5145B10A1BC48E2E00E86219 /* IDBResourceIdentifier.h in Headers */,
     25752                                E307DED11D81E4CB00141CAF /* CachedModuleScriptLoaderClient.h in Headers */,
    2572725753                                51D7236D1BB6174900478CA3 /* IDBResultData.h in Headers */,
    2572825754                                511EC1281C50AACA0032F983 /* IDBSerialization.h in Headers */,
     
    2597426000                                2E37E00612DBC5A400A6B233 /* JSDOMURL.h in Headers */,
    2597526001                                BC6932740D7E293900AE44D1 /* JSDOMWindowBase.h in Headers */,
     26002                                E307DECE1D81E4BA00141CAF /* CachedModuleScriptClient.h in Headers */,
    2597626003                                652FBBBC0DE27CB60001D386 /* JSDOMWindowCustom.h in Headers */,
    2597726004                                460CBF361D4BCD0E0092E88E /* JSDOMWindowProperties.h in Headers */,
     
    2685426881                                2D5C9D0019C7B52E00B3C5C1 /* PageOverlay.h in Headers */,
    2685526882                                2D5C9D0219C7B52E00B3C5C1 /* PageOverlayController.h in Headers */,
     26883                                E307DED51D81E4F200141CAF /* LoadableModuleScript.h in Headers */,
    2685626884                                FBDB61A116D6037E00BB3394 /* PageRuleCollector.h in Headers */,
    2685726885                                F3820895147D35F90010BC06 /* PageRuntimeAgent.h in Headers */,
     
    2749527523                                E1B25107152A0BB00069B779 /* StylePropertyShorthand.h in Headers */,
    2749627524                                83C05A5B1A686212007E5DEA /* StylePropertyShorthandFunctions.h in Headers */,
     27525                                E307DECD1D81E4B600141CAF /* CachedModuleScript.h in Headers */,
    2749727526                                BC2272E40E82EE9B00E7F975 /* StyleRareInheritedData.h in Headers */,
    2749827527                                BC2272BD0E82EAAE00E7F975 /* StyleRareNonInheritedData.h in Headers */,
     
    2894128970                                9444CBD91D88483A0073A074 /* CSSVariableParser.cpp in Sources */,
    2894228971                                9444CBE91D8861CA0073A074 /* CSSVariableReferenceValue.cpp in Sources */,
     28972                                E307DECF1D81E4C300141CAF /* CachedModuleScriptLoader.cpp in Sources */,
    2894328973                                BC1790C01BBF2C430006D13E /* CSSVariableValue.cpp in Sources */,
    2894428974                                E11AF15111B9A1A300805103 /* Cursor.cpp in Sources */,
     
    2944229472                                5185FCA31BB4C4E80012898F /* IDBOpenDBRequest.cpp in Sources */,
    2944329473                                5185FCA81BB4C4E80012898F /* IDBRequest.cpp in Sources */,
     29474                                E307DECC1D81E4B300141CAF /* CachedModuleScript.cpp in Sources */,
    2944429475                                514129981C6976900059E714 /* IDBRequestCompletionEvent.cpp in Sources */,
    2944529476                                510A58F91BACC7F200C19282 /* IDBRequestData.cpp in Sources */,
     
    3008530116                                8542A79A0AE5C94400DF58DF /* JSSVGElementWrapperFactory.cpp in Sources */,
    3008630117                                B2FA3D680AB75A6F000E5AC4 /* JSSVGEllipseElement.cpp in Sources */,
     30118                                E307DED41D81E4F000141CAF /* LoadableModuleScript.cpp in Sources */,
    3008730119                                B266CD4D0C3AEC6500EB08D2 /* JSSVGException.cpp in Sources */,
    3008830120                                B2FA3D6A0AB75A6F000E5AC4 /* JSSVGFEBlendElement.cpp in Sources */,
  • trunk/Source/WebCore/bindings/js/CachedModuleScriptClient.h

    r208787 r208788  
    2626#pragma once
    2727
    28 #include <runtime/ConsoleTypes.h>
    29 #include <wtf/HashCountedSet.h>
    30 #include <wtf/RefCounted.h>
    31 #include <wtf/text/WTFString.h>
    32 
    3328namespace WebCore {
    3429
    35 class LoadableScriptClient;
    36 class ScriptElement;
     30class CachedModuleScript;
    3731
    38 class LoadableScript : public RefCounted<LoadableScript> {
     32class CachedModuleScriptClient {
    3933public:
    40     enum class ErrorType {
    41         CachedScript,
    42         CrossOriginLoad,
    43         Nosniff,
    44     };
     34    virtual ~CachedModuleScriptClient() { }
    4535
    46     struct ConsoleMessage {
    47         MessageSource source;
    48         MessageLevel level;
    49         String message;
    50     };
    51 
    52     struct Error {
    53         ErrorType type;
    54         Optional<ConsoleMessage> consoleMessage;
    55     };
    56 
    57     virtual ~LoadableScript() { }
    58 
    59     virtual bool isLoaded() const = 0;
    60     virtual Optional<Error> wasErrored() const = 0;
    61     virtual bool wasCanceled() const = 0;
    62 
    63     virtual void execute(ScriptElement&) = 0;
    64 
    65     void addClient(LoadableScriptClient&);
    66     void removeClient(LoadableScriptClient&);
    67 
    68     virtual bool isClassicScript() const { return false; }
    69     virtual bool isModuleGraph() const { return false; }
    70 
    71 protected:
    72     void notifyClientFinished();
    73 
    74 private:
    75     HashCountedSet<LoadableScriptClient*> m_clients;
     36    virtual void notifyFinished(CachedModuleScript&) = 0;
    7637};
    7738
  • trunk/Source/WebCore/bindings/js/CachedModuleScriptLoader.h

    r208787 r208788  
    2626#pragma once
    2727
    28 #include <runtime/JSCJSValue.h>
    29 #include <wtf/Noncopyable.h>
    30 
    31 namespace JSC {
    32 
    33 class ExecState;
    34 class JSGlobalObject;
    35 class JSInternalPromise;
    36 class JSModuleLoader;
    37 
    38 }
     28#include "CachedResourceClient.h"
     29#include "CachedResourceHandle.h"
     30#include <wtf/Ref.h>
     31#include <wtf/RefCounted.h>
     32#include <wtf/RefPtr.h>
    3933
    4034namespace WebCore {
    4135
    42 class Document;
     36class CachedModuleScriptLoaderClient;
     37class CachedScript;
     38class DeferredPromise;
     39class JSDOMGlobalObject;
     40class ScriptElement;
     41class URL;
    4342
    44 class ScriptModuleLoader {
    45     WTF_MAKE_NONCOPYABLE(ScriptModuleLoader); WTF_MAKE_FAST_ALLOCATED;
     43class CachedModuleScriptLoader final : public RefCounted<CachedModuleScriptLoader>, private CachedResourceClient {
    4644public:
    47     explicit ScriptModuleLoader(Document&);
     45    static Ref<CachedModuleScriptLoader> create(CachedModuleScriptLoaderClient&, DeferredPromise&);
    4846
    49     Document& document() { return m_document; }
     47    virtual ~CachedModuleScriptLoader();
    5048
    51     JSC::JSInternalPromise* resolve(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue moduleName, JSC::JSValue importerModuleKey, JSC::JSValue initiator);
    52     JSC::JSInternalPromise* fetch(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue moduleKey, JSC::JSValue initiator);
    53     JSC::JSValue evaluate(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue moduleKey, JSC::JSValue moduleRecord, JSC::JSValue initiator);
     49    bool load(ScriptElement&, const URL& sourceURL);
     50
     51    CachedScript* cachedScript() { return m_cachedScript.get(); }
     52
     53    void clearClient()
     54    {
     55        ASSERT(m_client);
     56        m_client = nullptr;
     57    }
    5458
    5559private:
    56     Document& m_document;
     60    CachedModuleScriptLoader(CachedModuleScriptLoaderClient&, DeferredPromise&);
     61
     62    void notifyFinished(CachedResource&) final;
     63
     64    CachedModuleScriptLoaderClient* m_client { nullptr };
     65    RefPtr<DeferredPromise> m_promise;
     66    CachedResourceHandle<CachedScript> m_cachedScript;
    5767};
    5868
  • trunk/Source/WebCore/bindings/js/CachedModuleScriptLoaderClient.h

    r208787 r208788  
    2626#pragma once
    2727
    28 #include <runtime/ConsoleTypes.h>
    29 #include <wtf/HashCountedSet.h>
    30 #include <wtf/RefCounted.h>
    31 #include <wtf/text/WTFString.h>
     28#include "JSDOMPromise.h"
    3229
    3330namespace WebCore {
    3431
    35 class LoadableScriptClient;
    36 class ScriptElement;
     32class CachedModuleScriptLoader;
    3733
    38 class LoadableScript : public RefCounted<LoadableScript> {
     34class CachedModuleScriptLoaderClient {
    3935public:
    40     enum class ErrorType {
    41         CachedScript,
    42         CrossOriginLoad,
    43         Nosniff,
    44     };
     36    virtual ~CachedModuleScriptLoaderClient() { }
    4537
    46     struct ConsoleMessage {
    47         MessageSource source;
    48         MessageLevel level;
    49         String message;
    50     };
    51 
    52     struct Error {
    53         ErrorType type;
    54         Optional<ConsoleMessage> consoleMessage;
    55     };
    56 
    57     virtual ~LoadableScript() { }
    58 
    59     virtual bool isLoaded() const = 0;
    60     virtual Optional<Error> wasErrored() const = 0;
    61     virtual bool wasCanceled() const = 0;
    62 
    63     virtual void execute(ScriptElement&) = 0;
    64 
    65     void addClient(LoadableScriptClient&);
    66     void removeClient(LoadableScriptClient&);
    67 
    68     virtual bool isClassicScript() const { return false; }
    69     virtual bool isModuleGraph() const { return false; }
    70 
    71 protected:
    72     void notifyClientFinished();
    73 
    74 private:
    75     HashCountedSet<LoadableScriptClient*> m_clients;
     38    virtual void notifyFinished(CachedModuleScriptLoader&, RefPtr<DeferredPromise>) = 0;
    7639};
    7740
  • trunk/Source/WebCore/bindings/js/CachedScriptSourceProvider.h

    r208179 r208788  
    3737    WTF_MAKE_FAST_ALLOCATED;
    3838public:
    39     static Ref<CachedScriptSourceProvider> create(CachedScript* cachedScript) { return adoptRef(*new CachedScriptSourceProvider(cachedScript)); }
     39    static Ref<CachedScriptSourceProvider> create(CachedScript* cachedScript, JSC::SourceProviderSourceType sourceType) { return adoptRef(*new CachedScriptSourceProvider(cachedScript, sourceType)); }
    4040
    4141    virtual ~CachedScriptSourceProvider()
     
    4848
    4949private:
    50     CachedScriptSourceProvider(CachedScript* cachedScript)
    51         : SourceProvider(cachedScript->response().url(), TextPosition::minimumPosition(), JSC::SourceProviderSourceType::Program)
     50    CachedScriptSourceProvider(CachedScript* cachedScript, JSC::SourceProviderSourceType sourceType)
     51        : SourceProvider(cachedScript->response().url(), TextPosition::minimumPosition(), sourceType)
    5252        , m_cachedScript(cachedScript)
    5353    {
     
    6060inline JSC::SourceCode makeSource(CachedScript* cachedScript)
    6161{
    62     return JSC::SourceCode(CachedScriptSourceProvider::create(cachedScript));
     62    return JSC::SourceCode(CachedScriptSourceProvider::create(cachedScript, JSC::SourceProviderSourceType::Program));
    6363}
    6464
  • trunk/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp

    r208705 r208788  
    2727
    2828#include "ArrayValue.cpp"
     29#include "CachedModuleScript.cpp"
     30#include "CachedModuleScriptLoader.cpp"
    2931#include "CallbackFunction.cpp"
    3032#include "DOMWrapperWorld.cpp"
  • trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp

    r208124 r208788  
    157157}
    158158
     159String retrieveErrorMessage(ExecState& state, VM& vm, JSValue exception, CatchScope& catchScope)
     160{
     161    if (auto* exceptionBase = toExceptionBase(exception))
     162        return exceptionBase->toString();
     163
     164    // FIXME: <http://webkit.org/b/115087> Web Inspector: WebCore::reportException should not evaluate JavaScript handling exceptions
     165    // If this is a custom exception object, call toString on it to try and get a nice string representation for the exception.
     166    String errorMessage;
     167    if (auto* error = jsDynamicDowncast<ErrorInstance*>(exception))
     168        errorMessage = error->sanitizedToString(&state);
     169    else
     170        errorMessage = exception.toWTFString(&state);
     171
     172    // We need to clear any new exception that may be thrown in the toString() call above.
     173    // reportException() is not supposed to be making new exceptions.
     174    catchScope.clearException();
     175    vm.clearLastException();
     176    return errorMessage;
     177}
     178
    159179void reportException(ExecState* exec, JSC::Exception* exception, CachedScript* cachedScript, ExceptionDetails* exceptionDetails)
    160180{
     
    187207    }
    188208
    189     String errorMessage;
    190     JSValue exceptionValue = exception->value();
    191     if (ExceptionBase* exceptionBase = toExceptionBase(exceptionValue))
    192         errorMessage = exceptionBase->toString();
    193     else {
    194         // FIXME: <http://webkit.org/b/115087> Web Inspector: WebCore::reportException should not evaluate JavaScript handling exceptions
    195         // If this is a custom exception object, call toString on it to try and get a nice string representation for the exception.
    196         if (ErrorInstance* error = jsDynamicDowncast<ErrorInstance*>(exceptionValue))
    197             errorMessage = error->sanitizedToString(exec);
    198         else
    199             errorMessage = exceptionValue.toString(exec)->value(exec);
    200 
    201         // We need to clear any new exception that may be thrown in the toString() call above.
    202         // reportException() is not supposed to be making new exceptions.
    203         scope.clearException();
    204         vm.clearLastException();
    205     }
    206 
     209    String errorMessage = retrieveErrorMessage(*exec, vm, exception->value(), scope);
    207210    ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext();
    208211    scriptExecutionContext->reportException(errorMessage, lineNumber, columnNumber, exceptionSourceURL, exception, callStack->size() ? callStack : nullptr, cachedScript);
  • trunk/Source/WebCore/bindings/js/JSDOMBinding.h

    r208209 r208788  
    183183const JSC::HashTable& getHashTableForGlobalData(JSC::VM&, const JSC::HashTable& staticTable);
    184184
     185String retrieveErrorMessage(JSC::ExecState&, JSC::VM&, JSC::JSValue exception, JSC::CatchScope&);
    185186WEBCORE_EXPORT void reportException(JSC::ExecState*, JSC::JSValue exception, CachedScript* = nullptr);
    186187WEBCORE_EXPORT void reportException(JSC::ExecState*, JSC::Exception*, CachedScript* = nullptr, ExceptionDetails* = nullptr);
  • trunk/Source/WebCore/bindings/js/JSMainThreadExecState.h

    r208256 r208788  
    9494    }
    9595
    96     static JSC::JSInternalPromise* loadModule(JSC::ExecState* exec, const String& moduleName, JSC::JSValue initiator)
     96    static JSC::JSInternalPromise& loadModule(JSC::ExecState& state, const String& moduleName, JSC::JSValue initiator)
    9797    {
    98         JSMainThreadExecState currentState(exec);
    99         return JSC::loadModule(exec, moduleName, initiator);
     98        JSMainThreadExecState currentState(&state);
     99        return *JSC::loadModule(&state, moduleName, initiator);
    100100    }
    101101
    102     static JSC::JSInternalPromise* loadModule(JSC::ExecState* exec, const JSC::SourceCode& sourceCode, JSC::JSValue initiator)
     102    static JSC::JSInternalPromise& loadModule(JSC::ExecState& state, const JSC::SourceCode& sourceCode, JSC::JSValue initiator)
    103103    {
    104         JSMainThreadExecState currentState(exec);
    105         return JSC::loadModule(exec, sourceCode, initiator);
     104        JSMainThreadExecState currentState(&state);
     105        return *JSC::loadModule(&state, sourceCode, initiator);
    106106    }
    107107
    108     static JSC::JSValue linkAndEvaluateModule(JSC::ExecState* exec, const JSC::Identifier& moduleKey, JSC::JSValue initiator, NakedPtr<JSC::Exception>& returnedException)
     108    static JSC::JSValue linkAndEvaluateModule(JSC::ExecState& state, const JSC::Identifier& moduleKey, JSC::JSValue initiator, NakedPtr<JSC::Exception>& returnedException)
    109109    {
    110         JSC::VM& vm = exec->vm();
     110        JSC::VM& vm = state.vm();
    111111        auto scope = DECLARE_CATCH_SCOPE(vm);
    112112   
    113         JSMainThreadExecState currentState(exec);
    114         JSC::JSValue returnValue = JSC::linkAndEvaluateModule(exec, moduleKey, initiator);
     113        JSMainThreadExecState currentState(&state);
     114        auto returnValue = JSC::linkAndEvaluateModule(&state, moduleKey, initiator);
    115115        if (UNLIKELY(scope.exception())) {
    116116            returnedException = scope.exception();
  • trunk/Source/WebCore/bindings/js/ScriptController.cpp

    r208112 r208788  
    2323
    2424#include "BridgeJSC.h"
     25#include "CachedModuleScript.h"
    2526#include "ContentSecurityPolicy.h"
    2627#include "DocumentLoader.h"
     
    4243#include "PageGroup.h"
    4344#include "PluginViewBase.h"
     45#include "ScriptElement.h"
    4446#include "ScriptSourceCode.h"
    4547#include "ScriptableDocumentParser.h"
     
    5355#include <inspector/ScriptCallStack.h>
    5456#include <runtime/InitializeThreading.h>
     57#include <runtime/JSFunction.h>
     58#include <runtime/JSInternalPromise.h>
    5559#include <runtime/JSLock.h>
     60#include <runtime/JSModuleRecord.h>
     61#include <runtime/JSNativeStdFunction.h>
     62#include <wtf/TemporaryChange.h>
    5663#include <wtf/Threading.h>
    5764#include <wtf/text/TextPosition.h>
     
    155162    m_sourceURL = &sourceURL;
    156163
    157     Ref<Frame> protect(m_frame);
     164    Ref<Frame> protector(m_frame);
    158165
    159166    InspectorInstrumentationCookie cookie = InspectorInstrumentation::willEvaluateScript(m_frame, sourceURL, sourceCode.startLine());
     
    177184{
    178185    return evaluateInWorld(sourceCode, mainThreadNormalWorld(), exceptionDetails);
     186}
     187
     188void ScriptController::loadModuleScriptInWorld(CachedModuleScript& moduleScript, const String& moduleName, DOMWrapperWorld& world, Element& element)
     189{
     190    JSLockHolder lock(world.vm());
     191
     192    auto& shell = *windowShell(world);
     193    auto& state = *shell.window()->globalExec();
     194
     195    auto& promise = JSMainThreadExecState::loadModule(state, moduleName, toJS(&state, shell.window(), &element));
     196    setupModuleScriptHandlers(moduleScript, promise, world);
     197}
     198
     199void ScriptController::loadModuleScript(CachedModuleScript& moduleScript, const String& moduleName, Element& element)
     200{
     201    loadModuleScriptInWorld(moduleScript, moduleName, mainThreadNormalWorld(), element);
     202}
     203
     204void ScriptController::loadModuleScriptInWorld(CachedModuleScript& moduleScript, const ScriptSourceCode& sourceCode, DOMWrapperWorld& world, Element& element)
     205{
     206    JSLockHolder lock(world.vm());
     207
     208    auto& shell = *windowShell(world);
     209    auto& state = *shell.window()->globalExec();
     210
     211    auto& promise = JSMainThreadExecState::loadModule(state, sourceCode.jsSourceCode(), toJS(&state, shell.window(), &element));
     212    setupModuleScriptHandlers(moduleScript, promise, world);
     213}
     214
     215void ScriptController::loadModuleScript(CachedModuleScript& moduleScript, const ScriptSourceCode& sourceCode, Element& element)
     216{
     217    loadModuleScriptInWorld(moduleScript, sourceCode, mainThreadNormalWorld(), element);
     218}
     219
     220JSC::JSValue ScriptController::linkAndEvaluateModuleScriptInWorld(CachedModuleScript& moduleScript, DOMWrapperWorld& world, Element& element)
     221{
     222    JSLockHolder lock(world.vm());
     223
     224    auto& shell = *windowShell(world);
     225    auto& state = *shell.window()->globalExec();
     226
     227    // FIXME: Preventing Frame from being destroyed is essentially unnecessary.
     228    // https://bugs.webkit.org/show_bug.cgi?id=164763
     229    Ref<Frame> protector(m_frame);
     230
     231    NakedPtr<JSC::Exception> evaluationException;
     232    auto returnValue = JSMainThreadExecState::linkAndEvaluateModule(state, Identifier::fromUid(&state.vm(), moduleScript.moduleKey()), toJS(&state, shell.window(), &element), evaluationException);
     233    if (evaluationException) {
     234        // FIXME: Give a chance to dump the stack trace if the "crossorigin" attribute allows.
     235        // https://bugs.webkit.org/show_bug.cgi?id=164539
     236        reportException(&state, evaluationException, nullptr);
     237        return jsUndefined();
     238    }
     239    return returnValue;
     240}
     241
     242JSC::JSValue ScriptController::linkAndEvaluateModuleScript(CachedModuleScript& moduleScript, Element& element)
     243{
     244    return linkAndEvaluateModuleScriptInWorld(moduleScript, mainThreadNormalWorld(), element);
     245}
     246
     247JSC::JSValue ScriptController::evaluateModule(const URL& sourceURL, JSModuleRecord& moduleRecord, DOMWrapperWorld& world)
     248{
     249    JSLockHolder lock(world.vm());
     250
     251    const auto& jsSourceCode = moduleRecord.sourceCode();
     252
     253    auto& shell = *windowShell(world);
     254    auto& state = *shell.window()->globalExec();
     255    TemporaryChange<const String*> sourceURLScope(m_sourceURL, &sourceURL.string());
     256
     257    Ref<Frame> protector(m_frame);
     258
     259    auto cookie = InspectorInstrumentation::willEvaluateScript(m_frame, sourceURL, jsSourceCode.firstLine());
     260
     261    auto returnValue = moduleRecord.evaluate(&state);
     262    InspectorInstrumentation::didEvaluateScript(cookie, m_frame);
     263
     264    return returnValue;
     265}
     266
     267JSC::JSValue ScriptController::evaluateModule(const URL& sourceURL, JSModuleRecord& moduleRecord)
     268{
     269    return evaluateModule(sourceURL, moduleRecord, mainThreadNormalWorld());
    179270}
    180271
     
    257348
    258349    return &windowShell;
     350}
     351
     352static Identifier jsValueToModuleKey(ExecState* exec, JSValue value)
     353{
     354    if (value.isSymbol())
     355        return Identifier::fromUid(jsCast<Symbol*>(value)->privateName());
     356    ASSERT(value.isString());
     357    return Identifier::fromString(exec, jsCast<JSString*>(value)->value(exec));
     358}
     359
     360void ScriptController::setupModuleScriptHandlers(CachedModuleScript& moduleScriptRef, JSInternalPromise& promise, DOMWrapperWorld& world)
     361{
     362    auto& shell = *windowShell(world);
     363    auto& state = *shell.window()->globalExec();
     364
     365    // It is not guaranteed that either fulfillHandler or rejectHandler is eventually called.
     366    // For example, if the page load is canceled, the DeferredPromise used in the module loader pipeline will stop executing JS code.
     367    // Thus the promise returned from this function could remain unresolved.
     368
     369    JSC::PrivateName moduleLoaderAlreadyReportedErrorSymbol = m_moduleLoaderAlreadyReportedErrorSymbol;
     370    JSC::PrivateName moduleLoaderFetchingIsCanceledSymbol = m_moduleLoaderFetchingIsCanceledSymbol;
     371
     372    RefPtr<CachedModuleScript> moduleScript(&moduleScriptRef);
     373
     374    auto& fulfillHandler = *JSNativeStdFunction::create(state.vm(), shell.window(), 1, String(), [moduleScript](ExecState* exec) {
     375        Identifier moduleKey = jsValueToModuleKey(exec, exec->argument(0));
     376        moduleScript->notifyLoadCompleted(*moduleKey.impl());
     377        return JSValue::encode(jsUndefined());
     378    });
     379
     380    auto& rejectHandler = *JSNativeStdFunction::create(state.vm(), shell.window(), 1, String(), [moduleScript, moduleLoaderAlreadyReportedErrorSymbol, moduleLoaderFetchingIsCanceledSymbol](ExecState* exec) {
     381        JSValue error = exec->argument(0);
     382        if (auto* symbol = jsDynamicCast<Symbol*>(error)) {
     383            if (symbol->privateName() == moduleLoaderAlreadyReportedErrorSymbol) {
     384                moduleScript->notifyLoadFailed(LoadableScript::Error {
     385                    LoadableScript::ErrorType::CachedScript,
     386                    Nullopt
     387                });
     388                return JSValue::encode(jsUndefined());
     389            }
     390
     391            if (symbol->privateName() == moduleLoaderFetchingIsCanceledSymbol) {
     392                moduleScript->notifyLoadWasCanceled();
     393                return JSValue::encode(jsUndefined());
     394            }
     395        }
     396
     397        VM& vm = exec->vm();
     398        auto scope = DECLARE_CATCH_SCOPE(vm);
     399        moduleScript->notifyLoadFailed(LoadableScript::Error {
     400            LoadableScript::ErrorType::CachedScript,
     401            LoadableScript::ConsoleMessage {
     402                MessageSource::JS,
     403                MessageLevel::Error,
     404                retrieveErrorMessage(*exec, vm, error, scope),
     405            }
     406        });
     407        return JSValue::encode(jsUndefined());
     408    });
     409
     410    promise.then(&state, &fulfillHandler, &rejectHandler);
    259411}
    260412
     
    521673        return { }; // FIXME: Would jsNull be better?
    522674
    523     Ref<Frame> protect(m_frame); // Script execution can destroy the frame, and thus the ScriptController.
     675    // FIXME: Preventing Frame from being destroyed is essentially unnecessary.
     676    // https://bugs.webkit.org/show_bug.cgi?id=164763
     677    Ref<Frame> protector(m_frame); // Script execution can destroy the frame, and thus the ScriptController.
    524678
    525679    return evaluate(sourceCode, exceptionDetails);
  • trunk/Source/WebCore/bindings/js/ScriptController.h

    r208179 r208788  
    4343
    4444namespace JSC {
     45class ExecState;
    4546class JSGlobalObject;
    46 class ExecState;
     47class JSInternalPromise;
     48class JSModuleRecord;
    4749
    4850namespace Bindings {
     
    5456namespace WebCore {
    5557
     58class CachedModuleScript;
    5659class Frame;
    5760class HTMLDocument;
    5861class HTMLPlugInElement;
     62class SecurityOrigin;
    5963class ScriptSourceCode;
    60 class SecurityOrigin;
    6164class Widget;
    6265
     
    115118    JSC::JSValue evaluateInWorld(const ScriptSourceCode&, DOMWrapperWorld&, ExceptionDetails* = nullptr);
    116119
     120    void loadModuleScriptInWorld(CachedModuleScript&, const String& moduleName, DOMWrapperWorld&, Element&);
     121    void loadModuleScript(CachedModuleScript&, const String& moduleName, Element&);
     122    void loadModuleScriptInWorld(CachedModuleScript&, const ScriptSourceCode&, DOMWrapperWorld&, Element&);
     123    void loadModuleScript(CachedModuleScript&, const ScriptSourceCode&, Element&);
     124
     125    JSC::JSValue linkAndEvaluateModuleScriptInWorld(CachedModuleScript& , DOMWrapperWorld&, Element&);
     126    JSC::JSValue linkAndEvaluateModuleScript(CachedModuleScript&, Element&);
     127
     128    JSC::JSValue evaluateModule(const URL&, JSC::JSModuleRecord&, DOMWrapperWorld&);
     129    JSC::JSValue evaluateModule(const URL&, JSC::JSModuleRecord&);
     130
    117131    WTF::TextPosition eventHandlerPosition() const;
    118132
     
    134148
    135149    const String* sourceURL() const { return m_sourceURL; } // 0 if we are not evaluating any script
     150
     151    const JSC::PrivateName& moduleLoaderAlreadyReportedErrorSymbol() const { return m_moduleLoaderAlreadyReportedErrorSymbol; }
     152    const JSC::PrivateName& moduleLoaderFetchingIsCanceledSymbol() const { return m_moduleLoaderFetchingIsCanceledSymbol; }
    136153
    137154    void clearWindowShell(DOMWindow* newDOMWindow, bool goingIntoPageCache);
     
    167184private:
    168185    WEBCORE_EXPORT JSDOMWindowShell* initScript(DOMWrapperWorld&);
     186    void setupModuleScriptHandlers(CachedModuleScript&, JSC::JSInternalPromise&, DOMWrapperWorld&);
    169187
    170188    void disconnectPlatformScriptObjects();
     
    175193
    176194    bool m_paused;
     195    JSC::PrivateName m_moduleLoaderAlreadyReportedErrorSymbol;
     196    JSC::PrivateName m_moduleLoaderFetchingIsCanceledSymbol;
    177197
    178198    // The root object used for objects bound outside the context of a plugin, such
  • trunk/Source/WebCore/bindings/js/ScriptModuleLoader.cpp

    r208688 r208788  
    2727#include "ScriptModuleLoader.h"
    2828
     29#include "CachedModuleScriptLoader.h"
     30#include "CachedScript.h"
    2931#include "Document.h"
    3032#include "Frame.h"
    3133#include "JSDOMBinding.h"
     34#include "JSElement.h"
     35#include "LoadableModuleScript.h"
     36#include "MIMETypeRegistry.h"
     37#include "ScriptController.h"
     38#include "ScriptElement.h"
     39#include "ScriptSourceCode.h"
     40#include <runtime/JSInternalPromise.h>
    3241#include <runtime/JSInternalPromiseDeferred.h>
    3342#include <runtime/JSModuleRecord.h>
     
    4251}
    4352
    44 JSC::JSInternalPromise* ScriptModuleLoader::resolve(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader*, JSC::JSValue moduleNameValue, JSC::JSValue importerModuleKey, JSC::JSValue)
    45 {
    46     JSC::JSInternalPromiseDeferred* deferred = JSC::JSInternalPromiseDeferred::create(exec, globalObject);
     53ScriptModuleLoader::~ScriptModuleLoader()
     54{
     55    for (auto& loader : m_loaders)
     56        const_cast<CachedModuleScriptLoader&>(loader.get()).clearClient();
     57}
     58
     59
     60static bool isRootModule(JSC::JSValue importerModuleKey)
     61{
     62    return importerModuleKey.isSymbol() || importerModuleKey.isUndefined();
     63}
     64
     65JSC::JSInternalPromise* ScriptModuleLoader::resolve(JSC::JSGlobalObject* jsGlobalObject, JSC::ExecState* exec, JSC::JSModuleLoader*, JSC::JSValue moduleNameValue, JSC::JSValue importerModuleKey, JSC::JSValue)
     66{
     67    auto& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(jsGlobalObject);
     68    auto& jsPromise = *JSC::JSInternalPromiseDeferred::create(exec, &globalObject);
     69    auto promise = DeferredPromise::create(globalObject, jsPromise);
    4770
    4871    // We use a Symbol as a special purpose; It means this module is an inline module.
    4972    // So there is no correct URL to retrieve the module source code. If the module name
    5073    // value is a Symbol, it is used directly as a module key.
    51     //
    52     // FIXME: Using symbols for an inline module is a current implementation details of WebKit.
    53     // Once the spec of this part is specified, we will recast these part.
    54     if (moduleNameValue.isSymbol())
    55         return deferred->resolve(exec, moduleNameValue);
    56 
    57     if (!moduleNameValue.isString())
    58         return deferred->reject(exec, JSC::createTypeError(exec, "Module name is not Symbol or String."));
    59 
    60     String moduleName = asString(moduleNameValue)->value(exec);
    61 
    62     // Now, we consider the given moduleName as the same to the `import "..."` in the module code.
    63     // We use the completed URL as the unique module key.
    64     URL completedUrl;
    65 
    66     if (importerModuleKey.isSymbol())
    67         completedUrl = m_document.completeURL(moduleName);
    68     else if (importerModuleKey.isUndefined())
    69         completedUrl = m_document.completeURL(moduleName);
     74    if (moduleNameValue.isSymbol()) {
     75        promise->resolve(asSymbol(moduleNameValue)->privateName());
     76        return jsPromise.promise();
     77    }
     78
     79    // https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier
     80
     81    if (!moduleNameValue.isString()) {
     82        promise->reject(TypeError, ASCIILiteral("Module specifier is not Symbol or String."));
     83        return jsPromise.promise();
     84    }
     85
     86    String specifier = asString(moduleNameValue)->value(exec);
     87
     88    // 1. Apply the URL parser to specifier. If the result is not failure, return the result.
     89    URL absoluteURL(URL(), specifier);
     90    if (absoluteURL.isValid()) {
     91        promise->resolve(absoluteURL.string());
     92        return jsPromise.promise();
     93    }
     94
     95    // 2. If specifier does not start with the character U+002F SOLIDUS (/), the two-character sequence U+002E FULL STOP, U+002F SOLIDUS (./),
     96    //    or the three-character sequence U+002E FULL STOP, U+002E FULL STOP, U+002F SOLIDUS (../), return failure and abort these steps.
     97    if (!specifier.startsWith('/') && !specifier.startsWith("./") && !specifier.startsWith("../")) {
     98        promise->reject(TypeError, ASCIILiteral("Module specifier does not start with \"/\", \"./\", or \"../\"."));
     99        return jsPromise.promise();
     100    }
     101
     102    // 3. Return the result of applying the URL parser to specifier with script's base URL as the base URL.
     103
     104    URL completedURL;
     105
     106    if (isRootModule(importerModuleKey))
     107        completedURL = m_document.completeURL(specifier);
    70108    else if (importerModuleKey.isString()) {
    71         URL importerModuleUrl(URL(), asString(importerModuleKey)->value(exec));
    72         if (!importerModuleUrl.isValid())
    73             return deferred->reject(exec, JSC::createTypeError(exec, "Importer module key is an invalid URL."));
    74         completedUrl = m_document.completeURL(moduleName, importerModuleUrl);
    75     } else
    76         return deferred->reject(exec, JSC::createTypeError(exec, "Importer module key is not Symbol or String."));
    77 
    78     if (!completedUrl.isValid())
    79         return deferred->reject(exec, JSC::createTypeError(exec, "Module name constructs an invalid URL."));
    80 
    81     return deferred->resolve(exec, jsString(exec, completedUrl.string()));
    82 }
    83 
    84 JSC::JSInternalPromise* ScriptModuleLoader::fetch(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader*, JSC::JSValue moduleKeyValue, JSC::JSValue)
    85 {
    86     JSC::JSInternalPromiseDeferred* deferred = JSC::JSInternalPromiseDeferred::create(exec, globalObject);
    87 
    88     if (moduleKeyValue.isSymbol())
    89         return deferred->reject(exec, JSC::createTypeError(exec, "Symbol module key should be already fulfilled with the inlined resource."));
    90 
    91     if (!moduleKeyValue.isString())
    92         return deferred->reject(exec, JSC::createTypeError(exec, "Module key is not Symbol or String."));
    93 
    94     URL completedUrl(URL(), asString(moduleKeyValue)->value(exec));
    95     if (!completedUrl.isValid())
    96         return deferred->reject(exec, JSC::createTypeError(exec, "Module key is an invalid URL."));
    97 
    98     // FIXME: Implement the module fetcher.
    99 
    100     return deferred->promise();
     109        URL importerModuleRequestURL(URL(), asString(importerModuleKey)->value(exec));
     110        if (!importerModuleRequestURL.isValid()) {
     111            promise->reject(TypeError, ASCIILiteral("Importer module key is an invalid URL."));
     112            return jsPromise.promise();
     113        }
     114
     115        URL importerModuleResponseURL = m_requestURLToResponseURLMap.get(importerModuleRequestURL);
     116        if (!importerModuleResponseURL.isValid()) {
     117            promise->reject(TypeError, ASCIILiteral("Importer module has an invalid response URL."));
     118            return jsPromise.promise();
     119        }
     120
     121        completedURL = m_document.completeURL(specifier, importerModuleResponseURL);
     122    } else {
     123        promise->reject(TypeError, ASCIILiteral("Importer module key is not Symbol or String."));
     124        return jsPromise.promise();
     125    }
     126
     127    if (!completedURL.isValid()) {
     128        promise->reject(TypeError, ASCIILiteral("Module name constructs an invalid URL."));
     129        return jsPromise.promise();
     130    }
     131
     132    promise->resolve(completedURL.string());
     133    return jsPromise.promise();
     134}
     135
     136JSC::JSInternalPromise* ScriptModuleLoader::fetch(JSC::JSGlobalObject* jsGlobalObject, JSC::ExecState* exec, JSC::JSModuleLoader*, JSC::JSValue moduleKeyValue, JSC::JSValue initiator)
     137{
     138    auto& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(jsGlobalObject);
     139    auto& jsPromise = *JSC::JSInternalPromiseDeferred::create(exec, &globalObject);
     140    auto deferred = DeferredPromise::create(globalObject, jsPromise);
     141    if (moduleKeyValue.isSymbol()) {
     142        deferred->reject(TypeError, ASCIILiteral("Symbol module key should be already fulfilled with the inlined resource."));
     143        return jsPromise.promise();
     144    }
     145
     146    if (!moduleKeyValue.isString()) {
     147        deferred->reject(TypeError, ASCIILiteral("Module key is not Symbol or String."));
     148        return jsPromise.promise();
     149    }
     150
     151    // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script
     152
     153    URL completedURL(URL(), asString(moduleKeyValue)->value(exec));
     154    if (!completedURL.isValid()) {
     155        deferred->reject(TypeError, ASCIILiteral("Module key is a valid URL."));
     156        return jsPromise.promise();
     157    }
     158
     159    ASSERT_WITH_MESSAGE(JSC::jsDynamicCast<JSElement*>(initiator), "Initiator should be an JSElement");
     160    auto* scriptElement = toScriptElementIfPossible(&JSC::jsCast<JSElement*>(initiator)->wrapped());
     161    ASSERT_WITH_MESSAGE(scriptElement, "Initiator should be ScriptElement.");
     162
     163    if (auto* frame = m_document.frame()) {
     164        auto loader = CachedModuleScriptLoader::create(*this, deferred.get());
     165        m_loaders.add(loader.copyRef());
     166        if (!loader->load(*scriptElement, completedURL)) {
     167            loader->clearClient();
     168            m_loaders.remove(WTFMove(loader));
     169
     170            deferred->reject(frame->script().moduleLoaderAlreadyReportedErrorSymbol());
     171            return jsPromise.promise();
     172        }
     173    }
     174
     175    return jsPromise.promise();
    101176}
    102177
     
    109184    // Once the reflective part of the module loader is supported, we will handle arbitrary values.
    110185    // https://whatwg.github.io/loader/#registry-prototype-provide
    111     JSC::JSModuleRecord* moduleRecord = jsDynamicDowncast<JSC::JSModuleRecord*>(moduleRecordValue);
     186    auto* moduleRecord = jsDynamicDowncast<JSC::JSModuleRecord*>(moduleRecordValue);
    112187    if (!moduleRecord)
    113188        return JSC::jsUndefined();
    114189
    115     URL sourceUrl;
     190    URL sourceURL;
    116191    if (moduleKeyValue.isSymbol())
    117         sourceUrl = m_document.url();
     192        sourceURL = m_document.url();
    118193    else if (moduleKeyValue.isString())
    119         sourceUrl = URL(URL(), asString(moduleKeyValue)->value(exec));
     194        sourceURL = URL(URL(), asString(moduleKeyValue)->value(exec));
    120195    else
    121196        return JSC::throwTypeError(exec, scope, ASCIILiteral("Module key is not Symbol or String."));
    122197
    123     if (!sourceUrl.isValid())
     198    if (!sourceURL.isValid())
    124199        return JSC::throwTypeError(exec, scope, ASCIILiteral("Module key is an invalid URL."));
    125200
    126     // FIXME: Implement evaluating module code.
    127 
     201    if (auto* frame = m_document.frame())
     202        return frame->script().evaluateModule(sourceURL, *moduleRecord);
    128203    return JSC::jsUndefined();
    129204}
    130205
    131 }
     206void ScriptModuleLoader::notifyFinished(CachedModuleScriptLoader& loader, RefPtr<DeferredPromise> promise)
     207{
     208    // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script
     209
     210    if (!m_loaders.remove(&loader))
     211        return;
     212    loader.clearClient();
     213
     214    auto& cachedScript = *loader.cachedScript();
     215
     216    bool failed = false;
     217
     218    if (cachedScript.resourceError().isAccessControl()) {
     219        promise->reject(TypeError, ASCIILiteral("Cross-origin script load denied by Cross-Origin Resource Sharing policy."));
     220        return;
     221    }
     222
     223    if (cachedScript.errorOccurred())
     224        failed = true;
     225    else if (!MIMETypeRegistry::isSupportedJavaScriptMIMEType(cachedScript.response().mimeType())) {
     226        // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script
     227        // The result of extracting a MIME type from response's header list (ignoring parameters) is not a JavaScript MIME type.
     228        // For historical reasons, fetching a classic script does not include MIME type checking. In contrast, module scripts will fail to load if they are not of a correct MIME type.
     229        promise->reject(TypeError, makeString("'", cachedScript.response().mimeType(), "' is not a valid JavaScript MIME type."));
     230        return;
     231    }
     232
     233    auto* frame = m_document.frame();
     234    if (!frame)
     235        return;
     236
     237    if (failed) {
     238        // Reject a promise to propagate the error back all the way through module promise chains to the script element.
     239        promise->reject(frame->script().moduleLoaderAlreadyReportedErrorSymbol());
     240        return;
     241    }
     242
     243    if (cachedScript.wasCanceled()) {
     244        promise->reject(frame->script().moduleLoaderFetchingIsCanceledSymbol());
     245        return;
     246    }
     247
     248    m_requestURLToResponseURLMap.add(cachedScript.url(), cachedScript.response().url());
     249    // FIXME: Let's wrap around ScriptSourceCode to propagate it directly through the module pipeline.
     250    promise->resolve(ScriptSourceCode(&cachedScript, JSC::SourceProviderSourceType::Module).source().toString());
     251}
     252
     253}
  • trunk/Source/WebCore/bindings/js/ScriptModuleLoader.h

    r205278 r208788  
    2626#pragma once
    2727
     28#include "CachedModuleScriptLoader.h"
     29#include "CachedModuleScriptLoaderClient.h"
     30#include "URL.h"
     31#include "URLHash.h"
    2832#include <runtime/JSCJSValue.h>
    2933#include <wtf/Noncopyable.h>
     
    4145
    4246class Document;
     47class JSDOMGlobalObject;
    4348
    44 class ScriptModuleLoader {
     49class ScriptModuleLoader final : private CachedModuleScriptLoaderClient {
    4550    WTF_MAKE_NONCOPYABLE(ScriptModuleLoader); WTF_MAKE_FAST_ALLOCATED;
    4651public:
    4752    explicit ScriptModuleLoader(Document&);
     53    ~ScriptModuleLoader();
    4854
    4955    Document& document() { return m_document; }
     
    5460
    5561private:
     62    void notifyFinished(CachedModuleScriptLoader&, RefPtr<DeferredPromise>) final;
     63
    5664    Document& m_document;
     65    HashMap<URL, URL> m_requestURLToResponseURLMap;
     66    HashSet<Ref<CachedModuleScriptLoader>> m_loaders;
    5767};
    5868
  • trunk/Source/WebCore/bindings/js/ScriptSourceCode.h

    r208179 r208788  
    4343class ScriptSourceCode {
    4444public:
    45     ScriptSourceCode(const String& source, const URL& url = URL(), const TextPosition& startPosition = TextPosition::minimumPosition())
    46         : m_provider(JSC::StringSourceProvider::create(source, url.isNull() ? String() : url.string(), startPosition))
     45    ScriptSourceCode(const String& source, const URL& url = URL(), const TextPosition& startPosition = TextPosition::minimumPosition(), JSC::SourceProviderSourceType sourceType = JSC::SourceProviderSourceType::Program)
     46        : m_provider(JSC::StringSourceProvider::create(source, url.isNull() ? String() : url.string(), startPosition, sourceType))
    4747        , m_code(m_provider, startPosition.m_line.oneBasedInt(), startPosition.m_column.oneBasedInt())
    4848        , m_url(url)
     
    5050    }
    5151
    52     explicit ScriptSourceCode(CachedScript* cachedScript)
    53         : m_provider(CachedScriptSourceProvider::create(cachedScript))
     52    explicit ScriptSourceCode(CachedScript* cachedScript, JSC::SourceProviderSourceType sourceType)
     53        : m_provider(CachedScriptSourceProvider::create(cachedScript, sourceType))
    5454        , m_code(m_provider)
    5555        , m_cachedScript(cachedScript)
  • trunk/Source/WebCore/dom/CurrentScriptIncrementer.h

    r208660 r208788  
    4444            return;
    4545        auto& scriptElement = downcast<HTMLScriptElement>(element);
    46         m_document.pushCurrentScript(scriptElement.isInShadowTree() ? nullptr : &scriptElement);
     46        bool shouldPushNullForCurrentScript = scriptElement.isInShadowTree() || scriptElement.scriptType() == ScriptElement::ScriptType::Module;
     47        m_document.pushCurrentScript(shouldPushNullForCurrentScript ? nullptr : &scriptElement);
    4748    }
    4849
  • trunk/Source/WebCore/dom/LoadableClassicScript.cpp

    r206903 r208788  
    5252}
    5353
    54 Optional<LoadableScript::Error> LoadableClassicScript::wasErrored() const
     54Optional<LoadableScript::Error> LoadableClassicScript::error() const
    5555{
    5656    if (m_error)
     
    102102void LoadableClassicScript::execute(ScriptElement& scriptElement)
    103103{
    104     ASSERT(!wasErrored());
    105     scriptElement.executeScript(ScriptSourceCode(m_cachedScript.get()));
     104    ASSERT(!error());
     105    scriptElement.executeScript(ScriptSourceCode(m_cachedScript.get(), JSC::SourceProviderSourceType::Program));
    106106}
    107107
  • trunk/Source/WebCore/dom/LoadableClassicScript.h

    r206903 r208788  
    4141class LoadableClassicScript final : public LoadableScript, private CachedResourceClient {
    4242public:
    43     ~LoadableClassicScript();
     43    virtual ~LoadableClassicScript();
    4444
    4545    static Ref<LoadableClassicScript> create(CachedResourceHandle<CachedScript>&&);
    46     bool isLoaded() const override;
    47     Optional<Error> wasErrored() const override;
    48     bool wasCanceled() const override;
     46    bool isLoaded() const final;
     47    Optional<Error> error() const final;
     48    bool wasCanceled() const final;
    4949
    5050    CachedScript& cachedScript() { return *m_cachedScript; }
    5151    bool isClassicScript() const final { return true; }
    5252
    53     void execute(ScriptElement&) override;
     53    void execute(ScriptElement&) final;
    5454
    5555private:
  • trunk/Source/WebCore/dom/LoadableModuleScript.cpp

    r208787 r208788  
    2424 */
    2525
    26 #pragma once
     26#include "config.h"
     27#include "LoadableModuleScript.h"
    2728
    28 #include <runtime/ConsoleTypes.h>
    29 #include <wtf/HashCountedSet.h>
    30 #include <wtf/RefCounted.h>
    31 #include <wtf/text/WTFString.h>
     29#include "ScriptElement.h"
    3230
    3331namespace WebCore {
    3432
    35 class LoadableScriptClient;
    36 class ScriptElement;
     33Ref<LoadableModuleScript> LoadableModuleScript::create(CachedModuleScript& moduleScript)
     34{
     35    auto script = adoptRef(*new LoadableModuleScript(moduleScript));
     36    moduleScript.addClient(script.get());
     37    return script;
     38}
    3739
    38 class LoadableScript : public RefCounted<LoadableScript> {
    39 public:
    40     enum class ErrorType {
    41         CachedScript,
    42         CrossOriginLoad,
    43         Nosniff,
    44     };
     40LoadableModuleScript::LoadableModuleScript(CachedModuleScript& moduleScript)
     41    : m_moduleScript(moduleScript)
     42{
     43}
    4544
    46     struct ConsoleMessage {
    47         MessageSource source;
    48         MessageLevel level;
    49         String message;
    50     };
     45LoadableModuleScript::~LoadableModuleScript()
     46{
     47    m_moduleScript->removeClient(*this);
     48}
    5149
    52     struct Error {
    53         ErrorType type;
    54         Optional<ConsoleMessage> consoleMessage;
    55     };
     50bool LoadableModuleScript::isLoaded() const
     51{
     52    return m_moduleScript->isLoaded();
     53}
    5654
    57     virtual ~LoadableScript() { }
     55Optional<LoadableScript::Error> LoadableModuleScript::error() const
     56{
     57    return m_moduleScript->error();
     58}
    5859
    59     virtual bool isLoaded() const = 0;
    60     virtual Optional<Error> wasErrored() const = 0;
    61     virtual bool wasCanceled() const = 0;
     60bool LoadableModuleScript::wasCanceled() const
     61{
     62    return m_moduleScript->wasCanceled();
     63}
    6264
    63     virtual void execute(ScriptElement&) = 0;
     65void LoadableModuleScript::notifyFinished(CachedModuleScript&)
     66{
     67    notifyClientFinished();
     68}
    6469
    65     void addClient(LoadableScriptClient&);
    66     void removeClient(LoadableScriptClient&);
    67 
    68     virtual bool isClassicScript() const { return false; }
    69     virtual bool isModuleGraph() const { return false; }
    70 
    71 protected:
    72     void notifyClientFinished();
    73 
    74 private:
    75     HashCountedSet<LoadableScriptClient*> m_clients;
    76 };
     70void LoadableModuleScript::execute(ScriptElement& scriptElement)
     71{
     72    scriptElement.executeModuleScript(m_moduleScript.get());
     73}
    7774
    7875}
  • trunk/Source/WebCore/dom/LoadableModuleScript.h

    r208787 r208788  
    2626#pragma once
    2727
    28 #include <runtime/ConsoleTypes.h>
    29 #include <wtf/HashCountedSet.h>
    30 #include <wtf/RefCounted.h>
    31 #include <wtf/text/WTFString.h>
     28#include "CachedModuleScript.h"
     29#include "CachedModuleScriptClient.h"
     30#include "LoadableScript.h"
     31#include <wtf/TypeCasts.h>
    3232
    3333namespace WebCore {
    3434
    35 class LoadableScriptClient;
    36 class ScriptElement;
     35class LoadableModuleScript final : public LoadableScript, private CachedModuleScriptClient {
     36public:
     37    virtual ~LoadableModuleScript();
    3738
    38 class LoadableScript : public RefCounted<LoadableScript> {
    39 public:
    40     enum class ErrorType {
    41         CachedScript,
    42         CrossOriginLoad,
    43         Nosniff,
    44     };
     39    static Ref<LoadableModuleScript> create(CachedModuleScript&);
    4540
    46     struct ConsoleMessage {
    47         MessageSource source;
    48         MessageLevel level;
    49         String message;
    50     };
     41    bool isLoaded() const final;
     42    Optional<Error> error() const final;
     43    bool wasCanceled() const final;
    5144
    52     struct Error {
    53         ErrorType type;
    54         Optional<ConsoleMessage> consoleMessage;
    55     };
     45    CachedModuleScript& moduleScript() { return m_moduleScript.get(); }
     46    bool isModuleScript() const final { return true; }
    5647
    57     virtual ~LoadableScript() { }
     48    void execute(ScriptElement&) final;
    5849
    59     virtual bool isLoaded() const = 0;
    60     virtual Optional<Error> wasErrored() const = 0;
    61     virtual bool wasCanceled() const = 0;
    62 
    63     virtual void execute(ScriptElement&) = 0;
    64 
    65     void addClient(LoadableScriptClient&);
    66     void removeClient(LoadableScriptClient&);
    67 
    68     virtual bool isClassicScript() const { return false; }
    69     virtual bool isModuleGraph() const { return false; }
    70 
    71 protected:
    72     void notifyClientFinished();
     50    void setError(Error&&);
    7351
    7452private:
    75     HashCountedSet<LoadableScriptClient*> m_clients;
     53    LoadableModuleScript(CachedModuleScript&);
     54
     55    void notifyFinished(CachedModuleScript&) final;
     56
     57    Ref<CachedModuleScript> m_moduleScript;
    7658};
    7759
    7860}
     61
     62SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::LoadableModuleScript)
     63    static bool isType(const WebCore::LoadableScript& script) { return script.isModuleScript(); }
     64SPECIALIZE_TYPE_TRAITS_END()
  • trunk/Source/WebCore/dom/LoadableScript.h

    r205581 r208788  
    5858
    5959    virtual bool isLoaded() const = 0;
    60     virtual Optional<Error> wasErrored() const = 0;
     60    virtual Optional<Error> error() const = 0;
    6161    virtual bool wasCanceled() const = 0;
    6262
     
    6767
    6868    virtual bool isClassicScript() const { return false; }
    69     virtual bool isModuleGraph() const { return false; }
     69    virtual bool isModuleScript() const { return false; }
    7070
    7171protected:
  • trunk/Source/WebCore/dom/PendingScript.cpp

    r205581 r208788  
    8484}
    8585
    86 bool PendingScript::wasErrored() const
     86bool PendingScript::error() const
    8787{
    88     return m_loadableScript && m_loadableScript->wasErrored();
     88    return m_loadableScript && m_loadableScript->error();
    8989}
    9090
  • trunk/Source/WebCore/dom/PendingScript.h

    r205581 r208788  
    5959
    6060    bool isLoaded() const;
    61     bool wasErrored() const;
     61    bool error() const;
    6262
    6363    void notifyFinished(LoadableScript&) override;
  • trunk/Source/WebCore/dom/ScriptElement.cpp

    r208112 r208788  
    2525#include "ScriptElement.h"
    2626
     27#include "CachedModuleScript.h"
    2728#include "CachedResourceLoader.h"
    2829#include "CachedResourceRequest.h"
     
    3940#include "IgnoreDestructiveWriteCountIncrementer.h"
    4041#include "LoadableClassicScript.h"
     42#include "LoadableModuleScript.h"
    4143#include "MIMETypeRegistry.h"
    4244#include "Page.h"
     
    6971    , m_forceAsync(!parserInserted)
    7072    , m_willExecuteInOrder(false)
     73    , m_isModuleScript(false)
    7174{
    7275    if (parserInserted && m_element.document().scriptableDocumentParser() && !m_element.document().isInDocumentWrite())
     
    192195        return false;
    193196
    194     if (!determineScriptType(supportLegacyTypes))
    195         return false;
     197    ScriptType scriptType = ScriptType::Classic;
     198    if (Optional<ScriptType> result = determineScriptType(supportLegacyTypes))
     199        scriptType = result.value();
     200    else
     201        return false;
     202    m_isModuleScript = scriptType == ScriptType::Module;
    196203
    197204    if (wasParserInserted) {
     
    214221        return false;
    215222
    216     if (!isScriptForEventSupported())
    217         return false;
    218 
     223    if (scriptType == ScriptType::Classic && !isScriptForEventSupported())
     224        return false;
     225
     226    // According to the spec, the module tag ignores the "charset" attribute as the same to the worker's
     227    // importScript. But WebKit supports the "charset" for importScript intentionally. So to be consistent,
     228    // even for the module tags, we handle the "charset" attribute.
    219229    if (!charsetAttributeValue().isEmpty())
    220230        m_characterEncoding = charsetAttributeValue();
     
    222232        m_characterEncoding = document.charset();
    223233
    224     if (hasSourceAttribute()) {
    225         if (!requestClassicScript(sourceAttributeValue()))
    226             return false;
    227     }
    228 
    229     if (hasSourceAttribute() && deferAttributeValue() && m_parserInserted && !asyncAttributeValue()) {
     234    if (scriptType == ScriptType::Classic) {
     235        if (hasSourceAttribute()) {
     236            if (!requestClassicScript(sourceAttributeValue()))
     237                return false;
     238        }
     239    } else {
     240        ASSERT(scriptType == ScriptType::Module);
     241        if (!requestModuleScript(scriptStartPosition))
     242            return false;
     243    }
     244
     245    // All the inlined module script is handled by requestModuleScript. It produces LoadableModuleScript and inlined module script
     246    // is handled as the same to the external module script.
     247
     248    bool isClassicExternalScript = scriptType == ScriptType::Classic && hasSourceAttribute();
     249    bool isParserInsertedDeferredScript = ((isClassicExternalScript && deferAttributeValue()) || scriptType == ScriptType::Module)
     250        && m_parserInserted && !asyncAttributeValue();
     251    if (isParserInsertedDeferredScript) {
    230252        m_willExecuteWhenDocumentFinishedParsing = true;
    231253        m_willBeParserExecuted = true;
    232     } else if (hasSourceAttribute() && m_parserInserted && !asyncAttributeValue())
     254    } else if (isClassicExternalScript && m_parserInserted && !asyncAttributeValue()) {
     255        ASSERT(scriptType == ScriptType::Classic);
    233256        m_willBeParserExecuted = true;
    234     else if (!hasSourceAttribute() && m_parserInserted && !document.haveStylesheetsLoaded()) {
     257    } else if ((isClassicExternalScript || scriptType == ScriptType::Module) && !asyncAttributeValue() && !m_forceAsync) {
     258        m_willExecuteInOrder = true;
     259        ASSERT(m_loadableScript);
     260        document.scriptRunner()->queueScriptForExecution(this, *m_loadableScript, ScriptRunner::IN_ORDER_EXECUTION);
     261    } else if (hasSourceAttribute() || scriptType == ScriptType::Module) {
     262        ASSERT(m_loadableScript);
     263        ASSERT(asyncAttributeValue() || m_forceAsync);
     264        document.scriptRunner()->queueScriptForExecution(this, *m_loadableScript, ScriptRunner::ASYNC_EXECUTION);
     265    } else if (!hasSourceAttribute() && m_parserInserted && !document.haveStylesheetsLoaded()) {
     266        ASSERT(scriptType == ScriptType::Classic);
    235267        m_willBeParserExecuted = true;
    236268        m_readyToBeParserExecuted = true;
    237     } else if (hasSourceAttribute() && !asyncAttributeValue() && !m_forceAsync) {
    238         ASSERT(m_loadableScript);
    239         m_willExecuteInOrder = true;
    240         document.scriptRunner()->queueScriptForExecution(this, *m_loadableScript, ScriptRunner::IN_ORDER_EXECUTION);
    241     } else if (hasSourceAttribute()) {
    242         ASSERT(m_loadableScript);
    243         m_element.document().scriptRunner()->queueScriptForExecution(this, *m_loadableScript, ScriptRunner::ASYNC_EXECUTION);
    244269    } else {
    245         // Reset line numbering for nested writes.
     270        ASSERT(scriptType == ScriptType::Classic);
    246271        TextPosition position = document.isInDocumentWrite() ? TextPosition() : scriptStartPosition;
    247         executeScript(ScriptSourceCode(scriptContent(), document.url(), position));
     272        executeScript(ScriptSourceCode(scriptContent(), document.url(), position, JSC::SourceProviderSourceType::Program));
    248273    }
    249274
     
    262287    ASSERT(!m_loadableScript);
    263288    if (!stripLeadingAndTrailingHTMLSpaces(sourceURL).isEmpty()) {
    264         auto request = requestScriptWithCache(m_element.document().completeURL(sourceURL), m_element.attributeWithoutSynchronization(HTMLNames::nonceAttr));
     289        String nonceAttribute = m_element.attributeWithoutSynchronization(HTMLNames::nonceAttr);
     290        String crossOriginMode = m_element.attributeWithoutSynchronization(HTMLNames::crossoriginAttr);
     291        auto request = requestScriptWithCache(m_element.document().completeURL(sourceURL), nonceAttribute, crossOriginMode);
    265292        if (request) {
    266293            m_loadableScript = LoadableClassicScript::create(WTFMove(request));
     
    278305}
    279306
    280 CachedResourceHandle<CachedScript> ScriptElement::requestScriptWithCache(const URL& sourceURL, const String& nonceAttribute)
     307bool ScriptElement::requestModuleScript(const TextPosition& scriptStartPosition)
     308{
     309    String nonce = m_element.attributeWithoutSynchronization(HTMLNames::nonceAttr);
     310    String crossOriginMode = m_element.attributeWithoutSynchronization(HTMLNames::crossoriginAttr);
     311    if (crossOriginMode.isNull())
     312        crossOriginMode = ASCIILiteral("omit");
     313
     314    if (hasSourceAttribute()) {
     315        String sourceURL = sourceAttributeValue();
     316        Ref<Document> originalDocument(m_element.document());
     317        if (!m_element.dispatchBeforeLoadEvent(sourceURL))
     318            return false;
     319
     320        bool didEventListenerDisconnectThisElement = !m_element.inDocument() || &m_element.document() != originalDocument.ptr();
     321        if (didEventListenerDisconnectThisElement)
     322            return false;
     323
     324        if (stripLeadingAndTrailingHTMLSpaces(sourceURL).isEmpty()) {
     325            dispatchErrorEvent();
     326            return false;
     327        }
     328
     329        auto moduleScriptRootURL = m_element.document().completeURL(sourceURL);
     330        if (!moduleScriptRootURL.isValid()) {
     331            dispatchErrorEvent();
     332            return false;
     333        }
     334
     335        m_isExternalScript = true;
     336        auto moduleScript = CachedModuleScript::create(nonce, crossOriginMode);
     337        m_loadableScript = LoadableModuleScript::create(moduleScript.get());
     338        moduleScript->load(m_element, moduleScriptRootURL);
     339        return true;
     340    }
     341
     342    TextPosition position = m_element.document().isInDocumentWrite() ? TextPosition() : scriptStartPosition;
     343    ScriptSourceCode sourceCode(scriptContent(), m_element.document().url(), position, JSC::SourceProviderSourceType::Module);
     344
     345    ASSERT(m_element.document().contentSecurityPolicy());
     346    const auto& contentSecurityPolicy = *m_element.document().contentSecurityPolicy();
     347    bool hasKnownNonce = contentSecurityPolicy.allowScriptWithNonce(nonce, m_element.isInUserAgentShadowTree());
     348    if (!contentSecurityPolicy.allowInlineScript(m_element.document().url(), m_startLineNumber, sourceCode.source().toStringWithoutCopying(), hasKnownNonce))
     349        return false;
     350
     351    auto moduleScript = CachedModuleScript::create(nonce, crossOriginMode);
     352    m_loadableScript = LoadableModuleScript::create(moduleScript.get());
     353    moduleScript->load(m_element, sourceCode);
     354    return true;
     355}
     356
     357CachedResourceHandle<CachedScript> ScriptElement::requestScriptWithCacheForModuleScript(const URL& sourceURL)
     358{
     359    ASSERT(m_loadableScript);
     360    ASSERT(is<LoadableModuleScript>(*m_loadableScript));
     361    auto& moduleScript = downcast<LoadableModuleScript>(*m_loadableScript);
     362    return requestScriptWithCache(sourceURL, moduleScript.moduleScript().nonce(), moduleScript.moduleScript().crossOriginMode());
     363}
     364
     365CachedResourceHandle<CachedScript> ScriptElement::requestScriptWithCache(const URL& sourceURL, const String& nonceAttribute, const String& crossOriginMode)
    281366{
    282367    Document& document = m_element.document();
     
    291376
    292377    CachedResourceRequest request(ResourceRequest(sourceURL), options);
    293     request.setAsPotentiallyCrossOrigin(m_element.attributeWithoutSynchronization(HTMLNames::crossoriginAttr), document);
     378    request.setAsPotentiallyCrossOrigin(crossOriginMode, document);
    294379    request.upgradeInsecureRequestIfNeeded(document);
    295380
     
    315400    }
    316401
    317     Ref<Document> document(m_element.document());
    318     if (Frame* frame = document->frame()) {
    319         IgnoreDestructiveWriteCountIncrementer ignoreDesctructiveWriteCountIncrementer(m_isExternalScript ? document.ptr() : nullptr);
    320         CurrentScriptIncrementer currentScriptIncrementer(document, m_element);
    321 
    322         // Create a script from the script element node, using the script
    323         // block's source and the script block's type.
    324         // Note: This is where the script is compiled and actually executed.
    325         frame->script().evaluate(sourceCode);
    326     }
     402    auto& document = m_element.document();
     403    auto* frame = document.frame();
     404    if (!frame)
     405        return;
     406
     407    IgnoreDestructiveWriteCountIncrementer ignoreDesctructiveWriteCountIncrementer(m_isExternalScript ? &document : nullptr);
     408    CurrentScriptIncrementer currentScriptIncrementer(document, m_element);
     409
     410    frame->script().evaluate(sourceCode);
     411}
     412
     413void ScriptElement::executeModuleScript(CachedModuleScript& moduleScript)
     414{
     415    // https://html.spec.whatwg.org/multipage/scripting.html#execute-the-script-block
     416
     417    ASSERT(!moduleScript.error());
     418
     419    auto& document = m_element.document();
     420    auto* frame = document.frame();
     421    if (!frame)
     422        return;
     423
     424    IgnoreDestructiveWriteCountIncrementer ignoreDesctructiveWriteCountIncrementer(&document);
     425    CurrentScriptIncrementer currentScriptIncrementer(document, m_element);
     426
     427    frame->script().linkAndEvaluateModuleScript(moduleScript, element());
    327428}
    328429
    329430void ScriptElement::executeScriptAndDispatchEvent(LoadableScript& loadableScript)
    330431{
    331     if (Optional<LoadableScript::Error> error = loadableScript.wasErrored()) {
     432    if (Optional<LoadableScript::Error> error = loadableScript.error()) {
    332433        if (Optional<LoadableScript::ConsoleMessage> message = error->consoleMessage)
    333434            m_element.document().addConsoleMessage(message->source, message->level, message->message);
    334435        dispatchErrorEvent();
    335436    } else if (!loadableScript.wasCanceled()) {
    336         ASSERT(!loadableScript.wasErrored());
     437        ASSERT(!loadableScript.error());
    337438        loadableScript.execute(*this);
    338439        dispatchLoadEvent();
     
    345446        executeScriptAndDispatchEvent(*loadableScript);
    346447    else {
    347         ASSERT(!pendingScript.wasErrored());
    348         executeScript(ScriptSourceCode(scriptContent(), m_element.document().url(), pendingScript.startingPosition()));
     448        ASSERT(!pendingScript.error());
     449        JSC::SourceProviderSourceType sourceType = scriptType() == ScriptType::Module ? JSC::SourceProviderSourceType::Module : JSC::SourceProviderSourceType::Program;
     450        executeScript(ScriptSourceCode(scriptContent(), m_element.document().url(), pendingScript.startingPosition(), sourceType));
    349451        dispatchLoadEvent();
    350452    }
  • trunk/Source/WebCore/dom/ScriptElement.h

    r205854 r208788  
    3838class ScriptElement;
    3939class ScriptSourceCode;
     40class CachedModuleScript;
    4041
    4142class ScriptElement {
     
    5253    WEBCORE_EXPORT String scriptContent() const;
    5354    void executeScript(const ScriptSourceCode&);
     55    void executeModuleScript(CachedModuleScript&);
    5456
    5557    void executeScriptForScriptRunner(PendingScript&);
     
    6567    bool willExecuteInOrder() const { return m_willExecuteInOrder; }
    6668    LoadableScript* loadableScript() { return m_loadableScript.get(); }
     69
     70    CachedResourceHandle<CachedScript> requestScriptWithCacheForModuleScript(const URL&);
     71
     72    // https://html.spec.whatwg.org/multipage/scripting.html#concept-script-type
     73    enum class ScriptType { Classic, Module };
     74    ScriptType scriptType() const { return m_isModuleScript ? ScriptType::Module : ScriptType::Classic; }
    6775
    6876protected:
     
    8492    void executeScriptAndDispatchEvent(LoadableScript&);
    8593
    86     // https://html.spec.whatwg.org/multipage/scripting.html#concept-script-type
    87     enum class ScriptType { Classic, Module };
    8894    Optional<ScriptType> determineScriptType(LegacyTypeSupport) const;
    8995    bool ignoresLoadRequest() const;
    9096    bool isScriptForEventSupported() const;
    9197
    92     CachedResourceHandle<CachedScript> requestScriptWithCache(const URL&, const String&);
     98    CachedResourceHandle<CachedScript> requestScriptWithCache(const URL&, const String& nonceAttribute, const String& crossoriginAttribute);
    9399
    94100    bool requestClassicScript(const String& sourceURL);
     101    bool requestModuleScript(const TextPosition& scriptStartPosition);
    95102
    96103    virtual String sourceAttributeValue() const = 0;
     
    115122    bool m_forceAsync : 1;
    116123    bool m_willExecuteInOrder : 1;
     124    bool m_isModuleScript : 1;
    117125    String m_characterEncoding;
    118126    String m_fallbackCharacterEncoding;
  • trunk/Source/WebCore/html/parser/CSSPreloadScanner.cpp

    r195743 r208788  
    204204            URL baseElementURL; // FIXME: This should be passed in from the HTMLPreloadScanner via scan(): without it we will get relative URLs wrong.
    205205            // FIXME: Should this be including the charset in the preload request?
    206             m_requests->append(std::make_unique<PreloadRequest>("css", url, baseElementURL, CachedResource::CSSStyleSheet, String()));
     206            m_requests->append(std::make_unique<PreloadRequest>("css", url, baseElementURL, CachedResource::CSSStyleSheet, String(), PreloadRequest::ModuleScript::No));
    207207        }
    208208        m_state = Initial;
  • trunk/Source/WebCore/html/parser/HTMLPreloadScanner.cpp

    r205905 r208788  
    145145            return nullptr;
    146146
    147         auto request = std::make_unique<PreloadRequest>(initiatorFor(m_tagId), m_urlToLoad, predictedBaseURL, resourceType(), m_mediaAttribute);
     147        auto request = std::make_unique<PreloadRequest>(initiatorFor(m_tagId), m_urlToLoad, predictedBaseURL, resourceType(), m_mediaAttribute, m_moduleScript);
    148148        request->setCrossOriginMode(m_crossOriginMode);
     149
     150        // According to the spec, the module tag ignores the "charset" attribute as the same to the worker's
     151        // importScript. But WebKit supports the "charset" for importScript intentionally. So to be consistent,
     152        // even for the module tags, we handle the "charset" attribute.
    149153        request->setCharset(charset());
    150154        return request;
     
    206210            break;
    207211        case TagId::Script:
     212            if (match(attributeName, typeAttr)) {
     213                m_moduleScript = equalLettersIgnoringASCIICase(attributeValue, "module") ? PreloadRequest::ModuleScript::Yes : PreloadRequest::ModuleScript::No;
     214                break;
     215            }
    208216            processImageAndScriptAttribute(attributeName, attributeValue);
    209217            break;
     
    319327    bool m_inputIsImage;
    320328    float m_deviceScaleFactor;
     329    PreloadRequest::ModuleScript m_moduleScript { PreloadRequest::ModuleScript::No };
    321330};
    322331
  • trunk/Source/WebCore/html/parser/HTMLResourcePreloader.cpp

    r208049 r208788  
    4646    CachedResourceRequest request(completeURL(document), CachedResourceLoader::defaultCachedResourceOptions());
    4747    request.setInitiator(m_initiator);
    48     request.setAsPotentiallyCrossOrigin(m_crossOriginMode, document);
     48    String crossOriginMode = m_crossOriginMode;
     49    if (m_moduleScript == ModuleScript::Yes) {
     50        if (crossOriginMode.isNull())
     51            crossOriginMode = ASCIILiteral("omit");
     52    }
     53    request.setAsPotentiallyCrossOrigin(crossOriginMode, document);
    4954    return request;
    5055}
  • trunk/Source/WebCore/html/parser/HTMLResourcePreloader.h

    r208179 r208788  
    3434    WTF_MAKE_FAST_ALLOCATED;
    3535public:
    36     PreloadRequest(const String& initiator, const String& resourceURL, const URL& baseURL, CachedResource::Type resourceType, const String& mediaAttribute)
     36    enum class ModuleScript {
     37        Yes,
     38        No,
     39    };
     40    PreloadRequest(const String& initiator, const String& resourceURL, const URL& baseURL, CachedResource::Type resourceType, const String& mediaAttribute, ModuleScript moduleScript)
    3741        : m_initiator(initiator)
    3842        , m_resourceURL(resourceURL)
     
    4044        , m_resourceType(resourceType)
    4145        , m_mediaAttribute(mediaAttribute)
     46        , m_moduleScript(moduleScript)
    4247    {
    4348    }
     
    6166    String m_mediaAttribute;
    6267    String m_crossOriginMode;
     68    ModuleScript m_moduleScript;
    6369};
    6470
  • trunk/Source/WebCore/html/parser/HTMLScriptRunner.h

    r208179 r208788  
    7373    void stopWatchingForLoad(PendingScript&);
    7474    bool isPendingScriptReady(const PendingScript&);
    75     ScriptSourceCode sourceFromPendingScript(const PendingScript&, bool& errorOccurred) const;
    7675
    7776    Document* m_document;
  • trunk/Source/WebCore/loader/cache/CachedResourceRequest.cpp

    r207817 r208788  
    9292    if (mode.isNull())
    9393        return;
     94
    9495    m_options.mode = FetchOptions::Mode::Cors;
    95     m_options.credentials = equalLettersIgnoringASCIICase(mode, "use-credentials") ? FetchOptions::Credentials::Include : FetchOptions::Credentials::SameOrigin;
    96     m_options.allowCredentials = equalLettersIgnoringASCIICase(mode, "use-credentials") ? AllowStoredCredentials : DoNotAllowStoredCredentials;
    97 
     96
     97    FetchOptions::Credentials credentials = equalLettersIgnoringASCIICase(mode, "omit")
     98        ? FetchOptions::Credentials::Omit : equalLettersIgnoringASCIICase(mode, "use-credentials")
     99        ? FetchOptions::Credentials::Include : FetchOptions::Credentials::SameOrigin;
     100    m_options.credentials = credentials;
     101    m_options.allowCredentials = credentials == FetchOptions::Credentials::Include ? AllowStoredCredentials : DoNotAllowStoredCredentials;
    98102    WebCore::updateRequestForAccessControl(m_resourceRequest, *document.securityOrigin(), m_options.allowCredentials);
    99103}
  • trunk/Source/WebCore/xml/parser/XMLDocumentParser.cpp

    r208658 r208788  
    233233    ASSERT(m_pendingScript->accessCount() > 0);
    234234
    235     ScriptSourceCode sourceCode(m_pendingScript.get());
     235    // FIXME: Support ES6 modules in XML document.
     236    // https://bugs.webkit.org/show_bug.cgi?id=161651
     237    ScriptSourceCode sourceCode(m_pendingScript.get(), JSC::SourceProviderSourceType::Program);
    236238    bool errorOccurred = m_pendingScript->errorOccurred();
    237239    bool wasCanceled = m_pendingScript->wasCanceled();
Note: See TracChangeset for help on using the changeset viewer.