187 lines
6.9 KiB
JavaScript
187 lines
6.9 KiB
JavaScript
"use strict";
|
|
|
|
const SAME_ORIGIN = "https://{{host}}:{{ports[h2][0]}}";
|
|
const CROSS_ORIGIN = "https://{{hosts[alt][www]}}:{{ports[h2][0]}}";
|
|
|
|
const RESOURCES_PATH = "/loading/early-hints/resources";
|
|
const SAME_ORIGIN_RESOURCES_URL = SAME_ORIGIN + RESOURCES_PATH;
|
|
const CROSS_ORIGIN_RESOURCES_URL = CROSS_ORIGIN + RESOURCES_PATH;
|
|
|
|
/**
|
|
* Navigate to a test page with an Early Hints response.
|
|
*
|
|
* @typedef {Object} Preload
|
|
* @property {string} url - A URL to preload. Note: This is relative to the
|
|
* `test_url` parameter of `navigateToTestWithEarlyHints()`.
|
|
* @property {string} as_attr - `as` attribute of this preload.
|
|
* @property {string} [crossorigin_attr] - `crossorigin` attribute of this
|
|
* preload.
|
|
* @property {string} [fetchpriority_attr] - `fetchpriority` attribute of this
|
|
* preload.
|
|
*
|
|
* @param {string} test_url - URL of a test after the Early Hints response.
|
|
* @param {Array<Preload>} preloads - Preloads included in the Early Hints response.
|
|
* @param {bool} exclude_preloads_from_ok_response - Whether to exclude the preloads from the 200 OK reponse.
|
|
*/
|
|
function navigateToTestWithEarlyHints(test_url, preloads, exclude_preloads_from_ok_response) {
|
|
const params = new URLSearchParams();
|
|
params.set("test_url", test_url);
|
|
params.set("exclude_preloads_from_ok_response",
|
|
(!!exclude_preloads_from_ok_response).toString());
|
|
for (const preload of preloads) {
|
|
params.append("preloads", JSON.stringify(preload));
|
|
}
|
|
const url = RESOURCES_PATH +"/early-hints-test-loader.h2.py?" + params.toString();
|
|
window.location.replace(new URL(url, window.location));
|
|
}
|
|
|
|
/**
|
|
* Parses the query string of the current window location and returns preloads
|
|
* in the Early Hints response sent via `navigateToTestWithEarlyHints()`.
|
|
*
|
|
* @returns {Array<Preload>}
|
|
*/
|
|
function getPreloadsFromSearchParams() {
|
|
const params = new URLSearchParams(window.location.search);
|
|
const encoded_preloads = params.getAll("preloads");
|
|
const preloads = [];
|
|
for (const encoded of encoded_preloads) {
|
|
preloads.push(JSON.parse(encoded));
|
|
}
|
|
return preloads;
|
|
}
|
|
|
|
/**
|
|
* Fetches a script or an image.
|
|
*
|
|
* @param {string} element - "script" or "img".
|
|
* @param {string} url - URL of the resource.
|
|
*/
|
|
async function fetchResource(element, url) {
|
|
return new Promise((resolve, reject) => {
|
|
const el = document.createElement(element);
|
|
el.src = url;
|
|
el.onload = resolve;
|
|
el.onerror = _ => reject(new Error("Failed to fetch resource: " + url));
|
|
document.body.appendChild(el);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Fetches a script.
|
|
*
|
|
* @param {string} url
|
|
*/
|
|
async function fetchScript(url) {
|
|
return fetchResource("script", url);
|
|
}
|
|
|
|
/**
|
|
* Fetches an image.
|
|
*
|
|
* @param {string} url
|
|
*/
|
|
async function fetchImage(url) {
|
|
return fetchResource("img", url);
|
|
}
|
|
|
|
/**
|
|
* Returns true when the resource is preloaded via Early Hints.
|
|
*
|
|
* @param {string} url
|
|
* @returns {boolean}
|
|
*/
|
|
function isPreloadedByEarlyHints(url) {
|
|
const entries = performance.getEntriesByName(url);
|
|
if (entries.length === 0) {
|
|
return false;
|
|
}
|
|
assert_equals(entries.length, 1);
|
|
return entries[0].initiatorType === "early-hints";
|
|
}
|
|
|
|
/**
|
|
* Navigate to the referrer policy test page.
|
|
*
|
|
* @param {string} referrer_policy - A value of Referrer-Policy to test.
|
|
*/
|
|
function testReferrerPolicy(referrer_policy) {
|
|
const params = new URLSearchParams();
|
|
params.set("referrer-policy", referrer_policy);
|
|
const same_origin_preload_url = SAME_ORIGIN_RESOURCES_URL + "/fetch-and-record-js.h2.py?id=" + token();
|
|
params.set("same-origin-preload-url", same_origin_preload_url);
|
|
const cross_origin_preload_url = CROSS_ORIGIN_RESOURCES_URL + "/fetch-and-record-js.h2.py?id=" + token();
|
|
params.set("cross-origin-preload-url", cross_origin_preload_url);
|
|
|
|
const path = "resources/referrer-policy-test-loader.h2.py?" + params.toString();
|
|
const url = new URL(path, window.location);
|
|
window.location.replace(url);
|
|
}
|
|
|
|
/**
|
|
* Navigate to the content security policy basic test. The test page sends an
|
|
* Early Hints response with a cross origin resource preload. CSP headers are
|
|
* configured based on the given policies. A policy should be one of the
|
|
* followings:
|
|
* "absent" - Do not send Content-Security-Policy header
|
|
* "allowed" - Set Content-Security-Policy to allow the cross origin preload
|
|
* "disallowed" - Set Content-Security-Policy to disallow the cross origin preload
|
|
*
|
|
* @param {string} early_hints_policy - The policy for the Early Hints response
|
|
* @param {string} final_policy - The policy for the final response
|
|
*/
|
|
function navigateToContentSecurityPolicyBasicTest(
|
|
early_hints_policy, final_policy) {
|
|
const params = new URLSearchParams();
|
|
params.set("resource-origin", CROSS_ORIGIN);
|
|
params.set("resource-url",
|
|
CROSS_ORIGIN_RESOURCES_URL + "/empty.js?" + token());
|
|
params.set("early-hints-policy", early_hints_policy);
|
|
params.set("final-policy", final_policy);
|
|
|
|
const url = "resources/csp-basic-loader.h2.py?" + params.toString();
|
|
window.location.replace(new URL(url, window.location));
|
|
}
|
|
|
|
/**
|
|
* Navigate to a test page which sends an Early Hints containing a cross origin
|
|
* preload link with/without Content-Security-Policy header. The CSP header is
|
|
* configured based on the given policy. The test page disallows the preload
|
|
* while the preload is in-flight. The policy should be one of the followings:
|
|
* "absent" - Do not send Content-Security-Policy header
|
|
* "allowed" - Set Content-Security-Policy to allow the cross origin preload
|
|
*
|
|
* @param {string} early_hints_policy
|
|
*/
|
|
function navigateToContentSecurityPolicyDocumentDisallowTest(early_hints_policy) {
|
|
const resource_id = token();
|
|
const params = new URLSearchParams();
|
|
params.set("resource-origin", CROSS_ORIGIN);
|
|
params.set("resource-url",
|
|
CROSS_ORIGIN_RESOURCES_URL + "/delayed-js.h2.py?id=" + resource_id);
|
|
params.set("resume-url",
|
|
CROSS_ORIGIN_RESOURCES_URL + "/resume-delayed-js.h2.py?id=" + resource_id);
|
|
params.set("early-hints-policy", early_hints_policy);
|
|
|
|
const url = "resources/csp-document-disallow-loader.h2.py?" + params.toString();
|
|
window.location.replace(new URL(url, window.location));
|
|
}
|
|
|
|
/**
|
|
* Navigate to a test page which sends different Cross-Origin-Embedder-Policy
|
|
* values in an Early Hints response and the final response.
|
|
*
|
|
* @param {string} early_hints_policy - The policy for the Early Hints response
|
|
* @param {string} final_policy - The policy for the final response
|
|
*/
|
|
function navigateToCrossOriginEmbedderPolicyMismatchTest(
|
|
early_hints_policy, final_policy) {
|
|
const params = new URLSearchParams();
|
|
params.set("resource-url",
|
|
CROSS_ORIGIN_RESOURCES_URL + "/empty-corp-absent.js?" + token());
|
|
params.set("early-hints-policy", early_hints_policy);
|
|
params.set("final-policy", final_policy);
|
|
|
|
const url = "resources/coep-mismatch.h2.py?" + params.toString();
|
|
window.location.replace(new URL(url, window.location));
|
|
}
|