window-open-blank-from-different-initiator.html (3686B)
1 <meta name="timeout" content="long"> 2 <script src="/resources/testharness.js"></script> 3 <script src="/resources/testharnessreport.js"></script> 4 <script src="/common/get-host-info.sub.js"></script> 5 <script src="/common/utils.js"></script> 6 <script> 7 8 // This is a regression test for https://crbug.com/1170038. 9 // 10 // A document creates a popup and makes it navigate elsewhere. The navigation 11 // will never commit. The popup has not completed any real load outside of the 12 // initial empty document. Then from a different window with a different CSP 13 // policy, make it navigate to about:blank. 14 // 15 // Web browser behavior might change depending on whether a pending navigation 16 // exists for in the popup or not. Both are tested here. 17 18 const same_origin = get_host_info().HTTP_ORIGIN; 19 20 // Return a promise, resolving when |element| triggers |event_name| event. 21 const future = (element, event_name) => { 22 return new Promise(resolve => element.addEventListener(event_name, resolve)); 23 }; 24 25 // `createNewPopup` is a function returning a new window that has not committed 26 // any real load in its frame, outside of the initial empty document. The two 27 // tests below vary depending on whether there is a pending navigation in the 28 // frame or not. 29 const runTest = (description, createNewPopup) => { 30 promise_test(async test => { 31 // Open a same-origin window with a different CSP. 32 const executor_path = 33 "/html/browsers/sandboxing/resources/execute-postmessage.html?pipe="; 34 const csp = "|header(Content-Security-Policy, " + 35 "sandbox" + 36 " allow-scripts" + 37 " allow-popups" + 38 " allow-same-origin" + 39 " allow-popups-to-escape-sandbox"; 40 const executor = window.open(same_origin + executor_path + csp); 41 const executor_reply = await future(window, "message"); 42 assert_equals(executor_reply.data, "ready"); 43 44 const popup_name = token(); 45 const popup = await createNewPopup(test, popup_name); 46 47 // Request the first real load from a DIFFERENT window with different CSPs. 48 const first_real_load = future(popup, "load"); 49 executor.postMessage(`window.open("about:blank", "${popup_name}");`); 50 await first_real_load; 51 52 // The new blank document in the popup must inherit CSPs from |executor|: 53 let is_sandboxed = future(window, "message"); 54 popup.document.write(` 55 <script> 56 try { 57 document.domain = document.domain; 58 opener.opener.postMessage("not sandboxed", "*"); 59 } catch (error) { 60 opener.opener.postMessage("sandboxed", "*"); 61 } 62 </scr`+`ipt> 63 `); 64 assert_equals((await is_sandboxed).data, "sandboxed"); 65 }, description); 66 } 67 68 // Open a new window and start loading from an unresponsive server. The frame 69 // will be left with the initial empty document and a pending navigation. 70 runTest("One pending navigation", async (test, popup_name) => { 71 const unresponsive_path = "/common/slow.py?delay=1000000"; 72 return window.open(same_origin + unresponsive_path, popup_name); 73 }); 74 75 // Open a new window and start loading. The response is a 204 and the navigation 76 // is canceled. As a result, the frame will be left with the initial empty 77 // document and NO pending navigation. 78 runTest("No pending navigation", async (test, popup_name) => { 79 const no_content_path = "/common/blank.html?pipe=status(204)" 80 const popup = window.open(same_origin + no_content_path, popup_name); 81 82 // Unfortunately, there are no web API to detect a navigation has been 83 // canceled. Waiting using setTimeout is the only possible way to wait for it. 84 await new Promise(r => test.step_timeout(r, 1000)); 85 86 return popup; 87 }); 88 89 </script>