Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// META: script=/common/get-host-info.sub.js

function checkSupported() {
assert_implements('ancestorOrigins' in location, 'location.ancestorOrigins should be supported');
}

const embedPath = new URL("resources/ancestororigins-embed.py", location.href).pathname,
info = get_host_info(),
localOrigin = info.HTTP_ORIGIN,
localEmbed = localOrigin + embedPath,
remoteOrigin = info.HTTP_REMOTE_ORIGIN,
remoteEmbed = remoteOrigin + embedPath,
remoteOrigin2 = info.HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT,
remoteEmbed2 = remoteOrigin2 + embedPath;
let id = 0;

async_test(t => {
checkSupported();
const iframe = document.createElement("iframe"),
localId = ++id;
iframe.sandbox = "allow-scripts";
iframe.src = localEmbed + "?iframe=|" + encodeURIComponent(remoteEmbed) + "?id=" + localId;
document.body.appendChild(iframe);
t.add_cleanup(() => iframe.remove());

self.addEventListener("message", t.step_func(e => {
if(e.data.id === localId) {
assert_array_equals(e.data.output, ["null", localOrigin]);
t.done();
}
}));
}, "Ensure sandboxed iframes show up as null");

// The following code ends up generating multiple tests each with multiple nested <iframe>s. The
// variables in the array below seed various scenarios, described by "desc". The capital letters
// describe the <iframe>s in play. When the same letter is used at different nesting levels that
// means it is same-origin. Some defaulting is used to avoid too much duplication.
[
{
outerPolicy: true,
desc: "A uses no-referrer -> B -> A",
results: [remoteOrigin, "null"]
},
{
outerPolicy: true,
innerEmbed: remoteEmbed2,
desc: "A uses no-referrer -> B -> C",
results: [remoteOrigin, "null"]
},
{
innerPolicy: true,
desc: "A -> B uses no-referrer -> A",
results: ["null", localOrigin]
},
{
innerPolicy: true,
innerEmbed: remoteEmbed2,
desc: "A -> B uses no-referrer -> C",
results: ["null", localOrigin]
},
{
innerPolicy: true,
outerEmbed: localEmbed,
innerEmbed: remoteEmbed,
desc: "A -> A uses no-referrer -> C",
results: ["null", "null"],
intermediateResults: [localOrigin]
},
{
innerPolicy: true,
outerEmbed: localEmbed,
desc: "A -> A uses no-referrer -> A",
results: ["null", "null"],
intermediateResults: [localOrigin]
}
].forEach(val => {
async_test(t => {
checkSupported();
if(!val.intermediateResults) {
val.intermediateResults = [val.results[1]];
}
if(!val.outerEmbed) {
val.outerEmbed = remoteEmbed;
}
if(!val.innerEmbed) {
val.innerEmbed = localEmbed;
}

const iframe = document.createElement("iframe"),
innerId = ++id,
innermostId = ++id;
if(val.outerPolicy) {
iframe.referrerPolicy = "no-referrer";
}
let innerPolicy = "";
if(val.innerPolicy) {
innerPolicy = "no-referrer";
}
iframe.src = val.outerEmbed + "?id=" + innerId + "&iframe=" + innerPolicy + "|" + val.innerEmbed + "?id=" + innermostId;
document.body.appendChild(iframe);
t.add_cleanup(() => iframe.remove());

let almostDone = false;
function localDone () {
if(almostDone) {
t.done();
}
almostDone = true;
}

self.addEventListener("message", t.step_func(e => {
if(e.data.id === innerId) {
assert_array_equals(e.data.output, val.intermediateResults);
localDone();
}
else if(e.data.id === innermostId) {
assert_array_equals(e.data.output, val.results);
localDone();
}
}));
}, val.desc);
});

[
{
desc: "A -> B -> B uses no-referrer -> A",
innerinnerEmbed: localEmbed
},
{
desc: "A -> B -> B uses no-referrer -> B",
innerinnerEmbed: remoteEmbed
},
{
desc: "A -> B -> B uses no-referrer -> C",
innerinnerEmbed: remoteEmbed2
}
].forEach(val => {
async_test(t => {
checkSupported();
const iframe = document.createElement("iframe"),
localId = ++id;
iframe.src = remoteEmbed + "?iframe=|" + remoteEmbed + "?iframe=no-referrer%257C" + val.innerinnerEmbed + "?id=" + localId;
document.body.appendChild(iframe);
t.add_cleanup(() => iframe.remove());

self.addEventListener("message", t.step_func(e => {
if(e.data.id === localId) {
assert_array_equals(e.data.output, ["null", "null", localOrigin]);
t.done();
}
}));
}, val.desc);
});

