Check MIME type against asserted module type in ModuleScriptFetcher

Add module type to the module map key.

Plumb module type into ModuleScriptFetcher and its subclasses, and
require that the MIME type match the type that was specified with
import assertions.

Add the necessary import assertions to the JSON/CSS module web tests
so that they continue passing.  Add tests to ensure that the modules
don't load when the correct assertion is not present.

A minor functional change to JSON modules is that trying to start a
a Worker with a top-level JSON module (e.g. new Worker("./foo.json"))
now results in a rejected Promise, instead of loading a no-op worker
without an error.  This change follows the spec change at
https://github.com/whatwg/html/pull/5658/; note that the invocation
of 'fetch a single module script' from 'fetch a worklet/module worker
script graph' doesn't pass a ModuleRequest, so the type is assumed to
be JavaScript, and a failure will be triggered if the MIME type is
not JavaScript.

Some of the non-virtual versions of the tests now time out because
the import assertion syntax is seen as a syntax error when
--harmony-import-assertions is not enabled, causing <script>s not to
run.  TestExpectations is updated to account for these.

Bug: 1132413
Change-Id: I01bf7d907a96e791208534c9c4f2af11434c76db
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2674259
Commit-Queue: Dan Clark <daniec@microsoft.com>
Reviewed-by: Kouhei Ueno <kouhei@chromium.org>
Reviewed-by: Hiroshige Hayashizaki <hiroshige@chromium.org>
Cr-Commit-Position: refs/heads/master@{#852991}
diff --git a/html/semantics/scripting-1/the-script-element/css-module/import-css-module-basic.html b/html/semantics/scripting-1/the-script-element/css-module/import-css-module-basic.html
index 4ca2bb7..207d553 100644
--- a/html/semantics/scripting-1/the-script-element/css-module/import-css-module-basic.html
+++ b/html/semantics/scripting-1/the-script-element/css-module/import-css-module-basic.html
@@ -54,5 +54,18 @@
             });
             document.body.appendChild(iframe);
         }, "Malformed CSS should not load");
+
+        async_test(function (test) {
+            const iframe = document.createElement("iframe");
+            iframe.src = "resources/css-module-without-assertion-iframe.html";
+            iframe.onload = test.step_func_done(function () {
+                assert_equals(iframe.contentDocument.window_onerror, undefined);
+                assert_equals(iframe.contentDocument.script_onerror.type, "error");
+                assert_not_equals(getComputedStyle(iframe.contentDocument.querySelector('#test'))
+                    .backgroundColor, "rgb(255, 0, 0)",
+                    "CSS module without type assertion should result in a fetch error");
+            });
+            document.body.appendChild(iframe);
+        }, "CSS module without type assertion should result in a fetch error");
     </script>
 </body>
diff --git a/html/semantics/scripting-1/the-script-element/css-module/import-css-module-dynamic.html b/html/semantics/scripting-1/the-script-element/css-module/import-css-module-dynamic.html
new file mode 100644
index 0000000..4fbc111
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/css-module/import-css-module-dynamic.html
@@ -0,0 +1,22 @@
+<!doctype html>
+
+<head>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+</head>
+
+<body>
+    <script>
+        promise_test(async function (test) {
+            const css_module = await import("./resources/basic.css", { assert: { type: "css" }});
+            assert_true(css_module.default instanceof CSSStyleSheet);
+            assert_equals(css_module.default.cssRules[0].cssText, "#test { background-color: red; }");
+        }, "Load a CSS module with dynamic import()");
+
+        promise_test(function (test) {
+            return promise_rejects_js(test, TypeError,
+                import("./resources/basic.css"),
+                "Attempting to import() a CSS module without a type assertion should fail");
+        }, "Ensure that loading a CSS module with dymnamic import() fails without a type assertion");
+    </script>
+</body>
diff --git a/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-at-import-iframe.html b/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-at-import-iframe.html
index 86e7af7..cce9e21 100644
--- a/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-at-import-iframe.html
+++ b/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-at-import-iframe.html
@@ -8,7 +8,7 @@
         };
     </script>
     <script type="module">
-        import v from "./bad-import.css";
+        import v from "./bad-import.css" assert { type: "css" };
         document.adoptedStyleSheets = [v];
     </script>
 
