Title: [211473] trunk
Revision
211473
Author
utatane....@gmail.com
Date
2017-02-01 02:00:32 -0800 (Wed, 01 Feb 2017)

Log Message

Propagate networking errors correctly for import() operator
https://bugs.webkit.org/show_bug.cgi?id=167501

Reviewed by Ryosuke Niwa.

.:

* Source/ModuleFetchFailureKind.h: Added.

Source/WebCore:

We use the promise chain inside the module loader pipeline.
The problem is that,

1. The errors of loading module scripts are propagated through the promise's rejection.
2. Some module related errors like syntax error (when scanning module dependencies) are
   reported at loading time (evaluating time). These errors are propagated through the
   promise rejections and dumped to the console. LoadableModuleScript set catch handler
   for that and print these errors to the console for ScriptElement.
3. Some of errors are already reported to the console. For example, networking errors
   are reported by the CachedModuleLoader.
4. But there is no way to distinguish between (2) and (3) at the catch handler.

Previously, we propagate the special symbol for the already reported errors to distinguish
that. This was OK because these errors cannot be catched by the user code. However,
recent `import()` call needs to expose these errors to the user code. So now, accidentally,
the special purpose symbol is exposed.

Instead of propagating the special symbol, this patch just propagates the errors. But these
error objects are annotated with the private symbol. So these errors can be distinguished
from the other ones.

Currently, we do not have the way to expose the error details to the client of the
CachedScript. So we just report the error with the failed / canceled. This should be
more descriptive error messages in the separate patch[1].

[1]: https://bugs.webkit.org/show_bug.cgi?id=167553

Tests: http/tests/security/mixedContent/import-insecure-script-in-iframe.html
       js/dom/modules/import-not-found-error.html

* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSDOMPromise.h:
(WebCore::DeferredPromise::resolveWithCallback):
(WebCore::DeferredPromise::rejectWithCallback):
* bindings/js/ScriptController.cpp:
(WebCore::ScriptController::setupModuleScriptHandlers):
* bindings/js/ScriptController.h:
(WebCore::ScriptController::moduleLoaderAlreadyReportedErrorSymbol): Deleted.
(WebCore::ScriptController::moduleLoaderFetchingIsCanceledSymbol): Deleted.
* bindings/js/ScriptModuleLoader.cpp:
(WebCore::rejectToPropagateNetworkError):
(WebCore::ScriptModuleLoader::fetch):
(WebCore::ScriptModuleLoader::notifyFinished):
* bindings/js/WebCoreBuiltinNames.h:

LayoutTests:

* http/tests/security/mixedContent/import-insecure-script-in-iframe-expected.txt: Added.
* http/tests/security/mixedContent/import-insecure-script-in-iframe.html: Added.
* http/tests/security/mixedContent/resources/frame-with-insecure-import.html: Added.
* js/dom/modules/import-not-found-error-expected.txt: Added.
* js/dom/modules/import-not-found-error.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/ChangeLog (211472 => 211473)


--- trunk/ChangeLog	2017-02-01 07:55:44 UTC (rev 211472)
+++ trunk/ChangeLog	2017-02-01 10:00:32 UTC (rev 211473)
@@ -1,3 +1,12 @@
+2017-02-01  Yusuke Suzuki  <utatane....@gmail.com>
+
+        Propagate networking errors correctly for import() operator
+        https://bugs.webkit.org/show_bug.cgi?id=167501
+
+        Reviewed by Ryosuke Niwa.
+
+        * Source/ModuleFetchFailureKind.h: Added.
+
 2017-01-31  Carlos Garcia Campos  <cgar...@igalia.com>
 
         Unreviewed. Update OptionsGTK.cmake and NEWS for 2.15.4 release.

Modified: trunk/LayoutTests/ChangeLog (211472 => 211473)


