Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 106 additions & 37 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -11480,6 +11480,78 @@ partial interface <dfn id="document" data-lt="">Document</dfn> {
readonly attribute <span>Element</span>? <span data-x="dom-documentorshadowroot-activeElement">activeElement</span>;
};</code></pre>

<h4>Ancestor origins</h4>

<div algorithm>
<p>A <code>Document</code> object has an associated <dfn export for="Document"
data-x="concept-document-internal-ancestor-origin-objects-list">internal ancestor origin objects
list</dfn>, initially « ».</p>

<p>The <dfn>internal ancestor origin objects list creation steps</dfn> given a
<code>Document</code> object <var>innerDoc</var> are:</p>

<ol>
<li><p>Let <var>output</var> be « ».</p></li>

<li><p>Let <var>parentDoc</var> be <var>innerDoc</var>'s <span
data-x="doc-container-document">container document</span>.</p></li>

<li><p>If <var>parentDoc</var> is null, then return <var>output</var>.</p></li>

<li><p><span>Assert</span>: <var>parentDoc</var> is <span>fully active</span>.</p></li>

<li><p>Let <var>ancestorOrigins</var> be <var>parentDoc</var>'s <span
data-x="concept-document-internal-ancestor-origin-objects-list">internal ancestor origin objects
list</span>.</p></li>

<li><p><span data-x="list append">Append</span> <var>parentDoc</var>'s <span
data-x="concept-document-origin">origin</span> to <var>output</var>.</p></li>

<li>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could use https://infra.spec.whatwg.org/#list-extend, instead of iterating manually?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#11560 would need to change back to iterating the list though.

<p><span data-x="list iterate">For each</span> <var>ancestorOrigin</var> of
<var>ancestorOrigins</var>:</p>

<ol>
<li><p><span data-x="list append">Append</span> <var>ancestorOrigin</var> to
<var>output</var>.</p></li>
</ol>
</li>

<li><p>Return <var>output</var>.</p></li>
</ol>
</div>

<div algorithm>
<p>A <code>Document</code> object has an associated <dfn export for="Document"
data-x="concept-document-ancestor-origins-list">ancestor origins list</dfn>, initially a
<code>DOMStringList</code> object whose associated list is an empty <span>list</span>.</p>

<p>The <dfn>ancestor origins list creation steps</dfn> given a <code>Document</code> object
<var>document</var> are:</p>

<ol>
<li><p>Let <var>ancestorOrigins</var> be <var>document</var>'s <span
data-x="concept-document-internal-ancestor-origin-objects-list">internal ancestor origin objects
list</span>.</p></li>

<li><p>Let <var>output</var> be « ».</p></li>

<li>
<p><span data-x="list iterate">For each</span> <var>origin</var> of
<var>ancestorOrigins</var>:</p>

<ol>
<li><p><span data-x="list append">Append</span> the <span data-x="serialization of an
origin">serialization</span> of <var>origin</Var> to <var>output</var>.</p></li>
</ol>
</li>

<li><p>Return a new <code>DOMStringList</code> object whose associated list is
<var>output</var>.</p></li>
</ol>
</div>


<h4><dfn>Resource metadata management</dfn></h4>

<dl class="domintro">
Expand Down Expand Up @@ -96799,7 +96871,7 @@ interface <dfn interface>Location</dfn> { // but see also <a href="#the-location
[<span>LegacyUnforgeable</span>] undefined <span data-x="dom-location-replace">replace</span>(USVString url);
[<span>LegacyUnforgeable</span>] undefined <span data-x="dom-location-reload">reload</span>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not returning the same object each time from a getter seems very surprising. Why would we want that? You don't want obj.x !== obj.x (there's a rule for this in the design principles as well).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Step 1 says to return a an empty DOMStringList if this's relevant Document is null.

Since the relevant Document can change over time, I think we can't return the same object always. So options are:

  1. Cache whatever was returned the first time the getter is called. (This matches WebKit.)
  2. Return a new object every time. (Gecko, Chromium.)
  3. Maybe throw an InvalidStateError in step 1?

The current spec is wrong since it says SameObject but then in step 1 sometimes returns an empty list (not a DOMStringList).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have to return the same object always to not violate obj.x !== obj.x. Caching or throwing would work. Caching is probably the most compatible. SameObject is indeed wrong if the returned value has to change at certain points in time though.

Can you observe the object changing in WebKit? Maybe with initial about:blank?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, for example removing an iframe. But since WebKit caches the return value from the first access, it's different if you call the getter first before or after the iframe is removed.

https://software.hixie.ch/utilities/js/live-dom-viewer/saved/14480

Maybe option 4 is to create an empty DOMStringList in step 1 but cache it, so there can be two separate objects returned.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if you navigate an iframe its Location object stays the same, but the relevant Document changes as well. (Even across a cross-origin navigation I'm pretty sure as you're holding a proxy object, essentially.) We probably want to invalidate the list each time the relevant Document changes. Not a 100% sure how to best specify this though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR computes a new list when a Document is created and stores it on the Document object, so that is solved by this PR.

About the chaching or throwing issue, should we go with option 4?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite follow here. If iframe can be removed, the location have it's relevant document null, then

let a = location.ancestorOrigins;
...
/* relevant document for location becomes null */
...
let b = location.ancestorOrigins;
a !== b; // true

Also

let loc = i.location;
let list = loc.ancestorOrigins;
i.contentWindow.navigation.navigate("www.some.where.else-same-origin.com");
let whatIsThis = list !== loc.ancestorOrigins;

What value does whatIsThis have?

Is there a reason why we can't make this attribute NewObject?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@theIDinside it's ok to have a new object when there's a semantic change, but just accessing ancestorOrigins twice without removing an iframe or navigating should give the same object both times.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK I've attempted to fix this in e3091d3

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