diff --git a/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-basic-iframe.html b/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-basic-iframe.html
index 3a555c3..e093d39 100644
--- a/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-basic-iframe.html
+++ b/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-basic-iframe.html
@@ -8,7 +8,7 @@
         };
     </script>
     <script type="module">
-        import v from "./basic.css";
+        import v from "./basic.css" assert { type: "css" };
         document.adoptedStyleSheets = [v];
     </script>
 
diff --git a/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-basic-large-iframe.html b/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-basic-large-iframe.html
index cc5b660..0cf11e9 100644
--- a/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-basic-large-iframe.html
+++ b/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-basic-large-iframe.html
@@ -8,7 +8,7 @@
         };
     </script>
     <script type="module">
-        import v from "./basic-large.css";
+        import v from "./basic-large.css" assert { type: "css" };
         document.adoptedStyleSheets = [v];
     </script>
 
diff --git a/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-without-assertion-iframe.html b/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-without-assertion-iframe.html
new file mode 100644
index 0000000..3d1be84
--- /dev/null
+++ b/html/semantics/scripting-1/the-script-element/css-module/resources/css-module-without-assertion-iframe.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<body>
+    <script>
+        window.onerror = function (errorMsg, url, lineNumber, column, errorObj)
+        {
+            document.window_onerror = errorObj.name;
+            return true;
+        };
+
+        function scriptErrorHandler(e) {
+            document.script_onerror = e;
+        }
+    </script>
+    <script type="module" onerror="scriptErrorHandler(event)">
+        import v from "./basic.css";
+        document.adoptedStyleSheets = [v];
+    </script>
+
+    <div id="test">
+        I am a test div.
+    </div>
+</body>
\ No newline at end of file
diff --git a/html/semantics/scripting-1/the-script-element/css-module/resources/malformed-iframe.html b/html/semantics/scripting-1/the-script-element/css-module/resources/malformed-iframe.html
index 471edd6..f5c64f6 100644
--- a/html/semantics/scripting-1/the-script-element/css-module/resources/malformed-iframe.html
+++ b/html/semantics/scripting-1/the-script-element/css-module/resources/malformed-iframe.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <body>
     <script type="module">
-        import v from "./malformed.css";
+        import v from "./malformed.css" assert { type: "css" };
         document.adoptedStyleSheets = [v];
     </script>
 
diff --git a/html/semantics/scripting-1/the-script-element/css-module/resources/worker-dynamic-import.js b/html/semantics/scripting-1/the-script-element/css-module/resources/worker-dynamic-import.js
index 9a3b0bb..6f6852c 100644
--- a/html/semantics/scripting-1/the-script-element/css-module/resources/worker-dynamic-import.js
+++ b/html/semantics/scripting-1/the-script-element/css-module/resources/worker-dynamic-import.js
@@ -1,3 +1,3 @@
-import("./basic.css")
+import("./basic.css", { assert: { type: "css" } })
   .then(() => postMessage("LOADED"))
   .catch(e => postMessage("NOT LOADED"));
\ No newline at end of file
diff --git a/html/semantics/scripting-1/the-script-element/css-module/resources/worker.js b/html/semantics/scripting-1/the-script-element/css-module/resources/worker.js
index 397a12c..c97d965 100644
--- a/html/semantics/scripting-1/the-script-element/css-module/resources/worker.js
+++ b/html/semantics/scripting-1/the-script-element/css-module/resources/worker.js
@@ -1,2 +1,2 @@
-import "./basic.css";
+import "./basic.css" assert { type: "css" };
 postMessage("Unexpectedly loaded");
\ No newline at end of file
diff --git a/html/semantics/scripting-1/the-script-element/css-module/utf8.tentative.html b/html/semantics/scripting-1/the-script-element/css-module/utf8.tentative.html
index f71339b..6adcd71 100644
--- a/html/semantics/scripting-1/the-script-element/css-module/utf8.tentative.html
+++ b/html/semantics/scripting-1/the-script-element/css-module/utf8.tentative.html
@@ -17,18 +17,18 @@
 const t4 = async_test("utf-7");
 </script>
 <script type="module" onerror="t1.step(() => assert_unreached(event))">
-import v from "../serve-with-content-type.py?fn=css-module/resources/utf8.css&ct=text/css%3Bcharset=utf-8";
+import v from "../serve-with-content-type.py?fn=css-module/resources/utf8.css&ct=text/css%3Bcharset=utf-8" assert { type: "css" };
 check(t1, v);
 </script>
 <script type="module" onerror="t2.step(() => assert_unreached(event))">