--- trunk/LayoutTests/ChangeLog	2017-02-01 07:55:44 UTC (rev 211472)
+++ trunk/LayoutTests/ChangeLog	2017-02-01 10:00:32 UTC (rev 211473)
@@ -1,3 +1,16 @@
+2017-02-01  Yusuke Suzuki  <utatane....@gmail.com>
+
+        Propagate networking errors correctly for import() operator
+        https://bugs.webkit.org/show_bug.cgi?id=167501
+
+        Reviewed by Ryosuke Niwa.
+
+        * http/tests/security/mixedContent/import-insecure-script-in-iframe-expected.txt: Added.
+        * http/tests/security/mixedContent/import-insecure-script-in-iframe.html: Added.
+        * http/tests/security/mixedContent/resources/frame-with-insecure-import.html: Added.
+        * js/dom/modules/import-not-found-error-expected.txt: Added.
+        * js/dom/modules/import-not-found-error.html: Added.
+
 2017-01-31  Wenson Hsieh  <wenson_hs...@apple.com>
 
         Regression (Safari 10.1): Pressing Return in a contenteditable no longer inserts a line break under certain conditions

Added: trunk/LayoutTests/http/tests/security/mixedContent/import-insecure-script-in-iframe-expected.txt (0 => 211473)


--- trunk/LayoutTests/http/tests/security/mixedContent/import-insecure-script-in-iframe-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/security/mixedContent/import-insecure-script-in-iframe-expected.txt	2017-02-01 10:00:32 UTC (rev 211473)
@@ -0,0 +1,12 @@
+CONSOLE MESSAGE: line 1: [blocked] The page at https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-import.html was not allowed to run insecure content from http://127.0.0.1:8080/security/mixedContent/resources/script.js.
+
+This test loads a secure iframe that attempt to import() a module script via HTTP. Since the iframe's content is of a secure origin, importing a module script via HTTP should result in a mixed content error.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS window.data is "TypeError: Importing a module script failed."
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/security/mixedContent/import-insecure-script-in-iframe.html (0 => 211473)


--- trunk/LayoutTests/http/tests/security/mixedContent/import-insecure-script-in-iframe.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/security/mixedContent/import-insecure-script-in-iframe.html	2017-02-01 10:00:32 UTC (rev 211473)
@@ -0,0 +1,21 @@
+<html>
+<body>
+<script src=""
+<script>
+description(`This test loads a secure iframe that attempt to import() a module script via HTTP.
+Since the iframe's content is of a secure origin, importing a module script via HTTP should result
+in a mixed content error.
+`);
+window.jsTestIsAsync = true;
+window.data = ""
+window.addEventListener("message", function (error) {
+    window.data = ""
+    shouldBe(`window.data`, `"TypeError: Importing a module script failed."`);
+    finishJSTest();
+}, false);
+</script>
+<script src=""
+<p></p>
+<iframe src=""
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/security/mixedContent/resources/frame-with-insecure-import.html (0 => 211473)


--- trunk/LayoutTests/http/tests/security/mixedContent/resources/frame-with-insecure-import.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/security/mixedContent/resources/frame-with-insecure-import.html	2017-02-01 10:00:32 UTC (rev 211473)
@@ -0,0 +1,8 @@
+<script>
+window._onload_ = function() {
+    import("http://127.0.0.1:8080/security/mixedContent/resources/script.js").catch(function (error) {
+        if (window.parent)
+            window.parent.postMessage(String(error), '*');
+    });
+};
+</script>

Added: trunk/LayoutTests/js/dom/modules/import-not-found-error-expected.txt (0 => 211473)


--- trunk/LayoutTests/js/dom/modules/import-not-found-error-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/dom/modules/import-not-found-error-expected.txt	2017-02-01 10:00:32 UTC (rev 211473)
@@ -0,0 +1,10 @@
+Test import with non existing module.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS String(error) is "TypeError: Importing a module script failed."
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/dom/modules/import-not-found-error.html (0 => 211473)


--- trunk/LayoutTests/js/dom/modules/import-not-found-error.html	                        (rev 0)
+++ trunk/LayoutTests/js/dom/modules/import-not-found-error.html	2017-02-01 10:00:32 UTC (rev 211473)
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script>
+description('Test import with non existing module.');
+
+window.jsTestIsAsync = true;
+</script>
+<script src=""
+<script>
+var error = null;
+(async function () {
+    try {
+        await import(`./resources/import-not-found.js`);
+    } catch (e) {
+        error = e;
+    }
+    shouldBeEqualToString(`String(error)`, `TypeError: Importing a module script failed.`);
+    finishJSTest();
+}());
+</script>
+</body>
+</html>

Added: trunk/Source/ModuleFetchFailureKind.h (0 => 211473)