// rel=noreferrer sets https://html.spec.whatwg.org/#document-state-request-referrer-policy
// but does not affect https://html.spec.whatwg.org/#policy-container-referrer-policy
async_test(t => {
checkSupported();
const iframe = document.createElement("iframe"),
localId = ++id;
iframe.src = '/common/blank.html';
document.body.appendChild(iframe);
t.add_cleanup(() => iframe.remove());

iframe.addEventListener('load', () => {
const a = document.createElement("a");
a.rel = "noreferrer";
a.href = localEmbed + "?id=" + localId;
a.textContent = 'click here';
iframe.contentDocument.body.appendChild(a);

self.addEventListener("message", t.step_func(e => {
if(e.data.id === localId) {
assert_array_equals(e.data.output, [localOrigin]);
t.done();
}
}));
a.click();
}, {once: true});
}, "rel=noreferrer should not affect ancestorOrigins");
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
function checkSupported() {
assert_implements('ancestorOrigins' in location, 'location.ancestorOrigins should be supported');
}

test(() => {
checkSupported();
assert_equals(location.ancestorOrigins.length, 0)
}, "location.ancestorOrigins basic check");

async_test(t => {
checkSupported();
const frame = document.createElement("iframe"),
rp = document.createElement("meta");
frame.onload = t.step_func_done(() => {
const ancestorOrigins = frame.contentWindow.location.ancestorOrigins;
assert_equals(ancestorOrigins[0], self.origin);
assert_equals(ancestorOrigins.length, 1);

rp.name = "referrer";
rp.content = "no-referrer";
document.head.appendChild(rp);
assert_equals(self[0].location.ancestorOrigins, ancestorOrigins);
assert_equals(ancestorOrigins[0], self.origin);
assert_equals(ancestorOrigins.length, 1);
rp.remove();

frame.referrerPolicy = "no-referrer";
assert_equals(self[0].location.ancestorOrigins, ancestorOrigins);
assert_equals(ancestorOrigins[0], self.origin);
assert_equals(ancestorOrigins.length, 1);

frame.remove();
})
frame.src = "/common/blank.html";
document.body.appendChild(frame);
}, "location.ancestorOrigins cannot be masked by a dynamic referrer policy");

async_test(t => {
checkSupported();
const frame = document.createElement("iframe");
frame.onload = t.step_func_done(() => {
const ancestorOrigins = frame.contentWindow.location.ancestorOrigins;
assert_equals(ancestorOrigins[0], "null");
assert_equals(ancestorOrigins.length, 1);
frame.remove();
})
frame.src = "/common/blank.html";
frame.referrerPolicy = "no-referrer";
document.body.appendChild(frame);
}, "location.ancestorOrigins can be masked by a predetermined referrer policy");

async_test(t => {
checkSupported();
const frame = document.createElement("iframe");
t.add_cleanup(() => frame.remove());
frame.src = new URL("resources/ancestororigins-embed.py?id=123&iframe=|./ancestororigins-embed.py%3Fid=1234", location.href.replace("://", "://天気の良い日.")).href;
document.body.appendChild(frame);

let almostDone = false;
function localDone() {
if(almostDone) {
t.done();
}
almostDone = true;
}

self.onmessage = t.step_func(e => {
if(e.data.id === 123) {
assert_array_equals(e.data.output, [location.origin]);
localDone();
} else if(e.data.id === 1234) {
assert_array_equals(e.data.output, [location.origin.replace("://", "://xn--n8j6ds53lwwkrqhv28a."), location.origin]);
localDone();
} else {
assert_unreached();
}
});
}, "location.ancestorOrigins and IDNA");
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
def main(request, response):
headers = [("Content-Type", "text/html; charset=utf-8")]
body = "<!doctype html>"

if b"iframe" in request.GET:
frame = request.GET.first(b"iframe").split(b"|")
frameReferrer = frame[0].decode("utf-8")
frameURL = frame[1].decode("utf-8")
if frameReferrer != "":
frameReferrer = " referrerpolicy=" + frameReferrer

body = body + ("<iframe src=\"%s\"%s></iframe>" % (frameURL, frameReferrer)) + "\n"

if b"id" in request.GET:
body = body + """<script>
let output = [...self.location.ancestorOrigins];
top.postMessage({ id: %s, output }, "*");
</script>
""" % request.GET.first(b"id").decode("utf-8")

if body == "<!doctype html>":
return "Please specify either or both the 'iframe' and 'id' GET parameters."
return (headers, body)