diff --git a/html/browsers/browsing-the-web/remote-context-helper/resources/executor.sub.html b/html/browsers/browsing-the-web/remote-context-helper/resources/executor.sub.html index 38f4429d91e4ee..95ecb349319fe9 100644 --- a/html/browsers/browsing-the-web/remote-context-helper/resources/executor.sub.html +++ b/html/browsers/browsing-the-web/remote-context-helper/resources/executor.sub.html @@ -9,6 +9,8 @@ 'sec-fetch-mode': '{{header_or_default(sec-fetch-mode, absent)}}', 'sec-fetch-site': '{{header_or_default(sec-fetch-site, absent)}}', 'sec-fetch-dest': '{{header_or_default(sec-fetch-dest, absent)}}', + 'purpose': "{{header_or_default(Purpose, absent)}}", + 'sec-purpose': "{{header_or_default(Sec-Purpose, absent)}}", 'referer': '{{header_or_default(referer, absent)}}', }; requestExecutor(); diff --git a/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js b/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js index 6978cef83211e5..7de980f11f8df4 100644 --- a/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +++ b/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js @@ -161,95 +161,6 @@ */ const DEFAULT_CONTEXT_CONFIG = new RemoteContextConfig(); - /** - * This class represents a configuration for creating remote contexts. This is - * the entry-point - * for creating remote contexts, providing @see addWindow . - */ - class RemoteContextHelper { - /** - * @param {RemoteContextConfig|object} config The configuration - * for this remote context. - */ - constructor(config) { - this.config = RemoteContextConfig.ensure(config); - } - - /** - * Creates a new remote context and returns a `RemoteContextWrapper` giving - * access to it. - * @private - * @param {Object} options - * @param {(url: string) => Promise} options.executorCreator A - * function that takes a URL and causes the browser to navigate some - * window to that URL, e.g. via an iframe or a new window. - * @param {RemoteContextConfig|object} [options.extraConfig] If supplied, - * extra configuration for this remote context to be merged with - * `this`'s existing config. If it's not a `RemoteContextConfig`, it - * will be used to construct a new one. - * @returns {Promise} - */ - async createContext({ - executorCreator, - extraConfig, - isWorker = false, - }) { - const config = - this.config.merged(RemoteContextConfig.ensure(extraConfig)); - - const origin = finalizeOrigin(config.origin); - const url = new URL( - isWorker ? WORKER_EXECUTOR_PATH : WINDOW_EXECUTOR_PATH, origin); - - // UUID is needed for executor. - const uuid = token(); - url.searchParams.append('uuid', uuid); - - if (config.headers) { - addHeaders(url, config.headers); - } - for (const script of config.scripts) { - url.searchParams.append('script', makeAbsolute(script)); - } - - if (config.startOn) { - url.searchParams.append('startOn', config.startOn); - } - - await executorCreator(url.href); - return new RemoteContextWrapper(new RemoteContext(uuid), this, url.href); - } - - /** - * Creates a window with a remote context. @see createContext for - * @param {RemoteContextConfig|object} [extraConfig] Will be - * merged with `this`'s config. - * @param {Object} [options] - * @param {string} [options.target] Passed to `window.open` as the - * 2nd argument - * @param {string} [options.features] Passed to `window.open` as the - * 3rd argument - * @returns {Promise} - */ - addWindow(extraConfig, options) { - return this.createContext({ - executorCreator: windowExecutorCreator(options), - extraConfig, - }); - } - - async createContextWithUrl(extraConfig) { - let saveUrl; - let wrapper = await this.createContext({ - executorCreator: (url) => {saveUrl = url}, - extraConfig, - }); - return [wrapper, saveUrl]; - } - } - // Export this class. - self.RemoteContextHelper = RemoteContextHelper; - /** * Attaches header to the URL. See * https://web-platform-tests.org/writing-tests/server-pipes.html#headers @@ -330,6 +241,15 @@ return this.context.execute_script(fn, args); } + /** + * Returns a JavaScript object containing a subset of the request headers. + * The specific headers that are recorded are in ./executor.sub.html. + * @returns {Object} + */ + async getRequestHeaders() { + return this.executeScript(() => window.requestHeaders); + } + /** * Adds a string of HTML to the executor's document. * @param {string} html @@ -530,4 +450,103 @@ } } } + + + /** + * This class represents a configuration for creating remote contexts. This is + * the entry-point + * for creating remote contexts, providing @see addWindow . + */ + class RemoteContextHelper { + /** + * The constructor to use when creating new remote context wrappers. + * Can be overridden by subclasses. + */ + static RemoteContextWrapper = RemoteContextWrapper; + + /** + * @param {RemoteContextConfig|object} config The configuration + * for this remote context. + */ + constructor(config) { + this.config = RemoteContextConfig.ensure(config); + } + + /** + * Creates a new remote context and returns a `RemoteContextWrapper` giving + * access to it. + * @private + * @param {Object} options + * @param {(url: string) => Promise} options.executorCreator A + * function that takes a URL and causes the browser to navigate some + * window to that URL, e.g. via an iframe or a new window. + * @param {RemoteContextConfig|object} [options.extraConfig] If supplied, + * extra configuration for this remote context to be merged with + * `this`'s existing config. If it's not a `RemoteContextConfig`, it + * will be used to construct a new one. + * @param {Function} [options.remoteContextWrapperConstructor] If supplied, + * the constructor to use when creating the returned + * `RemoteContextWrapper`. (Useful for subclassing.) + * @returns {Promise} + */ + async createContext({ + executorCreator, + extraConfig, + isWorker = false + }) { + const config = + this.config.merged(RemoteContextConfig.ensure(extraConfig)); + + const origin = finalizeOrigin(config.origin); + const url = new URL( + isWorker ? WORKER_EXECUTOR_PATH : WINDOW_EXECUTOR_PATH, origin); + + // UUID is needed for executor. + const uuid = token(); + url.searchParams.append('uuid', uuid); + + if (config.headers) { + addHeaders(url, config.headers); + } + for (const script of config.scripts) { + url.searchParams.append('script', makeAbsolute(script)); + } + + if (config.startOn) { + url.searchParams.append('startOn', config.startOn); + } + + await executorCreator(url.href); + return new this.constructor.RemoteContextWrapper(new RemoteContext(uuid), this, url.href); + } + + /** + * Creates a window with a remote context. @see createContext for + * @param {RemoteContextConfig|object} [extraConfig] Will be + * merged with `this`'s config. + * @param {Object} [options] + * @param {string} [options.target] Passed to `window.open` as the + * 2nd argument + * @param {string} [options.features] Passed to `window.open` as the + * 3rd argument + * @returns {Promise} + */ + addWindow(extraConfig, options) { + return this.createContext({ + executorCreator: windowExecutorCreator(options), + extraConfig, + }); + } + + async createContextWithUrl(extraConfig) { + let saveUrl; + let wrapper = await this.createContext({ + executorCreator: (url) => {saveUrl = url}, + extraConfig, + }); + return [wrapper, saveUrl]; + } + } + // Export this class. + self.RemoteContextHelper = RemoteContextHelper; } diff --git a/speculation-rules/common/invalid-rules.https.html b/speculation-rules/common/invalid-rules.https.html new file mode 100644 index 00000000000000..0c3d042574fb64 --- /dev/null +++ b/speculation-rules/common/invalid-rules.https.html @@ -0,0 +1,29 @@ + + + + + + + + + + + + diff --git a/speculation-rules/prerender/script-supports-speculationrules.html b/speculation-rules/common/script-supports-speculationrules.html similarity index 90% rename from speculation-rules/prerender/script-supports-speculationrules.html rename to speculation-rules/common/script-supports-speculationrules.html index 2dc856fce5da7c..7446f2b6b5f2f8 100644 --- a/speculation-rules/prerender/script-supports-speculationrules.html +++ b/speculation-rules/common/script-supports-speculationrules.html @@ -1,15 +1,14 @@ - HTMLScriptElement.supports speculationrules - + diff --git a/speculation-rules/prefetch/invalid-rules.https.html b/speculation-rules/prefetch/invalid-rules.https.html deleted file mode 100644 index 0fdfacde643958..00000000000000 --- a/speculation-rules/prefetch/invalid-rules.https.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - diff --git a/speculation-rules/prerender/activation-start.html b/speculation-rules/prerender/activation-start.html index 7aee20c3465dcf..421d5694bb88f6 100644 --- a/speculation-rules/prerender/activation-start.html +++ b/speculation-rules/prerender/activation-start.html @@ -16,9 +16,9 @@ promise_test(async t => { const ACTIVATION_DELAY = 10; - const rcHelper = new RemoteContextHelper(); + const rcHelper = new PrerenderingRemoteContextHelper(); const referrerRC = await rcHelper.addWindow(undefined, { features: 'noopener' }); - const prerenderedRC = await addPrerenderRC(referrerRC); + const prerenderedRC = await referrerRC.createPrerenderedContext(); const iframeRC = await prerenderedRC.addIframe(); assert_equals( @@ -36,7 +36,7 @@ // Wait ACTIVATION_DELAY ms before activation. await new Promise(resolve => t.step_timeout(resolve, ACTIVATION_DELAY)); - await activatePrerenderRC(referrerRC, prerenderedRC); + await referrerRC.navigateExpectingPrerenderingActivation(prerenderedRC); assert_greater_than_equal( await getActivationStart(prerenderedRC), diff --git a/speculation-rules/prerender/credentialed-prerender-not-opt-in.html b/speculation-rules/prerender/credentialed-prerender-not-opt-in.html index 697382a6dc8569..fe3bae6fae4057 100644 --- a/speculation-rules/prerender/credentialed-prerender-not-opt-in.html +++ b/speculation-rules/prerender/credentialed-prerender-not-opt-in.html @@ -15,9 +15,9 @@ setup(() => assertSpeculationRulesIsSupported()); promise_test(async t => { - const rcHelper = new RemoteContextHelper(); + const rcHelper = new PrerenderingRemoteContextWrapper(); const referrerRC = await rcHelper.addWindow({origin: 'HTTPS_ORIGIN'}, { features: 'noopener' }); - const prerenderedRC = await addPrerenderRC(referrerRC, {origin: 'HTTPS_REMOTE_ORIGIN'}); + const prerenderedRC = await referrerRC.createPrerenderedContext({origin: 'HTTPS_REMOTE_ORIGIN'}); // Because the prerender doesn't use opt-in header, it is expected to be canceled. // And the navigation is expected to create another page instead of activation. diff --git a/speculation-rules/prerender/credentialed-prerender-opt-in.html b/speculation-rules/prerender/credentialed-prerender-opt-in.html index 91626bafce677b..21c88775f0081c 100644 --- a/speculation-rules/prerender/credentialed-prerender-opt-in.html +++ b/speculation-rules/prerender/credentialed-prerender-opt-in.html @@ -17,8 +17,11 @@ promise_test(async t => { const rcHelper = new RemoteContextHelper(); const referrerRC = await rcHelper.addWindow({origin: 'HTTPS_ORIGIN'}, { features: 'noopener' }); - const prerenderedRC = await addPrerenderRC(referrerRC, {origin: 'HTTPS_REMOTE_ORIGIN', headers: [['Supports-Loading-Mode', 'credentialed-prerender']] }); + const prerenderedRC = await referrerRC.createPrerenderedContext({ + origin: 'HTTPS_REMOTE_ORIGIN', + headers: [['Supports-Loading-Mode', 'credentialed-prerender']] + }); - await activatePrerenderRC(referrerRC, prerenderedRC); + await referrerRC.navigateExpectingPrerenderingActivation(prerenderedRC); }); diff --git a/speculation-rules/prerender/referrer-policy-mismatch.html b/speculation-rules/prerender/referrer-policy-mismatch.html index fa2d424660a367..a5f08832056274 100644 --- a/speculation-rules/prerender/referrer-policy-mismatch.html +++ b/speculation-rules/prerender/referrer-policy-mismatch.html @@ -15,17 +15,17 @@ setup(() => assertSpeculationRulesIsSupported()); promise_test(async t => { - const rcHelper = new RemoteContextHelper(); + const rcHelper = new PrerenderingRemoteContextHelper(); const referrerRC = await rcHelper.addWindow(undefined, { features: "noopener" }); await setReferrerPolicy(referrerRC, "strict-origin-when-cross-origin"); - const prerenderedRC = await addPrerenderRC(referrerRC); + const prerenderedRC = await referrerRC.createPrerenderedContext(); const referrerURL = await referrerRC.executeScript(() => location.href); assert_equals(await prerenderedRC.executeScript(() => document.prerendering), true); assert_equals(await prerenderedRC.executeScript(() => document.referrer), referrerURL); - await activatePrerenderRC(referrerRC, prerenderedRC, url => { + await referrerRC.navigateExpectingPrerenderingActivation(prerenderedRC, url => { const a = document.createElement("a"); a.href = url; a.referrerPolicy = "no-referrer"; @@ -37,17 +37,17 @@ }, 'prerendered with "strict-origin-when-cross-origin", activated with "no-referrer"'); promise_test(async t => { - const rcHelper = new RemoteContextHelper(); + const rcHelper = new PrerenderingRemoteContextHelper(); const referrerRC = await rcHelper.addWindow(undefined, { features: "noopener" }); await setReferrerPolicy(referrerRC, "strict-origin-when-cross-origin"); - const prerenderedRC = await addPrerenderRC(referrerRC); + const prerenderedRC = await referrerRC.createPrerenderedContext(); const referrerURL = await referrerRC.executeScript(() => location.href); assert_equals(await prerenderedRC.executeScript(() => document.prerendering), true); assert_equals(await prerenderedRC.executeScript(() => document.referrer), referrerURL); - await activatePrerenderRC(referrerRC, prerenderedRC, url => { + await referrerRC.navigateExpectingPrerenderingActivation(prerenderedRC, url => { const a = document.createElement("a"); a.href = url; a.referrerPolicy = "strict-origin"; @@ -59,10 +59,10 @@ }, 'prerendered with "strict-origin-when-cross-origin", activated with "strict-origin"'); promise_test(async t => { - const rcHelper = new RemoteContextHelper(); + const rcHelper = new PrerenderingRemoteContextHelper(); const referrerRC = await rcHelper.addWindow(undefined, { features: "noopener" }); await setReferrerPolicy(referrerRC, "strict-origin"); - const prerenderedRC = await addPrerenderRC(referrerRC); + const prerenderedRC = await referrerRC.createPrerenderedContext(); const referrerURL = await referrerRC.executeScript(() => location.href); const referrerOrigin = (new URL(referrerURL)).origin + "/"; @@ -70,7 +70,7 @@ assert_equals(await prerenderedRC.executeScript(() => document.prerendering), true); assert_equals(await prerenderedRC.executeScript(() => document.referrer), referrerOrigin); - await activatePrerenderRC(referrerRC, prerenderedRC, url => { + await referrerRC.navigateExpectingPrerenderingActivation(prerenderedRC, url => { const a = document.createElement("a"); a.href = url; a.referrerPolicy = "unsafe-url"; diff --git a/speculation-rules/prerender/resources/utils.js b/speculation-rules/prerender/resources/utils.js index f012d2d0e41ef6..0387f6dfd9b1b9 100644 --- a/speculation-rules/prerender/resources/utils.js +++ b/speculation-rules/prerender/resources/utils.js @@ -322,99 +322,68 @@ function test_prerender_defer(fn, label) { }, label); } -/** - * Starts prerendering a page from the given referrer `RemoteContextWrapper`, - * using `