--- trunk/Source/ModuleFetchFailureKind.h	                        (rev 0)
+++ trunk/Source/ModuleFetchFailureKind.h	2017-02-01 10:00:32 UTC (rev 211473)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 Yusuke Suzuki <utatane....@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
+
+namespace WebCore {
+
+enum class ModuleFetchFailureKind {
+    WasErrored,
+    WasCanceled,
+};
+
+} // namespace WebCore
+

Modified: trunk/Source/WebCore/ChangeLog (211472 => 211473)


--- trunk/Source/WebCore/ChangeLog	2017-02-01 07:55:44 UTC (rev 211472)
+++ trunk/Source/WebCore/ChangeLog	2017-02-01 10:00:32 UTC (rev 211473)
@@ -1,3 +1,55 @@
+2017-02-01  Yusuke Suzuki  <utatane....@gmail.com>
+
+        Propagate networking errors correctly for import() operator
+        https://bugs.webkit.org/show_bug.cgi?id=167501
+
+        Reviewed by Ryosuke Niwa.
+
+        We use the promise chain inside the module loader pipeline.
+        The problem is that,
+
+        1. The errors of loading module scripts are propagated through the promise's rejection.
+        2. Some module related errors like syntax error (when scanning module dependencies) are
+           reported at loading time (evaluating time). These errors are propagated through the
+           promise rejections and dumped to the console. LoadableModuleScript set catch handler
+           for that and print these errors to the console for ScriptElement.
+        3. Some of errors are already reported to the console. For example, networking errors
+           are reported by the CachedModuleLoader.
+        4. But there is no way to distinguish between (2) and (3) at the catch handler.
+
+        Previously, we propagate the special symbol for the already reported errors to distinguish
+        that. This was OK because these errors cannot be catched by the user code. However,
+        recent `import()` call needs to expose these errors to the user code. So now, accidentally,
+        the special purpose symbol is exposed.
+
+        Instead of propagating the special symbol, this patch just propagates the errors. But these
+        error objects are annotated with the private symbol. So these errors can be distinguished
+        from the other ones.
+
+        Currently, we do not have the way to expose the error details to the client of the
+        CachedScript. So we just report the error with the failed / canceled. This should be
+        more descriptive error messages in the separate patch[1].
+
+        [1]: https://bugs.webkit.org/show_bug.cgi?id=167553
+
+        Tests: http/tests/security/mixedContent/import-insecure-script-in-iframe.html
+               js/dom/modules/import-not-found-error.html
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSDOMPromise.h:
+        (WebCore::DeferredPromise::resolveWithCallback):
+        (WebCore::DeferredPromise::rejectWithCallback):
+        * bindings/js/ScriptController.cpp:
+        (WebCore::ScriptController::setupModuleScriptHandlers):
+        * bindings/js/ScriptController.h:
+        (WebCore::ScriptController::moduleLoaderAlreadyReportedErrorSymbol): Deleted.
+        (WebCore::ScriptController::moduleLoaderFetchingIsCanceledSymbol): Deleted.
+        * bindings/js/ScriptModuleLoader.cpp:
+        (WebCore::rejectToPropagateNetworkError):
+        (WebCore::ScriptModuleLoader::fetch):
+        (WebCore::ScriptModuleLoader::notifyFinished):
+        * bindings/js/WebCoreBuiltinNames.h:
+
 2017-01-31  Wenson Hsieh  <wenson_hs...@apple.com>
 
         Regression (Safari 10.1): Pressing Return in a contenteditable no longer inserts a line break under certain conditions

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (211472 => 211473)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-02-01 07:55:44 UTC (rev 211472)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2017-02-01 10:00:32 UTC (rev 211473)
@@ -2675,6 +2675,7 @@
 		6F995A391A70833700A735F4 /* JSWebGLVertexArrayObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6F995A2F1A70833700A735F4 /* JSWebGLVertexArrayObject.cpp */; };
 		6F995A3A1A70833700A735F4 /* JSWebGLVertexArrayObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F995A301A70833700A735F4 /* JSWebGLVertexArrayObject.h */; };
 		6FA4454E898F2FC168BC38C1 /* JSBeforeUnloadEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 29E04A27BED2F81F98E9022B /* JSBeforeUnloadEvent.h */; };
