test_blockParsing.js (3358B)
1 "use strict"; 2 3 const { TestUtils } = ChromeUtils.importESModule( 4 "resource://testing-common/TestUtils.sys.mjs" 5 ); 6 const { XPCShellContentUtils } = ChromeUtils.importESModule( 7 "resource://testing-common/XPCShellContentUtils.sys.mjs" 8 ); 9 const { setTimeout } = ChromeUtils.importESModule( 10 "resource://gre/modules/Timer.sys.mjs" 11 ); 12 13 XPCShellContentUtils.init(this); 14 15 function delay() { 16 return new Promise(resolve => { 17 setTimeout(resolve, 0); 18 }); 19 } 20 21 const server = XPCShellContentUtils.createHttpServer({ 22 hosts: ["example.com"], 23 }); 24 25 // XML document with only a <script> tag as the document element. 26 const PAGE_URL = "http://example.com/"; 27 server.registerPathHandler("/", (request, response) => { 28 response.setHeader("Content-Type", "application/xhtml+xml"); 29 response.write(String.raw`<!DOCTYPE html> 30 <script xmlns="http://www.w3.org/1999/xhtml" src="slow.js"/> 31 `); 32 }); 33 34 let resolveResumeScriptPromise; 35 let resumeScriptPromise = new Promise(resolve => { 36 resolveResumeScriptPromise = resolve; 37 }); 38 39 let resolveScriptRequestPromise; 40 let scriptRequestPromise = new Promise(resolve => { 41 resolveScriptRequestPromise = resolve; 42 }); 43 44 // An empty script which waits to complete until `resumeScriptPromise` 45 // resolves. 46 server.registerPathHandler("/slow.js", async (request, response) => { 47 response.processAsync(); 48 resolveScriptRequestPromise(); 49 50 await resumeScriptPromise; 51 52 response.setHeader("Content-type", "text/javascript"); 53 response.write(""); 54 response.finish(); 55 }); 56 57 add_setup(function () { 58 Services.prefs.setBoolPref("security.allow_unsafe_parent_loads", true); 59 }); 60 61 registerCleanupFunction(function () { 62 Services.prefs.clearUserPref("security.allow_unsafe_parent_loads"); 63 }); 64 65 // Tests that attempting to block parsing for a <script> tag while the 66 // parser is already blocked is handled correctly, and does not cause 67 // crashes or hangs. 68 add_task(async function test_nested_blockParser() { 69 // Wait for the document element of the page to be inserted, and block 70 // the parser when it is. 71 let resolveBlockerPromise; 72 let blockerPromise; 73 let docElementPromise = TestUtils.topicObserved( 74 "document-element-inserted", 75 doc => { 76 if (doc.location.href === PAGE_URL) { 77 blockerPromise = new Promise(resolve => { 78 resolveBlockerPromise = resolve; 79 }); 80 81 doc.blockParsing(blockerPromise); 82 return true; 83 } 84 return false; 85 } 86 ); 87 88 // Begin loading the page. 89 let pagePromise = XPCShellContentUtils.loadContentPage(PAGE_URL, { 90 remote: false, 91 }); 92 93 // Wait for the document element to be inserted. 94 await docElementPromise; 95 // Wait for the /slow.js script request to initiate. 96 await scriptRequestPromise; 97 98 // Make some trips through the event loop to be safe. 99 await delay(); 100 await delay(); 101 102 // Allow the /slow.js script request to complete. 103 resolveResumeScriptPromise(); 104 105 // Make some trips through the event loop so that the <script> request 106 // unblocks the parser. 107 await delay(); 108 await delay(); 109 110 // Release the parser blocker added in the observer above. 111 resolveBlockerPromise(); 112 113 // Make some trips through the event loop to allow the parser to 114 // unblock. 115 await delay(); 116 await delay(); 117 118 // Wait for the document to finish loading, and then close it. 119 let page = await pagePromise; 120 await page.close(); 121 });