diff --git a/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-while-navigating.window.js b/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-while-navigating.window.js new file mode 100644 index 00000000000000..c0c6ac15b16ccf --- /dev/null +++ b/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort-while-navigating.window.js @@ -0,0 +1,171 @@ +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func(() => { + frame.onload = null; + const client = new frame.contentWindow.XMLHttpRequest(); + client.open("GET", "/common/blank.html"); + // The abort event handler is called synchronously in Chrome but + // asynchronously in Firefox. See https://crbug.com/879620. + client.onabort = t.step_func_done(); + client.send(); + frame.contentWindow.location.href = new URL("resources/dummy.html", document.URL); + frame.contentDocument.open(); + }); +}, "document.open() aborts documents that are navigating through Location (XMLHttpRequest)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + frame.contentWindow.fetch("/common/blank.html").then( + t.unreached_func("Fetch should have been aborted"), + t.step_func_done(() => { + assert_true(happened); + })); + frame.contentWindow.location.href = new URL("resources/dummy.html", document.URL); + frame.contentDocument.open(); + happened = true; + }); +}, "document.open() aborts documents that are navigating through Location (fetch())"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + const img = frame.contentDocument.createElement("img"); + img.src = new URL("resources/slow-png.py", document.URL); + img.onload = t.unreached_func("Image loading should have errored"); + // The image fetch starts in a microtask, so let's be sure to test after + // the fetch has started. + t.step_timeout(() => { + frame.contentWindow.location.href = new URL("resources/dummy.html", document.URL); + frame.contentDocument.open(); + happened = true; + }); + // If 3 seconds have passed and the image has still not loaded, we consider + // it aborted. slow-png.py only sleeps for 2 wallclock seconds. + t.step_timeout(t.step_func_done(() => { + assert_true(happened); + }), 3000); + }); +}, "document.open() aborts documents that are navigating through Location (image loading)"); + +async_test(t => { + const div = document.body.appendChild(document.createElement("div")); + t.add_cleanup(() => div.remove()); + div.innerHTML = ""; + const frame = div.childNodes[0]; + const client = new frame.contentWindow.XMLHttpRequest(); + client.open("GET", "/common/blank.html"); + client.onabort = t.step_func_done(); + client.send(); + frame.contentDocument.open(); +}, "document.open() aborts documents that are navigating through iframe loading (XMLHttpRequest)"); + +async_test(t => { + const div = document.body.appendChild(document.createElement("div")); + t.add_cleanup(() => div.remove()); + div.innerHTML = ""; + const frame = div.childNodes[0]; + frame.contentWindow.fetch("/common/blank.html").then( + t.unreached_func("Fetch should have been aborted"), + t.step_func_done()); + frame.contentDocument.open(); +}, "document.open() aborts documents that are navigating through iframe loading (fetch())"); + +// We use resources/slow.py here, to prevent the situation where when +// document.open() is called the initial document has already become inactive. +async_test(t => { + const div = document.body.appendChild(document.createElement("div")); + t.add_cleanup(() => div.remove()); + div.innerHTML = ""; + const frame = div.childNodes[0]; + let happened = false; + const img = frame.contentDocument.createElement("img"); + img.src = new URL("resources/slow-png.py", document.URL); + img.onload = t.unreached_func("Image loading should have errored"); + // The image fetch starts in a microtask, so let's be sure to test after + // the fetch has started. + t.step_timeout(() => { + frame.contentDocument.open(); + happened = true; + }); + // If 3 seconds have passed and the image has still not loaded, we consider + // it aborted. slow-png.py only sleeps for 2 wallclock seconds. + t.step_timeout(t.step_func_done(() => { + assert_true(happened); + }), 3000); +}, "document.open() aborts documents that are navigating through iframe loading (image loading)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func(() => { + frame.onload = null; + const link = frame.contentDocument.body.appendChild(frame.contentDocument.createElement("a")); + link.href = new URL("resources/dummy.html", document.URL); + + const client = new frame.contentWindow.XMLHttpRequest(); + client.open("GET", "/common/blank.html"); + client.onabort = t.step_func_done(); + client.send(); + + link.click(); + frame.contentDocument.open(); + }); +}, "document.open() aborts documents that are queued for navigation through .click() (XMLHttpRequest)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func(() => { + frame.onload = null; + const link = frame.contentDocument.body.appendChild(frame.contentDocument.createElement("a")); + link.href = new URL("resources/dummy.html", document.URL); + + frame.contentWindow.fetch("/common/blank.html").then( + t.unreached_func("Fetch should have been aborted"), + t.step_func_done()); + + link.click(); + frame.contentDocument.open(); + }); +}, "document.open() aborts documents that are queued for navigation through .click() (fetch())"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func(() => { + frame.onload = null; + const link = frame.contentDocument.body.appendChild(frame.contentDocument.createElement("a")); + link.href = new URL("resources/dummy.html", document.URL); + + let happened = false; + const img = frame.contentDocument.createElement("img"); + img.src = new URL("resources/slow-png.py", document.URL); + img.onload = t.unreached_func("Image loading should have errored"); + // The image fetch starts in a microtask, so let's be sure to test after + // the fetch has started. + t.step_timeout(() => { + link.click(); + frame.contentDocument.open(); + happened = true; + }); + // If 3 seconds have passed and the image has still not loaded, we consider + // it aborted. slow-png.py only sleeps for 2 wallclock seconds. + t.step_timeout(t.step_func_done(() => { + assert_true(happened); + }), 3000); + }); +}, "document.open() aborts documents that are queued for navigation through .click() (image loading)"); diff --git a/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort.sub.window.js b/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort.sub.window.js new file mode 100644 index 00000000000000..885468902ec39b --- /dev/null +++ b/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort.sub.window.js @@ -0,0 +1,104 @@ +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + const client = new frame.contentWindow.XMLHttpRequest(); + client.open("GET", "/common/blank.html"); + client.onload = t.step_func_done(e => { + assert_true(happened); + }); + client.onerror = t.unreached_func("XMLHttpRequest should have succeeded"); + client.onabort = t.unreached_func("XMLHttpRequest should have succeeded"); + client.ontimeout = t.unreached_func("XMLHttpRequest should have succeeded"); + client.send(); + frame.contentDocument.open(); + happened = true; + }); +}, "document.open() does not abort documents that are not navigating (XMLHttpRequest)"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + frame.contentWindow.fetch("/common/blank.html").then( + t.step_func_done(() => { + assert_true(happened); + }), + t.unreached_func("Fetch should have succeeded") + ); + frame.contentDocument.open(); + happened = true; + }); +}, "document.open() does not abort documents that are not navigating (fetch())"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + const img = frame.contentDocument.createElement("img"); + img.src = new URL("resources/slow-png.py", document.URL); + img.onload = t.step_func_done(() => { + assert_true(happened); + }); + img.onerror = t.unreached_func("Image loading should not have errored"); + // The image fetch starts in a microtask, so let's be sure to test after + // the fetch has started. + t.step_timeout(() => { + frame.contentDocument.open(); + happened = true; + }); + }); +}, "document.open() does not abort documents that are not navigating (image loading)"); + +async_test(t => { + const __SERVER__NAME = "{{host}}"; + const __PORT = {{ports[ws][0]}}; + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + const ws = new frame.contentWindow.WebSocket(`ws://${__SERVER__NAME}:${__PORT}/echo`); + ws.onopen = t.step_func_done(() => { + assert_true(happened); + }); + ws.onclose = t.unreached_func("WebSocket fetch should have succeeded"); + ws.onerror = t.unreached_func("WebSocket should have no error"); + frame.contentDocument.open(); + happened = true; + }); +}, "document.open() does not abort documents that are not navigating (establish a WebSocket connection)"); + +// An already established WebSocket connection shouldn't be terminated during +// an "abort a document" anyway. Test just for completeness. +async_test(t => { + const __SERVER__NAME = "{{host}}"; + const __PORT = {{ports[ws][0]}}; + const frame = document.body.appendChild(document.createElement("iframe")); + t.add_cleanup(() => frame.remove()); + frame.src = "/common/blank.html"; + frame.onload = t.step_func(() => { + frame.onload = null; + let happened = false; + const ws = new frame.contentWindow.WebSocket(`ws://${__SERVER__NAME}:${__PORT}/echo`); + ws.onopen = t.step_func(() => { + t.step_timeout(t.step_func_done(() => { + assert_true(happened); + }), 100); + frame.contentDocument.open(); + happened = true; + }); + ws.onclose = t.unreached_func("WebSocket should not be closed"); + ws.onerror = t.unreached_func("WebSocket should have no error"); + }); +}, "document.open() does not abort documents that are not navigating (already established WebSocket connection)"); diff --git a/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/slow-png.py b/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/slow-png.py new file mode 100644 index 00000000000000..5fa2fd9a9d850a --- /dev/null +++ b/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/slow-png.py @@ -0,0 +1,8 @@ +from base64 import decodestring +import time + +png_response = decodestring('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNiAAAABgADNjd8qAAAAABJRU5ErkJggg==') + +def main(request, response): + time.sleep(2) + return 200, [], png_response