+		709A01FE1E3D0BDD006B0D4C /* ModuleFetchFailureKind.h in Headers */ = {isa = PBXBuildFile; fileRef = 709A01FD1E3D0BCC006B0D4C /* ModuleFetchFailureKind.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		70F546E8B8B5D7DC54EE144E /* JSBeforeUnloadEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8225432CA9D4B4CF4628EC7F /* JSBeforeUnloadEvent.cpp */; };
 		7117445914BC34EC00EE5FC8 /* SVGTextMetricsBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 7117445714BC34E200EE5FC8 /* SVGTextMetricsBuilder.h */; };
 		7118FED415685CC60030B79A /* JSSVGViewSpec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7118FED215685CC60030B79A /* JSSVGViewSpec.cpp */; };
@@ -10045,6 +10046,7 @@
 		6F995A2F1A70833700A735F4 /* JSWebGLVertexArrayObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebGLVertexArrayObject.cpp; sourceTree = "<group>"; };
 		6F995A301A70833700A735F4 /* JSWebGLVertexArrayObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebGLVertexArrayObject.h; sourceTree = "<group>"; };
 		6FAD4A561A9D0FAE009F7D3C /* OpenGLESSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OpenGLESSPI.h; sourceTree = "<group>"; };
+		709A01FD1E3D0BCC006B0D4C /* ModuleFetchFailureKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleFetchFailureKind.h; sourceTree = "<group>"; };
 		71004B9A1DC1109300A52A38 /* elapsed-time-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = "elapsed-time-support.js"; sourceTree = "<group>"; };
 		71004B9B1DC1109300A52A38 /* remaining-time-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = "remaining-time-support.js"; sourceTree = "<group>"; };
 		71004B9D1DC1398800A52A38 /* playback-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = "playback-support.js"; sourceTree = "<group>"; };
@@ -22198,6 +22200,7 @@
 				BC53DA2D1143121E000D817E /* DOMWrapperWorld.h */,
 				1432E8480C51493F00B1500F /* GCController.cpp */,
 				1432E8460C51493800B1500F /* GCController.h */,
+				709A01FD1E3D0BCC006B0D4C /* ModuleFetchFailureKind.h */,
 				C585A66011D4FAC5004C3E4B /* IDBBindingUtilities.cpp */,
 				C585A66111D4FAC5004C3E4B /* IDBBindingUtilities.h */,
 				E157A8EE18185425009F821D /* JSCryptoAlgorithmBuilder.cpp */,
@@ -25990,6 +25993,7 @@
 				A81369D0097374F600D74463 /* HTMLFormElement.h in Headers */,
 				A871DE2B0A152AC800B12A68 /* HTMLFrameElement.h in Headers */,
 				14FFE31D0AE1963300136BF5 /* HTMLFrameElementBase.h in Headers */,
+				709A01FE1E3D0BDD006B0D4C /* ModuleFetchFailureKind.h in Headers */,
 				93E241FF0B2B4E4000C732A1 /* HTMLFrameOwnerElement.h in Headers */,
 				A871DE280A152AC800B12A68 /* HTMLFrameSetElement.h in Headers */,
 				A871DE2D0A152AC800B12A68 /* HTMLHeadElement.h in Headers */,

Modified: trunk/Source/WebCore/bindings/js/JSDOMPromise.h (211472 => 211473)


--- trunk/Source/WebCore/bindings/js/JSDOMPromise.h	2017-02-01 07:55:44 UTC (rev 211472)
+++ trunk/Source/WebCore/bindings/js/JSDOMPromise.h	2017-02-01 10:00:32 UTC (rev 211473)
@@ -94,8 +94,8 @@
     void reject(ExceptionCode, const String& = { });
     void reject(const JSC::PrivateName&);
 
-    template<typename Callback, typename Value>
-    void resolveWithCallback(Callback callback, Value value)
+    template<typename Callback>
+    void resolveWithCallback(Callback callback)
     {
         if (isSuspended())
             return;
@@ -103,9 +103,21 @@
         ASSERT(m_globalObject);
         JSC::ExecState* exec = m_globalObject->globalExec();
         JSC::JSLockHolder locker(exec);
-        resolve(*exec, callback(*exec, *m_globalObject.get(), std::forward<Value>(value)));
+        resolve(*exec, callback(*exec, *m_globalObject.get()));
     }
 