-import v from "../serve-with-content-type.py?fn=css-module/resources/utf8.css&ct=text/css%3Bcharset=shift-jis";
+import v from "../serve-with-content-type.py?fn=css-module/resources/utf8.css&ct=text/css%3Bcharset=shift-jis" assert { type: "css" };
 check(t2, v);
 </script>
 <script type="module" onerror="t3.step(() => assert_unreached(event))">
-import v from "../serve-with-content-type.py?fn=css-module/resources/utf8.css&ct=text/css%3Bcharset=windows-1252";
+import v from "../serve-with-content-type.py?fn=css-module/resources/utf8.css&ct=text/css%3Bcharset=windows-1252" assert { type: "css" };
 check(t3, v);
 </script>
 <script type="module" onerror="t4.step(() => assert_unreached(event))">
-import v from "../serve-with-content-type.py?fn=css-module/resources/utf8.css&ct=text/css%3Bcharset=utf-7";
+import v from "../serve-with-content-type.py?fn=css-module/resources/utf8.css&ct=text/css%3Bcharset=utf-7" assert { type: "css" };
 check(t4, v);
 </script>
diff --git a/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.tentative.html b/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.tentative.html
index 2e1f9d8..cc47da1 100644
--- a/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.tentative.html
+++ b/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.tentative.html
@@ -10,11 +10,11 @@
         assert_not_equals(reg.installing, undefined);
     }, "Javascript importing JSON Module should load within the context of a service worker");
 
