Skip to content

Commit

Permalink
Upstream innerHTML from DOM Parsing spec
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 9, 2024
1 parent 11ea4a2 commit d89cec4
Showing 1 changed file with 119 additions and 5 deletions.
124 changes: 119 additions & 5 deletions source
Original file line number Diff line number Diff line change
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 @@ -112384,11 +112384,13 @@ 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 @@ -112673,6 +112675,9 @@ enum <dfn enum>DOMParserSupportedType</dfn> {
</dd>
</dl>

<p class="warning">These properties 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><code>Element</code>'s <dfn method for="Element"><code
Expand All @@ -112691,6 +112696,115 @@ enum <dfn enum>DOMParserSupportedType</dfn> {

</div>

<h4>innerHTML property</h4>

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

<p>Can be set, to replace the contents of the element with nodes parsed from the given string.

<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, or a
<span>"<code>SyntaxError</code>"</span> <code>DOMException</code> if the given string is not
well-formed.
</dd>

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

<p>Can be set, to replace the contents of the shadow root with nodes parsed from the given
string.</p>
</dd>
</dl>

<div w-nodev>

<p>The <dfn export>fragment serializing algorithm steps</dfn>, given a DOM <span>Element</span>
or <span>DocumentFragment</span> referred to as <var>node</var> and a flag <dfn>require
well-formed</dfn>, are:</p>

<ol>
<li><p>Let <var>context document</var> be the value of <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>Otherwise, <var>context document</var> is an <span data-x="XML documents">XML
document</span>; return an <span data-x="xml-serialization">XML serialization</span> of
<var>node</var> passing the flag <var>require well-formed</var>.</p></li>
</ol>

<p>The <dfn export>fragment parsing algorithm steps</dfn>, given a DOM <span>Element</span> or
<span>DocumentFragment</span> referred to as <var>context element</var> and string
<var>markup</var>, are:</p>

<ol>
<li><p>If the <var>context element</var>'s <span>node document</span> is an <span data-x="HTML
documents">HTML document</span>: let <var>algorithm</var> be the <span>HTML fragment parsing
algorithm</span>.</p></li>

<li><p>If the <var>context element</var>'s <span>node document</span> is an <span data-x="XML
documents">XML document</span>: let <var>algorithm</var> be the <span>XML fragment parsing
algorithm</span>.</p></li>

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

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

<li>
<p><span data-x="concept-node-append">Append</span> each <span>Node</span> 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 the value of <var>fragment</var>.</p></li>
</ol>

<p>The <dfn attribute for="Element"><code
data-x="dom-Element-innerHTML">element.innerHTML</code></dfn> and <dfn attribute
for="ShadowRoot"><code data-x="dom-ShadowRoot-innerHTML">shadowRoot.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>The <code data-x="dom-Element-innerHTML">element.innerHTML</code> and <code
data-x="dom-ShadowRoot-innerHTML">shadowRoot.innerHTML</code> setters steps are:</p>

<ol>
<li><p>Let <var>context object</var> be <span>this</span>.</p></li>
<li><p>Let <var>context element</var> be the <var>context object</var>'s <span
data-x="concept-DocumentFragment-host">host</span> if <var>this</var> is a
<span>ShadowRoot</span> object, or <var>this</var> otherwise.</p></li>

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

<li>
<p>If <var>context object</var> is a <span>template</span> element, then let <var>context
object</var> be the <span>template</span> element's <span>template contents</span> (a
<span>DocumentFragment</span>).</p>

<p class=note>Setting <code data-x="dom-Element-innerHTML">innerHTML</code> on a
<span>template</span> element will replace all the nodes in its <span>template contents</span>
(<span>template</span>.<span data-x="template contents">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 object</var>.</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 @@ -131459,10 +131573,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 d89cec4

Please sign in to comment.