[<span>LegacyUnforgeable</span>, SameObject] readonly attribute <span>DOMStringList</span> <span data-x="dom-location-ancestorOrigins">ancestorOrigins</span>;
[<span>LegacyUnforgeable</span>] readonly attribute <span>DOMStringList</span> <span data-x="dom-location-ancestorOrigins">ancestorOrigins</span>;
};</code></pre>

<dl class="domintro">
Expand Down Expand Up @@ -96902,38 +96974,6 @@ interface <dfn interface>Location</dfn> { // but see also <a href="#the-location
<code>Document</code></span> is non-null, and <code>about:blank</code> otherwise.</p>
</div>

<div algorithm>
<p>A <code>Location</code> object has an associated <dfn
data-x="concept-location-ancestor-origins-list">ancestor origins list</dfn>. When a
<code>Location</code> object is created, its <span
data-x="concept-location-ancestor-origins-list">ancestor origins list</span> must be set to a
<code>DOMStringList</code> object whose associated list is the <span>list</span> of strings that
the following steps would produce:</p>

<ol>
<li><p>Let <var>output</var> be a new <span>list</span> of strings.</p></li>

<li><p>Let <var>current</var> be the <code>Location</code> object's <span>relevant
<code>Document</code></span>.</p></li>

<li>
<p>While <var>current</var>'s <span data-x="doc-container-document">container document</span>
is non-null:</p>

<ol>
<li><p>Set <var>current</var> to <var>current</var>'s <span
data-x="doc-container-document">container document</span>.</p></li>

<li><p><span data-x="list append">Append</span> the <span data-x="serialization of an
origin">serialization</span> of <var>current</var>'s <span
data-x="concept-document-origin">origin</span> to <var>output</var>.</p></li>
</ol>
</li>

<li><p>Return <var>output</var>.</p></li>
</ol>
</div>

<div algorithm>
<p>To <dfn><code>Location</code>-object navigate</dfn> a <code>Location</code> object
<var>location</var> to a <span>URL</span> <var>url</var>, optionally given a <code
Expand Down Expand Up @@ -97478,22 +97518,27 @@ interface <dfn interface>Location</dfn> { // but see also <a href="#the-location

<hr>

<p>A <code>Location</code> object has an associated <dfn export for="Location"
data-x="concept-location-empty-domstringlist">empty <code>DOMStringList</code></dfn> which is a
<code>DOMStringList</code> object whose associated list is an empty <span>list</span>.</p>

<div algorithm>
<p>The <dfn attribute for="Location"><code
data-x="dom-location-ancestorOrigins">ancestorOrigins</code></dfn> getter steps are:</p>

<ol>
<li><p>If <span>this</span>'s <span>relevant <code>Document</code></span> is null, then return
an empty <span>list</span>.</p></li>
<span>this</span>'s <span data-x="concept-location-empty-domstringlist">empty
<code>DOMStringList</code></span>.</p></li>

<li><p>If <span>this</span>'s <span>relevant <code>Document</code></span>'s <span
data-x="concept-document-origin">origin</span> is not <span>same origin-domain</span> with the
<span>entry settings object</span>'s <span
data-x="concept-settings-object-origin">origin</span>, then throw a
<span>"<code>SecurityError</code>"</span> <code>DOMException</code>.</p></li>

<li><p>Otherwise, return <span>this</span>'s <span
data-x="concept-location-ancestor-origins-list">ancestor origins list</span>.</p></li>
<li><p>Otherwise, return <span>this</span>'s <span>relevant <code>Document</code></span>'s <span
data-x="concept-document-ancestor-origins-list">ancestor origins list</span>.</p></li>
</ol>
</div>

Expand Down Expand Up @@ -104488,6 +104533,21 @@ interface <dfn interface>NotRestoredReasons</dfn> {
</dl>
</li>

<li>
<p>If <var>embedder</var> is non-null, then:</p>

<ol>
<li><p>Set <var>document</var>'s <span
data-x="concept-document-internal-ancestor-origin-objects-list">internal ancestor origin
objects list</span> to the result of running the <span>internal ancestor origin objects list
creation steps</span> given <var>document</var>.</p></li>

<li><p>Set <var>document</var>'s <span data-x="concept-document-ancestor-origins-list">ancestor
origins list</span> to the result of running the <span>ancestor origins list creation
steps</span> given <var>document</var>.</p></li>
</ol>
</li>

<li>
<p>If <var>creator</var> is non-null, then:</p>

Expand Down Expand Up @@ -111176,7 +111236,7 @@ location.href = '#foo';</code></pre>
<p class="note">This means that both the <span data-x="is initial about:blank">initial
<code>about:blank</code></span> <code>Document</code>, and the new <code>Document</code> that
is about to be created, will share the same <code>Window</code> object.</p>
</li>
</li>

<li id="create-new-agent-and-window">
<p>Otherwise:</p>
Expand Down Expand Up @@ -111316,6 +111376,15 @@ location.href = '#foo';</code></pre>
<li><p>Set <var>window</var>'s <span data-x="concept-document-window">associated
<code>Document</code></span> to <var>document</var>.</p></li>

<li><p>Set <var>document</var>'s <span
data-x="concept-document-internal-ancestor-origin-objects-list">internal ancestor origin objects
list</span> to the result of running the <span>internal ancestor origin objects list creation
steps</span> given <var>document</var>.</p></li>

<li><p>Set <var>document</var>'s <span data-x="concept-document-ancestor-origins-list">ancestor
origins list</span> to the result of running the <span>ancestor origins list creation
steps</span> given <var>document</var>.</p></li>

<li><p><span>Run CSP initialization for a <code data-x="">Document</code></span> given
<var>document</var>. <ref>CSP</ref></p>

Expand Down