+    template<typename Callback>
+    void rejectWithCallback(Callback callback)
+    {
+        if (isSuspended())
+            return;
+        ASSERT(m_deferred);
+        ASSERT(m_globalObject);
+        JSC::ExecState* exec = m_globalObject->globalExec();
+        JSC::JSLockHolder locker(exec);
+        reject(*exec, callback(*exec, *m_globalObject.get()));
+    }
+
     JSC::JSValue promise() const;
 
     bool isSuspended() { return !m_deferred || !canInvokeCallback(); } // The wrapper world has gone away or active DOM objects have been suspended.

Modified: trunk/Source/WebCore/bindings/js/ScriptController.cpp (211472 => 211473)


--- trunk/Source/WebCore/bindings/js/ScriptController.cpp	2017-02-01 07:55:44 UTC (rev 211472)
+++ trunk/Source/WebCore/bindings/js/ScriptController.cpp	2017-02-01 10:00:32 UTC (rev 211473)
@@ -40,6 +40,7 @@
 #include "LoadableModuleScript.h"
 #include "MainFrame.h"
 #include "MemoryPressureHandler.h"
+#include "ModuleFetchFailureKind.h"
 #include "NP_jsobject.h"
 #include "Page.h"
 #include "PageConsoleClient.h"
@@ -379,9 +380,6 @@
     // For example, if the page load is canceled, the DeferredPromise used in the module loader pipeline will stop executing JS code.
     // Thus the promise returned from this function could remain unresolved.
 
-    JSC::PrivateName moduleLoaderAlreadyReportedErrorSymbol = m_moduleLoaderAlreadyReportedErrorSymbol;
-    JSC::PrivateName moduleLoaderFetchingIsCanceledSymbol = m_moduleLoaderFetchingIsCanceledSymbol;
-
     RefPtr<LoadableModuleScript> moduleScript(&moduleScriptRef);
 
     auto& fulfillHandler = *JSNativeStdFunction::create(state.vm(), shell.window(), 1, String(), [moduleScript](ExecState* exec) {
@@ -390,22 +388,26 @@
         return JSValue::encode(jsUndefined());
     });
 
