Skip to content

Commit

Permalink
Change initial about:blank navigation behavior for iframes and popups
Browse files Browse the repository at this point in the history
For iframes: previously, we did a confusing thing where we would navigate to a non-initial about:blank. 2/3 engines instead just fire a synchronous load event at the iframe element, with no navigation. This is a bit simpler, and matches the popup case a bit better (after the below modifications).

For popups: previously, we fired the load event (but not the pageshow event) when the popup stays on the initial about:blank. 2/3 engines instead fire no events in this case, and the remaining one only fires it in the explicit "about:blank" case but not in the empty string case.

In both cases, it wasn't quite clear what to do when navigating to something like about:blank#foo or about:blank?foo. The spec now makes it clear that such cases cause URL updates of the new browsing context but not full navigations. In particular, for now at least the the initial about:blank-ness of the Document is retained. (In browsers, it seems like it's always retained for replacement vs. push purposes, but is only sometimes retained for Window object reuse purposes. #3267 tracks sorting that out.)

This also refactors the window open steps so that they have two primary branches, depending on whether to create a new window or not. Previously the steps were sorta unified, but there were a lot of consultations of the "new" variable throughout, which made it hard to understand the differences between the cases.

Closes #6863.
  • Loading branch information
domenic committed Aug 10, 2021
1 parent 0050553 commit cdf62c8
Showing 1 changed file with 131 additions and 67 deletions.
198 changes: 131 additions & 67 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -6592,6 +6592,18 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
<span>tree order</span>.</p></li>
</ol>

<p>A <span>URL</span> <dfn>matches <code>about:blank</code></dfn> if its <span
data-x="concept-url-scheme">scheme</span> is "<code data-x="">about</code>", its <span
data-x="concept-url-path">path</span> contains a single string "<code data-x="">blank</code>", its
<span data-x="concept-url-username">username</span> and <span
data-x="concept-url-password">password</span> are the empty string, and its <span
data-x="concept-url-host">host</span> is null.</p>

<p class="note">Such a URL's <span data-x="concept-url-query">query</span> and <span
data-x="concept-url-fragment">fragment</span> can be non-null. For example, the <span>URL
record</span> created by <span data-x="URL parser">parsing</span> "<code
data-x="">about:blank?foo#bar</code>" <span>matches <code>about:blank</code></span>.</p>


<div w-nodev>

Expand Down Expand Up @@ -9270,7 +9282,7 @@ o.myself = o;</code></pre>
<span>nested browsing context</span>'s <span data-x="bc-container-document">container
document</span>'s <span data-x="concept-document-origin">origin</span>, even though its
<span>active <code>Document</code></span>'s <span data-x="concept-document-url">URL</span> is
"<code>about:blank</code>". <ref spec=DOM></p>
<code>about:blank</code>. <ref spec=DOM></p>

