https://bugs.webkit.org/show_bug.cgi?id=166926
Reviewed by Ryosuke Niwa.
Source/WebCore:
This patch introduces browser side dynamic-import implementation.
The dynamic-import is new ES feature which is now stage 3.
The JSC shell already implements it.
The dynamic-import allows us to kick module loading in a dynamic manner.
For example, you can write,
await module = import(`${HOST}/hello.js`);
The dynamic `import` operator (this is not a function) returns a promise with
module namespace object if the module loading succeeds. Otherwise, it returns
a rejected promise.
And importantly, this feature allows us to kick module loading from classic script.
Previously, module loading can be only used from <script type="module"> tag. And
all the module loading is done statically.
* CMakeLists.txt:
* WebCore.xcodeproj/project.pbxproj:
* bindings/js/CachedModuleScriptLoader.cpp:
(WebCore::CachedModuleScriptLoader::load):
* bindings/js/CachedScriptFetcher.cpp:
(WebCore::CachedScriptFetcher::create):
(WebCore::CachedScriptFetcher::requestModuleScript):
requestModuleScript function is used only when loading a new module script.
So, LoadableClassicScript should use requestScriptWithCache to load itself.
We pass String() for cross origin mode for null cross origin attribute as
specified.
(WebCore::CachedScriptFetcher::requestScriptWithCache):
* bindings/js/CachedScriptFetcher.h:
(WebCore::CachedScriptFetcher::CachedScriptFetcher):
* bindings/js/JSDOMWindowBase.cpp:
(WebCore::JSDOMWindowBase::moduleLoaderImportModule):
* bindings/js/JSDOMWindowBase.h:
* bindings/js/JSLazyEventListener.cpp:
(WebCore::JSLazyEventListener::initializeJSFunction):
* bindings/js/ScriptController.cpp:
(WebCore::ScriptController::executeScript):
* bindings/js/ScriptModuleLoader.cpp:
(WebCore::resolveModuleSpecifier):
Extract the part of resolving module specifier to a static function to use
it in ScriptModuleLoader::resolve and ScriptModuleLoader::importModule.
(WebCore::ScriptModuleLoader::resolve):
(WebCore::rejectPromise):
(WebCore::ScriptModuleLoader::importModule):
New hook moduleLoaderImportModule is implemented. This hook is called when
`import` operator is used. This hook is responsible to
1. resolve the module name to obtain module specifier. (like, resolve the
relative URL to get absolute URL.)
2. kick module loading with the resolved specifier.
When resolving the module name, the referrer information is needed.
For example, "./script.js" will be resolved to "http://example.com/script.js" if
the referrer module specifier is "http://example.com/".
If `import("./script.js")` is executed in the classic script
src="http://example.com/test.js", it starts loading "http://example.com/script.js".
So the information of the caller of `import` operator is necessary here.
This appropriate referrer is propagated by SourceOrigin.
* bindings/js/ScriptModuleLoader.h:
* dom/InlineClassicScript.h:
* dom/LoadableClassicScript.cpp:
(WebCore::LoadableClassicScript::load):
* dom/LoadableClassicScript.h:
* dom/LoadableModuleScript.h:
* dom/LoadableScript.h:
(WebCore::LoadableScript::LoadableScript):
(WebCore::LoadableScript::isClassicScript): Deleted.
(WebCore::LoadableScript::isModuleScript): Deleted.
* dom/ScriptElement.h:
* dom/ScriptElementCachedScriptFetcher.cpp: Copied from Source/WebCore/dom/InlineClassicScript.h.
(WebCore::ScriptElementCachedScriptFetcher::requestModuleScript):
This requestModuleScript will be used when the script tag (or modules imported from the script tag) uses `import` operator.
In classic scripts, `crossorigin` mode always becomes "omit" while module scripts
propagate the original `crossorigin` value.
* dom/ScriptElementCachedScriptFetcher.h: Copied from Source/WebCore/bindings/js/CachedScriptFetcher.h.
(WebCore::ScriptElementCachedScriptFetcher::crossOriginMode):
(WebCore::ScriptElementCachedScriptFetcher::ScriptElementCachedScriptFetcher):
LayoutTests:
* http/tests/misc/import-absolute-url-expected.txt: Added.
* http/tests/misc/import-absolute-url.html: Added.
* http/tests/security/contentSecurityPolicy/1.1/import-scriptnonce-expected.txt: Added.
* http/tests/security/contentSecurityPolicy/1.1/import-scriptnonce.html: Added.
* http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-allowed1.js: Added.
* http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-allowed2.js: Added.
* http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-allowed3.js: Added.
* http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-allowed4.js: Added.
* http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-allowed5.js: Added.
* http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-allowed6.js: Added.
* http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-blocked1.js: Added.
* http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-blocked2.js: Added.
* http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-blocked3.js: Added.
* http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-blocked4.js: Added.
* http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-blocked5.js: Added.
* http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-blocked6.js: Added.
* http/tests/security/import-module-crossorigin-loads-error-expected.txt: Added.
* http/tests/security/import-module-crossorigin-loads-error-src-expected.txt: Added.
* http/tests/security/import-module-crossorigin-loads-error-src.html: Added.
* http/tests/security/import-module-crossorigin-loads-error.html: Added.
* http/tests/security/import-module-crossorigin-loads-expected.txt: Added.
* http/tests/security/import-module-crossorigin-loads-src-expected.txt: Added.
* http/tests/security/import-module-crossorigin-loads-src.html: Added.
* http/tests/security/import-module-crossorigin-loads.html: Added.
* http/tests/security/import-script-crossorigin-loads-error-expected.txt: Added.
* http/tests/security/import-script-crossorigin-loads-error.html: Added.
* http/tests/security/import-script-crossorigin-loads-omit-expected.txt: Added.
* http/tests/security/import-script-crossorigin-loads-omit.html: Added.
* http/tests/security/resources/cors-deny.php: Added.
* http/tests/security/resources/import-module-crossorigin-loads-error-src.js: Added.
(import.string_appeared_here.then):
* http/tests/security/resources/import-module-crossorigin-loads-src.js: Added.
(import.string_appeared_here.then):
* js/dom/modules/import-execution-order-expected.txt: Added.
* js/dom/modules/import-execution-order.html: Copied from LayoutTests/js/dom/modules/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.html.
* js/dom/modules/import-from-handler-expected.txt: Added.
* js/dom/modules/import-from-handler.html: Copied from LayoutTests/js/dom/modules/module-src-simple.html.
* js/dom/modules/import-from-javascript-url-expected.txt: Added.
* js/dom/modules/import-from-javascript-url.html: Copied from LayoutTests/js/dom/modules/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.html.
* js/dom/modules/import-from-loaded-classic-expected.txt: Added.
* js/dom/modules/import-from-loaded-classic.html: Copied from LayoutTests/js/dom/modules/module-src-simple.html.
* js/dom/modules/import-from-loaded-module-expected.txt: Added.
* js/dom/modules/import-from-loaded-module.html: Copied from LayoutTests/js/dom/modules/module-src-simple.html.
* js/dom/modules/import-from-module-expected.txt: Added.
* js/dom/modules/import-from-module.html: Copied from LayoutTests/js/dom/modules/module-src-simple.html.
* js/dom/modules/import-incorrect-relative-specifier-expected.txt: Added.
* js/dom/modules/import-incorrect-relative-specifier.html: Copied from LayoutTests/js/dom/modules/module-src-simple.html.
* js/dom/modules/import-simple-expected.txt: Added.
* js/dom/modules/import-simple.html: Copied from LayoutTests/js/dom/modules/module-src-simple.html.
* js/dom/modules/module-document-write-src.html:
* js/dom/modules/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.html:
* js/dom/modules/module-execution-order-mixed-with-classic-scripts.html:
* js/dom/modules/module-execution-order-mixed.html:
* js/dom/modules/module-inline-dynamic.html:
* js/dom/modules/module-inline-simple.html:
* js/dom/modules/module-load-event-with-src.html:
* js/dom/modules/module-load-same-module-from-different-entry-point-dynamic.html:
* js/dom/modules/module-load-same-module-from-different-entry-point-in-src.html:
* js/dom/modules/module-load-same-module-from-different-entry-point.html:
* js/dom/modules/module-not-found-error-event-with-src-and-import.html:
* js/dom/modules/module-src-current-script.html:
* js/dom/modules/module-src-dynamic.html:
* js/dom/modules/module-src-simple.html:
* js/dom/modules/module-type-case-insensitive.html:
* js/dom/modules/module-will-fire-beforeload.html:
* js/dom/modules/nomodule-dynamic-classic-src.html:
* js/dom/modules/nomodule-has-no-effect-on-module-inline.html:
* js/dom/modules/nomodule-has-no-effect-on-module-src.html:
* js/dom/modules/nomodule-prevents-execution-classic-script-src.html:
* js/dom/modules/nomodule-reflect.html:
* js/dom/modules/resources/error-classic-script.js: Renamed from LayoutTests/js/dom/modules/script-tests/error-classic-script.js.
* js/dom/modules/resources/import-from-loaded-classic-finish.js: Added.
* js/dom/modules/resources/import-from-loaded-classic.js: Added.
* js/dom/modules/resources/import-from-loaded-module-finish.js: Added.
* js/dom/modules/resources/import-from-loaded-module.js: Added.
* js/dom/modules/resources/module-document-write-src.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-document-write-src.js.
* js/dom/modules/resources/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror-throw.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror-throw.js.
* js/dom/modules/resources/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.js.
* js/dom/modules/resources/module-execution-order-mixed-2.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-2.js.
* js/dom/modules/resources/module-execution-order-mixed-cappuccino.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-cappuccino.js.
* js/dom/modules/resources/module-execution-order-mixed-cocoa.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-cocoa.js.
* js/dom/modules/resources/module-execution-order-mixed-matcha.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-matcha.js.
* js/dom/modules/resources/module-execution-order-mixed-with-classic-scripts-2.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-2.js.
* js/dom/modules/resources/module-execution-order-mixed-with-classic-scripts-cappuccino.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-cappuccino.js.
* js/dom/modules/resources/module-execution-order-mixed-with-classic-scripts-cocoa.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-cocoa.js.
* js/dom/modules/resources/module-execution-order-mixed-with-classic-scripts-matcha.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-matcha.js.
* js/dom/modules/resources/module-execution-order-mixed-with-classic-scripts.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts.js.
* js/dom/modules/resources/module-execution-order-mixed.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed.js.
* js/dom/modules/resources/module-inline-dynamic.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-inline-dynamic.js.
* js/dom/modules/resources/module-inline-simple.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-inline-simple.js.
* js/dom/modules/resources/module-load-event-with-src.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-load-event-with-src.js.
* js/dom/modules/resources/module-load-same-module-from-different-entry-point.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-load-same-module-from-different-entry-point.js.
* js/dom/modules/resources/module-not-found-error-event-with-src-and-import.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-not-found-error-event-with-src-and-import.js.
* js/dom/modules/resources/module-src-current-script.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-src-current-script.js.
* js/dom/modules/resources/module-src-dynamic-cocoa.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-src-dynamic-cocoa.js.
* js/dom/modules/resources/module-src-dynamic.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-src-dynamic.js.
* js/dom/modules/resources/module-src-simple-cocoa.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-src-simple-cocoa.js.
* js/dom/modules/resources/module-src-simple.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-src-simple.js.
* js/dom/modules/resources/module-will-fire-beforeload.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-will-fire-beforeload.js.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@211280
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2017-01-27 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ Implement dynamic-import for WebCore
+ https://bugs.webkit.org/show_bug.cgi?id=166926
+
+ Reviewed by Ryosuke Niwa.
+
+ * http/tests/misc/import-absolute-url-expected.txt: Added.
+ * http/tests/misc/import-absolute-url.html: Added.
+ * http/tests/security/contentSecurityPolicy/1.1/import-scriptnonce-expected.txt: Added.
+ * http/tests/security/contentSecurityPolicy/1.1/import-scriptnonce.html: Added.
+ * http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-allowed1.js: Added.
+ * http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-allowed2.js: Added.
+ * http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-allowed3.js: Added.
+ * http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-allowed4.js: Added.
+ * http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-allowed5.js: Added.
+ * http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-allowed6.js: Added.
+ * http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-blocked1.js: Added.
+ * http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-blocked2.js: Added.
+ * http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-blocked3.js: Added.
+ * http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-blocked4.js: Added.
+ * http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-blocked5.js: Added.
+ * http/tests/security/contentSecurityPolicy/1.1/resources/import-scriptnonce-blocked6.js: Added.
+ * http/tests/security/import-module-crossorigin-loads-error-expected.txt: Added.
+ * http/tests/security/import-module-crossorigin-loads-error-src-expected.txt: Added.
+ * http/tests/security/import-module-crossorigin-loads-error-src.html: Added.
+ * http/tests/security/import-module-crossorigin-loads-error.html: Added.
+ * http/tests/security/import-module-crossorigin-loads-expected.txt: Added.
+ * http/tests/security/import-module-crossorigin-loads-src-expected.txt: Added.
+ * http/tests/security/import-module-crossorigin-loads-src.html: Added.
+ * http/tests/security/import-module-crossorigin-loads.html: Added.
+ * http/tests/security/import-script-crossorigin-loads-error-expected.txt: Added.
+ * http/tests/security/import-script-crossorigin-loads-error.html: Added.
+ * http/tests/security/import-script-crossorigin-loads-omit-expected.txt: Added.
+ * http/tests/security/import-script-crossorigin-loads-omit.html: Added.
+ * http/tests/security/resources/cors-deny.php: Added.
+ * http/tests/security/resources/import-module-crossorigin-loads-error-src.js: Added.
+ (import.string_appeared_here.then):
+ * http/tests/security/resources/import-module-crossorigin-loads-src.js: Added.
+ (import.string_appeared_here.then):
+ * js/dom/modules/import-execution-order-expected.txt: Added.
+ * js/dom/modules/import-execution-order.html: Copied from LayoutTests/js/dom/modules/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.html.
+ * js/dom/modules/import-from-handler-expected.txt: Added.
+ * js/dom/modules/import-from-handler.html: Copied from LayoutTests/js/dom/modules/module-src-simple.html.
+ * js/dom/modules/import-from-javascript-url-expected.txt: Added.
+ * js/dom/modules/import-from-javascript-url.html: Copied from LayoutTests/js/dom/modules/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.html.
+ * js/dom/modules/import-from-loaded-classic-expected.txt: Added.
+ * js/dom/modules/import-from-loaded-classic.html: Copied from LayoutTests/js/dom/modules/module-src-simple.html.
+ * js/dom/modules/import-from-loaded-module-expected.txt: Added.
+ * js/dom/modules/import-from-loaded-module.html: Copied from LayoutTests/js/dom/modules/module-src-simple.html.
+ * js/dom/modules/import-from-module-expected.txt: Added.
+ * js/dom/modules/import-from-module.html: Copied from LayoutTests/js/dom/modules/module-src-simple.html.
+ * js/dom/modules/import-incorrect-relative-specifier-expected.txt: Added.
+ * js/dom/modules/import-incorrect-relative-specifier.html: Copied from LayoutTests/js/dom/modules/module-src-simple.html.
+ * js/dom/modules/import-simple-expected.txt: Added.
+ * js/dom/modules/import-simple.html: Copied from LayoutTests/js/dom/modules/module-src-simple.html.
+ * js/dom/modules/module-document-write-src.html:
+ * js/dom/modules/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.html:
+ * js/dom/modules/module-execution-order-mixed-with-classic-scripts.html:
+ * js/dom/modules/module-execution-order-mixed.html:
+ * js/dom/modules/module-inline-dynamic.html:
+ * js/dom/modules/module-inline-simple.html:
+ * js/dom/modules/module-load-event-with-src.html:
+ * js/dom/modules/module-load-same-module-from-different-entry-point-dynamic.html:
+ * js/dom/modules/module-load-same-module-from-different-entry-point-in-src.html:
+ * js/dom/modules/module-load-same-module-from-different-entry-point.html:
+ * js/dom/modules/module-not-found-error-event-with-src-and-import.html:
+ * js/dom/modules/module-src-current-script.html:
+ * js/dom/modules/module-src-dynamic.html:
+ * js/dom/modules/module-src-simple.html:
+ * js/dom/modules/module-type-case-insensitive.html:
+ * js/dom/modules/module-will-fire-beforeload.html:
+ * js/dom/modules/nomodule-dynamic-classic-src.html:
+ * js/dom/modules/nomodule-has-no-effect-on-module-inline.html:
+ * js/dom/modules/nomodule-has-no-effect-on-module-src.html:
+ * js/dom/modules/nomodule-prevents-execution-classic-script-src.html:
+ * js/dom/modules/nomodule-reflect.html:
+ * js/dom/modules/resources/error-classic-script.js: Renamed from LayoutTests/js/dom/modules/script-tests/error-classic-script.js.
+ * js/dom/modules/resources/import-from-loaded-classic-finish.js: Added.
+ * js/dom/modules/resources/import-from-loaded-classic.js: Added.
+ * js/dom/modules/resources/import-from-loaded-module-finish.js: Added.
+ * js/dom/modules/resources/import-from-loaded-module.js: Added.
+ * js/dom/modules/resources/module-document-write-src.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-document-write-src.js.
+ * js/dom/modules/resources/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror-throw.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror-throw.js.
+ * js/dom/modules/resources/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.js.
+ * js/dom/modules/resources/module-execution-order-mixed-2.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-2.js.
+ * js/dom/modules/resources/module-execution-order-mixed-cappuccino.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-cappuccino.js.
+ * js/dom/modules/resources/module-execution-order-mixed-cocoa.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-cocoa.js.
+ * js/dom/modules/resources/module-execution-order-mixed-matcha.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-matcha.js.
+ * js/dom/modules/resources/module-execution-order-mixed-with-classic-scripts-2.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-2.js.
+ * js/dom/modules/resources/module-execution-order-mixed-with-classic-scripts-cappuccino.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-cappuccino.js.
+ * js/dom/modules/resources/module-execution-order-mixed-with-classic-scripts-cocoa.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-cocoa.js.
+ * js/dom/modules/resources/module-execution-order-mixed-with-classic-scripts-matcha.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts-matcha.js.
+ * js/dom/modules/resources/module-execution-order-mixed-with-classic-scripts.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed-with-classic-scripts.js.
+ * js/dom/modules/resources/module-execution-order-mixed.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-execution-order-mixed.js.
+ * js/dom/modules/resources/module-inline-dynamic.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-inline-dynamic.js.
+ * js/dom/modules/resources/module-inline-simple.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-inline-simple.js.
+ * js/dom/modules/resources/module-load-event-with-src.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-load-event-with-src.js.
+ * js/dom/modules/resources/module-load-same-module-from-different-entry-point.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-load-same-module-from-different-entry-point.js.
+ * js/dom/modules/resources/module-not-found-error-event-with-src-and-import.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-not-found-error-event-with-src-and-import.js.
+ * js/dom/modules/resources/module-src-current-script.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-src-current-script.js.
+ * js/dom/modules/resources/module-src-dynamic-cocoa.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-src-dynamic-cocoa.js.
+ * js/dom/modules/resources/module-src-dynamic.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-src-dynamic.js.
+ * js/dom/modules/resources/module-src-simple-cocoa.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-src-simple-cocoa.js.
+ * js/dom/modules/resources/module-src-simple.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-src-simple.js.
+ * js/dom/modules/resources/module-will-fire-beforeload.js: Renamed from LayoutTests/js/dom/modules/script-tests/module-will-fire-beforeload.js.
+
2017-01-26 Chris Dumez <cdumez@apple.com>
Crash when navigating back to a page in PacheCache when one of its frames has been removed
--- /dev/null
+Test modules with absolute URLs.
+http://127.0.0.1:8000/misc/resources/module-absolute-url2.js
+http://127.0.0.1:8000/misc/resources/module-absolute-url.js
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<script src="../../js-test-resources/js-test-pre.js"></script>
+</head>
+<body>
+Test modules with absolute URLs.<hr>
+<div id="console"></div>
+<script>
+var jsTestIsAsync = true;
+</script>
+<script>
+import("http://127.0.0.1:8000/misc/resources/module-absolute-url.js").then(finishJSTest);
+</script>
+<script src="../../js-test-resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+CONSOLE MESSAGE: line 61: Refused to execute a script because its hash, its nonce, or 'unsafe-inline' does not appear in the script-src directive of the Content Security Policy.
+CONSOLE MESSAGE: line 67: Refused to execute a script because its hash, its nonce, or 'unsafe-inline' does not appear in the script-src directive of the Content Security Policy.
+CONSOLE MESSAGE: line 73: Refused to execute a script because its hash, its nonce, or 'unsafe-inline' does not appear in the script-src directive of the Content Security Policy.
+CONSOLE MESSAGE: line 79: Refused to execute a script because its hash, its nonce, or 'unsafe-inline' does not appear in the script-src directive of the Content Security Policy.
+CONSOLE MESSAGE: line 85: Refused to execute a script because its hash, its nonce, or 'unsafe-inline' does not appear in the script-src directive of the Content Security Policy.
+CONSOLE MESSAGE: line 91: Refused to execute a script because its hash, its nonce, or 'unsafe-inline' does not appear in the script-src directive of the Content Security Policy.
+ALERT: 1,2,3,4,5,6
+This tests the effect of a script-nonce value.
+
+PASS
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv="Content-Security-Policy" content="script-src 'nonce-noncynonce' 'nonce-noncy+/=nonce'">
+ </head>
+ <body>
+ <script nonce="noncynonce">
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+ }
+
+ var modules = new Set([
+ 'allow1',
+ 'allow2',
+ 'allow3',
+ ]);
+
+ var array = [];
+ var count = 0;
+ function ok(num)
+ {
+ // load should be done for module tags before calling the result of import.
+ if (modules.has(`allow${num}`))
+ error(num);
+ array.push(num);
+ if (array.length === 6) {
+ alert(array.sort().toString());
+ done("PASS");
+ }
+ }
+
+ document.body.addEventListener('load', function (ev) {
+ let id = ev.target.id;
+ if (modules.has(id))
+ modules.delete(id);
+ else if (id)
+ error(id);
+ }, /* capture */ true);
+
+ document.body.addEventListener('error', function (ev) {
+ error(ev.target.id);
+ }, /* capture */ true);
+
+
+ function error(num)
+ {
+ alert(`FAIL (${num})`);
+ }
+
+ function done(msg) {
+ document.querySelector("pre").innerHTML = msg;
+ if (window.testRunner)
+ testRunner.notifyDone();
+ }
+ </script>
+
+ <script type="module" nonce="noncynonce" id="allow1">
+ import("./resources/import-scriptnonce-allowed1.js");
+ </script>
+ <script type="module" nonce="noncynonce noncynonce" id="block1">
+ import("./resources/import-scriptnonce-blocked1.js");
+ </script>
+ <script type="module" nonce="noncynonce" id="allow2">
+ import("./resources/import-scriptnonce-allowed2.js");
+ </script>
+ <script type="module" id="block2">
+ import("./resources/import-scriptnonce-blocked2.js");
+ </script>
+ <script type="module" nonce="noncy+/=nonce" id="allow3">
+ import("./resources/import-scriptnonce-allowed3.js");
+ </script>
+ <script type="module" nonce="noncynonceno?" id="block3">
+ import("./resources/import-scriptnonce-blocked3.js");
+ </script>
+ <script nonce="noncynonce" id="allow4">
+ import("./resources/import-scriptnonce-allowed4.js");
+ </script>
+ <script nonce="noncynonce noncynonce" id="block4">
+ import("./resources/import-scriptnonce-blocked4.js");
+ </script>
+ <script nonce="noncynonce" id="allow5">
+ import("./resources/import-scriptnonce-allowed5.js");
+ </script>
+ <script id="block5">
+ import("./resources/import-scriptnonce-blocked5.js");
+ </script>
+ <script nonce="noncy+/=nonce" id="allow6">
+ import("./resources/import-scriptnonce-allowed6.js");
+ </script>
+ <script nonce="noncynonceno?" id="block6">
+ import("./resources/import-scriptnonce-blocked6.js");
+ </script>
+ <p>
+ This tests the effect of a script-nonce value.
+ </p>
+ <pre></pre>
+ </body>
+</html>
--- /dev/null
+CONSOLE MESSAGE: Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
+This test passes if the module script does not load.
+
+PASS
--- /dev/null
+CONSOLE MESSAGE: Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
+This test passes if the module script does not load.
+
+PASS
--- /dev/null
+<body>
+<p>This test passes if the module script does not load.</p>
+<pre></pre>
+<script>
+if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+}
+
+function done(msg) {
+ document.querySelector("pre").innerHTML = msg;
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+</script>
+<script type="module" src="./resources/import-module-crossorigin-loads-error-src.js"></script>
--- /dev/null
+<body>
+<p>This test passes if the module script does not load.</p>
+<pre></pre>
+<script>
+if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+}
+
+function done(msg) {
+ document.querySelector("pre").innerHTML = msg;
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+</script>
+<script type="module">
+import("http://localhost:8000/security/resources/cors-deny.php?credentials=true").then(
+ function() { done("FAIL");},
+ function() { done("PASS"); });
+</script>
--- /dev/null
+ALERT: script ran.
+This test passes if the module script loads.
+
+PASS
--- /dev/null
+ALERT: script ran.
+This test passes if the module script loads.
+
+PASS
--- /dev/null
+<body>
+<p>This test passes if the module script loads.</p>
+<pre></pre>
+<script>
+if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+}
+
+function done(msg) {
+ document.querySelector("pre").innerHTML = msg;
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+</script>
+<script type="module" src="./resources/import-module-crossorigin-loads-src.js"></script>
--- /dev/null
+<body>
+<p>This test passes if the module script loads.</p>
+<pre></pre>
+<script>
+if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+}
+
+function done(msg) {
+ document.querySelector("pre").innerHTML = msg;
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+</script>
+<script type="module">
+// Executed with "omit".
+// https://github.com/tc39/proposal-dynamic-import/blob/master/HTML%20Integration.md
+import("http://localhost:8000/security/resources/cors-script.php?credentials=false").then(
+ function() { done("PASS");},
+ function() { done("FAIL"); });
+</script>
--- /dev/null
+CONSOLE MESSAGE: Origin http://127.0.0.1:8000 is not allowed by Access-Control-Allow-Origin.
+This test passes if the module script does not load.
+
+PASS
--- /dev/null
+<body>
+<p>This test passes if the module script does not load.</p>
+<pre></pre>
+<script crossorigin="use-credentials">
+if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+}
+
+function done(msg) {
+ document.querySelector("pre").innerHTML = msg;
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+
+// Executed with "omit".
+// https://github.com/tc39/proposal-dynamic-import/blob/master/HTML%20Integration.md
+import("http://localhost:8000/security/resources/cors-deny.php?credentials=true").then(
+ function() { done("FAIL");},
+ function() { done("PASS"); });
+</script>
--- /dev/null
+ALERT: script ran.
+This test passes if the module script loads.
+
+PASS
--- /dev/null
+<body>
+<p>This test passes if the module script loads.</p>
+<pre></pre>
+<script crossorigin="use-credentials">
+if (window.testRunner) {
+ testRunner.dumpAsText();
+ testRunner.waitUntilDone();
+}
+
+function done(msg) {
+ document.querySelector("pre").innerHTML = msg;
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+
+// Executed with "omit".
+// https://github.com/tc39/proposal-dynamic-import/blob/master/HTML%20Integration.md
+import("http://localhost:8000/security/resources/cors-script.php?credentials=false").then(
+ function() { done("PASS");},
+ function() { done("FAIL"); });
+</script>
--- /dev/null
+<?php
+header("Access-Control-Allow-Origin: http://example.org/");
+header("Content-Type: application/javascript");
+
+if (isset($_GET["credentials"])) {
+ if (strtolower($_GET["credentials"]) == "true")
+ header("Access-Control-Allow-Credentials: true");
+ else
+ header("Access-Control-Allow-Credentials: false");
+}
+
+if (strtolower($_GET["fail"]) == "true")
+ echo "throw({toString: function(){ return 'SomeError' }});";
+else
+ echo "alert('script ran.');";
+?>
--- /dev/null
+import("http://localhost:8000/security/resources/cors-deny.php?credentials=true").then(
+ function() { done("FAIL");},
+ function() { done("PASS"); });
--- /dev/null
+// Executed with "omit".
+// https://github.com/tc39/proposal-dynamic-import/blob/master/HTML%20Integration.md
+import("http://localhost:8000/security/resources/cors-script.php?credentials=false").then(
+ function() { done("PASS");},
+ function() { done("FAIL"); });
+
--- /dev/null
+Test import execution order.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Module is not executed yet.
+PASS count++ is 0
+PASS count++ is 1
+PASS count++ is 2
+PASS count++ is 3
+PASS count++ is 4
+PASS count++ is 5
+PASS count++ is 6
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test import execution order.');
+window.count = 0;
+
+// Module will be executed asynchronously.
+window.jsTestIsAsync = true;
+debug('Module is not executed yet.');
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+<script>
+(async function () {
+ await import(`./resources/module-execution-order-mixed.js`);
+ shouldBe("count++", "4");
+ await import(`./resources/module-execution-order-mixed-2.js`);
+ shouldBe("count++", "6");
+ finishJSTest();
+}());
+</script>
+</body>
+</html>
--- /dev/null
+Test import from handler.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Module is not executed yet.
+Module execution is confined in the module environment.
+PASS typeof cocoa is "undefined"
+PASS typeof exportedCocoa is "object"
+PASS exportedCocoa.taste() is "nice"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+MODULE
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test import from handler.');
+
+// Module will be executed asynchronously.
+window.jsTestIsAsync = true;
+</script>
+<script>
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+<a id="target" onclick="(import(`./resources/module-src-simple.js`)).then(() => finishJSTest())">MODULE</a>
+<script type="module">
+debug('Module is not executed yet.');
+let anchor = document.getElementById('target');
+anchor.dispatchEvent(new MouseEvent('click'));
+</script>
+</body>
+</html>
--- /dev/null
+Test import from javascript URL.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Module is not executed yet.
+Module execution is confined in the module environment.
+PASS typeof cocoa is "undefined"
+PASS typeof exportedCocoa is "object"
+PASS exportedCocoa.taste() is "nice"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+MODULE
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test import from javascript URL.');
+
+// Module will be executed asynchronously.
+window.jsTestIsAsync = true;
+</script>
+<script>
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+<a id="target" href="javascript:void((import(`./resources/module-src-simple.js`)).then(() => finishJSTest()))">MODULE</a>
+<script type="module">
+debug('Module is not executed yet.');
+let anchor = document.getElementById('target');
+anchor.dispatchEvent(new MouseEvent('click'));
+</script>
+</body>
+</html>
--- /dev/null
+Test import from loaded classic.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+import from loaded classic
+import from loaded classic finish
+PASS window.imported is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test import from loaded classic.');
+
+// Module will be executed asynchronously.
+window.jsTestIsAsync = true;
+
+function loaded()
+{
+ shouldBeTrue(`window.imported`);
+ finishJSTest();
+}
+</script>
+<script>
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+<script src="./resources/import-from-loaded-classic.js"></script>
+</body>
+</html>
--- /dev/null
+Test import from loaded module.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+import from loaded module
+import from loaded module finish
+PASS window.imported is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test import from loaded module.');
+
+// Module will be executed asynchronously.
+window.jsTestIsAsync = true;
+
+function loaded()
+{
+ shouldBeTrue(`window.imported`);
+ finishJSTest();
+}
+
+</script>
+<script>
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+<script type="module" src="./resources/import-from-loaded-module.js"></script>
+</body>
+</html>
--- /dev/null
+Test import from module script.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Module is not executed yet.
+Module execution is confined in the module environment.
+PASS typeof cocoa is "undefined"
+PASS typeof exportedCocoa is "object"
+PASS exportedCocoa.taste() is "nice"
+PASS window.imported is true
+PASS window.passedCocoa is window.exportedCocoa
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test import from module script.');
+
+// Module will be executed asynchronously.
+window.jsTestIsAsync = true;
+window.passedCocoa = null;
+
+function loaded(cocoa)
+{
+ window.passedCocoa = cocoa;
+ shouldBeTrue(`window.imported`);
+ shouldBe(`window.passedCocoa`, `window.exportedCocoa`);
+ finishJSTest();
+}
+
+</script>
+<script>
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+<script type="module">
+(async function() {
+ debug('Module is not executed yet.');
+ let ns = await import(`./resources/import-src-simple.js`);
+ loaded(ns.ok);
+}());
+</script>
+</body>
+</html>
--- /dev/null
+Test import rejects the incorrect relative specifiers.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS import("incorrect") rejected promise with TypeError: Module specifier does not start with "/", "./", or "../"..
+PASS import("$hello") rejected promise with TypeError: Module specifier does not start with "/", "./", or "../"..
+PASS import(".../test") rejected promise with TypeError: Module specifier does not start with "/", "./", or "../"..
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test import rejects the incorrect relative specifiers.');
+// Module will be executed asynchronously.
+window.jsTestIsAsync = true;
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+<script>
+(async function () {
+ await shouldReject(`import("incorrect")`);
+ await shouldReject(`import("$hello")`);
+ await shouldReject(`import(".../test")`);
+ finishJSTest();
+}());
+</script>
+</body>
+</html>
--- /dev/null
+Test import simple.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Module is not executed yet.
+Module execution is confined in the module environment.
+PASS typeof cocoa is "undefined"
+PASS typeof exportedCocoa is "object"
+PASS exportedCocoa.taste() is "nice"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script>
+description('Test import simple.');
+
+// Module will be executed asynchronously.
+window.jsTestIsAsync = true;
+</script>
+<script>
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+<script>
+(async function() {
+ debug('Module is not executed yet.');
+ await import(`./resources/module-src-simple.js`);
+ finishJSTest();
+}());
+</script>
+</body>
+</html>
debug('Module is not executed yet.');
</script>
<script src="../../../resources/js-test-post.js"></script>
-<script type="module" src="script-tests/module-document-write-src.js"></script>
+<script type="module" src="resources/module-document-write-src.js"></script>
</body>
</html>
</script>
<script src="../../../resources/js-test-post.js"></script>
<script type="module">
-import "./script-tests/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.js"
+import "./resources/module-execution-error-inside-dependent-module-should-be-propagated-to-onerror.js"
testFailed("executed");
</script>
</body>
<script>
shouldBe("count++", "1");
</script>
-<script type="module" src="script-tests/module-execution-order-mixed-with-classic-scripts.js"></script>
+<script type="module" src="resources/module-execution-order-mixed-with-classic-scripts.js"></script>
<script>
shouldBe("count++", "2");
</script>
<script>
shouldBe("count++", "3");
</script>
-<script type="module" src="script-tests/module-execution-order-mixed-with-classic-scripts-2.js"></script>
+<script type="module" src="resources/module-execution-order-mixed-with-classic-scripts-2.js"></script>
<script>
shouldBe("count++", "4");
</script>
debug('Module is not executed yet.');
</script>
<script src="../../../resources/js-test-post.js"></script>
-<script type="module" src="script-tests/module-execution-order-mixed.js"></script>
+<script type="module" src="resources/module-execution-order-mixed.js"></script>
<script type="module">
shouldBe("count++", "4");
</script>
-<script type="module" src="script-tests/module-execution-order-mixed-2.js"></script>
+<script type="module" src="resources/module-execution-order-mixed-2.js"></script>
<script type="module">
shouldBe("count++", "6");
finishJSTest();
(function () {
var element = document.createElement("script");
element.textContent = `
- import Cocoa from "./script-tests/module-inline-dynamic.js";
+ import Cocoa from "./resources/module-inline-dynamic.js";
var cocoa = new Cocoa();
debug("Module execution is confined in the module environment.");
</script>
<script src="../../../resources/js-test-post.js"></script>
<script type="module">
-import Cocoa from "./script-tests/module-inline-simple.js";
+import Cocoa from "./resources/module-inline-simple.js";
var cocoa = new Cocoa();
debug("Module execution is confined in the module environment.");
}
</script>
<script src="../../../resources/js-test-post.js"></script>
-<script type="module" onload="onLoad()" src="script-tests/module-load-event-with-src.js"></script>
+<script type="module" onload="onLoad()" src="resources/module-load-event-with-src.js"></script>
</body>
</html>
</script>
<script src="../../../resources/js-test-post.js"></script>
<script type="module">
-import "./script-tests/module-load-same-module-from-different-entry-point.js"
+import "./resources/module-load-same-module-from-different-entry-point.js"
debug('Executing the module.');
shouldBe(`window.moduleExecutedCount`, `1`);
var element = document.createElement("script");
element.type = "module";
-element.innerText = `import "./script-tests/module-load-same-module-from-different-entry-point.js"`;
+element.innerText = `import "./resources/module-load-same-module-from-different-entry-point.js"`;
element.onload = onLoad;
document.body.appendChild(element);
</script>
</script>
<script src="../../../resources/js-test-post.js"></script>
-<script type="module" src="./script-tests/module-load-same-module-from-different-entry-point.js" onload="onLoad()"></script>
-<script type="module" src="./script-tests/module-load-same-module-from-different-entry-point.js" onload="onLoad()"></script>
+<script type="module" src="./resources/module-load-same-module-from-different-entry-point.js" onload="onLoad()"></script>
+<script type="module" src="./resources/module-load-same-module-from-different-entry-point.js" onload="onLoad()"></script>
<script type="module">
finish();
</script>
</script>
<script src="../../../resources/js-test-post.js"></script>
<script type="module" onload="onLoad()">
-import "./script-tests/module-load-same-module-from-different-entry-point.js"
+import "./resources/module-load-same-module-from-different-entry-point.js"
debug('Executing the module.');
window.firstModuleIsExecuted = true;
</script>
<script type="module" onload="onLoad()">
-import "./script-tests/module-load-same-module-from-different-entry-point.js"
+import "./resources/module-load-same-module-from-different-entry-point.js"
debug('Executing the module.');
window.secondModuleIsExecuted = true;
</script>
}
</script>
<script src="../../../resources/js-test-post.js"></script>
-<script type="module" src="script-tests/module-not-found-error-event-with-src-and-import.js" onerror="onError()"></script>
+<script type="module" src="resources/module-not-found-error-event-with-src-and-import.js" onerror="onError()"></script>
<script type="module">
shouldNotBe(`error`, `null`);
shouldBe(`error.type`, `"error"`);
debug('Module is not executed yet.');
</script>
<script src="../../../resources/js-test-post.js"></script>
-<script type="module" src="./script-tests/module-src-current-script.js"></script>
+<script type="module" src="./resources/module-src-current-script.js"></script>
</body>
</html>
(function () {
var element = document.createElement('script');
element.type = 'module';
- element.src = './script-tests/module-src-dynamic.js';
+ element.src = './resources/module-src-dynamic.js';
document.body.appendChild(element);
}());
</script>
debug('Module is not executed yet.');
</script>
<script src="../../../resources/js-test-post.js"></script>
-<script type="module" src="./script-tests/module-src-simple.js"></script>
+<script type="module" src="./resources/module-src-simple.js"></script>
</body>
</html>
<script src="../../../resources/js-test-post.js"></script>
<script type="MoDuLe">
-import Cocoa from "./script-tests/module-inline-simple.js";
+import Cocoa from "./resources/module-inline-simple.js";
window.resolve1();
</script>
<script type="MODULE">
-import Cocoa from "./script-tests/module-inline-simple.js";
+import Cocoa from "./resources/module-inline-simple.js";
window.resolve2();
</script>
debug('Module is not executed yet.');
</script>
<script src="../../../resources/js-test-post.js"></script>
-<script type="module" onbeforeload="finishJSTest()" src="script-tests/module-will-fire-beforeload.js"></script>
+<script type="module" onbeforeload="finishJSTest()" src="resources/module-will-fire-beforeload.js"></script>
</body>
</html>
(function () {
var element = document.createElement('script');
element.noModule = true;
- element.src = './script-tests/error-classic-script.js';
+ element.src = './resources/error-classic-script.js';
document.body.appendChild(element);
setTimeout(function () {
shouldBeFalse(`executed`);
</script>
<script src="../../../resources/js-test-post.js"></script>
<script nomodule type="module">
-import Cocoa from "./script-tests/module-inline-simple.js";
+import Cocoa from "./resources/module-inline-simple.js";
var cocoa = new Cocoa();
debug("Module execution is confined in the module environment.");
debug('Module is not executed yet.');
</script>
<script src="../../../resources/js-test-post.js"></script>
-<script nomodule type="module" src="./script-tests/module-src-simple.js"></script>
+<script nomodule type="module" src="./resources/module-src-simple.js"></script>
</body>
</html>
description('Test nomodule prevents execution of classic script.');
window.executed = false;
</script>
-<script nomodule src="./script-tests/module-src-simple.js"></script>
+<script nomodule src="./resources/module-src-simple.js"></script>
<script>
shouldBeFalse(`executed`);
</script>
window.jsTestIsAsync = true;
</script>
<script src="../../../resources/js-test-post.js"></script>
-<script id="target" src="./script-tests/error-classic-script.js" nomodule></script>
+<script id="target" src="./resources/error-classic-script.js" nomodule></script>
<script id="target2">
window.executed2 = true;
</script>
--- /dev/null
+window.executed = true;
+testFailed("error");
+
--- /dev/null
+debug("import from loaded classic finish");
+window.imported = true;
--- /dev/null
+debug("import from loaded classic");
+import("./import-from-loaded-classic-finish.js").then(loaded);
--- /dev/null
+debug("import from loaded module finish");
+window.imported = true;
--- /dev/null
+debug("import from loaded module");
+import("./import-from-loaded-module-finish.js").then(loaded);
--- /dev/null
+import Cocoa from "./module-src-simple-cocoa.js";
+var cocoa = new Cocoa();
+
+debug("Module execution is confined in the module environment.");
+shouldBeEqualToString("typeof cocoa", "undefined");
+
+window.exportedCocoa = cocoa;
+shouldBeEqualToString("typeof exportedCocoa", "object");
+shouldBeEqualToString("exportedCocoa.taste()", "nice");
+export let ok = cocoa;
+window.imported = true;
--- /dev/null
+document.write("TEST FAILED");
+finishJSTest();
--- /dev/null
+debug("Executing the dependent module");
+throw new Error("out");
--- /dev/null
+import "./module-execution-error-inside-dependent-module-should-be-propagated-to-onerror-throw.js"
+testFailed("executed");
--- /dev/null
+shouldBe("count++", "5");
--- /dev/null
+import "./module-execution-order-mixed-matcha.js"
+
+shouldBe("count++", "2");
--- /dev/null
+import "./module-execution-order-mixed-matcha.js";
+
+shouldBe("count++", "1");
--- /dev/null
+shouldBe("count++", "0");
--- /dev/null
+shouldBe("count++", "11");
--- /dev/null
+import "./module-execution-order-mixed-with-classic-scripts-matcha.js"
+
+shouldBe("count++", "8");
--- /dev/null
+import "./module-execution-order-mixed-with-classic-scripts-matcha.js";
+
+shouldBe("count++", "7");
--- /dev/null
+shouldBe("count++", "6");
--- /dev/null
+import "./module-execution-order-mixed-with-classic-scripts-cocoa.js"
+import "./module-execution-order-mixed-with-classic-scripts-cappuccino.js"
+
+shouldBe("count++", "9");
--- /dev/null
+import "./module-execution-order-mixed-cocoa.js"
+import "./module-execution-order-mixed-cappuccino.js"
+
+shouldBe("count++", "3");
--- /dev/null
+export default class Cocoa {
+ taste() {
+ return "awesome";
+ }
+};
--- /dev/null
+export default class Cocoa {
+ taste() {
+ return "awesome";
+ }
+};
--- /dev/null
+debug('Executing a module with src attribute.');
+window.moduleExecuted = true;
--- /dev/null
+debug('Executing module-load-same-module-from-different-entry-point.js.');
+window.moduleExecutedCount++;
--- /dev/null
+import "./not-found.js"
--- /dev/null
+debug("Module execution is confined in the module environment.");
+shouldBe("document.currentScript", "null");
+finishJSTest();
--- /dev/null
+class Cocoa {
+ taste() {
+ return "nice";
+ }
+}
+
+export default Cocoa;
--- /dev/null
+import Cocoa from "./module-src-dynamic-cocoa.js";
+var cocoa = new Cocoa();
+
+debug("Module execution is confined in the module environment.");
+shouldBeEqualToString("typeof cocoa", "undefined");
+
+window.exportedCocoa = cocoa;
+shouldBeEqualToString("typeof exportedCocoa", "object");
+shouldBeEqualToString("exportedCocoa.taste()", "nice");
+finishJSTest();
--- /dev/null
+class Cocoa {
+ taste() {
+ return "nice";
+ }
+}
+
+export default Cocoa;
--- /dev/null
+import Cocoa from "./module-src-simple-cocoa.js";
+var cocoa = new Cocoa();
+
+debug("Module execution is confined in the module environment.");
+shouldBeEqualToString("typeof cocoa", "undefined");
+
+window.exportedCocoa = cocoa;
+shouldBeEqualToString("typeof exportedCocoa", "object");
+shouldBeEqualToString("exportedCocoa.taste()", "nice");
+finishJSTest();
--- /dev/null
+testFailed("executed");
-window.executed = true;
-testFailed("error");
-
dom/Range.cpp
dom/ScopedEventQueue.cpp
dom/ScriptElement.cpp
+ dom/ScriptElementCachedScriptFetcher.cpp
dom/ScriptExecutionContext.cpp
dom/ScriptRunner.cpp
dom/ScriptableDocumentParser.cpp
+2017-01-27 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ Implement dynamic-import for WebCore
+ https://bugs.webkit.org/show_bug.cgi?id=166926
+
+ Reviewed by Ryosuke Niwa.
+
+ This patch introduces browser side dynamic-import implementation.
+ The dynamic-import is new ES feature which is now stage 3.
+ The JSC shell already implements it.
+
+ The dynamic-import allows us to kick module loading in a dynamic manner.
+ For example, you can write,
+
+ await module = import(`${HOST}/hello.js`);
+
+ The dynamic `import` operator (this is not a function) returns a promise with
+ module namespace object if the module loading succeeds. Otherwise, it returns
+ a rejected promise.
+
+ And importantly, this feature allows us to kick module loading from classic script.
+ Previously, module loading can be only used from <script type="module"> tag. And
+ all the module loading is done statically.
+
+ * CMakeLists.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+ * bindings/js/CachedModuleScriptLoader.cpp:
+ (WebCore::CachedModuleScriptLoader::load):
+ * bindings/js/CachedScriptFetcher.cpp:
+ (WebCore::CachedScriptFetcher::create):
+ (WebCore::CachedScriptFetcher::requestModuleScript):
+ requestModuleScript function is used only when loading a new module script.
+ So, LoadableClassicScript should use requestScriptWithCache to load itself.
+ We pass String() for cross origin mode for null cross origin attribute as
+ specified.
+
+ (WebCore::CachedScriptFetcher::requestScriptWithCache):
+ * bindings/js/CachedScriptFetcher.h:
+ (WebCore::CachedScriptFetcher::CachedScriptFetcher):
+ * bindings/js/JSDOMWindowBase.cpp:
+ (WebCore::JSDOMWindowBase::moduleLoaderImportModule):
+ * bindings/js/JSDOMWindowBase.h:
+ * bindings/js/JSLazyEventListener.cpp:
+ (WebCore::JSLazyEventListener::initializeJSFunction):
+ * bindings/js/ScriptController.cpp:
+ (WebCore::ScriptController::executeScript):
+ * bindings/js/ScriptModuleLoader.cpp:
+ (WebCore::resolveModuleSpecifier):
+ Extract the part of resolving module specifier to a static function to use
+ it in ScriptModuleLoader::resolve and ScriptModuleLoader::importModule.
+
+ (WebCore::ScriptModuleLoader::resolve):
+ (WebCore::rejectPromise):
+ (WebCore::ScriptModuleLoader::importModule):
+ New hook moduleLoaderImportModule is implemented. This hook is called when
+ `import` operator is used. This hook is responsible to
+ 1. resolve the module name to obtain module specifier. (like, resolve the
+ relative URL to get absolute URL.)
+ 2. kick module loading with the resolved specifier.
+ When resolving the module name, the referrer information is needed.
+ For example, "./script.js" will be resolved to "http://example.com/script.js" if
+ the referrer module specifier is "http://example.com/".
+ If `import("./script.js")` is executed in the classic script
+ src="http://example.com/test.js", it starts loading "http://example.com/script.js".
+ So the information of the caller of `import` operator is necessary here.
+ This appropriate referrer is propagated by SourceOrigin.
+
+ * bindings/js/ScriptModuleLoader.h:
+ * dom/InlineClassicScript.h:
+ * dom/LoadableClassicScript.cpp:
+ (WebCore::LoadableClassicScript::load):
+ * dom/LoadableClassicScript.h:
+ * dom/LoadableModuleScript.h:
+ * dom/LoadableScript.h:
+ (WebCore::LoadableScript::LoadableScript):
+ (WebCore::LoadableScript::isClassicScript): Deleted.
+ (WebCore::LoadableScript::isModuleScript): Deleted.
+ * dom/ScriptElement.h:
+ * dom/ScriptElementCachedScriptFetcher.cpp: Copied from Source/WebCore/dom/InlineClassicScript.h.
+ (WebCore::ScriptElementCachedScriptFetcher::requestModuleScript):
+ This requestModuleScript will be used when the script tag (or modules imported from the script tag) uses `import` operator.
+ In classic scripts, `crossorigin` mode always becomes "omit" while module scripts
+ propagate the original `crossorigin` value.
+
+ * dom/ScriptElementCachedScriptFetcher.h: Copied from Source/WebCore/bindings/js/CachedScriptFetcher.h.
+ (WebCore::ScriptElementCachedScriptFetcher::crossOriginMode):
+ (WebCore::ScriptElementCachedScriptFetcher::ScriptElementCachedScriptFetcher):
+
2017-01-26 Chris Dumez <cdumez@apple.com>
Revert r210474 it is no longer needed
E3B2F0F01D7F4CB500B0C9D1 /* LoadableClassicScript.h in Headers */ = {isa = PBXBuildFile; fileRef = E3B2F0E41D7F35EC00B0C9D1 /* LoadableClassicScript.h */; settings = {ATTRIBUTES = (Private, ); }; };
E3B7C0631DC34160001FB0B8 /* JSDocumentDOMJIT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3B7C0621DC3415A001FB0B8 /* JSDocumentDOMJIT.cpp */; };
E3C99A091DC3D41C00794AD3 /* DOMJITCheckDOM.h in Headers */ = {isa = PBXBuildFile; fileRef = E3C99A081DC3D41700794AD3 /* DOMJITCheckDOM.h */; };
+ E3E4E2A71E3B17100023BB8A /* ScriptElementCachedScriptFetcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3E4E2A51E3B16FC0023BB8A /* ScriptElementCachedScriptFetcher.cpp */; };
+ E3E4E2A81E3B17100023BB8A /* ScriptElementCachedScriptFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = E3E4E2A61E3B16FC0023BB8A /* ScriptElementCachedScriptFetcher.h */; settings = {ATTRIBUTES = (Private, ); }; };
E3FA38641D71812D00AA5950 /* PendingScriptClient.h in Headers */ = {isa = PBXBuildFile; fileRef = E3FA38611D716E7600AA5950 /* PendingScriptClient.h */; };
E401C27517CE53EC00C41A35 /* ElementIteratorAssertions.h in Headers */ = {isa = PBXBuildFile; fileRef = E401C27417CE53EC00C41A35 /* ElementIteratorAssertions.h */; settings = {ATTRIBUTES = (Private, ); }; };
E401E0A41C3C0B8300F34D10 /* StyleChange.h in Headers */ = {isa = PBXBuildFile; fileRef = E401E0A31C3C0B8300F34D10 /* StyleChange.h */; settings = {ATTRIBUTES = (Private, ); }; };
E3B7C0621DC3415A001FB0B8 /* JSDocumentDOMJIT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDocumentDOMJIT.cpp; sourceTree = "<group>"; };
E3C99A081DC3D41700794AD3 /* DOMJITCheckDOM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITCheckDOM.h; sourceTree = "<group>"; };
E3D049931DADC04500718F3C /* NodeConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NodeConstants.h; sourceTree = "<group>"; };
+ E3E4E2A51E3B16FC0023BB8A /* ScriptElementCachedScriptFetcher.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptElementCachedScriptFetcher.cpp; sourceTree = "<group>"; };
+ E3E4E2A61E3B16FC0023BB8A /* ScriptElementCachedScriptFetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptElementCachedScriptFetcher.h; sourceTree = "<group>"; };
E3FA38611D716E7600AA5950 /* PendingScriptClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PendingScriptClient.h; sourceTree = "<group>"; };
E401C27417CE53EC00C41A35 /* ElementIteratorAssertions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementIteratorAssertions.h; sourceTree = "<group>"; };
E401E0A31C3C0B8300F34D10 /* StyleChange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleChange.h; sourceTree = "<group>"; };
4998AED013FB224D0090B1AA /* ScriptedAnimationController.h */,
08A484750E5272C500C3FE76 /* ScriptElement.cpp */,
08A484760E5272C500C3FE76 /* ScriptElement.h */,
+ E3E4E2A51E3B16FC0023BB8A /* ScriptElementCachedScriptFetcher.cpp */,
+ E3E4E2A61E3B16FC0023BB8A /* ScriptElementCachedScriptFetcher.h */,
E11C9DAF0EB3699500E409DB /* ScriptExecutionContext.cpp */,
E11C9D9A0EB3681200E409DB /* ScriptExecutionContext.h */,
8A413ADF1207BBA50082016E /* ScriptRunner.cpp */,
26EA89A71B4F2B75008C5FD2 /* HashableActionList.h in Headers */,
8482B7461198C35400BFB005 /* HashChangeEvent.h in Headers */,
A8748BE012CBF2DC001FBA41 /* HashTools.h in Headers */,
+ E3E4E2A81E3B17100023BB8A /* ScriptElementCachedScriptFetcher.h in Headers */,
F55B3DC01251F12D003EF269 /* HiddenInputType.h in Headers */,
515BE19C1D54F6C100DD7C68 /* HIDGamepad.h in Headers */,
515BE19E1D54F6C100DD7C68 /* HIDGamepadProvider.h in Headers */,
29A8124A0FBB9CA900510293 /* WebAccessibilityObjectWrapperBase.mm in Sources */,
AAA728F816D1D8BC00D3BBC6 /* WebAccessibilityObjectWrapperIOS.mm in Sources */,
AA478A8016CD70C3007D1BB4 /* WebAccessibilityObjectWrapperMac.mm in Sources */,
+ E3E4E2A71E3B17100023BB8A /* ScriptElementCachedScriptFetcher.cpp in Sources */,
2D3EF4491917915C00034184 /* WebActionDisablingCALayerDelegate.mm in Sources */,
120DE3ED1C86CA3E00B6D4DD /* WebAnimation.cpp in Sources */,
07D637411BB0B11300256CE9 /* WebAudioSourceProviderAVFObjC.mm in Sources */,
bool CachedModuleScriptLoader::load(Document& document, const URL& sourceURL)
{
ASSERT(!m_cachedScript);
- m_cachedScript = m_scriptFetcher->requestScriptWithCache(document, sourceURL);
+ m_cachedScript = m_scriptFetcher->requestModuleScript(document, sourceURL);
if (!m_cachedScript)
return false;
namespace WebCore {
-CachedResourceHandle<CachedScript> CachedScriptFetcher::requestScriptWithCache(Document& document, const URL& sourceURL) const
+Ref<CachedScriptFetcher> CachedScriptFetcher::create(const String& charset)
+{
+ return adoptRef(*new CachedScriptFetcher(charset));
+}
+
+CachedResourceHandle<CachedScript> CachedScriptFetcher::requestModuleScript(Document& document, const URL& sourceURL) const
+{
+ return requestScriptWithCache(document, sourceURL, String());
+}
+
+CachedResourceHandle<CachedScript> CachedScriptFetcher::requestScriptWithCache(Document& document, const URL& sourceURL, const String& crossOriginMode) const
{
auto* settings = document.settings();
if (settings && !settings->isScriptEnabled())
options.contentSecurityPolicyImposition = hasKnownNonce ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck;
CachedResourceRequest request(ResourceRequest(sourceURL), options);
- request.setAsPotentiallyCrossOrigin(m_crossOriginMode, document);
+ request.setAsPotentiallyCrossOrigin(crossOriginMode, document);
request.upgradeInsecureRequestIfNeeded(document);
request.setCharset(m_charset);
- request.setInitiator(m_initiatorName);
+ if (!m_initiatorName.isNull())
+ request.setInitiator(m_initiatorName);
return document.cachedResourceLoader().requestScript(WTFMove(request));
}
class CachedScriptFetcher : public JSC::ScriptFetcher {
public:
- CachedResourceHandle<CachedScript> requestScriptWithCache(Document&, const URL& sourceURL) const;
+ virtual CachedResourceHandle<CachedScript> requestModuleScript(Document&, const URL& sourceURL) const;
+
+ static Ref<CachedScriptFetcher> create(const String& charset);
protected:
- CachedScriptFetcher(const String& nonce, const String& crossOriginMode, const String& charset, const AtomicString& initiatorName, bool isInUserAgentShadowTree)
+ CachedScriptFetcher(const String& nonce, const String& charset, const AtomicString& initiatorName, bool isInUserAgentShadowTree)
: m_nonce(nonce)
- , m_crossOriginMode(crossOriginMode)
, m_charset(charset)
, m_initiatorName(initiatorName)
, m_isInUserAgentShadowTree(isInUserAgentShadowTree)
{
}
+ CachedScriptFetcher(const String& charset)
+ : m_charset(charset)
+ {
+ }
+
+ CachedResourceHandle<CachedScript> requestScriptWithCache(Document&, const URL& sourceURL, const String& crossOriginMode) const;
+
private:
String m_nonce;
- String m_crossOriginMode;
String m_charset;
AtomicString m_initiatorName;
bool m_isInUserAgentShadowTree { false };
&javaScriptRuntimeFlags,
&queueTaskToEventLoop,
&shouldInterruptScriptBeforeTimeout,
- nullptr,
+ &moduleLoaderImportModule,
&moduleLoaderResolve,
&moduleLoaderFetch,
nullptr,
return JSC::jsUndefined();
}
+JSC::JSInternalPromise* JSDOMWindowBase::moduleLoaderImportModule(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSString* moduleName, const JSC::SourceOrigin& sourceOrigin)
+{
+ JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject);
+ if (RefPtr<Document> document = thisObject->wrapped().document())
+ return document->moduleLoader()->importModule(globalObject, exec, moduleLoader, moduleName, sourceOrigin);
+ JSC::JSInternalPromiseDeferred* deferred = JSC::JSInternalPromiseDeferred::create(exec, globalObject);
+ return deferred->reject(exec, jsUndefined());
+}
+
} // namespace WebCore
static JSC::JSInternalPromise* moduleLoaderResolve(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue, JSC::JSValue);
static JSC::JSInternalPromise* moduleLoaderFetch(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue);
static JSC::JSValue moduleLoaderEvaluate(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue, JSC::JSValue);
+ static JSC::JSInternalPromise* moduleLoaderImportModule(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSString*, const JSC::SourceOrigin&);
RefPtr<DOMWindow> m_wrapped;
JSDOMWindowShell* m_shell;
#include "config.h"
#include "JSLazyEventListener.h"
+#include "CachedScriptFetcher.h"
#include "ContentSecurityPolicy.h"
#include "Frame.h"
#include "JSNode.h"
JSObject* jsFunction = constructFunctionSkippingEvalEnabledCheck(
exec, exec->lexicalGlobalObject(), args, Identifier::fromString(exec, m_functionName),
- SourceOrigin { m_sourceURL }, m_sourceURL, m_sourcePosition, overrideLineNumber);
+ SourceOrigin { m_sourceURL, CachedScriptFetcher::create(document.charset()) }, m_sourceURL, m_sourcePosition, overrideLineNumber);
if (UNLIKELY(scope.exception())) {
reportCurrentException(exec);
JSValue ScriptController::executeScript(const String& script, bool forceUserGesture, ExceptionDetails* exceptionDetails)
{
UserGestureIndicator gestureIndicator(forceUserGesture ? std::optional<ProcessingUserGestureState>(ProcessingUserGesture) : std::nullopt);
- return executeScript(ScriptSourceCode(script, m_frame.document()->url()), exceptionDetails);
+ return executeScript(ScriptSourceCode(script, m_frame.document()->url(), TextPosition(), JSC::SourceProviderSourceType::Program, CachedScriptFetcher::create(m_frame.document()->charset())), exceptionDetails);
}
JSValue ScriptController::executeScript(const ScriptSourceCode& sourceCode, ExceptionDetails* exceptionDetails)
#include "CachedModuleScriptLoader.h"
#include "CachedScript.h"
+#include "CachedScriptFetcher.h"
#include "Document.h"
#include "Frame.h"
#include "JSDOMBinding.h"
#include "MIMETypeRegistry.h"
#include "ScriptController.h"
#include "ScriptSourceCode.h"
+#include <runtime/Completion.h>
#include <runtime/JSInternalPromise.h>
#include <runtime/JSInternalPromiseDeferred.h>
#include <runtime/JSModuleRecord.h>
return importerModuleKey.isSymbol() || importerModuleKey.isUndefined();
}
+static Expected<URL, ASCIILiteral> resolveModuleSpecifier(Document& document, const String& specifier, const URL& baseURL)
+{
+ // https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier
+
+ URL absoluteURL(URL(), specifier);
+ if (absoluteURL.isValid())
+ return absoluteURL;
+
+ if (!specifier.startsWith('/') && !specifier.startsWith("./") && !specifier.startsWith("../"))
+ return makeUnexpected(ASCIILiteral("Module specifier does not start with \"/\", \"./\", or \"../\"."));
+
+ auto result = document.completeURL(specifier, baseURL);
+ if (!result.isValid())
+ return makeUnexpected(ASCIILiteral("Module name does not resolve to a valid URL."));
+ return result;
+}
+
JSC::JSInternalPromise* ScriptModuleLoader::resolve(JSC::JSGlobalObject* jsGlobalObject, JSC::ExecState* exec, JSC::JSModuleLoader*, JSC::JSValue moduleNameValue, JSC::JSValue importerModuleKey, JSC::JSValue)
{
auto& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(jsGlobalObject);
return jsPromise.promise();
}
- // https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier
-
if (!moduleNameValue.isString()) {
- promise->reject(TypeError, ASCIILiteral("Module specifier is not Symbol or String."));
+ promise->reject(TypeError, ASCIILiteral("Importer module key is not a Symbol or a String."));
return jsPromise.promise();
}
String specifier = asString(moduleNameValue)->value(exec);
-
- // 1. Apply the URL parser to specifier. If the result is not failure, return the result.
- URL absoluteURL(URL(), specifier);
- if (absoluteURL.isValid()) {
- promise->resolve<IDLDOMString>(absoluteURL.string());
- return jsPromise.promise();
- }
-
- // 2. If specifier does not start with the character U+002F SOLIDUS (/), the two-character sequence U+002E FULL STOP, U+002F SOLIDUS (./),
- // or the three-character sequence U+002E FULL STOP, U+002E FULL STOP, U+002F SOLIDUS (../), return failure and abort these steps.
- if (!specifier.startsWith('/') && !specifier.startsWith("./") && !specifier.startsWith("../")) {
- promise->reject(TypeError, ASCIILiteral("Module specifier does not start with \"/\", \"./\", or \"../\"."));
- return jsPromise.promise();
- }
-
- // 3. Return the result of applying the URL parser to specifier with script's base URL as the base URL.
-
- URL completedURL;
-
+ URL baseURL;
if (isRootModule(importerModuleKey))
- completedURL = m_document.completeURL(specifier);
- else if (importerModuleKey.isString()) {
+ baseURL = m_document.baseURL();
+ else {
+ ASSERT(importerModuleKey.isString());
URL importerModuleRequestURL(URL(), asString(importerModuleKey)->value(exec));
- if (!importerModuleRequestURL.isValid()) {
- promise->reject(TypeError, ASCIILiteral("Importer module key is an invalid URL."));
- return jsPromise.promise();
- }
+ ASSERT_WITH_MESSAGE(importerModuleRequestURL.isValid(), "Invalid module referrer never starts importing dependent modules.");
- URL importerModuleResponseURL = m_requestURLToResponseURLMap.get(importerModuleRequestURL);
- if (!importerModuleResponseURL.isValid()) {
- promise->reject(TypeError, ASCIILiteral("Importer module has an invalid response URL."));
- return jsPromise.promise();
- }
-
- completedURL = m_document.completeURL(specifier, importerModuleResponseURL);
- } else {
- promise->reject(TypeError, ASCIILiteral("Importer module key is not Symbol or String."));
- return jsPromise.promise();
+ auto iterator = m_requestURLToResponseURLMap.find(importerModuleRequestURL);
+ ASSERT_WITH_MESSAGE(iterator != m_requestURLToResponseURLMap.end(), "Module referrer must register itself to the map before starting importing dependent modules.");
+ baseURL = iterator->value;
}
- if (!completedURL.isValid()) {
- promise->reject(TypeError, ASCIILiteral("Module name constructs an invalid URL."));
+ auto result = resolveModuleSpecifier(m_document, specifier, baseURL);
+ if (!result) {
+ promise->reject(TypeError, result.error());
return jsPromise.promise();
}
- promise->resolve<IDLDOMString>(completedURL.string());
+ promise->resolve<IDLDOMString>(result->string());
return jsPromise.promise();
}
return JSC::jsUndefined();
}
+static JSC::JSInternalPromise* rejectPromise(JSC::ExecState& state, JSDOMGlobalObject& globalObject, ExceptionCode ec, ASCIILiteral message)
+{
+ auto& jsPromise = *JSC::JSInternalPromiseDeferred::create(&state, &globalObject);
+ auto deferred = DeferredPromise::create(globalObject, jsPromise);
+ deferred->reject(ec, WTFMove(message));
+ return jsPromise.promise();
+}
+
+JSC::JSInternalPromise* ScriptModuleLoader::importModule(JSC::JSGlobalObject* jsGlobalObject, JSC::ExecState* exec, JSC::JSModuleLoader*, JSC::JSString* moduleName, const JSC::SourceOrigin& sourceOrigin)
+{
+ auto& state = *exec;
+ JSC::VM& vm = exec->vm();
+ auto& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(jsGlobalObject);
+
+ // FIXME: setTimeout and setInterval with "string()" should propagate SourceOrigin.
+ // https://webkit.org/b/167097
+ ASSERT_WITH_MESSAGE(!sourceOrigin.isNull(), "If SourceOrigin is null, this function is not invoked.");
+ if (!sourceOrigin.fetcher())
+ return rejectPromise(state, globalObject, TypeError, ASCIILiteral("Could not use import operator in this context."));
+
+ URL baseURL(URL(), sourceOrigin.string());
+ if (!baseURL.isValid())
+ return rejectPromise(state, globalObject, TypeError, ASCIILiteral("Importer module key is not Symbol or String."));
+
+ auto specifier = moduleName->value(exec);
+ auto result = resolveModuleSpecifier(m_document, specifier, baseURL);
+ if (!result)
+ return rejectPromise(state, globalObject, TypeError, result.error());
+
+ return JSC::importModule(exec, JSC::Identifier::fromString(&vm, result->string()), JSC::JSScriptFetcher::create(vm, sourceOrigin.fetcher() ));
+}
+
void ScriptModuleLoader::notifyFinished(CachedModuleScriptLoader& loader, RefPtr<DeferredPromise> promise)
{
// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script
class JSGlobalObject;
class JSInternalPromise;
class JSModuleLoader;
+class SourceOrigin;
}
JSC::JSInternalPromise* resolve(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue moduleName, JSC::JSValue importerModuleKey, JSC::JSValue scriptFetcher);
JSC::JSInternalPromise* fetch(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue moduleKey, JSC::JSValue scriptFetcher);
JSC::JSValue evaluate(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue moduleKey, JSC::JSValue moduleRecord, JSC::JSValue scriptFetcher);
+ JSC::JSInternalPromise* importModule(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSString*, const JSC::SourceOrigin&);
private:
void notifyFinished(CachedModuleScriptLoader&, RefPtr<DeferredPromise>) final;
#pragma once
-#include "CachedScriptFetcher.h"
+#include "ScriptElementCachedScriptFetcher.h"
namespace WebCore {
class ScriptElement;
-class InlineClassicScript final : public CachedScriptFetcher {
+class InlineClassicScript final : public ScriptElementCachedScriptFetcher {
public:
static Ref<InlineClassicScript> create(ScriptElement&);
+ bool isClassicScript() const final { return true; }
+ bool isModuleScript() const final { return false; }
+
private:
InlineClassicScript(const String& nonce, const String& crossOriginMode, const String& charset, const AtomicString& initiatorName, bool isInUserAgentShadowTree)
- : CachedScriptFetcher(nonce, crossOriginMode, charset, initiatorName, isInUserAgentShadowTree)
+ : ScriptElementCachedScriptFetcher(nonce, crossOriginMode, charset, initiatorName, isInUserAgentShadowTree)
{
}
};
bool LoadableClassicScript::load(Document& document, const URL& sourceURL)
{
ASSERT(!m_cachedScript);
- m_cachedScript = requestScriptWithCache(document, sourceURL);
+ m_cachedScript = requestScriptWithCache(document, sourceURL, crossOriginMode());
if (!m_cachedScript)
return false;
m_cachedScript->addClient(*this);
bool wasCanceled() const final;
CachedScript& cachedScript() { return *m_cachedScript; }
+
bool isClassicScript() const final { return true; }
+ bool isModuleScript() const final { return false; }
void execute(ScriptElement&) final;
bool wasCanceled() const final;
CachedModuleScript& moduleScript() { return m_moduleScript.get(); }
+
+ bool isClassicScript() const final { return false; }
bool isModuleScript() const final { return true; }
void execute(ScriptElement&) final;
#pragma once
-#include "CachedScriptFetcher.h"
+#include "ScriptElementCachedScriptFetcher.h"
#include <runtime/ConsoleTypes.h>
#include <wtf/HashCountedSet.h>
#include <wtf/RefCounted.h>
class LoadableScriptClient;
class ScriptElement;
-class LoadableScript : public CachedScriptFetcher {
+class LoadableScript : public ScriptElementCachedScriptFetcher {
public:
enum class ErrorType {
CachedScript,
void addClient(LoadableScriptClient&);
void removeClient(LoadableScriptClient&);
- virtual bool isClassicScript() const { return false; }
- virtual bool isModuleScript() const { return false; }
-
protected:
LoadableScript(const String& nonce, const String& crossOriginMode, const String& charset, const AtomicString& initiatorName, bool isInUserAgentShadowTree)
- : CachedScriptFetcher(nonce, crossOriginMode, charset, initiatorName, isInUserAgentShadowTree)
+ : ScriptElementCachedScriptFetcher(nonce, crossOriginMode, charset, initiatorName, isInUserAgentShadowTree)
{
}
bool ignoresLoadRequest() const;
bool isScriptForEventSupported() const;
- CachedResourceHandle<CachedScript> requestScriptWithCache(const URL&, const String& nonceAttribute, const String& crossoriginAttribute);
-
bool requestClassicScript(const String& sourceURL);
bool requestModuleScript(const TextPosition& scriptStartPosition);
--- /dev/null
+/*
+ * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScriptElementCachedScriptFetcher.h"
+
+#include "Element.h"
+#include "ScriptElement.h"
+
+namespace WebCore {
+
+CachedResourceHandle<CachedScript> ScriptElementCachedScriptFetcher::requestModuleScript(Document& document, const URL& sourceURL) const
+{
+ // https://github.com/tc39/proposal-dynamic-import/blob/master/HTML Integration.md
+ // If the fetcher is not module script, credential mode is always "omit".
+
+ return requestScriptWithCache(document, sourceURL, isClassicScript() ? ASCIILiteral("omit") : m_crossOriginMode);
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "CachedScriptFetcher.h"
+
+namespace WebCore {
+
+class ScriptElementCachedScriptFetcher : public CachedScriptFetcher {
+public:
+ virtual CachedResourceHandle<CachedScript> requestModuleScript(Document&, const URL& sourceURL) const;
+
+ virtual bool isClassicScript() const = 0;
+ virtual bool isModuleScript() const = 0;
+
+ const String& crossOriginMode() const { return m_crossOriginMode; }
+
+protected:
+ ScriptElementCachedScriptFetcher(const String& nonce, const String& crossOriginMode, const String& charset, const AtomicString& initiatorName, bool isInUserAgentShadowTree)
+ : CachedScriptFetcher(nonce, charset, initiatorName, isInUserAgentShadowTree)
+ , m_crossOriginMode(crossOriginMode)
+ {
+ }
+
+private:
+ String m_crossOriginMode;
+};
+
+} // namespace WebCore