229 lines
8.6 KiB
HTML
229 lines
8.6 KiB
HTML
<!DOCTYPE html>
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<body>
|
|
<script>
|
|
function readableURL(url) {
|
|
return url.replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
}
|
|
|
|
// For each of the following tests, we'll inject a frame containing the HTML we'd like to poke at
|
|
// as a `srcdoc` attribute. Because we're injecting markup via `srcdoc`, we need to entity-escape
|
|
// the content we'd like to treat as "raw" (e.g. `\n` => ` `, `<` => `<`), and
|
|
// double-escape the "escaped" content.
|
|
var rawBrace = "<";
|
|
var escapedBrace = "&lt;";
|
|
var doubleEscapedBrace = "&amp;lt;";
|
|
var rawNewline = " ";
|
|
var escapedNewline = "&#10;";
|
|
// doubleEscapedNewline is used inside a data URI, and so must have its '#' escaped.
|
|
var doubleEscapedNewline = "&amp;%2310;";
|
|
|
|
function appendFrameAndGetElement(test, frame) {
|
|
return new Promise((resolve, reject) => {
|
|
frame.onload = test.step_func(_ => {
|
|
frame.onload = null;
|
|
resolve(frame.contentDocument.querySelector('#dangling'));
|
|
});
|
|
document.body.appendChild(frame);
|
|
});
|
|
}
|
|
|
|
function assert_img_loaded(test, frame) {
|
|
appendFrameAndGetElement(test, frame)
|
|
.then(test.step_func_done(img => {
|
|
assert_equals(img.naturalHeight, 1, "Height");
|
|
frame.remove();
|
|
}));
|
|
}
|
|
|
|
function assert_img_not_loaded(test, frame) {
|
|
appendFrameAndGetElement(test, frame)
|
|
.then(test.step_func_done(img => {
|
|
assert_equals(img.naturalHeight, 0, "Height");
|
|
assert_equals(img.naturalWidth, 0, "Width");
|
|
}));
|
|
}
|
|
|
|
function assert_nested_img_not_loaded(test, frame) {
|
|
window.addEventListener('message', test.step_func(e => {
|
|
if (e.source != frame.contentWindow)
|
|
return;
|
|
|
|
assert_equals(e.data, 'error');
|
|
test.done();
|
|
}));
|
|
appendFrameAndGetElement(test, frame);
|
|
}
|
|
|
|
function assert_nested_img_loaded(test, frame) {
|
|
window.addEventListener('message', test.step_func(e => {
|
|
if (e.source != frame.contentWindow)
|
|
return;
|
|
|
|
assert_equals(e.data, 'loaded');
|
|
test.done();
|
|
}));
|
|
appendFrameAndGetElement(test, frame);
|
|
}
|
|
|
|
function createFrame(markup) {
|
|
var i = document.createElement('iframe');
|
|
i.srcdoc = `${markup}sekrit`;
|
|
return i;
|
|
}
|
|
|
|
// Subresource requests:
|
|
[
|
|
// Data URLs don't themselves trigger blocking:
|
|
`<img id="dangling" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">`,
|
|
`<img id="dangling" src="data:image/png;base64,${rawNewline}iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">`,
|
|
`<img id="dangling" src="data:image/png;base64,i${rawNewline}VBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">`,
|
|
|
|
// Data URLs with visual structure don't trigger blocking
|
|
`<img id="dangling" src="data:image/svg+xml;utf8,
|
|
<svg width='1' height='1' xmlns='http://www.w3.org/2000/svg'>
|
|
<rect width='100%' height='100%' fill='rebeccapurple'/>
|
|
<rect x='10%' y='10%' width='80%' height='80%' fill='lightgreen'/>
|
|
</svg>">`
|
|
].forEach(markup => {
|
|
async_test(t => {
|
|
var i = createFrame(`${markup} <element attr="" another=''>`);
|
|
assert_img_loaded(t, i);
|
|
}, readableURL(markup));
|
|
});
|
|
|
|
// Nested subresource requests:
|
|
//
|
|
// The following tests load a given HTML string into `<iframe srcdoc="...">`, so we'll
|
|
// end up with a frame with an ID of `dangling` inside the srcdoc frame. That frame's
|
|
// `src` is a `data:` URL that resolves to an HTML document containing an `<img>`. The
|
|
// error/load handlers on that image are piped back up to the top-level document to
|
|
// determine whether the tests' expectations were met. *phew*
|
|
|
|
// Allowed:
|
|
[
|
|
// Just a newline:
|
|
`<iframe id="dangling"
|
|
src="data:text/html,
|
|
<img
|
|
onload='window.parent.postMessage("loaded", "*");'
|
|
onerror='window.parent.postMessage("error", "*");'
|
|
src='http://{{host}}:{{ports[http][0]}}/images/gr${rawNewline}een-256x256.png'>
|
|
">
|
|
</iframe>`,
|
|
|
|
// Just a brace:
|
|
`<iframe id="dangling"
|
|
src="data:text/html,
|
|
<img
|
|
onload='window.parent.postMessage("loaded", "*");'
|
|
onerror='window.parent.postMessage("error", "*");'
|
|
src='http://{{host}}:{{ports[http][0]}}/images/green-256x256.png?${rawBrace}'>
|
|
">
|
|
</iframe>`,
|
|
|
|
// Newline and escaped brace.
|
|
`<iframe id="dangling"
|
|
src="data:text/html,
|
|
<img
|
|
onload='window.parent.postMessage("loaded", "*");'
|
|
onerror='window.parent.postMessage("error", "*");'
|
|
src='http://{{host}}:{{ports[http][0]}}/images/gr${rawNewline}een-256x256.png?${doubleEscapedBrace}'>
|
|
">
|
|
</iframe>`,
|
|
|
|
// Brace and escaped newline:
|
|
`<iframe id="dangling"
|
|
src="data:text/html,
|
|
<img
|
|
onload='window.parent.postMessage("loaded", "*");'
|
|
onerror='window.parent.postMessage("error", "*");'
|
|
src='http://{{host}}:{{ports[http][0]}}/images/green-256x256.png?${doubleEscapedNewline}${rawBrace}'>
|
|
">
|
|
</iframe>`,
|
|
].forEach(markup => {
|
|
async_test(t => {
|
|
var i = createFrame(`
|
|
<script>
|
|
// Repeat the message so that the parent can track this frame as the source.
|
|
window.onmessage = e => window.parent.postMessage(e.data, '*');
|
|
</scr`+`ipt>
|
|
${markup}
|
|
`);
|
|
assert_nested_img_loaded(t, i);
|
|
}, readableURL(markup));
|
|
});
|
|
|
|
// Nested requests that should fail:
|
|
[
|
|
// Newline and brace:
|
|
`<iframe id="dangling"
|
|
src="data:text/html,
|
|
<img
|
|
onload='window.parent.postMessage("loaded", "*");'
|
|
onerror='window.parent.postMessage("error", "*");'
|
|
src='http://{{host}}:{{ports[http][0]}}/images/gr${rawNewline}een-256x256.png?${rawBrace}'>
|
|
">
|
|
</iframe>`,
|
|
|
|
// Leading whitespace:
|
|
`<iframe id="dangling"
|
|
src=" data:text/html,
|
|
<img
|
|
onload='window.parent.postMessage("loaded", "*");'
|
|
onerror='window.parent.postMessage("error", "*");'
|
|
src='http://{{host}}:{{ports[http][0]}}/images/gr${rawNewline}een-256x256.png?${rawBrace}'>
|
|
">
|
|
</iframe>`,
|
|
|
|
// Leading newline:
|
|
`<iframe id="dangling"
|
|
src="\ndata:text/html,
|
|
<img
|
|
onload='window.parent.postMessage("loaded", "*");'
|
|
onerror='window.parent.postMessage("error", "*");'
|
|
src='http://{{host}}:{{ports[http][0]}}/images/gr${rawNewline}een-256x256.png?${rawBrace}'>
|
|
">
|
|
</iframe>`,
|
|
`<iframe id="dangling"
|
|
src="${rawNewline}data:text/html,
|
|
<img
|
|
onload='window.parent.postMessage("loaded", "*");'
|
|
onerror='window.parent.postMessage("error", "*");'
|
|
src='http://{{host}}:{{ports[http][0]}}/images/gr${rawNewline}een-256x256.png?${rawBrace}'>
|
|
">
|
|
</iframe>`,
|
|
|
|
// Leading tab:
|
|
`<iframe id="dangling"
|
|
src="\tdata:text/html,
|
|
<img
|
|
onload='window.parent.postMessage("loaded", "*");'
|
|
onerror='window.parent.postMessage("error", "*");'
|
|
src='http://{{host}}:{{ports[http][0]}}/images/gr${rawNewline}een-256x256.png?${rawBrace}'>
|
|
">
|
|
</iframe>`,
|
|
|
|
// Leading carrige return:
|
|
`<iframe id="dangling"
|
|
src="\rdata:text/html,
|
|
<img
|
|
onload='window.parent.postMessage("loaded", "*");'
|
|
onerror='window.parent.postMessage("error", "*");'
|
|
src='http://{{host}}:{{ports[http][0]}}/images/gr${rawNewline}een-256x256.png?${rawBrace}'>
|
|
">
|
|
</iframe>`,
|
|
].forEach(markup => {
|
|
async_test(t => {
|
|
var i = createFrame(`
|
|
<script>
|
|
// Repeat the message so that the parent can track this frame as the source.
|
|
window.onmessage = e => window.parent.postMessage(e.data, '*');
|
|
</scr`+`ipt>
|
|
${markup}
|
|
`);
|
|
assert_nested_img_not_loaded(t, i);
|
|
}, readableURL(markup));
|
|
});
|
|
</script>
|