<p>When a <code>Document</code> is created by a <span data-x="concept-script">script</span> using
the <code data-x="dom-DOMImplementation-createDocument">createDocument()</code> or <code
Expand Down Expand Up @@ -30735,39 +30747,49 @@ interface <dfn interface>HTMLIFrameElement</dfn> : <span>HTMLElement</span> {
</ol>
</li>

<li><p>Otherwise, if <var>element</var> has a <code data-x="attr-iframe-src">src</code> attribute
specified, or <var>initialInsertion</var> is false, then run the <span>shared attribute
processing steps for <code>iframe</code> and <code>frame</code> elements</span> given
<var>element</var>.</p></li>
<li><p>Otherwise, run the <span>shared attribute processing steps for <code>iframe</code> and
<code>frame</code> elements</span> given <var>element</var> and
<var>initialInsertion</var>.</p></li>
</ol>

<p id="otherwise-steps-for-iframe-or-frame-elements">The <dfn>shared attribute processing steps
for <code>iframe</code> and <code>frame</code> elements</dfn>, given an element
<var>element</var>, are:</p>
<var>element</var> and a boolean <var>initialInsertion</var>, are:</p>

<ol>
<li>
<p>If <var>element</var> has no <code data-x="attr-iframe-src">src</code> attribute specified,
or its value is the empty string, let <var>url</var> be the <span>URL</span>
"<code>about:blank</code>".</p>
<!-- https://software.hixie.ch/utilities/js/live-dom-viewer/?saved=2641 -->

<p>Otherwise, <span data-x="parse a url">parse</span> the value of <var>element</var>'s <code
data-x="attr-iframe-src">src</code> attribute, relative to <var>element</var>'s <span>node
document</span>.</p>
<li><p>Let <var>url</var> be the <span>URL record</span> <code>about:blank</code>.</p></li>

<p>If that is not successful, then let <var>url</var> be the <span>URL</span>
"<code>about:blank</code>". Otherwise, let <var>url</var> be the <span>resulting URL
record</span>.</p>
</li>
<li><p>If <var>element</var> has a <code data-x="attr-iframe-src">src</code> attribute specified,
and its value is not the empty string, then <span data-x="parse a url">parse</span> the value of
that attribute relative to <var>element</var>'s <span>node document</span>. If this is
successful, then set <var>url</var> to the <span>resulting URL record</span>.</p></li>

<li><p>If there exists an <span>ancestor browsing context</span> of <var>element</var>'s
<span>nested browsing context</span> whose <span>active document</span>'s <span
data-x="concept-document-url">URL</span>, ignoring <span
data-x="concept-url-fragment">fragments</span>, is equal to <var>url</var>, then return.</p></li>
<!-- https://www.hixie.ch/tests/adhoc/html/frames/iframes/ 008.html and 009.html -->
<!-- https://software.hixie.ch/utilities/js/live-dom-viewer/?saved=1969 -->
<!-- I'm assuming that "resolve" will normalize things like scheme and hostname case -->

<li>
<p>If <var>url</var> <span>matches <code>about:blank</code></span> and
<var>initialInsertion</var> is true, then:</p>

<ol>
<li>
<p>Perform the <span>URL and history update steps</span> given <var>element</var>'s
<span>nested browsing context</span>'s <span>active document</span> and <var>url</var>.</p>

<p class="note">This is necessary in case <var>url</var> is something like <code
data-x="">about:blank?foo</code>. If <var>url</var> is just plain <code
data-x="">about:blank</code>, this will do nothing.</p>
</li>

<li><p>Run the <span>iframe load event steps</span> given <var>element</var>.</p></li>

<li><p>Return.</p></li>
</ol>
</li>

<li><p>Let <var>resource</var> be a new <span data-x="concept-request">request</span> whose <span
data-x="concept-request-url">URL</span> is <var>url</var> and whose <span
Expand Down Expand Up @@ -32143,11 +32165,12 @@ interface <dfn interface>HTMLObjectElement</dfn> : <span>HTMLElement</span> {
<p>If the <code>object</code> element's <span>nested browsing context</span> is null, then
<span>create a new nested browsing context</span> for the element.</p>

<p>If the <span>URL</span> of the given resource is not <code>about:blank</code>, then
<span>navigate</span><!-- DONAV object --> the element's <span>nested browsing
context</span> to that resource, with <var data-x="navigation-hh">historyHandling</var> set
to "<code data-x="hh-replace">replace</code>" and the <span>source browsing context</span>
set to the <code>object</code> element's <span>node document</span>'s <span
<p>If the <span>URL</span> of the given resource does not <span data-x="matches
about:blank">match <code>about:blank</code></span>, then <span>navigate</span><!-- DONAV
object --> the element's <span>nested browsing context</span> to that resource, with <var
data-x="navigation-hh">historyHandling</var> set to "<code
data-x="hh-replace">replace</code>" and the <span>source browsing context</span> set to the
<code>object</code> element's <span>node document</span>'s <span
data-x="concept-document-bc">browsing context</span>. (The <code
data-x="attr-object-data">data</code> attribute of the <code>object</code> element doesn't
get updated if the browsing context gets further navigated to other locations.)</p>
Expand Down Expand Up @@ -79132,8 +79155,8 @@ popup4.close();</code></pre></div>
origin</span>.</p></li>

<li>
<p>If <var>invocationOrigin</var> is non-null and <var>url</var> is <code>about:blank</code>,
then return <var>invocationOrigin</var>.</p>
<p>If <var>invocationOrigin</var> is non-null and <var>url</var> <span>matches
<code>about:blank</code></span>, then return <var>invocationOrigin</var>.</p>

<p class="note">The result here is that two documents end up with the same underlying
<span>origin</span>, meaning that <code data-x="dom-document-domain">document.domain</code>
Expand Down Expand Up @@ -80733,69 +80756,93 @@ dictionary <dfn dictionary>WindowPostMessageOptions</dfn> : <span>StructuredSeri
tab.</p>
</li>

<li><p>Let <var>new</var> be true if <var>windowType</var> is either "<code data-x="">new and
unrestricted</code>" or "<code data-x="">new with no opener</code>", and false otherwise.</p></li>

<li><p>If <var>target browsing context</var> is null, then return null.</p></li>

<li><p>If <var>new</var> is true, then <span>set up browsing context features</span> for
<var>target browsing context</var> given <var>tokenizedFeatures</var>. <ref
spec="CSSOMVIEW"></p></li>

<li><p>Let <var>urlRecord</var> be the <span>URL</span> "<code>about:blank</code>".</p></li>

<li>
<p>If <var>url</var> is not the empty string or <var>new</var> is true, then:
<p>If <var>windowType</var> is either "<code data-x="">new and unrestricted</code>" or "<code
data-x="">new with no opener</code>", then:</p>

<ol>
<li><p><span>Set up browsing context features</span> for <var>target browsing context</var>
given <var>tokenizedFeatures</var>. <ref spec="CSSOMVIEW"></p></li>

<li><p>Let <var>urlRecord</var> be the <span>URL record</span>
<code>about:blank</code>.</p></li>

<li><p>If <var>url</var> is not the empty string, then <span data-x="parse a url">parse</span>
<var>url</var> relative to the <span>entry settings object</span>, and set <var>urlRecord</var>
to the <span>resulting URL record</span>, if any. If the <span>parse a URL</span> algorithm
failed, then throw a <span>"<code>SyntaxError</code>"</span> <code>DOMException</code>.</p></li>

<li><p>Let <var>request</var> be a new <span data-x="concept-request">request</span> whose
<span data-x="concept-request-url">URL</span> is <var>urlRecord</var>.</p></li>

<li><p>If <var>noreferrer</var> is true, then set <var>request</var>'s <span
data-x="concept-request-referrer">referrer</span> to "<code
data-x="">noreferrer</code>".</p></li>
failed, then throw a <span>"<code>SyntaxError</code>"</span>
<code>DOMException</code>.</p></li>

<li><p>Let <var>window</var> be <var>target browsing context</var>'s <span>active
window</span>.</p></li>
<li>
<p>If <var>urlRecord</var> <span>matches <code>about:blank</code></span>, then perform the
<span>URL and history update steps</span> given <var>target browsing context</var>'s
<span>active document</span> and <var>urlRecord</var>.</p>

<li><p>If <var>urlRecord</var> is "<code>about:blank</code>" and <var>new</var> is true, then
<span>queue a global task</span> on the <span>networking task source</span> given
<var>window</var> to <span data-x="concept-event-fire">fire an event</span> named <code
data-x="event-load">load</code> at <var>window</var>, with the <var>legacy target override
flag</var> set.</p>
<p class="note">This is necessary in case <var>url</var> is something like <code
data-x="">about:blank?foo</code>. If <var>url</var> is just plain <code
data-x="">about:blank</code>, this will do nothing.</p>
</li>

<li>
<p>Otherwise:</p>

<ol>
<li><p>Let <var>historyHandling</var> be "<code data-x="hh-replace">replace</code>" if
<var>new</var> is true; otherwise "<code data-x="hh-default">default</code>".</p></li>
<li><p>Let <var>request</var> be a new <span data-x="concept-request">request</span> whose
<span data-x="concept-request-url">URL</span> is <var>urlRecord</var>.</p></li>

<li><p>If <var>noreferrer</var> is true, then set <var>request</var>'s <span
data-x="concept-request-referrer">referrer</span> to "<code
data-x="">no-referrer</code>".</p></li>

<li><p><span>Navigate</span><!--DONAV window.open()--> <var>target browsing context</var> to
<var>request</var>, with <var><span>exceptionsEnabled</span></var> set to true, <var
data-x="navigation-hh">historyHandling</var> set to <var>historyHandling</var>, and the
<span>source browsing context</span> set to <var>source browsing context</var>.</p></li>
data-x="navigation-hh">historyHandling</var> set to "<code
data-x="hh-replace">replace</code>", and the <span>source browsing context</span> set to
<var>source browsing context</var>.</p></li>
</ol>
</li>
</ol>
</li>

<li><p>If <var>noopener</var> is true or <var>windowType</var> is "<code
data-x="">new with no opener</code>", then return null.</p></li>

<li>
<p>Otherwise, if <var>new</var> is false, set <var>target browsing context</var>'s <span>opener
browsing context</span> to <var>source browsing context</var>.</p>
<p>Otherwise:</p>

<ol>
<li>
<p>If <var>url</var> is not the empty string, then:</p>

<ol>
<li><p>Let <var>urlRecord</var> be the <span>URL record</span>
<code>about:blank</code>.</p></li>

<p class="note">If <var>new</var> is true this is done as part of <span>creating a new auxiliary
browsing context</span>.</p>
<li><p><span data-x="parse a url">Parse</span> <var>url</var> relative to the <span>entry
settings object</span>, and set <var>urlRecord</var> to the <span>resulting URL
record</span>, if any. If the <span>parse a URL</span> algorithm failed, then throw a
<span>"<code>SyntaxError</code>"</span> <code>DOMException</code>.</p></li>

<li><p>Let <var>request</var> be a new <span data-x="concept-request">request</span> whose
<span data-x="concept-request-url">URL</span> is <var>urlRecord</var>.</p></li>

<li><p>If <var>noreferrer</var> is true, then set <var>request</var>'s <span
data-x="concept-request-referrer">referrer</span> to "<code
data-x="">noreferrer</code>".</p></li>

<li><p><span>Navigate</span><!--DONAV window.open()--> <var>target browsing context</var> to
<var>request</var>, with <var><span>exceptionsEnabled</span></var> set to true and the
<span>source browsing context</span> set to <var>source browsing context</var>.</p></li>
</ol>
</li>

<li><p>If <var>noopener</var> is false, then set <var>target browsing context</var>'s
<span>opener browsing context</span> to <var>source browsing context</var>.</p></li>
</ol>
</li>

<li><p>If <var>noopener</var> is true or <var>windowType</var> is "<code
data-x="">new with no opener</code>", then return null.</p></li>

<li><p>Return <var>target browsing context</var>'s <code>WindowProxy</code> object.</p></li>
</ol>

Expand Down Expand Up @@ -88515,9 +88562,26 @@ dictionary <dfn dictionary>PageTransitionEventInit</dfn> : <span>EventInit</span
<li><p>Set <var>document</var>'s <span>completely loaded time</span> to the current
time.</p></li>

<li><p>Let <var>container</var> be <var>document</var>'s <span
data-x="concept-document-bc">browsing context</span>'s <span
data-x="bc-container">container</span>.</p></li>
<li>
<p>Let <var>container</var> be <var>document</var>'s <span
data-x="concept-document-bc">browsing context</span>'s <span
data-x="bc-container">container</span>.</p>

<div class="note">
<p>This will be null in the case where <var>document</var> is the <span data-x="is initial
about:blank">initial <code>about:blank</code></span> <code>Document</code> in a
<code>frame</code> or <code>iframe</code>, since at the point of <span data-x="creating a new
browsing context">browsing context creation</span> which calls this algorithm, the container
relationship has not yet been established. (That happens in a subsequent step of <span>create
a new nested browsing context</span>.)</p>

<p>The consequence of this is that we the following steps do nothing, i.e., we do not fire an
asynchronous <code data-x="event-load">load</code> event on the container element for such
cases. Instead, a synchronous <code data-x="event-load">load</code> event is fired in a special
initial-insertion case in the <span>shared attribute processing steps for <code>iframe</code>
and <code>frame</code> elements</span>.</p>
</div>
</li>

<li><p>If <var>container</var> is an <code>iframe</code> element, then <span>queue an element
task</span> on the <span>DOM manipulation task source</span> given <var>container</var> to run
Expand Down Expand Up @@ -119018,7 +119082,7 @@ interface <dfn interface>HTMLFrameSetElement</dfn> : <span>HTMLElement</span> {
<li><p>If <var>element</var> has a <code undefined data-x="attr-frame-src">src</code> attribute
specified, or <var>initialInsertion</var> is false, then run the <span>shared attribute
processing steps for <code>iframe</code> and <code>frame</code> elements</span> given
<var>element</var>.</p></li>
<var>element</var> and <var>initialInsertion</var>.</p></li>
</ol>

<p>The <code>frame</code> element <span>potentially delays the load event</span>.</p>
Expand Down

0 comments on commit cdf62c8

Please sign in to comment.