-    promise_test(async (test) => {
-        const reg = await navigator.serviceWorker.register('./module.json', { type: 'module' });
-        test.add_cleanup(() => reg.unregister());
-        assert_not_equals(reg.installing, undefined);
-    }, "JSON Modules should load within the context of a service worker");
+    promise_test(test => {
+        return promise_rejects_dom(test, "SecurityError",
+            navigator.serviceWorker.register('./module.json', { type: 'module' }),
+            "Attempting to load JSON as a service worker should fail");
+    }, "Trying to register a service worker with a top-level JSON Module should fail");
 
     promise_test(async (test) => {
         const reg = await navigator.serviceWorker.register('./serviceworker-dynamic-import.js', { type: 'module' });
diff --git a/html/semantics/scripting-1/the-script-element/json-module/module.tentative.html b/html/semantics/scripting-1/the-script-element/json-module/module.tentative.html
index 9324385..a495d4a 100644
--- a/html/semantics/scripting-1/the-script-element/json-module/module.tentative.html
+++ b/html/semantics/scripting-1/the-script-element/json-module/module.tentative.html
@@ -8,7 +8,7 @@
 const t = async_test();
 </script>
 <script type="module" onerror="t.step(() => assert_unreached(event))">
-import v from "./module.json";
+import v from "./module.json" assert { type: "json" };
 t.step(() => {
   assert_equals(typeof v, "object");
   assert_array_equals(Object.keys(v), ["test"]);
diff --git a/html/semantics/scripting-1/the-script-element/json-module/non-object.tentative.any.js b/html/semantics/scripting-1/the-script-element/json-module/non-object.tentative.any.js
index dcbe60f..6d50717 100644
--- a/html/semantics/scripting-1/the-script-element/json-module/non-object.tentative.any.js
+++ b/html/semantics/scripting-1/the-script-element/json-module/non-object.tentative.any.js
@@ -2,13 +2,13 @@
 
 for (const value of [null, true, false, "string"]) {
   promise_test(async t => {
-    const result = await import(`./${value}.json`);
+    const result = await import(`./${value}.json`, { assert: { type: "json" } });
     assert_equals(result.default, value);
   }, `Non-object: ${value}`);
 }
 
 promise_test(async t => {
-  const result = await import("./array.json");
+  const result = await import("./array.json", { assert: { type: "json" } });
   assert_array_equals(result.default, ["en", "try"]);
 }, "Non-object: array");
 
diff --git a/html/semantics/scripting-1/the-script-element/json-module/serviceworker-dynamic-import.js b/html/semantics/scripting-1/the-script-element/json-module/serviceworker-dynamic-import.js
index 3c7d294..9466c6f 100644
--- a/html/semantics/scripting-1/the-script-element/json-module/serviceworker-dynamic-import.js
+++ b/html/semantics/scripting-1/the-script-element/json-module/serviceworker-dynamic-import.js
@@ -1,5 +1,5 @@
 onmessage = e => {
-    e.waitUntil(import("./module.json")
+    e.waitUntil(import("./module.json", { assert: { type: "json" } })
         .then(module => e.source.postMessage("LOADED"))
         .catch(error => e.source.postMessage("FAILED")));
   };
\ No newline at end of file
diff --git a/html/semantics/scripting-1/the-script-element/json-module/serviceworker.js b/html/semantics/scripting-1/the-script-element/json-module/serviceworker.js
index 6d71f01..3f0a4d1 100644
--- a/html/semantics/scripting-1/the-script-element/json-module/serviceworker.js
+++ b/html/semantics/scripting-1/the-script-element/json-module/serviceworker.js
@@ -1 +1 @@
-import './module.json';
\ No newline at end of file
+import './module.json' assert { type: "json" };
\ No newline at end of file
diff --git a/html/semantics/scripting-1/the-script-element/json-module/utf8.tentative.html b/html/semantics/scripting-1/the-script-element/json-module/utf8.tentative.html
index 1c0360b..24a6f10 100644
--- a/html/semantics/scripting-1/the-script-element/json-module/utf8.tentative.html
+++ b/html/semantics/scripting-1/the-script-element/json-module/utf8.tentative.html
@@ -19,18 +19,18 @@
 const t4 = async_test("utf-7");
 </script>
 <script type="module" onerror="t1.step(() => assert_unreached(event))">
-import v from "../serve-with-content-type.py?fn=json-module/utf8.json&ct=text/json%3Bcharset=utf-8";
+import v from "../serve-with-content-type.py?fn=json-module/utf8.json&ct=text/json%3Bcharset=utf-8" assert { type: "json"};
 check(t1, v);
 </script>
 <script type="module" onerror="t2.step(() => assert_unreached(event))">
-import v from "../serve-with-content-type.py?fn=json-module/utf8.json&ct=text/json%3Bcharset=shift-jis";
+import v from "../serve-with-content-type.py?fn=json-module/utf8.json&ct=text/json%3Bcharset=shift-jis" assert { type: "json"};
 check(t2, v);
 </script>
 <script type="module" onerror="t3.step(() => assert_unreached(event))">
-import v from "../serve-with-content-type.py?fn=json-module/utf8.json&ct=text/json%3Bcharset=windows-1252";
+import v from "../serve-with-content-type.py?fn=json-module/utf8.json&ct=text/json%3Bcharset=windows-1252" assert { type: "json"};
 check(t3, v);
 </script>
 <script type="module" onerror="t4.step(() => assert_unreached(event))">
-import v from "../serve-with-content-type.py?fn=json-module/utf8.json&ct=text/json%3Bcharset=utf-7";
+import v from "../serve-with-content-type.py?fn=json-module/utf8.json&ct=text/json%3Bcharset=utf-7" assert { type: "json"};;
 check(t4, v);
 </script>
diff --git a/html/semantics/scripting-1/the-script-element/json-module/valid-content-type.tentative.html b/html/semantics/scripting-1/the-script-element/json-module/valid-content-type.tentative.html
index 78e8b1d..ff5953c 100644
--- a/html/semantics/scripting-1/the-script-element/json-module/valid-content-type.tentative.html
+++ b/html/semantics/scripting-1/the-script-element/json-module/valid-content-type.tentative.html
@@ -19,18 +19,18 @@
 const t4 = async_test("image/svg+json");
 </script>
 <script type="module" onerror="t1.step(() => assert_unreached(event))">
-import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=text/json";
+import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=text/json" assert { type: "json"};
 check(t1, v);
 </script>
 <script type="module" onerror="t2.step(() => assert_unreached(event))">
-import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=application/json";
+import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=application/json" assert { type: "json"};
 check(t2, v);
 </script>
 <script type="module" onerror="t3.step(() => assert_unreached(event))">
-import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=text/html+json";
+import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=text/html+json" assert { type: "json"};
 check(t3, v);
 </script>
 <script type="module" onerror="t4.step(() => assert_unreached(event))">
-import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=image/svg+json";
+import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=image/svg+json" assert { type: "json"};
 check(t4, v);
 </script>