Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test gets skipped with pattern: verify
- Manifest: dom/base/test/mochitest.toml
<!DOCTYPE html>
<html>
<!-- The JS bytecode cache is not supposed to be observable. To make it
observable, the ScriptLoader is instrumented to trigger events on the
script tag.
-->
<head>
<meta charset="utf-8">
<title>Test for request fallback for SRI mismatch on module bytecode</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<script type="application/javascript">
// List of testcases
//
// prep
// HTML file loaded in iframe that prepares the bytecode cache
// prepEvents
// Non-ordered multi-set of expected events dispatched during loading the
// "prep" HTML file
// src
// HTML file loaded in iframe after preparation finishes
// events
// Non-ordered multi-set of expected events dispatched during loading the
// "src" HTML file
const tests = [
// 1. Module bytecode is saved with integrity
// 2. Module bytecode is loaded by script element with integrity
{
prep: "file_script_module_sri_basic_prep.html",
prepEvents: [
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
src: "file_script_module_sri_basic.html",
events: [
"scriptloader_load_bytecode",
"scriptloader_evaluate_module",
"test_evaluated",
],
},
// 1. Module bytecode is saved without integrity
// 2. Module bytecode is loaded by script element with integrity
{
prep: "file_script_module_sri_fallback_prep.html",
prepEvents: [
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
src: "file_script_module_sri_fallback.html",
events: [
"scriptloader_load_bytecode",
"scriptloader_fallback",
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
},
// 1. Module bytecode is saved without integrity
// 2. Module bytecode is loaded by script element with wrong integrity
//
// The module script is not evaluated
{
prep: "file_script_module_sri_fallback_failure_prep.html",
prepEvents: [
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
src: "file_script_module_sri_fallback_failure.html",
events: [
"scriptloader_load_bytecode",
"scriptloader_fallback",
"scriptloader_load_source",
// This event is dispatched by another script, after the first module
// script load is terminated.
"test_evaluated",
],
},
// 1. Module bytecode is saved without integrity
// 2. Module bytecode is loaded by script element without integrity, and then
// loaded by script element with integrity
//
// The integrity attribute is ignored because the first request without
// integrity is shared between them.
{
prep: "file_script_module_sri_elem_elem_1_prep.html",
prepEvents: [
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
src: "file_script_module_sri_elem_elem_1.html",
events: [
"scriptloader_load_bytecode",
"scriptloader_evaluate_module",
"test_evaluated",
// NOTE: scriptloader_evaluate_module is dispatched even if
// the module is already evaluated before and it's evaluation is
// skipped this time.
"scriptloader_evaluate_module",
],
},
// 1. Module bytecode is saved without integrity
// 2. Module bytecode is loaded by script element with integrity, and then
// loaded by script element without integrity
//
// The request with integrity is shared between them.
{
prep: "file_script_module_sri_elem_elem_2_prep.html",
prepEvents: [
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
src: "file_script_module_sri_elem_elem_2.html",
events: [
"scriptloader_load_bytecode",
"scriptloader_fallback",
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
"scriptloader_evaluate_module",
],
},
// 1. Module bytecode is saved without integrity
// 2. Module bytecode is loaded by script element with integrity, and then
// imported statically.
//
// The request with integrity is shared between them.
{
prep: "file_script_module_sri_elem_import_prep.html",
prepEvents: [
// file_script_module_sri_elem_import_imported.mjs
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
src: "file_script_module_sri_elem_import.html",
events: [
// file_script_module_sri_elem_import_imported.mjs
"scriptloader_load_bytecode",
"scriptloader_fallback",
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
// file_script_module_sri_elem_import.mjs
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
},
// 1. Module bytecode is saved without integrity
// 2. Module bytecode is imported statically, and
// loaded by script element with integrity
//
// Even if the import is performed first, the script element's request
// with integrity is used because of preload.
{
prep: "file_script_module_sri_import_elem_prep.html",
prepEvents: [
// file_script_module_sri_import_elem_imported.mjs
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
src: "file_script_module_sri_import_elem.html",
events: [
// file_script_module_sri_import_elem.mjs
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
// file_script_module_sri_import_elem_imported.mjs
"scriptloader_load_bytecode",
"scriptloader_fallback",
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
},
// 1. Module bytecode is saved without integrity
// 2. Module bytecode is imported statically, and
// loaded by script element with integrity, without preload
//
// The request without integrity triggered by import is shared between
// them.
{
prep: "file_script_module_sri_import_elem_nopreload_prep.html",
prepEvents: [
// file_script_module_sri_import_elem_nopreload_imported.mjs
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
src: "file_script_module_sri_import_elem_nopreload.html",
events: [
// file_script_module_sri_import_elem_nopreload.mjs
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
// file_script_module_sri_import_elem_nopreload_imported.mjs
"scriptloader_load_bytecode",
"scriptloader_evaluate_module",
"test_evaluated",
],
},
// 1. Module bytecode is saved without integrity
// 2. Module bytecode is loaded by script element with integrity, and then
// imported dynamically.
//
// The request with integrity is shared between them.
{
prep: "file_script_module_sri_elem_dynamic_prep.html",
prepEvents: [
// file_script_module_sri_elem_dynamic_imported.mjs
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
src: "file_script_module_sri_elem_dynamic.html",
events: [
// file_script_module_sri_elem_dynamic_imported.mjs
"scriptloader_load_bytecode",
"scriptloader_fallback",
"scriptloader_load_source",
"scriptloader_evaluate_module", // (element)
"scriptloader_evaluate_module", // (dynamic)
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
// file_script_module_sri_elem_dynamic.mjs
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
},
// 1. Module bytecode is saved without integrity
// 2. Module bytecode is imported dynamically, and then
// loaded by script element with integrity
//
// Even if the dynamic import is performed first, the script element's
// request with integrity is used because of preload.
{
prep: "file_script_module_sri_dynamic_elem_prep.html",
prepEvents: [
// file_script_module_sri_dynamic_elem_imported.mjs
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
src: "file_script_module_sri_dynamic_elem.html",
events: [
// file_script_module_sri_dynamic_elem_imported.mjs
"scriptloader_load_bytecode",
"scriptloader_fallback",
"scriptloader_load_source",
"scriptloader_evaluate_module", // (element)
"scriptloader_evaluate_module", // (dynamic)
"scriptloader_encode",
"test_evaluated",
// file_script_module_sri_dynamic_elem.mjs
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
},
// 1. Module bytecode is saved without integrity
// 2. Module bytecode is imported dynamically, and then
// loaded by script element with integrity, without preload
//
// The request without integrity triggered by dynamic import is shared
// between them.
{
prep: "file_script_module_sri_dynamic_elem_nopreload_prep.html",
prepEvents: [
// file_script_module_sri_dynamic_elem_nopreload_imported.mjs
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
src: "file_script_module_sri_dynamic_elem_nopreload.html",
events: [
// file_script_module_sri_dynamic_elem_nopreload_imported.mjs
"scriptloader_load_bytecode",
"scriptloader_evaluate_module", // (element)
"scriptloader_evaluate_module", // (dynamic)
"test_evaluated",
// file_script_module_sri_dynamic_elem_nopreload.mjs
"scriptloader_load_source",
"scriptloader_evaluate_module",
"scriptloader_encode",
"scriptloader_bytecode_saved",
"test_evaluated",
],
},
];
promise_test(async function() {
await SpecialPowers.pushPrefEnv({set: [
['dom.script_loader.bytecode_cache.enabled', true],
['dom.expose_test_interfaces', true],
['dom.script_loader.bytecode_cache.strategy', -1]
]});
for (const { prep, prepEvents, src, events } of tests) {
for (let i = 0; i < 2; i++) {
const expectedEvents = i == 0 ? prepEvents : events;
const currentSrc = i == 0 ? prep : src;
const iframe = document.createElement("iframe");
document.body.appendChild(iframe);
const iwin = iframe.contentWindow;
dump("## Start: " + currentSrc + "\n");
let observedEvents = [];
await new Promise(resolve => {
function logEvent(evt) {
if (evt.type != "test_evaluated") {
if (!/^watchme/.test(evt.target.id)) {
return;
}
}
dump("## ScriptLoader event: " + evt.type + "\n");
observedEvents.push(evt.type);
if (observedEvents.length == expectedEvents.length) {
resolve();
}
}
iwin.addEventListener("scriptloader_load_source", logEvent);
iwin.addEventListener("scriptloader_load_bytecode", logEvent);
iwin.addEventListener("scriptloader_execute", logEvent);
iwin.addEventListener("scriptloader_evaluate_module", logEvent);
iwin.addEventListener("scriptloader_encode", logEvent);
iwin.addEventListener("scriptloader_no_encode", logEvent);
iwin.addEventListener("scriptloader_bytecode_saved", logEvent);
iwin.addEventListener("scriptloader_bytecode_failed", logEvent);
iwin.addEventListener("scriptloader_fallback", logEvent);
iwin.addEventListener("test_evaluated", logEvent);
iframe.src = currentSrc;
});
// The event order is non-deterministic.
// Just compare them as multi-set.
expectedEvents.sort();
observedEvents.sort();
assert_equals(
JSON.stringify(observedEvents),
JSON.stringify(expectedEvents),
`Expected events should be observed for ${currentSrc}`);
document.body.removeChild(iframe);
}
}
}, "Test module bytecode save and load");
done();
</script>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1436400">Mozilla Bug 1436400</a>
</body>
</html>