diff options
Diffstat (limited to 'test/wpt/tests/fetch/security/dangling-markup-mitigation-data-url.tentative.sub.html')
-rw-r--r-- | test/wpt/tests/fetch/security/dangling-markup-mitigation-data-url.tentative.sub.html | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/test/wpt/tests/fetch/security/dangling-markup-mitigation-data-url.tentative.sub.html b/test/wpt/tests/fetch/security/dangling-markup-mitigation-data-url.tentative.sub.html new file mode 100644 index 0000000..f27735d --- /dev/null +++ b/test/wpt/tests/fetch/security/dangling-markup-mitigation-data-url.tentative.sub.html @@ -0,0 +1,229 @@ +<!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> |