diff --git a/dom/nodes/Document-base-url-not-live.window.js b/dom/nodes/Document-base-url-not-live.window.js new file mode 100644 index 00000000000000..f2d19882d75bc4 --- /dev/null +++ b/dom/nodes/Document-base-url-not-live.window.js @@ -0,0 +1,54 @@ +// Confirms that the base URL an about:blank or about:srcdoc document inherits +// from its initiator/container is a snapshot taken at creation, not a live view +// of the initiator's current base URL. +// +// Reading baseURI is not enough on its own: implementations cache the base URL, +// so a live-but-cached implementation would still return the creation-time value +// on read. To distinguish snapshot from live, the container's base URL is changed +// and the child is then forced to recompute its base URL (by inserting and +// removing a ). A snapshot yields the creation-time value; a live view +// yields the container's new base URL. +// +// See https://github.com/whatwg/dom/issues/454 + +function makeIframe(doc, configure) { + return new Promise(resolve => { + const iframe = doc.createElement("iframe"); + configure(iframe); + iframe.addEventListener("load", () => resolve(iframe), { once: true }); + doc.body.appendChild(iframe); + }); +} + +// Inserting then removing a makes the document recompute its base URL. +function forceBaseURLRecompute(doc) { + const base = doc.createElement("base"); + base.setAttribute("href", "http://example.org/forced/"); + doc.head.appendChild(base); + doc.head.removeChild(base); +} + +function notLiveTest(configureChild) { + return async t => { + const container = await makeIframe(document, f => f.src = "about:blank"); + t.add_cleanup(() => container.remove()); + const cdoc = container.contentDocument; + + const child = await makeIframe(cdoc, configureChild); + const childDoc = child.contentDocument; + const inherited = childDoc.baseURI; + + const cbase = cdoc.createElement("base"); + cbase.setAttribute("href", "http://example.com/changed/"); + cdoc.head.appendChild(cbase); + assert_equals(cdoc.baseURI, "http://example.com/changed/", "container base URL changed"); + + forceBaseURLRecompute(childDoc); + assert_equals(childDoc.baseURI, inherited, + "child base URL is a snapshot from creation, not the container's current base URL"); + }; +} + +promise_test(notLiveTest(f => f.src = "about:blank"), "about:blank base URL is not live"); + +promise_test(notLiveTest(f => f.srcdoc = "x"), "about:srcdoc base URL is not live"); diff --git a/dom/nodes/Document-cloneNode-about-base-url-relative.window.js b/dom/nodes/Document-cloneNode-about-base-url-relative.window.js new file mode 100644 index 00000000000000..deadfd9f2ffbbf --- /dev/null +++ b/dom/nodes/Document-cloneNode-about-base-url-relative.window.js @@ -0,0 +1,40 @@ +// A relative href in an about:blank document, and how it interacts with +// cloning. +// +// The base URL an about:blank document inherits from its initiator is exposed +// through the no- path (base URL override), so ordinary relative URLs +// resolve against it. A element, however, resolves its href against the +// document's own URL, so a relative resolves against +// about:blank rather than the inherited base URL. Cloning does not change this. +// +// See https://github.com/whatwg/dom/issues/454 + +function aboutBlankDocument(t) { + return new Promise(resolve => { + const iframe = document.createElement("iframe"); + iframe.src = "about:blank"; + iframe.onload = () => resolve(iframe); + t.add_cleanup(() => iframe.remove()); + document.body.appendChild(iframe); + }); +} + +promise_test(async t => { + const doc = (await aboutBlankDocument(t)).contentDocument; + + const base = doc.createElement("base"); + base.setAttribute("href", "sub/"); + doc.head.appendChild(base); + assert_equals(doc.baseURI, "about:blank"); +}, "A relative in an about:blank document resolves against about:blank"); + +promise_test(async t => { + const doc = (await aboutBlankDocument(t)).contentDocument; + + const base = doc.createElement("base"); + base.setAttribute("href", "sub/"); + doc.head.appendChild(base); + + assert_equals(doc.cloneNode(true).baseURI, "about:blank", "deep"); + assert_equals(doc.cloneNode(false).baseURI, "about:blank", "shallow"); +}, "Clone of an about:blank document with a relative "); diff --git a/dom/nodes/Document-cloneNode-srcdoc-base-url.window.js b/dom/nodes/Document-cloneNode-srcdoc-base-url.window.js new file mode 100644 index 00000000000000..4a78497631a2d3 --- /dev/null +++ b/dom/nodes/Document-cloneNode-srcdoc-base-url.window.js @@ -0,0 +1,32 @@ +// A relative href in an about:srcdoc document, and how it interacts with +// cloning. Parallels the about:blank case. +// +// The base URL an about:srcdoc document inherits from its container is exposed +// through the no- path (base URL override), so ordinary relative URLs +// resolve against it. A element, however, resolves its href against the +// document's own URL, so a relative resolves against +// about:srcdoc rather than the inherited base URL. Cloning does not change this. +// +// See https://github.com/whatwg/dom/issues/454 + +function srcdocDocument(t, srcdoc) { + return new Promise(resolve => { + const iframe = document.createElement("iframe"); + iframe.srcdoc = srcdoc; + iframe.onload = () => resolve(iframe); + t.add_cleanup(() => iframe.remove()); + document.body.appendChild(iframe); + }); +} + +promise_test(async t => { + const doc = (await srcdocDocument(t, "x")).contentDocument; + assert_equals(doc.baseURI, "about:srcdoc"); +}, "A relative in an about:srcdoc document resolves against about:srcdoc"); + +promise_test(async t => { + const doc = (await srcdocDocument(t, "x")).contentDocument; + + assert_equals(doc.cloneNode(true).baseURI, "about:srcdoc", "deep"); + assert_equals(doc.cloneNode(false).baseURI, "about:srcdoc", "shallow"); +}, "Clone of an about:srcdoc document with a relative ");