summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/network-error-logging/support/nel.sub.js
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/network-error-logging/support/nel.sub.js')
-rw-r--r--testing/web-platform/tests/network-error-logging/support/nel.sub.js293
1 files changed, 293 insertions, 0 deletions
diff --git a/testing/web-platform/tests/network-error-logging/support/nel.sub.js b/testing/web-platform/tests/network-error-logging/support/nel.sub.js
new file mode 100644
index 0000000000..856af10cf7
--- /dev/null
+++ b/testing/web-platform/tests/network-error-logging/support/nel.sub.js
@@ -0,0 +1,293 @@
+const reportID = "{{$id:uuid()}}";
+
+/*
+ * NEL tests have to run serially, since the user agent maintains a global cache
+ * of Reporting and NEL policies, and we don't want the policies for multiple
+ * tests to interfere with each other. These functions (along with a Python
+ * handler in lock.py) implement a simple spin lock.
+ */
+
+function obtainNELLock() {
+ return fetch("/network-error-logging/support/lock.py?op=lock&reportID=" + reportID);
+}
+
+function releaseNELLock() {
+ return fetch("/network-error-logging/support/lock.py?op=unlock&reportID=" + reportID);
+}
+
+function nel_test(callback, name, properties) {
+ promise_test(async t => {
+ await obtainNELLock();
+ await clearReportingAndNELConfigurations();
+ await callback(t);
+ await releaseNELLock();
+ }, name, properties);
+}
+
+function nel_iframe_test(callback, name, properties) {
+ promise_test(async t => {
+ await obtainNELLock();
+ await clearReportingAndNELConfigurationsInIframe();
+ await callback(t);
+ await releaseNELLock();
+ }, name, properties);
+}
+
+/*
+ * Helper functions for constructing domain names that contain NEL policies.
+ */
+function _monitoredDomain(subdomain) {
+ if (subdomain == "www") {
+ return "{{hosts[alt][www]}}"
+ } else if (subdomain == "www1") {
+ return "{{hosts[alt][www1]}}"
+ } else if (subdomain == "www2") {
+ return "{{hosts[alt][www2]}}"
+ } else if (subdomain == "nonexistent") {
+ return "{{hosts[alt][nonexistent]}}"
+ } else {
+ return "{{hosts[alt][]}}"
+ }
+}
+
+function _getNELResourceURL(subdomain, suffix) {
+ return "https://" + _monitoredDomain(subdomain) +
+ ":{{ports[https][0]}}/network-error-logging/support/" + suffix;
+}
+
+/*
+ * Fetches a resource whose headers define a basic NEL policy (i.e., with no
+ * include_subdomains flag). We ensure that we request the resource from a
+ * different origin than is used for the main test case HTML file or for report
+ * uploads. This minimizes the number of reports that are generated for this
+ * policy.
+ */
+
+function getURLForResourceWithBasicPolicy(subdomain) {
+ return _getNELResourceURL(subdomain, "pass.png?id="+reportID+"&success_fraction=1.0");
+}
+
+function fetchResourceWithBasicPolicy(subdomain) {
+ const url = getURLForResourceWithBasicPolicy(subdomain);
+ return fetch(url, {mode: "no-cors"});
+}
+
+function fetchResourceWithZeroSuccessFractionPolicy(subdomain) {
+ const url = _getNELResourceURL(subdomain, "pass.png?id="+reportID+"&success_fraction=0.0");
+ return fetch(url, {mode: "no-cors"});
+}
+
+/*
+ * Similar to the above methods, but fetch resources in an iframe. Allows matching
+ * full context of reports sent from an iframe that's same-site relative to the domains
+ * a policy set.
+ */
+
+ function loadResourceWithBasicPolicyInIframe(subdomain) {
+ return loadResourceWithPolicyInIframe(
+ getURLForResourceWithBasicPolicy(subdomain));
+}
+
+function loadResourceWithZeroSuccessFractionPolicyInIframe(subdomain) {
+ return loadResourceWithPolicyInIframe(
+ _getNELResourceURL(subdomain, "pass.png?id="+reportID+"&success_fraction=0.0"));
+}
+
+function clearResourceWithBasicPolicyInIframe(subdomain) {
+ return loadResourceWithPolicyInIframe(
+ getURLForClearingConfiguration(subdomain));
+}
+
+function loadResourceWithPolicyInIframe(url) {
+ return new Promise((resolve, reject) => {
+ const frame = document.createElement('iframe');
+ frame.src = url;
+ frame.onload = () => resolve(frame);
+ frame.onerror = () => reject('failed to load ' + url);
+ document.body.appendChild(frame);
+ });
+}
+
+/*
+ * Fetches a resource whose headers define an include_subdomains NEL policy.
+ */
+
+function getURLForResourceWithIncludeSubdomainsPolicy(subdomain) {
+ return _getNELResourceURL(subdomain, "subdomains-pass.png?id="+reportID);
+}
+
+function fetchResourceWithIncludeSubdomainsPolicy(subdomain) {
+ const url = getURLForResourceWithIncludeSubdomainsPolicy(subdomain);
+ return fetch(url, {mode: "no-cors"});
+}
+
+/*
+ * Fetches a resource whose headers do NOT define a NEL policy. This may or may
+ * not generate a NEL report, depending on whether you've already successfully
+ * requested a resource from the same origin that included a NEL policy.
+ */
+
+function getURLForResourceWithNoPolicy(subdomain) {
+ return _getNELResourceURL(subdomain, "no-policy-pass.png");
+}
+
+function fetchResourceWithNoPolicy(subdomain) {
+ const url = getURLForResourceWithNoPolicy(subdomain);
+ return fetch(url, {mode: "no-cors"});
+}
+
+/*
+ * Fetches a resource that doesn't exist. This may or may not generate a NEL
+ * report, depending on whether you've already successfully requested a resource
+ * from the same origin that included a NEL policy.
+ */
+
+function getURLForMissingResource(subdomain) {
+ return _getNELResourceURL(subdomain, "nonexistent.png");
+}
+
+function fetchMissingResource(subdomain) {
+ const url = getURLForMissingResource(subdomain);
+ return fetch(url, {mode: "no-cors"});
+}
+
+/*
+ * Fetches a resource that can be cached without validation.
+ */
+
+function getURLForCachedResource(subdomain) {
+ return _getNELResourceURL(subdomain, "cached-for-one-minute.png");
+}
+
+function fetchCachedResource(subdomain) {
+ const url = getURLForCachedResource(subdomain);
+ return fetch(url, {mode: "no-cors"});
+}
+
+/*
+ * Fetches a resource that can be cached but requires validation.
+ */
+
+function getURLForValidatedCachedResource(subdomain) {
+ return _getNELResourceURL(subdomain, "cached-with-validation.py");
+}
+
+function fetchValidatedCachedResource(subdomain) {
+ const url = getURLForValidatedCachedResource(subdomain);
+ return fetch(url, {mode: "no-cors"});
+}
+
+/*
+ * Fetches a resource that redirects once before returning a successful
+ * response.
+ */
+
+function getURLForRedirectedResource(subdomain) {
+ return _getNELResourceURL(subdomain, "redirect.py?id="+reportID);
+}
+
+function fetchRedirectedResource(subdomain) {
+ const url = getURLForRedirectedResource(subdomain);
+ return fetch(url, {mode: "no-cors"});
+}
+
+/*
+ * Fetches resources that clear out any existing Reporting or NEL configurations
+ * for all origins that any test case might use.
+ */
+
+function getURLForClearingConfiguration(subdomain) {
+ return _getNELResourceURL(subdomain, "clear-policy-pass.png?id="+reportID);
+}
+
+async function clearReportingAndNELConfigurations(subdomain) {
+ await Promise.all([
+ fetch(getURLForClearingConfiguration(""), {mode: "no-cors"}),
+ fetch(getURLForClearingConfiguration("www"), {mode: "no-cors"}),
+ fetch(getURLForClearingConfiguration("www1"), {mode: "no-cors"}),
+ fetch(getURLForClearingConfiguration("www2"), {mode: "no-cors"}),
+ ]);
+ return;
+}
+
+async function clearReportingAndNELConfigurationsInIframe(subdomain) {
+ await Promise.all([
+ clearResourceWithBasicPolicyInIframe(""),
+ clearResourceWithBasicPolicyInIframe("www"),
+ clearResourceWithBasicPolicyInIframe("www1"),
+ clearResourceWithBasicPolicyInIframe("www2"),
+ ]);
+ return;
+}
+
+/*
+ * Returns whether all of the fields in obj1 also exist in obj2 with the same
+ * values. (Put another way, returns whether obj1 and obj2 are equal, ignoring
+ * any extra fields in obj2.)
+ */
+
+function _isSubsetOf(obj1, obj2) {
+ for (const prop in obj1) {
+ if (typeof obj1[prop] === 'object') {
+ if (typeof obj2[prop] !== 'object') {
+ return false;
+ }
+ if (!_isSubsetOf(obj1[prop], obj2[prop])) {
+ return false;
+ }
+ } else if (obj1[prop] != obj2[prop]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ * Verifies that a report was uploaded that contains all of the fields in
+ * expected.
+ */
+
+async function reportExists(expected, retain_reports) {
+ var timeout =
+ document.querySelector("meta[name=timeout][content=long]") ? 50 : 1;
+ var reportLocation =
+ "/reporting/resources/report.py?op=retrieve_report&timeout=" +
+ timeout + "&reportID=" + reportID;
+ if (retain_reports)
+ reportLocation += "&retain=1";
+ const response = await fetch(reportLocation);
+ const json = await response.json();
+ for (const report of json) {
+ if (_isSubsetOf(expected, report)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+ * Verifies that reports were uploaded that contains all of the fields in
+ * expected.
+ */
+
+async function reportsExist(expected_reports, retain_reports) {
+ const timeout = 10;
+ let reportLocation =
+ "/reporting/resources/report.py?op=retrieve_report&timeout=" +
+ timeout + "&reportID=" + reportID;
+ if (retain_reports)
+ reportLocation += "&retain";
+ // There must be the report of pass.png, so adding 1.
+ const min_count = expected_reports.length + 1;
+ reportLocation += "&min_count=" + min_count;
+ const response = await fetch(reportLocation);
+ const json = await response.json();
+ for (const expected of expected_reports) {
+ const found = json.some((report) => {
+ return _isSubsetOf(expected, report);
+ });
+ if (!found)
+ return false;
+ }
+ return true;
+}