-
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.
Navigation API: ensure that 204/205/downloads never settle
See WICG/navigation-api#137. This requires distinguishing between "dropped" navigations and other canceled navigations at the FrameLoader/navigation API interface. This also makes cross-document ongoing navigations generally abortable, as can be seen by the revamped navigate-cross-document-double.html test. Previously, we would clean up the ongoing navigation for any cross-document nav, but per spec we need to keep it around so that it can be aborted if someone interrupts it. (This applies both to "normal" cross-document navigations, and ones to 204s/etc.) Bug: 1183545 Change-Id: I6f8f1771816ddf454d651f7147d3179fba88979b
- Loading branch information
1 parent
aaa06bb
commit b2aa133
Showing
6 changed files
with
245 additions
and
28 deletions.
There are no files selected for viewing
52 changes: 52 additions & 0 deletions
52
navigation-api/navigation-methods/return-value/back-204-205-download.html
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,52 @@ | ||
<!doctype html> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="resources/helpers.js"></script> | ||
<script src="/common/utils.js"></script> | ||
|
||
<body> | ||
<script> | ||
const tests = [ | ||
["204s", "204"], | ||
["205s", "205"], | ||
["Content-Disposition: attachment responses", "download"] | ||
]; | ||
|
||
for (const [description, action] of tests) { | ||
promise_test(async t => { | ||
const id = token(); | ||
|
||
const i = document.createElement("iframe"); | ||
i.src = `resources/204-205-download-on-second-visit.py?id=${id}`; | ||
document.body.append(i); | ||
await new Promise(r => i.onload = r); | ||
|
||
// Configure it to return a 204 on the next visit | ||
await fetch(i.src + `&action=${action}`, { method: "POST" }); | ||
|
||
// Now navigate elsewhere | ||
i.contentWindow.location.href = "/common/blank.html"; | ||
await new Promise(r => i.onload = r); | ||
|
||
// Now try going back. It should do nothing (and not tell us about the result). | ||
|
||
const indexBefore = i.contentWindow.navigation.currentEntry.index; | ||
|
||
// One might be surprised that navigate does not fire. (It does fire for the | ||
// corresponding tests of navigation.navigate(), i.e., this is | ||
// traversal-specific behavior.) See https://github.com/WICG/navigation-api/issues/207 | ||
// for some discussion. | ||
i.contentWindow.navigation.onnavigate = t.unreached_func("onnavigate should not be called"); | ||
i.contentWindow.navigation.onnavigatesuccess = t.unreached_func("onnavigatesuccess should not be called"); | ||
i.contentWindow.navigation.onnavigateerror = t.unreached_func("onnavigateerror should not be called"); | ||
|
||
const result = i.contentWindow.navigation.back(); | ||
|
||
assertNeverSettles(t, result, i.contentWindow); | ||
|
||
await new Promise(resolve => t.step_timeout(resolve, 50)); | ||
assert_equals(i.contentWindow.navigation.currentEntry.index, indexBefore); | ||
assert_equals(i.contentWindow.navigation.transition, null); | ||
}, `back() promises to ${description} never settle`); | ||
} | ||
</script> |
42 changes: 42 additions & 0 deletions
42
navigation-api/navigation-methods/return-value/navigate-204-205-download.html
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,42 @@ | ||
<!doctype html> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="resources/helpers.js"></script> | ||
|
||
<body> | ||
<script> | ||
const tests = [ | ||
["204s", "/common/blank.html?pipe=status(204)"], | ||
["205s", "/common/blank.html?pipe=status(205)"], | ||
["Content-Disposition: attachment responses", "/common/blank.html?pipe=header(Content-Disposition,attachment)"] | ||
]; | ||
|
||
for (const [description, url] of tests) { | ||
promise_test(async t => { | ||
const i = document.createElement("iframe"); | ||
i.src = "/common/blank.html"; | ||
document.body.append(i); | ||
await new Promise(resolve => i.onload = resolve); | ||
|
||
// This seems to be important? Without it the (outer) window load event | ||
// doesn't fire, and the test harness hangs forever. This is probably a | ||
// Chromium bug, but maybe a testharness bug, especially since explicit_done | ||
// doesn't seem to help? | ||
t.add_cleanup(() => i.remove()); | ||
|
||
let navigateCount = 0; | ||
i.contentWindow.navigation.onnavigate = () => { ++navigateCount; }; | ||
i.contentWindow.navigation.onnavigatesuccess = t.unreached_func("onnavigatesuccess should not be called"); | ||
i.contentWindow.navigation.onnavigateerror = t.unreached_func("onnavigateerror should not be called"); | ||
|
||
const result = i.contentWindow.navigation.navigate(url); | ||
|
||
assert_equals(navigateCount, 1); | ||
assertNeverSettles(t, result, i.contentWindow); | ||
|
||
await new Promise(resolve => t.step_timeout(resolve, 50)); | ||
assert_equals(i.contentWindow.location.href, i.src); | ||
assert_equals(i.contentWindow.navigation.transition, null); | ||
}, `navigate() promises to ${description} never settle`); | ||
} | ||
</script> |
24 changes: 24 additions & 0 deletions
24
navigation-api/navigation-methods/return-value/resources/204-205-download-on-second-visit.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,24 @@ | ||
def main(request, response): | ||
key = request.GET[b"id"] | ||
|
||
# If hit with a POST with ?action=X, store X in the stash | ||
if request.method == "POST": | ||
action = request.GET[b"action"] | ||
request.server.stash.put(key, action) | ||
|
||
return (204, [], "") | ||
|
||
# If hit with a GET, either return a normal initial page, or the abnormal requested response | ||
elif request.method == "GET": | ||
action = request.server.stash.take(key) | ||
|
||
if action is None: | ||
return (200, [("Content-Type", "text/html"), ("Cache-Control", "no-store")], "initial page") | ||
if action == b"204": | ||
return (204, [], "") | ||
if action == b"205": | ||
return (205, [], "") | ||
if action == b"download": | ||
return (200, [("Content-Type", "text/plain"), ("Content-Disposition", "attachment")], "some text to download") | ||
|
||
return (400, [], "") |
66 changes: 66 additions & 0 deletions
66
navigation-api/ordering-and-transition/navigate-204-205-download-then-same-document.html
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,66 @@ | ||
<!doctype html> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
|
||
<script type="module"> | ||
import { Recorder } from "./resources/helpers.mjs"; | ||
|
||
const tests = [ | ||
["204s", "/common/blank.html?pipe=status(204)"], | ||
["205s", "/common/blank.html?pipe=status(205)"], | ||
["Content-Disposition: attachment responses", "/common/blank.html?pipe=header(Content-Disposition,attachment)"] | ||
]; | ||
|
||
for (const [description, url] of tests) { | ||
promise_test(async t => { | ||
const i = document.createElement("iframe"); | ||
i.src = "/common/blank.html"; | ||
document.body.append(i); | ||
await new Promise(resolve => i.onload = () => t.step_timeout(resolve, 0)); | ||
|
||
const fromStart = i.contentWindow.navigation.currentEntry; | ||
|
||
const recorder = new Recorder({ | ||
window: i.contentWindow, | ||
finalExpectedEvent: "finished fulfilled 2" | ||
}); | ||
|
||
recorder.setUpNavigationAPIListeners(); | ||
|
||
const result1 = i.contentWindow.navigation.navigate(url); | ||
recorder.setUpResultListeners(result1, " 1"); | ||
|
||
// Give the server time to send the response. This is not strictly | ||
// necessary (the expectations are the same either way) but it's better | ||
// coverage if the server is done responding by this time; it guarantees | ||
// we're hitting the code path for "got a 204/etc. and ignored it" instead | ||
// of "didn't get a response yet". | ||
await new Promise(resolve => t.step_timeout(resolve, 50)); | ||
|
||
const result2 = i.contentWindow.navigation.navigate("#1"); | ||
recorder.setUpResultListeners(result2, " 2"); | ||
|
||
Promise.resolve().then(() => recorder.record("promise microtask")); | ||
|
||
await recorder.readyToAssert; | ||
|
||
recorder.assert([ | ||
/* event name, location.hash value, navigation.transition properties */ | ||
["navigate", "", null], | ||
["AbortSignal abort", "", null], | ||
["navigateerror", "", null], | ||
|
||
["navigate", "", null], | ||
["currententrychange", "#1", null], | ||
["committed rejected 1", "#1", null], | ||
["finished rejected 1", "#1", null], | ||
["committed fulfilled 2", "#1", null], | ||
["promise microtask", "#1", null], | ||
["navigatesuccess", "#1", null], | ||
["finished fulfilled 2", "#1", null] | ||
]); | ||
|
||
recorder.assertErrorsAreAbortErrors(); | ||
}, `event and promise ordering when navigate() is to a ${description} and then to a same-document navigation`); | ||
} | ||
</script> |
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
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