summaryrefslogtreecommitdiffstats
path: root/dom/base/test/unit/test_blockParsing.js
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/test/unit/test_blockParsing.js')
-rw-r--r--dom/base/test/unit/test_blockParsing.js121
1 files changed, 121 insertions, 0 deletions
diff --git a/dom/base/test/unit/test_blockParsing.js b/dom/base/test/unit/test_blockParsing.js
new file mode 100644
index 0000000000..e5d35f6eef
--- /dev/null
+++ b/dom/base/test/unit/test_blockParsing.js
@@ -0,0 +1,121 @@
+"use strict";
+
+const { TestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TestUtils.sys.mjs"
+);
+const { XPCShellContentUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/XPCShellContentUtils.sys.mjs"
+);
+const { setTimeout } = ChromeUtils.importESModule(
+ "resource://gre/modules/Timer.sys.mjs"
+);
+
+XPCShellContentUtils.init(this);
+
+function delay() {
+ return new Promise(resolve => {
+ setTimeout(resolve, 0);
+ });
+}
+
+const server = XPCShellContentUtils.createHttpServer({
+ hosts: ["example.com"],
+});
+
+// XML document with only a <script> tag as the document element.
+const PAGE_URL = "http://example.com/";
+server.registerPathHandler("/", (request, response) => {
+ response.setHeader("Content-Type", "application/xhtml+xml");
+ response.write(String.raw`<!DOCTYPE html>
+ <script xmlns="http://www.w3.org/1999/xhtml" src="slow.js"/>
+ `);
+});
+
+let resolveResumeScriptPromise;
+let resumeScriptPromise = new Promise(resolve => {
+ resolveResumeScriptPromise = resolve;
+});
+
+let resolveScriptRequestPromise;
+let scriptRequestPromise = new Promise(resolve => {
+ resolveScriptRequestPromise = resolve;
+});
+
+// An empty script which waits to complete until `resumeScriptPromise`
+// resolves.
+server.registerPathHandler("/slow.js", async (request, response) => {
+ response.processAsync();
+ resolveScriptRequestPromise();
+
+ await resumeScriptPromise;
+
+ response.setHeader("Content-type", "text/javascript");
+ response.write("");
+ response.finish();
+});
+
+add_setup(function () {
+ Services.prefs.setBoolPref("security.allow_unsafe_parent_loads", true);
+});
+
+registerCleanupFunction(function () {
+ Services.prefs.clearUserPref("security.allow_unsafe_parent_loads");
+});
+
+// Tests that attempting to block parsing for a <script> tag while the
+// parser is already blocked is handled correctly, and does not cause
+// crashes or hangs.
+add_task(async function test_nested_blockParser() {
+ // Wait for the document element of the page to be inserted, and block
+ // the parser when it is.
+ let resolveBlockerPromise;
+ let blockerPromise;
+ let docElementPromise = TestUtils.topicObserved(
+ "document-element-inserted",
+ doc => {
+ if (doc.location.href === PAGE_URL) {
+ blockerPromise = new Promise(resolve => {
+ resolveBlockerPromise = resolve;
+ });
+
+ doc.blockParsing(blockerPromise);
+ return true;
+ }
+ return false;
+ }
+ );
+
+ // Begin loading the page.
+ let pagePromise = XPCShellContentUtils.loadContentPage(PAGE_URL, {
+ remote: false,
+ });
+
+ // Wait for the document element to be inserted.
+ await docElementPromise;
+ // Wait for the /slow.js script request to initiate.
+ await scriptRequestPromise;
+
+ // Make some trips through the event loop to be safe.
+ await delay();
+ await delay();
+
+ // Allow the /slow.js script request to complete.
+ resolveResumeScriptPromise();
+
+ // Make some trips through the event loop so that the <script> request
+ // unblocks the parser.
+ await delay();
+ await delay();
+
+ // Release the parser blocker added in the observer above.
+ resolveBlockerPromise();
+
+ // Make some trips through the event loop to allow the parser to
+ // unblock.
+ await delay();
+ await delay();
+
+ // Wait for the document to finish loading, and then close it.
+ let page = await pagePromise;
+ await page.close();
+});