226 lines
7.8 KiB
JavaScript
226 lines
7.8 KiB
JavaScript
// `integrityValue` indicates the 'integrity' attribute value at the time of
|
|
// #prepare-a-script.
|
|
//
|
|
// `integrityValueAfterPrepare` indicates how the 'integrity' attribute value
|
|
// is modified after #prepare-a-script:
|
|
// - `undefined` => not modified.
|
|
// - `null` => 'integrity' attribute is removed.
|
|
// - others => 'integrity' attribute value is set to that value.
|
|
//
|
|
// TODO: Make the arguments a dictionary for readability in the test files.
|
|
var SRIScriptTest = function(pass, name, src, integrityValue, crossoriginValue, nonce, integrityValueAfterPrepare) {
|
|
this.pass = pass;
|
|
this.name = "Script: " + name;
|
|
this.src = src;
|
|
this.integrityValue = integrityValue;
|
|
this.crossoriginValue = crossoriginValue;
|
|
this.nonce = nonce;
|
|
this.integrityValueAfterPrepare = integrityValueAfterPrepare;
|
|
}
|
|
|
|
SRIScriptTest.prototype.execute = function() {
|
|
var test = async_test(this.name);
|
|
var e = document.createElement("script");
|
|
e.src = this.src;
|
|
if (this.integrityValue) {
|
|
e.setAttribute("integrity", this.integrityValue);
|
|
}
|
|
if(this.crossoriginValue) {
|
|
e.setAttribute("crossorigin", this.crossoriginValue);
|
|
}
|
|
if(this.nonce) {
|
|
e.setAttribute("nonce", this.nonce);
|
|
}
|
|
if(this.pass) {
|
|
e.addEventListener("load", function() {test.done()});
|
|
e.addEventListener("error", function() {
|
|
test.step(function(){ assert_unreached("Good load fired error handler.") })
|
|
});
|
|
} else {
|
|
e.addEventListener("load", function() {
|
|
test.step(function() { assert_unreached("Bad load succeeded.") })
|
|
});
|
|
e.addEventListener("error", function() {test.done()});
|
|
}
|
|
document.body.appendChild(e);
|
|
|
|
if (this.integrityValueAfterPrepare === null) {
|
|
e.removeAttribute("integrity");
|
|
} else if (this.integrityValueAfterPrepare !== undefined) {
|
|
e.setAttribute("integrity", this.integrityValueAfterPrepare);
|
|
}
|
|
};
|
|
|
|
function set_extra_attributes(element, attrs) {
|
|
// Apply the rest of the attributes, if any.
|
|
for (const [attr_name, attr_val] of Object.entries(attrs)) {
|
|
element[attr_name] = attr_val;
|
|
}
|
|
}
|
|
|
|
function buildElementFromDestination(resource_url, destination, attrs) {
|
|
// Assert: |destination| is a valid destination.
|
|
let element;
|
|
|
|
// The below switch is responsible for:
|
|
// 1. Creating the correct subresource element
|
|
// 2. Setting said element's href, src, or fetch-instigating property
|
|
// appropriately.
|
|
switch (destination) {
|
|
case "script":
|
|
element = document.createElement(destination);
|
|
set_extra_attributes(element, attrs);
|
|
element.src = resource_url;
|
|
break;
|
|
case "style":
|
|
element = document.createElement('link');
|
|
set_extra_attributes(element, attrs);
|
|
element.rel = 'stylesheet';
|
|
element.href = resource_url;
|
|
break;
|
|
case "image":
|
|
element = document.createElement('img');
|
|
set_extra_attributes(element, attrs);
|
|
element.src = resource_url;
|
|
break;
|
|
default:
|
|
assert_unreached("INVALID DESTINATION");
|
|
}
|
|
|
|
return element;
|
|
}
|
|
|
|
// When using SRIPreloadTest, also include /preload/resources/preload_helper.js
|
|
// |number_of_requests| is used to ensure that preload requests are actually
|
|
// reused as expected.
|
|
const SRIPreloadTest = (preload_sri_success, subresource_sri_success, name,
|
|
number_of_requests, destination, resource_url,
|
|
link_attrs, subresource_attrs) => {
|
|
const test = async_test(name);
|
|
const link = document.createElement('link');
|
|
|
|
// Early-fail in UAs that do not support `preload` links.
|
|
test.step_func(() => {
|
|
assert_true(link.relList.supports('preload'),
|
|
"This test is automatically failing because the browser does not" +
|
|
"support `preload` links.");
|
|
})();
|
|
|
|
// Build up the link.
|
|
link.rel = 'preload';
|
|
link.as = destination;
|
|
link.href = resource_url;
|
|
for (const [attr_name, attr_val] of Object.entries(link_attrs)) {
|
|
link[attr_name] = attr_val; // This may override `rel` to modulepreload.
|
|
}
|
|
|
|
// Preload + subresource success and failure loading functions.
|
|
const valid_preload_failed = test.step_func(() =>
|
|
{ assert_unreached("Valid preload fired error handler.") });
|
|
const invalid_preload_succeeded = test.step_func(() =>
|
|
{ assert_unreached("Invalid preload load succeeded.") });
|
|
const valid_subresource_failed = test.step_func(() =>
|
|
{ assert_unreached("Valid subresource fired error handler.") });
|
|
const invalid_subresource_succeeded = test.step_func(() =>
|
|
{ assert_unreached("Invalid subresource load succeeded.") });
|
|
const subresource_pass = test.step_func(() => {
|
|
verifyNumberOfResourceTimingEntries(resource_url, number_of_requests);
|
|
test.done();
|
|
});
|
|
const preload_pass = test.step_func(() => {
|
|
const subresource_element = buildElementFromDestination(
|
|
resource_url,
|
|
destination,
|
|
subresource_attrs
|
|
);
|
|
|
|
if (subresource_sri_success) {
|
|
subresource_element.onload = subresource_pass;
|
|
subresource_element.onerror = valid_subresource_failed;
|
|
} else {
|
|
subresource_element.onload = invalid_subresource_succeeded;
|
|
subresource_element.onerror = subresource_pass;
|
|
}
|
|
|
|
document.body.append(subresource_element);
|
|
});
|
|
|
|
if (preload_sri_success) {
|
|
link.onload = preload_pass;
|
|
link.onerror = valid_preload_failed;
|
|
} else {
|
|
link.onload = invalid_preload_succeeded;
|
|
link.onerror = preload_pass;
|
|
}
|
|
|
|
document.head.append(link);
|
|
}
|
|
|
|
// <link> tests
|
|
// Style tests must be done synchronously because they rely on the presence
|
|
// and absence of global style, which can affect later tests. Thus, instead
|
|
// of executing them one at a time, the style tests are implemented as a
|
|
// queue that builds up a list of tests, and then executes them one at a
|
|
// time.
|
|
var SRIStyleTest = function(queue, pass, name, attrs, customCallback, altPassValue) {
|
|
this.pass = pass;
|
|
this.name = "Style: " + name;
|
|
this.customCallback = customCallback || function () {};
|
|
this.attrs = attrs || {};
|
|
this.passValue = altPassValue || "rgb(255, 255, 0)";
|
|
|
|
this.test = async_test(this.name);
|
|
|
|
this.queue = queue;
|
|
this.queue.push(this);
|
|
}
|
|
|
|
SRIStyleTest.prototype.execute = function() {
|
|
var that = this;
|
|
var container = document.getElementById("container");
|
|
while (container.hasChildNodes()) {
|
|
container.removeChild(container.firstChild);
|
|
}
|
|
|
|
var test = this.test;
|
|
|
|
var div = document.createElement("div");
|
|
div.className = "testdiv";
|
|
var e = document.createElement("link");
|
|
|
|
// The link relation is guaranteed to not be "preload" or "modulepreload".
|
|
this.attrs.rel = this.attrs.rel || "stylesheet";
|
|
for (var key in this.attrs) {
|
|
if (this.attrs.hasOwnProperty(key)) {
|
|
e.setAttribute(key, this.attrs[key]);
|
|
}
|
|
}
|
|
|
|
if(this.pass) {
|
|
e.addEventListener("load", function() {
|
|
test.step(function() {
|
|
var background = window.getComputedStyle(div, null).getPropertyValue("background-color");
|
|
assert_equals(background, that.passValue);
|
|
test.done();
|
|
});
|
|
});
|
|
e.addEventListener("error", function() {
|
|
test.step(function(){ assert_unreached("Good load fired error handler.") })
|
|
});
|
|
} else {
|
|
e.addEventListener("load", function() {
|
|
test.step(function() { assert_unreached("Bad load succeeded.") })
|
|
});
|
|
e.addEventListener("error", function() {
|
|
test.step(function() {
|
|
var background = window.getComputedStyle(div, null).getPropertyValue("background-color");
|
|
assert_not_equals(background, that.passValue);
|
|
test.done();
|
|
});
|
|
});
|
|
}
|
|
container.appendChild(div);
|
|
container.appendChild(e);
|
|
this.customCallback(e, container);
|
|
};
|
|
|