-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
HTML: document.open() and aborting documents
For #10773. Co-authored-by: Anne van Kesteren <[email protected]>
- Loading branch information
Showing
3 changed files
with
283 additions
and
0 deletions.
There are no files selected for viewing
171 changes: 171 additions & 0 deletions
171
...ppapis/dynamic-markup-insertion/opening-the-input-stream/abort-while-navigating.window.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 = "<iframe src='resources/slow.py'></iframe>"; | ||
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 = "<iframe src='resources/slow.py'></iframe>"; | ||
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 = "<iframe src='resources/slow.py'></iframe>"; | ||
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)"); |
104 changes: 104 additions & 0 deletions
104
html/webappapis/dynamic-markup-insertion/opening-the-input-stream/abort.sub.window.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)"); |
8 changes: 8 additions & 0 deletions
8
html/webappapis/dynamic-markup-insertion/opening-the-input-stream/resources/slow-png.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |