| <meta name="timeout" content="long"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="/common/get-host-info.sub.js"></script> |
| <script src="/common/utils.js"></script> |
| <script> |
| |
| // This is a regression test for https://crbug.com/1170038. |
| // |
| // A document creates a popup and makes it navigate elsewhere. The navigation |
| // will never commit. The popup has not completed any real load outside of the |
| // initial empty document. Then from a different window with a different CSP |
| // policy, make it navigate to about:blank. |
| // |
| // Web browser behavior might change depending on whether a pending navigation |
| // exists for in the popup or not. Both are tested here. |
| |
| const same_origin = get_host_info().HTTP_ORIGIN; |
| |
| // Return a promise, resolving when |element| triggers |event_name| event. |
| const future = (element, event_name) => { |
| return new Promise(resolve => element.addEventListener(event_name, resolve)); |
| }; |
| |
| // `createNewPopup` is a function returning a new window that has not committed |
| // any real load in its frame, outside of the initial empty document. The two |
| // tests below vary depending on whether there is a pending navigation in the |
| // frame or not. |
| const runTest = (description, createNewPopup) => { |
| promise_test(async test => { |
| // Open a same-origin window with a different CSP. |
| const executor_path = |
| "/html/browsers/sandboxing/resources/execute-postmessage.html?pipe="; |
| const csp = "|header(Content-Security-Policy, " + |
| "sandbox" + |
| " allow-scripts" + |
| " allow-popups" + |
| " allow-same-origin" + |
| " allow-popups-to-escape-sandbox"; |
| const executor = window.open(same_origin + executor_path + csp); |
| const executor_reply = await future(window, "message"); |
| assert_equals(executor_reply.data, "ready"); |
| |
| const popup_name = token(); |
| const popup = await createNewPopup(test, popup_name); |
| |
| // Request the first real load from a DIFFERENT window with different CSPs. |
| const first_real_load = future(popup, "load"); |
| executor.postMessage(`window.open("about:blank", "${popup_name}");`); |
| await first_real_load; |
| |
| // The new blank document in the popup must inherit CSPs from |executor|: |
| let is_sandboxed = future(window, "message"); |
| popup.document.write(` |
| <script> |
| try { |
| document.domain = document.domain; |
| opener.opener.postMessage("not sandboxed", "*"); |
| } catch (error) { |
| opener.opener.postMessage("sandboxed", "*"); |
| } |
| </scr`+`ipt> |
| `); |
| assert_equals((await is_sandboxed).data, "sandboxed"); |
| }, description); |
| } |
| |
| // Open a new window and start loading from an unresponsive server. The frame |
| // will be left with the initial empty document and a pending navigation. |
| runTest("One pending navigation", async (test, popup_name) => { |
| const unresponsive_path = |
| "/common/slow.py?delay=1000000"; |
| return window.open(same_origin + unresponsive_path, popup_name); |
| }); |
| |
| // Open a new window and start loading. The response is a 204 and the navigation |
| // is canceled. As a result, the frame will be left with the initial empty |
| // document and NO pending navigation. |
| runTest("No pending navigation", async (test, popup_name) => { |
| const no_content_path = "/common/blank.html?pipe=status(204)" |
| const popup = window.open(same_origin + no_content_path, popup_name); |
| |
| // Unfortunately, there are no web API to detect a navigation has been |
| // canceled. Waiting using setTimeout is the only possible way to wait for it. |
| await new Promise(r => test.step_timeout(r, 1000)); |
| |
| return popup; |
| }); |
| |
| </script> |