commit 0f95e013a05ed4f7313d7ee22102db7b63594ef7 parent 7cfe92b98fca65bebae7d8ef0f6c05a78a3d4fd7 Author: Mike West <mkwst@chromium.org> Date: Tue, 14 Oct 2025 22:23:32 +0000 Bug 1992314 [wpt PR 55197] - [OriginAPI] Implement `Origin.from()`., a=testonly Automatic update from web-platform-tests [OriginAPI] Implement `Origin.from()`. As discussed in https://github.com/mikewest/origin-api/issues/8 and defined in https://mikewest.github.io/origin-api/#extraction. Bug: 434131026 Change-Id: I0df352406f79d110dde4c528abadb853cdc08bb0 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7002661 Reviewed-by: Antonio Sartori <antoniosartori@chromium.org> Commit-Queue: Mike West <mkwst@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Cr-Commit-Position: refs/heads/main@{#1526104} -- wpt-commits: 91169fd7b9dd7a74c896e0349a54a7fc48998a0c wpt-pr: 55197 Diffstat:
10 files changed, 376 insertions(+), 0 deletions(-)
diff --git a/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-global.any.js b/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-global.any.js @@ -0,0 +1,10 @@ +// META: title=`Origin.from(WindowOrWorkerGlobalScope)` +// META: global=window,worker +// META: script=/common/get-host-info.sub.js + +test(t => { + const origin = Origin.from(globalThis); + assert_true(!!origin); + assert_false(origin.opaque, "Origin should not be opaque."); + assert_true(origin.isSameOrigin(Origin.from(get_host_info().ORIGIN))); +}, `Origin.from(globalThis) is a tuple origin.`); diff --git a/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-htmlhyperlinkelementutils.window.js b/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-htmlhyperlinkelementutils.window.js @@ -0,0 +1,44 @@ +// META: title=`Origin.from(HTMLHyperlinkElementUtils)` +// META: script=resources/serializations.js + +for (const opaque of urls.opaque) { + // <a> + test(t => { + const a = document.createElement("a"); + a.href = opaque; + const origin = Origin.from(a); + assert_true(!!origin); + assert_true(origin.opaque); + }, `Origin.from(<a href="${opaque}">) returns an opaque origin.`); + + // <area> + test(t => { + const area = document.createElement("area"); + area.href = opaque; + const origin = Origin.from(area); + assert_true(!!origin); + assert_true(origin.opaque); + }, `Origin.from(<area href="${opaque}">) returns an opaque origin.`); +} + +for (const tuple of urls.tuple) { + // <a> + test(t => { + const a = document.createElement("a"); + a.href = tuple; + const origin = Origin.from(a); + assert_true(!!origin); + assert_false(origin.opaque); + }, `Origin.from(<a href="${tuple}">) returns a tuple origin.`); + + // <area> + test(t => { + const area = document.createElement("area"); + area.href = tuple; + const origin = Origin.from(area); + assert_true(!!origin); + assert_false(origin.opaque); + }, `Origin.from(<area href="${tuple}">) returns a tuple origin.`); +} + + diff --git a/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-location.window.js b/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-location.window.js @@ -0,0 +1,53 @@ +// META: title=`Origin.from(Location)` +// META: script=/common/get-host-info.sub.js + +test(t => { + const origin = Origin.from(window.location); + assert_true(!!origin); + assert_false(origin.opaque); + assert_true(origin.isSameOrigin(Origin.from(get_host_info().ORIGIN))); +}, `Origin.from(window.location) returns a tuple origin.`); + +async_test(t => { + const el = document.createElement('iframe'); + el.src = "/common/blank.html"; + el.onload = t.step_func_done(_ => { + const origin = Origin.from(el.contentWindow.location); + assert_true(!!origin); + assert_false(origin.opaque); + assert_true(origin.isSameOrigin(Origin.from(get_host_info().ORIGIN))); + }); + document.body.appendChild(el); +}, `Origin.from(Location) returns a tuple origin for same-origin frames.`); + +async_test(t => { + const el = document.createElement('iframe'); + el.src = get_host_info().REMOTE_ORIGIN + "/common/blank.html"; + el.onload = t.step_func_done(_ => { + assert_throws_js(TypeError, _ => Origin.from(el.contentWindow.location)); + }); + document.body.appendChild(el); +}, `Origin.from(Location) throws for cross-origin frames.`); + +async_test(t => { + const w = window.open("/html/browsers/windows/resources/post-to-opener.html"); + window.addEventListener("message", t.step_func(e => { + if (e.source === w) { + const origin = Origin.from(w.location); + assert_true(!!origin); + assert_false(origin.opaque); + assert_true(origin.isSameOrigin(Origin.from(get_host_info().ORIGIN))); + t.done(); + } + })); +}, `Origin.from(Location) returns a tuple origin for same-origin windows.`); + +async_test(t => { + const w = window.open(get_host_info().REMOTE_ORIGIN + "/html/browsers/windows/resources/post-to-opener.html"); + window.addEventListener("message", t.step_func(e => { + if (e.source === w) { + assert_throws_js(TypeError, _ => Origin.from(w.location)); + t.done(); + } + })); +}, `Origin.from(Location) throws for cross-origin windows.`); diff --git a/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-messageevent.window.js b/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-messageevent.window.js @@ -0,0 +1,74 @@ +// META: title=`Origin.from(MessageEvent)` +// META: script=/common/get-host-info.sub.js + +async_test(t => { + const el = document.createElement('iframe'); + el.src = "/html/browsers/windows/resources/message-parent.html" + window.addEventListener("message", t.step_func(e => { + if (e.source === el.contentWindow) { + const origin = Origin.from(e); + assert_true(!!origin); + assert_false(origin.opaque); + assert_true(origin.isSameOrigin(Origin.from(get_host_info().ORIGIN))); + t.done(); + } + })); + document.body.appendChild(el); +}, `Origin.from(MessageEvent) returns a tuple origin for messages from same-origin frames.`); + +async_test(t => { + const el = document.createElement('iframe'); + el.src = get_host_info().REMOTE_ORIGIN + "/html/browsers/windows/resources/message-parent.html" + window.addEventListener("message", t.step_func(e => { + if (e.source === el.contentWindow) { + const origin = Origin.from(e); + assert_true(!!origin); + assert_false(origin.opaque); + assert_true(origin.isSameOrigin(Origin.from(get_host_info().REMOTE_ORIGIN))); + t.done(); + } + })); + document.body.appendChild(el); +}, `Origin.from(MessageEvent) returns a tuple origin for messages from cross-origin frames.`); + +async_test(t => { + const el = document.createElement('iframe'); + el.src = get_host_info().REMOTE_ORIGIN + "/html/browsers/windows/resources/message-parent.html" + el.sandbox = "allow-scripts"; + window.addEventListener("message", t.step_func(e => { + if (e.source === el.contentWindow) { + const origin = Origin.from(e); + assert_true(!!origin); + assert_true(origin.opaque); + assert_false(origin.isSameOrigin(Origin.from(get_host_info().REMOTE_ORIGIN))); + t.done(); + } + })); + document.body.appendChild(el); +}, `Origin.from(MessageEvent) returns an opaque origin for messages from sandboxed frames.`); + +async_test(t => { + const w = window.open("/html/browsers/windows/resources/post-to-opener.html"); + window.addEventListener("message", t.step_func(e => { + if (e.source === w) { + const origin = Origin.from(e); + assert_true(!!origin); + assert_false(origin.opaque); + assert_true(origin.isSameOrigin(Origin.from(get_host_info().ORIGIN))); + t.done(); + } + })); +}, `Origin.from(MessageEvent) returns a tuple origin for same-origin windows.`); + +async_test(t => { + const w = window.open(get_host_info().REMOTE_ORIGIN + "/html/browsers/windows/resources/post-to-opener.html"); + window.addEventListener("message", t.step_func(e => { + if (e.source === w) { + const origin = Origin.from(e); + assert_true(!!origin); + assert_false(origin.opaque); + assert_true(origin.isSameOrigin(Origin.from(get_host_info().REMOTE_ORIGIN))); + t.done(); + } + })); +}, `Origin.from(MessageEvent) returns a tuple origin for cross-origin windows.`); diff --git a/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-origin.any.js b/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-origin.any.js @@ -0,0 +1,22 @@ +// META: title=`Origin.from(URL)` +// META: script=resources/serializations.js + +for (const opaque of urls.opaque) { + test(t => { + const originFromString = Origin.from(opaque); + const origin = Origin.from(originFromString); + assert_true(!!origin); + assert_true(origin.opaque, "Origin should be opaque."); + assert_true(origin.isSameOrigin(originFromString)); + }, `Origin.from(Origin.from(${JSON.stringify(opaque)})) is an opaque origin.`); +} + +for (const tuple of urls.tuple) { + test(t => { + const originFromString = Origin.from(tuple); + const origin = Origin.from(originFromString); + assert_true(!!origin); + assert_false(origin.opaque, "Origin should be opaque."); + assert_true(origin.isSameOrigin(originFromString)); + }, `Origin.from(Origin.from(${JSON.stringify(tuple)})) is an tuple origin.`); +} diff --git a/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-string.any.js b/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-string.any.js @@ -0,0 +1,24 @@ +// META: title=`Origin.from(String)` +// META: script=resources/serializations.js + +for (const invalid of urls.invalid) { + test(t => { + assert_throws_js(TypeError, _ => Origin.from(invalid)); + }, `Origin.from(${JSON.stringify(invalid)}) throws a TypeError.`); +} + +for (const opaque of urls.opaque) { + test(t => { + const origin = Origin.from(opaque); + assert_true(!!origin); + assert_true(origin.opaque, "Origin should be opaque."); + }, `Origin.from(${JSON.stringify(opaque)}) is an opaque origin.`); +} + +for (const tuple of urls.tuple) { + test(t => { + const origin = Origin.from(tuple); + assert_true(!!origin); + assert_false(origin.opaque, "Origin should not be opaque."); + }, `Origin.from(${JSON.stringify(tuple)}) is an opaque origin.`); +} diff --git a/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-url.any.js b/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-url.any.js @@ -0,0 +1,24 @@ +// META: title=`Origin.from(URL)` +// META: script=resources/serializations.js + +for (const invalid of urls.invalid) { + test(t => { + assert_throws_js(TypeError, _ => Origin.from(new URL(invalid))); + }, `Origin.from(${JSON.stringify(invalid)}) throws a TypeError.`); +} + +for (const opaque of urls.opaque) { + test(t => { + const origin = Origin.from(new URL(opaque)); + assert_true(!!origin); + assert_true(origin.opaque, "Origin should be opaque."); + }, `Origin.from(${JSON.stringify(opaque)}) is an opaque origin.`); +} + +for (const tuple of urls.tuple) { + test(t => { + const origin = Origin.from(new URL(tuple)); + assert_true(!!origin); + assert_false(origin.opaque, "Origin should not be opaque."); + }, `Origin.from(${JSON.stringify(tuple)}) is an opaque origin.`); +} diff --git a/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-window.window.js b/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from-window.window.js @@ -0,0 +1,64 @@ +// META: title=`Origin.from(Location)` +// META: script=/common/get-host-info.sub.js + +test(t => { + const origin = Origin.from(window); + assert_true(!!origin); + assert_false(origin.opaque); + assert_true(origin.isSameOrigin(Origin.from(get_host_info().ORIGIN))); +}, `Origin.from(window) returns a tuple origin.`); + +async_test(t => { + const el = document.createElement('iframe'); + el.src = "/common/blank.html"; + el.onload = t.step_func_done(_ => { + const origin = Origin.from(el.contentWindow); + assert_true(!!origin); + assert_false(origin.opaque); + assert_true(origin.isSameOrigin(Origin.from(get_host_info().ORIGIN))); + }); + document.body.appendChild(el); +}, `Origin.from(Window) returns a tuple origin for same-origin frames.`); + +async_test(t => { + const el = document.createElement('iframe'); + el.src = get_host_info().REMOTE_ORIGIN + "/common/blank.html"; + el.onload = t.step_func_done(_ => { + assert_throws_js(TypeError, _ => Origin.from(el.contentWindow)); + }); + document.body.appendChild(el); +}, `Origin.from(Window) throws for cross-origin frames.`); + +async_test(t => { + const el = document.createElement('iframe'); + el.src = "/common/blank.html"; + el.sandbox = "allow-scripts"; + el.onload = t.step_func_done(_ => { + assert_throws_js(TypeError, _ => Origin.from(el.contentWindow)); + t.done(); + }); + document.body.appendChild(el); +}, `Origin.from(Window) throws for sandboxed frames.`); + +async_test(t => { + const w = window.open("/html/browsers/windows/resources/post-to-opener.html"); + window.addEventListener("message", t.step_func(e => { + if (e.source === w) { + const origin = Origin.from(w); + assert_true(!!origin); + assert_false(origin.opaque); + assert_true(origin.isSameOrigin(Origin.from(get_host_info().ORIGIN))); + t.done(); + } + })); +}, `Origin.from(Window) returns a tuple origin for same-origin windows.`); + +async_test(t => { + const w = window.open(get_host_info().REMOTE_ORIGIN + "/html/browsers/windows/resources/post-to-opener.html"); + window.addEventListener("message", t.step_func(e => { + if (e.source === w) { + assert_throws_js(TypeError, _ => Origin.from(w)); + t.done(); + } + })); +}, `Origin.from(Window) throws for cross-origin windows.`); diff --git a/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from.any.js b/testing/web-platform/tests/html/browsers/origin/tentative/api/origin-from.any.js @@ -0,0 +1,25 @@ +// META: title=`Origin.from()` +// META: script=resources/serializations.js + +// +// Invalid Inputs: `null`, `undefined`, invalid URL strings, random objects. +// +const invalidInputs = [ + null, + undefined, + 1, + 1.1, + true, + {}, + Object, + Origin, + Origin.from, +]; + +for (const invalid of invalidInputs) { + test(t => { + assert_throws_js(TypeError, _ => Origin.from(invalid)); + }, `Origin.from(${invalid}) throws a TypeError.`); +} + +// Specific object types are tested in `origin-from-*.js` in this directory. diff --git a/testing/web-platform/tests/html/browsers/origin/tentative/api/resources/serializations.js b/testing/web-platform/tests/html/browsers/origin/tentative/api/resources/serializations.js @@ -0,0 +1,36 @@ +const urls = { + invalid: [ + "", + "not-valid", + ], + opaque: [ + "about:blank", + "data:text/plain,opaque", + "weird-protocol:whatever", + "weird-hierarchical-protocol://host/path?etc", + "blob:weird-protocol:whatever", + "blob:weird-hierarchical-protocol://host/path?etc", + ], + tuple: [ + "http://site.example", + "https://site.example", + "https://site.example:123", + "http://sub.site.example", + "https://sub.site.example", + "https://sub.site.example:123", + "https://xn--mlauted-m2a.example", + "ftp://ftp.example", + "ws://ws.example", + "wss://wss.example", + "https://trailing.slash/", + "https://user:pass@site.example", + "https://has.a.port:1234/and/path", + "https://ümlauted.example", + "file:///path/to/a/file.txt", + "blob:https://example.com/some-guid", + "ftp://example.com/", + "https://example.com/path?query#fragment", + "https://127.0.0.1/", + "https://[::1]/", + ], +};