mirror of
https://github.com/servo/servo.git
synced 2025-10-17 08:49:21 +01:00
Update web-platform-tests to revision b'b728032f59a396243864b0f8584e7211e3632005'
This commit is contained in:
parent
ace9b32b1c
commit
df68c4e5d1
15632 changed files with 514865 additions and 155000 deletions
|
@ -0,0 +1,127 @@
|
|||
// META: script=/common/get-host-info.sub.js
|
||||
// META: script=/common/utils.js
|
||||
// META: script=/common/dispatcher/dispatcher.js
|
||||
//
|
||||
// This is a regression test for crbug.com/583445. It checks an obscure bug in
|
||||
// Chromium's handling of `document.open()` whereby the URL change would affect
|
||||
// the document's origin after a javascript navigation.
|
||||
//
|
||||
// See also dcheng@'s comments on the original code review in which he
|
||||
// introduced the precursor to this test:
|
||||
// https://codereview.chromium.org/1675473002.
|
||||
|
||||
function nextMessage() {
|
||||
return new Promise((resolve) => {
|
||||
window.addEventListener("message", (e) => { resolve(e.data); }, {
|
||||
once: true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
promise_test(async (t) => {
|
||||
// Embed a cross-origin frame A and set up remote code execution.
|
||||
const iframeA = document.body.appendChild(document.createElement("iframe"));
|
||||
t.add_cleanup(() => { iframeA.remove(); });
|
||||
|
||||
const uuidA = token();
|
||||
iframeA.src = remoteExecutorUrl(uuidA, { host: get_host_info().REMOTE_HOST });
|
||||
const ctxA = new RemoteContext(uuidA);
|
||||
|
||||
// Frame A embeds a cross-origin frame B, which is same-origin with the
|
||||
// top-level frame. Frame B is the center of this test: it is where we will
|
||||
// verify that a bug does not grant it UXSS in frame A.
|
||||
//
|
||||
// Though we could reach into `iframeA.frames[0]` to get a proxy to frame B
|
||||
// and use `setTimeout()` like below to execute code inside it, we set up
|
||||
// remote code execution using `dispatcher.js` for better ergonomics.
|
||||
const uuidB = token();
|
||||
await ctxA.execute_script((url) => {
|
||||
const iframeB = document.createElement("iframe");
|
||||
iframeB.src = url;
|
||||
document.body.appendChild(iframeB);
|
||||
}, [remoteExecutorUrl(uuidB).href]);
|
||||
|
||||
// Start listening for a message, which will come as a result of executing
|
||||
// the code below in frame B.
|
||||
const message = nextMessage();
|
||||
|
||||
const ctxB = new RemoteContext(uuidB);
|
||||
await ctxB.execute_script(() => {
|
||||
// Frame B embeds an `about:blank` frame C.
|
||||
const iframeC = document.body.appendChild(document.createElement("iframe"));
|
||||
|
||||
// We wish to execute code inside frame C, but it is important to this test
|
||||
// that its URL remain `about:blank`, so we cannot use `dispatcher.js`.
|
||||
// Instead we rely on `setTimeout()`.
|
||||
//
|
||||
// We use `setTimeout(string, ...)` instead of `setTimeout(function, ...)`
|
||||
// as the given script executes against the target window's global object
|
||||
// and does not capture any local variables.
|
||||
//
|
||||
// In order to have nice syntax highlighting and avoid quote-escaping hell,
|
||||
// we use a trick employed by `dispatcher.js`. We rely on the fact that
|
||||
// functions in JS have a stringifier that returns their source code. Thus
|
||||
// `"(" + func + ")()"` is a string that executes `func()` when evaluated.
|
||||
iframeC.contentWindow.setTimeout("(" + (() => {
|
||||
// This executes in frame C.
|
||||
|
||||
// Frame C calls `document.open()` on its parent, which results in B's
|
||||
// URL being set to `about:blank` (C's URL).
|
||||
//
|
||||
// However, just before `document.open()` is called, B schedules a
|
||||
// self-navigation to a `javascript:` URL. This will occur after
|
||||
// `document.open()`, so the document will navigate from `about:blank` to
|
||||
// the new URL.
|
||||
//
|
||||
// This should not result in B's origin changing, so B should remain
|
||||
// same-origin with the top-level frame.
|
||||
//
|
||||
// Due to crbug.com/583445, this used to behave wrongly in Chromium. The
|
||||
// navigation code incorrectly assumed that B's origin should be inherited
|
||||
// from its parent A because B's URL was `about:blank`.
|
||||
//
|
||||
// It is important to schedule this from within the child, as this
|
||||
// guarantees that `document.open()` will be called before the navigation.
|
||||
// A previous version of this test scheduled this from within frame B
|
||||
// right after scheduling the call to `document.open()`, but that ran the
|
||||
// risk of races depending on which timeout fired first.
|
||||
parent.window.setTimeout("(" + (() => {
|
||||
// This executes in frame B.
|
||||
|
||||
location = "javascript:(" + (() => {
|
||||
/* This also executes in frame B.
|
||||
*
|
||||
* Note that because this whole function gets stuffed in a JS URL,
|
||||
* single-line comments do not work, as they affect the following
|
||||
* lines. */
|
||||
|
||||
let error;
|
||||
try {
|
||||
/* This will fail with a `SecurityError` if frame B is no longer
|
||||
* same-origin with the top-level frame. */
|
||||
top.window.testSameOrigin = true;
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
top.postMessage({
|
||||
error: error?.toString(),
|
||||
}, "*");
|
||||
|
||||
}) + ")()";
|
||||
|
||||
}) + ")()", 0);
|
||||
|
||||
// This executes in frame C.
|
||||
parent.document.open();
|
||||
|
||||
}) + ")()", 0);
|
||||
});
|
||||
|
||||
// Await the message from frame B after its navigation.
|
||||
const { error } = await message;
|
||||
assert_equals(error, undefined, "error accessing top frame from frame B");
|
||||
assert_true(window.testSameOrigin, "top frame testSameOrigin is mutated");
|
||||
|
||||
}, "Regression test for crbug.com/583445");
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue