Skip to content

Commit

Permalink
Upstream the innerHTML property from DOM Parsing and Serialization
Browse files Browse the repository at this point in the history
This includes the innerHTML property on Element and ShadowRoot.

The fragment serializing algorithm steps and fragment parsing algorithm steps are also upstreamed.
  • Loading branch information
lukewarlow committed Apr 15, 2024
1 parent 4f7e114 commit d6a5f09
Showing 1 changed file with 138 additions and 5 deletions.
143 changes: 138 additions & 5 deletions source
Expand Up @@ -3369,8 +3369,8 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
<ref>DOMPARSING</ref></p>

<ul class="brief">
<li><dfn data-x="dom-innerHTML" data-x-href="https://w3c.github.io/DOM-Parsing/#dom-element-innerhtml"><code>innerHTML</code></dfn></li>
<li><dfn data-x="dom-outerHTML" data-x-href="https://w3c.github.io/DOM-Parsing/#dom-element-outerhtml"><code>outerHTML</code></dfn></li>
<li><dfn data-x="xml-serialization" data-x-href="https://w3c.github.io/DOM-Parsing/#dfn-xml-serialization"><code>XML serialization</code></dfn></li>
</ul>

<p>The following features are defined in <cite>Selection API</cite>: <ref>SELECTION</ref></p>
Expand Down Expand Up @@ -55937,7 +55937,7 @@ interface <dfn interface>HTMLLegendElement</dfn> : <span>HTMLElement</span> {
owner</span> of "e" would be the outer form "a".</p>

<p>This happens as follows: First, the "e" node gets associated with "c" in the <span>HTML
parser</span>. Then, the <code data-x="dom-innerHTML">innerHTML</code> algorithm moves the nodes
parser</span>. Then, the <code data-x="dom-element-innerHTML">innerHTML</code> algorithm moves the nodes
from the temporary document to the "b" element. At this point, the nodes see their ancestor chain
change, and thus all the "magic" associations done by the parser are reset to normal ancestor
associations.</p>
Expand Down Expand Up @@ -61875,7 +61875,7 @@ interface <dfn interface>HTMLScriptElement</dfn> : <span>HTMLElement</span> {
<p class="note">When inserted using the <code data-x="dom-document-write">document.write()</code>
method, <code>script</code> elements <a href="#document-written-scripts-intervention">usually</a>
execute (typically blocking further script execution or HTML parsing). When inserted using the
<code data-x="dom-innerHTML">innerHTML</code> and <code data-x="dom-outerHTML">outerHTML</code>
<code data-x="dom-element-innerHTML">innerHTML</code> and <code data-x="dom-outerHTML">outerHTML</code>
attributes, they do not execute at all.</p>

<p>The <code data-x="attr-script-defer">defer</code> attribute may be specified even if the <code
Expand Down Expand Up @@ -112399,11 +112399,15 @@ document.body.appendChild(frame)</code></pre>
<pre><code class="idl">partial interface <span id="Element-partial">Element</span> {
[<span>CEReactions</span>] undefined <span data-x="dom-Element-setHTMLUnsafe">setHTMLUnsafe</span>(<span data-x="tt-htmlstring">HTMLString</span> html);
DOMString <span data-x="dom-Element-getHTML">getHTML</span>(optional <span>GetHTMLOptions</span> options = {});

[<span>CEReactions</span>] attribute [<span>LegacyNullToEmptyString</span>] <span data-x="tt-htmlstring">HTMLString</span> <span data-x="dom-Element-innerHTML">innerHTML</span>;
};

partial interface <span id="ShadowRoot-partial">ShadowRoot</span> {
[<span>CEReactions</span>] undefined <span data-x="dom-ShadowRoot-setHTMLUnsafe">setHTMLUnsafe</span>(<span data-x="tt-htmlstring">HTMLString</span> html);
DOMString <span data-x="dom-ShadowRoot-getHTML">getHTML</span>(optional <span>GetHTMLOptions</span> options = {});

[<span>CEReactions</span>] attribute [<span>LegacyNullToEmptyString</span>] <span data-x="tt-htmlstring">HTMLString</span> <span data-x="dom-ShadowRoot-innerHTML">innerHTML</span>;
};

dictionary <dfn dictionary>GetHTMLOptions</dfn> {
Expand Down Expand Up @@ -112709,6 +112713,135 @@ enum <dfn enum>DOMParserSupportedType</dfn> {

</div>

<h4>The <code data-x="dom-element-innerHTML">innerHTML</code> property</h4>

<p class="XXX">The <code data-x="dom-element-innerHTML">innerHTML</code> property has a number of outstanding issues
in the <cite>DOM Parsing and Serialization</cite> <a href="https://github.com/w3c/DOM-Parsing/issues">issue
tracker</a>, documenting various problems with its specification.</p>

<dl class="domintro">
<dt><code data-x=""><var>element</var>.<span subdfn data-x="dom-Element-innerHTML">innerHTML</span></code></dt>
<dd>
<p>Returns a fragment of HTML or XML that represents the element's contents.</p>

<p>In the case of an XML document, throws a <span>"<code>InvalidStateError</code>"</span>
<code>DOMException</code> if the element cannot be serialized to XML.</p>
</dd>
<dt><code data-x=""><var>element</var>.<span data-x="dom-Element-innerHTML">innerHTML</span> = <var>value</var></code></dt>
<dd>
<p>Replaces the contents of the element with nodes parsed from the given string.</p>

<p>In the case of an XML document, throws a <span>"<code>SyntaxError</code>"</span>
<code>DOMException</code> if the given string is not well-formed.</p>
</dd>

<dt><code data-x=""><var>shadowRoot</var>.<span subdfn data-x="dom-ShadowRoot-innerHTML">innerHTML</span></code></dt>
<dd>
<p>Returns a fragment of HTML that represents the shadow roots's contents.</p>
</dd>

<dt><code data-x=""><var>shadowRoot</var>.<span data-x="dom-ShadowRoot-innerHTML">innerHTML</span> = <var>value</var></code></dt>
<dd>
<p>Replaces the contents of the shadow root with nodes parsed from the given string.</p>
</dd>
</dl>

<p class="warning">These properties' setters perform no sanitization to remove
potentially-dangerous elements and attributes like <code>script</code> or <span>event handler
content attributes</span>.</p>

<div w-nodev>

<p>The <dfn export>fragment serializing algorithm steps</dfn>, given an <code>Element</code> or
<code>DocumentFragment</code> <var>node</var> and a boolean <var>require well-formed</var>,
are:</p>

<ol>
<li><p>Let <var>context document</var> be <var>node</var>'s <span>node document</span>.</p></li>

<li><p>If <var>context document</var> is an <span data-x="HTML documents">HTML document</span>,
return the result of <span>HTML fragment serialization algorithm</span> with <var>node</var>,
false, and « ».</p></li>

<li><p>Return the <span data-x="xml-serialization">XML serialization</span> of <var>node</var>
given <var>require well-formed</var>.</p></li>
</ol>

<p>The <dfn export>fragment parsing algorithm steps</dfn>, given an <code>Element</code> or
<code>DocumentFragment</code> <var>context</var> and a string <var>markup</var>, are:</p>

<ol>
<li><p>Let <var>algorithm</var> be the <span>HTML fragment parsing algorithm</span>.</p></li>

<li><p>If <var>context</var>'s <span>node document</span> is an <span data-x="XML
documents">XML document</span>, then set <var>algorithm</var> to the <span>XML fragment parsing
algorithm</span>.</p></li>

<li><p>Let <var>new children</var> be the result of invoking <var>algorithm</var> given
<var>markup</var>, with <var data-x="concept-frag-parse-context">context</var> set to
<var>context</var>.</p></li>

<li><p>Let <var>fragment</var> be a new <code>DocumentFragment</code> whose <span>node
document</span> is <var>context</var>'s <span>node document</span>.</p></li>

<li>
<p><span data-x="concept-node-append">Append</span> each <code>Node</code> in <var>new
children</var> to <var>fragment</var> (in <span>tree order</span>).</p>

<p class=note>This ensures the <span>node document</span> for the new <span
data-x="node">nodes</span> is correct.</p>
</li>

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

<p><code>Element</code>'s <dfn attribute for="Element"><code
data-x="dom-Element-innerHTML">innerHTML</code></dfn> getter steps are to return the result of
running <span>fragment serializing algorithm steps</span> with <span>this</span> and true.</p>

<p><code>ShadowRoot</code>'s <dfn attribute for="ShadowRoot"><code
data-x="dom-ShadowRoot-innerHTML">innerHTML</code></dfn> getter steps are to return the result of
running <span>fragment serializing algorithm steps</span> with <span>this</span> and true.</p>

<p><code>Element</code>'s <code data-x="dom-Element-innerHTML">innerHTML</code> setter steps
are:</p>

<ol>
<li><p>Let <var>context</var> be <span>this</span>.</p></li>

<li><p>Let <var>fragment</var> be the result of invoking the <span>fragment parsing algorithm
steps</span> with <var>context</var> and the given value.</p></li>

<li>
<p>If <var>context</var> is a <code>template</code> element, then set <var>context</var> to
the <code>template</code> element's <span>template contents</span> (a
<code>DocumentFragment</code>).</p>

<p class=note>Setting <code data-x="dom-Element-innerHTML">innerHTML</code> on a
<code>template</code> element will replace all the nodes in its <span>template contents</span>
rather than its <span data-x="concept-tree-child">children</span>.</p>
</li>

<li><p><span data-x="concept-node-replace-all">Replace all</span> with <var>fragment</var>
within <var>context</var>.</p></li>
</ol>

<p><code>ShadowRoot</code>'s <code data-x="dom-ShadowRoot-innerHTML">innerHTML</code> setter
steps are:</p>

<ol>
<li><p>Let <var>context</var> be <span>this</span>'s <span
data-x="concept-DocumentFragment-host">host</span>.</p></li>

<li><p>Let <var>fragment</var> be the result of invoking the <span>fragment parsing algorithm
steps</span> with <var>context</var> and the given value.</p></li>

<li><p><span data-x="concept-node-replace-all">Replace all</span> with <var>fragment</var>
within <span>this</span>.</p></li>
</ol>

</div>

<h3 split-filename="timers-and-user-prompts" id="timers">Timers</h3>

<p>The <code data-x="dom-setTimeout">setTimeout()</code> and <code
Expand Down Expand Up @@ -131475,10 +131608,10 @@ document.body.appendChild(text);

<p>This can enable cross-site scripting attacks. An example of this would be a page that lets the
user enter some font family names that are then inserted into a CSS <code>style</code> block via
the DOM and which then uses the <code data-x="dom-innerHTML">innerHTML</code> IDL attribute to get
the DOM and which then uses the <code data-x="dom-element-innerHTML">innerHTML</code> IDL attribute to get
the HTML serialization of that <code>style</code> element: if the user enters
"<code data-x="">&lt;/style>&lt;script>attack&lt;/script></code>" as a font family name, <code
data-x="dom-innerHTML">innerHTML</code> will return markup that, if parsed in a different context,
data-x="dom-element-innerHTML">innerHTML</code> will return markup that, if parsed in a different context,
would contain a <code>script</code> node, even though no <code>script</code> node existed in the
original DOM.</p>

Expand Down

0 comments on commit d6a5f09

Please sign in to comment.