-    auto& rejectHandler = *JSNativeStdFunction::create(state.vm(), shell.window(), 1, String(), [moduleScript, moduleLoaderAlreadyReportedErrorSymbol, moduleLoaderFetchingIsCanceledSymbol](ExecState* exec) {
-        JSValue error = exec->argument(0);
+    auto& rejectHandler = *JSNativeStdFunction::create(state.vm(), shell.window(), 1, String(), [moduleScript](ExecState* exec) {
         VM& vm = exec->vm();
-        if (auto* symbol = jsDynamicCast<Symbol*>(vm, error)) {
-            if (symbol->privateName() == moduleLoaderAlreadyReportedErrorSymbol) {
-                moduleScript->notifyLoadFailed(LoadableScript::Error {
-                    LoadableScript::ErrorType::CachedScript,
-                    std::nullopt
-                });
+        JSValue errorValue = exec->argument(0);
+        if (errorValue.isObject()) {
+            auto* object = JSC::asObject(errorValue);
+            if (JSValue failureKindValue = object->getDirect(vm, static_cast<JSVMClientData&>(*vm.clientData).builtinNames().failureKindPrivateName())) {
+                // This is host propagated error in the module loader pipeline.
+                switch (static_cast<ModuleFetchFailureKind>(failureKindValue.asInt32())) {
+                case ModuleFetchFailureKind::WasErrored:
+                    moduleScript->notifyLoadFailed(LoadableScript::Error {
+                        LoadableScript::ErrorType::CachedScript,
+                        std::nullopt
+                    });
+                    break;
+                case ModuleFetchFailureKind::WasCanceled:
+                    moduleScript->notifyLoadWasCanceled();
+                    break;
+                }
                 return JSValue::encode(jsUndefined());
             }
-
-            if (symbol->privateName() == moduleLoaderFetchingIsCanceledSymbol) {
-                moduleScript->notifyLoadWasCanceled();
-                return JSValue::encode(jsUndefined());
-            }
         }
 
         auto scope = DECLARE_CATCH_SCOPE(vm);
@@ -414,7 +416,7 @@
             LoadableScript::ConsoleMessage {
                 MessageSource::JS,
                 MessageLevel::Error,
-                retrieveErrorMessage(*exec, vm, error, scope),
+                retrieveErrorMessage(*exec, vm, errorValue, scope),
             }
         });
         return JSValue::encode(jsUndefined());

Modified: trunk/Source/WebCore/bindings/js/ScriptController.h (211472 => 211473)


--- trunk/Source/WebCore/bindings/js/ScriptController.h	2017-02-01 07:55:44 UTC (rev 211472)
+++ trunk/Source/WebCore/bindings/js/ScriptController.h	2017-02-01 10:00:32 UTC (rev 211473)
@@ -147,9 +147,6 @@
 
     const String* sourceURL() const { return m_sourceURL; } // 0 if we are not evaluating any script
 
-    const JSC::PrivateName& moduleLoaderAlreadyReportedErrorSymbol() const { return m_moduleLoaderAlreadyReportedErrorSymbol; }
-    const JSC::PrivateName& moduleLoaderFetchingIsCanceledSymbol() const { return m_moduleLoaderFetchingIsCanceledSymbol; }
-
     void clearWindowShellsNotMatchingDOMWindow(DOMWindow*, bool goingIntoPageCache);
     void setDOMWindowForWindowShell(DOMWindow*);
     void updateDocument();
@@ -192,8 +189,6 @@
     const String* m_sourceURL;
 
     bool m_paused;
-    JSC::PrivateName m_moduleLoaderAlreadyReportedErrorSymbol;
-    JSC::PrivateName m_moduleLoaderFetchingIsCanceledSymbol;
 
     // The root object used for objects bound outside the context of a plugin, such
     // as NPAPI plugins. The plugins using these objects prevent a page from being cached so they

Modified: trunk/Source/WebCore/bindings/js/ScriptModuleLoader.cpp (211472 => 211473)


--- trunk/Source/WebCore/bindings/js/ScriptModuleLoader.cpp	2017-02-01 07:55:44 UTC (rev 211472)
+++ trunk/Source/WebCore/bindings/js/ScriptModuleLoader.cpp	2017-02-01 10:00:32 UTC (rev 211473)
@@ -34,8 +34,10 @@
 #include "JSDOMBinding.h"
 #include "LoadableModuleScript.h"
 #include "MIMETypeRegistry.h"
+#include "ModuleFetchFailureKind.h"
 #include "ScriptController.h"
 #include "ScriptSourceCode.h"
+#include "WebCoreJSClientData.h"
 #include <runtime/Completion.h>
 #include <runtime/JSInternalPromise.h>
 #include <runtime/JSInternalPromiseDeferred.h>
@@ -123,6 +125,20 @@
     return jsPromise.promise();
 }
 
+void rejectToPropagateNetworkError(DeferredPromise& deferred, ModuleFetchFailureKind failureKind, ASCIILiteral message)
+{
+    deferred.rejectWithCallback([&] (JSC::ExecState& state, JSDOMGlobalObject&) {
+        // We annotate exception with special private symbol. It allows us to distinguish these errors from the user thrown ones.
+        JSC::VM& vm = state.vm();
+        // FIXME: Propagate more descriptive error.
+        // https://bugs.webkit.org/show_bug.cgi?id=167553
+        auto* error = JSC::createTypeError(&state, message);
+        ASSERT(error);
+        error->putDirect(vm, static_cast<JSVMClientData&>(*vm.clientData).builtinNames().failureKindPrivateName(), JSC::jsNumber(static_cast<int32_t>(failureKind)));
+        return error;
+    });
+}
+
 JSC::JSInternalPromise* ScriptModuleLoader::fetch(JSC::JSGlobalObject* jsGlobalObject, JSC::ExecState* exec, JSC::JSModuleLoader*, JSC::JSValue moduleKeyValue, JSC::JSValue scriptFetcher)
 {
     ASSERT(JSC::jsDynamicCast<JSC::JSScriptFetcher*>(exec->vm(), scriptFetcher));
@@ -148,15 +164,13 @@
         return jsPromise.promise();
     }
 
-    if (auto* frame = m_document.frame()) {
-        auto loader = CachedModuleScriptLoader::create(*this, deferred.get(), *static_cast<CachedScriptFetcher*>(JSC::jsCast<JSC::JSScriptFetcher*>(scriptFetcher)->fetcher()));
-        m_loaders.add(loader.copyRef());
-        if (!loader->load(m_document, completedURL)) {
-            loader->clearClient();
-            m_loaders.remove(WTFMove(loader));
-            deferred->reject(frame->script().moduleLoaderAlreadyReportedErrorSymbol());
-            return jsPromise.promise();
-        }
+    auto loader = CachedModuleScriptLoader::create(*this, deferred.get(), *static_cast<CachedScriptFetcher*>(JSC::jsCast<JSC::JSScriptFetcher*>(scriptFetcher)->fetcher()));
+    m_loaders.add(loader.copyRef());
+    if (!loader->load(m_document, completedURL)) {
+        loader->clearClient();
+        m_loaders.remove(WTFMove(loader));
+        rejectToPropagateNetworkError(deferred.get(), ModuleFetchFailureKind::WasErrored, ASCIILiteral("Importing a module script failed."));
+        return jsPromise.promise();
     }
 
     return jsPromise.promise();
@@ -232,43 +246,34 @@
 
     auto& cachedScript = *loader.cachedScript();
 
-    bool failed = false;
-
     if (cachedScript.resourceError().isAccessControl()) {
         promise->reject(TypeError, ASCIILiteral("Cross-origin script load denied by Cross-Origin Resource Sharing policy."));
         return;
     }
 
-    if (cachedScript.errorOccurred())
-        failed = true;
-    else if (!MIMETypeRegistry::isSupportedJavaScriptMIMEType(cachedScript.response().mimeType())) {
-        // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script
-        // The result of extracting a MIME type from response's header list (ignoring parameters) is not a _javascript_ MIME type.
-        // 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.
-        promise->reject(TypeError, makeString("'", cachedScript.response().mimeType(), "' is not a valid _javascript_ MIME type."));
+    if (cachedScript.errorOccurred()) {
+        rejectToPropagateNetworkError(*promise, ModuleFetchFailureKind::WasErrored, ASCIILiteral("Importing a module script failed."));
         return;
     }
 
-    auto* frame = m_document.frame();
-    if (!frame)
+    if (cachedScript.wasCanceled()) {
+        rejectToPropagateNetworkError(*promise, ModuleFetchFailureKind::WasCanceled, ASCIILiteral("Importing a module script is canceled."));
         return;
-
-    if (failed) {
-        // Reject a promise to propagate the error back all the way through module promise chains to the script element.
-        promise->reject(frame->script().moduleLoaderAlreadyReportedErrorSymbol());
-        return;
     }
 
-    if (cachedScript.wasCanceled()) {
-        promise->reject(frame->script().moduleLoaderFetchingIsCanceledSymbol());
+    if (!MIMETypeRegistry::isSupportedJavaScriptMIMEType(cachedScript.response().mimeType())) {
+        // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script
+        // The result of extracting a MIME type from response's header list (ignoring parameters) is not a _javascript_ MIME type.
+        // 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.
+        promise->reject(TypeError, makeString("'", cachedScript.response().mimeType(), "' is not a valid _javascript_ MIME type."));
         return;
     }
 
     m_requestURLToResponseURLMap.add(cachedScript.url(), cachedScript.response().url());
-    ScriptSourceCode scriptSourceCode(&cachedScript, JSC::SourceProviderSourceType::Module, loader.scriptFetcher());
-    promise->resolveWithCallback([] (JSC::ExecState& state, JSDOMGlobalObject&, JSC::SourceCode sourceCode) {
-        return JSC::JSSourceCode::create(state.vm(), WTFMove(sourceCode));
-    }, scriptSourceCode.jsSourceCode());
+    promise->resolveWithCallback([&] (JSC::ExecState& state, JSDOMGlobalObject&) {
+        return JSC::JSSourceCode::create(state.vm(),
+            JSC::SourceCode { ScriptSourceCode { &cachedScript, JSC::SourceProviderSourceType::Module, loader.scriptFetcher() }.jsSourceCode() });
+    });
 }
 
 }

Modified: trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h (211472 => 211473)


--- trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h	2017-02-01 07:55:44 UTC (rev 211472)
+++ trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h	2017-02-01 10:00:32 UTC (rev 211473)
@@ -45,6 +45,7 @@
     macro(controller) \
     macro(createReadableStreamSource) \
     macro(disturbed) \
+    macro(failureKind) \
     macro(fetchRequest) \
     macro(fillFromJS) \
     macro(finishConsumingStream) \
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to